#include <string.h>
#include <stdio.h>
#include "util.h"
#include "vpack.h"
#include "globals.h"
#include "read_blif.h"

/*------------------------------------------------------------
 *  Copyright 2002 By Kara K.W. Poon and Steve Wilton
 *
 * Permission to use, copy, and modify this software and its documentation is
 * hereby granted only under the following terms and conditions.  Both the
 * above copyright notice and this permission notice must appear in all copies
 * of the software, derivative works or modified versions, and any portions
 * thereof, and both notices must appear in supporting documentation.
 * Permission is granted ONLY for non-commercial use.  For
 * commercial use, please contact the authors.
 *
 * This software may be distributed (but not offered for sale or transferred
 * for compensation) to third parties, provided such third parties agree to
 * abide by the terms and conditions of this notice.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS, AS
 * WELL AS THE UNIVERSITY OF BRITISH COLUMBIA AND THE
 * UNIVERSITY OF TORONTO DISCLAIM ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL THE
 * AUTHORS OR THE UNIVERSITY OF BRITISH COLUMBIA OR THE
 * UNIVERSITY OF TORONTO BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *------------------------------------------------------------*/

/*
  T-Vpack was written by Vaughn Betz at the University of Toronto.
  
  May 2001   Modified by Dr. Steve Wilton at the University 
             of British Columbia to propagate signal 
             activities
  July 2001  Further modified by Kara Poon at the University 
             of British Columbia to propagate both
             static probability and transition density
 */
/*
  November 2006		Modified by Yu Chi Wai at the Imperial
					College of London to support adding 
					virtual embedded block (VEB) to the circuit
 */


/* 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 last_lut_read;
static int previous_last_lut = -1;

static int *num_driver, *temp_num_pins;

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

static int num_dsp;  /* Used only for naming */
static int num_veb;  /* Used only for naming */
static int num_memory;

static int add_net (char *ptr, int type, int bnum, int doall); 
static void get_tok(char *buffer, int pass, int doall, int *done, 
        int lut_size, char *inside_names_ptr);
static void get_function_line(char *firsttoken, int lut_size);
static void init_parse(int doall);
static void check_net (int lut_size);
static void free_parse (void);
static void io_line (int in_or_out, int doall);
static void add_lut (int doall, int lut_size);
static void add_latch (int doall, int lut_size);
static void add_dsp (int doall);
static void add_veb (int doall);
static void add_memory(int doall);
static void add_carryout_to_line(int doall, int lut_size);
static void dum_parse (char *buf);
static int hash_value (char *name);
static char add_activity_to_net (char *ptr, 
				 float probability,
				 float density);
static void init_block_name_list();
static void add_block_name_to_block_name_list(char *name);
static int get_index_in_block_name_list(char *name);
static void free_block_name_list();
void read_activity(char *filename);
static void null_function(int blockno, int lut_size);
void convert2binary (int lut_size,
		     int decimal_number,
		     char* binary_string);


static void init_block_name_list()
{
   block_name_list = (char **)NULL;
   num_blocks_in_block_name_list = 0;
}

static void add_block_name_to_block_name_list(char *name)
{
   if (num_blocks_in_block_name_list == 0) {
      block_name_list = (char **)my_malloc(sizeof(char *)*1);
   } else {
      block_name_list = (char **)my_realloc(block_name_list,
                                 sizeof(char *)*(1+num_blocks_in_block_name_list));
   }
   block_name_list[num_blocks_in_block_name_list] = my_malloc(
                                 (1+(int)strlen(name)));
   strcpy(block_name_list[num_blocks_in_block_name_list],name);
   num_blocks_in_block_name_list ++;
}

static int get_index_in_block_name_list(char *name)
{
   int i;
  
   for(i=0;i<num_blocks_in_block_name_list;i++) {
      if(strcmp(name,block_name_list[i])==0) {
         return(i);
      }
   }
   return(-1);
}

static void free_block_name_list()
{
   int i;

   if (block_name_list != (char **)NULL) {
      for(i=0;i<num_blocks_in_block_name_list;i++) {
         free(block_name_list[i]);
      }
      free(block_name_list);
   }
}

void read_blif_and_activity (char *blif_file, char *activity,int lut_size) {
 char buffer[BUFSIZE];
 int pass, done, doall;
 char inside_names;


 blif = my_fopen (blif_file, "r", 0);

 last_lut_read = -1;

 for (doall=0;doall<=1;doall++) {
    init_parse(doall);


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

    for (pass=1;pass<=3;pass++) { 
       inside_names = 0;
       linenum = 0;   /* Reset line number. */
       done = 0;
       while((my_fgets(buffer,BUFSIZE,blif) != NULL) && !done) {
          get_tok(buffer, pass, doall, &done, lut_size, &inside_names);

       }

       rewind (blif);  /* Start at beginning of file again */
    }
 } 

 fclose(blif);
 check_net(lut_size);

 if (activity[0] != '\0') {
    read_activity(activity);
 }

 free_parse();
}


static void init_parse(int doall) {

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

 int i, len;
 struct hash_nets *h_ptr;

 if (!doall) {  /* Initialization before first (counting) pass */
    num_nets = 0;  
    hash = (struct hash_nets **) my_calloc(sizeof(struct hash_nets *),
            HASHSIZE);
    init_block_name_list();
 }

/* Allocate memory for second (load) pass */ 

 else {   
    net = (struct s_net *) my_malloc(num_nets*sizeof(struct s_net));
    block = (struct s_block *) my_malloc(num_blocks*
        sizeof(struct s_block));   
    num_driver = (int *) my_malloc(num_nets * sizeof(int));
    temp_num_pins = (int *) my_malloc(num_nets*sizeof(int));

    for (i=0;i<num_nets;i++) {
       num_driver[i] = 0;
       net[i].num_pins = 0;
       net[i].num_packed = 0;
       net[i].num_clusters = 0;
    }

    for (i=0;i<HASHSIZE;i++) {
       h_ptr = hash[i];   
       while (h_ptr != NULL) {
          net[h_ptr->index].pins = (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;
          len = strlen (h_ptr->name);
          net[h_ptr->index].name = (char *) my_malloc ((len + 1)* sizeof(char));
          strcpy (net[h_ptr->index].name, h_ptr->name);
          h_ptr = h_ptr->next;
       }
    }
 }

/* 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_blocks = 0;
 num_dsp = 0;
 num_veb = 0;
 num_memory = 0;
}


static void get_tok (char *buffer, int pass, int doall, int *done,
       int lut_size, char *inside_names_ptr) {

/* 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  buffer2[BUFSIZE];


 strcpy(buffer2, buffer);

 ptr = my_strtok(buffer,TOKENS,blif,buffer);

 if (ptr == NULL) return; 

 if (strcmp(ptr,".names") == 0) {
    *inside_names_ptr = 1;
    if (pass == 3) {
       add_lut(doall, lut_size);
    }
    else {
       dum_parse(buffer);
    }
    return;
 }

 if (strcmp(ptr,".latch") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    if (pass == 3) {
       add_latch (doall, lut_size);
    }
    else {
       dum_parse(buffer);
    }
    return;
 }

 if (strcmp(ptr,".dsp") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;

    if (pass == 3) {
       add_dsp (doall);
    }
    else {
       dum_parse(buffer);
    }
    return;
 }

 if (strcmp(ptr,".veb") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;

    if (pass == 3) {
       add_veb (doall);
    }
    else {
       dum_parse(buffer);
    }
    return;
 }

 if (strcmp(ptr,".memory") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    if (pass == 3) {
       add_memory (doall);
    }
    else {
       dum_parse(buffer);
    }
    return;
 }

 if (strcmp(ptr,".model") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    ptr = my_strtok(NULL,TOKENS,blif,buffer);

    if (doall && pass == 3) { /* Only bother on main second pass. */
       if (ptr != NULL) {
          model = (char *) my_malloc ((strlen(ptr)+1) * sizeof(char));
          strcpy(model,ptr);
       }
       else {
          model = (char *) my_malloc (sizeof(char));
          model[0] = '\0';
       }
       model_lines++;              /* For error checking only */
    }
    return;
 }

 if (strcmp(ptr,".inputs") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    if (pass == 1) {
       io_line(DRIVER, doall);
       *done = 1;
    }
    else {
       dum_parse(buffer);
       if (pass == 3 && doall) ilines++;    /* Error checking only */
    }
    return;
 }

 if (strcmp(ptr,".outputs") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    if (pass == 2) {
       io_line(RECEIVER, doall);
       *done = 1;
    }
    else {
       dum_parse(buffer);
       if (pass == 3 && doall) olines++;  /* Make sure only one .output line */
    }                            /* For error checking only */
    return;
 }

 if (strcmp(ptr,".end") == 0) {
    *inside_names_ptr = 0;
    last_lut_read = -1;
    if (pass == 3 && doall) endlines++;   /* Error checking only */
    return;
 }

 if (strcmp(ptr,"carryout_to") == 0) {
    *inside_names_ptr = 0;
    if (pass == 3) {
       if (doall) {
          add_carryout_to_line(doall,lut_size);
       }
    } else {
       dum_parse(buffer);  
    }
    return;
 }

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

 if (pass == 3) {
    if (*inside_names_ptr) {
       if (doall) {
          get_function_line(buffer2, lut_size);
       }
    }
 } else {
    dum_parse(buffer);
 }

}


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, int lut_size) {

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

 char *ptr, saved_names[MAXLUT+2][BUFSIZE], buf[BUFSIZE];
 int i, j, len;

 num_blocks++;
 last_lut_read = num_blocks-1;
 
/* Count # nets connecting */
 i=0;
 while ((ptr = my_strtok(NULL,TOKENS,blif,buf)) != NULL)  {
    if (i == MAXLUT+1) {
       fprintf(stderr,"Error:  LUT #%d has %d inputs.  Increase MAXLUT or"
            " check the netlist, line %d.\n",num_blocks-1,i-1,linenum);
       exit(1);
    }
    strcpy (saved_names[i], ptr);
    i++;
 }

 if (!doall) {          /* Counting pass only ... */
    for (j=0;j<i;j++) 
       add_net(saved_names[j],RECEIVER,num_blocks-1,doall);

    add_block_name_to_block_name_list(saved_names[i-1]);
    return;
 }


 block[num_blocks-1].num_nets = i;
 block[num_blocks-1].type = LUT;
 block[num_blocks-1].carryout_to = -1;
 block[num_blocks-1].carryout_to_name = (char *)NULL;

 null_function(num_blocks-1,lut_size);

 for (i=0;i<block[num_blocks-1].num_nets-1;i++)   /* Do inputs */
    block[num_blocks-1].nets[i+1] = add_net (saved_names[i],RECEIVER,
                                    num_blocks-1,doall); 

 block[num_blocks-1].nets[0] = add_net (
       saved_names[block[num_blocks-1].num_nets-1], DRIVER,num_blocks-1,doall);

 for (i=block[num_blocks-1].num_nets; i<lut_size+2; i++)
    block[num_blocks-1].nets[i] = OPEN;

 len = strlen (saved_names[block[num_blocks-1].num_nets-1]);
 block[num_blocks-1].name = (char *) my_malloc ((len+1) * sizeof (char));
 strcpy(block[num_blocks-1].name, saved_names[block[num_blocks-1].num_nets-1]);

 if (get_index_in_block_name_list(block[num_blocks-1].name) != num_blocks-1) {
    printf("Error: inconsistency in block_name_list %d %d\n",
            get_index_in_block_name_list(block[num_blocks-1].name),num_blocks-1);

 }
 num_luts++;
}


static void add_latch (int doall, int lut_size) {

/* Adds the flipflop (.latch) currently being parsed to the block array.  *
 * Adds its pins to the nets data structure by calling add_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, len;

 num_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_net(saved_names[0],RECEIVER,num_blocks-1,doall);  /* D */
    add_net(saved_names[1],DRIVER,num_blocks-1,doall);    /* Q */
    add_net(saved_names[3],RECEIVER,num_blocks-1,doall);  /* Clock */
    add_block_name_to_block_name_list(saved_names[1]);
    return;
 }

 block[num_blocks-1].carryout_to = -1;
 block[num_blocks-1].carryout_to_name = (char *)NULL;

 block[num_blocks-1].num_nets = 3;
 block[num_blocks-1].type = LATCH;

 block[num_blocks-1].nets[0] = add_net(saved_names[1],DRIVER,num_blocks-1,
     doall);                                                        /* Q */
 block[num_blocks-1].nets[1] = add_net(saved_names[0],RECEIVER,num_blocks-1,
     doall);                                                        /* D */
 block[num_blocks-1].nets[lut_size+1] = add_net(saved_names[3],RECEIVER,     
     num_blocks-1,doall);                                           /* Clock */

 for (i=2;i<lut_size+1;i++) 
    block[num_blocks-1].nets[i] = OPEN;
    
 len = strlen (saved_names[1]);
 block[num_blocks-1].name = (char *) my_malloc ((len+1) * sizeof (char));
 strcpy(block[num_blocks-1].name,saved_names[1]);
 num_latches++;
}




static void add_dsp (int doall) {

/* Adds a dsp block (.dsp) currently being parsed to the block array.  *
 * Adds its pins to the nets data structure by calling add_net.  If doall *
 * is zero this is a counting pass; if it is 1 this is the final          * 
 * (loading) pass.  Blif format for a dsp is:                           *
 * .dsp <num inputs> <num outputs> <num control> input-list output-list control-list */

 char *ptr, buf[BUFSIZE], saved_names[NETSONLINE][BUFSIZE];
 int i, j,len;
 int num_in, num_out, num_control;

 num_blocks++;


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

 for (i=0;i<BUFSIZE;i++) {
    if (i >= NETSONLINE) {
       printf("Error: maximum nets allowed on a single line is %d.  This can be changed in util.h\n", NETSONLINE);
       exit(0);
    }
    ptr = my_strtok (NULL,TOKENS,blif,buf);
    if (ptr == NULL) 
       break;
    strcpy (saved_names[i], ptr);
 }

 if (i <3) {
    fprintf(stderr,"Error:  .dsp has less than 3 parameters.\n"
            "check the netlist, line %d.\n",linenum);
    exit(1);
 }

 num_in = atoi(saved_names[0]);
 num_out = atoi(saved_names[1]);
 num_control = atoi(saved_names[2]); 

 if (i != 3 + num_in + num_out + num_control) {
    fprintf(stderr,"Error:  .dsp has wrong number of signals.\n"
            "check the netlist, line %d. (%d %d)\n",linenum,i-3,num_in+num_out+num_control);
    exit(1);
 }


 if (!doall) {   /* If only a counting pass ... */
    for(j=0;j<num_in;j++) {
       if (strcmp(saved_names[3+j],"open")) {
          add_net(saved_names[3+j],RECEIVER,num_blocks-1,doall); 
       }
    }
    for(j=0;j<num_out;j++) {

       if (strcmp(saved_names[3+num_in+j],"open")) {
          add_net(saved_names[3+num_in+j],DRIVER,num_blocks-1,doall);  /* D */
       }
    }
    for(j=0;j<num_control;j++) {

       if (strcmp(saved_names[3+num_in+num_out+j],"open")) {
          add_net(saved_names[3+num_in+num_out+j],RECEIVER,num_blocks-1,doall);  /* D */
       }
    }
    sprintf(buf,"dspblock%d",num_dsp);
    add_block_name_to_block_name_list(buf);
    num_dsp++;
    return;
 }

 block[num_blocks-1].num_nets = num_in+num_out+num_control;;
 block[num_blocks-1].type = DSP;
 block[num_blocks-1].carryout_to = -1;
 block[num_blocks-1].carryout_to_name = (char *)NULL;


 for(j=0;j<num_in;j++) {
    if (strcmp(saved_names[3+j],"open")) {
       block[num_blocks-1].nets[j] = 
             add_net(saved_names[3+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j] = OPEN; 
    }
 }
 for(j=0;j<num_out;j++) {
    if (strcmp(saved_names[3+num_in+j],"open")) {
       block[num_blocks-1].nets[j+num_in] = 
          add_net(saved_names[3+num_in+j],DRIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in] = OPEN; 
    }
 }
 for(j=0;j<num_control;j++) {
    if (strcmp(saved_names[3+num_in+num_out+j],"open")) {
       block[num_blocks-1].nets[j+num_in+num_out] = 
          add_net(saved_names[3+num_in+num_out+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in+num_out] = OPEN;
    }
 }
 block[num_blocks-1].num_of_each_type[0] = num_in;
 block[num_blocks-1].num_of_each_type[1] = num_out;
 block[num_blocks-1].num_of_each_type[2] = num_control;
    

 sprintf(buf,"dspblock%d",num_dsp);
 num_dsp ++; 
 len = strlen (buf);
 block[num_blocks-1].name = (char *) my_malloc ((len+1) * sizeof (char));
 strcpy(block[num_blocks-1].name,buf);
}


//Added by Yu Chi Wai
static void add_veb (int doall) {

/* Adds a veb block (.veb) currently being parsed to the block array.  *
 * Adds its pins to the nets data structure by calling add_net.  If doall *
 * is zero this is a counting pass; if it is 1 this is the final          * 
 * (loading) pass.  Blif format for a veb is:                           *
 * .veb veb_name <num inputs> <num outputs> <num control> input-list output-list control-list */

 char *ptr, buf[BUFSIZE], saved_names[NETSONLINE][BUFSIZE];
 int i, j,len;
 int num_in, num_out, num_control;

 num_blocks++;


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

 for (i=0;i<BUFSIZE;i++) {
    if (i >= NETSONLINE) {
       printf("Error: maximum nets allowed on a single line is %d.  This can be changed in util.h\n", NETSONLINE);
       exit(0);
    }
    ptr = my_strtok (NULL,TOKENS,blif,buf);
    if (ptr == NULL) 
       break;
    strcpy (saved_names[i], ptr);
 }

 if (i <3) {
    fprintf(stderr,"Error:  .veb has less than 3 parameters.\n"
            "check the netlist, line %d.\n",linenum);
    exit(1);
 }

 num_in = atoi(saved_names[1]);
 num_out = atoi(saved_names[2]);
 num_control = atoi(saved_names[3]); 

  if (i != 4 + num_in + num_out + num_control) {
    fprintf(stderr,"Error:  .veb has wrong number of signals.\n"
            "check the netlist, line %d. (%d %d)\n",linenum,i-4,num_in+num_out+num_control);
    exit(1);
 }


 if (!doall) {   /* If only a counting pass ... */
    for(j=0;j<num_in;j++) {
       if (strcmp(saved_names[4+j],"open")) {
          add_net(saved_names[4+j],RECEIVER,num_blocks-1,doall); 
       }
    }
    for(j=0;j<num_out;j++) {

       if (strcmp(saved_names[4+num_in+j],"open")) {
          add_net(saved_names[4+num_in+j],DRIVER,num_blocks-1,doall);  /* D */
       }
    }
    for(j=0;j<num_control;j++) {

       if (strcmp(saved_names[4+num_in+num_out+j],"open")) {
          add_net(saved_names[4+num_in+num_out+j],RECEIVER,num_blocks-1,doall);  /* D */
       }
    }

    sprintf(buf,"%s",saved_names[0]);
    add_block_name_to_block_name_list(buf);
    num_veb++;   
 
    return;
 }


 block[num_blocks-1].num_nets = num_in+num_out+num_control;;
 block[num_blocks-1].type = VEB;
 block[num_blocks-1].carryout_to = -1;
 block[num_blocks-1].carryout_to_name = (char *)NULL;


 for(j=0;j<num_in;j++) {
    if (strcmp(saved_names[4+j],"open")) {
       block[num_blocks-1].nets[j] = 
             add_net(saved_names[4+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j] = OPEN; 
    }
 }
 for(j=0;j<num_out;j++) {
    if (strcmp(saved_names[4+num_in+j],"open")) {
       block[num_blocks-1].nets[j+num_in] = 
          add_net(saved_names[4+num_in+j],DRIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in] = OPEN; 
    }
 }
 for(j=0;j<num_control;j++) {
    if (strcmp(saved_names[4+num_in+num_out+j],"open")) {
       block[num_blocks-1].nets[j+num_in+num_out] = 
          add_net(saved_names[4+num_in+num_out+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in+num_out] = OPEN;
    }
 }
 block[num_blocks-1].num_of_each_type[0] = num_in;
 block[num_blocks-1].num_of_each_type[1] = num_out;
 block[num_blocks-1].num_of_each_type[2] = num_control;
    
 sprintf(buf,"%s",saved_names[0]);
 num_veb ++; 
 len = strlen (buf);
 block[num_blocks-1].name = (char *) my_malloc ((len+1) * sizeof (char));
 strcpy(block[num_blocks-1].name,buf);
}


static void add_memory (int doall) {

/* Adds a memory block (.memory) currently being parsed to the block array.  *
 * Adds its pins to the nets data structure by calling add_net.  If doall *
 * is zero this is a counting pass; if it is 1 this is the final          * 
 * (loading) pass.  Blif format for a memory is:                           *
 * .memory <num addr inputs> <num data inputs> <num data outputs> <num control> input-list output-list control-list */

 char *ptr, buf[BUFSIZE], saved_names[NETSONLINE][BUFSIZE];
 int i, j,len;
 int num_addr, num_in, num_out, num_control;

 num_blocks++;

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

 for (i=0;i<BUFSIZE;i++) {

    if (i >= NETSONLINE) {
       printf("Error: maximum nets allowed on a single line is %d.  This can be changed in util.h\n", NETSONLINE);
       exit(0);
    }

    ptr = my_strtok (NULL,TOKENS,blif,buf);
    if (ptr == NULL) 
       break;
    strcpy (saved_names[i], ptr);
 }

 if (i <4) {
    fprintf(stderr,"Error:  .memory has less than 4 parameters.\n"
            "check the netlist, line %d.\n",linenum);
    exit(1);
 }

 num_addr = atoi(saved_names[0]);
 num_in = atoi(saved_names[1]);
 num_out = atoi(saved_names[2]);
 num_control = atoi(saved_names[3]); 

 if (i != 4 + num_addr + num_in + num_out + num_control) {
    fprintf(stderr,"Error:  .memory has wrong number of signals.\n"
            "check the netlist, line %d.\n",linenum);
    exit(1);
 }

 if (!doall) {   /* If only a counting pass ... */
    for(j=0;j<num_addr;j++) {
       if (strcmp(saved_names[4+j],"open")) {
          add_net(saved_names[4+j],RECEIVER,num_blocks-1,doall); 
       }
    }
    for(j=0;j<num_in;j++) {
       if (strcmp(saved_names[4+num_addr+j],"open")) {
          add_net(saved_names[4+num_addr+j],RECEIVER,num_blocks-1,doall); 
       }
    }
    for(j=0;j<num_out;j++) {
       if (strcmp(saved_names[4+num_in+num_addr+j],"open")) {
          add_net(saved_names[4+num_in+num_addr+j],DRIVER,num_blocks-1,doall);  /* D */
       }
    }
    for(j=0;j<num_control;j++) {
       if (strcmp(saved_names[4+num_in+num_out+num_addr+j],"open")) {
          add_net(saved_names[4+num_in+num_out+num_addr+j],RECEIVER,num_blocks-1,doall);  /* D */
       }
    }
    sprintf(buf,"memory%d",num_memory);
    add_block_name_to_block_name_list(buf);
    num_memory++;
    return;
 }

 block[num_blocks-1].num_nets = num_addr + num_in+num_out+num_control;;
 block[num_blocks-1].type = MEMORY;
 block[num_blocks-1].carryout_to = -1;
 block[num_blocks-1].carryout_to_name = (char *)NULL;


 for(j=0;j<num_addr;j++) {
    if (strcmp(saved_names[4+j],"open")) {
       block[num_blocks-1].nets[j] = 
             add_net(saved_names[4+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j] = OPEN; 
    }
 }
 for(j=0;j<num_in;j++) {
    if (strcmp(saved_names[4+num_addr+j],"open")) {
       block[num_blocks-1].nets[j+num_addr] = 
             add_net(saved_names[4+num_addr+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_addr] = OPEN; 
    }
 }
 for(j=0;j<num_out;j++) {
    if (strcmp(saved_names[4+num_in+num_addr+j],"open")) {
       block[num_blocks-1].nets[j+num_addr+num_in] = 
          add_net(saved_names[4+num_in+num_addr+j],DRIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in+num_addr] = OPEN; 
    }
 }
 for(j=0;j<num_control;j++) {
    if (strcmp(saved_names[4+num_addr+num_in+num_out+j],"open")) {
       block[num_blocks-1].nets[j+num_addr+num_in+num_out] = 
          add_net(saved_names[4+num_addr+num_in+num_out+j],RECEIVER,num_blocks-1,doall);  
    } else {
       block[num_blocks-1].nets[j+num_in+num_out+num_addr] = OPEN;
    }
 }
 block[num_blocks-1].num_of_each_type[0] = num_addr;
 block[num_blocks-1].num_of_each_type[1] = num_in;
 block[num_blocks-1].num_of_each_type[2] = num_out;
 block[num_blocks-1].num_of_each_type[3] = num_control;

 sprintf(buf,"memory%d",num_memory);
 num_memory ++; 
 len = strlen (buf);
 block[num_blocks-1].name = (char *) my_malloc ((len+1) * sizeof (char));
 strcpy(block[num_blocks-1].name,buf);
}


static void io_line(int in_or_out, int doall) {  

/* Adds an input or output block to the 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];
 char buf3[BUFSIZE]; /* SC_05 */
 int nindex, len;
  
 while (1) {
    ptr = my_strtok(NULL,TOKENS,blif,buf2);
    if (ptr == NULL) return;
    num_blocks++;
    
    nindex = add_net(ptr,in_or_out,num_blocks-1,doall); 
                 /* zero offset indexing */

    if (!doall) {

       if (in_or_out == RECEIVER) {
/*          sprintf(buf2,"out:%s",ptr); /* /* SC_05 */
		   sprintf(buf3, "out:%s", ptr); /* SC_05 */
/*          add_block_name_to_block_name_list(buf2);*/ /* SC_05 */
		   add_block_name_to_block_name_list(buf3); /* SC_05 */
       } else {
          add_block_name_to_block_name_list(ptr);
       }
       continue;
    }


    len = strlen (ptr);
    if (in_or_out == RECEIVER) {  /* output pads need out: prefix 
                                     to make names unique from LUTs */
       block[num_blocks-1].name = (char *) my_malloc ((len+1+4) *
            sizeof (char));          /* Space for out: at start */
       strcpy(block[num_blocks-1].name,"out:");
       strcat(block[num_blocks-1].name,ptr);
    }
    else {
       block[num_blocks-1].name = (char *) my_malloc ((len+1) *
            sizeof (char));     
       strcpy(block[num_blocks-1].name,ptr);
    }

    block[num_blocks-1].num_nets = 1;
    block[num_blocks-1].nets[0] = nindex;  /* Put in driver position for */
    block[num_blocks-1].carryout_to = -1;
    block[num_blocks-1].carryout_to_name = (char *)NULL;

   /*  OUTPAD, since it has only one pin (even though it's a receiver */

    if (in_or_out == DRIVER) {             /* processing .inputs line */
       num_p_inputs++;
       block[num_blocks-1].type = INPAD;
    }
    else {                                 /* processing .outputs line */
       num_p_outputs++;
       block[num_blocks-1].type = OUTPAD;
    }
 } 
}




static int add_net (char *ptr, int type, int bnum, int doall) {   

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

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

 index = hash_value(ptr);
 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);
       }

       net[nindex].num_pins++;
       if (type == DRIVER) {
          num_driver[nindex]++;
          j=0;           /* Driver always in position 0 of pinlist */
       }
       else {
          j = net[nindex].num_pins - num_driver[nindex]; 
   /* num_driver is the number of signal drivers of this net. *
    * should always be zero or 1 unless the netlist is bad.   */

          if (j >= temp_num_pins[nindex]) {
             printf("Error:  Net #%d (%s) has no driver and will cause\n",
                nindex, ptr);
             printf("memory corruption.\n");
             exit(1);
          }
       }
       net[nindex].pins[j] = bnum;
       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_net:  the second (load) pass could not\n");
    printf("find net %s in the symbol table.\n", ptr);
    exit(1);
 }

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

 num_nets++;
 h_ptr = (struct hash_nets *) my_malloc (sizeof(struct hash_nets));
 if (prev_ptr == NULL) {
    hash[index] = h_ptr;
 }     
 else {  
    prev_ptr->next = h_ptr;
 }    
 h_ptr->next = NULL;
 h_ptr->index = num_nets - 1;
 h_ptr->count = 1;
 h_ptr->name = (char *) my_malloc((strlen(ptr)+1)*sizeof(char));
 strcpy(h_ptr->name,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, int lut_size, char *echo_file) {

/* 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, max_pin; 
 FILE *fp;

 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.\n", num_luts, num_latches);
 printf("Total Blocks: %d.  Total Nets: %d\n", num_blocks, num_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_blocks: %d, num_nets: %d\n",num_blocks,num_nets);

 fprintf(fp,"\nNet\tName\t\t#Pins\tDriver\tRecvs.\n");
 for (i=0;i<num_nets;i++) {
    fprintf(fp,"\n%d\t%s\t", i, net[i].name);
    if (strlen(net[i].name) < 8)
       fprintf(fp,"\t");         /* Name field is 16 chars wide */
    fprintf(fp,"%d", net[i].num_pins);
    for (j=0;j<net[i].num_pins;j++) 
        fprintf(fp,"\t%d",net[i].pins[j]);
 }

 fprintf(fp,"\n\n\nBlocks\t\t\tBlock Type Legend:\n");
 fprintf(fp,"\t\t\tINPAD = %d\tOUTPAD = %d\n", INPAD, OUTPAD);
 fprintf(fp,"\t\t\tLUT = %d\t\tLATCH = %d\n", LUT, LATCH);
 fprintf(fp,"\t\t\tEMPTY = %d\tLUT_AND_LATCH = %d\n\n", EMPTY, 
       LUT_AND_LATCH);
 
 fprintf(fp,"\nBlock\tName\t\tType\t#Nets\tOutput\tInputs");
 for (i=0;i<lut_size;i++) 
    fprintf(fp,"\t");
 fprintf(fp,"Clock\n\n");

 for (i=0;i<num_blocks;i++) { 
    fprintf(fp,"\n%d\t%s\t",i, block[i].name);
    if (strlen(block[i].name) < 8)
       fprintf(fp,"\t");         /* Name field is 16 chars wide */
    fprintf(fp,"%d\t%d", block[i].type, block[i].num_nets);

   /* I'm assuming EMPTY blocks are always INPADs when I print               *
    * them out.  This is true right after the netlist is read in, and again  *
    * after ff_packing and compression of the netlist.  It's not true after  *
    * ff_packing and before netlist compression.                             */

    if (block[i].type == INPAD || block[i].type == OUTPAD || 
          block[i].type == EMPTY)
       max_pin = 1;
    else if ((block[i].type == DSP) || (block[i].type == MEMORY) || (block[i].type == VEB))   
       max_pin = block[i].num_nets;
    else
       max_pin = lut_size+2;

    for (j=0;j<max_pin;j++) {
        if (block[i].nets[j] == OPEN) 
           fprintf(fp,"\tOPEN");
        else
           fprintf(fp,"\t%d",block[i].nets[j]);
    }
 }  

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


static void check_net (int lut_size) {

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

 int i, error, iblk;
 
 error = 0;

 if (ilines != 1) {
     printf("Warning:  found %d .inputs lines; expected 1.\n",
        ilines);
     error++;
 }

 if (olines != 1) {
     printf("Warning:  found %d .outputs lines; expected 1.\n",
        olines);
     error++;
 }

 if (model_lines != 1) {
     printf("Warning:  found %d .model lines; expected 1.\n",
        model_lines);
     error++;
 }

 if (endlines != 1) {
     printf("Warning:  found %d .end lines; expected 1.\n",
        endlines);
     error++;
 }

 for (i=0;i<num_nets;i++) {

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

    if ((net[i].num_pins - num_driver[i]) < 1) {

/* 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. */

       iblk = net[i].pins[0];
       if (block[iblk].type == INPAD) {
          printf("Warning:  Input %s is unused; removing it.\n",
             block[iblk].name);
          net[i].pins[0] = OPEN;
          block[iblk].type = EMPTY;
       }
          
       else {
          printf("Warning:  net %s has no fanout.\n",net[i].name);
          error++;
       }
    }

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

 for (i=0;i<num_blocks;i++) {
    if (block[i].type == LUT) {
       if (block[i].num_nets < 2) {
          printf("Warning:  logic block #%d with output %s has only %d pin.\n",
             i,block[i].name,block[i].num_nets);

/* LUTs with 1 pin (an output)  can be a constant generator.  Warn the   *
 * user, but don't exit.                                                 */

          if (block[i].num_nets != 1) {
             error++;
          }
          else {
             printf("\tPin is an output -- may be a constant generator.\n");
             printf("\tNon-fatal error.\n");
          }
       }

       if (block[i].num_nets > lut_size + 1) {
          printf("Warning:  logic block #%d with output %s has %d pins.\n",
             i,block[i].name,block[i].num_nets);
          error++;
       }
    }

    else if (block[i].type == LATCH) {
       if (block[i].num_nets != 3) {
          printf("Warning:  Latch #%d with output %s has %d pin(s).\n",
             i, block[i].name, block[i].num_nets);
          error++;
       }
    }
       
    else if ((block[i].type != DSP) &&
             (block[i].type != MEMORY) &&
			 (block[i].type != VEB)) {
       if (block[i].num_nets != 1) {
          printf("Warning:  io block #%d with output %s of type %d"
             "has %d pins.\n", i, block[i].name, block[i].type,
             block[i].num_nets);
          error++;
       }
    }
 }
 
 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_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);
 free_block_name_list();
}


/* This routine reads an "activity" file.  Each line in the .act  *
 * file corresponds to a single net.  Each line has two entries:      *
 * the name of the net, and its activity (average number of           *
 * transitions per clock cycle                                        *
 * File created by Steve Wilton, May 2001.                            */


void read_activity(char *filename)
{
/*   char buf[BUFSIZE], *ptr, *word1, *word2, *word3; */ /* SC_06 */
   char buf[BUFSIZE], *ptr, *word1, *word2, *word3, *word4; /* SC_06 */

   FILE *fp;
   int i,file, fail;

   if (num_nets == 0) {
      printf("Error reading activity file.  Must read netlist first\n");
      exit(-1);
   }

   for(i=0;i<num_nets;i++) {
		net[i].probability = -1.0;
		net[i].density = -1.0;
   }
   fp = my_fopen (filename, "r", 0);
   if (fp == NULL) {
      printf("Error: could not open activity file: %s\n",filename);
      exit(-1);
   } else {

       fail = 0;
       ptr = my_fgets (buf, BUFSIZE, fp);
       while (ptr != NULL) {
          word1 = strtok(buf,TOKENS);
          word2 = strtok(&(buf[strlen(word1)+1]),TOKENS);
			 word3 = strtok(&(buf[strlen(word1)+1+strlen(word2)+1]),TOKENS);
			 word4 = strtok(&(buf[strlen(word1)+1+strlen(word2)+1+strlen(word3)+1]), TOKENS); /* SC_06 */
/*          fail |= add_activity_to_net (word1, atof(word2), atof(word3));*/ /* SC_06 */
			 fail |= add_activity_to_net (word1, atof(word2), atof(word4)); /* SC_06 */
          ptr = my_fgets (buf, BUFSIZE, fp);
       }
       fclose(fp);

       /* Make sure all nets have an activity value */

       for(i=0;i<num_nets;i++) {

        if ((net[i].probability < 0.0) || (net[i].density<0.0))
			 {
				printf("Error: Activity file does not contain signal %s\n",
						 net[i].name);
				fail++;
			 }
       }
       if (fail>0) {
          exit(-1);
       }
   }
}

/* this routine match the activities in the activity file to the *
 * net in the .blif file.                                        */

static char add_activity_to_net (char *ptr, float probability, float density) {

 struct hash_nets *h_ptr;
 int index, nindex;

 index = hash_value(ptr);
 h_ptr = hash[index]; 

 while (h_ptr != NULL) {
    if (strcmp(h_ptr->name,ptr) == 0) { /* Net in hash table */
       nindex = h_ptr->index;
		 net[nindex].probability = probability;
		 net[nindex].density = density;
       return ( (char)0);
    }
    h_ptr = h_ptr->next;
 }
 /* *** NCKC: changing this error to a warning and returning 0 instead of 1. *** */
 /*printf("Error: net %s found in activity file, but it does not exist\n",ptr);*/
 printf("Warning: net %s found in activity file, but it does not exist\n",ptr);
 printf("in the .blif file.\n");
 return( (char)0);
}


static void add_carryout_to_line(int doall, int lut_size)
{
 char *ptr, saved_names[MAXLUT+2][BUFSIZE], buf[BUFSIZE];
 int i, j;

/* last_lut_read */
 
/* Count # nets connecting */
 i=0;
 while ((ptr = my_strtok(NULL,TOKENS,blif,buf)) != NULL)  {
    if (i == 1) {
       fprintf(stderr,"Error: LUT #%d has more than one carryout signal.\n",
                             num_blocks-1);
       exit(1);
    }
    strcpy (saved_names[i], ptr);
    i++;
 }
 j = get_index_in_block_name_list(saved_names[0]);
 if (j==-1) {
    printf("Error: node %s has carryout_to %s, but %s doesn't exist\n",
        block[last_lut_read].name,
        saved_names[0], saved_names[0]);
    exit(0);
 }
 if (block[j].type != LUT) {
    printf("Error: node %s has carryout_to %s, but %s isn't a LUT\n",
        block[last_lut_read].name,
        saved_names[0], saved_names[0]);
    exit(0);
 }
 block[last_lut_read].carryout_to = j;
 block[last_lut_read].carryout_to_name = (char *)
            my_malloc(sizeof(saved_names[0]));
 strcpy(block[last_lut_read].carryout_to_name, saved_names[0]);

 printf("node %s has carryout_to: %s (number %d)\n",
        block[last_lut_read].name,
        block[last_lut_read].carryout_to_name, j);
}

/* This routine output the SRAM bit stream for function
   implemented in the LUTs                               */

static void get_function_line(char *firsttoken, int lut_size)
{
   char *ptr, buf[BUFSIZE], *functionstring;
   char *binary_string;
   int i, j, k, ok, bit, number_counter, pos_counter, dont_care;

   functionstring = (char *)malloc( sizeof(char)*(lut_size+1));
   binary_string = (char *)malloc( sizeof(char)*(lut_size+1));
   if (last_lut_read == -1) {
      printf("error: function line in wrong place\n");
      exit(0);
   }

    /* first token is the string */
   k = 0;  

   for(i=0;i<lut_size;i++ ) {
      if ((firsttoken[k] == '\0') || (firsttoken[k] == ' '))
	{
        for(j=i;j<lut_size;j++) {
           functionstring[j] = '-';
	}
        i=lut_size;
      }
      functionstring[i] = firsttoken[k++];
   }
   
   functionstring[lut_size] = '\0';

   while (firsttoken[k]== ' ')
     {
       k++;
     };

	if (last_lut_read != previous_last_lut)
	  { 
		 null_function(last_lut_read, lut_size);
		 previous_last_lut = last_lut_read;
	  }


   for (number_counter=0; number_counter < pow(2, lut_size); number_counter++)
     {
       convert2binary(lut_size, number_counter, binary_string);

       ok = 0;
       dont_care =0;
       for (pos_counter =0; pos_counter <lut_size; pos_counter ++)
			{
			  if (functionstring[pos_counter] != '-')
				 {
					if (functionstring[pos_counter] == binary_string[pos_counter])
					  {
						 ok = 1;					
					  }
					else
					  {
						 ok = 0;
						 pos_counter = lut_size;
					  }
             }
			  else
				 {
					dont_care++;
				 }
			}
		 
       if ((dont_care == 4) || (ok == 1))
			{
			  block[previous_last_lut].function[number_counter] = firsttoken[k];
			}
     }

   free(functionstring);
   free(binary_string);

}

/* set all the sram cells to zero if no function is implemented */
static void null_function(int blockno, int lut_size)
{
   int i;
	int function_range;

	function_range = pow(2, lut_size);

   block[blockno].function = (char *)malloc( sizeof(char)*(function_range+1) );
	for(i=0;i < function_range;i++) {

      block[blockno].function[i] = '0';
   }
   
	block[blockno].function[function_range] = '\0';
}

/* convert a decimal_number to binary value */
void convert2binary (int lut_size,
		     int decimal_number,
		     char* binary_string)
{
  int i, k;
  int remainder;
  char binary_char[2];

  binary_string[lut_size] = '\0';
  i=lut_size - 1;
  while (decimal_number >0)
    {
      remainder = decimal_number%2;
      sprintf(binary_char, "%d", remainder);
      binary_string[i--] = binary_char[0];
      decimal_number = decimal_number >> 1;
    }

  while (i>=0)
    {
      binary_string[i--] = '0';
    }  

 
}
