blob: 989d1fff894ee65d6ceaaba9976f8a9d4e69dde6 [file] [log] [blame]
/*
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "odin_globals.h"
#include "odin_util.h"
#include "read_blif.h"
#include "string_cache.h"
#include "netlist_utils.h"
#include "odin_types.h"
#include "Hashtable.hpp"
#include "netlist_check.h"
#include "node_creation_library.h"
#include "simulate_blif.h"
#include "vtr_util.h"
#include "vtr_memory.h"
#define TOKENS " \t\n"
#define GND_NAME "gnd"
#define VCC_NAME "vcc"
#define HBPAD_NAME "unconn"
#define READ_BLIF_BUFFER 1048576 // 1MB
long file_line_number;
int line_count;
// Stores pin names of the form port[pin]
struct hard_block_pins{
int count;
char **names;
// Maps name to index.
Hashtable *index;
};
// Stores port names, and their sizes.
struct hard_block_ports{
char *signature;
int count;
int *sizes;
char **names;
// Maps portname to index.
Hashtable *index;
};
// Stores all information pertaining to a hard block model. (.model)
struct hard_block_model{
char *name;
hard_block_pins *inputs;
hard_block_pins *outputs;
hard_block_ports *input_ports;
hard_block_ports *output_ports;
};
// A cache structure for models.
struct hard_block_models{
hard_block_model **models;
int count;
// Maps name to model
Hashtable *index;
};
netlist_t * blif_netlist;
bool static skip_reading_bit_map=false;
bool insert_global_clock;
void rb_create_top_driver_nets(const char *instance_name_prefix, Hashtable *output_nets_hash);
void rb_look_for_clocks();// not sure if this is needed
void add_top_input_nodes(FILE *file, Hashtable *output_nets_hash);
void rb_create_top_output_nodes(FILE *file);
int read_tokens (char *buffer, hard_block_models *models, FILE *file, Hashtable *output_nets_hash);
static void dum_parse (char *buffer, FILE *file);
void create_internal_node_and_driver(FILE *file, Hashtable *output_nets_hash);
operation_list assign_node_type_from_node_name(char * output_name);// function will decide the node->type of the given node
operation_list read_bit_map_find_unknown_gate(int input_count, nnode_t * node, FILE *file);
void create_latch_node_and_driver(FILE *file, Hashtable *output_nets_hash);
void create_hard_block_nodes(hard_block_models *models, FILE *file, Hashtable *output_nets_hash);
void hook_up_nets(Hashtable *output_nets_hash);
void hook_up_node(nnode_t *node, Hashtable *output_nets_hash);
char* search_clock_name(FILE *file);
void free_hard_block_model(hard_block_model *model);
char *get_hard_block_port_name(char *name);
long get_hard_block_pin_number(char *original_name);
static int compare_hard_block_pin_names(const void *p1, const void *p2);
hard_block_ports *get_hard_block_ports(char **pins, int count);
Hashtable *index_names(char **names, int count);
Hashtable *associate_names(char **names1, char **names2, int count);
void free_hard_block_pins(hard_block_pins *p);
void free_hard_block_ports(hard_block_ports *p);
hard_block_model *get_hard_block_model(char *name, hard_block_ports *ports, hard_block_models *models);
void add_hard_block_model(hard_block_model *m, hard_block_ports *ports, hard_block_models *models);
char *generate_hard_block_ports_signature(hard_block_ports *ports);
int verify_hard_block_ports_against_model(hard_block_ports *ports, hard_block_model *model);
hard_block_model *read_hard_block_model(char *name_subckt, hard_block_ports *ports, FILE *file);
void free_hard_block_models(hard_block_models *models);
hard_block_models *create_hard_block_models();
int count_blif_lines(FILE *file);
/*
* Reads a blif file with the given filename and produces
* a netlist which is referred to by the global variable
* "blif_netlist".
*/
netlist_t *read_blif()
{
insert_global_clock = true;
current_parse_file = 0;
blif_netlist = allocate_netlist();
/*Opening the blif file */
FILE *file = vtr::fopen (configuration.list_of_file_names[current_parse_file].c_str(), "r");
if (file == NULL)
{
error_message(ARG_ERROR, -1, current_parse_file, "cannot open file: %s\n", configuration.list_of_file_names[current_parse_file].c_str());
}
int num_lines = count_blif_lines(file);
Hashtable *output_nets_hash = new Hashtable();
printf("Reading top level module\n"); fflush(stdout);
/* create the top level module */
rb_create_top_driver_nets("top", output_nets_hash);
/* Extracting the netlist by reading the blif file */
printf("Reading blif netlist..."); fflush(stdout);
file_line_number = 0;
line_count = 0;
int position = -1;
double time = wall_time();
// A cache of hard block models indexed by name. As each one is read, it's stored here to be used again.
hard_block_models *models = create_hard_block_models();
printf("\n");
char buffer[READ_BLIF_BUFFER];
while (vtr::fgets(buffer, READ_BLIF_BUFFER, file) && read_tokens(buffer, models, file, output_nets_hash))
{ // Print a progress bar indicating completeness.
position = print_progress_bar((++line_count)/(double)num_lines, position, 50, wall_time() - time);
}
free_hard_block_models(models);
/* Now look for high-level signals */
rb_look_for_clocks();
// We the estimate of completion is rough...make sure we end up at 100%. ;)
print_progress_bar(1.0, position, 50, wall_time() - time);
printf("-------------------------------------\n"); fflush(stdout);
// Outputs netlist graph.
check_netlist(blif_netlist);
delete output_nets_hash;
fclose (file);
return blif_netlist;
}
/*---------------------------------------------------------------------------------------------
* (function: read_tokens)
*
* Parses the given line from the blif file. Returns true if there are more lines
* to read.
*-------------------------------------------------------------------------------------------*/
int read_tokens (char *buffer, hard_block_models *models, FILE *file, Hashtable *output_nets_hash)
{
/* Figures out which, if any token is at the start of this line and *
* takes the appropriate action. */
char *token = vtr::strtok (buffer, TOKENS, file, buffer);
if (token)
{
if(skip_reading_bit_map && ((token[0] == '0') || (token[0] == '1') || (token[0] == '-')))
{
dum_parse(buffer, file);
}
else
{
skip_reading_bit_map= false;
if (strcmp (token, ".inputs") == 0)
{
add_top_input_nodes(file, output_nets_hash);// create the top input nodes
}
else if (strcmp (token, ".outputs") == 0)
{
rb_create_top_output_nodes(file);// create the top output nodes
}
else if (strcmp (token, ".names") == 0)
{
create_internal_node_and_driver(file, output_nets_hash);
}
else if (strcmp(token,".latch") == 0)
{
create_latch_node_and_driver(file, output_nets_hash);
}
else if (strcmp(token,".subckt") == 0)
{
create_hard_block_nodes(models, file, output_nets_hash);
}
else if (strcmp(token,".end")==0)
{
// Marks the end of the main module of the blif
// Call function to hook up the nets
hook_up_nets(output_nets_hash);
return false;
}
else if (strcmp(token,".model")==0)
{
// Ignore models.
dum_parse(buffer, file);
}
}
}
return true;
}
/*---------------------------------------------------------------------------------------------
* function:assign_node_type_from_node_name(char *)
This function tries to assign the node->type by looking at the name
Else return GENERIC
*-------------------------------------------------------------------------------------------*/
operation_list assign_node_type_from_node_name(char * output_name)
{
//variable to extract the type
operation_list result = GENERIC;
int start, end;
int length_string = strlen(output_name);
for(start = length_string-1; (start >= 0) && (output_name[start] != '^'); start--);
for(end = length_string-1; (end >= 0) && (output_name[end] != '~'); end-- );
if((start < end) && (end > 0))
{
// Stores the extracted string
char *extracted_string = (char*)vtr::calloc(end-start+2, sizeof(char));
int i, j;
for(i = start + 1, j = 0; i < end; i++, j++)
{
extracted_string[j] = output_name[i];
}
extracted_string[j]='\0';
for(i=0; i<operation_list_END; i++)
{
if(!strcmp(extracted_string,operation_list_STR[i][ODIN_LONG_STRING])
|| !strcmp(extracted_string,operation_list_STR[i][ODIN_SHORT_STRING]))
{
result = static_cast<operation_list>(i);
break;
}
}
vtr::free(extracted_string);
}
return result;
}
/*---------------------------------------------------------------------------------------------
* function:create_latch_node_and_driver
to create an ff node and driver from that node
format .latch <input> <output> [<type> <control/clock>] <initial val>
*-------------------------------------------------------------------------------------------*/
void create_latch_node_and_driver(FILE *file, Hashtable *output_nets_hash)
{
/* Storing the names of the input and the final output in array names */
char ** names = NULL; // Store the names of the tokens
int input_token_count = 0; /*to keep track whether controlling clock is specified or not */
/*input_token_count=3 it is not and =5 it is */
char *ptr = NULL;
char buffer[READ_BLIF_BUFFER];
while ((ptr = vtr::strtok (NULL, TOKENS, file, buffer)) != NULL)
{
input_token_count += 1;
names = (char**)vtr::realloc(names, (sizeof(char*))* (input_token_count));
names[input_token_count-1] = vtr::strdup(ptr);
}
/* assigning the new_node */
if(input_token_count != 5)
{
/* supported added for the ABC .latch output without control */
if(input_token_count == 3)
{
input_token_count = 5;
names = (char**)vtr::realloc(names, sizeof(char*) * input_token_count);
names[3] = search_clock_name(file);
names[4] = names[2];
names[2] = vtr::strdup("re");
}
else
{
std::string line = "";
for(int i=0; i< input_token_count; i++)
{
line += names[i];
line += " ";
}
error_message(NETLIST_ERROR,file_line_number,current_parse_file, "This .latch Format not supported: <%s> \n\t required format :.latch <input> <output> [<type> <control/clock>] <initial val>",
line.c_str());
}
}
nnode_t *new_node = allocate_nnode();
new_node->related_ast_node = NULL;
new_node->type = FF_NODE;
new_node->edge_type = edge_type_blif_enum(names[2]);
/* Read in the initial value of the latch.
Possible values from a blif file are:
0: LOW
1: HIGH
2: DON'T CARE
3: UNKNOWN
2 and 3 are treated in the same way */
int initial_value = atoi(names[4]);
if(initial_value == 0 || initial_value == 1){
new_node->initial_value = initial_value;
new_node->has_initial_value = true;
}
/* allocate the output pin (there is always one output pin) */
allocate_more_output_pins(new_node, 1);
add_output_port_information(new_node, 1);
/* allocate the input pin */
allocate_more_input_pins(new_node,2);/* input[1] is clock */
/* add the port information */
int i;
for(i = 0; i < 2; i++)
{
add_input_port_information(new_node,1);
}
/* add names and type information to the created input pins */
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(names[0]);
new_pin->type = INPUT;
add_input_pin_to_node(new_node, new_pin,0);
new_pin = allocate_npin();
new_pin->name = vtr::strdup(names[3]);
new_pin->type = INPUT;
add_input_pin_to_node(new_node, new_pin,1);
/* add a name for the node, keeping the name of the node same as the output */
new_node->name = make_full_ref_name(names[1],NULL, NULL, NULL,-1);
/*add this node to blif_netlist as an ff (flip-flop) node */
blif_netlist->ff_nodes = (nnode_t **)vtr::realloc(blif_netlist->ff_nodes, sizeof(nnode_t*)*(blif_netlist->num_ff_nodes+1));
blif_netlist->ff_nodes[blif_netlist->num_ff_nodes++] = new_node;
new_node->file_number = current_parse_file;
new_node->line_number = line_count;
/*add name information and a net(driver) for the output */
nnet_t *new_net = allocate_nnet();
new_net->name = new_node->name;
new_pin = allocate_npin();
new_pin->name = new_node->name;
new_pin->type = OUTPUT;
add_output_pin_to_node(new_node, new_pin, 0);
add_driver_pin_to_net(new_net, new_pin);
output_nets_hash->add(new_node->name, new_net);
/* Free the char** names */
for (i = 0; i < input_token_count; i++)
vtr::free(names[i]);
vtr::free(names);
vtr::free(ptr);
}
/*---------------------------------------------------------------------------------------------
* function: search_clock_name
to search the clock if the control in the latch
is not mentioned
*-------------------------------------------------------------------------------------------*/
char* search_clock_name(FILE* file)
{
fpos_t pos;
int last_line = file_line_number;
fgetpos(file,&pos);
rewind(file);
char *to_return = NULL;
char ** input_names = NULL;
int input_names_count = 0;
int found = 0;
while(!found)
{
char buffer[READ_BLIF_BUFFER];
vtr::fgets(buffer,READ_BLIF_BUFFER,file);
// not sure if this is needed
if(feof(file))
break;
char *ptr = NULL;
if((ptr = vtr::strtok(buffer, TOKENS, file, buffer)))
{
if(!strcmp(ptr,".end"))
break;
if(!strcmp(ptr,".inputs"))
{
/* store the inputs in array of string */
while((ptr = vtr::strtok (NULL, TOKENS, file, buffer)))
{
input_names = (char**)vtr::realloc(input_names,sizeof(char*) * (input_names_count + 1));
input_names[input_names_count++] = vtr::strdup(ptr);
}
}
else if(!strcmp(ptr,".names") || !strcmp(ptr,".latch"))
{
while((ptr = vtr::strtok (NULL, TOKENS,file, buffer)))
{
int i;
for(i = 0; i < input_names_count; i++)
{
if(!strcmp(ptr,input_names[i]))
{
vtr::free(input_names[i]);
input_names[i] = input_names[--input_names_count];
}
}
}
}
else if(input_names_count == 1)
{
found = 1;
}
}
}
file_line_number = last_line;
fsetpos(file,&pos);
if (found)
{
to_return = input_names[0];
}
else
{
to_return = vtr::strdup(DEFAULT_CLOCK_NAME);
for(int i = 0; i < input_names_count; i++)
{
if(input_names[i])
{
vtr::free(input_names[i]);
}
}
}
vtr::free(input_names);
return to_return;
}
/*---------------------------------------------------------------------------------------------
* function:create_hard_block_nodes
to create the hard block nodes
*-------------------------------------------------------------------------------------------*/
void create_hard_block_nodes(hard_block_models *models, FILE *file, Hashtable *output_nets_hash)
{
char buffer[READ_BLIF_BUFFER];
char *subcircuit_name = vtr::strtok (NULL, TOKENS, file, buffer);
/* storing the names on the formal-actual parameter */
char *token;
int count = 0;
// Contains strings of the form port[pin]=port~pin
char **names_parameters = NULL;
while ((token = vtr::strtok (NULL, TOKENS, file, buffer)) != NULL)
{
names_parameters = (char**)vtr::realloc(names_parameters, sizeof(char*)*(count + 1));
names_parameters[count++] = vtr::strdup(token);
}
// Split the name parameters at the equals sign.
char **mappings = (char**)vtr::calloc(count, sizeof(char*));
char **names = (char**)vtr::calloc(count, sizeof(char*));
int i = 0;
for (i = 0; i < count; i++)
{
mappings[i] = vtr::strdup(strtok(names_parameters[i], "="));
names[i] = vtr::strdup(strtok(NULL, "="));
}
// Associate mappings with their connections.
Hashtable *mapping_index = associate_names(mappings, names, count);
// Sort the mappings.
qsort(mappings, count, sizeof(char *), compare_hard_block_pin_names);
for(i = 0; i < count; i++)
vtr::free(names_parameters[i]);
vtr::free(names_parameters);
// Index the mappings in a hard_block_ports struct.
hard_block_ports *ports = get_hard_block_ports(mappings, count);
for (i = 0; i < count; i++)
{
vtr::free(mappings[i]);
mappings[i] = NULL;
}
vtr::free(mappings);
mappings = NULL;
// Look up the model in the models cache.
hard_block_model *model = NULL;
if ((subcircuit_name != NULL) && (!(model = get_hard_block_model(subcircuit_name, ports, models))))
{
// If the model isn's present, scan ahead and find it.
model = read_hard_block_model(subcircuit_name, ports, file);
// Add it to the cache.
add_hard_block_model(model, ports, models);
}
nnode_t *new_node = allocate_nnode();
// Name the node subcircuit_name~hard_block_number so that the name is unique.
static long hard_block_number = 0;
odin_sprintf(buffer, "%s~%ld", subcircuit_name, hard_block_number++);
new_node->name = make_full_ref_name(buffer, NULL, NULL, NULL,-1);
// Determine the type of hard block.
char *subcircuit_name_prefix = vtr::strdup(subcircuit_name);
subcircuit_name_prefix[5] = '\0';
if (!strcmp(subcircuit_name, "multiply") || !strcmp(subcircuit_name_prefix, "mult_"))
new_node->type = MULTIPLY;
else if (!strcmp(subcircuit_name, "adder") || !strcmp(subcircuit_name_prefix, "adder"))
new_node->type = ADD;
else if (!strcmp(subcircuit_name, "sub") || !strcmp(subcircuit_name_prefix, "sub"))
new_node->type = MINUS;
else
{
new_node->type = MEMORY;
}
vtr::free(subcircuit_name_prefix);
/* Add input and output ports to the new node. */
{
hard_block_ports *p;
p = model->input_ports;
for (i = 0; i < p->count; i++)
add_input_port_information(new_node, p->sizes[i]);
p = model->output_ports;
for (i = 0; i < p->count; i++)
add_output_port_information(new_node, p->sizes[i]);
}
// Allocate pins positions.
if (model->inputs->count > 0)
allocate_more_input_pins (new_node, model->inputs->count);
if (model->outputs->count > 0)
allocate_more_output_pins(new_node, model->outputs->count);
// Add input pins.
for(i = 0; i < model->inputs->count; i++)
{
char *mapping = model->inputs->names[i];
char *name = (char *)mapping_index->get(mapping);
if (!name)
error_message(NETLIST_ERROR, file_line_number, current_parse_file, "Invalid hard block mapping: %s", mapping);
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(name);
new_pin->type = INPUT;
new_pin->mapping = get_hard_block_port_name(mapping);
add_input_pin_to_node(new_node, new_pin, i);
}
// Add output pins, nets, and index each net.
for(i = 0; i < model->outputs->count; i++)
{
char *mapping = model->outputs->names[i];
char *name = (char *)mapping_index->get(mapping);
if (!name) error_message(NETLIST_ERROR, file_line_number, current_parse_file,"Invalid hard block mapping: %s", model->outputs->names[i]);
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(name);
new_pin->type = OUTPUT;
new_pin->mapping = get_hard_block_port_name(mapping);
add_output_pin_to_node(new_node, new_pin, i);
nnet_t *new_net = allocate_nnet();
new_net->name = vtr::strdup(name);
add_driver_pin_to_net(new_net,new_pin);
// Index the net by name.
output_nets_hash->add(name, new_net);
}
// Create a fake ast node.
new_node->related_ast_node = (ast_node_t *)vtr::calloc(1, sizeof(ast_node_t));
new_node->related_ast_node->children = (ast_node_t **)vtr::calloc(1,sizeof(ast_node_t *));
new_node->related_ast_node->children[0] = (ast_node_t *)vtr::calloc(1, sizeof(ast_node_t));
new_node->related_ast_node->children[0]->types.identifier = vtr::strdup(subcircuit_name);
/*add this node to blif_netlist as an internal node */
blif_netlist->internal_nodes = (nnode_t **)vtr::realloc(blif_netlist->internal_nodes, sizeof(nnode_t*) * (blif_netlist->num_internal_nodes + 1));
blif_netlist->internal_nodes[blif_netlist->num_internal_nodes++] = new_node;
new_node->file_number = current_parse_file;
new_node->line_number = line_count;
free_hard_block_ports(ports);
mapping_index->destroy_free_items();
delete mapping_index;
vtr::free(names);
}
/*---------------------------------------------------------------------------------------------
* function:create_internal_node_and_driver
to create an internal node and driver from that node
*-------------------------------------------------------------------------------------------*/
void create_internal_node_and_driver(FILE *file, Hashtable *output_nets_hash)
{
/* Storing the names of the input and the final output in array names */
char *ptr = NULL;
char **names = NULL; // stores the names of the input and the output, last name stored would be of the output
int input_count = 0;
char buffer[READ_BLIF_BUFFER];
while ((ptr = vtr::strtok (NULL, TOKENS, file, buffer)))
{
names = (char**)vtr::realloc(names, sizeof(char*) * (input_count + 1));
names[input_count++]= vtr::strdup(ptr);
}
/* assigning the new_node */
nnode_t *new_node = allocate_nnode();
new_node->related_ast_node = NULL;
/* gnd vcc unconn already created as top module so ignore them */
if (
!strcmp(names[input_count-1],"gnd")
|| !strcmp(names[input_count-1],"vcc")
|| !strcmp(names[input_count-1],"unconn")
)
{
skip_reading_bit_map = true;
free_nnode(new_node);
}
else
{
/* assign the node type by seeing the name */
operation_list node_type = (operation_list)assign_node_type_from_node_name(names[input_count-1]);
if(node_type != GENERIC)
{
new_node->type = node_type;
skip_reading_bit_map = true;
}
/* Check for GENERIC type , change the node by reading the bit map */
else if(node_type == GENERIC)
{
new_node->type = (operation_list)read_bit_map_find_unknown_gate(input_count-1, new_node, file);
skip_reading_bit_map = true;
}
/* allocate the input pin (= input_count-1)*/
if (input_count-1 > 0) // check if there is any input pins
{
allocate_more_input_pins(new_node, input_count-1);
/* add the port information */
if(new_node->type == MUX_2)
{
add_input_port_information(new_node, (input_count-1)/2);
add_input_port_information(new_node, (input_count-1)/2);
}
else
{
int i;
for(i = 0; i < input_count-1; i++)
add_input_port_information(new_node, 1);
}
}
/* add names and type information to the created input pins */
int i;
for(i = 0; i <= input_count-2; i++)
{
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(names[i]);
new_pin->type = INPUT;
add_input_pin_to_node(new_node, new_pin, i);
}
/* add information for the intermediate VCC and GND node (appears in ABC )*/
if(new_node->type == GND_NODE)
{
allocate_more_input_pins(new_node,1);
add_input_port_information(new_node, 1);
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(GND_NAME);
new_pin->type = INPUT;
add_input_pin_to_node(new_node, new_pin,0);
}
if(new_node->type == VCC_NODE)
{
allocate_more_input_pins(new_node,1);
add_input_port_information(new_node, 1);
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(VCC_NAME);
new_pin->type = INPUT;
add_input_pin_to_node(new_node, new_pin,0);
}
/* allocate the output pin (there is always one output pin) */
allocate_more_output_pins(new_node, 1);
add_output_port_information(new_node, 1);
/* add a name for the node, keeping the name of the node same as the output */
new_node->name = make_full_ref_name(names[input_count-1],NULL, NULL, NULL,-1);
/*add this node to blif_netlist as an internal node */
blif_netlist->internal_nodes = (nnode_t**)vtr::realloc(blif_netlist->internal_nodes, sizeof(nnode_t*)*(blif_netlist->num_internal_nodes+1));
blif_netlist->internal_nodes[blif_netlist->num_internal_nodes++] = new_node;
new_node->file_number = current_parse_file;
new_node->line_number = line_count;
/*add name information and a net(driver) for the output */
npin_t *new_pin = allocate_npin();
new_pin->name = new_node->name;
new_pin->type = OUTPUT;
add_output_pin_to_node(new_node, new_pin, 0);
nnet_t *new_net = allocate_nnet();
new_net->name = new_node->name;
add_driver_pin_to_net(new_net,new_pin);
output_nets_hash->add(new_node->name, new_net);
}
/* Free the char** names */
for(int i = 0; i < input_count; i++)
vtr::free(names[i]);
vtr::free(names);
}
/*
*---------------------------------------------------------------------------------------------
* function: read_bit_map_find_unknown_gate
read the bit map for simulation
*-------------------------------------------------------------------------------------------*/
operation_list read_bit_map_find_unknown_gate(int input_count, nnode_t *node, FILE *file)
{
operation_list to_return = operation_list_END;
fpos_t pos;
int last_line = file_line_number;
const char *One = "1";
const char *Zero = "0";
fgetpos(file,&pos);
char **bit_map = NULL;
char *output_bit_map = NULL;// to distinguish whether for the bit_map output is 1 or 0
int line_count_bitmap = 0; //stores the number of lines in a particular bit map
char buffer[READ_BLIF_BUFFER];
if(!input_count)
{
vtr::fgets (buffer, READ_BLIF_BUFFER, file);
file_line_number = last_line;
fsetpos(file,&pos);
char *ptr = vtr::strtok(buffer,"\t\n", file, buffer);
if(!ptr)
{
to_return = GND_NODE;
}
else if(!strcmp(ptr," 1"))
{
to_return = VCC_NODE;
}
else if(!strcmp(ptr," 0"))
{
to_return = GND_NODE;
}
else
{
to_return = VCC_NODE;
}
}
else
{
while(1)
{
vtr::fgets (buffer, READ_BLIF_BUFFER, file);
if(!(buffer[0] == '0' || buffer[0] == '1' || buffer[0] == '-'))
break;
bit_map = (char**)vtr::realloc(bit_map,sizeof(char*) * (line_count_bitmap + 1));
bit_map[line_count_bitmap++] = vtr::strdup(vtr::strtok(buffer,TOKENS, file, buffer));
if (output_bit_map != NULL) vtr::free(output_bit_map);
output_bit_map = vtr::strdup(vtr::strtok(NULL,TOKENS, file, buffer));
}
oassert(output_bit_map);
file_line_number = last_line;
fsetpos(file,&pos);
/*Patern recognition for faster simulation*/
if(!strcmp(output_bit_map, One))
{
//On-gate recognition
//TODO move off-logic parts to appropriate code block
vtr::free(output_bit_map);
output_bit_map = vtr::strdup(One);
node->generic_output = 1;
/* Single line bit map : */
if(line_count_bitmap == 1)
{
// GT
if(!strcmp(bit_map[0],"100"))
{
to_return = GT;
}
// LT
else if(!strcmp(bit_map[0],"010"))
{
to_return = LT;
}
/* LOGICAL_AND and LOGICAL_NAND for ABC*/
else
{
int i;
for(i = 0; i < input_count && bit_map[0][i] == '1'; i++);
if(i == input_count)
{
if (!strcmp(output_bit_map,"1"))
{
to_return = LOGICAL_AND;
}
else if (!strcmp(output_bit_map,"0"))
{
to_return = LOGICAL_NAND;
}
}
/* BITWISE_NOT */
if(!strcmp(bit_map[0],"0") && to_return == operation_list_END)
{
to_return = BITWISE_NOT;
}
/* LOGICAL_NOR and LOGICAL_OR for ABC */
for(i = 0; i < input_count && bit_map[0][i] == '0'; i++);
if(i == input_count && to_return == operation_list_END)
{
if (!strcmp(output_bit_map,"1"))
{
to_return = LOGICAL_NOR;
}
else if (!strcmp(output_bit_map,"0"))
{
to_return = LOGICAL_OR;
}
}
}
}
/* Assumption that bit map is in order when read from blif */
else if(line_count_bitmap == 2)
{
/* LOGICAL_XOR */
if((strcmp(bit_map[0],"01")==0) && (strcmp(bit_map[1],"10")==0))
{
to_return = LOGICAL_XOR;
}
/* LOGICAL_XNOR */
else if((strcmp(bit_map[0],"00")==0) && (strcmp(bit_map[1],"11")==0))
{
to_return = LOGICAL_XNOR;
}
}
else if (line_count_bitmap == 4)
{
/* ADDER_FUNC */
if (
(!strcmp(bit_map[0],"001"))
&& (!strcmp(bit_map[1],"010"))
&& (!strcmp(bit_map[2],"100"))
&& (!strcmp(bit_map[3],"111"))
)
{
to_return = ADDER_FUNC;
}
/* CARRY_FUNC */
else if(
(!strcmp(bit_map[0],"011"))
&& (!strcmp(bit_map[1],"101"))
&& (!strcmp(bit_map[2],"110"))
&& (!strcmp(bit_map[3],"111"))
)
{
to_return = CARRY_FUNC;
}
/* LOGICAL_XOR */
else if(
(!strcmp(bit_map[0],"001"))
&& (!strcmp(bit_map[1],"010"))
&& (!strcmp(bit_map[2],"100"))
&& (!strcmp(bit_map[3],"111"))
)
{
to_return = LOGICAL_XOR;
}
/* LOGICAL_XNOR */
else if(
(!strcmp(bit_map[0],"000"))
&& (!strcmp(bit_map[1],"011"))
&& (!strcmp(bit_map[2],"101"))
&& (!strcmp(bit_map[3],"110"))
)
{
to_return = LOGICAL_XNOR;
}
}
if(line_count_bitmap == input_count && to_return == operation_list_END)
{
/* LOGICAL_OR */
int i;
for(i = 0; i < line_count_bitmap; i++)
{
if(bit_map[i][i] == '1')
{
int j;
for(j = 1; j < input_count; j++)
{
if(bit_map[i][(i+j)% input_count]!='-')
{
break;
}
}
if(j != input_count)
{
break;
}
}
else
{
break;
}
}
if(i == line_count_bitmap)
{
to_return = LOGICAL_OR;
}
else
{
/* LOGICAL_NAND */
for(i = 0; i < line_count_bitmap; i++)
{
if(bit_map[i][i]=='0')
{
int j;
for(j = 1; j < input_count; j++)
{
if(bit_map[i][(i+j)% input_count]!='-')
{
break;
}
}
if(j != input_count)
{
break;
}
}
else
{
break;
}
}
if(i == line_count_bitmap)
{
to_return = LOGICAL_NAND;
}
}
}
/* MUX_2 */
if(line_count_bitmap*2 == input_count && to_return == operation_list_END)
{
int i;
for(i = 0; i < line_count_bitmap; i++)
{
if((bit_map[i][i]=='1') && (bit_map[i][i+line_count_bitmap] =='1'))
{
int j;
for (j = 1; j < line_count_bitmap; j++)
{
if (
(bit_map[i][ (i+j) % line_count_bitmap] != '-')
|| (bit_map[i][((i+j) % line_count_bitmap) + line_count_bitmap] != '-')
)
{
break;
}
}
if(j != input_count)
{
break;
}
}
else
{
break;
}
}
if(i == line_count_bitmap)
{
to_return = MUX_2;
}
}
}
else
{
//Off-gate recognition
//TODO
vtr::free(output_bit_map);
output_bit_map = vtr::strdup(Zero);
node->generic_output = 0;
}
/* assigning the bit_map to the node if it is GENERIC */
if(to_return == operation_list_END)
{
node->bit_map = bit_map;
node->bit_map_line_count = line_count_bitmap;
to_return = GENERIC;
}
}
if(output_bit_map)
{
vtr::free(output_bit_map);
}
if(bit_map)
{
for(int i = 0; i < line_count_bitmap; i++)
{
vtr::free(bit_map[i]);
}
vtr::free(bit_map);
}
return to_return;
}
/*
*---------------------------------------------------------------------------------------------
* function: add_top_input_nodes
to add the top level inputs to the netlist
*-------------------------------------------------------------------------------------------*/
static void build_top_input_node(const char *name_str, Hashtable *output_nets_hash)
{
char *temp_string = make_full_ref_name(name_str, NULL, NULL,NULL, -1);
/* create a new top input node and net*/
nnode_t *new_node = allocate_nnode();
new_node->related_ast_node = NULL;
new_node->type = INPUT_NODE;
/* add the name of the input variable */
new_node->name = temp_string;
new_node->file_number = current_parse_file;
new_node->line_number = line_count;
/* allocate the pins needed */
allocate_more_output_pins(new_node, 1);
add_output_port_information(new_node, 1);
/* Create the pin connection for the net */
npin_t *new_pin = allocate_npin();
new_pin->name = vtr::strdup(temp_string);
new_pin->type = OUTPUT;
/* hookup the pin, net, and node */
add_output_pin_to_node(new_node, new_pin, 0);
nnet_t *new_net = allocate_nnet();
new_net->name = vtr::strdup(temp_string);
add_driver_pin_to_net(new_net, new_pin);
blif_netlist->top_input_nodes = (nnode_t**)vtr::realloc(blif_netlist->top_input_nodes, sizeof(nnode_t*)*(blif_netlist->num_top_input_nodes+1));
blif_netlist->top_input_nodes[blif_netlist->num_top_input_nodes++] = new_node;
//long sc_spot = sc_add_string(output_nets_sc, temp_string);
//if (output_nets_sc->data[sc_spot])
//warning_message(NETLIST_ERROR,linenum,-1, "Net (%s) with the same name already created\n",temp_string);
//output_nets_sc->data[sc_spot] = new_net;
output_nets_hash->add(temp_string, new_net);
}
void add_top_input_nodes(FILE *file, Hashtable *output_nets_hash)
{
/**
* insert a global clock for fall back.
* in case of undriven internal clocks, they will attach to the global clock
* this also fix the issue of constant verilog (no input)
* that cannot simulate due to empty input vector
*/
if(insert_global_clock)
{
insert_global_clock = false;
build_top_input_node(DEFAULT_CLOCK_NAME, output_nets_hash);
}
char *ptr;
char buffer[READ_BLIF_BUFFER];
while ((ptr = vtr::strtok (NULL, TOKENS, file, buffer)))
{
build_top_input_node(ptr, output_nets_hash);
}
}
/*---------------------------------------------------------------------------------------------
* function: create_top_output_nodes
to add the top level outputs to the netlist
*-------------------------------------------------------------------------------------------*/
void rb_create_top_output_nodes(FILE *file)
{
char *ptr;
char buffer[READ_BLIF_BUFFER];
while ((ptr = vtr::strtok (NULL, TOKENS, file, buffer)))
{
char *temp_string = make_full_ref_name(ptr, NULL, NULL,NULL, -1);;
/*add_a_fanout_pin_to_net((nnet_t*)output_nets_sc->data[sc_spot], new_pin);*/
/* create a new top output node and */
nnode_t *new_node = allocate_nnode();
new_node->related_ast_node = NULL;
new_node->type = OUTPUT_NODE;
/* add the name of the output variable */
new_node->name = temp_string;
/* allocate the input pin needed */
allocate_more_input_pins(new_node, 1);
add_input_port_information(new_node, 1);
/* Create the pin connection for the net */
npin_t *new_pin = allocate_npin();
new_pin->name = temp_string;
/* hookup the pin, net, and node */
add_input_pin_to_node(new_node, new_pin, 0);
/*adding the node to the blif_netlist output nodes
add_node_to_netlist() function can also be used */
blif_netlist->top_output_nodes = (nnode_t**)vtr::realloc(blif_netlist->top_output_nodes, sizeof(nnode_t*)*(blif_netlist->num_top_output_nodes+1));
blif_netlist->top_output_nodes[blif_netlist->num_top_output_nodes++] = new_node;
new_node->file_number = current_parse_file;
new_node->line_number = line_count;
}
}
/*---------------------------------------------------------------------------------------------
* (function: look_for_clocks)
*-------------------------------------------------------------------------------------------*/
void rb_look_for_clocks()
{
int i;
for (i = 0; i < blif_netlist->num_ff_nodes; i++)
{
if (blif_netlist->ff_nodes[i]->input_pins[1]->net->driver_pin->node->type != CLOCK_NODE)
{
blif_netlist->ff_nodes[i]->input_pins[1]->net->driver_pin->node->type = CLOCK_NODE;
}
}
}
/*
----------------------------------------------------------------------------
function: Creates the drivers for the top module
Top module is :
* Special as all inputs are actually drivers.
* Also make the 0 and 1 constant nodes at this point.
---------------------------------------------------------------------------
*/
void rb_create_top_driver_nets(const char *instance_name_prefix, Hashtable *output_nets_hash)
{
npin_t *new_pin;
/* create the constant nets */
/* ZERO net */
/* description given for the zero net is same for other two */
blif_netlist->zero_net = allocate_nnet(); // allocate memory to net pointer
blif_netlist->gnd_node = allocate_nnode(); // allocate memory to node pointer
blif_netlist->gnd_node->type = GND_NODE; // mark the type
allocate_more_output_pins(blif_netlist->gnd_node, 1);// alloacate 1 output pin pointer to this node
add_output_port_information(blif_netlist->gnd_node, 1);// add port info. this port has 1 pin ,till now number of port for this is one
new_pin = allocate_npin();
add_output_pin_to_node(blif_netlist->gnd_node, new_pin, 0);// add this pin to output pin pointer array of this node
add_driver_pin_to_net(blif_netlist->zero_net,new_pin);// add this pin to net as driver pin
/*ONE net*/
blif_netlist->one_net = allocate_nnet();
blif_netlist->vcc_node = allocate_nnode();
blif_netlist->vcc_node->type = VCC_NODE;
allocate_more_output_pins(blif_netlist->vcc_node, 1);
add_output_port_information(blif_netlist->vcc_node, 1);
new_pin = allocate_npin();
add_output_pin_to_node(blif_netlist->vcc_node, new_pin, 0);
add_driver_pin_to_net(blif_netlist->one_net, new_pin);
/* Pad net */
blif_netlist->pad_net = allocate_nnet();
blif_netlist->pad_node = allocate_nnode();
blif_netlist->pad_node->type = PAD_NODE;
allocate_more_output_pins(blif_netlist->pad_node, 1);
add_output_port_information(blif_netlist->pad_node, 1);
new_pin = allocate_npin();
add_output_pin_to_node(blif_netlist->pad_node, new_pin, 0);
add_driver_pin_to_net(blif_netlist->pad_net, new_pin);
/* CREATE the driver for the ZERO */
blif_netlist->zero_net->name = make_full_ref_name(instance_name_prefix, NULL, NULL, zero_string, -1);
output_nets_hash->add(GND_NAME, blif_netlist->zero_net);
/* CREATE the driver for the ONE and store twice */
blif_netlist->one_net->name = make_full_ref_name(instance_name_prefix, NULL, NULL, one_string, -1);
output_nets_hash->add(VCC_NAME, blif_netlist->one_net);
/* CREATE the driver for the PAD */
blif_netlist->pad_net->name = make_full_ref_name(instance_name_prefix, NULL, NULL, pad_string, -1);
output_nets_hash->add(HBPAD_NAME, blif_netlist->pad_net);
blif_netlist->vcc_node->name = vtr::strdup(VCC_NAME);
blif_netlist->gnd_node->name = vtr::strdup(GND_NAME);
blif_netlist->pad_node->name = vtr::strdup(HBPAD_NAME);
}
/*---------------------------------------------------------------------------------------------
* (function: dum_parse)
*-------------------------------------------------------------------------------------------*/
static void dum_parse (char *buffer, FILE *file)
{
/* Continue parsing to the end of this (possibly continued) line. */
while (vtr::strtok (NULL, TOKENS, file, buffer));
}
/*---------------------------------------------------------------------------------------------
* function: hook_up_nets()
* find the output nets and add the corresponding nets
*-------------------------------------------------------------------------------------------*/
void hook_up_nets(Hashtable *output_nets_hash)
{
nnode_t **node_sets[] = {blif_netlist->internal_nodes, blif_netlist->ff_nodes, blif_netlist->top_output_nodes};
int counts[] = {blif_netlist->num_internal_nodes, blif_netlist->num_ff_nodes, blif_netlist->num_top_output_nodes};
int num_sets = 3;
/* hook all the input pins in all the internal nodes to the net */
int i;
for (i = 0; i < num_sets; i++)
{
int j;
for(j = 0; j < counts[i]; j++)
{
nnode_t *node = node_sets[i][j];
hook_up_node(node, output_nets_hash);
}
}
}
/*
* Connect the given node's input pins to their corresponding nets by
* looking each one up in the output_nets_sc.
*/
void hook_up_node(nnode_t *node, Hashtable *output_nets_hash)
{
int j;
for(j = 0; j < node->num_input_pins; j++)
{
npin_t *input_pin = node->input_pins[j];
nnet_t *output_net = (nnet_t *)output_nets_hash->get(input_pin->name);
if(!output_net)
error_message(NETLIST_ERROR,file_line_number, current_parse_file, "Error: Could not hook up the pin %s: not available.", input_pin->name);
add_fanout_pin_to_net(output_net, input_pin);
}
}
/*
* Scans ahead in the given file to find the
* model for the hard block by the given name.
* Returns the file to its original position when finished.
*/
hard_block_model *read_hard_block_model(char *name_subckt, hard_block_ports *ports, FILE *file)
{
// Store the current position in the file.
fpos_t pos;
int last_line = file_line_number;
fgetpos(file,&pos);
hard_block_model *model;
while(1) {
model = NULL;
// Search the file for .model followed buy the subcircuit name.
char buffer[READ_BLIF_BUFFER];
while (vtr::fgets(buffer, READ_BLIF_BUFFER, file))
{
char *token = vtr::strtok(buffer,TOKENS, file, buffer);
// match .model followed by the subcircuit name.
if (token && !strcmp(token,".model") && !strcmp(vtr::strtok(NULL,TOKENS, file, buffer), name_subckt))
{
model = (hard_block_model *)vtr::calloc(1, sizeof(hard_block_model));
model->name = vtr::strdup(name_subckt);
model->inputs = (hard_block_pins *)vtr::calloc(1, sizeof(hard_block_pins));
model->inputs->count = 0;
model->inputs->names = NULL;
model->outputs = (hard_block_pins *)vtr::calloc(1, sizeof(hard_block_pins));
model->outputs->count = 0;
model->outputs->names = NULL;
// Read the inputs and outputs.
while (vtr::fgets(buffer, READ_BLIF_BUFFER, file))
{
char *first_word = vtr::strtok(buffer, TOKENS, file, buffer);
if(first_word)
{
if(!strcmp(first_word, ".inputs"))
{
char *name;
while ((name = vtr::strtok(NULL, TOKENS, file, buffer)))
{
model->inputs->names = (char **)vtr::realloc(model->inputs->names, sizeof(char *) * (model->inputs->count + 1));
model->inputs->names[model->inputs->count++] = vtr::strdup(name);
}
}
else if(!strcmp(first_word, ".outputs"))
{
char *name;
while ((name = vtr::strtok(NULL, TOKENS, file, buffer)))
{
model->outputs->names = (char **)vtr::realloc(model->outputs->names, sizeof(char *) * (model->outputs->count + 1));
model->outputs->names[model->outputs->count++] = vtr::strdup(name);
}
}
else if(!strcmp(first_word, ".end"))
{
break;
}
}
}
break;
}
}
if(!model || feof(file))
error_message(NETLIST_ERROR, last_line, current_parse_file, "A subcircuit model for '%s' with matching ports was not found.",name_subckt);
// Sort the names.
qsort(model->inputs->names, model->inputs->count, sizeof(char *), compare_hard_block_pin_names);
qsort(model->outputs->names, model->outputs->count, sizeof(char *), compare_hard_block_pin_names);
// Index the names.
model->inputs->index = index_names(model->inputs->names, model->inputs->count);
model->outputs->index = index_names(model->outputs->names, model->outputs->count);
// Organise the names into ports.
model->input_ports = get_hard_block_ports(model->inputs->names, model->inputs->count);
model->output_ports = get_hard_block_ports(model->outputs->names, model->outputs->count);
// Check that the model we've read matches the ports of the instance we are trying to match.
if (verify_hard_block_ports_against_model(ports, model))
{
break;
}
else
{ // If not, free it, and keep looking.
free_hard_block_model(model);
}
}
// Restore the original position in the file.
file_line_number = last_line;
fsetpos(file,&pos);
return model;
}
/*
* Callback function for qsort which compares pin names
* of the form port_name[pin_number] primarily
* on the port_name, and on the pin_number if the port_names
* are identical.
*/
static int compare_hard_block_pin_names(const void *p1, const void *p2)
{
char *name1 = *(char * const *)p1;
char *name2 = *(char * const *)p2;
char *port_name1 = get_hard_block_port_name(name1);
char *port_name2 = get_hard_block_port_name(name2);
int portname_difference = strcmp(port_name1, port_name2);
vtr::free(port_name1);
vtr::free(port_name2);
// If the portnames are the same, compare the pin numbers.
if (!portname_difference)
{
int n1 = get_hard_block_pin_number(name1);
int n2 = get_hard_block_pin_number(name2);
return n1 - n2;
}
else
{
return portname_difference;
}
}
/*
* Creates a hashtable index for an array of strings of
* the form names[i]=>i.
*/
Hashtable *index_names(char **names, int count)
{
Hashtable *index = new Hashtable();
for (long i = 0; i < count; i++)
{
int *offset = (int *)vtr::calloc(1, sizeof(int));
*offset = i;
index->add(names[i], offset);
}
return index;
}
/*
* Create an associative index of names1[i]=>names2[i]
*/
Hashtable *associate_names(char **names1, char **names2, int count)
{
Hashtable *index = new Hashtable();
for (long i = 0; i < count; i++)
index->add(names1[i], names2[i]);
return index;
}
/*
* Organises the given strings representing pin names on a hard block
* model into ports, and indexes the ports by name. Returns the organised
* ports as a hard_block_ports struct.
*/
hard_block_ports *get_hard_block_ports(char **pins, int count)
{
// Count the input port sizes.
hard_block_ports *ports = (hard_block_ports *)vtr::calloc(1, sizeof(hard_block_ports));
ports->count = 0;
ports->sizes = NULL;
ports->names = NULL;
char *prev_portname = NULL;
int i;
for (i = 0; i < count; i++)
{
char *portname = get_hard_block_port_name(pins[i]);
// Compare the part of the name before the "["
if (!i || strcmp(prev_portname, portname))
{
ports->sizes = (int *)vtr::realloc(ports->sizes, sizeof(int) * (ports->count + 1));
ports->names = (char **)vtr::realloc(ports->names, sizeof(char *) * (ports->count + 1));
ports->sizes[ports->count] = 0;
ports->names[ports->count] = vtr::strdup(portname);
ports->count++;
}
if ( prev_portname != NULL )
vtr::free(prev_portname);
prev_portname = portname;
ports->sizes[ports->count-1]++;
}
if ( prev_portname != NULL )
vtr::free(prev_portname);
ports->signature = generate_hard_block_ports_signature(ports);
ports->index = index_names(ports->names, ports->count);
return ports;
}
/*
* Check for inconsistencies between the hard block model and the ports found
* in the hard block instance. Returns false if differences are found.
*/
int verify_hard_block_ports_against_model(hard_block_ports *ports, hard_block_model *model)
{
hard_block_ports *port_sets[] = {model->input_ports, model->output_ports};
int i;
for (i = 0; i < 2; i++)
{
hard_block_ports *p = port_sets[i];
int j;
for (j = 0; j < p->count; j++)
{
// Look up each port from the model in "ports"
char *name = p->names[j];
int size = p->sizes[j];
int *idx = (int *)ports->index->get(name);
// Model port not specified in ports.
if (!idx)
{
//printf("Model port not specified in ports. %s\n", name);
return false;
}
// Make sure they match in size.
int instance_size = ports->sizes[*idx];
// Port sizes differ.
if (size != instance_size)
{
//printf("Port sizes differ. %s\n", name);
return false;
}
}
}
hard_block_ports *in = model->input_ports;
hard_block_ports *out = model->output_ports;
int j;
for (j = 0; j < ports->count; j++)
{
// Look up each port from the subckt to make sure it appears in the model.
char *name = ports->names[j];
int *in_idx = (int *)in->index->get(name);
int *out_idx = (int *)out->index->get(name);
// Port does not appear in the model.
if (!in_idx && !out_idx)
{
//printf("Port does not appear in the model. %s\n", name);
return false;
}
}
return true;
}
/*
* Generates string which represents the geometry of the given hard block ports.
*/
char *generate_hard_block_ports_signature(hard_block_ports *ports)
{
char buffer[READ_BLIF_BUFFER];
buffer[0] = '\0';
strcat(buffer, "_");
int j;
for (j = 0; j < ports->count; j++)
{
char buffer1[READ_BLIF_BUFFER];
odin_sprintf(buffer1, "%s_%d_", ports->names[j], ports->sizes[j]);
strcat(buffer, buffer1);
}
return vtr::strdup(buffer);
}
/*
* Gets the text in the given string which occurs
* before the first instance of "[". The string is
* presumably of the form "port[pin_number]"
*
* The retuned string is strduped and must be freed.
* The original string is unaffected.
*/
char *get_hard_block_port_name(char *name)
{
name = vtr::strdup(name);
if (strchr(name,'['))
return strtok(name,"[");
else
return name;
}
/*
* Parses a port name of the form port[pin_number]
* and returns the pin number as a long. Returns -1
* if there is no [pin_number] in the name. Throws an
* error if pin_number is not parsable as a long.
*
* The original string is unaffected.
*/
long get_hard_block_pin_number(char *original_name)
{
if (!strchr(original_name,'['))
return -1;
char *name = vtr::strdup(original_name);
strtok(name,"[");
char *endptr;
char *pin_number_string = strtok(NULL,"]");
long pin_number = strtol(pin_number_string, &endptr, 10);
if (pin_number_string == endptr)
error_message(NETLIST_ERROR,file_line_number, current_parse_file,"The given port name \"%s\" does not contain a valid pin number.", original_name);
vtr::free(name);
return pin_number;
}
/*
* Adds the given model to the hard block model cache.
*/
void add_hard_block_model(hard_block_model *m, hard_block_ports *ports, hard_block_models *models)
{
if(models && m)
{
char needle[READ_BLIF_BUFFER] = { 0 };
if(m->name && ports && ports->signature)
sprintf(needle, "%s%s", m->name, ports->signature);
else if(m->name)
sprintf(needle, "%s", m->name);
else if(ports && ports->signature)
sprintf(needle, "%s", ports->signature);
if(strlen(needle) > 0)
{
models->count += 1;
models->models = (hard_block_model **)vtr::realloc(models->models, models->count * sizeof(hard_block_model *));
models->models[models->count-1] = m;
models->index->add(needle, m);
}
}
}
/*
* Looks up a hard block model by name. Returns null if the
* model is not found.
*/
hard_block_model *get_hard_block_model(char *name, hard_block_ports *ports, hard_block_models *models)
{
hard_block_model *to_return = NULL;
char needle[READ_BLIF_BUFFER] = { 0 };
if(name && ports && ports->signature)
sprintf(needle, "%s%s", name, ports->signature);
else if(name)
sprintf(needle, "%s", name);
else if(ports && ports->signature)
sprintf(needle, "%s", ports->signature);
if(strlen(needle) > 0)
to_return = (hard_block_model *)models->index->get(needle);
return to_return;
}
/*
* Creates a new hard block model cache.
*/
hard_block_models *create_hard_block_models()
{
hard_block_models *m = (hard_block_models *)vtr::calloc(1, sizeof(hard_block_models));
m->models = NULL;
m->count = 0;
m->index = new Hashtable();
return m;
}
/*
* Counts the number of lines in the given blif file
* before a .end token is hit.
*/
int count_blif_lines(FILE *file)
{
int num_lines = 0;
char buffer[READ_BLIF_BUFFER];
while (vtr::fgets(buffer, READ_BLIF_BUFFER, file))
{
if (strstr(buffer, ".end"))
break;
num_lines++;
}
rewind(file);
return num_lines;
}
/*
* Frees the hard block model cache, freeing
* all encapsulated hard block models.
*/
void free_hard_block_models(hard_block_models *models)
{
//does not delete the items in the hash
delete models->index;
int i;
for (i = 0; i < models->count; i++)
free_hard_block_model(models->models[i]);
vtr::free(models->models);
vtr::free(models);
}
/*
* Frees a hard_block_model.
*/
void free_hard_block_model(hard_block_model *model)
{
free_hard_block_pins(model->inputs);
free_hard_block_pins(model->outputs);
free_hard_block_ports(model->input_ports);
free_hard_block_ports(model->output_ports);
vtr::free(model->name);
vtr::free(model);
}
/*
* Frees hard_block_pins
*/
void free_hard_block_pins(hard_block_pins *p)
{
while (p->count--)
vtr::free(p->names[p->count]);
vtr::free(p->names);
p->index->destroy_free_items();
delete p->index;
vtr::free(p);
}
/*
* Frees hard_block_ports
*/
void free_hard_block_ports(hard_block_ports *p)
{
while(p->count--)
vtr::free(p->names[p->count]);
vtr::free(p->signature);
vtr::free(p->names);
vtr::free(p->sizes);
p->index->destroy_free_items();
delete p->index;
vtr::free(p);
}