blob: b2c6f64178244b8b0096b044d80ff05f7be903f0 [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "hash.h"
#include "vpr_types.h"
#include "vpr_utils.h"
#include "ReadLine.h"
#include "globals.h"
static char *pinlist_str = "pinlist:";
enum special_blk
{ NORMAL = 0, INPAD, OUTPAD };
static t_type_ptr get_type_by_name(IN const char *name,
IN int num_types,
IN const struct s_type_descriptor
block_types[],
IN t_type_ptr IO_type,
IN const char *net_file,
IN int line,
OUT enum special_blk *overide);
/* Initializes the block_list with info from a netlist */
void
read_netlist(IN const char *net_file,
IN int num_types,
IN const struct s_type_descriptor block_types[],
IN t_type_ptr IO_type,
IN int io_ipin,
IN int io_opin,
OUT t_subblock_data * subblock_data_ptr,
OUT int *num_blocks,
OUT struct s_block *block_list[],
OUT int *num_nets,
OUT struct s_net *net_list[])
{
FILE *infile;
int bcount;
struct s_block *blist;
int ncount;
struct s_net *nlist;
int i, j, k, l, m;
enum
{ COUNT, LOAD, MAP, STOP }
pass;
int line, prev_line;
enum special_blk overide;
char **block_tokens;
char **pin_tokens;
char **tokens;
t_subblock **slist = NULL;
int *scount = NULL;
t_type_ptr type = NULL;
infile = my_fopen(net_file, "r");
bcount = 0;
blist = NULL;
ncount = 0;
nlist = NULL;
memset(subblock_data_ptr, 0, sizeof(t_subblock_data));
/* Multi-pass load
* COUNT
* -> count blocks
* -> count nets
*
* LOAD
* -> alloc num_subblocks_per_block list
* -> allocate s_block list at start
* -> allocate s_net list at start
* -> count subblocks per block
* -> sets block names
* -> sets block types
* -> allocs block net lists
* -> sets net names
*
* MAP
* -> fills in s_block:nets list
* -> fills in subblocks */
for(pass = 0; pass < STOP; ++pass)
{
rewind(infile);
line = 0;
i = 0;
j = 0;
overide = NORMAL;
/* Alloc the lists */
if(LOAD == pass)
{
blist =
(struct s_block *)my_malloc(sizeof(struct s_block) *
bcount);
memset(blist, 0, (sizeof(struct s_block) * bcount));
nlist =
(struct s_net *)my_malloc(sizeof(struct s_net) *
ncount);
memset(nlist, 0, (sizeof(struct s_net) * ncount));
slist =
(t_subblock **) my_malloc(sizeof(t_subblock *) *
bcount);
memset(slist, 0, (sizeof(t_subblock *) * bcount));
scount = (int *)my_malloc(sizeof(int) * bcount);
memset(scount, 0, (sizeof(int) * bcount));
}
/* Read file line by line */
block_tokens = ReadLineTokens(infile, &line);
prev_line = line;
while(block_tokens)
{
/* .global directives have special meaning */
if(0 == strcmp(block_tokens[0], ".global"))
{
if(MAP == pass)
{
for(l = 0; l < ncount; ++l)
{
if(0 ==
strcmp(nlist[l].name,
block_tokens[1]))
{
nlist[l].is_global = TRUE;
break;
}
}
if(l == ncount)
{
printf(ERRTAG
"'%s':%d - '.global' specified an invalid net\n",
net_file, prev_line);
exit(1);
}
}
/* Don't do any more processing on this */
FreeTokens(&block_tokens);
block_tokens = ReadLineTokens(infile, &line);
prev_line = line;
continue;
}
pin_tokens = ReadLineTokens(infile, &line);
if(CountTokens(block_tokens) != 2)
{
printf(ERRTAG "'%s':%d - block type line should "
"be in form '.type_name block_name'\n",
net_file, prev_line);
exit(1);
}
if(NULL == pin_tokens)
{
printf(ERRTAG
"'%s':%d - blocks must be follow by a 'pinlist:' line\n",
net_file, line);
exit(1);
}
if(0 != strcmp("pinlist:", pin_tokens[0]))
{
printf(ERRTAG
"'%s':%d - 'pinlist:' line must follow "
"block type line\n", net_file, line);
exit(1);
}
type =
get_type_by_name(block_tokens[0], num_types,
block_types, IO_type, net_file,
prev_line, &overide);
/* Check if we are overiding the pinlist format for this block */
if(overide)
{
if(CountTokens(pin_tokens) != 2)
{ /* 'pinlist:' and name */
printf(ERRTAG
"'%s':%d - pinlist for .input and .output should "
"only have one item.\n", net_file,
line);
exit(1);
}
/* Make a new faked token list with 'pinlist:' and then pin mappings and a null */
tokens =
(char **)my_malloc(sizeof(char *) *
(type->num_pins + 2));
l = strlen(pinlist_str) + 1;
k = strlen(pin_tokens[1]) + 1;
tokens[0] =
(char *)my_malloc(sizeof(char) * (k + l));
memcpy(tokens[0], pinlist_str, l * sizeof(char));
memcpy(tokens[0] + l, pin_tokens[1],
k * sizeof(char));
/* Set all other pins to open */
for(k = 0; k < type->num_pins; ++k)
{
tokens[1 + k] = "open"; /* free wont be called on this so is safe */
}
tokens[1 + k] = NULL; /* End of token list marker */
/* Set the one pin with the value given */
for(k = 0; k < type->num_pins; ++k)
{
switch (overide)
{
case INPAD:
tokens[1 + io_opin] =
(tokens[0] + l);
break;
case OUTPAD:
tokens[1 + io_ipin] =
(tokens[0] + l);
break;
}
}
FreeTokens(&pin_tokens);
pin_tokens = tokens;
tokens = NULL;
}
if(CountTokens(pin_tokens) != (type->num_pins + 1))
{
printf(ERRTAG
"'%s':%d - 'pinlist:' line has %d pins instead of "
"expect %d pins.\n", net_file, line,
CountTokens(pin_tokens) - 1,
type->num_pins);
exit(1);
}
/* Load block name and type and alloc net list */
if(LOAD == pass)
{
blist[i].name = my_strdup(block_tokens[1]);
blist[i].type = type;
blist[i].nets =
(int *)my_malloc(sizeof(int) *
type->num_pins);
for(k = 0; k < type->num_pins; ++k)
{
blist[i].nets[k] = OPEN;
}
}
/* Examine pin list to determine nets */
for(k = 0; k < type->num_pins; ++k)
{
if(0 != strcmp("open", pin_tokens[1 + k]))
{
if(DRIVER ==
type->class_inf[type->pin_class[k]].
type)
{
if(LOAD == pass)
{
nlist[j].name =
my_strdup(pin_tokens
[1 + k]);
}
if(MAP == pass)
{
blist[i].nets[k] = j; /* If we are net source we don't need to search */
}
++j; /* This was an active netlist */
}
else
{
if(MAP == pass)
{
/* Map sinks by doing a linear search to find the net */
blist[i].nets[k] = OPEN;
for(l = 0; l < ncount;
++l)
{
if(0 ==
strcmp(nlist
[l].
name,
pin_tokens
[1 +
k]))
{
blist[i].
nets
[k] =
l;
break;
}
}
if(OPEN ==
blist[i].nets[k])
{
printf(ERRTAG
"'%s':%d - Net '%s' not found\n",
net_file,
line,
pin_tokens
[1 + k]);
exit(1);
}
}
}
}
}
/* Allocating subblocks */
if(MAP == pass)
{
/* All blocks internally have subblocks but I/O subblocks are
allocated and loaded elsewhere */
if(scount[i] > 0) {
slist[i] = (t_subblock *)
my_malloc(sizeof(t_subblock) * scount[i]);
for(k = 0; k < scount[i]; ++k)
{
slist[i][k].name = NULL;
slist[i][k].clock = OPEN;
slist[i][k].inputs =
(int *)my_malloc(sizeof(int) *
type->
max_subblock_inputs);
for(l = 0; l < type->max_subblock_inputs;
++l)
{
slist[i][k].inputs[l] = OPEN;
}
slist[i][k].outputs =
(int *)my_malloc(sizeof(int) *
type->
max_subblock_outputs);
for(l = 0; l < type->max_subblock_outputs;
++l)
{
slist[i][k].outputs[l] = OPEN;
}
}
}
}
/* Ignore subblock data */
tokens = ReadLineTokens(infile, &line);
prev_line = line;
m = 0;
while(tokens && (0 == strcmp(tokens[0], "subblock:")))
{
if(CountTokens(tokens) != (type->max_subblock_inputs + type->max_subblock_outputs + 1 + /* clocks */
2))
{ /* 'subblock:', name */
printf("subblock wrong pin count, netlist has %d, architecture as %d on line %d \n" ,
CountTokens(tokens) - 2, (type->max_subblock_inputs + type->max_subblock_outputs + 1),
line);
exit(1);
}
/* Count subblocks given */
if(LOAD == pass)
{
scount[i]++;
}
/* Load subblock name */
if(MAP == pass)
{
assert(i < bcount);
assert(m < scount[i]);
slist[i][m].name = my_strdup(tokens[1]);
for(k = 0; k < type->max_subblock_inputs;
++k)
{
/* Check prefix and load pin num */
l = 2 + k;
if(0 ==
strncmp("ble_", tokens[l], 4))
{
slist[i][m].inputs[k] = type->num_pins + my_atoi(tokens[l] + 4); /* Skip the 'ble_' part */
}
else if(0 !=
strcmp("open", tokens[l]))
{
slist[i][m].inputs[k] =
my_atoi(tokens[l]);
}
}
for(k = 0; k < type->max_subblock_outputs;
++k)
{
l = 2 +
type->max_subblock_inputs + k;
if(0 != strcmp("open", tokens[l]))
{
slist[i][m].outputs[k] =
my_atoi(tokens[l]);
}
}
l = 2 + type->max_subblock_inputs +
type->max_subblock_outputs;
if(0 != strcmp("open", tokens[l]))
{
slist[i][m].clock =
my_atoi(tokens[l]);
}
}
++m; /* Next subblock */
FreeTokens(&tokens);
tokens = ReadLineTokens(infile, &line);
prev_line = line;
}
if(pass > COUNT)
{
/* Check num of subblocks read */
if(scount[i] > type->max_subblocks)
{
printf("too many subblocks on block [%d] %s\n", i, blist[i].name);
exit(1);
}
}
++i; /* End of this block */
FreeTokens(&block_tokens);
FreeTokens(&pin_tokens);
block_tokens = tokens;
}
/* Save counts */
if(COUNT == pass)
{
bcount = i;
ncount = j;
}
}
fclose(infile);
/* Builds mappings from each netlist to the blocks contained */
sync_nets_to_blocks(bcount, blist, ncount, nlist);
/* Send values back to caller */
*num_blocks = bcount;
*block_list = blist;
*num_nets = ncount;
*net_list = nlist;
subblock_data_ptr->subblock_inf = slist;
subblock_data_ptr->num_subblocks_per_block = scount;
}
static t_type_ptr
get_type_by_name(IN const char *name,
IN int num_types,
IN const struct s_type_descriptor block_types[],
IN t_type_ptr IO_type,
IN const char *net_file,
IN int line,
OUT enum special_blk *overide)
{
/* Just does a simple linear search for now */
int i;
/* pin_overide is used to specify that the .input and .output
* blocks only have one pin specified and should be treated
* as if used as a .io with a full pin spec */
*overide = NORMAL;
/* .input and .output are special names that map to the basic IO type */
if(0 == strcmp(".input", name))
{
*overide = INPAD;
return IO_type;
}
if(0 == strcmp(".output", name))
{
*overide = OUTPAD;
return IO_type;
}
/* Linear type search. Don't really expect to have too many
* types for it to be a problem */
for(i = 0; i < num_types; ++i)
{
if(0 == strcmp(block_types[i].name, name))
{
return (block_types + i);
}
}
/* No type matched */
printf(ERRTAG "'%s':%d - Invalid block type '%s'\n",
net_file, line, name);
exit(1);
}