blob: 6b442bea65a52f33d242d7c972f0bc0d0ba0b45a [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "hash.h"
#include "vpr_utils.h"
#include "check_netlist.h"
#include "assert.h"
#include "read_xml_arch_file.h"
#define ERROR_THRESHOLD 100
/**************** Subroutines local to this module **************************/
static int check_connections_to_global_clb_pins(int inet);
static int check_for_duplicated_names(void);
static int check_clb_conn(int iblk,
int num_conn);
static int check_clb_internal_nets(int iblk);
static int check_subblock_internal_nets(int iblk, int isub);
static void check_for_multiple_sink_connections(void);
static int get_num_conn(int bnum);
static int check_subblocks(int iblk);
static int check_primitives(int iblk, int isub);
/*********************** Subroutine definitions *****************************/
void
check_netlist()
{
/* This routine checks that the netlist makes sense */
int i, error, num_conn;
int net_count;
struct s_hash **net_hash_table, *h_net_ptr;
net_hash_table = alloc_hash_table();
net_count = 0;
error = 0;
/* Check that nets fanout and have a driver. */
for(i = 0; i < num_nets; i++)
{
h_net_ptr = insert_in_hash_table(net_hash_table, clb_net[i].name, i);
if(h_net_ptr->count != 1) {
printf(ERRTAG "net %s has multiple drivers.\n", clb_net[i].name);
error++;
}
error += check_connections_to_global_clb_pins(i);
if(error >= ERROR_THRESHOLD) {
printf("Too many errors in netlist, exiting\n");
exit(1);
}
}
free_hash_table(net_hash_table);
/* Check that each block makes sense. */
for(i = 0; i < num_blocks; i++)
{
num_conn = get_num_conn(i);
error += check_clb_conn(i, num_conn);
error += check_clb_internal_nets(i);
error += check_subblocks(i);
if(error >= ERROR_THRESHOLD) {
printf("Too many errors in netlist, exiting\n");
exit(1);
}
}
error += check_for_duplicated_names();
if(error != 0)
{
printf("Found %d fatal Errors in the input netlist.\n", error);
exit(1);
}
/* HACK: Jason Luu January 17, 2011 Do not route common constants gnd and vcc
Todo: Need to make architecture driven.
*/
for(i = 0; i < num_nets; i++)
{
if(strcmp(clb_net[i].name, "vcc") == 0) {
clb_net[i].is_global = TRUE;
} else if(strcmp(clb_net[i].name, "gnd") == 0) {
clb_net[i].is_global = TRUE;
}
}
}
static int
check_connections_to_global_clb_pins(int inet)
{
/* Checks that a global net (inet) connects only to global CLB input pins *
* and that non-global nets never connects to a global CLB pin. Either *
* global or non-global nets are allowed to connect to pads. */
int ipin, num_pins, iblk, node_block_pin, error;
num_pins = (clb_net[inet].num_sinks + 1);
error = 0;
/* For now global signals can be driven by an I/O pad or any CLB output *
* although a CLB output generates a warning. I could make a global CLB *
* output pin type to allow people to make architectures that didn't have *
* this warning. */
for(ipin = 0; ipin < num_pins; ipin++)
{
iblk = clb_net[inet].node_block[ipin];
node_block_pin = clb_net[inet].node_block_pin[ipin];
if(block[iblk].type->is_global_pin[node_block_pin] !=
clb_net[inet].is_global && block[iblk].type != IO_TYPE)
{
/* Allow a CLB output pin to drive a global net (warning only). */
if(ipin == 0 && clb_net[inet].is_global)
{
printf
(WARNTAG "in check_connections_to_global_clb_pins:\n"
"\tnet #%d (%s) is driven by CLB output pin (#%d)\n"
"\ton block #%d (%s).\n", inet,
clb_net[inet].name, node_block_pin, iblk,
block[iblk].name);
}
else
{ /* Otherwise -> Error */
printf
(ERRTAG "in check_connections_to_global_clb_pins:\n"
"\tpin %d on net #%d (%s) connects to CLB input pin (#%d)\n"
"\ton block #%d (%s).\n", ipin, inet,
clb_net[inet].name, node_block_pin, iblk,
block[iblk].name);
error++;
}
if(clb_net[inet].is_global)
printf("\tNet is global, but CLB pin is not.\n\n");
else
printf("\tCLB pin is global, but net is not.\n\n");
}
} /* End for all pins */
return (error);
}
static int
check_clb_conn(int iblk,
int num_conn)
{
/* Checks that the connections into and out of the clb make sense. */
int iclass, ipin, error;
t_type_ptr type;
error = 0;
type = block[iblk].type;
if(type == IO_TYPE)
{
if(num_conn != 1)
{
printf(ERRTAG "io blk #%d (%s) has %d pins.\n",
iblk, block[iblk].name, num_conn);
error++;
}
}
else if(num_conn < 2)
{
printf(WARNTAG "logic block #%d (%s) has only %d pin.\n",
iblk, block[iblk].name, num_conn);
/* Allow the case where we have only one OUTPUT pin connected to continue. *
* This is used sometimes as a constant generator for a primary output, *
* but I will still warn the user. If the only pin connected is an input, *
* abort. */
if(num_conn == 1)
{
for(ipin = 0; ipin < type->num_pins; ipin++)
{
if(block[iblk].nets[ipin] != OPEN)
{
iclass = type->pin_class[ipin];
if(type->class_inf[iclass].type != DRIVER)
{
error++;
}
else
{
printf
("\tPin is an output -- may be a constant generator.\n"
"\tNon-fatal, but check this.\n");
}
break;
}
}
}
else
{
error++;
}
}
/* This case should already have been flagged as an error -- this is *
* just a redundant double check. */
if(num_conn > type->num_pins)
{
printf(ERRTAG "logic block #%d with output %s has %d pins.\n",
iblk, block[iblk].name, num_conn);
error++;
}
return (error);
}
static int check_clb_internal_nets(int iblk) {
/** TODO:
* Check if the internal CLB nets makes sense and are connected properly
* Consists of 3 main loops
* 1. a) Check name uniqueness
b) Check all net connections are to CLB pins or subblock pins and that they match the net examined
* 2. Check all connected CLB pins are connected to valid internal nets
* 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes
*/
return 0;
}
static int check_subblock_internal_nets(int iblk, int isub) {
/**
* TODO
* Check if the internal CLB nets makes sense and are connected properly
* Consists of 3 main checks
* 1. a) Check name uniqueness
b) Check all net connections are to CLB pins or subblock pins and that they match the net examined
* 2. Check all connected CLB pins are connected to valid internal nets
* 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes
*/
return 0;
}
static int
check_subblocks(int iblk)
{
/* TODO */
/* This routine checks the subblocks of iblk (which must be a CLB). It *
* returns the number of errors found. */
return 0;
}
static int
check_primitives(int iblk, int isub)
{
/* TODO:
This routine checks the subblocks of iblk (which must be a CLB). It *
* returns the number of errors found. */
return 0;
}
static int
check_for_duplicated_names(void)
{
#if 0
int iblk, isub, iprim, error;
int clb_count, sub_count, prim_count;
struct s_hash **clb_hash_table, *clb_h_ptr;
struct s_hash **sub_hash_table, *sub_h_ptr;
struct s_hash **prim_hash_table, *prim_h_ptr;
clb_hash_table = alloc_hash_table();
sub_hash_table = alloc_hash_table();
prim_hash_table = alloc_hash_table();
error = clb_count = sub_count = prim_count = 0;
for(iblk = 0; iblk < num_blocks; iblk++)
{
clb_h_ptr = insert_in_hash_table(clb_hash_table, block[iblk].name, clb_count);
if(clb_h_ptr->count > 1) {
printf(ERRTAG "block %s has duplicated name\n", block[iblk].name);
error++;
} else {
clb_count++;
}
for(isub = 0; isub < block[iblk].num_subblocks; isub++)
{
sub_h_ptr = insert_in_hash_table(sub_hash_table, block[iblk].subblocks[isub].name, sub_count);
if(sub_h_ptr->count > 1) {
printf(ERRTAG "subblock %s has duplicated name\n", block[iblk].subblocks[isub].name);
error++;
} else {
sub_count++;
}
for(iprim = 0; iprim < block[iblk].subblocks[isub].num_primitives; iprim++)
{
prim_h_ptr = insert_in_hash_table(prim_hash_table, block[iblk].subblocks[isub].primitives[iprim].name, prim_count);
if(prim_h_ptr->count > 1) {
printf(ERRTAG "primitive %s has duplicated name\n", block[iblk].subblocks[isub].primitives[iprim].name);
error++;
} else {
prim_count++;
}
}
}
}
return error;
#endif
return 0;
}
static int
get_num_conn(int bnum)
{
/* This routine returns the number of connections to a block. */
int i, num_conn;
t_type_ptr type;
type = block[bnum].type;
num_conn = 0;
for(i = 0; i < type->num_pins; i++)
{
if(block[bnum].nets[i] != OPEN)
num_conn++;
}
return (num_conn);
}