/***********************************/
/* Synthesizable Verilog Dumping   */
/*       Xifan TANG, EPFL/LSI      */
/***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

/* Include vpr structs*/
#include "util.h"
#include "physical_types.h"
#include "vpr_types.h"
#include "globals.h"
#include "rr_graph_util.h"
#include "rr_graph.h"
#include "rr_graph2.h"
#include "vpr_utils.h"
#include "route_common.h"

/* FPGA-SPICE utils */
#include "read_xml_spice_util.h"
#include "linkedlist.h"
#include "fpga_x2p_types.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_pbtypes_utils.h"
#include "fpga_x2p_globals.h"

/* syn_verilog globals */
#include "verilog_global.h"
#include "verilog_utils.h"

/****** Subroutines *******/
void init_list_include_verilog_netlists(t_spice* spice) { 
  int i, j, cur;
  int to_include = 0;
  int num_to_include = 0;

  /* Initialize */
  for (i = 0; i < spice->num_include_netlist; i++) { 
    FreeSpiceModelNetlist(&(spice->include_netlists[i]));
  }
  my_free(spice->include_netlists);
  spice->include_netlists = NULL;
  spice->num_include_netlist = 0;

  /* Generate include netlist list */
  vpr_printf(TIO_MESSAGE_INFO, "Listing Verilog Netlist Names to be included...\n");
  for (i = 0; i < spice->num_spice_model; i++) {
    if (NULL != spice->spice_models[i].verilog_netlist) {
      /* Check if this netlist name has already existed in the list */
      to_include = 1;
      for (j = 0; j < i; j++) {
        if (NULL == spice->spice_models[j].verilog_netlist) {
          continue;
        }
        if (0 == strcmp(spice->spice_models[j].verilog_netlist, spice->spice_models[i].verilog_netlist)) {
          to_include = 0;
          break;
        }
      }
      /* Increamental */
      if (1 == to_include) {
        num_to_include++;
      }
    }
  }

  /* realloc */
  spice->include_netlists = (t_spice_model_netlist*)my_realloc(spice->include_netlists, 
                              sizeof(t_spice_model_netlist)*(num_to_include + spice->num_include_netlist));

  /* Fill the new included netlists */
  cur = spice->num_include_netlist;
  for (i = 0; i < spice->num_spice_model; i++) {
    if (NULL != spice->spice_models[i].verilog_netlist) {
      /* Check if this netlist name has already existed in the list */
      to_include = 1;
      for (j = 0; j < i; j++) {
        if (NULL == spice->spice_models[j].verilog_netlist) {
          continue;
        }
        if (0 == strcmp(spice->spice_models[j].verilog_netlist, spice->spice_models[i].verilog_netlist)) {
          to_include = 0;
          break;
        }
      }
      /* Increamental */
      if (1 == to_include) {
        spice->include_netlists[cur].path = my_strdup(spice->spice_models[i].verilog_netlist); 
        spice->include_netlists[cur].included = 0;
        vpr_printf(TIO_MESSAGE_INFO, "[%d] %s\n", cur+1, spice->include_netlists[cur].path);
        cur++;
      }
    }
  }
  /* Check */
  assert(cur == (num_to_include + spice->num_include_netlist));
  /* Update */
  spice->num_include_netlist += num_to_include;
  
  return;
}


void init_include_user_defined_verilog_netlists(t_spice spice) {
  int i;

  /* Include user-defined sub-circuit netlist */
  for (i = 0; i < spice.num_include_netlist; i++) {
    spice.include_netlists[i].included = 0;
  }

  return;
}

void dump_include_user_defined_verilog_netlists(FILE* fp,
                                                t_spice spice) {
  int i;

  /* A valid file handler*/
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid File Handler!\n", __FILE__, __LINE__);
    exit(1);
  }

  /* Include user-defined sub-circuit netlist */
  for (i = 0; i < spice.num_include_netlist; i++) {
    if (0 == spice.include_netlists[i].included) {
      assert(NULL != spice.include_netlists[i].path);
      fprintf(fp, "// `include \"%s\"\n", spice.include_netlists[i].path);
      spice.include_netlists[i].included = 1;
    } else {
      assert(1 == spice.include_netlists[i].included);
    }
  } 

  return;
}

void dump_verilog_file_header(FILE* fp,
                              char* usage) {
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__); 
    exit(1);
  } 
  fprintf(fp,"//-------------------------------------------\n");
  fprintf(fp,"//    FPGA Synthesizable Verilog Netlist     \n");
  fprintf(fp,"//    Description: %s \n",usage);
  fprintf(fp,"//           Author: Xifan TANG              \n");
  fprintf(fp,"//        Organization: EPFL/IC/LSI          \n");
  fprintf(fp,"//    Date: %s \n", my_gettime());
  fprintf(fp,"//-------------------------------------------\n");
  fprintf(fp,"//----- Time scale -----\n");
  fprintf(fp,"`timescale 1ns / 1ps\n");
  fprintf(fp,"\n");

  return;
}

/* Dump preproc */
void dump_verilog_preproc(FILE* fp, 
                          t_syn_verilog_opts fpga_verilog_opts,
                          enum e_verilog_tb_type verilog_tb_type) {

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__); 
    exit(1);
  } 

  /* To enable timing */
  if (TRUE == fpga_verilog_opts.include_timing) {
    fprintf(fp, "`define %s 1\n", verilog_timing_preproc_flag);
    fprintf(fp, "\n");
  } 

  /* To enable timing */
  if (TRUE == fpga_verilog_opts.include_signal_init) {
    fprintf(fp, "`define %s 1\n", verilog_signal_init_preproc_flag);
    fprintf(fp, "\n");
  } 

  /* To enable formal verfication flag */
  if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) {
    fprintf(fp, "`define %s 1\n",
                 verilog_formal_verification_preproc_flag); // the flag to enable formal verification during compilation
    fprintf(fp, "\n");
  } 

  /* To enable functional verfication with Icarus */
  if (TRUE == fpga_verilog_opts.include_icarus_simulator) {
    fprintf(fp, "`define %s 1\n",
                 icarus_simulator_flag); // the flag to enable formal verification during compilation
    fprintf(fp, "\n");
  } 

  return;
}

void dump_simulation_preproc(FILE* fp, 
                             t_syn_verilog_opts fpga_verilog_opts,
                             enum e_verilog_tb_type verilog_tb_type) {

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__); 
    exit(1);
  } 

  /* To enable manualy checked simulation */
  if (TRUE == fpga_verilog_opts.print_top_testbench) {
    fprintf(fp, "`define %s 1\n", initial_simulation_flag);
    fprintf(fp, "\n");
  } 

  /* To enable auto-checked simulation */
  if (TRUE == fpga_verilog_opts.print_autocheck_top_testbench) {
    fprintf(fp, "`define %s 1\n", autochecked_simulation_flag);
    fprintf(fp, "\n");
  } 

  /* To enable pre-configured FPGA simulation */
  if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) {
    fprintf(fp, "`define %s 1\n", formal_simulation_flag); 
    fprintf(fp, "\n");
  } 

  return;
}

void dump_verilog_simulation_preproc(char* subckt_dir,
                                 t_syn_verilog_opts fpga_verilog_opts) {
  /* Create a file handler */
  FILE* fp = NULL;
  char* file_description = NULL;
  char* fname = NULL;

  fname = my_strcat(subckt_dir, 
                    defines_verilog_simulation_file_name);

  /* Create a file*/
  fp = fopen(fname, "w");

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,
               "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
               __FILE__, __LINE__, fname); 
    exit(1);
  } 

  /* Generate the descriptions*/
  file_description = "Simulation Flags";
  dump_verilog_file_header(fp, file_description);

  /* Dump the defines preproc flags*/
  dump_simulation_preproc(fp, fpga_verilog_opts, VERILOG_TB_TOP); 

  fclose(fp);

  /* Free */
  my_free(fname);

  return;
}

void dump_verilog_defines_preproc(char* subckt_dir,
                                 t_syn_verilog_opts fpga_verilog_opts) {
  /* Create a file handler */
  FILE* fp = NULL;
  char* file_description = NULL;
  char* fname = NULL;

  fname = my_strcat(subckt_dir, 
                    defines_verilog_file_name);

  /* Create a file*/
  fp = fopen(fname, "w");

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,
               "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
               __FILE__, __LINE__, fname); 
    exit(1);
  } 

  /* Generate the descriptions*/
  file_description = "Preproc Flags";
  dump_verilog_file_header(fp, file_description);

  /* Dump the defines preproc flags*/
  dump_verilog_preproc(fp, fpga_verilog_opts, VERILOG_TB_TOP); 

  fclose(fp);

  /* Free */
  my_free(fname);

  return;
}

void verilog_include_defines_preproc_file(FILE* fp, 
                                          char* verilog_dir) {
  char* temp_include_file_path = NULL;
  char* formatted_verilog_dir = NULL;

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!",
               __FILE__, __LINE__); 
    exit(1);
  } 

  fprintf(fp, "//------ Include defines: preproc flags -----\n");
  formatted_verilog_dir = format_dir_path(verilog_dir);
  temp_include_file_path = my_strcat(formatted_verilog_dir, defines_verilog_file_name);
  fprintf(fp, "`include \"%s\"\n", temp_include_file_path);
  fprintf(fp, "//------ End Include defines: preproc flags -----\n");
  my_free(temp_include_file_path);

  return;
}

void verilog_include_simulation_defines_file(FILE* fp, 
                                             char* verilog_dir) {
  char* temp_include_file_path = NULL;
  char* formatted_verilog_dir = NULL;

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!",
               __FILE__, __LINE__); 
    exit(1);
  } 

  fprintf(fp, "//------ Include simulation defines -----\n");
  formatted_verilog_dir = format_dir_path(verilog_dir);
  temp_include_file_path = my_strcat(formatted_verilog_dir, defines_verilog_simulation_file_name);
  fprintf(fp, "`include \"%s\"\n", temp_include_file_path);
  fprintf(fp, "//------ End Include simulation defines -----\n");
  my_free(temp_include_file_path);

  return;
}

/* Create a file handler for a subckt Verilog netlist */
FILE* verilog_create_one_subckt_file(char* subckt_dir,
                                     const char* subckt_name_prefix,
                                     const char* verilog_subckt_file_name_prefix,
                                     char** verilog_fname) {
  FILE* fp = NULL;
  char* file_description = NULL;

  char* temp = my_strcat(subckt_dir, verilog_subckt_file_name_prefix);
  (*verilog_fname) = my_strcat(temp, verilog_netlist_file_postfix);

  /* Create a file*/
  fp = fopen((*verilog_fname), "w");

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,
               "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
               __FILE__, __LINE__, (*verilog_fname)); 
    exit(1);
  } 

  /* Generate the descriptions*/
  file_description = (char*) my_malloc(sizeof(char) * (strlen(subckt_name_prefix) + 9));
  sprintf(file_description, 
          "%s in FPGA", 
          subckt_name_prefix);
 
  dump_verilog_file_header(fp, file_description);

  /* Free */
  my_free(temp);
  my_free(file_description);

  return fp;
}


/* Create a file handler for a subckt Verilog netlist */
FILE* verilog_create_one_subckt_file(char* subckt_dir,
                                     const char* subckt_name_prefix,
                                     const char* verilog_subckt_file_name_prefix,
                                     int grid_x, int grid_y,
                                     char** verilog_fname) {
  FILE* fp = NULL;
  char* file_description = NULL;

  (*verilog_fname) = my_strcat(subckt_dir, 
                               fpga_spice_create_one_subckt_filename(verilog_subckt_file_name_prefix, grid_x, grid_y, verilog_netlist_file_postfix));

  /* Create a file*/
  fp = fopen((*verilog_fname), "w");

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,
               "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
               __FILE__, __LINE__, (*verilog_fname)); 
    exit(1);
  } 

  /* Generate the descriptions*/
  if (-1 == grid_y) {
    file_description = (char*) my_malloc(sizeof(char) * (strlen(subckt_name_prefix) + 2
                                         + strlen(my_itoa(grid_x)) + 2 
                                         + 10));
    sprintf(file_description, 
            "%s [%d] in FPGA", 
            subckt_name_prefix, grid_x);
  } else {
    file_description = (char*) my_malloc(sizeof(char) * (strlen(subckt_name_prefix) + 2
                                         + strlen(my_itoa(grid_x)) + 2 + strlen(my_itoa(grid_y))
                                         + 10));
    sprintf(file_description, 
            "%s [%d][%d] in FPGA", 
            subckt_name_prefix, grid_x, grid_y);
  }
 
  dump_verilog_file_header(fp, file_description);

  /* Free */
  my_free(file_description);

  return fp;
}

/* Output all the created subckt file names in a header file,
 * that can be easily imported in a top-level netlist
 */
void dump_verilog_subckt_header_file(t_llist* subckt_llist_head,
                                     const char* subckt_dir,
                                     const char* header_file_name) {
  FILE* fp = NULL;
  char* verilog_fname = NULL;
  t_llist* temp = NULL; 

  verilog_fname = my_strcat(subckt_dir, 
                            header_file_name);

  /* Create a file*/
  fp = fopen(verilog_fname, "w");

  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,
               "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
               __FILE__, __LINE__, verilog_fname); 
    exit(1);
  } 

  /* Generate the descriptions*/
  dump_verilog_file_header(fp, "Header file");

  /* Output file names */
  temp = subckt_llist_head;
  while (temp) {
    fprintf(fp, "`include \"%s\"\n",
            (char*)(temp->dptr));
    temp = temp->next;
  }
  
  /* Close fp */
  fclose(fp);

  /* Free */
  my_free(verilog_fname);
   
  return;
}

/* Determine the split sign for generic port */
char determine_verilog_generic_port_split_sign(enum e_dump_verilog_port_type dump_port_type) {
  char ret;

  switch (dump_port_type) {
  case VERILOG_PORT_INPUT:
  case VERILOG_PORT_OUTPUT:
  case VERILOG_PORT_INOUT:
  case VERILOG_PORT_CONKT:
    ret = ',';
    break;
  case VERILOG_PORT_WIRE:
  case VERILOG_PORT_REG:
    ret = ';';
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of Verilog port to be dumped !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return ret;
}

/* Dump a generic Verilog port */
void dump_verilog_generic_port(FILE* fp, 
                               enum e_dump_verilog_port_type dump_port_type,
                               char* port_name, int port_lsb, int port_msb) {  
  boolean dump_single_port = FALSE;
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert((!(port_lsb < 0))&&(!(port_msb < 0)));
  if (port_lsb == port_msb) {
    dump_single_port = TRUE;
  }
  dump_single_port = FALSE; /* Disable it for a clear synthesis */

  switch (dump_port_type) {
  case VERILOG_PORT_INPUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"input %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"input [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_OUTPUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"output %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"output [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_INOUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"inout %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"inout [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_WIRE:
    if (TRUE == dump_single_port) {
      fprintf(fp,"wire %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"wire [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_REG:
    if (TRUE == dump_single_port) {
      fprintf(fp,"reg %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"reg [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_CONKT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"%s[%d] ", 
              port_name, port_lsb);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"%s[%d:%d] ", 
              port_name,
              port_lsb, port_msb);
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of Verilog port to be dumped !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}

/* Dump a generic Verilog port */
void dump_verilog_generic_port_no_repeat(FILE* fp, 
                               enum e_dump_verilog_port_type dump_port_type,
                               char* port_name, int port_lsb, int port_msb) {  
  boolean dump_single_port = FALSE;
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert((!(port_lsb < 0))&&(!(port_msb < 0)));
  if (port_lsb == port_msb) {
    dump_single_port = TRUE;
  }
  //dump_single_port = FALSE; /* Disable it for a clear synthesis */

  switch (dump_port_type) {
  case VERILOG_PORT_INPUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"input %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"input [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_OUTPUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"output %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"output [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_INOUT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"inout %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"inout [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_WIRE:
    if (TRUE == dump_single_port) {
      fprintf(fp,"wire %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"wire [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_REG:
    if (TRUE == dump_single_port) {
      fprintf(fp,"reg %s ", 
              port_name);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"reg [%d:%d] %s ", 
              port_lsb, port_msb,
              port_name);
    }
    break;
  case VERILOG_PORT_CONKT:
    if (TRUE == dump_single_port) {
      fprintf(fp,"%s[%d] ", 
              port_name, port_lsb);
    } else {
      assert(FALSE == dump_single_port);
      fprintf(fp,"%s[%d:%d] ", 
              port_name,
              port_lsb, port_msb);
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of Verilog port to be dumped !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}

char* chomp_verilog_prefix(char* verilog_node_prefix) {
  int len = 0;
  char* ret = NULL;

  if (NULL == verilog_node_prefix) {
    return NULL;
  }

  len = strlen(verilog_node_prefix); /* String length without the last "\0"*/
  ret = (char*)my_malloc(sizeof(char)*(len+1));
  
  /* Don't do anything when input is NULL*/
  if (NULL == verilog_node_prefix) {
    my_free(ret);
    return NULL;
  }
  strcpy(ret,verilog_node_prefix);
  /* If the path end up with "_" we should remove it*/
  while ('_' == ret[len-1]) {
    ret[len-1] = ret[len];
    len--;
  }

  return ret;
}

char* format_verilog_node_prefix(char* verilog_node_prefix) {
  int len = strlen(verilog_node_prefix); /* String length without the last "\0"*/
  char* ret = (char*)my_malloc(sizeof(char)*(len+1));
 
  /* Don't do anything when input is NULL*/ 
  if (NULL == verilog_node_prefix) {
    my_free(ret);
    return NULL;
  }

  strcpy(ret,verilog_node_prefix);
  /* If the path does not end up with "_" we should complete it*/
  /*
  if (ret[len-1] != '_') {
    strcat(ret, "_");
  }
  */
  return ret;
}

/* Return the port_type in a verilog format */
char* verilog_convert_port_type_to_string(enum e_spice_model_port_type port_type) {
  switch (port_type) {
  case SPICE_MODEL_PORT_INPUT: 
  case SPICE_MODEL_PORT_CLOCK: 
  case SPICE_MODEL_PORT_SRAM:
  case SPICE_MODEL_PORT_BL:
  case SPICE_MODEL_PORT_WL:
    return "input";
  case SPICE_MODEL_PORT_OUTPUT: 
    return "output";
  case SPICE_MODEL_PORT_INOUT: 
    return "inout";
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid port type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return NULL;
}

/* Dump all the global ports that are stored in the linked list 
 * Return the number of ports that have been dumped 
 */
int rec_dump_verilog_spice_model_lib_global_ports(FILE* fp, 
                                                  const t_spice_model* cur_spice_model,
                                                  boolean dump_port_type, 
                                                  boolean recursive,
                                                  boolean require_explicit_port_map) {
  int dumped_port_cnt;
  boolean dump_comma = FALSE;
  t_spice_model_port* cur_spice_model_port = NULL;
  t_llist* spice_model_head = NULL;
  t_llist* head = NULL;

  dumped_port_cnt = 0;

  /* Check */
  assert(NULL != cur_spice_model);
  if (0 < cur_spice_model->num_port) {
    assert(NULL != cur_spice_model->ports);
  }

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
  }

  rec_stats_spice_model_global_ports(cur_spice_model,
                                     recursive,
                                     &spice_model_head);

  /* Traverse the linked list and dump the ports */
  head = spice_model_head;
  while (head) {
    /* Get the port to be dumped */
    cur_spice_model_port = (t_spice_model_port*)(head->dptr);
    /* We have some port to dump ! 
     * Print a comment line 
     */
    /* Check if we need to dump a comma */
    if (TRUE == dump_comma) {
      fprintf(fp, ", //----- Global port of SPICE_MODEL(%s) -----\n",
                  cur_spice_model->name);
    }
    if (TRUE == dump_port_type) {
      fprintf(fp, "%s [0:%d] %s", 
              verilog_convert_port_type_to_string(cur_spice_model_port->type),
              cur_spice_model_port->size - 1, 
              cur_spice_model_port->lib_name);
    } else {
      /* Add explicit port mapping if required */
      if (TRUE == require_explicit_port_map) {
        fprintf(fp, ".%s(",
                cur_spice_model_port->lib_name);
      }
      fprintf(fp, "%s[0:%d]", 
            cur_spice_model_port->lib_name,
            cur_spice_model_port->size - 1); 
      if (TRUE == require_explicit_port_map) {
        fprintf(fp, ")");
      }
    }
    /* Decide if we need a comma */
    dump_comma = TRUE; 
    /* Update counter */
    dumped_port_cnt++;

    /* Go to the next node */
    head = head->next;
  }

  /* We have dumped some port! 
   * Print another comment line  
   */
  if (0 < dumped_port_cnt) {
    fprintf(fp, "\n");
  }

  /* Free linked list */
  head = spice_model_head;
  while (head) {
    head->dptr = NULL;
    head = head->next;
  }
  free_llist(spice_model_head);

  return dumped_port_cnt;
}

/* Dump all the global ports that are stored in the linked list 
 * Return the number of ports that have been dumped 
 */
int rec_dump_verilog_spice_model_global_ports(FILE* fp, 
                                              const t_spice_model* cur_spice_model,
                                              boolean dump_port_type, 
                                              boolean recursive,
                                              boolean require_explicit_port_map,
                                              boolean is_lib_name) {
  int dumped_port_cnt;
  boolean dump_comma = FALSE;
  t_spice_model_port* cur_spice_model_port = NULL;
  t_llist* spice_model_head = NULL;
  t_llist* head = NULL;

  dumped_port_cnt = 0;

  /* Check */
  assert(NULL != cur_spice_model);
  if (0 < cur_spice_model->num_port) {
    assert(NULL != cur_spice_model->ports);
  }

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
  }

  rec_stats_spice_model_global_ports(cur_spice_model,
                                     recursive,
                                     &spice_model_head);

  /* Traverse the linked list and dump the ports */
  head = spice_model_head;
  if (NULL != head) {
    fprintf(fp, "//----- Global port of SPICE_MODEL(%s) -----\n",
                cur_spice_model->name);
  }
  while (head) {
    /* Get the port to be dumped */
    cur_spice_model_port = (t_spice_model_port*)(head->dptr);
    /* We have some port to dump ! 
     * Print a comment line 
     */
    /* Check if we need to dump a comma */
    if (TRUE == dump_comma) {
      fprintf(fp, ",\n");
    }
    if (TRUE == dump_port_type) {
      fprintf(fp, "%s [0:%d] %s", 
              verilog_convert_port_type_to_string(cur_spice_model_port->type),
              cur_spice_model_port->size - 1, 
              cur_spice_model_port->prefix);
    } else {
      /* Add explicit port mapping if required */
      if (TRUE == require_explicit_port_map ) {
        if (TRUE == is_lib_name) {
          fprintf(fp, ".%s(",
                  cur_spice_model_port->lib_name);
        } else {
          fprintf(fp, ".%s(",
                  cur_spice_model_port->prefix);
        }
      }
      fprintf(fp, "%s[0:%d]", 
            cur_spice_model_port->prefix,
            cur_spice_model_port->size - 1); 
      if (TRUE == require_explicit_port_map) {
        fprintf(fp, ")");
      }
    }
    /* Decide if we need a comma */
    dump_comma = TRUE; 
    /* Update counter */
    dumped_port_cnt++;

    /* Go to the next node */
    head = head->next;
  }

  /* We have dumped some port! 
   * Print another comment line  
   */
  if (0 < dumped_port_cnt) {
    fprintf(fp, "\n");
  }

  /* Free linked list */
  head = spice_model_head;
  while (head) {
    head->dptr = NULL;
    head = head->next;
  }
  free_llist(spice_model_head);

  return dumped_port_cnt;
}

/* Dump all the global ports that are stored in the linked list */
int dump_verilog_global_ports(FILE* fp, t_llist* head,
                               boolean dump_port_type,
                               bool is_explicit_mapping) {
  t_llist* temp = head;
  t_spice_model_port* cur_global_port = NULL;
  int dumped_port_cnt = 0;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
  }

  /* fprintf(fp, "//----- BEGIN Global ports -----\n"); */
  while(NULL != temp) {
    cur_global_port = (t_spice_model_port*)(temp->dptr); 
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s(", 
              cur_global_port->prefix);
    }
    if (TRUE == dump_port_type) {
      fprintf(fp, "%s [0:%d] %s", 
              verilog_convert_port_type_to_string(cur_global_port->type),
              cur_global_port->size - 1, 
              cur_global_port->prefix);
    } else {
      fprintf(fp, "%s[0:%d]", 
              cur_global_port->prefix,
              cur_global_port->size - 1); 
    }
    if (true == is_explicit_mapping) {
      fprintf(fp, ")"); 
    }
    /* if this is the tail, we do not dump a comma */
    if (NULL != temp->next) {
     fprintf(fp, ", //---- global port \n");
    }
    /* Update counter */
    dumped_port_cnt++;
    /* Go to the next */
    temp = temp->next;
  }
  /* fprintf(fp, "//----- END Global ports -----\n"); */

  return dumped_port_cnt;
}

/* Dump all the global ports that are stored in the linked list */
int dump_verilog_global_ports_explicit(FILE* fp, t_llist* head,
                                       boolean dump_port_type) {
  t_llist* temp = head;
  t_spice_model_port* cur_global_port = NULL;
  int dumped_port_cnt = 0;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
  }

  /* fprintf(fp, "//----- BEGIN Global ports -----\n"); */
  while(NULL != temp) {
    cur_global_port = (t_spice_model_port*)(temp->dptr); 
    fprintf(fp, ".%s(", 
            cur_global_port->prefix);
    if (TRUE == dump_port_type) {
      fprintf(fp, "%s [0:%d] %s", 
              verilog_convert_port_type_to_string(cur_global_port->type),
              cur_global_port->size - 1, 
              cur_global_port->prefix);
    } else {
      fprintf(fp, "%s[0:%d]", 
              cur_global_port->prefix,
              cur_global_port->size - 1); 
    }
    fprintf(fp, ")");

    /* if this is the tail, we do not dump a comma */
    if (NULL != temp->next) {
     fprintf(fp, ", //---- global port \n");
    }
    /* Update counter */
    dumped_port_cnt++;
    /* Go to the next */
    temp = temp->next;
  }
  /* fprintf(fp, "//----- END Global ports -----\n"); */

  return dumped_port_cnt;
}

/* Always dump the output ports of a SRAM in MUX */
void dump_verilog_mux_sram_one_outport(FILE* fp, 
                                       t_sram_orgz_info* cur_sram_orgz_info,
                                       t_spice_model* cur_mux_spice_model, int mux_size,
                                       int sram_lsb, int sram_msb,
                                       int port_type_index, 
                                       enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  /* Keep the branch as it is, in case thing may become more complicated*/
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    if (0 == port_type_index) {
      port_name = "out";
    } else {
      assert(1 == port_type_index);
      port_name = "outb";
    }
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    if (0 == port_type_index) {
      port_name = "out";
    } else if (1 == port_type_index) {
      port_name = "outb";
    } else {
      assert(-1 == port_type_index);
      port_name = "in";
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    if (0 == port_type_index) {
      port_name = "out";
    } else {
      assert(1 == port_type_index);
      port_name = "outb";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*
                     (strlen(cur_mux_spice_model->prefix) + 5
                    + strlen(my_itoa(mux_size)) + 1
                    + strlen(my_itoa(cur_mux_spice_model->cnt)) + 1
                    + strlen(mem_model->prefix) + 1
                    + strlen(port_name) + 1));
  sprintf(port_full_name, "%s_size%d_%d_%s_%s", 
                          cur_mux_spice_model->prefix, mux_size,
                          cur_mux_spice_model->cnt,
                           mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* Always dump the output ports of a SRAM in MUX */
void dump_verilog_mux_sram_one_local_outport(FILE* fp, 
                                             t_sram_orgz_info* cur_sram_orgz_info,
                                             t_spice_model* cur_mux_spice_model, int mux_size,
                                             int sram_lsb, int sram_msb,
                                             int port_type_index, 
                                             enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  /* Keep the branch as it is, in case thing may become more complicated*/
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    if (0 == port_type_index) {
      port_name = "out_local_bus";
    } else {
      assert(1 == port_type_index);
      port_name = "outb_local_bus";
    }
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    if (0 == port_type_index) {
      port_name = "out_local_bus";
    } else if (1 == port_type_index) {
      port_name = "outb_local_bus";
    } else {
      assert(-1 == port_type_index);
      port_name = "in_local_bus";
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    if (0 == port_type_index) {
      port_name = "out_local_bus";
    } else {
      assert(1 == port_type_index);
      port_name = "outb_local_bus";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*
                     (strlen(cur_mux_spice_model->prefix) + 5
                    + strlen(my_itoa(mux_size)) + 1
                    + strlen(my_itoa(cur_mux_spice_model->cnt)) + 1
                    + strlen(mem_model->prefix) + 1
                    + strlen(port_name) + 1));
  sprintf(port_full_name, "%s_size%d_%d_%s_%s", 
                          cur_mux_spice_model->prefix, mux_size,
                          cur_mux_spice_model->cnt,
                           mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* Always dump the output ports of a SRAM */
void dump_verilog_sram_one_local_outport(FILE* fp, 
                                         t_sram_orgz_info* cur_sram_orgz_info,
                                         int sram_lsb, int sram_msb,
                                         int port_type_index, 
                                         enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  /* Keep the branch as it is, in case thing may become more complicated*/
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    if (0 == port_type_index) {
      port_name = "out_local_bus";
    } else {
      assert(1 == port_type_index);
      port_name = "outb_local_bus";
    }
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    if (0 == port_type_index) {
      port_name = "ccff_out_local_bus";
    } else if (1 == port_type_index) {
      port_name = "ccff_outb_local_bus";
    } else {
      assert(-1 == port_type_index);
      port_name = "ccff_in_local_bus";
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    if (0 == port_type_index) {
      port_name = "out_local_bus";
    } else {
      assert(1 == port_type_index);
      port_name = "outb_local_bus";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(mem_model->prefix) + strlen(port_name) + 1 + 1));
  sprintf(port_full_name, "%s_%s", mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}



/* Always dump the output ports of a SRAM */
void dump_verilog_sram_one_outport(FILE* fp, 
                                   t_sram_orgz_info* cur_sram_orgz_info,
                                   int sram_lsb, int sram_msb,
                                   int port_type_index, 
                                   enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  /* Keep the branch as it is, in case thing may become more complicated*/
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    if (0 == port_type_index) {
      port_name = "out";
    } else {
      assert(1 == port_type_index);
      port_name = "outb";
    }
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    if (0 == port_type_index) {
      port_name = "ccff_out";
    } else if (1 == port_type_index) {
      port_name = "ccff_outb";
    } else {
      assert(-1 == port_type_index);
      port_name = "ccff_in";
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    if (0 == port_type_index) {
      port_name = "out";
    } else {
      assert(1 == port_type_index);
      port_name = "outb";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(mem_model->prefix) + strlen(port_name) + 1 + 1));
  sprintf(port_full_name, "%s_%s", mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* Dump SRAM output ports, including two ports, out and outb */
void dump_verilog_sram_outports(FILE* fp, 
                                t_sram_orgz_info* cur_sram_orgz_info,
                                int sram_lsb, int sram_msb,
                                enum e_dump_verilog_port_type dump_port_type) {
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  if (0 > (sram_msb - sram_lsb)) {
    return;
  }

  if ((sram_lsb < 0)||(sram_msb < 0)) {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid sram_lsb(%d) and sram_msb(%d)!\n",
               __FILE__, __LINE__, sram_lsb, sram_msb);
    return;
  }

  /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
  dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                sram_lsb, sram_msb, 
                                0, dump_port_type);
  fprintf(fp, ",\n");
  /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
  dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                sram_lsb, sram_msb, 
                                1, dump_port_type);
  
  return;
}

/* Dump SRAM ports visible for formal verification purpose, 
 * which is supposed to be the last port in the port list */
void dump_verilog_formal_verification_sram_ports(FILE* fp, 
                                                 t_sram_orgz_info* cur_sram_orgz_info,
                                                 int sram_lsb, int sram_msb,
                                                 enum e_dump_verilog_port_type dump_port_type,
                                                 bool is_explicit_mapping) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    mem_model = cur_sram_orgz_info->standalone_sram_info->mem_model;
    port_name = "out_fm";
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    mem_model = cur_sram_orgz_info->ccff_info->mem_model;
    port_name = "out_fm";
    break;
  case SPICE_SRAM_MEMORY_BANK:
    mem_model = cur_sram_orgz_info->mem_bank_info->mem_model;
    port_name = "out_fm";
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(mem_model->prefix) + strlen(port_name) + 1 + 1));
  sprintf(port_full_name, "%s_%s", mem_model->prefix, port_name);
  if (true == is_explicit_mapping) {
    fprintf(fp, ".%s(", 
            port_full_name);
  }
  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 
  if (true == is_explicit_mapping) {
    fprintf(fp, ")");
  }

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}


void dump_verilog_sram_one_port(FILE* fp, 
                                t_sram_orgz_info* cur_sram_orgz_info,
                                int sram_lsb, int sram_msb,
                                int port_type_index,
                                enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;
  enum e_dump_verilog_port_type actual_dump_port_type = dump_port_type;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Get memory_model */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
 
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    mem_model = cur_sram_orgz_info->standalone_sram_info->mem_model;
    if (0 == port_type_index) {
      port_name = "out";
    } else {
      assert(1 == port_type_index);
      port_name = "outb";
    }
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    mem_model = cur_sram_orgz_info->ccff_info->mem_model;
    if (0 == port_type_index) {
      port_name = "ccff_head";
    } else if (1 == port_type_index) {
      assert(1 == port_type_index);
      port_name = "ccff_tail";
      /* Special case: scan-chain ff output should be an output always */
      if (VERILOG_PORT_INPUT == dump_port_type) {
        actual_dump_port_type = VERILOG_PORT_OUTPUT;
      }
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    mem_model = cur_sram_orgz_info->mem_bank_info->mem_model;
    if (0 == port_type_index) {
      port_name = "bl";
    } else if (1 == port_type_index) {
      port_name = "wl";
    /* Create inverted BL and WL signals */
    } else if (2 == port_type_index) {
      port_name = "blb";
    } else if (3 == port_type_index) {
      port_name = "wlb";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(mem_model->prefix) + strlen(port_name) + 1 + 1));
  sprintf(port_full_name, "%s_%s", mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, actual_dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* Wire SRAM ports in formal verififcation purpose to regular SRAM ports */
void dump_verilog_formal_verification_sram_ports_wiring(FILE* fp, 
                                                        t_sram_orgz_info* cur_sram_orgz_info,
                                                        int sram_lsb, int sram_msb) {
  fprintf(fp, "assign ");
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE: 
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
                                        sram_lsb, sram_msb,
                                        0, VERILOG_PORT_CONKT);
    break;
  case SPICE_SRAM_MEMORY_BANK:
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
                                  sram_lsb, sram_msb,
                                  0, VERILOG_PORT_CONKT);
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  fprintf(fp, " = ");

  dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info,
                                              sram_lsb, sram_msb,
                                              VERILOG_PORT_CONKT, false);
  fprintf(fp, ";\n");

  return;
}

/* Wire SRAM ports in formal verififcation purpose to regular SRAM ports */
void dump_verilog_formal_verification_mux_sram_ports_wiring(FILE* fp, 
                                                            t_sram_orgz_info* cur_sram_orgz_info,
                                                            t_spice_model* cur_mux_spice_model, int mux_size,
                                                            int sram_lsb, int sram_msb) {
  fprintf(fp, "assign ");

  dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info,
                                    cur_mux_spice_model, mux_size,
                                    sram_lsb, sram_msb,
                                    0, VERILOG_PORT_CONKT);

  fprintf(fp, " = ");

  dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info,
                                              sram_lsb, sram_msb,
                                              VERILOG_PORT_CONKT, false);
  fprintf(fp, ";\n");

  return;
}

/* Dump SRAM ports, which is supposed to be the last port in the port list */
void dump_verilog_sram_local_ports(FILE* fp, 
                                   t_sram_orgz_info* cur_sram_orgz_info,
                                   int sram_lsb, int sram_msb,
                                   enum e_dump_verilog_port_type dump_port_type,
                                   bool is_explicit_mapping) {
  /* Need to dump inverted BL/WL if needed */
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;
  t_spice_model* cur_sram_verilog_model = NULL;
  t_spice_model* ccff_mem_model = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  if (0 > (sram_msb - sram_lsb)) {
    return;
  }

  if ((sram_lsb < 0)||(sram_msb < 0)) {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid sram_lsb(%d) and sram_msb(%d)!\n",
               __FILE__, __LINE__, sram_lsb, sram_msb);
    return;
  }

  /* Get model of the configuration chain */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &ccff_mem_model);

  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
  case SPICE_SRAM_MEMORY_BANK:
    /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               0, dump_port_type);
    fprintf(fp, ",\n");
    /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               1, dump_port_type);
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s_ccff_head(",
                   ccff_mem_model->prefix);
    }
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                        sram_lsb, sram_lsb, 
                                        -1, dump_port_type);
    if (true == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    fprintf(fp, ",\n");
    /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s_ccff_tail(",
                   ccff_mem_model->prefix);
    }
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                        sram_msb, sram_msb, 
                                        0, dump_port_type);
    if (true == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /* Find the BLB and WLB port, if there is any */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &cur_sram_verilog_model);
  find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                 &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
  /* BL inverted port */
  if (1 == num_blb_ports) {
    fprintf(fp, ",\n");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               2, dump_port_type);
  }
  /* WL inverted port */
  if (1 == num_wlb_ports) {
    fprintf(fp, ",\n");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               3, dump_port_type);
  }
  
  return;
}


/* Dump SRAM ports, which is supposed to be the last port in the port list */
void dump_verilog_sram_ports(FILE* fp, 
                             t_sram_orgz_info* cur_sram_orgz_info,
                             int sram_lsb, int sram_msb,
                             enum e_dump_verilog_port_type dump_port_type) {
  /* Need to dump inverted BL/WL if needed */
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;
  t_spice_model* cur_sram_verilog_model = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  if (0 > (sram_msb - sram_lsb)) {
    return;
  }

  if ((sram_lsb < 0)||(sram_msb < 0)) {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid sram_lsb(%d) and sram_msb(%d)!\n",
               __FILE__, __LINE__, sram_lsb, sram_msb);
    return;
  }
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
  case SPICE_SRAM_MEMORY_BANK:
    /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               0, dump_port_type);
    fprintf(fp, ",\n");
    /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               1, dump_port_type);
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_lsb, 
                               0, dump_port_type);
    fprintf(fp, ",\n");
    /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_msb, sram_msb, 
                               1, dump_port_type);
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /* Find the BLB and WLB port, if there is any */
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &cur_sram_verilog_model);
  find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                 &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
  /* BL inverted port */
  if (1 == num_blb_ports) {
    fprintf(fp, ",\n");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               2, dump_port_type);
  }
  /* WL inverted port */
  if (1 == num_wlb_ports) {
    fprintf(fp, ",\n");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               sram_lsb, sram_msb, 
                               3, dump_port_type);
  }
  
  return;
}

void dump_verilog_reserved_sram_one_port(FILE* fp, 
                                         t_sram_orgz_info* cur_sram_orgz_info,
                                         int sram_lsb, int sram_msb,
                                         int port_type_index,
                                         enum e_dump_verilog_port_type dump_port_type) {
  t_spice_model* mem_model = NULL;
  char* port_name = NULL;
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }
 
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
  case SPICE_SRAM_SCAN_CHAIN:
    return;
  case SPICE_SRAM_MEMORY_BANK:
    get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
    if (0 == port_type_index) {
      port_name = "reserved_bl";
    } else {
      assert(1 == port_type_index);
      port_name = "reserved_wl";
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(mem_model->prefix) + strlen(port_name) + 1 + 1));
  sprintf(port_full_name, "%s_%s", mem_model->prefix, port_name);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, sram_lsb, sram_msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}


/* Dump SRAM ports, which is supposed to be the last port in the port list */
void dump_verilog_reserved_sram_ports(FILE* fp, 
                                      t_sram_orgz_info* cur_sram_orgz_info,
                                      int sram_lsb, int sram_msb,
                                      enum e_dump_verilog_port_type dump_port_type) {
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  if (0 > (sram_msb - sram_lsb)) {
    return;
  }

  /* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */ 
  
  if ((sram_lsb < 0)||(sram_msb < 0)) {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid sram_lsb(%d) and sram_msb(%d)!\n",
               __FILE__, __LINE__, sram_lsb, sram_msb);
    return;
  }

  dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info,
                                      sram_lsb, sram_msb,
                                      0, dump_port_type);
  fprintf(fp, ",\n");
  /* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */ 
  dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info,
                                      sram_lsb, sram_msb,
                                      1, dump_port_type);
 
  return;
}


/* Dump a verilog submodule of SRAMs in MUX, according to SRAM organization type */
void dump_verilog_mux_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info,
                                     t_spice_model* cur_mux_verilog_model, int mux_size,
                                     t_spice_model* cur_sram_verilog_model) {
  int cur_bl, cur_wl, cur_num_sram;
  int num_bl_ports, num_wl_ports;
  t_spice_model_port** bl_port = NULL;
  t_spice_model_port** wl_port = NULL;
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;

  int num_bl_per_sram = 0;
  int num_wl_per_sram = 0;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  assert(NULL != cur_sram_orgz_info);
  assert(NULL != cur_sram_verilog_model);
  assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
        || (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));

  /* Get current index of SRAM module */
  cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info); 

  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_MEMORY_BANK:
    /* Detect the SRAM SPICE model linked to this SRAM port */
    find_bl_wl_ports_spice_model(cur_sram_verilog_model, 
                                 &num_bl_ports, &bl_port, &num_wl_ports, &wl_port); 
    assert(1 == num_bl_ports);
    assert(1 == num_wl_ports);
    num_bl_per_sram = bl_port[0]->size; 
    num_wl_per_sram = wl_port[0]->size; 
    /* Find the BLB and WLB port, if there is any */
    find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                   &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
    if (1 == num_blb_ports) {
      assert(num_bl_per_sram == blb_port[0]->size);
    } else {
      assert(0 == num_blb_ports);
    }
    if (1 == num_wlb_ports) {
      assert(num_wl_per_sram == wlb_port[0]->size);
    } else {
      assert(0 == num_wlb_ports);
    }

    /* SRAM subckts*/
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      cur_mux_verilog_model, mux_size,
                                      cur_num_sram, cur_num_sram,
                                      0, VERILOG_PORT_CONKT);
    fprintf(fp, ",");
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      cur_mux_verilog_model, mux_size,
                                      cur_num_sram, cur_num_sram,
                                      0, VERILOG_PORT_CONKT);
    fprintf(fp, ",");
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      cur_mux_verilog_model, mux_size,
                                      cur_num_sram, cur_num_sram,
                                      1, VERILOG_PORT_CONKT);
    fprintf(fp, ",");
    get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &cur_bl, &cur_wl); 
    /* Connect to Bit lines and Word lines, consider each conf_bit */
    fprintf(fp, "%s_size%d_%d_configbus0[%d:%d], ", 
            cur_mux_verilog_model->prefix, mux_size, cur_mux_verilog_model->cnt, 
            cur_num_sram, cur_num_sram + num_bl_per_sram - 1); 
    fprintf(fp, "%s_size%d_%d_configbus1[%d:%d] ", 
            cur_mux_verilog_model->prefix, mux_size, cur_mux_verilog_model->cnt, 
            cur_num_sram, cur_num_sram + num_wl_per_sram - 1); /* Outputs */
    /* If we have a BLB or WLB, we need to dump inverted config_bus */
    if (1 == num_blb_ports) { 
      fprintf(fp, ", ");
      fprintf(fp, "%s_size%d_%d_configbus0_b[%d:%d] ", 
              cur_mux_verilog_model->prefix, mux_size, cur_mux_verilog_model->cnt, 
              cur_num_sram, cur_num_sram + num_bl_per_sram - 1); 
    }
    if (1 == num_wlb_ports) { 
      fprintf(fp, ", ");
      fprintf(fp, "%s_size%d_%d_configbus1_b[%d:%d] ", 
              cur_mux_verilog_model->prefix, mux_size, cur_mux_verilog_model->cnt, 
              cur_num_sram, cur_num_sram + num_wl_per_sram - 1); 
    }

    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    update_sram_orgz_info_num_blwl(cur_sram_orgz_info, 
                                   cur_bl + 1,
                                   cur_wl + 1);
    break;
  case SPICE_SRAM_STANDALONE:
    /* SRAM subckts*/
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
    fprintf(fp, "%s_out[%d], ", cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt); /* Input*/
    fprintf(fp, "%s_out[%d], %s_outb[%d] ", 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt); /* Outputs */
    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* Add a scan-chain DFF module here ! */
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
    /* Input of Scan-chain DFF, should be connected to the output of its precedent */
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info,
                               cur_num_sram,
                               cur_num_sram,
                               0, VERILOG_PORT_CONKT);
    fprintf(fp, ", \n");  //
    /* Output of Scan-chain DFF, should be connected to the output of its successor */
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info,
                               cur_num_sram,
                               cur_num_sram,
                               1, VERILOG_PORT_CONKT);
    fprintf(fp, ", \n");  //
    /* Memory outputs of Scan-chain DFF, should be connected to the SRAM(memory port) of IOPAD, MUX and LUT */
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      cur_mux_verilog_model, mux_size,
                                      cur_num_sram,
                                      cur_num_sram,
                                      1, VERILOG_PORT_CONKT);
    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /* Update the counter */
  cur_sram_verilog_model->cnt++;

  return;
}



/* Dump a verilog submodule of SRAM, according to SRAM organization type */
void dump_verilog_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info,
                                 t_spice_model* cur_sram_verilog_model) {
  int cur_bl, cur_wl, cur_num_sram;
  int num_bl_ports, num_wl_ports;
  t_spice_model_port** bl_port = NULL;
  t_spice_model_port** wl_port = NULL;
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;

  int num_bl_per_sram = 0;
  int num_wl_per_sram = 0;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  assert(NULL != cur_sram_orgz_info);
  assert(NULL != cur_sram_verilog_model);
  assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
        || (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));

  /* Get current index of SRAM module */
  cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info); 

  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_MEMORY_BANK:
    /* Detect the SRAM SPICE model linked to this SRAM port */
    find_bl_wl_ports_spice_model(cur_sram_verilog_model, 
                                 &num_bl_ports, &bl_port, &num_wl_ports, &wl_port); 
    assert(1 == num_bl_ports);
    assert(1 == num_wl_ports);
    num_bl_per_sram = bl_port[0]->size; 
    num_wl_per_sram = wl_port[0]->size; 
    /* Find the BLB and WLB port, if there is any */
    find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                   &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
    if (1 == num_blb_ports) {
      assert(num_bl_per_sram == blb_port[0]->size);
    } else {
      assert(0 == num_blb_ports);
    }
    if (1 == num_wlb_ports) {
      assert(num_wl_per_sram == wlb_port[0]->size);
    } else {
      assert(0 == num_wlb_ports);
    }

    /* SRAM subckts*/
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
    fprintf(fp, "%s_out[%d], ", cur_sram_verilog_model->prefix, cur_num_sram); /* Input*/
    fprintf(fp, "%s_out[%d], %s_outb[%d], ", 
            cur_sram_verilog_model->prefix, cur_num_sram, 
            cur_sram_verilog_model->prefix, cur_num_sram); /* Outputs */
    get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &cur_bl, &cur_wl); 
    /* Connect to Bit lines and Word lines, consider each conf_bit */
    fprintf(fp, "%s_%d_configbus0[%d:%d], ", 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
            cur_bl, cur_bl + num_bl_per_sram - 1); 
    fprintf(fp, "%s_%d_configbus1[%d:%d] ", 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
            cur_wl, cur_wl + num_wl_per_sram - 1); /* Outputs */
    if (1 == num_blb_ports) {
      fprintf(fp, ", ");
      fprintf(fp, "%s_%d_configbus0_b[%d:%d] ", 
              cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
              cur_bl, cur_bl + num_bl_per_sram - 1); 
    }
    if (1 == num_wlb_ports) {
      fprintf(fp, ", ");
      fprintf(fp, "%s_%d_configbus1_b[%d:%d] ", 
              cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
              cur_wl, cur_wl + num_wl_per_sram - 1); /* Outputs */
    }
    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    update_sram_orgz_info_num_blwl(cur_sram_orgz_info, 
                                   cur_bl + 1,
                                   cur_wl + 1);
    break;
  case SPICE_SRAM_STANDALONE:
    /* SRAM subckts*/
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
    fprintf(fp, "%s_out[%d], ", cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt); /* Input*/
    fprintf(fp, "%s_out[%d], %s_outb[%d] ", 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt, 
            cur_sram_verilog_model->prefix, cur_sram_verilog_model->cnt); /* Outputs */
    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* Add a scan-chain DFF module here ! */
    fprintf(fp, "%s %s_%d_ (", cur_sram_verilog_model->name, cur_sram_verilog_model->prefix, 
                               cur_sram_verilog_model->cnt); 
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE, TRUE)) {
      fprintf(fp, ",\n");
    }
   /* Input of Scan-chain DFF, should be connected to the output of its precedent */
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info,
                               cur_num_sram,
                               cur_num_sram,
                               0, VERILOG_PORT_CONKT);
    fprintf(fp, ", \n");  //
    /* Output of Scan-chain DFF, should be connected to the output of its successor */
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info,
                               cur_num_sram,
                               cur_num_sram,
                               1, VERILOG_PORT_CONKT);
    fprintf(fp, ", \n");  //
    /* Memory outputs of Scan-chain DFF, should be connected to the SRAM(memory port) of IOPAD, MUX and LUT */
    dump_verilog_sram_one_outport(fp,  
                                  cur_sram_orgz_info,
                                  cur_num_sram, cur_num_sram,
                                  1, VERILOG_PORT_CONKT);
    fprintf(fp, ");\n");  //
    /* Update the counter */
    update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info,
                                      cur_num_sram + 1);
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  /* Update the counter */
  cur_sram_verilog_model->cnt++;

  return;
}

void dump_verilog_ccff_config_bus(FILE* fp,
                                 t_spice_model* mem_spice_model, 
                                 t_sram_orgz_info* cur_sram_orgz_info,
                                 int lsb, int msb,
                                 enum e_dump_verilog_port_type dump_port_type) {
  char* port_full_name = NULL;   
 
  /* Check */
  assert(NULL != mem_spice_model);
  assert(SPICE_MODEL_CCFF == mem_spice_model->type);

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*
                                   ( strlen(mem_spice_model->prefix) + 1
                                   + strlen(my_itoa(mem_spice_model->cnt)) + 12 + 1));
  sprintf(port_full_name, "%s_%d_config_bus0", mem_spice_model->prefix, mem_spice_model->cnt);

  dump_verilog_generic_port(fp, dump_port_type, port_full_name, lsb, msb); 

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* Dump MUX reserved and normal configuration wire bus */
void dump_verilog_mem_config_bus(FILE* fp, t_spice_model* mem_spice_model, 
                                 t_sram_orgz_info* cur_sram_orgz_info,
                                 int cur_num_sram,
                                 int num_mem_reserved_conf_bits,
                                 int num_mem_conf_bits) { 
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert(NULL != mem_spice_model);
  assert((SPICE_MODEL_SRAM == mem_spice_model->type)
        || (SPICE_MODEL_CCFF == mem_spice_model->type));

  /* Depend on the style of configuraion circuit */
  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* We need to connect CCFF inputs and outputs in cacading
     * Scan-chain FF outputs are directly wired to SRAM inputs of MUXes  
     */ 
    /* Connect first CCFF to the head */
    /*
    fprintf(fp, "assign ");
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, cur_num_sram, cur_num_sram, -1, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, cur_num_sram, cur_num_sram, 0, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
     */ 
    /* Connect last CCFF to the tail */
    /*
    fprintf(fp, "assign ");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, cur_num_sram + num_mem_conf_bits - 1, cur_num_sram + num_mem_conf_bits - 1, 1, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, cur_num_sram + num_mem_conf_bits - 1, cur_num_sram + num_mem_conf_bits - 1, 0, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
     */ 
    /* Connect CCFFs into chains */
    /* Cascade the CCFF between head and tail */
    /*
    if (1 < num_mem_conf_bits) {
      fprintf(fp, "assign ");
      dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                    cur_num_sram + 1, cur_num_sram + num_mem_conf_bits - 1,
                                    -1, VERILOG_PORT_CONKT);
      fprintf(fp, " = ");
      dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                    cur_num_sram, cur_num_sram + num_mem_conf_bits - 2,
                                    0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
     */ 
    break;
  case SPICE_SRAM_MEMORY_BANK:
    /* Find the BLB and WLB port, if there is any */
    find_blb_wlb_ports_spice_model(mem_spice_model, 
                                   &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
    /* configuration wire bus */
    if (0 < (num_mem_reserved_conf_bits + num_mem_conf_bits)) {
      /* First bus is for sram_out in CMOS MUX or BL in RRAM MUX */
      fprintf(fp, "wire [%d:%d] %s_%d_configbus0;\n",
              cur_num_sram,
              cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1,
              mem_spice_model->prefix, mem_spice_model->cnt);
      /* Second bus is for sram_out_inv in CMOS MUX or WL in RRAM MUX */
      fprintf(fp, "wire [%d:%d] %s_%d_configbus1;\n",
              cur_num_sram,
              cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1,
              mem_spice_model->prefix, mem_spice_model->cnt);
      if (1 == num_blb_ports) {
        fprintf(fp, "wire [%d:%d] %s_%d_configbus0_b;\n",
                cur_num_sram,
                cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1,
                mem_spice_model->prefix, mem_spice_model->cnt);
      }
      if (1 == num_wlb_ports) {
        fprintf(fp, "wire [%d:%d] %s_%d_configbus1_b;\n",
                cur_num_sram,
                cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1,
                mem_spice_model->prefix, mem_spice_model->cnt);
      }
    }
    /* Connect wires to config bus */
    /* reserved configuration bits */
    if (0 < num_mem_reserved_conf_bits) {
      fprintf(fp, "assign %s_%d_configbus0[%d:%d] = ",
              mem_spice_model->prefix, mem_spice_model->cnt,
              cur_num_sram,
              cur_num_sram + num_mem_reserved_conf_bits - 1);
      dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info, 
                                          0, num_mem_reserved_conf_bits - 1,
                                          0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
      fprintf(fp, "assign %s_%d_configbus1[%d:%d] = ",
              mem_spice_model->prefix, mem_spice_model->cnt,
              cur_num_sram,
              cur_num_sram + num_mem_reserved_conf_bits - 1);
      dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info, 
                                          0, num_mem_reserved_conf_bits - 1,
                                          1, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    /* normal configuration bits */
    if (0 < num_mem_conf_bits) {
      fprintf(fp, "assign %s_%d_configbus0[%d:%d] = ",
              mem_spice_model->prefix, mem_spice_model->cnt,
              cur_num_sram + num_mem_reserved_conf_bits,
              cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1);
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 cur_num_sram, cur_num_sram + num_mem_conf_bits - 1,
                                 0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
      fprintf(fp, "assign %s_%d_configbus1[%d:%d] = ",
              mem_spice_model->prefix,  mem_spice_model->cnt,
              cur_num_sram + num_mem_reserved_conf_bits,
              cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1);
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 cur_num_sram, cur_num_sram + num_mem_conf_bits - 1,
                                 1, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
      /* Dump inverted config_bus if needed */
      if (1 == num_blb_ports) {
        fprintf(fp, "assign %s_%d_configbus0_b[%d:%d] = ",
                mem_spice_model->prefix, mem_spice_model->cnt,
                cur_num_sram + num_mem_reserved_conf_bits,
                cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1);
        dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                   cur_num_sram, cur_num_sram + num_mem_conf_bits - 1,
                                   2, VERILOG_PORT_CONKT);
        fprintf(fp, ";\n");
      }
      if (1 == num_wlb_ports) {
        fprintf(fp, "assign %s_%d_configbus1_b[%d:%d] = ",
                mem_spice_model->prefix,  mem_spice_model->cnt,
                cur_num_sram + num_mem_reserved_conf_bits,
                cur_num_sram + num_mem_reserved_conf_bits + num_mem_conf_bits - 1);
        dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                   cur_num_sram, cur_num_sram + num_mem_conf_bits - 1,
                                   3, VERILOG_PORT_CONKT);
        fprintf(fp, ";\n");
      }
    }
      break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}

/* Dump MUX reserved and normal configuration wire bus */
void dump_verilog_cmos_mux_config_bus(FILE* fp, t_spice_model* mux_spice_model, 
                                      t_sram_orgz_info* cur_sram_orgz_info,
                                      int mux_size, int cur_num_sram,
                                      int num_mux_reserved_conf_bits,
                                      int num_mux_conf_bits) { 
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;
  t_spice_model* cur_sram_verilog_model = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert(NULL != mux_spice_model);
  assert(SPICE_MODEL_MUX == mux_spice_model->type);

  switch(cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* We do not need any configuration bus
     * Scan-chain FF outputs are directly wired to SRAM inputs of MUXes  
     */ 
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                      -1, VERILOG_PORT_WIRE);
    fprintf(fp, ";\n");

    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                      0, VERILOG_PORT_WIRE);
    fprintf(fp, ";\n");

    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                      1, VERILOG_PORT_WIRE);
    fprintf(fp, ";\n");
    /* We need to connect CCFF inputs and outputs in cacading
     * Scan-chain FF outputs are directly wired to SRAM inputs of MUXes  
     */ 
    /* Connect first CCFF to the head */
    fprintf(fp, "assign ");
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram, 
                                      -1, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                        cur_num_sram, cur_num_sram, 
                                        -1, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
    /* Connect last CCFF to the tail */
    fprintf(fp, "assign ");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                        cur_num_sram + num_mux_conf_bits - 1, cur_num_sram + num_mux_conf_bits - 1, 
                                        0, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram + num_mux_conf_bits - 1, cur_num_sram + num_mux_conf_bits - 1,
                                      0, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
    /* Connect CCFFs into chains */
    /* Connect the first CCFF (LSB) to the head */
    /* Connect the last CCFF (MSB) to the tail */
    /* Cascade the CCFF between head and tail */
    if (1 < num_mux_conf_bits) {
      fprintf(fp, "assign ");
      dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                        mux_spice_model, mux_size,
                                        cur_num_sram + 1, cur_num_sram + num_mux_conf_bits - 1,
                                        -1, VERILOG_PORT_CONKT);
      fprintf(fp, " = ");
      dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                        mux_spice_model, mux_size,
                                        cur_num_sram, cur_num_sram + num_mux_conf_bits - 2,
                                        0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    /* configuration wire bus */
    /* First bus is for sram_out in CMOS MUX */
    fprintf(fp, "wire [%d:%d] %s_size%d_%d_configbus0;\n",
                cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
    /* Second bus is for sram_out_inv in CMOS MUX */
    fprintf(fp, "wire [%d:%d] %s_size%d_%d_configbus1;\n",
                cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
    /* Declare output ports as wires */
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                      0, VERILOG_PORT_WIRE);
    fprintf(fp, ";\n");
    /* Declare output ports as wires */
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                      1, VERILOG_PORT_WIRE);
    fprintf(fp, ";\n");
    /* Connect wires to config bus */
    fprintf(fp, "assign %s_size%d_%d_configbus0[%d:%d] = ",
                mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
                cur_num_sram, cur_num_sram + num_mux_conf_bits - 1);
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                               0, VERILOG_PORT_CONKT);
    fprintf(fp, ";\n");
    fprintf(fp, "assign %s_size%d_%d_configbus1[%d:%d] = ",
            mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
            cur_num_sram, cur_num_sram + num_mux_conf_bits - 1);
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                               cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                               1, VERILOG_PORT_CONKT);
    fprintf(fp, ";\n");
    /* Find the BLB and WLB port, if there is any */
    get_sram_orgz_info_mem_model(cur_sram_orgz_info, &cur_sram_verilog_model);
    find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                   &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
    /* Dump inverted config_bus if needed */
    if (1 == num_blb_ports) {
      fprintf(fp, "wire [%d:%d] %s_size%d_%d_configbus0_b;\n",
                  cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                  mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
      fprintf(fp, "assign %s_size%d_%d_configbus0_b[%d:%d] = ",
                  mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
                  cur_num_sram, cur_num_sram + num_mux_conf_bits - 1);
       dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                  cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                  2, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    if (1 == num_wlb_ports) {
    fprintf(fp, "wire [%d:%d] %s_size%d_%d_configbus1_b;\n",
                cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
      fprintf(fp, "assign %s_size%d_%d_configbus1_b[%d:%d] = ",
              mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
              cur_num_sram, cur_num_sram + num_mux_conf_bits - 1);
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                 3, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid SRAM organization!\n", 
               __FILE__, __LINE__);
    exit(1);
  }
  return;

}

/* Dump MUX reserved and normal configuration wire bus */
void dump_verilog_mux_config_bus(FILE* fp, t_spice_model* mux_spice_model, 
                                 t_sram_orgz_info* cur_sram_orgz_info,
                                 int mux_size, int cur_num_sram,
                                 int num_mux_reserved_conf_bits,
                                 int num_mux_conf_bits) { 
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert(NULL != mux_spice_model);
  assert(SPICE_MODEL_MUX == mux_spice_model->type);

  /* depend on the design technology of this MUX:
   * bus connections are different
   * SRAM MUX: bus is connected to the output ports of SRAM
   * RRAM MUX: bus is connected to the BL/WL of MUX
   * TODO: Maybe things will become even more complicated, 
   * the bus connections may depend on the type of configuration circuit...
   * Currently, this is fine.
   */
  switch (mux_spice_model->design_tech) {
  case SPICE_MODEL_DESIGN_CMOS:
    dump_verilog_cmos_mux_config_bus(fp, mux_spice_model, cur_sram_orgz_info, 
                                     mux_size, cur_num_sram,
                                     num_mux_reserved_conf_bits, num_mux_conf_bits); 
    break;
  case SPICE_MODEL_DESIGN_RRAM:
    /* configuration wire bus */
    /* First bus is for sram_out in CMOS MUX or BL in RRAM MUX */
    fprintf(fp, "wire [0:%d] %s_size%d_%d_configbus0;\n",
            num_mux_reserved_conf_bits + num_mux_conf_bits - 1,
            mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
    /* Second bus is for sram_out_inv in CMOS MUX or WL in RRAM MUX */
    fprintf(fp, "wire [0:%d] %s_size%d_%d_configbus1;\n",
            num_mux_reserved_conf_bits + num_mux_conf_bits - 1,
            mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
    /* Connect wires to config bus */
    /* reserved configuration bits */
    if (0 < num_mux_reserved_conf_bits) {
      fprintf(fp, "assign %s_size%d_%d_configbus0[%d:%d] = ",
              mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
              0, num_mux_reserved_conf_bits - 1);
      dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info, 
                                          0, num_mux_reserved_conf_bits - 1,
                                          0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
      fprintf(fp, "assign %s_size%d_%d_configbus1[%d:%d] = ",
              mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
              0, num_mux_reserved_conf_bits - 1);
      dump_verilog_reserved_sram_one_port(fp, cur_sram_orgz_info, 
                                          0, num_mux_reserved_conf_bits - 1,
                                          1, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    /* normal configuration bits */
    if (0 < num_mux_conf_bits) {
      fprintf(fp, "assign %s_size%d_%d_configbus0[%d:%d] = ",
              mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
              num_mux_reserved_conf_bits,
              num_mux_reserved_conf_bits + num_mux_conf_bits - 1);
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                 0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
      fprintf(fp, "assign %s_size%d_%d_configbus1[%d:%d] = ",
              mux_spice_model->prefix, mux_size, mux_spice_model->cnt,
              num_mux_reserved_conf_bits,
              num_mux_reserved_conf_bits + num_mux_conf_bits - 1);
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
                                 1, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid design technology for SRAM!\n", 
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}

/* Dump CMOS verilog MUX configuraiton bus ports */
void dump_verilog_cmos_mux_config_bus_ports(FILE* fp, t_spice_model* mux_spice_model, 
                                            t_sram_orgz_info* cur_sram_orgz_info,
                                            int mux_size, int cur_num_sram,
                                            int num_mux_reserved_conf_bits,
                                            int num_mux_conf_bits,
                                            bool is_explicit_mapping) { 
  int num_sram_port;
  t_spice_model_port** sram_port = find_spice_model_ports(mux_spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE);
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert(NULL != mux_spice_model);
  assert(SPICE_MODEL_MUX == mux_spice_model->type);

  switch(cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* configuration wire bus */
    /* FOR Scan-chain, we need regular output of a scan-chain FF
     * We do not need a prefix implying MUX name, size and index 
     */
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s (",
              sram_port[0]->prefix);
    }
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, 
                                      cur_num_sram + num_mux_conf_bits - 1,
                                      0, VERILOG_PORT_CONKT);
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    fprintf(fp, ", ");
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ".%s_inv (",
              sram_port[0]->prefix);
    }
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, 
                                      cur_num_sram + num_mux_conf_bits - 1,
                                      1, VERILOG_PORT_CONKT);
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    break;
  case SPICE_SRAM_MEMORY_BANK:
    /* configuration wire bus */
    /* First bus is for sram_out in CMOS MUX 
     * We need a prefix implying MUX name, size and index 
     */
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ".%s (",
              sram_port[0]->prefix);
    }
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, 
                                      cur_num_sram + num_mux_conf_bits - 1,
                                      0, VERILOG_PORT_CONKT);
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    fprintf(fp, ",\n");
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ".%s_inv (",
              sram_port[0]->prefix);
    }
    dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                      mux_spice_model, mux_size,
                                      cur_num_sram, 
                                      cur_num_sram + num_mux_conf_bits - 1,
                                      1, VERILOG_PORT_CONKT);
    if (TRUE == is_explicit_mapping) {
      fprintf(fp, ")");
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid SRAM organization!\n", 
               __FILE__, __LINE__);
    exit(1);
  }
  return;
}


/* Dump MUX reserved and normal configuration wire bus */
void dump_verilog_mux_config_bus_ports(FILE* fp, t_spice_model* mux_spice_model, 
                                       t_sram_orgz_info* cur_sram_orgz_info,
                                       int mux_size, int cur_num_sram,
                                       int num_mux_reserved_conf_bits,
                                       int num_mux_conf_bits,
                                       bool is_explicit_mapping) { 
  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Check */
  assert(NULL != mux_spice_model);
  assert(SPICE_MODEL_MUX == mux_spice_model->type);

  /* depend on the design technology of this MUX:
   * bus connections are different
   * SRAM MUX: bus is connected to the output ports of SRAM
   */
  switch (mux_spice_model->design_tech) {
  case SPICE_MODEL_DESIGN_CMOS:
    dump_verilog_cmos_mux_config_bus_ports(fp, mux_spice_model, cur_sram_orgz_info,
                                           mux_size, cur_num_sram,
                                           num_mux_reserved_conf_bits,
                                           num_mux_conf_bits, is_explicit_mapping); 
    break;
  case SPICE_MODEL_DESIGN_RRAM:
    /*TODO: Do explicit mapping for the RRAM*/
    /* configuration wire bus */
    fprintf(fp, "%s_size%d_%d_configbus0, ",
            mux_spice_model->prefix, mux_size, mux_spice_model->cnt);

    fprintf(fp, "%s_size%d_%d_configbus1 ",
            mux_spice_model->prefix, mux_size, mux_spice_model->cnt);
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid design technology for SRAM!\n", 
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}


/* Dump common ports of each pb_type in physical mode,
 * common ports include:
 * 1. inpad; 2. outpad; 3. iopad; TODO: merge other two to iopad 
 * 4. SRAMs (standalone)
 * 5. BL/WLs
 * 6. Scan-chain FFs 
 */
void dump_verilog_grid_common_port(FILE* fp, t_spice_model* cur_verilog_model,
                                   char* general_port_prefix, int lsb, int msb,
                                   enum e_dump_verilog_port_type dump_port_type,
                                   bool is_explicit_mapping) {
  char* port_full_name = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  assert(NULL != cur_verilog_model);
  if (0 >  msb - lsb) {
    return;
  }

  /*Malloc and generate the full name of port */
  port_full_name = (char*)my_malloc(sizeof(char)*(strlen(general_port_prefix) + strlen(cur_verilog_model->prefix) + 1));
  sprintf(port_full_name, "%s%s", general_port_prefix, cur_verilog_model->prefix);
  fprintf(fp, ",\n");
  if (true == is_explicit_mapping) {
    fprintf(fp, ".%s(",
            port_full_name);
  }
  dump_verilog_generic_port(fp, dump_port_type, port_full_name, msb, lsb); 
  if (true == is_explicit_mapping) {
    fprintf(fp, ")");
  }

  /* Free */
  /* Local variables such as port1_name and port2 name are automatically freed  */
  my_free(port_full_name);

  return;
}

/* A widely used function to dump the configuration bus
 * This is supposed to be called when declaring local wires in the main body of a module
 * We will the internal wires (bus) used for connect SRAMs/RRAMs to other modules,
 * such as LUTs, MUXes and IOs 
 */
void dump_verilog_sram_config_bus_internal_wires(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info, 
                                                 int lsb, int msb) {
  t_spice_model* mem_model = NULL;

  /* Get the memory spice model*/
  get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
  assert (NULL != mem_model);

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  /* Depend on the configuraion style */
  switch(cur_sram_orgz_info->type) {
  case SPICE_SRAM_STANDALONE:
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, msb, -1, VERILOG_PORT_WIRE); 
    fprintf(fp, ";\n");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, msb, 0, VERILOG_PORT_WIRE); 
    fprintf(fp, ";\n");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, msb, 1, VERILOG_PORT_WIRE); 
    fprintf(fp, ";\n");
    /* Connect first CCFF to the head */
    fprintf(fp, "assign ");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, lsb, -1, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, lsb, lsb, 0, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
    /* Connect last CCFF to the tail */
    fprintf(fp, "assign ");
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, msb, msb, 1, VERILOG_PORT_CONKT); 
    fprintf(fp, " = ");
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, msb, msb, 0, VERILOG_PORT_CONKT); 
    fprintf(fp, ";\n");
    /* Connect CCFFs into chains */
    /* Cascade the CCFF between head and tail */
    if (1 < msb - lsb) {
      fprintf(fp, "assign ");
      dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                          lsb + 1, msb,
                                           -1, VERILOG_PORT_CONKT);
      fprintf(fp, " = ");
      dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 
                                          lsb, msb - 1,
                                          0, VERILOG_PORT_CONKT);
      fprintf(fp, ";\n");
    }

    break;
  case SPICE_SRAM_MEMORY_BANK:
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, lsb, msb, 0, VERILOG_PORT_WIRE); 
    fprintf(fp, ";\n");
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, lsb, msb, 1, VERILOG_PORT_WIRE); 
    fprintf(fp, ";\n");
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid SRAM organization!\n", 
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}

void dump_verilog_toplevel_one_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type, 
                                                              int pin_index, int side,
                                                              int x, int y,
                                                              boolean dump_port_type) {
  int height;  
  t_type_ptr type = NULL;
  char* verilog_port_type = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }
  /* Check */
  assert((!(0 > x))&&(!(x > (nx + 1)))); 
  assert((!(0 > y))&&(!(y > (ny + 1)))); 
  type = grid[x][y].type;
  assert(NULL != type);

  assert((!(0 > pin_index))&&(pin_index < type->num_pins));
  assert((!(0 > side))&&(!(side > 3)));

  /* Assign the type of PIN*/ 
  switch (pin_type) {
  case IPIN:
  /* case SINK: */
    verilog_port_type = "output";
    break;
  /* case SOURCE: */
  case OPIN:
    verilog_port_type = "input";
    break;
  /* SINK and SOURCE are hypothesis nodes */
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid pin_type!\n", __FILE__, __LINE__);
    exit(1); 
  }

  /* Output the pins on the side*/ 
  height = get_grid_pin_height(x, y, pin_index);
  if (1 == type->pinloc[height][side][pin_index]) {
    /* Not sure if we need to plus a height */
    /* fprintf(fp, "grid_%d__%d__pin_%d__%d__%d_ ", x, y, height, side, pin_index); */
    if (TRUE == dump_port_type) {
      fprintf(fp, "%s ", verilog_port_type);
    }
    fprintf(fp, " grid_%d__%d__pin_%d__%d__%d_", x, y, height, side, pin_index);
    if (TRUE == dump_port_type) {
      fprintf(fp, ",\n");
    }
  } else {
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Fail to print a grid pin (x=%d, y=%d, height=%d, side=%d, index=%d)\n",
              __FILE__, __LINE__, x, y, height, side, pin_index);
    exit(1);
  } 

  return;
}

/* Generate the subckt name for a MUX module/submodule */
char* generate_verilog_subckt_name(t_spice_model* spice_model, 
                                   char* postfix) {
  char* subckt_name = NULL;

  subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model->name) 
                                  + strlen(postfix) + 1)); 
  sprintf(subckt_name, "%s%s",
          spice_model->name, postfix);

  return subckt_name;
}

/* Generate the subckt name for a MUX module/submodule */
char* generate_verilog_mem_subckt_name(t_spice_model* spice_model, 
                                       t_spice_model* mem_model,
                                       char* postfix) {
  char* subckt_name = NULL;

  subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model->name) 
                                 + strlen(mem_model->name) + 1 + strlen(postfix) + 1)); 
  sprintf(subckt_name, "%s_%s%s",
          spice_model->name, mem_model->name, postfix);

  return subckt_name;
}

/* Generate the subckt name for a decoder submodule */
char* generate_verilog_decoder_subckt_name(int addr_len, int data_len) {
  char* subckt_name = NULL;

  subckt_name = (char*)my_malloc(sizeof(char)*(strlen("decoder") 
                                 + strlen(my_itoa(addr_len)) + 2 
                                 + strlen(my_itoa(data_len)) + 1)); 
  sprintf(subckt_name, "%s%dto%d",
          "decoder", addr_len, data_len);

  return subckt_name;
}

/* Generate the subckt name for a MUX module/submodule */
char* generate_verilog_mux_basis_subckt_name(t_spice_model* spice_model, 
                                             int mux_size, char* postfix) {
  char* mux_subckt_name = NULL;

  /* If the tgate spice model of this MUX is a MUX2 standard cell,
   * the mux_subckt name will be the name of the standard cell
   */
  if ( SPICE_MODEL_GATE == spice_model->pass_gate_logic->spice_model->type) {
    assert ( SPICE_MODEL_GATE_MUX2 == spice_model->design_tech_info.gate_info->type);
    mux_subckt_name = my_strdup(spice_model->pass_gate_logic->spice_model->name);
  } else {
    mux_subckt_name = generate_verilog_mux_subckt_name(spice_model, mux_size, postfix);
  }

  return mux_subckt_name;
}


/* Generate the subckt name for a MUX module/submodule */
char* generate_verilog_mux_subckt_name(t_spice_model* spice_model, 
                                       int mux_size, char* postfix) {
  char* mux_subckt_name = NULL;

  mux_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model->name) + 5 
                                     + strlen(my_itoa(mux_size)) + strlen(postfix) + 1)); 
  sprintf(mux_subckt_name, "%s_size%d%s",
          spice_model->name, mux_size, postfix);

  return mux_subckt_name;
}

enum e_dump_verilog_port_type 
convert_spice_model_port_type_to_verilog_port_type(enum e_spice_model_port_type spice_model_port_type) {
  enum e_dump_verilog_port_type verilog_port_type; 

  switch (spice_model_port_type) {
  case SPICE_MODEL_PORT_INPUT: 
    verilog_port_type = VERILOG_PORT_INPUT;
    break;
  case SPICE_MODEL_PORT_OUTPUT: 
    verilog_port_type = VERILOG_PORT_OUTPUT;
    break;
  case SPICE_MODEL_PORT_INOUT: 
    verilog_port_type = VERILOG_PORT_INOUT;
    break;
  case SPICE_MODEL_PORT_CLOCK: 
  case SPICE_MODEL_PORT_SRAM:
  case SPICE_MODEL_PORT_BL:
  case SPICE_MODEL_PORT_BLB:
  case SPICE_MODEL_PORT_WL:
  case SPICE_MODEL_PORT_WLB:
    verilog_port_type = VERILOG_PORT_INPUT;
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of Verilog port to be dumped !\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return verilog_port_type;
}

int dump_verilog_mem_module_one_port_map(FILE* fp,
                                         t_spice_model* mem_model,
                                         enum e_spice_model_port_type port_type_to_dump,
                                         boolean dump_port_type,
                                         int index, int num_mem, boolean dump_first_comma,
                                         boolean require_explicit_port_map) {
  int iport;
  int cnt = 0;
  enum e_dump_verilog_port_type verilog_port_type; 
  int lsb = 0;

  for (iport = 0; iport < mem_model->num_port; iport++) {
    /* bypass global ports */
    if (TRUE == mem_model->ports[iport].is_global) {
      continue;
    }
    /* bypass non-input ports */
    if (port_type_to_dump != mem_model->ports[iport].type) {
      continue;
    }
    if (((0 == cnt) && (TRUE == dump_first_comma))
       || (0 < cnt)) {
      fprintf(fp, ",\n");
    }
    if (TRUE == dump_port_type) {
      verilog_port_type = convert_spice_model_port_type_to_verilog_port_type(port_type_to_dump);
    } else {
      assert (FALSE == dump_port_type);
      verilog_port_type = VERILOG_PORT_CONKT;
      /* Dump explicit port mapping if needed */
      if ( (TRUE == require_explicit_port_map) 
         && (TRUE == mem_model->dump_explicit_port_map)) {
        fprintf(fp, " .%s(", mem_model->ports[iport].lib_name);
      }
    }
    /* The LSB depends on the port size */
    assert (-1 < index);
    lsb = index * mem_model->ports[iport].size;
    dump_verilog_generic_port(fp, verilog_port_type,
                              mem_model->ports[iport].prefix, lsb, lsb + num_mem * mem_model->ports[iport].size - 1);
    if (  (FALSE == dump_port_type) 
        && (TRUE == require_explicit_port_map) 
        &&(TRUE == mem_model->dump_explicit_port_map)) {
      fprintf(fp, ")");
    }
    cnt++;
  }

  return cnt;
}

/* 
 * Dump the port map of a memory module 
 * which consist of a number of SRAMs/CCFFs etc.
 */
void dump_verilog_mem_module_port_map(FILE* fp, 
                                      t_spice_model* mem_model,
                                      boolean dump_port_type,
                                      int lsb, int num_mem,
                                      boolean require_explicit_port_map) {
  boolean dump_first_comma = FALSE;
  /* Here we force the sequence of ports: of a memory subumodule:
   * 1. Global ports 
   * 2. input ports 
   * 3. output ports 
   * 4. bl ports 
   * 5. wl ports 
   * 6. blb ports 
   * 7. wlb ports 
   * Other ports are not accepted!!! 
   */
  /* 1. Global ports!  */
  if (0 < rec_dump_verilog_spice_model_global_ports(fp, mem_model, dump_port_type, TRUE, require_explicit_port_map, TRUE)) {
    dump_first_comma = TRUE;
  }

  /* 2. input ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_INPUT, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  /* 3. output ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_OUTPUT, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  /* 4. bl ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_BL, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  /* 5. wl ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_WL, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  /* 6. blb ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_BLB, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  /* 7. wlb ports */ 
  if (0 < dump_verilog_mem_module_one_port_map(fp, mem_model, SPICE_MODEL_PORT_WLB, 
                                               dump_port_type, lsb, num_mem, dump_first_comma,
                                               require_explicit_port_map)) {
    dump_first_comma = TRUE;
  } else {
    dump_first_comma = FALSE;
  }

  return;
} 

/* Dump a verilog submodule in the mem submodule (part of MUX, LUT and other ), according to SRAM organization type */
void dump_verilog_mem_sram_submodule(FILE* fp,
                                     t_sram_orgz_info* cur_sram_orgz_info,
                                     t_spice_model* cur_verilog_model, int mux_size,
                                     t_spice_model* cur_sram_verilog_model,
                                     int lsb, int msb,
                                     bool is_explicit_mapping) {
  int cur_bl, cur_wl;
  int num_bl_ports, num_wl_ports;
  t_spice_model_port** bl_port = NULL;
  t_spice_model_port** wl_port = NULL;
  int num_blb_ports, num_wlb_ports;
  t_spice_model_port** blb_port = NULL;
  t_spice_model_port** wlb_port = NULL;

  int num_bl_per_sram = 0;
  int num_wl_per_sram = 0;
  int iport = 0;
  t_llist* spice_model_head = NULL;

  /* Check the file handler*/ 
  if (NULL == fp) {
    vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", 
               __FILE__, __LINE__); 
    exit(1);
  }

  assert(NULL != cur_sram_orgz_info);
  assert(NULL != cur_sram_verilog_model);
  assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
        || (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));

  switch (cur_sram_orgz_info->type) {
  case SPICE_SRAM_MEMORY_BANK:
    /* Detect the SRAM SPICE model linked to this SRAM port */
    find_bl_wl_ports_spice_model(cur_sram_verilog_model, 
                                 &num_bl_ports, &bl_port, &num_wl_ports, &wl_port); 
    assert(1 == num_bl_ports);
    assert(1 == num_wl_ports);
    num_bl_per_sram = bl_port[0]->size; 
    num_wl_per_sram = wl_port[0]->size; 
    /* Find the BLB and WLB port, if there is any */
    find_blb_wlb_ports_spice_model(cur_sram_verilog_model, 
                                   &num_blb_ports, &blb_port, &num_wlb_ports, &wlb_port); 
    if (1 == num_blb_ports) {
      assert(num_bl_per_sram == blb_port[0]->size);
    } else {
      assert(0 == num_blb_ports);
    }
    if (1 == num_wlb_ports) {
      assert(num_wl_per_sram == wlb_port[0]->size);
    } else {
      assert(0 == num_wlb_ports);
    }

    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, my_bool_to_boolean(is_explicit_mapping), TRUE)) {
      fprintf(fp, ",\n");
    }

    if (SPICE_MODEL_MUX == cur_verilog_model->type) {
      fprintf(fp, "%s_size%d_%d_", 
              cur_verilog_model->name, mux_size, cur_verilog_model->cnt);
    }
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                      lsb, msb,
                                      0, VERILOG_PORT_CONKT);
    fprintf(fp, ",");
    if (SPICE_MODEL_MUX == cur_verilog_model->type) {
      fprintf(fp, "%s_size%d_%d_", 
              cur_verilog_model->name, mux_size, cur_verilog_model->cnt);
    }
    dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, 
                                      lsb, msb,
                                      1, VERILOG_PORT_CONKT);
    fprintf(fp, ",");
    get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &cur_bl, &cur_wl); 
    /* Connect to Bit lines and Word lines, consider each conf_bit */
    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                lsb, msb,
                                0, VERILOG_PORT_CONKT);
    fprintf(fp, ",");

    dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                lsb, msb,
                                1, VERILOG_PORT_CONKT);
    /* If we have a BLB or WLB, we need to dump inverted config_bus */
    if (1 == num_blb_ports) { 
      fprintf(fp, ", ");
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 lsb, msb,
                                 2, VERILOG_PORT_CONKT);
    }
    if (1 == num_wlb_ports) { 
      fprintf(fp, ", ");
      dump_verilog_sram_one_port(fp, cur_sram_orgz_info, 
                                 lsb, msb,
                                 3, VERILOG_PORT_CONKT);
    }

    break;
  case SPICE_SRAM_STANDALONE:
    /* SRAM subckts*/
    /* Only dump the global ports belonging to a spice_model */
    if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, my_bool_to_boolean(is_explicit_mapping), TRUE)) {
      fprintf(fp, ",\n");
    }
    fprintf(fp, "%s_in[%d:%d], ", 
            cur_sram_verilog_model->prefix, lsb, msb); /* Input*/
    fprintf(fp, "%s_out[%d:%d], %s_outb[%d:%d] ", 
            cur_sram_verilog_model->prefix, lsb, msb, 
            cur_sram_verilog_model->prefix, lsb, msb); /* Outputs */
    break;
  case SPICE_SRAM_SCAN_CHAIN:
    /* Only dump the global ports belonging to a spice_model */
    rec_stats_spice_model_global_ports(cur_sram_verilog_model,
                                       TRUE,
                                       &spice_model_head);
    if (0 < dump_verilog_global_ports( fp, spice_model_head, FALSE, is_explicit_mapping)) {
    //if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_sram_verilog_model, FALSE, TRUE, FALSE)) {
      fprintf(fp, ",\n");
    }
    if (SPICE_MODEL_MUX == cur_verilog_model->type) {
      /* Input of Scan-chain DFF, should be connected to the output of its precedent */
    if (true == is_explicit_mapping) {
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
      dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info,
                                        cur_verilog_model, mux_size,
                                        lsb, msb,
                                        -1, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
      fprintf(fp, ", \n"); 
      /* Output of Scan-chain DFF, should be connected to the output of its successor */
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
      dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info,
                                        cur_verilog_model, mux_size,
                                        lsb, msb,
                                        0, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
      fprintf(fp, ", \n");
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
    if (true == is_explicit_mapping) {
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
      dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info, 
                                        cur_verilog_model, mux_size,
                                        lsb, msb,
                                        1, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
      break;
    } 
    /* Input of Scan-chain DFF, should be connected to the output of its precedent */
    if (true == is_explicit_mapping) {
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
                                        lsb, msb,
                                         -1, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
    fprintf(fp, ", \n");  
    /* Output of Scan-chain DFF, should be connected to the output of its successor */
    if (true == is_explicit_mapping) {
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
                                        lsb, msb,
                                         0, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
    fprintf(fp, ", \n");  
    if (true == is_explicit_mapping) {
      while(TRUE == cur_sram_verilog_model->ports[iport].is_global) {
        iport++;
      }
      fprintf(fp, ".%s(",
              cur_sram_verilog_model->ports[iport].prefix);
    }
    dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
                                        lsb, msb,
                                        1, VERILOG_PORT_CONKT);
    if (true == is_explicit_mapping) {
        iport++;
      fprintf(fp, ")");
    }
    break;
  default:
    vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
               __FILE__, __LINE__);
    exit(1);
  }

  return;
}
 
char* gen_verilog_grid_one_pin_name(int x, int y,
                                    int height, int side, int pin_index,
                                    boolean for_top_netlist) {
  char* ret = NULL;

  /* This pin appear at this side! */
  if (TRUE == for_top_netlist) {
    ret = (char*) my_malloc(sizeof(char) * 
                            (5 + strlen(my_itoa(x)) + 2 + strlen(my_itoa(y))
                             + 6 + strlen(my_itoa(height)) 
                             + 2 + strlen(my_itoa(side))
                             + 2 + strlen(my_itoa(pin_index))
                             + 2 ));    
    sprintf(ret, "grid_%d__%d__pin_%d__%d__%d_", 
            x, y,
            height, side, pin_index);
  } else {
    assert(FALSE == for_top_netlist);
    ret = (char*) my_malloc(sizeof(char) * 
                            (strlen(convert_side_index_to_string(side)) 
                             + 8 + strlen(my_itoa(height)) 
                             + 6 + strlen(my_itoa(pin_index))
                             + 2 ));    
    sprintf(ret, "%s_height_%d__pin_%d_", 
            convert_side_index_to_string(side), height, pin_index);
  }

  return ret;
}

char* gen_verilog_routing_channel_one_pin_name(t_rr_node* chan_rr_node,
                                              int x, int y, int track_idx,
                                              enum PORTS pin_direction) {

  char* ret = NULL;
  
  ret = (char*)my_malloc(strlen(convert_chan_type_to_string(chan_rr_node->type))
                         + 1 + strlen(my_itoa(x))
                         + 2 + strlen(my_itoa(y))
                         + 6 + strlen(my_itoa(track_idx))
                         + 2 + 1);

   switch (pin_direction) {
   case OUT_PORT:
     sprintf(ret, "%s_%d__%d__out_%d_", 
             convert_chan_type_to_string(chan_rr_node->type), 
             x, y, track_idx); 
     break;
   case IN_PORT:
     sprintf(ret, "%s_%d__%d__in_%d_",
             convert_chan_type_to_string(chan_rr_node->type), 
             x, y, track_idx); 
     break;
   default:
     vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid direction of chan_rr_node!\n",
                __FILE__, __LINE__);
     exit(1);
  }

  return ret;
}

char* gen_verilog_routing_channel_one_midout_name(t_cb* cur_cb_info,
                                                 int track_idx) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(strlen(convert_chan_type_to_string(cur_cb_info->type))
                         + 1 + strlen(my_itoa(cur_cb_info->x))
                         + 2 + strlen(my_itoa(cur_cb_info->y))
                         + 9 + strlen(my_itoa(track_idx))
                         + 1 + 1);

  sprintf(ret, "%s_%d__%d__midout_%d_",
          convert_chan_type_to_string(cur_cb_info->type),
          cur_cb_info->x, cur_cb_info->y, track_idx);

  return ret;
}

char* gen_verilog_one_cb_module_name(t_cb* cur_cb_info) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(strlen(convert_cb_type_to_string(cur_cb_info->type))
                         + 1 + strlen(my_itoa(cur_cb_info->x))
                         + 2 + strlen(my_itoa(cur_cb_info->y))
                         + 1 + 1); 

  sprintf(ret, "%s_%d__%d_", 
          convert_cb_type_to_string(cur_cb_info->type),
          cur_cb_info->x, cur_cb_info->y);

  return ret;
}

char* gen_verilog_one_cb_instance_name(t_cb* cur_cb_info) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(strlen(convert_cb_type_to_string(cur_cb_info->type))
                         + 1 + strlen(my_itoa(cur_cb_info->x))
                         + 2 + strlen(my_itoa(cur_cb_info->y))
                         + 4 + 1); 

  sprintf(ret, "%s_%d__%d__0_", 
          convert_cb_type_to_string(cur_cb_info->type),
          cur_cb_info->x, cur_cb_info->y);

  return ret;
}

char* gen_verilog_one_sb_module_name(t_sb* cur_sb_info) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(2 + 1 + strlen(my_itoa(cur_sb_info->x))
                         + 2 + strlen(my_itoa(cur_sb_info->y))
                         + 1 + 1); 

  sprintf(ret, "sb_%d__%d_", 
          cur_sb_info->x, cur_sb_info->y);

  return ret;
}

char* gen_verilog_one_sb_instance_name(t_sb* cur_sb_info) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(2 + 1 + strlen(my_itoa(cur_sb_info->x))
                         + 2 + strlen(my_itoa(cur_sb_info->y))
                         + 4 + 1); 

  sprintf(ret, "sb_%d__%d__0_", 
          cur_sb_info->x, cur_sb_info->y);

  return ret;
}

char* gen_verilog_one_routing_channel_module_name(t_rr_type chan_type,
                                                  int x, int y) {
  char* ret = NULL;
  
  if (-1 == y) {
    ret = (char*)my_malloc(strlen(convert_chan_type_to_string(chan_type))
                           + 1 + strlen(my_itoa(x))
                           + 1 + 1); 
    sprintf(ret, "%s_%d_", 
            convert_chan_type_to_string(chan_type), 
            x);
  } else {
    ret = (char*)my_malloc(strlen(convert_chan_type_to_string(chan_type))
                           + 1 + strlen(my_itoa(x))
                           + 2 + strlen(my_itoa(y))
                           + 1 + 1); 
    sprintf(ret, "%s_%d__%d_", 
            convert_chan_type_to_string(chan_type), 
            x, y);
  }

  return ret;
}

char* gen_verilog_one_routing_channel_instance_name(t_rr_type chan_type,
                                                    int x, int y) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(strlen(convert_chan_type_to_string(chan_type))
                         + 1 + strlen(my_itoa(x))
                         + 2 + strlen(my_itoa(y))
                         + 4 + 1); 

  sprintf(ret, "%s_%d__%d__0_", 
          convert_chan_type_to_string(chan_type), 
          x, y);

  return ret;
}

/* Generate the subckt name for a MUX module/submodule */
char* gen_verilog_one_mux_module_name(t_spice_model* spice_model, 
                                      int mux_size) {
  char* mux_subckt_name = NULL;

  mux_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model->name) + 5 
                                     + strlen(my_itoa(mux_size)) + 1)); 
  sprintf(mux_subckt_name, "%s_size%d",
          spice_model->name, mux_size);

  return mux_subckt_name;
}

/* Generate the full path of a pb_graph_pin in the hierarchy of verilog netlists
 * For example: grid_<x>__<y>_/grid_<mode_name>_<z>/.../<port_name>_<pin_number>_
 */
char* gen_verilog_one_grid_instance_name(int grid_x, int grid_y) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(sizeof(char) * 
                        ( 5 + strlen(my_itoa(grid_x))
                        + 2 + strlen(my_itoa(grid_y))
                        + 1 + 1));

  sprintf(ret, "grid_%d__%d_",
          grid_x, grid_y);

  return ret;
}

char* gen_verilog_one_grid_module_name(int grid_x, int grid_y) {
  return gen_verilog_one_grid_instance_name(grid_x, grid_y);
}

char* gen_verilog_one_block_instance_name(int grid_x, int grid_y, int grid_z) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(sizeof(char) * 
                        ( 5 + strlen(my_itoa(grid_x))
                        + 2 + strlen(my_itoa(grid_y))
                        + 2 + strlen(my_itoa(grid_z))
                        + 1 + 1));

  sprintf(ret, "grid_%d__%d__%d_",
          grid_x, grid_y, grid_z);

  return ret;
}

char* gen_verilog_one_phy_block_instance_name(t_type_ptr cur_type_ptr, 
                                              int block_z) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(sizeof(char) * 
                        ( 5 + strlen(cur_type_ptr->name)
                        + 1 + strlen(my_itoa(block_z))
                        + 1 + 1));

  sprintf(ret, "grid_%s_%d_",
          cur_type_ptr->name, block_z);

  return ret;
}

char* gen_verilog_one_pb_graph_node_instance_name(t_pb_graph_node* cur_pb_graph_node) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(sizeof(char) * 
                        ( strlen(cur_pb_graph_node->pb_type->name)
                        + 1 + strlen(my_itoa(cur_pb_graph_node->placement_index))
                        + 1 + 1));

  sprintf(ret, "%s_%d_",
          cur_pb_graph_node->pb_type->name, cur_pb_graph_node->placement_index);

  return ret;
}

char* gen_verilog_one_pb_type_pin_name(char* prefix, 
                                       t_port* cur_port, int pin_number) {
  char* ret = NULL;
  
  ret = (char*)my_malloc(sizeof(char) * 
                        (strlen(prefix) + 2 
                        + strlen(cur_port->name)
                        + 1 + strlen(my_itoa(pin_number))
                        + 1 + 1));

  sprintf(ret, "%s__%s_%d_",
          prefix, cur_port->name, pin_number);
   
  return ret;
}

/* Generate the full path of a pb_graph_pin in the hierarchy of verilog netlists
 * For example: grid_<x>__<y>_/grid_<mode_name>_<z>/.../<port_name>_<pin_number>_
 */
char* gen_verilog_one_pb_graph_pin_full_name_in_hierarchy(t_pb_graph_pin* cur_pb_graph_pin) {
  char* full_name = NULL;
  char* cur_name = NULL;
  t_pb_graph_node* temp = cur_pb_graph_pin->parent_node;

  /* Give the pin name */
  full_name = gen_verilog_one_pb_type_pin_name(cur_pb_graph_pin->parent_node->pb_type->name, 
                                               cur_pb_graph_pin->port, 
                                               cur_pb_graph_pin->pin_number);

  /* The instance name of the top-level graph node is very special 
   * we output it in another function  
   */
  while (NULL != temp->parent_pb_graph_node) {
    /* Generate the instance name of current pb_graph_node
     * and add a slash to separate the upper level 
     */
    cur_name = gen_verilog_one_pb_graph_node_instance_name(temp);
    cur_name = my_strcat(cur_name, "/");
    full_name = my_strcat(cur_name, full_name);
    /* Go to upper level */
    temp = temp->parent_pb_graph_node;
    my_free(cur_name);
  } 
  return full_name;
}

char* gen_verilog_top_module_io_port_prefix(char* global_prefix, 
                                            char* io_port_prefix) {
  char* port_name = NULL;

  port_name = (char*)my_malloc(sizeof(char)*(strlen(global_prefix) + strlen(io_port_prefix) + 1));
  sprintf(port_name, "%s%s", global_prefix, io_port_prefix);

  return port_name;
}

char* gen_verilog_one_pb_graph_pin_full_name_in_hierarchy_parent_node(t_pb_graph_pin* cur_pb_graph_pin) {
  char* full_name = NULL;
  char* cur_name = NULL;
  t_pb_graph_node* temp = cur_pb_graph_pin->parent_node;
  //t_pb_graph_node* temp = cur_pb_graph_pin->parent_node->parent_pb_graph_node;

  full_name = "";
  /* The instance name of the top-level graph node is very special 
   * we output it in another function  
   */
  while (NULL != temp->parent_pb_graph_node) {
    /* Generate the instance name of current pb_graph_node
     * and add a slash to separate the upper level 
     */
    cur_name = gen_verilog_one_pb_graph_node_instance_name(temp);
    cur_name = my_strcat(cur_name, "/");
    full_name = my_strcat(cur_name, full_name);
    /* Go to upper level */
    temp = temp->parent_pb_graph_node;
    my_free(cur_name);
  }
 
  return full_name;
}

char* gen_verilog_one_pb_graph_pin_full_name_in_hierarchy_grand_parent_node(t_pb_graph_pin* cur_pb_graph_pin) {
  char* full_name = "";
  char* cur_name = NULL;
  t_pb_graph_node* temp = cur_pb_graph_pin->parent_node;
  
  if (NULL != temp->parent_pb_graph_node) {
    temp = temp->parent_pb_graph_node;
  }
  else {
    return full_name;
  }
  
  /* The instance name of the top-level graph node is very special 
   * we output it in another function  
   */
  while (NULL != temp->parent_pb_graph_node) {
    /* Generate the instance name of current pb_graph_node
     * and add a slash to separate the upper level 
     */
    cur_name = gen_verilog_one_pb_graph_node_instance_name(temp);
    cur_name = my_strcat(cur_name, "/");
    full_name = my_strcat(cur_name, full_name);
    /* Go to upper level */
    temp = temp->parent_pb_graph_node;
    my_free(cur_name);
  }
 
  return full_name;
}

char* gen_verilog_one_pb_graph_node_full_name_in_hierarchy(t_pb_graph_node* cur_pb_graph_node) {
  char* full_name = NULL;
  char* cur_name = NULL;
  t_pb_graph_node* temp = cur_pb_graph_node;

  full_name = "";
  /* The instance name of the top-level graph node is very special 
   * we output it in another function  
   */
  while (NULL != temp->parent_pb_graph_node) {
    /* Generate the instance name of current pb_graph_node
     * and add a slash to separate the upper level 
     */
    cur_name = gen_verilog_one_pb_graph_node_instance_name(temp);
    cur_name = my_strcat(cur_name, "/");
    full_name = my_strcat(cur_name, full_name);
    /* Go to upper level */
    temp = temp->parent_pb_graph_node;
    my_free(cur_name);
  }
 
  return full_name;
}