#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "read_blif.h"
#include "arch_types.h"

/* PRINT_PIN_NETS */

/* TODO: use hash table instead of this to keep data structures consistent */
#define HASHSIZE 4093

#define MAX_ATOM_PARSE 200000000

/* This source file will read in a FLAT blif netlist consisting     *
* of .inputs, .outputs, .names and .latch commands.  It currently   *
* does not handle hierarchical blif files.  Hierarchical            *
* blif files can be flattened via the read_blif and write_blif      *
* commands of sis.  LUT circuits should only have .names commands;  *
* there should be no gates.  This parser performs limited error     *
* checking concerning the consistency of the netlist it obtains.    *
* .inputs and .outputs statements must be given; this parser does   *
* not infer primary inputs and outputs from non-driven and fanout   *
* free nodes.  This parser can be extended to do this if necessary, *
* or the sis read_blif and write_blif commands can be used to put a *
* netlist into the standard format.                                 *
* V. Betz, August 25, 1994.                                         *
* Added more error checking, March 30, 1995, V. Betz                */


static int *num_driver, *temp_num_pins;
static int *logical_block_input_count, *logical_block_output_count;
static int num_blif_models;

/* # of .input, .output, .model and .end lines */
static int ilines, olines, model_lines, endlines;
static struct hash_logical_nets **hash;
static char *model;
static FILE *blif;

static int add_vpack_net(char *ptr,
		   int type,
		   int bnum,
		   int bport,
		   int bpin,
		   	boolean is_global,
		   int doall);
static void get_tok(char *buffer,
		    int pass,
		    int doall,
			boolean *done,
		    boolean *add_truth_table,
			INP t_model* inpad_model, 
			INP t_model* outpad_model, 
			INP t_model* logic_model, 
			INP t_model* latch_model,
			INP t_model* user_models);
static void init_parse(int doall);
static void check_net(boolean sweep_hanging_nets_and_inputs);
static void free_parse(void);
static void io_line(int in_or_out,
		    int doall, t_model *io_model);
static void add_lut(int doall,
	t_model *logic_model);
static void add_latch(int doall, INP t_model *latch_model);
static void add_subckt(int doall, INP t_model *user_models);
static void dum_parse(char *buf);
static int hash_value(char *name);
static void check_and_count_models(int doall, const char* model_name, t_model* user_models);
static void load_default_models(INP t_model *library_models, OUTP t_model** inpad_model, OUTP t_model** outpad_model, 
					OUTP t_model** logic_model, OUTP t_model** latch_model);

void
read_blif(char *blif_file,
	  boolean sweep_hanging_nets_and_inputs,
	  t_model *user_models,
	  t_model *library_models)
{
    char buffer[BUFSIZE];
    int pass, doall;
	boolean done;
	boolean add_truth_table;
	t_model *inpad_model, *outpad_model, *logic_model, *latch_model;

	
    blif = fopen(blif_file, "r");
	if(blif == NULL) {
		printf("Failed to open blif file %s\n", blif_file);
		exit(1);
	}
	load_default_models(library_models, &inpad_model, &outpad_model, &logic_model, &latch_model);

	/* doall = 0 means do a counting pass, doall = 1 means allocate and load data structures */
    for(doall = 0; doall <= 1; doall++)
	{
		init_parse(doall);

/* Three passes to ensure inputs are first blocks, outputs second and    *
 * LUTs and latches third, subckts last.  Just makes the output netlist more readable. */

	    for(pass = 0; pass <= 4; pass++) 
		{
		    linenum = 0;	/* Reset line number. */
			done = FALSE;
			add_truth_table = FALSE;
			model_lines = 0;
			while(my_fgets(buffer, BUFSIZE, blif) != NULL)
			{
				get_tok(buffer, pass, doall, &done, &add_truth_table, inpad_model, outpad_model, logic_model, latch_model, user_models);
			}
		    rewind(blif);	/* Start at beginning of file again */
		}
	}
    fclose(blif);
    check_net(sweep_hanging_nets_and_inputs);
    free_parse();
}

static void
init_parse(int doall)
{

/* Allocates and initializes the data structures needed for the parse. */

    int i;
    struct hash_logical_nets *h_ptr;

    if(!doall)
	{			/* Initialization before first (counting) pass */
	    num_logical_nets = 0;
		/* TODO: use hash table instead of this  */
	    hash = (struct hash_logical_nets **)my_calloc(sizeof(struct hash_logical_nets *), HASHSIZE);
	}
/* Allocate memory for second (load) pass */
    else
	{
	    vpack_net = (struct s_net *)my_calloc(num_logical_nets, sizeof(struct s_net));
	    logical_block = (struct s_logical_block *)my_calloc(num_logical_blocks, sizeof(struct s_logical_block));
		num_driver = (int *)my_malloc(num_logical_nets * sizeof(int));
	    temp_num_pins = (int *)my_malloc(num_logical_nets * sizeof(int));

		logical_block_input_count = my_calloc(num_logical_blocks, sizeof(int));
		logical_block_output_count = my_calloc(num_logical_blocks, sizeof(int));
		

	    for(i = 0; i < num_logical_nets; i++)
		{
		    num_driver[i] = 0;
			vpack_net[i].num_sinks = 0;
			vpack_net[i].name = NULL;
			vpack_net[i].node_block = NULL;
			vpack_net[i].node_block_port = NULL;
			vpack_net[i].node_block_pin = NULL;
			vpack_net[i].is_global = FALSE;
		}

		for(i = 0; i < num_logical_blocks; i++)
		{
		    logical_block[i].index = i;
		}


		for(i = 0; i < HASHSIZE; i++)
		{
		    h_ptr = hash[i];
		    while(h_ptr != NULL)
			{
			    vpack_net[h_ptr->index].node_block = (int *)my_malloc(h_ptr->count * sizeof(int));
				vpack_net[h_ptr->index].node_block_port = (int *)my_malloc(h_ptr->count * sizeof(int));
				vpack_net[h_ptr->index].node_block_pin = (int *)my_malloc(h_ptr->count * sizeof(int));

/* For avoiding assigning values beyond end of pins array. */
			    temp_num_pins[h_ptr->index] = h_ptr->count;
			    vpack_net[h_ptr->index].name = my_strdup(h_ptr->name);
			    h_ptr = h_ptr->next;
			}
		}
#ifdef PRINT_PIN_NETS
		printf("i\ttemp_num_pins\n\n");
		for (i=0;i<num_logical_nets;i++) {
		   printf("%d\t%d\n",i,temp_num_pins[i]);
		}  
		printf("num_logical_nets %d\n", num_logical_nets);
#endif
	}

/* Initializations for both passes. */

    ilines = 0;
    olines = 0;
    model_lines = 0;
    endlines = 0;
    num_p_inputs = 0;
    num_p_outputs = 0;
    num_luts = 0;
    num_latches = 0;
    num_logical_blocks = 0;
	num_blif_models = 0;
    num_subckts = 0;
}


static void
get_tok(char *buffer,
	int pass,
	int doall,
	boolean *done,
	boolean *add_truth_table,
	INP t_model* inpad_model, 
	INP t_model* outpad_model, 
	INP t_model* logic_model, 
	INP t_model* latch_model,
	INP t_model* user_models)
{

/* Figures out which, if any token is at the start of this line and *
 * takes the appropriate action.                                    */

#define TOKENS " \t\n"
    char *ptr;
	char *fn;
	struct s_linked_vptr *data;

    ptr = my_strtok(buffer, TOKENS, blif, buffer);
    if(ptr == NULL)
		return;

	if(*add_truth_table) {
		if(ptr[0] == '0' || ptr[0] == '1' || ptr[0] == '-') {
			data = my_malloc(sizeof(struct s_linked_vptr));
			fn = ptr;
			ptr = my_strtok(NULL, TOKENS, blif, buffer);
			if(!ptr || strlen(ptr) != 1) {
				if(strlen(fn) == 1) {
					/* constant generator */
					data->next = logical_block[num_logical_blocks - 1].truth_table;
					data->data_vptr = my_malloc(strlen(fn) + 4);
					sprintf(data->data_vptr, " %s", fn);
					logical_block[num_logical_blocks - 1].truth_table = data;
					ptr = fn;
				} else {
					printf(ERRTAG "Unknown truth table data %s %s\n", fn, ptr);
					exit(1);
				}
			} else {
				data->next = logical_block[num_logical_blocks - 1].truth_table;
				data->data_vptr = my_malloc(strlen(fn) + 3);
				sprintf(data->data_vptr, "%s %s", fn, ptr);
				logical_block[num_logical_blocks - 1].truth_table = data;
			}
		}
	}

    if(strcmp(ptr, ".names") == 0)
	{
		*add_truth_table = FALSE;
	    if(pass == 3)
		{
		    add_lut(doall, logic_model);
			*add_truth_table = doall;
		}
	    else
		{
		    dum_parse(buffer);
		}
	    return;
	}

    if(strcmp(ptr, ".latch") == 0)
	{
		*add_truth_table = FALSE;
	    if(pass == 3)
		{
		    add_latch(doall, latch_model);
		}
	    else
		{
		    dum_parse(buffer);
		}
	    return;
	}

    if(strcmp(ptr, ".model") == 0)
	{
		*add_truth_table = FALSE;
	    ptr = my_strtok(NULL, TOKENS, blif, buffer);
		if(doall && pass == 4)
		{		
		    if(ptr != NULL)
			{
			    model = (char *)my_malloc((strlen(ptr) + 1) * sizeof(char));
			    strcpy(model, ptr);
				if(blif_circuit_name == NULL) {
					blif_circuit_name = my_strdup(model);
				}
			}
		    else
			{
			    model = (char *)my_malloc(sizeof(char));
			    model[0] = '\0';
			}
		}
		
		if(pass == 0 && model_lines > 0) {
			check_and_count_models(doall, ptr, user_models);
		} else {
			dum_parse(buffer);
		}
		model_lines++;
	    return;
	}

    if(strcmp(ptr, ".inputs") == 0)
	{
		*add_truth_table = FALSE;
		/* packing can only one fully defined model */
	    if(pass == 1 && model_lines == 1)
		{
		    io_line(DRIVER, doall, inpad_model);
		    *done = 1;
		}
	    else
		{
		    dum_parse(buffer);
		    if(pass == 4 && doall)
				ilines++;	/* Error checking only */
		}
	    return;
	}

    if(strcmp(ptr, ".outputs") == 0)
	{
		*add_truth_table = FALSE;
		/* packing can only one fully defined model */
	    if(pass == 2  && model_lines == 1)
		{
		    io_line(RECEIVER, doall, outpad_model);
		    *done = 1;
		}
	    else
		{
		    dum_parse(buffer);
		    if(pass == 4 && doall)
				olines++;	/* Make sure only one .output line */
		}		/* For error checking only */
	    return;
	}
    if(strcmp(ptr, ".end") == 0)
	{
		*add_truth_table = FALSE;
		if(pass == 4 && doall)
		{
			endlines++;	/* Error checking only */
		}
		return;
	}

	if(strcmp(ptr, ".subckt") == 0)
	{
		*add_truth_table = FALSE;
		if(pass == 3)
		{
			add_subckt(doall, user_models);
		}
	}

/* Could have numbers following a .names command, so not matching any *
 * of the tokens above is not an error.                               */

}


static void
dum_parse(char *buf)
{

/* Continue parsing to the end of this (possibly continued) line. */

    while(my_strtok(NULL, TOKENS, blif, buf) != NULL)
		;
}


static void
add_lut(int doall,
	t_model *logic_model)
{

/* Adds a LUT as VPACK_COMB from (.names) currently being parsed to the logical_block array.  Adds *
 * its pins to the nets data structure by calling add_vpack_net.  If doall is *
 * zero this is a counting pass; if it is 1 this is the final (loading) *
 * pass.                                                                */

    char *ptr, **saved_names, buf[BUFSIZE];
    int i, j, output_net_index;

	saved_names = (char**) alloc_matrix(0, logic_model->inputs->size, 0, BUFSIZE - 1, sizeof(char));

    num_logical_blocks++;

/* Count # nets connecting */
    i = 0;
    while((ptr = my_strtok(NULL, TOKENS, blif, buf)) != NULL)
	{
	    strcpy(saved_names[i], ptr);
	    i++;
	}
	output_net_index = i - 1;
	if(strcmp(saved_names[output_net_index],"unconn") == 0) {
		/* unconn is a keyword to pad unused pins, ignore this block */
		free_matrix(saved_names, 0, logic_model->inputs->size, 0, sizeof(char));
		num_logical_blocks--;
		return;
	}

    if(!doall)
	{			/* Counting pass only ... */
	    for(j = 0; j <= output_net_index; j++)
			/* On this pass it doesn't matter if RECEIVER or DRIVER.  Just checking if in hash.  [0] should be DRIVER */
			add_vpack_net(saved_names[j], RECEIVER, num_logical_blocks - 1, 0, j, FALSE, doall);
		free_matrix(saved_names, 0, logic_model->inputs->size, 0, sizeof(char));
	    return;
	}

	logical_block[num_logical_blocks - 1].model = logic_model;

	if(output_net_index > logic_model->inputs->size) {
		printf(ERRTAG "LUT size of %d in .blif file is too big for FPGA which has a maximum LUT size of %d\n", 
			output_net_index, logic_model->inputs->size);
		exit(1);
	}
	assert(logic_model->inputs->next == NULL);
	assert(logic_model->outputs->next == NULL);
	assert(logic_model->outputs->size == 1);

	logical_block[num_logical_blocks - 1].input_nets = 
		(int **) my_malloc(sizeof(int*));
	logical_block[num_logical_blocks - 1].output_nets = 
		(int **) my_malloc(sizeof(int*));
	logical_block[num_logical_blocks - 1].clock_net = OPEN;

	logical_block[num_logical_blocks - 1].input_nets[0] = 
		(int *) my_malloc(logic_model->inputs->size * sizeof(int));
	logical_block[num_logical_blocks - 1].output_nets[0] = 
		(int *) my_malloc(sizeof(int));

    logical_block[num_logical_blocks - 1].type = VPACK_COMB;
    for(i = 0; i < output_net_index; i++)	/* Do inputs */
		logical_block[num_logical_blocks - 1].input_nets[0][i] = add_vpack_net(saved_names[i], RECEIVER, num_logical_blocks - 1, 0, i, FALSE, doall);
    logical_block[num_logical_blocks - 1].output_nets[0][0] = add_vpack_net(saved_names[output_net_index], DRIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);

    for(i = output_net_index; i < logic_model->inputs->size; i++)
		logical_block[num_logical_blocks - 1].input_nets[0][i] = OPEN;

    logical_block[num_logical_blocks - 1].name = my_strdup(saved_names[output_net_index]);
	logical_block[num_logical_blocks - 1].truth_table = NULL;
    num_luts++;

	free_matrix(saved_names, 0, logic_model->inputs->size, 0, sizeof(char));
}

static void
add_latch(int doall, INP t_model *latch_model)
{

/* Adds the flipflop (.latch) currently being parsed to the logical_block array.  *
 * Adds its pins to the nets data structure by calling add_vpack_net.  If doall *
 * is zero this is a counting pass; if it is 1 this is the final          * 
 * (loading) pass.  Blif format for a latch is:                           *
 * .latch <input> <output> <type (latch on)> <control (clock)> <init_val> *
 * The latch pins are in .nets 0 to 2 in the order: Q D CLOCK.            */

    char *ptr, buf[BUFSIZE], saved_names[6][BUFSIZE];
    int i;

    num_logical_blocks++;

/* Count # parameters, making sure we don't go over 6 (avoids memory corr.) */
/* Note that we can't rely on the tokens being around unless we copy them.  */

    for(i = 0; i < 6; i++)
	{
	    ptr = my_strtok(NULL, TOKENS, blif, buf);
	    if(ptr == NULL)
			break;
	    strcpy(saved_names[i], ptr);
	}

    if(i != 5)
	{
	    fprintf(stderr, "Error:  .latch does not have 5 parameters.\n" "check the netlist, line %d.\n", linenum);
	    exit(1);
	}

    if(!doall)
	{			/* If only a counting pass ... */
	    add_vpack_net(saved_names[0], RECEIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);	/* D */
	    add_vpack_net(saved_names[1], DRIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);	/* Q */
	    add_vpack_net(saved_names[3], RECEIVER, num_logical_blocks - 1, 0, 0, TRUE, doall);	/* Clock */
	    return;
	}

	logical_block[num_logical_blocks - 1].model = latch_model;
	logical_block[num_logical_blocks - 1].type = VPACK_LATCH;

	logical_block[num_logical_blocks - 1].input_nets = 
		(int **) my_malloc(sizeof(int*));
	logical_block[num_logical_blocks - 1].output_nets = 
		(int **) my_malloc(sizeof(int*));

	logical_block[num_logical_blocks - 1].input_nets[0] = 
		(int *) my_malloc(sizeof(int));
	logical_block[num_logical_blocks - 1].output_nets[0] = 
		(int *) my_malloc(sizeof(int));

    logical_block[num_logical_blocks - 1].output_nets[0][0] = add_vpack_net(saved_names[1], DRIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);	/* Q */
    logical_block[num_logical_blocks - 1].input_nets[0][0] = add_vpack_net(saved_names[0], RECEIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);	/* D */
    logical_block[num_logical_blocks - 1].clock_net = add_vpack_net(saved_names[3], RECEIVER, num_logical_blocks - 1, 0, 0, TRUE, doall);	/* Clock */

    logical_block[num_logical_blocks - 1].name = my_strdup(saved_names[1]);
	logical_block[num_logical_blocks - 1].truth_table = NULL;
    num_latches++;
}

static void
add_subckt(int doall, t_model *user_models)
{
    char *ptr;
	char *close_bracket;
	char subckt_name[BUFSIZE];
	char buf[BUFSIZE];
	fpos_t current_subckt_pos; 
    int i, j, iparse;
	int subckt_index_signals = 0;
	char **subckt_signal_name = NULL;
	char *port_name, *pin_number;
	char **circuit_signal_name = NULL;
	char *subckt_logical_block_name = NULL;
	short toggle = 0;
	int input_net_count, output_net_count, input_port_count, output_port_count;
	t_model *cur_model;
	t_model_ports *port;
	boolean found_subckt_signal;

    num_logical_blocks++;
	num_subckts++;

/* now we have to find the matching subckt */
	/* find the name we are looking for */
	strcpy(subckt_name, my_strtok(NULL, TOKENS, blif, buf)); 
	/* get all the signals in the form z=r */
	iparse = 0;
	while(iparse < MAX_ATOM_PARSE)
	{
		iparse++;
		/* Assumpiton is that it will be "signal1, =, signal1b, spacing, and repeat" */
	    ptr = my_strtok(NULL, " \t\n=", blif, buf);

	    if(ptr == NULL && toggle == 0)
			break;
		else if (ptr == NULL && toggle == 1)
		{
			printf("subckt %s formed incorrectly with signal=signal at\n", subckt_name, buf);
			exit(-1);
		}
		else if (toggle == 0)
		{
			/* ELSE - parse in one or the other */
			/* allocate a new spot for both the circuit_signal name and the subckt_signal name */
			subckt_signal_name = (char**)my_realloc(subckt_signal_name, (subckt_index_signals+1)*sizeof(char**));
			circuit_signal_name = (char**)my_realloc(circuit_signal_name, (subckt_index_signals+1)*sizeof(char**));

			/* copy in the subckt_signal name */
			subckt_signal_name[subckt_index_signals] = my_strdup(ptr);

			toggle = 1;
		}
		else if (toggle == 1)
		{
			/* copy in the circuit_signal name */
			circuit_signal_name[subckt_index_signals] = my_strdup(ptr);
			if(!doall) {
				/* Counting pass, does not matter if driver or receiver and pin number does not matter */
				add_vpack_net(circuit_signal_name[subckt_index_signals], RECEIVER, num_logical_blocks - 1, 0, 0, FALSE, doall);
			}

			toggle = 0;
			subckt_index_signals++;
		}
	}
	assert(iparse < MAX_ATOM_PARSE);
	/* record the position of the parse so far so when we resume we will move to the next item */	
	if (fgetpos(blif, &current_subckt_pos) != 0)
	{
		printf("Error in file pointer read - read_blif.c\n");
		exit(-1);
	}

	input_net_count = 0;
	output_net_count = 0;

	if (doall)
	{
		/* get the matching model to this subckt */

		cur_model = user_models;
		while(cur_model != NULL) {
			if(strcmp(cur_model->name, subckt_name) == 0) {
				break;
			}
			cur_model = cur_model->next;
		}
		if (cur_model == NULL)
		{
			printf("Didn't find matching model to subckt %s - error\n", subckt_name);
			exit(-1);
		}

		/* IF - do all then we need to allocate a string to hold all the subckt info */

		/* initialize the logical_block structure */
		
		  /* record model info */
		logical_block[num_logical_blocks-1].model = cur_model;
		
		/* allocate space for inputs and initialize all input nets to OPEN */
		input_port_count = 0;
		port = cur_model->inputs;
		while(port) {
			if(!port->is_clock) {
				input_port_count++;
			}
			port = port->next;
		}
		logical_block[num_logical_blocks-1].input_nets = my_malloc(input_port_count * sizeof(int *));
		
		port = cur_model->inputs;
		while(port) {
			if(port->is_clock) {
				/* Clock ports are different from regular input ports, skip */
				port = port->next;
				continue;
			}
			assert (port->size >= 0);
			logical_block[num_logical_blocks-1].input_nets[port->index] = my_malloc(port->size * sizeof(int));
			for(j = 0; j < port->size; j++) {
				logical_block[num_logical_blocks-1].input_nets[port->index][j] = OPEN;
			}
			port = port->next;
		}
		assert(port == NULL || (port->is_clock && port->next == NULL));

		/* allocate space for outputs and initialize all output nets to OPEN */
		output_port_count = 0;
		port = cur_model->outputs;
		while(port){
			port = port->next;
			output_port_count++;
		}
		logical_block[num_logical_blocks-1].output_nets =  my_malloc(output_port_count * sizeof(int *));

		port = cur_model->outputs;
		while(port) {
			assert (port->size >= 0);
			logical_block[num_logical_blocks-1].output_nets[port->index] = my_malloc(port->size * sizeof(int));
			for(j = 0; j < port->size; j++) {
				logical_block[num_logical_blocks-1].output_nets[port->index][j] = OPEN;
			}
			port = port->next;
		}
		assert(port == NULL);

		/* initialize clock data */
		logical_block[num_logical_blocks-1].clock_net = OPEN;

		logical_block[num_logical_blocks-1].type = VPACK_COMB;
		logical_block[num_logical_blocks - 1].truth_table = NULL;

		/* setup the index signal if open or not */
		
		for(i = 0; i < subckt_index_signals; i++) {
			found_subckt_signal = FALSE;
			/* determine the port name and the pin_number of the subckt */
			port_name = my_strdup(subckt_signal_name[i]);
			pin_number = strrchr(port_name, '[');
			if(pin_number == NULL) {
				pin_number = "0"; /* default to 0 */
			} else {
				/* The pin numbering is port_name[pin_number] so need to go one to the right of [ then NULL out ] */
				*pin_number = '\0';
				pin_number++;
				close_bracket = pin_number;
				while(*close_bracket != '\0' && *close_bracket != ']') {
					close_bracket++;
				}
				*close_bracket = '\0';
			}

			port = cur_model->inputs;
			while(port) {
				if(strcmp(port_name, port->name) == 0) {
					if(found_subckt_signal) {
						printf(ERRTAG "Two instances of %s subckt signal found in subckt %s\n",
							subckt_signal_name[i], subckt_name);
					}
					found_subckt_signal = TRUE;
					if(port->is_clock) {
						assert(logical_block[num_logical_blocks-1].clock_net == OPEN);
						assert(my_atoi(pin_number) == 0);
						logical_block[num_logical_blocks-1].clock_net = 
							add_vpack_net(circuit_signal_name[i], RECEIVER, num_logical_blocks - 1, port->index, my_atoi(pin_number), TRUE, doall);
					} else {
						logical_block[num_logical_blocks-1].input_nets[port->index][my_atoi(pin_number)] = 
							add_vpack_net(circuit_signal_name[i], RECEIVER, num_logical_blocks - 1, port->index, my_atoi(pin_number), FALSE, doall);
						input_net_count++;
					}
				}
				port = port->next;
			}

			port = cur_model->outputs;
			while(port) {
				if(strcmp(port_name, port->name) == 0) {
					if(found_subckt_signal) {
						printf(ERRTAG "Two instances of %s subckt signal found in subckt %s\n",
							subckt_signal_name[i], subckt_name);
					}
					found_subckt_signal = TRUE;
					logical_block[num_logical_blocks-1].output_nets[port->index][my_atoi(pin_number)] = 
						add_vpack_net(circuit_signal_name[i], DRIVER, num_logical_blocks - 1, port->index, my_atoi(pin_number), FALSE, doall);
					if(subckt_logical_block_name == NULL && circuit_signal_name[i] != NULL) {
						subckt_logical_block_name = circuit_signal_name[i];
					}
					output_net_count++;
				}
				port = port->next;
			}
			
			/* record the name to be first output net parsed */
			logical_block[num_logical_blocks-1].name = my_strdup(subckt_logical_block_name);

			if(!found_subckt_signal) {
				printf("Unknown subckt port %s\n", subckt_signal_name[i]);
				exit(1);
			}
		}
	}

	for(i = 0; i < subckt_index_signals; i++) {
		free(subckt_signal_name[i]);
		free(circuit_signal_name[i]);
	}
	free(subckt_signal_name);
	free(circuit_signal_name);

	/* now that you've done the analysis, move the file pointer back */
	if (fsetpos(blif, &current_subckt_pos) != 0)
	{
		printf("Error in moving back file pointer - read_blif.c\n");
		exit(-1);
	}
}

static void
io_line(int in_or_out,
	int doall, t_model *io_model)
{

/* Adds an input or output logical_block to the logical_block data structures.           *
 * in_or_out:  DRIVER for input, RECEIVER for output.                    *
 * doall:  1 for final pass when structures are loaded.  0 for           *
 * first pass when hash table is built and pins, nets, etc. are counted. */

    char *ptr;
    char buf2[BUFSIZE];
    int nindex, len, iparse;

	iparse = 0;
    while(iparse < MAX_ATOM_PARSE)
	{
		iparse++;
	    ptr = my_strtok(NULL, TOKENS, blif, buf2);
	    if(ptr == NULL)
		return;
	    num_logical_blocks++;

	    nindex = add_vpack_net(ptr, in_or_out, num_logical_blocks - 1, 0, 0, FALSE, doall);
	    /* zero offset indexing */
	    if(!doall)
			continue;	/* Just counting things when doall == 0 */

		logical_block[num_logical_blocks -1].clock_net = OPEN;
		logical_block[num_logical_blocks -1].input_nets = NULL;
		logical_block[num_logical_blocks -1].output_nets = NULL;
		logical_block[num_logical_blocks - 1].model = io_model;
		
	    len = strlen(ptr);
	    if(in_or_out == RECEIVER)
		{		/* output pads need out: prefix 
				 * to make names unique from LUTs */
		    logical_block[num_logical_blocks - 1].name = (char *)my_malloc((len + 1 + 4) * sizeof(char));	/* Space for out: at start */
		    strcpy(logical_block[num_logical_blocks - 1].name, "out:");
		    strcat(logical_block[num_logical_blocks - 1].name, ptr);
			logical_block[num_logical_blocks -1].input_nets = (int **)my_malloc(sizeof(int*));
			logical_block[num_logical_blocks -1].input_nets[0] = (int *)my_malloc(sizeof(int));
			logical_block[num_logical_blocks - 1].input_nets[0][0] = OPEN;
		}
	    else
		{
			assert(in_or_out == DRIVER);
		    logical_block[num_logical_blocks - 1].name = (char *)my_malloc((len + 1) * sizeof (char));
		    strcpy(logical_block[num_logical_blocks - 1].name, ptr);
			logical_block[num_logical_blocks -1].output_nets = (int **)my_malloc(sizeof(int*));
			logical_block[num_logical_blocks -1].output_nets[0] = (int *)my_malloc(sizeof(int));
			logical_block[num_logical_blocks - 1].output_nets[0][0] = OPEN;
		}

	    if(in_or_out == DRIVER)
		{		/* processing .inputs line */
		    num_p_inputs++;
		    logical_block[num_logical_blocks - 1].type = VPACK_INPAD;
			logical_block[num_logical_blocks - 1].output_nets[0][0] = nindex;
		}
	    else
		{		/* processing .outputs line */
		    num_p_outputs++;
		    logical_block[num_logical_blocks - 1].type = VPACK_OUTPAD;
			logical_block[num_logical_blocks - 1].input_nets[0][0] = nindex;
		}
		logical_block[num_logical_blocks - 1].truth_table = NULL;
	}
	assert(iparse < MAX_ATOM_PARSE);
}

static void check_and_count_models(int doall, const char* model_name, t_model *user_models) {
	fpos_t start_pos;
	t_model *user_model;

	num_blif_models++;
	if(doall) {
		/* get start position to do two passes on model */
		if (fgetpos(blif, &start_pos) != 0)
		{
			printf(ERRTAG "in file pointer read - read_blif.c\n");
			exit(-1);
		}

		/* get corresponding architecture model */
		user_model = user_models;
		while(user_model) {
			if(0 == strcmp(model_name, user_model->name)) {
				break;
			}
			user_model = user_model->next;
		}
		if(user_model == NULL) {
			printf(ERRTAG "No corresponding model %s in architecture description \n", model_name);
			exit(1);
		}

		/* check ports */
	}
}


static int
add_vpack_net(char *ptr,
	int type,
	int bnum,
	int bport,
	int bpin,
	boolean is_global,
	int doall)
{

/* This routine is given a vpack_net name in *ptr, either DRIVER or RECEIVER *
 * specifying whether the logical_block number (bnum) and the output pin (bpin) is driving this   *
 * vpack_net or in the fan-out and doall, which is 0 for the counting pass   *
 * and 1 for the loading pass.  It updates the vpack_net data structure and  *
 * returns the vpack_net number so the calling routine can update the logical_block  *
 * data structure.                                                     */

    struct hash_logical_nets *h_ptr, *prev_ptr;
    int index, j, nindex;

	if(strcmp(ptr, "open") == 0) {
		printf(ERRTAG "net name \"open\" is a reserved keyword in VPR");
		exit(1);
	}

	if(strcmp(ptr, "unconn") == 0) {
		return OPEN;
	}
	index = hash_value(ptr);

	if(doall) {
		if(type == RECEIVER && !is_global) {
			logical_block_input_count[bnum]++;
		} else if (type == DRIVER) {
			logical_block_output_count[bnum]++;
		}
	}
	
    h_ptr = hash[index];
    prev_ptr = h_ptr;

    while(h_ptr != NULL)
	{
	    if(strcmp(h_ptr->name, ptr) == 0)
		{		/* Net already in hash table */
		    nindex = h_ptr->index;

		    if(!doall)
			{	/* Counting pass only */
			    (h_ptr->count)++;
			    return (nindex);
			}

		    if(type == DRIVER)
			{
			    num_driver[nindex]++;
			    j = 0;	/* Driver always in position 0 of pinlist */
			}
		    else
			{
				vpack_net[nindex].num_sinks++;
				if((num_driver[nindex] < 0) || (num_driver[nindex] > 1)) {
					printf(ERRTAG "number of drivers for net #%d (%s) has %d drivers.\n",
						nindex, ptr, num_driver[index]);
				}
			    j = vpack_net[nindex].num_sinks;

				/* num_driver is the number of signal drivers of this vpack_net. *
			     * should always be zero or 1 unless the netlist is bad.   */
			    if((vpack_net[nindex].num_sinks - num_driver[nindex]) >= temp_num_pins[nindex])
				{
				    printf ("Error:  Net #%d (%s) has no driver and will cause\n", nindex, ptr);
				    printf("memory corruption.\n");
				    exit(1);
				}
			}
		    vpack_net[nindex].node_block[j] = bnum;
			vpack_net[nindex].node_block_port[j] = bport;
			vpack_net[nindex].node_block_pin[j] = bpin;
			vpack_net[nindex].is_global = is_global;
		    return (nindex);
		}
	    prev_ptr = h_ptr;
	    h_ptr = h_ptr->next;
	}

    /* Net was not in the hash table. */

    if(doall == 1)
	{
	    printf("Error in add_vpack_net:  the second (load) pass could not\n");
	    printf("find vpack_net %s in the symbol table.\n", ptr);
	    exit(1);
	}

/* Add the vpack_net (only counting pass will add nets to symbol table). */

    num_logical_nets++;
    h_ptr = (struct hash_logical_nets *)my_malloc(sizeof(struct hash_logical_nets));
    if(prev_ptr == NULL)
	{
	    hash[index] = h_ptr;
	}
    else
	{
	    prev_ptr->next = h_ptr;
	}
    h_ptr->next = NULL;
    h_ptr->index = num_logical_nets - 1;
    h_ptr->count = 1;
    h_ptr->name = my_strdup(ptr);
    return (h_ptr->index);
}


static int
hash_value(char *name)
{

    int i, k;
    int val = 0, mult = 1;

    i = strlen(name);
    k = max(i - 7, 0);
    for(i = strlen(name) - 1; i >= k; i--)
	{
	    val += mult * ((int)name[i]);
	    mult *= 10;
	}
    val += (int)name[0];
    val %= HASHSIZE;

    return (val);
}


void
echo_input(char *blif_file,
	   char *echo_file,
	   t_model *library_models)
{

/* Echo back the netlist data structures to file input.echo to *
 * allow the user to look at the internal state of the program *
 * and check the parsing.                                      */

    int i, j;
    FILE *fp;
	t_model_ports *port;
	t_model *latch_model;
	t_model *logic_model;
	t_model *cur;
	int *lut_distribution;
	int num_absorbable_latch;
	int inet;

	cur = library_models;
	logic_model = latch_model = NULL;
	while(cur) {
		if(strcmp(cur->name, MODEL_LOGIC) == 0) {
			logic_model = cur;
			assert(logic_model->inputs->next == NULL);
		} else if(strcmp(cur->name, MODEL_LATCH) == 0) {
			latch_model = cur;
			assert(latch_model->inputs->size == 1);
		}
		cur = cur->next;
	}

	lut_distribution = my_calloc(logic_model->inputs[0].size + 1, sizeof(int));
	num_absorbable_latch = 0;
	for(i = 0; i < num_logical_blocks; i++) {
		if(logical_block[i].model == logic_model) {
			if(logic_model == NULL)
				continue;
			for(j = 0; j < logic_model->inputs[0].size; j++) {
				if(logical_block[i].input_nets[0][j] == OPEN) {
					break;
				}
			}
			lut_distribution[j]++;
		} else if (logical_block[i].model == latch_model) {
			if(latch_model == NULL)
				continue;
			inet = logical_block[i].input_nets[0][0];
			if (vpack_net[inet].num_sinks == 1 && logical_block[vpack_net[inet].node_block[0]].model == logic_model) {
				num_absorbable_latch++;
			}
		}
	}

    printf("Input netlist file: %s  Model: %s\n", blif_file, model);
    printf("Primary Inputs: %d.  Primary Outputs: %d.\n", num_p_inputs, num_p_outputs);
	printf("LUTs: %d.  Latches: %d Subckts: %d.\n", num_luts, num_latches, num_subckts);
	printf("# Standard absorbable latches: %d\n", num_absorbable_latch);
	for(i = 0; i < logic_model->inputs[0].size + 1; i++) {
		printf("LUT size %d = %d, ", i, lut_distribution[i]);
	}
	printf("\n");
    printf("Total Blocks: %d.  Total Nets: %d\n", num_logical_blocks, num_logical_nets);

    fp = my_fopen(echo_file, "w", 0);

    fprintf(fp, "Input netlist file: %s  Model: %s\n", blif_file, model);
    fprintf(fp, "num_p_inputs: %d, num_p_outputs: %d, num_luts: %d," " num_latches: %d\n", num_p_inputs, num_p_outputs, num_luts, num_latches);
    fprintf(fp, "num_logical_blocks: %d, num_logical_nets: %d\n", num_logical_blocks, num_logical_nets);

    fprintf(fp, "\nNet\tName\t\t#Pins\tDriver\tRecvs.\n");
    for(i = 0; i < num_logical_nets; i++)
	{
	    fprintf(fp, "\n%d\t%s\t", i, vpack_net[i].name);
	    if(strlen(vpack_net[i].name) < 8)
		fprintf(fp, "\t");	/* Name field is 16 chars wide */
		fprintf(fp, "%d", vpack_net[i].num_sinks + 1);
		for(j = 0; j <= vpack_net[i].num_sinks; j++)
		fprintf(fp, "\t(%d,%d,%d)", vpack_net[i].node_block[j], vpack_net[i].node_block_port[j], vpack_net[i].node_block_pin[j]);
	}

    fprintf(fp, "\n\n\nBlocks\t\t\tBlock Type Legend:\n");
    fprintf(fp, "\t\t\tINPAD = %d\tOUTPAD = %d\n", VPACK_INPAD, VPACK_OUTPAD);
    fprintf(fp, "\t\t\tCOMB = %d\t\tLATCH = %d\n", VPACK_COMB, VPACK_LATCH);
    fprintf(fp, "\t\t\tEMPTY = %d\n", VPACK_EMPTY);
	
    for(i = 0; i < num_logical_blocks; i++)
	{
	    fprintf(fp, "\nblock %d\t%s\t", i, logical_block[i].name);
	    fprintf(fp, "type: %d\n", logical_block[i].type);
		fprintf(fp, "model name: %s\n", logical_block[i].model->name);

		port = logical_block[i].model->inputs;

		while(port) {
			fprintf(fp, "\tInput Port: %s\n", port->name);
			for(j = 0; j < port->size; j++) {
				if(logical_block[i].input_nets[port->index][j] == OPEN)
					fprintf(fp, "\tOPEN");
				else
					fprintf(fp, "\t%d", logical_block[i].input_nets[port->index][j]);
				}		
			port = port->next;
		}

		port = logical_block[i].model->outputs;
		while(port) {
			fprintf(fp, "\tOutput Port: %s\n", port->name);
			for(j = 0; j < port->size; j++) {
				if(logical_block[i].output_nets[port->index][j] == OPEN) {
					fprintf(fp, "\tOPEN");
				} else {
					fprintf(fp, "\t%d", logical_block[i].output_nets[port->index][j]);
				}		
			}
			port = port->next;
		}

		fprintf(fp, "\n\tclock net %d\n", logical_block[i].clock_net);
	}

    fprintf(fp, "\n");
    fclose(fp);
}



/* load default vpack models (inpad, outpad, logic) */
static void
load_default_models(INP t_model *library_models, OUTP t_model** inpad_model, OUTP t_model** outpad_model, 
					OUTP t_model** logic_model, OUTP t_model** latch_model)
{
	t_model *cur_model;
	cur_model = library_models;
	*inpad_model = *outpad_model = *logic_model = *latch_model = NULL;
	while(cur_model) {
		if(strcmp(MODEL_INPUT, cur_model->name) == 0) {
			assert(cur_model->inputs == NULL);
			assert(cur_model->outputs->next == NULL);
			assert(cur_model->outputs->size == 1);
			*inpad_model = cur_model;
		} else if(strcmp(MODEL_OUTPUT, cur_model->name) == 0) {
			assert(cur_model->outputs == NULL);
			assert(cur_model->inputs->next == NULL);
			assert(cur_model->inputs->size == 1);
			*outpad_model = cur_model;
		} else if(strcmp(MODEL_LOGIC, cur_model->name) == 0) {
			assert(cur_model->inputs->next == NULL);
			assert(cur_model->outputs->next == NULL);
			assert(cur_model->outputs->size == 1);
			*logic_model = cur_model;
		} else if(strcmp(MODEL_LATCH, cur_model->name) == 0) {
			assert(cur_model->outputs->next == NULL);
			assert(cur_model->outputs->size == 1);
			*latch_model = cur_model;
		} else {
			assert(0);
		}
		cur_model = cur_model->next;
	}
}


static void
check_net(boolean sweep_hanging_nets_and_inputs)
{

/* Checks the input netlist for obvious errors. */

    int i, j, k, error, iblk, ipin, iport, inet, check_net;
	boolean found;
	int count_inputs, count_outputs;
	int explicit_vpack_models;
	t_model_ports *port;
	struct s_linked_vptr *p_io_removed;
	int removed_nets;

	explicit_vpack_models = num_blif_models + 1;

    error = 0;
	removed_nets = 0;

    if(ilines != explicit_vpack_models)
	{
	    printf(ERRTAG "Found %d .inputs lines; expected %d.\n", ilines, explicit_vpack_models);
	    error++;
	}

    if(olines != explicit_vpack_models)
	{
	    printf(ERRTAG "Found %d .outputs lines; expected %d.\n", olines,explicit_vpack_models);
	    error++;
	}

    if(model_lines != explicit_vpack_models)
	{
	    printf(ERRTAG "Found %d .model lines; expected %d.\n", model_lines, num_blif_models + 1);
	    error++;
	}

    if(endlines != explicit_vpack_models)
	{
	    printf(ERRTAG "Found %d .end lines; expected %d.\n", endlines, explicit_vpack_models);
	    error++;
	}
    for(i = 0; i < num_logical_nets; i++)
	{

	    if(num_driver[i] != 1)
		{
			printf(ERRTAG "vpack_net %s has" " %d signals driving it.\n", vpack_net[i].name, num_driver[i]);
		    error++;
		}

	    if(vpack_net[i].num_sinks == 0)
		{

			/* If this is an input pad, it is unused and I just remove it with  *
			 * a warning message.  Lots of the mcnc circuits have this problem. 

			   Also, subckts from ODIN often have unused driven nets
			 */

			iblk = vpack_net[i].node_block[0];
			iport = vpack_net[i].node_block_port[0];
			ipin = vpack_net[i].node_block_pin[0];

			assert((vpack_net[i].num_sinks - num_driver[i]) == -1);
			
			/* All nets should connect to inputs of block except output pads */
			if(logical_block[iblk].type != VPACK_OUTPAD) {
				if(sweep_hanging_nets_and_inputs) {
					removed_nets++;
					vpack_net[i].node_block[0] = OPEN;
					vpack_net[i].node_block_port[0] = OPEN;
					vpack_net[i].node_block_pin[0] = OPEN;
					logical_block[iblk].output_nets[iport][ipin] = OPEN;
					logical_block_output_count[iblk]--;					
				} else {
					printf(WARNTAG "vpack_net %s has no fanout.\n", vpack_net[i].name);
				}
				continue;
			}
		}

	    if(strcmp(vpack_net[i].name, "open") == 0 || strcmp(vpack_net[i].name, "unconn") == 0)
		{
		    printf(ERRTAG "vpack_net #%d has the reserved name %s.\n", i, vpack_net[i].name);
		    error++;
		}

		for(j = 0; j <= vpack_net[i].num_sinks; j++) {
			iblk = vpack_net[i].node_block[j];
			iport = vpack_net[i].node_block_port[j];
			ipin = vpack_net[i].node_block_pin[j];
			if(ipin == OPEN) {
				/* Clocks are not connected to regular pins on a block hence open */
				check_net = logical_block[iblk].clock_net;
				if(check_net != i) {
					printf("Internal Error: clock net for block %s #%d is net %s #%d but connecting net is %s #%d\n",
						logical_block[iblk].name, iblk,
						vpack_net[check_net].name, check_net,
						vpack_net[i].name, i);
					error++;
				}

			} else {
				if(j == 0) {
					check_net = logical_block[iblk].output_nets[iport][ipin];
					if(check_net != i) {
						printf("Internal Error: output net for block %s #%d is net %s #%d but connecting net is %s #%d\n",
							logical_block[iblk].name, iblk,
							vpack_net[check_net].name, check_net,
							vpack_net[i].name, i);
						error++;
					}
				} else {
					if(vpack_net[i].is_global) {
						check_net = logical_block[iblk].clock_net;
					} else {
						check_net = logical_block[iblk].input_nets[iport][ipin];
					}
					if(check_net != i) {
						printf("Internal Error: input net for block %s #%d is net %s #%d but connecting net is %s #%d\n",
							logical_block[iblk].name, iblk,
							vpack_net[check_net].name, check_net,
							vpack_net[i].name, i);
						error++;
					}
				}
			} 
		}
	}
	printf("Swept away %d nets with no fanout\n", removed_nets);
    for(i = 0; i < num_logical_blocks; i++)
	{
		/* This block has no output and is not an output pad so it has no use, hence we remove it */
		if((logical_block_output_count[i] == 0) && (logical_block[i].type != VPACK_OUTPAD)) {
			printf(WARNTAG "logical_block %s #%d has no fanout.\n", logical_block[i].name, i);
			if(sweep_hanging_nets_and_inputs && (logical_block[i].type == VPACK_INPAD)) {
				logical_block[i].type = VPACK_EMPTY;
				printf("  Removing input\n");
				p_io_removed = my_malloc(sizeof(struct s_linked_vptr));
				p_io_removed->data_vptr = my_strdup(logical_block[i].name);
				p_io_removed->next = circuit_p_io_removed;
				circuit_p_io_removed = p_io_removed;
				continue;
			} else {
				printf("  " ERRTAG " sweep hanging nodes in your logic synthesis tool because VPR can't do this yet\n");
				error++;
			}
		}
		count_inputs = 0;
		count_outputs = 0;
		port = logical_block[i].model->inputs;
		while(port) {
			if(port->is_clock)
			{
				port = port->next;
				continue;
			}
				
			for(j = 0; j < port->size; j++) 
			{
				if(logical_block[i].input_nets[port->index][j] == OPEN)
					continue;
				count_inputs++;
				inet = logical_block[i].input_nets[port->index][j];
				found = FALSE;
				for(k = 1; k <= vpack_net[inet].num_sinks; k++) 
				{
					if(vpack_net[inet].node_block[k] == i) {
						if(vpack_net[inet].node_block_port[k] == port->index) {
							if(vpack_net[inet].node_block_pin[k] == j) {
								found = TRUE;
							}
						}
					}
				}
				assert(found == TRUE);
			}
			port = port->next;
		}
		assert(count_inputs == logical_block_input_count[i]);
		logical_block[i].used_input_pins = count_inputs;

		port = logical_block[i].model->outputs;
		while(port) {
			for(j = 0; j < port->size; j++) 
			{
				if(logical_block[i].output_nets[port->index][j] == OPEN)
					continue;
				count_outputs++;
				inet = logical_block[i].output_nets[port->index][j];
				vpack_net[inet].is_const_gen = FALSE;
				if(count_inputs == 0 && logical_block[i].type != VPACK_INPAD && logical_block[i].type != VPACK_OUTPAD && logical_block[i].clock_net == OPEN) {
					printf("Net is a constant generator: %s\n", vpack_net[inet].name);
					vpack_net[inet].is_const_gen = TRUE;
				}
				found = FALSE;
				if(vpack_net[inet].node_block[0] == i) {
					if(vpack_net[inet].node_block_port[0] == port->index) {
						if(vpack_net[inet].node_block_pin[0] == j) {
							found = TRUE;
						}
					}
				}
				assert(found == TRUE);
			}
			port = port->next;
		}
		assert(count_outputs == logical_block_output_count[i]);

	    if(logical_block[i].type == VPACK_LATCH)
		{
			if(logical_block_input_count[i] != 1)
			{
				printf (ERRTAG "Latch #%d with output %s has %d input pin(s), expected one (D).\n", i, logical_block[i].name, logical_block_input_count[i]);
			    error++;
			}
			if(logical_block_output_count[i] != 1)
			{
				printf (ERRTAG "Latch #%d with output %s has %d output pin(s), expected one (Q).\n", i, logical_block[i].name, logical_block_output_count[i]);
			    error++;
			}
			if(logical_block[i].clock_net == OPEN)
			{
				printf (ERRTAG "Latch #%d with output %s has no clock.\n", i, logical_block[i].name);
			    error++;
			}
		}

	    else if(logical_block[i].type == VPACK_INPAD)
		{
			if(logical_block_input_count[i] != 0) {
				printf (ERRTAG "io inpad logical_block #%d name %s of type %d" "has %d input pins.\n", 
					i, logical_block[i].name, logical_block[i].type, logical_block_input_count[i]);
			    error++;
			}
			if(logical_block_output_count[i] != 1) {
				printf (ERRTAG "io inpad logical_block #%d name %s of type %d" "has %d output pins.\n", 
					i, logical_block[i].name, logical_block[i].type, logical_block_output_count[i]);
			    error++;
			}
			if(logical_block[i].clock_net != OPEN)
			{
				printf (ERRTAG "io inpad #%d with output %s has clock.\n", i, logical_block[i].name);
			    error++;
			}
		}
		else if(logical_block[i].type == VPACK_OUTPAD)
		{
			if(logical_block_input_count[i] != 1) {
				printf (ERRTAG "io outpad logical_block #%d name %s of type %d" "has %d input pins.\n", 
					i, logical_block[i].name, logical_block[i].type, logical_block_input_count[i]);
			    error++;
			}
			if(logical_block_output_count[i] != 0) {
				printf (ERRTAG "io outpad logical_block #%d name %s of type %d" "has %d output pins.\n", 
					i, logical_block[i].name, logical_block[i].type, logical_block_output_count[i]);
			    error++;
			}
			if(logical_block[i].clock_net != OPEN)
			{
				printf (ERRTAG "io outpad #%d with name %s has clock.\n", i, logical_block[i].name);
			    error++;
			}
		}
		else if(logical_block[i].type == VPACK_COMB)
		{
			if(logical_block_input_count[i] <= 0)
			{
				printf ("Warning:  logical_block #%d with output %s has only %d pin.\n", i, logical_block[i].name, logical_block_input_count[i]);

			    if(logical_block_input_count[i] < 0)
				{
				    error++;
				}
			    else
				{
					if(logical_block_output_count[i] > 0) {
						printf ("\tBlock contains output -- may be a constant generator.\n");
					} else {
						printf ("\t" ERRTAG "Block contains no output.\n");
						error++;
					}
				}
			}

			if(strcmp(logical_block[i].model->name, MODEL_LOGIC) == 0) {
				if(logical_block_output_count[i] != 1) {
					printf (ERRTAG "logical_block #%d name %s of model %s \n has %d output pins instead of 1.\n", 
						i, logical_block[i].name, logical_block[i].model->name, logical_block_output_count[i]);
					error++;
				}
			}
		} else {
			printf(ERRTAG "Unknown type for logical_block #%d %s\n", i, logical_block[i].name);
		}
	}

    if(error != 0)
	{
	    printf("Found %d fatal errors in the input netlist.\n", error);
	    exit(1);
	}
}


static void
free_parse(void)
{

/* Release memory needed only during blif network parsing. */

    int i;
    struct hash_logical_nets *h_ptr, *temp_ptr;

    for(i = 0; i < HASHSIZE; i++)
	{
	    h_ptr = hash[i];
	    while(h_ptr != NULL)
		{
		    free((void *)h_ptr->name);
		    temp_ptr = h_ptr->next;
		    free((void *)h_ptr);
		    h_ptr = temp_ptr;
		}
	}
    free((void *)num_driver);
    free((void *)hash);
    free((void *)temp_num_pins);
}

