/***********************************/ /* Synthesizable Verilog Dumping */ /* Xifan TANG, EPFL/LSI */ /***********************************/ #include #include #include #include #include #include #include #include #include #include /* Include vpr structs*/ #include "util.h" #include "physical_types.h" #include "vpr_types.h" #include "globals.h" #include "rr_graph.h" #include "vpr_utils.h" #include "path_delay.h" #include "stats.h" /* Include FPGA-SPICE utils */ #include "linkedlist.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_globals.h" #include "fpga_x2p_mux_utils.h" #include "fpga_x2p_bitstream_utils.h" /* Include verilog utils */ #include "verilog_global.h" #include "verilog_utils.h" #include "verilog_pbtypes.h" #include "verilog_decoder.h" #include "verilog_submodules.h" #include "mux_utils.h" #include "verilog_submodule_mux.h" /***** Subroutines *****/ static void dump_verilog_submodule_timing(FILE* fp, t_spice_model* cur_spice_model) { int iport, ipin, iedge; int num_input_port; t_spice_model_port** input_port= NULL; input_port = find_spice_model_ports(cur_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); /* return if there is no delay info */ if ( 0 == cur_spice_model->num_delay_info) { return; } /* Return if there is no input ports */ if (0 == num_input_port) { return; } /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } fprintf(fp, "`ifdef %s\n", verilog_timing_preproc_flag); fprintf(fp, " //------ BEGIN Pin-to-pin Timing constraints -----\n"); fprintf(fp, " specify\n"); /* Give pin-to-pin delays */ /* Enumerate timing edges of each input ports */ for (iport = 0; iport < num_input_port; iport++) { for (ipin = 0; ipin < input_port[iport]->size; ipin++) { for (iedge = 0; iedge < input_port[iport]->num_tedges[ipin]; iedge++) { fprintf(fp, "(%s[%d] => %s[%d]) = (%.2g, %.2g);\n", input_port[iport]->lib_name, ipin, input_port[iport]->tedge[ipin][iedge]->to_port->lib_name, input_port[iport]->tedge[ipin][iedge]->to_port_pin_number, input_port[iport]->tedge[ipin][iedge]->trise / verilog_sim_timescale, input_port[iport]->tedge[ipin][iedge]->tfall / verilog_sim_timescale); } } } fprintf(fp, " endspecify\n"); fprintf(fp, " //------ END Pin-to-pin Timing constraints -----\n"); fprintf(fp, "`endif\n"); return; } static void dump_verilog_submodule_signal_init(FILE* fp, t_spice_model* cur_spice_model) { int iport; int num_input_port; t_spice_model_port** input_port= NULL; input_port = find_spice_model_ports(cur_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } fprintf(fp, "\n`ifdef %s\n", verilog_signal_init_preproc_flag); fprintf(fp, " //------ BEGIN driver initialization -----\n"); fprintf(fp, "initial begin\n"); // fprintf(fp, "`ifdef %s\n #0.001\n`endif\n", // Commented, looks no longer needed // icarus_simulator_flag); fprintf(fp, " `ifdef %s\n", verilog_formal_verification_preproc_flag); for (iport = 0; iport < num_input_port; iport++) { fprintf(fp, " $deposit(%s, 1'b0);\n", input_port[iport]->lib_name); } fprintf(fp, " `else\n"); for (iport = 0; iport < num_input_port; iport++) { fprintf(fp, " $deposit(%s, $random);\n", input_port[iport]->lib_name); } fprintf(fp, " `endif\n"); fprintf(fp, "end\n"); fprintf(fp, " //------ END driver initialization -----\n"); fprintf(fp, "`endif\n"); return; } /* Dump a module of inverter or buffer or tapered buffer */ static void dump_verilog_invbuf_module(FILE* fp, t_spice_model* invbuf_spice_model) { int ipin, iport, port_cnt; int num_input_port = 0; int num_output_port = 0; int num_powergate_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; t_spice_model_port** powergate_port = NULL; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } fprintf(fp, "//----- Verilog module for %s -----\n", invbuf_spice_model->name); /* Find the input port, output port*/ input_port = find_spice_model_ports(invbuf_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(invbuf_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); powergate_port = find_spice_model_config_done_ports(invbuf_spice_model, SPICE_MODEL_PORT_INPUT, &num_powergate_port, FALSE); /* Make sure: * There is only 1 input port and 1 output port, * each size of which is 1 */ assert(1 == num_input_port); assert(1 == input_port[0]->size); assert(1 == num_output_port); assert(1 == output_port[0]->size); /* If power-gated, we need to find enable signals */ if (TRUE == invbuf_spice_model->design_tech_info.power_gated) { if (0 == num_powergate_port) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Inverter, buffer SPICE model is power-gated, but cannot find any power-gate port!\n", __FILE__, __LINE__); exit(1); } assert ( 0 < num_powergate_port); } /* dump module body */ fprintf(fp, "module %s (\n", invbuf_spice_model->name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, invbuf_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Dump ports */ fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name); fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name); fprintf(fp, ");\n"); /* Finish dumping ports */ /* Assign logics : depending on topology */ switch (invbuf_spice_model->design_tech_info.buffer_info->type) { case SPICE_MODEL_BUF_INV: if (TRUE == invbuf_spice_model->design_tech_info.power_gated) { /* Create a sensitive list */ fprintf(fp, "reg %s_reg;\n", output_port[0]->lib_name); fprintf(fp, "always @("); /* Power-gate port first*/ for (iport = 0; iport < num_powergate_port; iport++) { fprintf(fp, "%s,", powergate_port[iport]->lib_name); } fprintf(fp, "%s) begin\n", input_port[0]->lib_name); /* Dump the case of power-gated */ fprintf(fp, " if ("); port_cnt = 0; /* Initialize the counter: decide if we need to put down '&&' */ for (iport = 0; iport < num_powergate_port; iport++) { if (0 == powergate_port[iport]->default_val) { for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) { if ( 0 < port_cnt ) { fprintf(fp, "\n\t&&"); } /* Power-gated signal are disable during operating, enabled during configuration, * Therefore, we need to reverse them here */ fprintf(fp, "(~%s[%d])", powergate_port[iport]->lib_name, ipin); port_cnt++; /* Update port counter*/ } } else { assert (1 == powergate_port[iport]->default_val); for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) { if ( 0 < port_cnt ) { fprintf(fp, "\n\t&&"); } /* Power-gated signal are disable during operating, enabled during configuration, * Therefore, we need to reverse them here */ fprintf(fp, "(%s[%d])", powergate_port[iport]->lib_name, ipin); port_cnt++; /* Update port counter*/ } } } fprintf(fp, ") begin\n"); fprintf(fp, "\t\tassign %s_reg = ~%s;\n", output_port[0]->lib_name, input_port[0]->lib_name); fprintf(fp, "\tend else begin\n"); fprintf(fp, "\t\tassign %s_reg = 1'bz;\n", output_port[0]->lib_name); fprintf(fp, "\tend\n"); fprintf(fp, "end\n"); fprintf(fp, "assign %s = %s_reg;\n", output_port[0]->lib_name, output_port[0]->lib_name); } else { fprintf(fp, "assign %s = (%s === 1'bz)? $random : ~%s;\n", output_port[0]->lib_name, input_port[0]->lib_name, input_port[0]->lib_name); } break; case SPICE_MODEL_BUF_BUF: if (TRUE == invbuf_spice_model->design_tech_info.power_gated) { /* Create a sensitive list */ fprintf(fp, "reg %s_reg;\n", output_port[0]->lib_name); fprintf(fp, "always @("); /* Power-gate port first*/ for (iport = 0; iport < num_powergate_port; iport++) { fprintf(fp, "%s,", powergate_port[iport]->lib_name); } fprintf(fp, "%s) begin\n", input_port[0]->lib_name); /* Dump the case of power-gated */ fprintf(fp, " if ("); port_cnt = 0; /* Initialize the counter: decide if we need to put down '&&' */ for (iport = 0; iport < num_powergate_port; iport++) { if (0 == powergate_port[iport]->default_val) { for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) { if ( 0 < port_cnt ) { fprintf(fp, "\n\t&&"); } /* Power-gated signal are disable during operating, enabled during configuration, * Therefore, we need to reverse them here */ fprintf(fp, "(~%s[%d])", powergate_port[iport]->lib_name, ipin); port_cnt++; /* Update port counter*/ } } else { assert (1 == powergate_port[iport]->default_val); for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) { if ( 0 < port_cnt ) { fprintf(fp, "\n\t&&"); } /* Power-gated signal are disable during operating, enabled during configuration, * Therefore, we need to reverse them here */ fprintf(fp, "(%s[%d])", powergate_port[iport]->lib_name, ipin); port_cnt++; /* Update port counter*/ } } } fprintf(fp, ") begin\n"); fprintf(fp, "\t\tassign %s_reg = %s;\n", output_port[0]->lib_name, input_port[0]->lib_name); fprintf(fp, "\tend else begin\n"); fprintf(fp, "\t\tassign %s_reg = 1'bz;\n", output_port[0]->lib_name); fprintf(fp, "\tend\n"); fprintf(fp, "end\n"); fprintf(fp, "assign %s = %s_reg;\n", output_port[0]->lib_name, output_port[0]->lib_name); } else if (FALSE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf) { fprintf(fp, "assign %s = (%s === 1'bz)? $random : %s;\n", output_port[0]->lib_name, input_port[0]->lib_name, input_port[0]->lib_name); } else { assert (TRUE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf); fprintf(fp, "assign %s = (%s === 1'bz)? $random : ", output_port[0]->lib_name, input_port[0]->lib_name); /* depend on the stage, we may invert the output */ if (1 == invbuf_spice_model->design_tech_info.buffer_info->tap_buf_level % 2) { fprintf(fp, "~"); } fprintf(fp, "%s;\n", input_port[0]->lib_name); } break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n", __FILE__, __LINE__, invbuf_spice_model->name); exit(1); } /* Print timing info */ dump_verilog_submodule_timing(fp, invbuf_spice_model); dump_verilog_submodule_signal_init(fp, invbuf_spice_model); fprintf(fp, "endmodule\n"); fprintf(fp, "\n"); /* Free */ my_free(input_port); my_free(output_port); return; } /* Dump a module of pass-gate logic */ static void dump_verilog_passgate_module(FILE* fp, t_spice_model* passgate_spice_model) { int iport; int num_input_port = 0; int num_output_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } /* Find the input port, output port*/ input_port = find_spice_model_ports(passgate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(passgate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); /* Make sure: * There is only 1 output port, * each size of which is 1 */ assert(1 == num_output_port); assert(1 == output_port[0]->size); fprintf(fp, "//----- Verilog module for %s -----\n", passgate_spice_model->name); /* dump module body */ fprintf(fp, "module %s (\n", passgate_spice_model->name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, passgate_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Assign ports : depending on topology */ switch (passgate_spice_model->design_tech_info.pass_gate_info->type) { case SPICE_MODEL_PASS_GATE_TRANSMISSION: /* Make sure: * There is only 3 input port (in, sel, selb), * each size of which is 1 */ assert(3 == num_input_port); for (iport = 0; iport < num_input_port; iport++) { assert(1 == input_port[iport]->size); } /* Dump ports */ fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name); fprintf(fp, "input [0:0] %s,\n", input_port[1]->lib_name); fprintf(fp, "input [0:0] %s,\n", input_port[2]->lib_name); fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name); fprintf(fp, ");\n"); /* Finish dumping ports */ break; case SPICE_MODEL_PASS_GATE_TRANSISTOR: /* Make sure: * There is only 2 input port (in, sel), * each size of which is 1 */ assert(2 == num_input_port); for (iport = 0; iport < num_input_port; iport++) { assert(1 == input_port[iport]->size); } /* Dump ports */ fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name); fprintf(fp, "input [0:0] %s,\n", input_port[1]->lib_name); fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name); fprintf(fp, ");\n"); /* Finish dumping ports */ break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n", __FILE__, __LINE__, passgate_spice_model->name); exit(1); } /* Dump logics */ fprintf(fp, "assign %s = %s? %s : 1'bz;\n", output_port[0]->lib_name, input_port[1]->lib_name, input_port[0]->lib_name); /* Print timing info */ dump_verilog_submodule_timing(fp, passgate_spice_model); /* Print signal initialization */ dump_verilog_submodule_signal_init(fp, passgate_spice_model); fprintf(fp, "endmodule\n"); fprintf(fp, "\n"); /* Free */ my_free(input_port); my_free(output_port); return; } /* Dump a module of pass-gate logic */ static void dump_verilog_gate_module(FILE* fp, t_spice_model* gate_spice_model) { int iport, ipin, jport, jpin; int num_input_port = 0; int num_output_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } /* Find the input port, output port*/ input_port = find_spice_model_ports(gate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(gate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); /* Make sure: * There is only 1 output port, * each size of which is 1 */ assert(1 == num_output_port); assert(1 == output_port[0]->size); assert(0 < num_input_port); fprintf(fp, "//----- Verilog module for %s -----\n", gate_spice_model->name); /* dump module body */ fprintf(fp, "module %s (\n", gate_spice_model->name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, gate_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Dump ports */ for (iport = 0; iport < num_input_port; iport++) { fprintf(fp, "input [0:%d] %s,\n", input_port[iport]->size - 1, input_port[iport]->lib_name); } for (iport = 0; iport < num_output_port; iport++) { fprintf(fp, "output [0:%d] %s\n", output_port[iport]->size - 1, output_port[iport]->lib_name); } fprintf(fp, ");\n"); /* Dump logics */ switch (gate_spice_model->design_tech_info.gate_info->type) { case SPICE_MODEL_GATE_AND: for (iport = 0; iport < num_output_port; iport++) { for (ipin = 0; ipin < output_port[iport]->size; ipin++) { fprintf(fp, "assign %s[%d] = ", output_port[iport]->lib_name, ipin); for (jport = 0; jport < num_input_port; jport++) { for (jpin = 0; jpin < input_port[jport]->size; jpin++) { fprintf(fp, "%s[%d]", input_port[jport]->lib_name, jpin); if ((jport == num_input_port - 1) && (jpin == input_port[jport]->size - 1)) { continue; /* Stop output AND sign for the last element in the loop */ } fprintf(fp, " & "); } } fprintf(fp, ";\n"); } } break; case SPICE_MODEL_GATE_OR: for (iport = 0; iport < num_output_port; iport++) { for (ipin = 0; ipin < output_port[iport]->size; ipin++) { fprintf(fp, "assign %s[%d] = ", output_port[iport]->lib_name, ipin); for (jport = 0; jport < num_input_port; jport++) { for (jpin = 0; jpin < input_port[jport]->size; jpin++) { fprintf(fp, "%s[%d]", input_port[jport]->lib_name, jpin); if ((jport == num_input_port - 1) && (jpin == input_port[jport]->size - 1)) { continue; /* Stop output AND sign for the last element in the loop */ } fprintf(fp, " | "); } } fprintf(fp, ";\n"); } } break; case SPICE_MODEL_GATE_MUX2: /* Check on the port sequence and map */ /* MUX2 should only have 1 output port with size 1 */ if (1 != num_output_port) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d]) MUX2 circuit model must have only 1 output!\n", __FILE__, __LINE__); exit(1); } else if (1 != output_port[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d]) Output size of a MUX2 circuit model must be 1!\n", __FILE__, __LINE__); exit(1); } /* MUX2 should only have 3 output port, each of which has a port size of 1 */ if (3 != num_input_port) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d]) MUX2 circuit model must have only 3 input!\n", __FILE__, __LINE__); exit(1); } else { for (iport = 0; iport < num_input_port; iport++) { /* Bypass port size of 1 */ if (1 == input_port[iport]->size) { continue; } vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d]) Input size MUX2 circuit model must be 1!\n", __FILE__, __LINE__); exit(1); } } /* Now, we output the logic of MUX2 * IMPORTANT Restriction: * We always assum the first two inputs are data inputs * the third input is the select port */ fprintf(fp, "assign %s[%d] = %s[%d] ? %s[%d] : %s[%d];\n", output_port[0]->lib_name, 0, input_port[2]->lib_name, 0, input_port[0]->lib_name, 0, input_port[1]->lib_name, 0); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n", __FILE__, __LINE__, gate_spice_model->name); exit(1); } /* Print timing info */ dump_verilog_submodule_timing(fp, gate_spice_model); /* Print signal initialization */ dump_verilog_submodule_signal_init(fp, gate_spice_model); fprintf(fp, "endmodule\n"); fprintf(fp, "\n"); /* Free */ my_free(input_port); my_free(output_port); return; } /* Dump Essential modules: * 1. inverters * 2. buffers * 3. pass-gate logics */ static void dump_verilog_submodule_essentials(char* verilog_dir, char* submodule_dir, int num_spice_model, t_spice_model* spice_models) { int imodel; char* verilog_name = my_strcat(submodule_dir, essentials_verilog_file_name); FILE* fp = NULL; /* Create file */ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Verilog netlist %s", __FILE__, __LINE__, essentials_verilog_file_name); exit(1); } dump_verilog_file_header(fp,"Essential gates"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Output essential models*/ for (imodel = 0; imodel < num_spice_model; imodel++) { /* By pass user-defined modules */ if (NULL != spice_models[imodel].verilog_netlist) { continue; } if (SPICE_MODEL_INVBUF == spice_models[imodel].type) { dump_verilog_invbuf_module(fp, &(spice_models[imodel])); } if (SPICE_MODEL_PASSGATE == spice_models[imodel].type) { dump_verilog_passgate_module(fp, &(spice_models[imodel])); } if (SPICE_MODEL_GATE == spice_models[imodel].type) { dump_verilog_gate_module(fp, &(spice_models[imodel])); } } /* Close file handler*/ fclose(fp); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); /* Free */ return; } /* Dump a CMOS MUX basis module */ static void dump_verilog_cmos_mux_one_basis_module(FILE* fp, char* mux_basis_subckt_name, int mux_size, int num_input_basis_subckt, t_spice_model* cur_spice_model, boolean special_basis) { int cur_mem, i; int num_mem = num_input_basis_subckt; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Determine the number of memory bit * The function considers a special case : * 2-input basis in tree-like MUX only requires 1 memory bit */ num_mem = determine_num_sram_bits_mux_basis_subckt(cur_spice_model, mux_size, num_input_basis_subckt, special_basis); /* Comment lines */ fprintf(fp, "//---- CMOS MUX basis module: %s -----\n", mux_basis_subckt_name); /* Print the port list and definition */ fprintf(fp, "module %s (\n", mux_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Port list */ fprintf(fp, "input [0:%d] in,\n", num_input_basis_subckt - 1); fprintf(fp, "output out,\n"); fprintf(fp, "input [0:%d] mem,\n", num_mem - 1); fprintf(fp, "input [0:%d] mem_inv);\n", num_mem - 1); /* Verilog Behavior description for a MUX */ fprintf(fp, "//---- Behavior-level description -----\n"); /* Special case: only one memory, switch case is simpler * When mem = 1, propagate input 0; * when mem = 0, propagate input 1; */ if (1 == num_mem) { fprintf(fp, " reg out_reg;\n"); fprintf(fp, " always @(in, mem)\n"); fprintf(fp, " case (mem)\n"); fprintf(fp, " 1'b1: out_reg = in[0];\n"); fprintf(fp, " 1'b0: out_reg = in[1];\n"); fprintf(fp, " default: out_reg <= 1'bz;\n"); fprintf(fp, " endcase\n"); fprintf(fp, " assign out = out_reg;\n"); } else { /* Other cases, we need to follow the rules: * When mem[k] is enabled, switch on input[k] * Only one memory bit is enabled! */ fprintf(fp, " reg out_reg;\n"); fprintf(fp, " always @(in, mem)\n"); fprintf(fp, " case (mem)\n"); fprintf(fp, "//---- Note that MSB is mem[0] while LSB is mem[%d] -----\n", num_mem-1); fprintf(fp, "//---- Due to the delcare convention of port [MSB:LSB] -----\n"); for (cur_mem = 0; cur_mem < num_mem; cur_mem++) { fprintf(fp, " %d'b", num_mem); for (i = 0; i < cur_mem; i++) { fprintf(fp, "0"); } fprintf(fp, "1"); for (i = cur_mem + 1; i < num_mem; i++) { fprintf(fp, "0"); } fprintf(fp, ":"); fprintf(fp, " out_reg <= in[%d];\n", cur_mem); } fprintf(fp, " default: out_reg <= 1'bz;\n"); fprintf(fp, " endcase\n"); fprintf(fp, " assign out = out_reg;\n"); } /* Put an end to this module */ fprintf(fp, "endmodule\n"); /* Comment lines */ fprintf(fp, "//---- END CMOS MUX basis module: %s -----\n\n", mux_basis_subckt_name); return; } /* Dump a structural verilog for SRAM-based MUX basis module * This is only called when structural verilog dumping option is enabled for this spice model * Note that the structural verilog may be used for functionality verification!!! */ static void dump_verilog_cmos_mux_one_basis_module_structural(FILE* fp, char* mux_basis_subckt_name, int mux_size, int num_input_basis_subckt, t_spice_model* cur_spice_model, boolean special_basis) { int i; int num_mem = num_input_basis_subckt; /* Get the tgate module name */ char* tgate_module_name = cur_spice_model->pass_gate_logic->spice_model_name; t_spice_model* tgate_spice_model = cur_spice_model->pass_gate_logic->spice_model; int num_input_port = 0; int num_output_port = 0; int num_sram_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; t_spice_model_port** sram_port = NULL; assert(TRUE == cur_spice_model->dump_structural_verilog); /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Find the input port, output port, and sram port*/ assert ( NULL != tgate_spice_model); input_port = find_spice_model_ports(tgate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(tgate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); sram_port = find_spice_model_ports(tgate_spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Check */ assert ((3 == num_input_port)); for (i = 0; i < num_input_port; i++) { assert ( 1 == input_port[i]->size ); } assert ((1 == num_output_port) && (1 == output_port[0]->size)); /* Determine the number of memory bit * The function considers a special case : * 2-input basis in tree-like MUX only requires 1 memory bit */ num_mem = determine_num_sram_bits_mux_basis_subckt(cur_spice_model, mux_size, num_input_basis_subckt, special_basis); /* Comment lines */ fprintf(fp, "//---- Structural Verilog for CMOS MUX basis module: %s -----\n", mux_basis_subckt_name); /* Print the port list and definition */ fprintf(fp, "module %s (\n", mux_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Port list */ fprintf(fp, "input [0:%d] in,\n", num_input_basis_subckt - 1); fprintf(fp, "output out,\n"); fprintf(fp, "input [0:%d] mem,\n", num_mem - 1/*, sram_port[0]->prefix*/); fprintf(fp, "input [0:%d] mem_inv);\n", num_mem - 1/*, sram_port[0]->prefix*/); /* Verilog Behavior description for a MUX */ fprintf(fp, "//---- Structure-level description -----\n"); /* Special case: only one memory, switch case is simpler * When mem = 1, propagate input 0; * when mem = 0, propagate input 1; */ if (1 == num_mem) { /* Transmission gates are connected to each input and also the output*/ fprintf(fp, " %s %s_0 ", tgate_module_name, tgate_module_name); /* Dump explicit port map if required */ if (TRUE == tgate_spice_model->dump_explicit_port_map) { fprintf(fp, " (.%s(in[0]), .%s(mem[0]), .%s(mem_inv[0]), .%s(out));\n", input_port[0]->lib_name, input_port[1]->lib_name, input_port[2]->lib_name, output_port[0]->lib_name); } else { fprintf(fp, " (in[0], mem[0], mem_inv[0], out);\n"); } fprintf(fp, " %s %s_1 ", tgate_module_name, tgate_module_name); /* Dump explicit port map if required */ if (TRUE == tgate_spice_model->dump_explicit_port_map) { fprintf(fp, " (.%s(in[1]), .%s(mem_inv[0]), .%s(mem[0]), .%s(out));\n", input_port[0]->lib_name, input_port[1]->lib_name, input_port[2]->lib_name, output_port[0]->lib_name); } else { fprintf(fp, " (in[1], mem_inv[0], mem[0], out);\n"); } } else { /* Other cases, we need to follow the rules: * When mem[k] is enabled, switch on input[k] * Only one memory bit is enabled! */ for (i = 0; i < num_mem; i++) { fprintf(fp, " %s %s_%d ", tgate_module_name, tgate_module_name, i); /* Dump explicit port map if required */ if (TRUE == tgate_spice_model->dump_explicit_port_map) { fprintf(fp, " (.%s(in[%d]), .%s(mem[%d]), .%s(mem_inv[%d]), .%s(out));\n", input_port[0]->lib_name, i, input_port[1]->lib_name, i, input_port[2]->lib_name, i, output_port[0]->lib_name); } else { fprintf(fp, " (in[%d], mem[%d], mem_inv[%d], out);\n", i, i, i); } } } /* Put an end to this module */ fprintf(fp, "endmodule\n"); /* Comment lines */ fprintf(fp, "//---- END Structural Verilog CMOS MUX basis module: %s -----\n\n", mux_basis_subckt_name); return; } /* Dump a structural verilog for RRAM MUX basis module * This is only called when structural verilog dumping option is enabled for this spice model * Note that the structural verilog cannot be used for functionality verification!!! */ static void dump_verilog_rram_mux_one_basis_module_structural(FILE* fp, char* mux_basis_subckt_name, int num_input_basis_subckt, t_spice_model* cur_spice_model) { /* RRAM MUX needs 2*(input_size + 1) memory bits for configuration purpose */ int num_mem = num_input_basis_subckt + 1; int i; char* progTE_module_name = "PROG_TE"; char* progBE_module_name = "PROG_BE"; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } assert(TRUE == cur_spice_model->dump_structural_verilog); /* Comment lines */ fprintf(fp, "//---- Structural Verilog for RRAM MUX basis module: %s -----\n", mux_basis_subckt_name); /* Print the port list and definition */ fprintf(fp, "module %s (\n", mux_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Port list */ fprintf(fp, "input wire [0:%d] in,\n", num_input_basis_subckt - 1); fprintf(fp, "output wire out,\n"); fprintf(fp, "input wire [0:%d] bl,\n", num_mem - 1); fprintf(fp, "input wire [0:%d] wl);\n", num_mem - 1); /* Print internal structure of 4T1R programming structures * Written in structural Verilog * The whole structure-level description is divided into two parts: * 1. Left part consists of N PROG_TE modules, each of which * includes a PMOS, a NMOS and a RRAM, which is actually the left * part of a 4T1R programming structure * 2. Right part includes only a PROG_BE module, which consists * of a PMOS and a NMOS, which is actually the right part of a * 4T1R programming sturcture */ /* LEFT part */ for (i = 0; i < num_input_basis_subckt - 1; i++) { fprintf(fp, "%s %s_%d (.A(in[%d]), .WL(wl[%d]), .BLB(bl[%d]), .Z(out));\n", progTE_module_name, progTE_module_name, i, i, i, i); } /* RIGHT part */ fprintf(fp, "%s %s_%d (.INOUT(out), .WL(wl[%d]), .BLB(bl[%d]));\n", progBE_module_name, progBE_module_name, i, i, i); /* Put an end to this module */ fprintf(fp, "endmodule\n"); /* Comment lines */ fprintf(fp, "//---- END Structural Verilog for RRAM MUX basis module: %s -----\n\n", mux_basis_subckt_name); return; } /* Dump a RRAM MUX basis module */ static void dump_verilog_rram_mux_one_basis_module(FILE* fp, char* mux_basis_subckt_name, int num_input_basis_subckt, t_spice_model* cur_spice_model) { /* RRAM MUX needs 2*(input_size + 1) memory bits for configuration purpose */ int num_mem = num_input_basis_subckt + 1; int i, iport, ipin; int find_prog_EN = 0; int find_prog_ENb = 0; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Comment lines */ fprintf(fp, "//---- RRAM MUX basis module: %s -----\n", mux_basis_subckt_name); /* Print the port list and definition */ fprintf(fp, "module %s (\n", mux_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, cur_spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Port list */ fprintf(fp, "input wire [0:%d] in,\n", num_input_basis_subckt - 1); fprintf(fp, "output wire out,\n"); fprintf(fp, "input wire [0:%d] bl,\n", num_mem - 1); fprintf(fp, "input wire [0:%d] wl);\n", num_mem - 1); /* Print the internal logics: * ONLY 4T1R programming structure is supported up to now */ fprintf(fp, "reg [0:%d] reg_out;\n", num_input_basis_subckt - 1); fprintf(fp, "always @("); for (i = 0; i < num_mem; i++) { if (0 < i) { fprintf(fp, ","); } fprintf(fp, "wl[%d], bl[%d] ", i, i); } fprintf(fp, ")\n"); fprintf(fp, "begin \n"); /* Only when the last bit of wl is enabled, * the propagating path can be changed * (RRAM value can be changed) */ fprintf(fp, "\tif ((wl[%d])", num_mem - 1); /* Find the config_enable ports (prog_EN and prog_ENb) * in global ports*/ for (iport = 0; iport < cur_spice_model->num_port; iport++) { if (FALSE == cur_spice_model->ports[iport].is_config_enable) { continue; } /* Reach here, the port should be is_config_enable */ if (0 == cur_spice_model->ports[iport].default_val) { for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) { fprintf(fp, "\n\t&&(%s[%d])", cur_spice_model->ports[iport].prefix, ipin); } /* Update counter */ find_prog_EN++; } else { assert (1 == cur_spice_model->ports[iport].default_val); for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) { fprintf(fp, "\n\t&&(~%s[%d])", cur_spice_model->ports[iport].prefix, ipin); } /* Update counter */ find_prog_ENb++; } } /* Check if we find any config_enable signals */ if (0 == find_prog_EN) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Unable to find a config_enable signal with default value 0 for a RRAM MUX (%s)!\n", __FILE__, __LINE__, cur_spice_model->name); exit(1); } if (0 == find_prog_ENb) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Unable to find a config_enable signal with default value 1 for a RRAM MUX (%s)!\n", __FILE__, __LINE__, cur_spice_model->name); exit(1); } /* Finish the if clause */ fprintf(fp, ") begin\n"); for (i = 0; i < num_input_basis_subckt; i++) { fprintf(fp, "\tif (1 == bl[%d]) begin\n", i); fprintf(fp, "\t\tassign reg_out = %d;\n",i); fprintf(fp, "\tend else "); } fprintf(fp, "\tbegin\n"); fprintf(fp, "\t\t\tassign reg_out = 0;\n"); fprintf(fp, "\t\tend\n"); fprintf(fp, "\tend\n"); fprintf(fp, "end\n"); fprintf(fp, "assign out = in[reg_out];\n"); /* Put an end to this module */ fprintf(fp, "endmodule\n"); /* Comment lines */ fprintf(fp, "//---- END RRAM MUX basis module: %s -----\n\n", mux_basis_subckt_name); return; } /* Print a basis submodule */ static void dump_verilog_mux_one_basis_module(FILE* fp, char* mux_basis_subckt_name, int mux_size, int num_input_basis_subckt, t_spice_model* cur_spice_model, boolean special_basis) { /* Make sure we have a valid 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 technology */ switch (cur_spice_model->design_tech) { case SPICE_MODEL_DESIGN_CMOS: if (TRUE == cur_spice_model->dump_structural_verilog) { dump_verilog_cmos_mux_one_basis_module_structural(fp, mux_basis_subckt_name, mux_size, num_input_basis_subckt, cur_spice_model, special_basis); } else { dump_verilog_cmos_mux_one_basis_module(fp, mux_basis_subckt_name, mux_size, num_input_basis_subckt, cur_spice_model, special_basis); } break; case SPICE_MODEL_DESIGN_RRAM: /* If requested, we can dump structural verilog for basis module */ if (TRUE == cur_spice_model->dump_structural_verilog) { dump_verilog_rram_mux_one_basis_module_structural(fp, mux_basis_subckt_name, num_input_basis_subckt, cur_spice_model); } else { dump_verilog_rram_mux_one_basis_module(fp, mux_basis_subckt_name, num_input_basis_subckt, cur_spice_model); } break; default: vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s)\n", __FILE__, __LINE__, cur_spice_model->name); exit(1); } return; } /** * Dump a verilog module for the basis circuit of a MUX */ static void dump_verilog_mux_basis_module(FILE* fp, t_spice_mux_model* spice_mux_model) { /** Act depends on the structure of MUX * 1. tree-like/one-level: we generate a basis module * 2. two/multi-level: we generate a basis and a special module (if required) */ int num_input_basis_subckt = 0; int num_input_special_basis_subckt = 0; char* mux_basis_subckt_name = NULL; char* special_basis_subckt_name = NULL; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Try to find a mux in cmos technology, * if we have, then build CMOS 2:1 MUX, and given cmos_mux2to1_subckt_name */ /* Exception: LUT require an auto-generation of netlist can run as well*/ assert((SPICE_MODEL_MUX == spice_mux_model->spice_model->type) ||(SPICE_MODEL_LUT == spice_mux_model->spice_model->type)); /* Generate the spice_mux_arch */ spice_mux_model->spice_mux_arch = (t_spice_mux_arch*)my_malloc(sizeof(t_spice_mux_arch)); init_spice_mux_arch(spice_mux_model->spice_model, spice_mux_model->spice_mux_arch, spice_mux_model->size); /* Exception: if tgate is a standard cell, we skip the basis circuit generation */ t_spice_model* tgate_spice_model = spice_mux_model->spice_model->pass_gate_logic->spice_model; if (SPICE_MODEL_GATE == tgate_spice_model->type) { assert (SPICE_MODEL_GATE_MUX2 == tgate_spice_model->design_tech_info.gate_info->type); /* Double check the mux structure, which should be tree-like */ if ( SPICE_MODEL_STRUCTURE_TREE != spice_mux_model->spice_mux_arch->structure ) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Structure of Circuit model (%s) should be tree-like because it is linked to a 2:1 MUX!\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } return; } /* Corner case: Error out MUX_SIZE = 2, automatcially give a one-level structure */ /* if ((2 == spice_mux_model->size)&&(SPICE_MODEL_STRUCTURE_ONELEVEL != spice_mux_model->spice_model->design_tech_info.structure)) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Structure of SPICE model (%s) should be one-level because it is linked to a 2:1 MUX!\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } */ /* Prepare the basis subckt name: */ mux_basis_subckt_name = generate_verilog_mux_basis_subckt_name(spice_mux_model->spice_model, spice_mux_model->size, verilog_mux_basis_posfix); special_basis_subckt_name = generate_verilog_mux_basis_subckt_name(spice_mux_model->spice_model, spice_mux_model->size, verilog_mux_special_basis_posfix); /* deteremine the number of inputs of basis subckt */ num_input_basis_subckt = spice_mux_model->spice_mux_arch->num_input_basis; /* Print the basis subckt*/ dump_verilog_mux_one_basis_module(fp, mux_basis_subckt_name, spice_mux_model->size, num_input_basis_subckt, spice_mux_model->spice_model, FALSE); /* See if we need a special basis */ switch (spice_mux_model->spice_model->design_tech_info.mux_info->structure) { case SPICE_MODEL_STRUCTURE_TREE: case SPICE_MODEL_STRUCTURE_ONELEVEL: break; case SPICE_MODEL_STRUCTURE_MULTILEVEL: num_input_special_basis_subckt = find_spice_mux_arch_special_basis_size(*(spice_mux_model->spice_mux_arch)); if (0 < num_input_special_basis_subckt) { dump_verilog_mux_one_basis_module(fp, special_basis_subckt_name, spice_mux_model->size, num_input_special_basis_subckt, spice_mux_model->spice_model, FALSE); } break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid structure for spice model (%s)!\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } /* Free */ my_free(mux_basis_subckt_name); my_free(special_basis_subckt_name); return; } static void dump_verilog_cmos_mux_tree_structure(FILE* fp, char* mux_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port, bool is_explicit_mapping) { int i, j, level, nextlevel; int nextj, out_idx; int mux_basis_cnt = 0; int num_buf_input_port = 0; int num_buf_output_port = 0; t_spice_model_port** buf_input_port = NULL; t_spice_model_port** buf_output_port = NULL; boolean* inter_buf_loc = NULL; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Intermediate buffer location map */ inter_buf_loc = (boolean*)my_calloc(spice_mux_arch.num_level + 1, sizeof(boolean)); for (i = 0; i < spice_mux_arch.num_level + 1; i++) { inter_buf_loc[i] = FALSE; } if (NULL != spice_model.lut_intermediate_buffer->location_map) { assert ((size_t)spice_mux_arch.num_level - 1 == strlen(spice_model.lut_intermediate_buffer->location_map)); /* For intermediate buffers */ for (i = 0; i < spice_mux_arch.num_level - 1; i++) { if ('1' == spice_model.lut_intermediate_buffer->location_map[i]) { inter_buf_loc[spice_mux_arch.num_level - i - 1] = TRUE; } } } /* printf("inter_buf_loc[]="); for (i = 0; i < spice_mux_arch.num_level + 1; i++) { printf("%d", inter_buf_loc[i]); } printf("\n"); */ mux_basis_cnt = 0; for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, spice_mux_arch.num_input_per_level[nextlevel] -1, /* input0 input1 */ level); /* For intermediate buffers */ if (TRUE == inter_buf_loc[level]) { fprintf(fp, "wire [%d:%d] mux2_l%d_in_buf; \n", 0, spice_mux_arch.num_input_per_level[nextlevel] -1, /* input0 input1 */ level); } } fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, 0, 0); for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); /* Print basis mux2to1 for each level*/ for (j = 0; j < spice_mux_arch.num_input_per_level[nextlevel]; j++) { nextj = j + 1; out_idx = j/2; /* Each basis mux2to1: svdd sgnd */ fprintf(fp, "%s mux_basis_no%d (", mux_basis_subckt_name, mux_basis_cnt); /* given_name */ /* For MUX2 standard cell */ t_spice_model* tgate_spice_model = spice_model.pass_gate_logic->spice_model; /* For non-standard cells */ if (SPICE_MODEL_GATE == tgate_spice_model->type) { assert(SPICE_MODEL_GATE_MUX2 == tgate_spice_model->design_tech_info.gate_info->type); int num_input_port = 0; int num_output_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; input_port = find_spice_model_ports(tgate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(tgate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); /* Quick check on the number of ports */ assert(3 == num_input_port); /* A, B and SEL */ assert(1 == num_output_port); /* OUT */ bool use_explicit_port_map; if ( (true == is_explicit_mapping) || (TRUE == tgate_spice_model->dump_explicit_port_map) ) { use_explicit_port_map = true; } /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, tgate_spice_model, FALSE, FALSE, my_bool_to_boolean(use_explicit_port_map))) { fprintf(fp, ",\n"); } if (true == use_explicit_port_map) { fprintf(fp, ".%s(", input_port[0]->lib_name); } /* For intermediate buffers */ if (TRUE == inter_buf_loc[level]) { fprintf(fp, "mux2_l%d_in_buf[%d]", level, j); /* input0 */ } else { fprintf(fp, "mux2_l%d_in[%d]", level, j); /* input0 */ } if (true == use_explicit_port_map) { fprintf(fp, "), .%s(", input_port[1]->lib_name); } else { fprintf(fp, ", "); } /* For intermediate buffers */ if (TRUE == inter_buf_loc[level]) { fprintf(fp, "mux2_l%d_in_buf[%d]", level, nextj); /* input1 */ } else { fprintf(fp, "mux2_l%d_in[%d]", level, nextj); /* input1 */ } if (true == use_explicit_port_map) { fprintf(fp, "), .%s(", output_port[0]->lib_name); } else { fprintf(fp, ", "); } fprintf(fp, "mux2_l%d_in[%d]", nextlevel, out_idx); /* output */ if (true == use_explicit_port_map) { fprintf(fp, "), .%s(", input_port[2]->lib_name); } else { fprintf(fp, ", "); } fprintf(fp, "%s[%d]", sram_port[0]->prefix, i); /* sram */ if (true == use_explicit_port_map) { fprintf(fp, "));\n"); } else { fprintf(fp, ");\n"); } } else { assert (SPICE_MODEL_PASSGATE == tgate_spice_model->type); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } if (true == is_explicit_mapping) { fprintf(fp, ".in("); } /* For intermediate buffers */ if (TRUE == inter_buf_loc[level]) { fprintf(fp, "mux2_l%d_in_buf[%d:%d]", level, j, nextj); /* input0 input1 */ } else { fprintf(fp, "mux2_l%d_in[%d:%d]", level, j, nextj); /* input0 input1 */ } if (true == is_explicit_mapping) { fprintf(fp, "), .out("); } else { fprintf(fp, ", "); } fprintf(fp, "mux2_l%d_in[%d]", nextlevel, out_idx); /* output */ if (true == is_explicit_mapping) { fprintf(fp, "), .mem("); } else { fprintf(fp, ", "); } fprintf(fp, "%s[%d]", sram_port[0]->prefix, i); /* sram */ if (true == is_explicit_mapping) { fprintf(fp, "), .mem_inv("); } else { fprintf(fp, ", "); } fprintf(fp, "%s_inv[%d]", sram_port[0]->prefix, i); /* sram_inv */ if (true == is_explicit_mapping) { fprintf(fp, "));\n"); } else { fprintf(fp, ");\n"); } } /* For intermediate buffers */ if (TRUE == inter_buf_loc[nextlevel]) { /* Find the input port, output port, and sram port*/ buf_input_port = find_spice_model_ports(spice_model.lut_intermediate_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(spice_model.lut_intermediate_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert ( (1 == num_buf_input_port) &&(1 == buf_input_port[0]->size)); assert ( (1 == num_buf_output_port) &&(1 == buf_output_port[0]->size)); /* TODO: what about tapered buffer, can we support? */ /* Each buf: svdd sgnd size=param*/ fprintf(fp, "%s %s_%d_%d (", spice_model.lut_intermediate_buffer->spice_model_name, spice_model.lut_intermediate_buffer->spice_model_name, nextlevel, out_idx); /* Given name*/ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.lut_intermediate_buffer->spice_model, FALSE, FALSE, spice_model.lut_intermediate_buffer->spice_model->dump_explicit_port_map)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if ( TRUE == spice_model.lut_intermediate_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in[%d] ", nextlevel, out_idx); /* output */ if ( TRUE == spice_model.lut_intermediate_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if ( TRUE == spice_model.lut_intermediate_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in_buf[%d] ", nextlevel, out_idx); /* output */ if ( TRUE == spice_model.lut_intermediate_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); /* Free */ my_free(buf_input_port); my_free(buf_output_port); } /* Update the counter */ j = nextj; mux_basis_cnt++; } } /* Assert */ assert(0 == nextlevel); assert(0 == out_idx); assert(mux_basis_cnt == spice_mux_arch.num_input - 1); /* Free */ my_free(inter_buf_loc); return; } static void dump_verilog_cmos_mux_multilevel_structure(FILE* fp, char* mux_basis_subckt_name, char* mux_special_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port, bool is_explicit_mapping) { int i, j, level, nextlevel, sram_idx; int out_idx; int mux_basis_cnt = 0; int special_basis_cnt = 0; int cur_num_input_basis = 0; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } mux_basis_cnt = 0; assert((2 == spice_mux_arch.num_input_basis)||(2 < spice_mux_arch.num_input_basis)); for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; sram_idx = nextlevel * spice_mux_arch.num_input_basis; /* Check */ assert(nextlevel > -1); fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, spice_mux_arch.num_input_per_level[nextlevel] -1, /* input0 input1 */ level); } fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, 0, 0); if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { /* Print local wires for local encoders */ fprintf(fp, "wire [0:%d] %s_data;\n", spice_mux_arch.num_level * spice_mux_arch.num_input_basis - 1, sram_port[0]->prefix); fprintf(fp, "wire [0:%d] %s_data_inv;\n", spice_mux_arch.num_level * spice_mux_arch.num_input_basis - 1, sram_port[0]->prefix); } for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; sram_idx = nextlevel * spice_mux_arch.num_input_basis; /* Check */ assert(nextlevel > -1); /* Determine the number of input of this basis */ cur_num_input_basis = spice_mux_arch.num_input_basis; /* Instanciate local encoder circuit here */ if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { /* Get the number of inputs */ int num_outputs = cur_num_input_basis; int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs); /* Find the decoder name */ fprintf(fp, "%s %s_%d_ (", generate_verilog_decoder_subckt_name(num_inputs, num_outputs), generate_verilog_decoder_subckt_name(num_inputs, num_outputs), i); if (true == is_explicit_mapping) { fprintf(fp, ".addr(%s[%d:%d]), .data(%s_data[%d:%d]), .data_inv(%s_data_inv[%d:%d]) );\n", sram_port[0]->prefix, nextlevel * num_inputs, (nextlevel + 1) * num_inputs - 1, sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis - 1, sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis - 1); } else { fprintf(fp, "%s[%d:%d], %s_data[%d:%d], %s_data_inv[%d:%d]);\n", sram_port[0]->prefix, nextlevel * num_inputs, (nextlevel + 1) * num_inputs - 1, sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis - 1, sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis - 1); } } /* Print basis muxQto1 for each level*/ for (j = 0; j < spice_mux_arch.num_input_per_level[nextlevel]; j = j + cur_num_input_basis) { /* output index */ out_idx = j / spice_mux_arch.num_input_basis; /* Determine the number of input of this basis */ cur_num_input_basis = spice_mux_arch.num_input_basis; if ((j + cur_num_input_basis) > spice_mux_arch.num_input_per_level[nextlevel]) { cur_num_input_basis = find_spice_mux_arch_special_basis_size(spice_mux_arch); if (0 < cur_num_input_basis) { /* Print the special basis */ fprintf(fp, "%s special_basis(", mux_special_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } if (true == is_explicit_mapping) { fprintf(fp, ".in("); } fprintf(fp, "mux2_l%d_in[%d:%d]", level, j, j + cur_num_input_basis - 1); /* input0 input1 */ if (true == is_explicit_mapping) { fprintf(fp, "), .out("); } else { fprintf(fp, ", "); } fprintf(fp, "mux2_l%d_in[%d]", nextlevel, out_idx); /* output */ if (true == is_explicit_mapping) { fprintf(fp, "), .mem("); } else { fprintf(fp, ", "); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } else { fprintf(fp, "%s[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } if (true == is_explicit_mapping) { fprintf(fp, "), .mem_inv("); } else { fprintf(fp, ", "); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data_inv[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } else { fprintf(fp, "%s_inv[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } if (true == is_explicit_mapping) { fprintf(fp, ")"); } fprintf(fp, ");\n"); special_basis_cnt++; } continue; } /* Each basis muxQto1: svdd sgnd */ fprintf(fp, "%s ", mux_basis_subckt_name); /* subckt_name */ fprintf(fp, "mux_basis_no%d (", mux_basis_cnt); /* given_name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } if (true == is_explicit_mapping) { fprintf(fp, ".in("); } fprintf(fp, "mux2_l%d_in[%d:%d]", level, j, j + cur_num_input_basis - 1); /* input0 input1 */ if (true == is_explicit_mapping) { fprintf(fp, "), .out("); } else { fprintf(fp, ", "); } fprintf(fp, "mux2_l%d_in[%d]", nextlevel, out_idx); /* output */ /* Print number of sram bits for this basis */ if (true == is_explicit_mapping) { fprintf(fp, "), .mem("); } else { fprintf(fp, ", "); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } else { fprintf(fp, "%s[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } if (true == is_explicit_mapping) { fprintf(fp, "), .mem_inv("); } else { fprintf(fp, ", "); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data_inv[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } else { fprintf(fp, "%s_inv[%d:%d]", sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1); } if (true == is_explicit_mapping) { fprintf(fp, ")"); } fprintf(fp, ");"); fprintf(fp, "\n"); /* Update the counter */ mux_basis_cnt++; } } /* Assert */ assert(0 == nextlevel); assert(0 == out_idx); assert((1 == special_basis_cnt)||(0 == special_basis_cnt)); /* assert((mux_basis_cnt + special_basis_cnt) == (int)((spice_mux_arch.num_input - 1)/(spice_mux_arch.num_input_basis - 1)) + 1); */ return; } static void dump_verilog_cmos_mux_onelevel_structure(FILE* fp, char* mux_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port, bool is_explicit_mapping) { /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } assert(SPICE_MODEL_DESIGN_CMOS == spice_model.design_tech); fprintf(fp, "wire [0:%d] mux2_l%d_in; \n", spice_mux_arch.num_input - 1, 1); /* input0 */ fprintf(fp, "wire [0:%d] mux2_l%d_in; \n", 0, 0); /* output */ /* Instanciate local encoder circuit here */ if ( (TRUE == spice_model.design_tech_info.mux_info->local_encoder) && ( 2 < spice_mux_arch.num_input) ) { /* Get the number of inputs */ int num_outputs = spice_mux_arch.num_input; int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs); /* Print local wires for local encoders */ fprintf(fp, "wire [0:%d] %s_data;\n", spice_mux_arch.num_input - 1, sram_port[0]->prefix); fprintf(fp, "wire [0:%d] %s_data_inv;\n", spice_mux_arch.num_input - 1, sram_port[0]->prefix); /* Find the decoder name */ fprintf(fp, "%s %s_0_ (", generate_verilog_decoder_subckt_name(num_inputs, num_outputs), generate_verilog_decoder_subckt_name(num_inputs, num_outputs)); if (true == is_explicit_mapping) { fprintf(fp, ".addr(%s), .data(%s_data), .data_inv(%s_data_inv) );\n", sram_port[0]->prefix, sram_port[0]->prefix, sram_port[0]->prefix); } else { fprintf(fp, "%s, %s_data, %s_data_inv);\n", sram_port[0]->prefix, sram_port[0]->prefix, sram_port[0]->prefix); } } fprintf(fp, "%s mux_basis (\n", mux_basis_subckt_name); /* given_name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } fprintf(fp, "//----- MUX inputs -----\n"); if (true == is_explicit_mapping) { fprintf(fp, ".in("); } fprintf(fp, "mux2_l%d_in[0:%d]", 1, spice_mux_arch.num_input - 1); /* input0 */ if (true == is_explicit_mapping) { fprintf(fp, "), .out("); } else { fprintf(fp, ", "); } fprintf(fp, "mux2_l%d_in[%d]", 0, 0); /* output */ if (true == is_explicit_mapping) { fprintf(fp, "),"); } else { fprintf(fp, ","); } fprintf(fp, "\n"); fprintf(fp, "//----- SRAM ports -----\n"); /* Special basis for 2-input MUX, there is only one configuration bit */ if (2 == spice_mux_arch.num_input) { if (true == is_explicit_mapping) { fprintf(fp, ".mem("); } fprintf(fp, "%s[0:%d]", sram_port[0]->prefix, 0); /* sram */ if (true == is_explicit_mapping) { fprintf(fp, "), .mem_inv("); } else { fprintf(fp, ", "); } fprintf(fp, "%s_inv[0:%d]", sram_port[0]->prefix, 0); /* sram_inv */ if (true == is_explicit_mapping) { fprintf(fp, ")"); } } else { if (true == is_explicit_mapping) { fprintf(fp, ".mem("); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data[0:%d]", sram_port[0]->prefix, spice_mux_arch.num_input - 1); /* sram */ } else { fprintf(fp, "%s[0:%d]", sram_port[0]->prefix, spice_mux_arch.num_input - 1); /* sram */ } if (true == is_explicit_mapping) { fprintf(fp, "), .mem_inv("); } else { fprintf(fp, ", "); } if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) { fprintf(fp, "%s_data_inv[0:%d]", sram_port[0]->prefix, spice_mux_arch.num_input - 1); /* sram_inv */ } else { fprintf(fp, "%s_inv[0:%d]", sram_port[0]->prefix, spice_mux_arch.num_input - 1); /* sram_inv */ } if (true == is_explicit_mapping) { fprintf(fp, ")"); } } fprintf(fp, "\n"); fprintf(fp, ");\n"); return; } static void dump_verilog_cmos_mux_submodule(FILE* fp, int mux_size, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, bool is_explicit_mapping) { int i, num_conf_bits, iport, ipin, num_mode_bits; int num_input_port = 0; int num_output_port = 0; int num_sram_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; t_spice_model_port** sram_port = NULL; int num_buf_input_port = 0; int num_buf_output_port = 0; t_spice_model_port** buf_input_port = NULL; t_spice_model_port** buf_output_port = NULL; enum e_spice_model_structure cur_mux_structure; /* Find the basis subckt*/ char* mux_basis_subckt_name = NULL; char* mux_special_basis_subckt_name = NULL; mux_basis_subckt_name = generate_verilog_mux_basis_subckt_name(&spice_model, mux_size, verilog_mux_basis_posfix); mux_special_basis_subckt_name = generate_verilog_mux_basis_subckt_name(&spice_model, mux_size, verilog_mux_special_basis_posfix); /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Ensure we have a CMOS MUX, * ATTENTION: support LUT as well */ assert((SPICE_MODEL_MUX == spice_model.type)||(SPICE_MODEL_LUT == spice_model.type)); assert(SPICE_MODEL_DESIGN_CMOS == spice_model.design_tech); /* Find the input port, output port, and sram port*/ input_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); sram_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Asserts*/ if ((SPICE_MODEL_MUX == spice_model.type) || ((SPICE_MODEL_LUT == spice_model.type) && (FALSE == spice_model.design_tech_info.lut_info->frac_lut))) { assert(1 == num_input_port); assert(1 == num_output_port); assert(1 == num_sram_port); assert(1 == output_port[0]->size); } else { assert((SPICE_MODEL_LUT == spice_model.type) && (TRUE == spice_model.design_tech_info.lut_info->frac_lut)); assert(1 == num_input_port); assert(2 == num_sram_port); for (iport = 0; iport < num_output_port; iport++) { assert(0 < output_port[iport]->size); } } /* Setup a reasonable frac_out level for the output port*/ for (iport = 0; iport < num_output_port; iport++) { /* We always initialize the lut_frac_level when there is only 1 output! * It should be pointed the last level! */ if ((OPEN == output_port[iport]->lut_frac_level) || (1 == num_output_port)) { output_port[iport]->lut_frac_level = spice_mux_arch.num_level; } } /* Add Fracturable LUT outputs */ /* We have two types of naming rules in terms of the usage of MUXes: * 1. MUXes, the naming rule is __size * 2. LUTs, the naming rule is _mux_size */ num_conf_bits = count_num_sram_bits_one_spice_model(&spice_model, mux_size); num_mode_bits = count_num_mode_bits_one_spice_model(&spice_model); /* Knock out the SRAM bits for the mode selection, they are separated dealed */ num_conf_bits = num_conf_bits - num_mode_bits; if (SPICE_MODEL_LUT == spice_model.type) { /* Special for LUT MUX */ fprintf(fp, "//------ CMOS MUX info: spice_model_name= %s_MUX, size=%d -----\n", spice_model.name, mux_size); fprintf(fp, "module %s_mux(\n", spice_model.name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Print input ports*/ fprintf(fp, "input wire [0:%d] %s,\n", num_conf_bits - 1, input_port[0]->prefix); /* Print output ports*/ for (iport = 0; iport < num_output_port; iport++) { fprintf(fp, "output wire [0:%d] %s,\n", output_port[iport]->size - 1, output_port[iport]->prefix); } /* Print configuration ports*/ /* The configuration port in MUX context is the input port in LUT context ! */ fprintf(fp, "input wire [0:%d] %s,\n", input_port[0]->size - 1, sram_port[0]->prefix); fprintf(fp, "input wire [0:%d] %s_inv\n", input_port[0]->size - 1, sram_port[0]->prefix); } else { fprintf(fp, "//----- CMOS MUX info: spice_model_name=%s, size=%d, structure: %s -----\n", spice_model.name, mux_size, gen_str_spice_model_structure(spice_model.design_tech_info.mux_info->structure)); fprintf(fp, "module %s (\n", gen_verilog_one_mux_module_name(&spice_model, mux_size)); /* Print input ports*/ fprintf(fp, "input wire [0:%d] %s,\n", mux_size - 1, input_port[0]->prefix); /* Print output ports*/ fprintf(fp, "output wire [0:%d] %s,\n", output_port[0]->size - 1, output_port[0]->prefix); /* Print configuration ports*/ fprintf(fp, "input wire [0:%d] %s,\n", num_conf_bits - 1, sram_port[0]->prefix); fprintf(fp, "input wire [0:%d] %s_inv\n", num_conf_bits - 1, sram_port[0]->prefix); } /* Print local vdd and gnd*/ fprintf(fp, ");"); fprintf(fp, "\n"); /* Handle the corner case: input size = 2 */ cur_mux_structure = spice_model.design_tech_info.mux_info->structure; if (2 == spice_mux_arch.num_input) { cur_mux_structure = SPICE_MODEL_STRUCTURE_ONELEVEL; } /* Print internal architecture*/ switch (cur_mux_structure) { case SPICE_MODEL_STRUCTURE_TREE: dump_verilog_cmos_mux_tree_structure(fp, mux_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port, is_explicit_mapping); break; case SPICE_MODEL_STRUCTURE_ONELEVEL: dump_verilog_cmos_mux_onelevel_structure(fp, mux_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port, is_explicit_mapping); break; case SPICE_MODEL_STRUCTURE_MULTILEVEL: dump_verilog_cmos_mux_multilevel_structure(fp, mux_basis_subckt_name, mux_special_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port, is_explicit_mapping); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid structure for spice model (%s)!\n", __FILE__, __LINE__, spice_model.name); exit(1); } /* To connect the input ports*/ for (i = 0; i < mux_size; i++) { if (1 == spice_model.input_buffer->exist) { /* Find the input port, output port, and sram port*/ buf_input_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert ( (1 == num_buf_input_port) &&(1 == buf_input_port[0]->size)); assert ( (1 == num_buf_output_port) &&(1 == buf_output_port[0]->size)); /* TODO: what about tapered buffer, can we support? */ /* Each buf: svdd sgnd size=param*/ fprintf(fp, "%s %s_%d_ (", spice_model.input_buffer->spice_model_name, spice_model.input_buffer->spice_model_name, i); /* Given name*/ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.input_buffer->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "%s[%d]", input_port[0]->prefix, i); /* input port */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in[%d] ", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); /* Free */ my_free(buf_input_port); my_free(buf_output_port); } else { /* There is no buffer, I create a zero resisitance between*/ /* Resistance R 0*/ fprintf(fp, "assign %s[%d] = mux2_l%d_in[%d];\n", input_port[0]->prefix, i, spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); } } /* Special: for the last inputs, we connect to VDD|GND * TODO: create an option to select the connection VDD or GND */ if ((SPICE_MODEL_MUX == spice_model.type) && (TRUE == spice_model.design_tech_info.mux_info->add_const_input)) { assert ( (0 == spice_model.design_tech_info.mux_info->const_input_val) || (1 == spice_model.design_tech_info.mux_info->const_input_val) ); fprintf(fp, "assign mux2_l%d_in[%d] = 1'b%d;\n", spice_mux_arch.input_level[spice_mux_arch.num_input - 1], spice_mux_arch.input_offset[spice_mux_arch.num_input - 1], spice_model.design_tech_info.mux_info->const_input_val); } /* Output buffer*/ for (iport = 0; iport < num_output_port; iport++) { for (ipin = 0; ipin < output_port[iport]->size; ipin++) { if (1 == spice_model.output_buffer->exist) { /* Find the input port, output port, and sram port*/ buf_input_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert ( (1 == num_buf_input_port) &&(1 == buf_input_port[0]->size)); assert ( (1 == num_buf_output_port) &&(1 == buf_output_port[0]->size)); /* Each buf: svdd sgnd size=param*/ fprintf(fp, "%s %s_out_%d_%d (", spice_model.output_buffer->spice_model_name, spice_model.output_buffer->spice_model_name, iport, ipin); /* subckt name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* check */ assert ( -1 < spice_mux_arch.num_level - output_port[iport]->lut_frac_level ); /* Dump explicit port map if required */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in[%d]", spice_mux_arch.num_level - output_port[iport]->lut_frac_level, output_port[iport]->lut_output_mask[ipin]); /* input port */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "%s[%d]", output_port[iport]->prefix, ipin); /* Output port*/ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); /* Free */ my_free(buf_input_port); my_free(buf_output_port); } else { /* check */ assert ( -1 < spice_mux_arch.num_level - output_port[iport]->lut_frac_level ); /* There is no buffer, I create a zero resisitance between*/ /* Resistance R 0*/ fprintf(fp, "assign mux2_l%d_in[%d] = %s[%d];\n", spice_mux_arch.num_level - output_port[iport]->lut_frac_level, output_port[iport]->lut_output_mask[ipin], output_port[iport]->prefix, ipin); } } } fprintf(fp, "endmodule\n"); fprintf(fp, "//----- END CMOS MUX info: spice_model_name=%s, size=%d -----\n\n", spice_model.name, mux_size); fprintf(fp, "\n"); /* Free */ my_free(mux_basis_subckt_name); my_free(mux_special_basis_subckt_name); my_free(input_port); my_free(output_port); my_free(sram_port); return; } /* Print the RRAM MUX SPICE model. * The internal structures of CMOS and RRAM MUXes are similar. * This one can be merged to CMOS function. * However I use another function, because in future the internal structure may change. * We will suffer less software problems. */ static void dump_verilog_rram_mux_tree_structure(FILE* fp, char* mux_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port) { int i, j, level, nextlevel; int nextj, out_idx; int mux_basis_cnt = 0; int cur_mem_lsb = 0; int cur_mem_msb = 0; assert(SPICE_MODEL_DESIGN_RRAM == spice_model.design_tech); /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, spice_mux_arch.num_input_per_level[nextlevel] -1, /* input0 input1 */ level); } fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, 0, 0); mux_basis_cnt = 0; for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); /* Print basis mux2to1 for each level*/ for (j = 0; j < spice_mux_arch.num_input_per_level[nextlevel]; j++) { nextj = j + 1; out_idx = j/2; cur_mem_lsb = cur_mem_msb; cur_mem_msb += 6; /* Each basis mux2to1: svdd sgnd */ fprintf(fp, "%s mux_basis_no%d (", mux_basis_subckt_name, mux_basis_cnt); /* given_name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "mux2_l%d_in[%d:%d], ", level, j, nextj); /* input0 input1 */ fprintf(fp, "mux2_l%d_in[%d], ", nextlevel, out_idx); /* output */ fprintf(fp, "%s[%d:%d] %s_inv[%d:%d]);\n", sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1, sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1); /* sram sram_inv */ /* Update the counter */ j = nextj; mux_basis_cnt++; } } /* Assert */ assert(0 == nextlevel); assert(0 == out_idx); assert(mux_basis_cnt == spice_mux_arch.num_input - 1); assert(cur_mem_msb == 6 * spice_mux_arch.num_level); return; } static void dump_verilog_rram_mux_multilevel_structure(FILE* fp, char* mux_basis_subckt_name, char* mux_special_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port) { int i, j, level, nextlevel; int out_idx; int mux_basis_cnt = 0; int special_basis_cnt = 0; int cur_num_input_basis = 0; int cur_mem_lsb = 0; int cur_mem_msb = 0; assert(SPICE_MODEL_DESIGN_RRAM == spice_model.design_tech); /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, spice_mux_arch.num_input_per_level[nextlevel] -1, /* input0 input1 */ level); } fprintf(fp, "wire [%d:%d] mux2_l%d_in; \n", 0, 0, 0); mux_basis_cnt = 0; assert((2 == spice_mux_arch.num_input_basis)||(2 < spice_mux_arch.num_input_basis)); for (i = 0; i < spice_mux_arch.num_level; i++) { level = spice_mux_arch.num_level - i; nextlevel = spice_mux_arch.num_level - i - 1; /* Check */ assert(nextlevel > -1); /* Memory port offset update */ cur_mem_lsb = cur_mem_msb; /* Print basis muxQto1 for each level*/ for (j = 0; j < spice_mux_arch.num_input_per_level[nextlevel]; j = j+cur_num_input_basis) { /* output index */ out_idx = j/spice_mux_arch.num_input_basis; /* Determine the number of input of this basis */ cur_num_input_basis = spice_mux_arch.num_input_basis; cur_mem_msb = cur_mem_lsb + (cur_num_input_basis + 1); if ((j + cur_num_input_basis) > spice_mux_arch.num_input_per_level[nextlevel]) { cur_num_input_basis = find_spice_mux_arch_special_basis_size(spice_mux_arch); if (0 < cur_num_input_basis) { /* Print the special basis */ fprintf(fp, "%s special_basis(\n", mux_special_basis_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "mux2_l%d_in[%d:%d], ", level, j, j + cur_num_input_basis - 1); /* inputs */ fprintf(fp, "mux2_l%d_in[%d], ", nextlevel, out_idx); /* output */ cur_mem_msb = cur_mem_lsb + (cur_num_input_basis + 1); fprintf(fp, "%s[%d:%d], %s_inv[%d,%d]", sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1, sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1); /* sram sram_inv */ fprintf(fp, ");\n"); special_basis_cnt++; continue; } } /* Each basis muxQto1: svdd sgnd */ fprintf(fp, "%s ", mux_basis_subckt_name); /* subckt_name */ fprintf(fp, "mux_basis_no%d (", mux_basis_cnt); /* given_name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "mux2_l%d_in[%d:%d], ", level, j, j + cur_num_input_basis - 1); /* input0 input1 */ fprintf(fp, "mux2_l%d_in[%d], ", nextlevel, out_idx); /* output */ /* Print number of sram bits for this basis */ fprintf(fp, "%s[%d:%d], %s_inv[%d:%d]", sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1, sram_port[0]->prefix, cur_mem_lsb, cur_mem_msb - 1); /* sram sram_inv */ fprintf(fp, ");\n"); /* Update the counter */ mux_basis_cnt++; } } /* Assert */ assert(0 == nextlevel); assert(0 == out_idx); assert((1 == special_basis_cnt)||(0 == special_basis_cnt)); /* assert((mux_basis_cnt + special_basis_cnt) == (int)((spice_mux_arch.num_input - 1)/(spice_mux_arch.num_input_basis - 1)) + 1); */ /* Free */ return; } static void dump_verilog_rram_mux_onelevel_structure(FILE* fp, char* mux_basis_subckt_name, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, int num_sram_port, t_spice_model_port** sram_port) { int num_conf_bits; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } assert(SPICE_MODEL_DESIGN_RRAM == spice_model.design_tech); fprintf(fp, "wire [0:%d] mux2_l%d_in; \n", spice_mux_arch.num_input - 1, 1); /* input0 */ fprintf(fp, "wire [0:%d] mux2_l%d_in; \n", 0, 0); /* output */ fprintf(fp, "%s mux_basis (\n", mux_basis_subckt_name); /* given_name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, FALSE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "//----- MUX inputs -----\n"); fprintf(fp, "mux2_l%d_in[0:%d],\n ", 1, spice_mux_arch.num_input - 1); /* inputs */ fprintf(fp, "mux2_l%d_in[%d],\n", 0, 0); /* output */ fprintf(fp, "//----- SRAM ports -----\n"); num_conf_bits = count_num_sram_bits_one_spice_model(&spice_model, spice_mux_arch.num_input); fprintf(fp, "%s[0:%d], %s_inv[0:%d]", sram_port[0]->prefix, num_conf_bits - 1, sram_port[0]->prefix, num_conf_bits - 1); /* sram sram_inv */ fprintf(fp, "\n"); fprintf(fp, ");\n"); return; } static void dump_verilog_rram_mux_submodule(FILE* fp, int mux_size, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, bool is_explicit_mapping) { int i, num_conf_bits; int num_input_port = 0; int num_output_port = 0; int num_sram_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; t_spice_model_port** sram_port = NULL; int num_buf_input_port = 0; int num_buf_output_port = 0; t_spice_model_port** buf_input_port = NULL; t_spice_model_port** buf_output_port = NULL; /* Find the basis subckt*/ char* mux_basis_subckt_name = NULL; char* mux_special_basis_subckt_name = NULL; mux_basis_subckt_name = generate_verilog_mux_basis_subckt_name(&spice_model, mux_size, verilog_mux_basis_posfix); mux_special_basis_subckt_name = generate_verilog_mux_basis_subckt_name(&spice_model, mux_size, verilog_mux_special_basis_posfix); /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Ensure we have a RRAM MUX*/ assert((SPICE_MODEL_MUX == spice_model.type)||(SPICE_MODEL_LUT == spice_model.type)); assert(SPICE_MODEL_DESIGN_RRAM == spice_model.design_tech); /* Find the input port, output port, and sram port*/ input_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); sram_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Asserts*/ assert(1 == num_input_port); assert(1 == num_output_port); assert(1 == num_sram_port); assert(1 == output_port[0]->size); /* Print the definition of subckt*/ if (SPICE_MODEL_LUT == spice_model.type) { /* RRAM LUT is not supported now... */ vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])RRAM LUT is not supported!\n", __FILE__, __LINE__); exit(1); /* Special for LUT MUX*/ /* fprintf(fp, "***** RRAM MUX info: spice_model_name= %s_MUX, size=%d *****\n", spice_model.name, mux_size); fprintf(fp, ".subckt %s_mux_size%d ", spice_model.name, mux_size); */ } else { fprintf(fp, "//----- RRAM MUX info: spice_model_name=%s, size=%d, structure: %s -----\n", spice_model.name, mux_size, gen_str_spice_model_structure(spice_model.design_tech_info.mux_info->structure)); fprintf(fp, "module %s ( \n", gen_verilog_one_mux_module_name(&spice_model, mux_size)); } /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Print input ports*/ fprintf(fp, "input wire [0:%d] %s,\n ", mux_size - 1, input_port[0]->prefix); /* Print output ports*/ fprintf(fp, "output wire %s,\n ", output_port[0]->prefix); /* Print configuration ports */ num_conf_bits = count_num_sram_bits_one_spice_model(&spice_model, mux_size); fprintf(fp, "input wire [0:%d] %s,\n", num_conf_bits - 1, sram_port[0]->prefix); fprintf(fp, "input wire [0:%d] %s_inv\n", num_conf_bits - 1, sram_port[0]->prefix); /* Print local vdd and gnd*/ fprintf(fp, ");\n"); /* Print internal architecture*/ /* RRAM MUX is optimal in terms of area, delay and power for one-level structure. */ switch (spice_model.design_tech_info.mux_info->structure) { case SPICE_MODEL_STRUCTURE_TREE: dump_verilog_rram_mux_tree_structure(fp, mux_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port); break; case SPICE_MODEL_STRUCTURE_MULTILEVEL: dump_verilog_rram_mux_multilevel_structure(fp, mux_basis_subckt_name, mux_special_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port); break; case SPICE_MODEL_STRUCTURE_ONELEVEL: dump_verilog_rram_mux_onelevel_structure(fp, mux_basis_subckt_name, spice_model, spice_mux_arch, num_sram_port, sram_port); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid structure for spice model (%s)!\n", __FILE__, __LINE__, spice_model.name); exit(1); } /* To connect the input ports*/ for (i = 0; i < mux_size; i++) { if (1 == spice_model.input_buffer->exist) { /* Find the input port, output port, and sram port*/ buf_input_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(spice_model.input_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert ( (1 == num_buf_input_port) &&(1 == buf_input_port[0]->size)); assert ( (1 == num_buf_output_port) &&(1 == buf_output_port[0]->size)); /* Each inv: svdd sgnd size=param*/ fprintf(fp, "%s %s%d (", spice_model.input_buffer->spice_model_name, spice_model.input_buffer->spice_model_name, i); /* Given name*/ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.input_buffer->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "%s[%d]", input_port[0]->prefix, i); /* input port */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in[%d]", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/ if ( TRUE == spice_model.input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); /* Free */ my_free(buf_input_port); my_free(buf_output_port); } else { /* There is no buffer, I create a zero resisitance between*/ /* Resistance R 0*/ fprintf(fp, "assign %s[%d] = mux2_l%d_in[%d];\n", input_port[0]->prefix, i, spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); } } /* Special: for the last inputs, we connect to VDD|GND * TODO: create an option to select the connection VDD or GND */ if ((SPICE_MODEL_MUX == spice_model.type) && (TRUE == spice_model.design_tech_info.mux_info->add_const_input)) { assert ( (0 == spice_model.design_tech_info.mux_info->const_input_val) || (1 == spice_model.design_tech_info.mux_info->const_input_val) ); fprintf(fp, "assign mux2_l%d_in[%d] = 1'b%d;\n", spice_mux_arch.input_level[spice_mux_arch.num_input], spice_mux_arch.input_offset[spice_mux_arch.num_input], spice_model.design_tech_info.mux_info->const_input_val); } /* Output buffer*/ if (1 == spice_model.output_buffer->exist) { /* Find the input port, output port, and sram port*/ buf_input_port = find_spice_model_ports(spice_model.output_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(spice_model.output_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert ( (1 == num_buf_input_port) &&(1 == buf_input_port[0]->size)); assert ( (1 == num_buf_output_port) &&(1 == buf_output_port[0]->size)); /* Each buf: svdd sgnd size=param*/ fprintf(fp, "%s %s_out (", spice_model.output_buffer->spice_model_name, spice_model.output_buffer->spice_model_name); /* subckt name */ /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "mux2_l%d_in[%d]", 0 , 0); /* input port */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "%s", output_port[0]->prefix); /* Output port*/ if ( TRUE == spice_model.output_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); /* Free */ my_free(buf_input_port); my_free(buf_output_port); } else { /* There is no buffer, I create a zero resisitance between*/ /* Resistance R 0*/ fprintf(fp, "assign mux2_l0_in[0] %s;\n", output_port[0]->prefix); } fprintf(fp, "endmodule\n"); fprintf(fp, "//------ END RRAM MUX info: spice_model_name=%s, size=%d -----\n\n", spice_model.name, mux_size); fprintf(fp, "\n"); /* Free */ my_free(mux_basis_subckt_name); my_free(mux_special_basis_subckt_name); my_free(input_port); my_free(output_port); my_free(sram_port); return; } /* Dump a memory submodule for the MUX */ static void dump_verilog_cmos_mux_mem_submodule(FILE* fp, int mux_size, t_spice_model spice_model, t_spice_mux_arch spice_mux_arch, bool is_explicit_mapping) { int i, num_conf_bits; int num_sram_port = 0; t_spice_model_port** sram_port = NULL; /* Find the basis subckt*/ char* mux_mem_subckt_name = NULL; t_spice_model* mem_model = NULL; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* We only do this for MUX not LUT * LUT memory block added at top-level */ assert((SPICE_MODEL_MUX == spice_model.type)||(SPICE_MODEL_LUT == spice_model.type)); if (SPICE_MODEL_LUT == spice_model.type) { return; } /* Ensure we have a CMOS MUX */ assert(SPICE_MODEL_DESIGN_CMOS == spice_model.design_tech); /* Generate subckt name */ mux_mem_subckt_name = generate_verilog_mux_subckt_name(&spice_model, mux_size, verilog_mem_posfix); /* Get SRAM port */ sram_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Asserts*/ assert ((1 == num_sram_port) && (NULL != sram_port)); assert (NULL != sram_port[0]->spice_model); assert ((SPICE_MODEL_SCFF == sram_port[0]->spice_model->type) || (SPICE_MODEL_SRAM == sram_port[0]->spice_model->type)); /* Get the memory model */ mem_model = sram_port[0]->spice_model; /* We have two types of naming rules in terms of the usage of MUXes: * 1. MUXes, the naming rule is __size * 2. LUTs, the naming rule is _mux_size */ num_conf_bits = count_num_sram_bits_one_spice_model(&spice_model, mux_size); fprintf(fp, "//----- CMOS MUX info: spice_model_name=%s, size=%d, structure: %s -----\n", spice_model.name, mux_size, gen_str_spice_model_structure(spice_model.design_tech_info.mux_info->structure)); fprintf(fp, "module %s (", mux_mem_subckt_name); /* Here we force the sequence of ports: of a memory subumodule: * 1. Global ports * 2. input ports * 3. output ports * 4. bl/wl ports */ /* Local Encoding support */ dump_verilog_mem_module_port_map(fp, mem_model, TRUE, 0, num_conf_bits, my_bool_to_boolean(is_explicit_mapping)); fprintf(fp, ");\n"); /* Dump all the submodules */ for (i = 0 ; i < num_conf_bits; i++) { fprintf(fp, "%s %s_%d_ ( ", mem_model->name, mem_model->prefix, i); dump_verilog_mem_module_port_map(fp, mem_model, FALSE, i, 1, mem_model->dump_explicit_port_map); fprintf(fp, ");\n"); } /* END of this submodule */ fprintf(fp, "endmodule\n"); /* Free */ my_free(mux_mem_subckt_name); return; } /** Dump a verilog module for a MUX * We always dump a basis submodule for a MUX * whatever structure it is: one-level, two-level or multi-level */ static void dump_verilog_mux_mem_module(FILE* fp, t_spice_mux_model* spice_mux_model, bool is_explicit_mapping) { /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Make sure we have a valid spice_model*/ if (NULL == spice_mux_model) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid spice_mux_model!\n",__FILE__, __LINE__); exit(1); } /* Make sure we have a valid spice_model*/ if (NULL == spice_mux_model->spice_model) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid spice_model!\n",__FILE__, __LINE__); exit(1); } /* Check the mux size */ if (spice_mux_model->size < 2) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid MUX size(=%d)! Should be at least 2.\n", __FILE__, __LINE__, spice_mux_model->size); exit(1); } /* Print the definition of subckt*/ /* Check the design technology*/ switch (spice_mux_model->spice_model->design_tech) { case SPICE_MODEL_DESIGN_CMOS: dump_verilog_cmos_mux_mem_submodule(fp, spice_mux_model->size, *(spice_mux_model->spice_model), *(spice_mux_model->spice_mux_arch), is_explicit_mapping); break; case SPICE_MODEL_DESIGN_RRAM: /* We do not need a memory submodule for RRAM MUX, * RRAM are embedded in the datapath */ break; default: vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s)\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } return; } /** Dump a verilog module for a MUX * We always dump a basis submodule for a MUX * whatever structure it is: one-level, two-level or multi-level */ static void dump_verilog_mux_module(FILE* fp, t_spice_mux_model* spice_mux_model, bool is_explicit_mapping) { /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } /* Make sure we have a valid spice_model*/ if (NULL == spice_mux_model) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid spice_mux_model!\n",__FILE__, __LINE__); exit(1); } /* Make sure we have a valid spice_model*/ if (NULL == spice_mux_model->spice_model) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid spice_model!\n",__FILE__, __LINE__); exit(1); } /* Check the mux size*/ if (spice_mux_model->size < 2) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid MUX size(=%d)! Should be at least 2.\n", __FILE__, __LINE__, spice_mux_model->size); exit(1); } /* Corner case: Error out MUX_SIZE = 2, automatcially give a one-level structure */ /* if ((2 == spice_mux_model->size)&&(SPICE_MODEL_STRUCTURE_ONELEVEL != spice_mux_model->spice_model->design_tech_info.structure)) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Structure of SPICE model (%s) should be one-level because it is linked to a 2:1 MUX!\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } */ /* Print the definition of subckt*/ /* Check the design technology*/ switch (spice_mux_model->spice_model->design_tech) { case SPICE_MODEL_DESIGN_CMOS: dump_verilog_cmos_mux_submodule(fp, spice_mux_model->size, *(spice_mux_model->spice_model), *(spice_mux_model->spice_mux_arch), is_explicit_mapping); break; case SPICE_MODEL_DESIGN_RRAM: dump_verilog_rram_mux_submodule(fp, spice_mux_model->size, *(spice_mux_model->spice_model), *(spice_mux_model->spice_mux_arch), is_explicit_mapping); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s)\n", __FILE__, __LINE__, spice_mux_model->spice_model->name); exit(1); } return; } /*** Top-level function *****/ /* We should count how many multiplexers with different sizes are needed */ static void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, int num_switch, t_switch_inf* switches, t_spice* spice, t_det_routing_arch* routing_arch, bool is_explicit_mapping) { /* Statisitcs for input sizes and structures of MUXes * used in FPGA architecture */ /* We have linked list whichs stores spice model information of multiplexer*/ t_llist* muxes_head = NULL; t_llist* temp = NULL; int mux_cnt = 0; int max_mux_size = -1; int min_mux_size = -1; FILE* fp = NULL; char* verilog_name = my_strcat(submodule_dir,muxes_verilog_file_name); int num_input_ports = 0; t_spice_model_port** input_ports = NULL; int num_sram_ports = 0; t_spice_model_port** sram_ports = NULL; int num_input_basis = 0; t_spice_mux_model* cur_spice_mux_model = NULL; int max_routing_mux_size = -1; /* Alloc the muxes*/ muxes_head = stats_spice_muxes(num_switch, switches, spice, routing_arch); /* Print the muxes netlist*/ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create subckt SPICE netlist %s",__FILE__, __LINE__, verilog_name); exit(1); } /* Generate the descriptions*/ dump_verilog_file_header(fp,"MUXes used in FPGA"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Print mux netlist one by one*/ temp = muxes_head; while(temp) { assert(NULL != temp->dptr); cur_spice_mux_model = (t_spice_mux_model*)(temp->dptr); /* Bypass the spice models who has a user-defined subckt */ if (NULL != cur_spice_mux_model->spice_model->verilog_netlist) { input_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_INPUT, &num_input_ports, TRUE); sram_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_ports, TRUE); assert(0 != num_input_ports); assert(0 != num_sram_ports); /* Check the Input port size */ if (cur_spice_mux_model->size != input_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) size(%d) unmatch with the architecture needs(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, input_ports[0]->size,cur_spice_mux_model->size); exit(1); } /* Check the SRAM port size */ num_input_basis = determine_num_input_basis_multilevel_mux(cur_spice_mux_model->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level); if ((num_input_basis * cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level) != sram_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) SRAM size(%d) unmatch with the num of level(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, sram_ports[0]->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level*num_input_basis); exit(1); } /* Move on to the next*/ temp = temp->next; continue; } /* Let's have a N:1 MUX as basis*/ dump_verilog_mux_basis_module(fp, cur_spice_mux_model); /* Print the mux subckt */ dump_verilog_mux_module(fp, cur_spice_mux_model, is_explicit_mapping); /* Update the statistics*/ mux_cnt++; if ((-1 == max_mux_size)||(max_mux_size < cur_spice_mux_model->size)) { max_mux_size = cur_spice_mux_model->size; } if ((-1 == min_mux_size)||(min_mux_size > cur_spice_mux_model->size)) { min_mux_size = cur_spice_mux_model->size; } /* Exclude LUT MUX from this statistics */ if ((SPICE_MODEL_MUX == cur_spice_mux_model->spice_model->type) &&((-1 == max_routing_mux_size)||(max_routing_mux_size < cur_spice_mux_model->size))) { max_routing_mux_size = cur_spice_mux_model->size; } /* Move on to the next*/ temp = temp->next; } /* Generate modules into a .bak file now. Rename after it is verified */ std::string verilog_fname(my_strcat(submodule_dir, muxes_verilog_file_name)); verilog_fname += ".bak"; /* Create the file stream */ std::fstream sfp; sfp.open(verilog_fname, std::fstream::out | std::fstream::trunc); /* Print out debugging information for if the file is not opened/created properly */ vpr_printf(TIO_MESSAGE_INFO, "Creating Verilog netlist for Multiplexers (%s) ...\n", verilog_fname.c_str()); check_file_handler(sfp); /* TODO: this conversion is temporary. Will be removed after code reconstruction */ MuxLibrary mux_lib = convert_mux_arch_to_library(spice->circuit_lib, muxes_head); /* Generate basis sub-circuit for unique branches shared by the multiplexers */ for (auto mux : mux_lib.muxes()) { const MuxGraph& mux_graph = mux_lib.mux_graph(mux); CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux); /* Create a mux graph for the branch circuit */ std::vector branch_mux_graphs = mux_graph.build_mux_branch_graphs(); /* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */ for (auto branch_mux_graph : branch_mux_graphs) { generate_verilog_mux_branch_module(sfp, spice->circuit_lib, mux_circuit_model, branch_mux_graph); } } /* Dump MUX graph one by one */ /* Close the file steam */ sfp.close(); /* TODO: * Scan-chain configuration circuit does not need any BLs/WLs! * SRAM MUX does not need any reserved BL/WLs! */ /* Determine reserved Bit/Word Lines if a memory bank is specified, * At least 1 BL/WL should be reserved! */ try_update_sram_orgz_info_reserved_blwl(cur_sram_orgz_info, max_routing_mux_size, max_routing_mux_size); vpr_printf(TIO_MESSAGE_INFO,"Generated %d Multiplexer submodules.\n", mux_cnt); vpr_printf(TIO_MESSAGE_INFO,"Max. MUX size = %d.\t", max_mux_size); vpr_printf(TIO_MESSAGE_INFO,"Min. MUX size = %d.\n", min_mux_size); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); /* Close the file*/ fclose(fp); /* remember to free the linked list*/ free_muxes_llist(muxes_head); /* Free strings */ free(verilog_name); return; } /*************************************************************************************** * Create a Verilog module for a encoder with a given output size * Inputs * | | | | | * +-----------+ * / \ * / Encoder \ * +-----------------+ * | | | | | | | | * Outputs * * The outputs are assumes to be one-hot codes (at most only one '1' exist) * Considering this fact, there are only num_of_outputs conditions to be encoded. * Therefore, the number of inputs is ceil(log(num_of_outputs)/log(2)) ***************************************************************************************/ static void dump_verilog_mux_local_encoder_module(FILE* fp, int num_outputs) { /* Make sure we have a encoder which is at least 2 ! */ assert (2 <= num_outputs); /* Get the number of inputs */ int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs); /* Validate the FILE handler */ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s,LINE[%d]Invalid file handler!\n", __FILE__, __LINE__); exit(1); } /* Print the name of encoder */ fprintf(fp, "//-------- Local Decoder convert %d-bit addr to %d-bit data \n", num_inputs, num_outputs); fprintf(fp, "module %s(", generate_verilog_decoder_subckt_name(num_inputs, num_outputs)); fprintf(fp, "\n"); /* Inputs */ dump_verilog_generic_port(fp, VERILOG_PORT_INPUT, "addr", 0, num_inputs - 1); fprintf(fp, ",\n"); /* Outputs */ fprintf(fp, "output "); dump_verilog_generic_port(fp, VERILOG_PORT_REG, "data", 0, num_outputs - 1); fprintf(fp, ",\n"); dump_verilog_generic_port(fp, VERILOG_PORT_OUTPUT, "data_inv", 0, num_outputs - 1); fprintf(fp, "\n);\n"); /* Print the truth table of this encoder */ /* Internal logics */ /* We use a magic number -1 as the addr=1 should be mapped to ...1 * Otherwise addr will map addr=1 to ..10 * Note that there should be a range for the shift operators * We should narrow the encoding to be applied to a given set of data * This will lead to that any addr which falls out of the op code of data * will give a all-zero code * For example: * data is 5-bit while addr is 3-bit * data=8'b0_0000 will be encoded to addr=3'b001; * data=8'b0_0001 will be encoded to addr=3'b010; * data=8'b0_0010 will be encoded to addr=3'b011; * data=8'b0_0100 will be encoded to addr=3'b100; * data=8'b0_1000 will be encoded to addr=3'b101; * data=8'b1_0000 will be encoded to addr=3'b110; * The rest of addr codes 3'b110, 3'b111 will be decoded to data=8'b0_0000; */ fprintf(fp, "always@(addr)\n"); fprintf(fp, "case (addr)\n"); /* Create a string for addr and data */ for (int i = 0; i < num_outputs; ++i) { fprintf(fp, "\t%d'b%s : data = %d'b%s;\n", num_inputs, my_itobin(i, num_inputs), num_outputs, my_ito1hot(i, num_outputs)); } fprintf(fp, "\tdefault : data = %d'b%s;\n", num_outputs, my_ito1hot(num_outputs - 1, num_outputs)); fprintf(fp, "endcase\n"); fprintf(fp, "assign data_inv = ~data;\n"); /* Finish */ fprintf(fp, "endmodule\n"); fprintf(fp, "//-------- END Local Decoder convert %d-bit addr to %d-bit data \n\n", num_inputs, num_outputs); return; } /* We should count how many multiplexers with different sizes are needed */ static void dump_verilog_submodule_local_encoders(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, int num_switch, t_switch_inf* switches, t_spice* spice, t_det_routing_arch* routing_arch, bool is_explicit_mapping) { /* Statisitcs for input sizes and structures of MUXes * used in FPGA architecture */ /* We have linked list whichs stores spice model information of multiplexer*/ t_llist* muxes_head = NULL; t_llist* temp = NULL; FILE* fp = NULL; char* verilog_name = my_strcat(submodule_dir, local_encoder_verilog_file_name); int num_input_ports = 0; t_spice_model_port** input_ports = NULL; int num_sram_ports = 0; t_spice_model_port** sram_ports = NULL; int num_input_basis = 0; t_spice_mux_model* cur_spice_mux_model = NULL; /* Alloc the muxes*/ muxes_head = stats_spice_muxes(num_switch, switches, spice, routing_arch); /* Print the muxes netlist*/ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create subckt SPICE netlist %s",__FILE__, __LINE__, verilog_name); exit(1); } /* Generate the descriptions*/ dump_verilog_file_header(fp,"MUXes used in FPGA"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Create a vector for local encoders with different sizes */ std::vector encoder_sizes; /* Make sure a clean start */ encoder_sizes.clear(); /* Print mux netlist one by one*/ temp = muxes_head; while(temp) { assert(NULL != temp->dptr); cur_spice_mux_model = (t_spice_mux_model*)(temp->dptr); /* Bypass the spice models who has a user-defined subckt */ if (NULL != cur_spice_mux_model->spice_model->verilog_netlist) { input_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_INPUT, &num_input_ports, TRUE); sram_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_ports, TRUE); assert(0 != num_input_ports); assert(0 != num_sram_ports); /* Check the Input port size */ if (cur_spice_mux_model->size != input_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) size(%d) unmatch with the architecture needs(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, input_ports[0]->size,cur_spice_mux_model->size); exit(1); } /* Check the SRAM port size */ num_input_basis = determine_num_input_basis_multilevel_mux(cur_spice_mux_model->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level); if ((num_input_basis * cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level) != sram_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) SRAM size(%d) unmatch with the num of level(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, sram_ports[0]->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level*num_input_basis); exit(1); } /* Move on to the next*/ temp = temp->next; continue; } /* Bypass those without local encoders, we only care SPICE models whose type is MUX! */ if ( (SPICE_MODEL_MUX != cur_spice_mux_model->spice_model->type) || (FALSE == cur_spice_mux_model->spice_model->design_tech_info.mux_info->local_encoder) ) { /* Move on to the next*/ temp = temp->next; continue; } /* Reach here, we need to generate a local encoder Verilog module */ /* Generate the spice_mux_arch */ cur_spice_mux_model->spice_mux_arch = (t_spice_mux_arch*)my_malloc(sizeof(t_spice_mux_arch)); init_spice_mux_arch(cur_spice_mux_model->spice_model, cur_spice_mux_model->spice_mux_arch, cur_spice_mux_model->size); /* We will bypass all the TREE-LIKE multiplexers and those with 2-inputs */ if ( (SPICE_MODEL_STRUCTURE_TREE == cur_spice_mux_model->spice_mux_arch->structure) || ( 2 == cur_spice_mux_model->spice_mux_arch->num_input) ) { /* Move on to the next*/ temp = temp->next; continue; } /* Find the size of local encoders */ std::vector::iterator it = std::find(encoder_sizes.begin(), encoder_sizes.end(), cur_spice_mux_model->spice_mux_arch->num_input_basis); /* See if a same-sized local encoder is already in the list */ if (it == encoder_sizes.end()) { /* Need to add to the list */ encoder_sizes.push_back(cur_spice_mux_model->spice_mux_arch->num_input_basis); } /* Move on to the next*/ temp = temp->next; } /* Print the local encoder subckt */ for (size_t i = 0; i < encoder_sizes.size(); ++i) { dump_verilog_mux_local_encoder_module(fp, encoder_sizes[i]); } vpr_printf(TIO_MESSAGE_INFO,"Generated %d local encoders for Multiplexers.\n", encoder_sizes.size()); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); /* Close the file*/ fclose(fp); /* remember to free the linked list*/ free_muxes_llist(muxes_head); /* Free strings */ free(verilog_name); return; } static void dump_verilog_wire_module(FILE* fp, char* wire_subckt_name, t_spice_model verilog_model) { int num_input_port = 0; int num_output_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } /* Check the wire model*/ assert(NULL != verilog_model.wire_param); assert(0 < verilog_model.wire_param->level); /* Find the input port, output port*/ input_port = find_spice_model_ports(&verilog_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(&verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); /* Asserts*/ assert(1 == num_input_port); assert(1 == num_output_port); assert(1 == input_port[0]->size); assert(1 == output_port[0]->size); /* print the spice model*/ fprintf(fp, "//-----Wire module, verilog_model_name=%s -----\n", verilog_model.name); switch (verilog_model.type) { case SPICE_MODEL_CHAN_WIRE: /* Add an output at middle point for connecting CB inputs */ fprintf(fp, "module %s (\n", wire_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &verilog_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "input wire %s, output wire %s, output wire mid_out);\n", input_port[0]->prefix, output_port[0]->prefix); fprintf(fp, "\tassign %s = %s;\n", output_port[0]->prefix, input_port[0]->prefix); fprintf(fp, "\tassign mid_out = %s;\n", input_port[0]->prefix); break; case SPICE_MODEL_WIRE: /* Add an output at middle point for connecting CB inputs */ fprintf(fp, "module %s (\n", wire_subckt_name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, &verilog_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } fprintf(fp, "input wire %s, output wire %s);\n", input_port[0]->prefix, output_port[0]->prefix); /* Direct shortcut */ fprintf(fp, "\t\tassign %s = %s;\n", output_port[0]->prefix, input_port[0]->prefix); break; default: vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid type of spice_model! Expect [chan_wire|wire].\n", __FILE__, __LINE__); exit(1); } /* Finish*/ fprintf(fp, "endmodule\n"); fprintf(fp, "//-----END Wire module, verilog_model_name=%s -----\n", verilog_model.name); fprintf(fp, "\n"); return; } /* Dump one module of a LUT */ static void dump_verilog_submodule_one_lut(FILE* fp, t_spice_model* verilog_model, bool is_explicit_mapping) { int num_input_port = 0; int num_output_port = 0; int num_sram_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; t_spice_model_port** sram_port = NULL; int iport, ipin; int sram_port_index = OPEN; int mode_port_index = OPEN; int mode_lsb = 0; int num_dumped_port = 0; char* mode_inport_postfix = "_mode"; int num_buf_input_port = 0; int num_buf_output_port = 0; t_spice_model_port** buf_input_port = NULL; t_spice_model_port** buf_output_port = NULL; int jport, jpin, pin_cnt; int modegate_num_input_port = 0; int modegate_num_input_pins = 0; int modegate_num_output_port = 0; t_spice_model_port** modegate_input_port = NULL; t_spice_model_port** modegate_output_port = NULL; char* required_gate_type = NULL; enum e_spice_model_gate_type required_gate_model_type; /* Check */ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } assert(SPICE_MODEL_LUT == verilog_model->type); /* Print module name */ fprintf(fp, "//-----LUT module, verilog_model_name=%s -----\n", verilog_model->name); fprintf(fp, "module %s (", verilog_model->name); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, TRUE, FALSE, FALSE)) { fprintf(fp, ",\n"); } /* Print module port list */ /* Find the input port, output port, and sram port*/ input_port = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); sram_port = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Asserts*/ if (FALSE == verilog_model->design_tech_info.lut_info->frac_lut) { /* when fracturable LUT is considered * More than 1 output is allowed * Only two SRAM ports are allowed */ assert(1 == num_input_port); assert(1 == num_output_port); assert(1 == num_sram_port); } else { assert (TRUE == verilog_model->design_tech_info.lut_info->frac_lut); /* when fracturable LUT is considered * More than 1 output is allowed * Only two SRAM ports are allowed */ assert(1 == num_input_port); for (iport = 0; iport < num_output_port; iport++) { assert(0 < output_port[iport]->size); } assert(2 == num_sram_port); } /* input port */ fprintf(fp, "input wire [0:%d] %s,\n", input_port[0]->size - 1, input_port[0]->prefix); /* Print output ports*/ for (iport = 0; iport < num_output_port; iport++) { fprintf(fp, "output wire [0:%d] %s,\n", output_port[iport]->size - 1, output_port[iport]->prefix); } /* Print configuration ports*/ num_dumped_port = 0; for (iport = 0; iport < num_sram_port; iport++) { /* By pass mode select ports */ if (TRUE == sram_port[iport]->mode_select) { continue; } assert(FALSE == sram_port[iport]->mode_select); fprintf(fp, "input wire [0:%d] %s_out,\n", sram_port[iport]->size - 1, sram_port[iport]->prefix); /* Inverted configuration port is not connected to any internal signal of a LUT */ fprintf(fp, "input wire [0:%d] %s_outb\n", sram_port[iport]->size - 1, sram_port[iport]->prefix); sram_port_index = iport; num_dumped_port++; } assert(1 == num_dumped_port); /* Print mode configuration ports*/ num_dumped_port = 0; for (iport = 0; iport < num_sram_port; iport++) { /* By pass mode select ports */ if (FALSE == sram_port[iport]->mode_select) { continue; } fprintf(fp, ",\n"); assert(TRUE == sram_port[iport]->mode_select); fprintf(fp, "input wire [0:%d] %s_out,\n", sram_port[iport]->size - 1, sram_port[iport]->prefix); /* Inverted configuration port is not connected to any internal signal of a LUT */ fprintf(fp, "input wire [0:%d] %s_outb\n", sram_port[iport]->size - 1, sram_port[iport]->prefix); mode_port_index = iport; num_dumped_port++; } /* Check if all required SRAMs ports*/ if (TRUE == verilog_model->design_tech_info.lut_info->frac_lut) { if (1 != num_dumped_port) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s,LINE[%d]) Fracturable LUT (spice_model_name=%s) must have 1 mode port!\n", __FILE__, __LINE__, verilog_model->name); exit(1); } } /* End of port list */ fprintf(fp, ");\n"); /* Add mode selector */ fprintf(fp, " wire [0:%d] %s%s;\n", input_port[0]->size - 1, input_port[0]->prefix, mode_inport_postfix); fprintf(fp, " wire [0:%d] %s_b;\n", input_port[0]->size - 1, input_port[0]->prefix); fprintf(fp, " wire [0:%d] %s_buf;\n", input_port[0]->size - 1, input_port[0]->prefix); /* Regular ports */ if (FALSE == verilog_model->design_tech_info.lut_info->frac_lut) { /* Wire the mode ports to regular inputs */ for (ipin = 0; ipin < input_port[0]->size; ipin++) { fprintf(fp, " assign %s%s[%d] = %s[%d];\n", input_port[0]->prefix, mode_inport_postfix, ipin, input_port[0]->prefix, ipin); } } else { assert (TRUE == verilog_model->design_tech_info.lut_info->frac_lut); assert( NULL != input_port[0]->tri_state_map ); /* Create inverters between input port and its inversion */ mode_lsb = 0; for (ipin = 0; ipin < input_port[0]->size; ipin++) { /* Set up checking flags */ if ('0' == input_port[0]->tri_state_map[ipin]) { required_gate_type = "AND"; required_gate_model_type = SPICE_MODEL_GATE_AND; } if ('1' == input_port[0]->tri_state_map[ipin]) { required_gate_type = "OR"; required_gate_model_type = SPICE_MODEL_GATE_OR; } switch (input_port[0]->tri_state_map[ipin]) { case '-': fprintf(fp, " assign %s%s[%d] = %s[%d];\n", input_port[0]->prefix, mode_inport_postfix, ipin, input_port[0]->prefix, ipin); break; case '0': case '1': /* Check: we must have an AND2/OR2 gate */ if (NULL == input_port[0]->spice_model) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE: %s, [LINE%d]) %s gate for the input port (name=%s) of spice model (name=%s) is not defined!\n", __FILE__, __LINE__, required_gate_type, input_port[0]->prefix, verilog_model->name); exit(1); } if ((SPICE_MODEL_GATE != input_port[0]->spice_model->type) || (required_gate_model_type != input_port[0]->spice_model->design_tech_info.gate_info->type)) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE: %s, [LINE%d]) %s gate for the input port (name=%s) of spice model (name=%s) is not defined as a AND logic gate!\n", __FILE__, __LINE__, required_gate_type, input_port[0]->prefix, verilog_model->name); exit(1); } /* Check input ports */ modegate_input_port = find_spice_model_ports(input_port[0]->spice_model, SPICE_MODEL_PORT_INPUT, &modegate_num_input_port, TRUE); modegate_num_input_pins = 0; for (jport = 0; jport < modegate_num_input_port; jport++) { modegate_num_input_pins += modegate_input_port[jport]->size; } if (2 != modegate_num_input_pins) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE: %s, [LINE%d]) %s gate for the input port (name=%s) of spice model (name=%s) should have only 2 input pins!\n", __FILE__, __LINE__, required_gate_type, input_port[0]->prefix, verilog_model->name); exit(1); } /* Check output ports */ modegate_output_port = find_spice_model_ports(input_port[0]->spice_model, SPICE_MODEL_PORT_OUTPUT, &modegate_num_output_port, TRUE); if ( (1 != modegate_num_output_port) || (1 != modegate_output_port[0]->size)) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE: %s, [LINE%d]) %s gate for the input port (name=%s) of spice model (name=%s) should have only 1 output!\n", __FILE__, __LINE__, required_gate_type, input_port[0]->prefix, verilog_model->name); exit(1); } /* Instance the AND2/OR2 gate */ fprintf(fp, " %s %s_%s_%d_(", input_port[0]->spice_model->name, input_port[0]->spice_model->prefix, input_port[0]->prefix, ipin); pin_cnt = 0; for (jport = 0; jport < modegate_num_input_port; jport++) { if (0 < jport) { fprintf(fp, ","); } for (jpin = 0; jpin < modegate_input_port[jport]->size; jpin++) { if (0 < jpin) { fprintf(fp, ","); } if (0 == pin_cnt) { /* Dump explicit port map if required */ if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", modegate_input_port[jport]->lib_name); } fprintf(fp, "%s[%d]", input_port[0]->prefix, ipin); if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } } else if (1 == pin_cnt) { /* Dump explicit port map if required */ if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", modegate_input_port[jport]->lib_name); } fprintf(fp, " %s_out[%d]", sram_port[mode_port_index]->prefix, mode_lsb); if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } } pin_cnt++; } } assert(2 == pin_cnt); fprintf(fp, ", "); /* Dump explicit port map if required */ if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", modegate_output_port[0]->lib_name); } fprintf(fp, " %s%s[%d]", input_port[0]->prefix, mode_inport_postfix, ipin); if (TRUE == input_port[0]->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); mode_lsb++; /* Free ports */ my_free(modegate_input_port); my_free(modegate_output_port); break; default: vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s,LINE[%d]) Invalid LUT tri_state_map = %s ", __FILE__, __LINE__, input_port[0]->tri_state_map); exit(1); } } if (mode_lsb != sram_port[mode_port_index]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s,LINE[%d]) SPICE model LUT (name=%s) has a unmatched tri-state map (%s) implied by mode_port size(%d)!\n", __FILE__, __LINE__, verilog_model->name, input_port[0]->tri_state_map[ipin], input_port[0]->size); exit(1); } } /* Find the ports for input_inverter */ buf_input_port = find_spice_model_ports(verilog_model->lut_input_buffer->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(verilog_model->lut_input_buffer->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert(1 == num_buf_input_port); assert(1 == num_buf_output_port); /* Create buffer input port */ for (ipin = 0; ipin < input_port[0]->size; ipin++) { fprintf(fp, "%s %s_%s_%d_ ( ", verilog_model->lut_input_buffer->spice_model->name, verilog_model->lut_input_buffer->spice_model->name, input_port[0]->prefix, ipin); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model->lut_input_buffer->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if (TRUE == verilog_model->lut_input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "%s%s[%d]", input_port[0]->prefix, mode_inport_postfix, ipin); if (TRUE == verilog_model->lut_input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if (TRUE == verilog_model->lut_input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "%s_buf[%d]", input_port[0]->prefix, ipin); if (TRUE == verilog_model->lut_input_buffer->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); } /* Free */ my_free(buf_input_port); my_free(buf_output_port); /* Find the ports for input_inverter */ buf_input_port = find_spice_model_ports(verilog_model->lut_input_inverter->spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE); buf_output_port = find_spice_model_ports(verilog_model->lut_input_inverter->spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE); /* Check */ assert(1 == num_buf_input_port); assert(1 == num_buf_output_port); /* Create inverted input port */ for (ipin = 0; ipin < input_port[0]->size; ipin++) { fprintf(fp, "%s %s_%s_%d_ ( ", verilog_model->lut_input_inverter->spice_model->name, verilog_model->lut_input_inverter->spice_model->name, input_port[0]->prefix, ipin); /* Dump global ports */ if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model->lut_input_inverter->spice_model, FALSE, FALSE, TRUE)) { fprintf(fp, ",\n"); } /* Dump explicit port map if required */ if (TRUE == verilog_model->lut_input_inverter->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_input_port[0]->lib_name); } fprintf(fp, "%s%s[%d]", input_port[0]->prefix, mode_inport_postfix, ipin); if (TRUE == verilog_model->lut_input_inverter->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ", "); /* Dump explicit port map if required */ if (TRUE == verilog_model->lut_input_inverter->spice_model->dump_explicit_port_map) { fprintf(fp, ".%s(", buf_output_port[0]->lib_name); } fprintf(fp, "%s_b[%d]", input_port[0]->prefix, ipin); if (TRUE == verilog_model->lut_input_inverter->spice_model->dump_explicit_port_map) { fprintf(fp, ")"); } fprintf(fp, ");\n"); } /* Free */ my_free(buf_input_port); my_free(buf_output_port); /* Internal structure of a LUT */ /* Call the LUT MUX */ fprintf(fp, " %s_mux %s_mux_0_ (", verilog_model->name, verilog_model->name); /* Connect MUX inputs to LUT configuration port */ assert(FALSE == sram_port[sram_port_index]->mode_select); if (true == is_explicit_mapping) { fprintf(fp, ".in("); } fprintf(fp, "%s_out", sram_port[sram_port_index]->prefix); if (true == is_explicit_mapping) { fprintf(fp, "), "); } else { fprintf(fp, ", "); } /* Connect MUX output to LUT output */ for (iport = 0; iport < num_output_port; iport++) { if (true == is_explicit_mapping) { fprintf(fp, ".%s(", output_port[iport]->prefix); } fprintf(fp, "%s", output_port[iport]->prefix); if (true == is_explicit_mapping) { fprintf(fp, "), "); } else { fprintf(fp, ", "); } } /* Connect MUX configuration port to LUT inputs */ if (true == is_explicit_mapping) { fprintf(fp, ".sram("); } fprintf(fp, "%s_buf", input_port[0]->prefix); /* Connect MUX inverted configuration port to inverted LUT inputs */ if (true == is_explicit_mapping) { fprintf(fp, "), .sram_inv("); } else { fprintf(fp, ", "); } fprintf(fp, "%s_b", input_port[0]->prefix); if (true == is_explicit_mapping) { fprintf(fp, ")"); } /* End of call LUT MUX */ fprintf(fp, ");\n"); /* Print timing info */ dump_verilog_submodule_timing(fp, verilog_model); /* Print signal initialization */ dump_verilog_submodule_signal_init(fp, verilog_model); /* Print end of module */ fprintf(fp, "endmodule\n"); fprintf(fp, "//-----END LUT module, verilog_model_name=%s -----\n", verilog_model->name); fprintf(fp, "\n"); /* Free */ my_free(input_port); my_free(output_port); my_free(sram_port); return; } /* Dump one module of a LUT */ static void dump_verilog_submodule_one_mem(FILE* fp, t_spice_model* verilog_model) { int iport, ipin, pin_index; int num_conf_bits; int num_sram_port = 0; t_spice_model_port** sram_port = NULL; t_spice_model* mem_model = NULL; /* Find the basis subckt*/ char* mem_subckt_name = NULL; /* Make sure we have a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",__FILE__, __LINE__); exit(1); } sram_port = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE); /* Return if there is no sram port */ if (0 == num_sram_port) { return; } /* Currently, Only support one mem_model for each SPICE MODEL */ for (iport = 0; iport < num_sram_port; iport++) { if (NULL == mem_model) { mem_model = sram_port[iport]->spice_model; continue; } if ( mem_model != sram_port[iport]->spice_model ) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s,LINE[%d]) Different memory model has been found for a spice_model %s! Currently only support unified memory model\n", __FILE__, __LINE__, verilog_model->name); exit(1); } } /* Generate subckt name */ mem_subckt_name = generate_verilog_mem_subckt_name(verilog_model, mem_model, verilog_mem_posfix); num_conf_bits = count_num_sram_bits_one_spice_model(verilog_model, -1); fprintf(fp, "//----- CMOS Mem info: spice_model_name=%s -----\n", verilog_model->name); fprintf(fp, "module %s (", mem_subckt_name); dump_verilog_mem_module_port_map(fp, mem_model, TRUE, 0, num_conf_bits, FALSE); fprintf(fp, ");\n"); /* For each SRAM port we generate mem subckt */ pin_index = 0; /* Dump all the submodules */ for (ipin = 0 ; ipin < num_conf_bits; ipin++) { fprintf(fp, "%s %s_%d_ ( ", mem_model->name, mem_model->prefix, ipin); dump_verilog_mem_module_port_map(fp, mem_model, FALSE, pin_index, 1, mem_model->dump_explicit_port_map); fprintf(fp, ");\n"); pin_index++; } /* END of this submodule */ fprintf(fp, "endmodule\n"); /* Free */ my_free(mem_subckt_name); } /* Dump verilog top-level module for LUTs */ static void dump_verilog_submodule_luts(char* verilog_dir, char* submodule_dir, int num_spice_model, t_spice_model* spice_models, boolean include_timing, boolean include_signal_init, bool is_explicit_mapping) { FILE* fp = NULL; char* verilog_name = my_strcat(submodule_dir, luts_verilog_file_name); int imodel; /* Create File Handlers */ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",__FILE__, __LINE__, luts_verilog_file_name); exit(1); } dump_verilog_file_header(fp,"Look-Up Tables"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Search for each LUT spice model */ for (imodel = 0; imodel < num_spice_model; imodel++) { /* Bypass user-defined spice models */ if (NULL != spice_models[imodel].verilog_netlist) { continue; } if (SPICE_MODEL_LUT == spice_models[imodel].type) { dump_verilog_submodule_one_lut(fp, &(spice_models[imodel]), is_explicit_mapping); } } /* Close the file handler */ fclose(fp); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); return; } static void dump_verilog_submodule_wires(char* verilog_dir, char* subckt_dir, int num_segments, t_segment_inf* segments, int num_spice_model, t_spice_model* spice_models) { FILE* fp = NULL; char* verilog_name = my_strcat(subckt_dir, wires_verilog_file_name); char* seg_wire_subckt_name = NULL; char* seg_index_str = NULL; int iseg, imodel, len_seg_subckt_name; fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",__FILE__, __LINE__, wires_verilog_file_name); exit(1); } dump_verilog_file_header(fp,"Wires"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Output wire models*/ for (imodel = 0; imodel < num_spice_model; imodel++) { /* Bypass user-defined spice models */ if (NULL != spice_models[imodel].verilog_netlist) { continue; } if (SPICE_MODEL_WIRE == spice_models[imodel].type) { assert(NULL != spice_models[imodel].wire_param); dump_verilog_wire_module(fp, spice_models[imodel].name, spice_models[imodel]); } } /* Create wire models for routing segments*/ fprintf(fp,"//----- Wire models for segments in routing -----\n"); for (iseg = 0; iseg < num_segments; iseg++) { assert(NULL != segments[iseg].spice_model); assert(SPICE_MODEL_CHAN_WIRE == segments[iseg].spice_model->type); assert(NULL != segments[iseg].spice_model->wire_param); /* Give a unique name for subckt of wire_model of segment, * spice_model name is unique, and segment name is unique as well */ seg_index_str = my_itoa(iseg); len_seg_subckt_name = strlen(segments[iseg].spice_model->name) + 4 + strlen(seg_index_str) + 1; /* '\0'*/ seg_wire_subckt_name = (char*)my_malloc(sizeof(char)*len_seg_subckt_name); sprintf(seg_wire_subckt_name,"%s_seg%s", segments[iseg].spice_model->name, seg_index_str); /* Bypass user-defined spice models */ if (NULL != segments[iseg].spice_model->verilog_netlist) { continue; } dump_verilog_wire_module(fp, seg_wire_subckt_name, *(segments[iseg].spice_model)); } /* Create module for hard-wired VDD and GND */ /* for (imodel = 0; imodel < num_spice_model; imodel++) { if (SPICE_MODEL_VDD == spice_models[imodel].type) { dump_verilog_hard_wired_vdd(fp, spice_models[imodel]); } else if (SPICE_MODEL_GND == spice_models[imodel].type) { dump_verilog_hard_wired_gnd(fp, spice_models[imodel]); } } */ /* Close the file handler */ fclose(fp); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); /*Free*/ my_free(seg_index_str); my_free(seg_wire_subckt_name); return; } static void dump_verilog_submodule_memories(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, int num_switch, t_switch_inf* switches, t_spice* spice, t_det_routing_arch* routing_arch, bool is_explicit_mapping) { /* Statisitcs for input sizes and structures of MUXes * used in FPGA architecture */ /* We have linked list whichs stores spice model information of multiplexer*/ t_llist* muxes_head = NULL; t_llist* temp = NULL; FILE* fp = NULL; char* verilog_name = my_strcat(submodule_dir, memories_verilog_file_name); int num_input_ports = 0; t_spice_model_port** input_ports = NULL; int num_sram_ports = 0; t_spice_model_port** sram_ports = NULL; int num_input_basis = 0; t_spice_mux_model* cur_spice_mux_model = NULL; int imodel; /* Alloc the muxes*/ muxes_head = stats_spice_muxes(num_switch, switches, spice, routing_arch); /* Print the muxes netlist*/ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create subckt SPICE netlist %s", __FILE__, __LINE__, verilog_name); exit(1); } /* Generate the descriptions*/ dump_verilog_file_header(fp,"Memories used in FPGA"); verilog_include_defines_preproc_file(fp, verilog_dir); /* Print mux netlist one by one*/ temp = muxes_head; while(temp) { assert(NULL != temp->dptr); cur_spice_mux_model = (t_spice_mux_model*)(temp->dptr); /* Bypass the spice models who has a user-defined subckt */ if (NULL != cur_spice_mux_model->spice_model->verilog_netlist) { input_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_INPUT, &num_input_ports, TRUE); sram_ports = find_spice_model_ports(cur_spice_mux_model->spice_model, SPICE_MODEL_PORT_SRAM, &num_sram_ports, TRUE); assert(0 != num_input_ports); assert(0 != num_sram_ports); /* Check the Input port size */ if (cur_spice_mux_model->size != input_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) size(%d) unmatch with the architecture needs(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, input_ports[0]->size,cur_spice_mux_model->size); exit(1); } /* Check the SRAM port size */ num_input_basis = determine_num_input_basis_multilevel_mux(cur_spice_mux_model->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level); if ((num_input_basis * cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level) != sram_ports[0]->size) { vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])User-defined MUX SPICE MODEL(%s) SRAM size(%d) unmatch with the num of level(%d)!\n", __FILE__, __LINE__, cur_spice_mux_model->spice_model->name, sram_ports[0]->size, cur_spice_mux_model->spice_model->design_tech_info.mux_info->mux_num_level * num_input_basis); exit(1); } /* Move on to the next*/ temp = temp->next; /* Free */ my_free(input_ports); my_free(sram_ports); continue; } /* Generate the spice_mux_arch */ cur_spice_mux_model->spice_mux_arch = (t_spice_mux_arch*)my_malloc(sizeof(t_spice_mux_arch)); init_spice_mux_arch(cur_spice_mux_model->spice_model, cur_spice_mux_model->spice_mux_arch, cur_spice_mux_model->size); /* Print the mux mem subckt */ dump_verilog_mux_mem_module(fp, cur_spice_mux_model, is_explicit_mapping); /* Update the statistics*/ /* Move on to the next*/ temp = temp->next; } /* Search all the other SPICE models and create memory module */ for (imodel = 0; imodel < spice->num_spice_model; imodel++) { /* Bypass MUX */ if (SPICE_MODEL_MUX == spice->spice_models[imodel].type) { continue; } /* We only care those with SRAM ports */ sram_ports = find_spice_model_ports(&(spice->spice_models[imodel]), SPICE_MODEL_PORT_SRAM, &num_sram_ports, TRUE); if (0 == num_sram_ports) { continue; } /* Create a memory submodule */ dump_verilog_submodule_one_mem(fp, &(spice->spice_models[imodel])); } /* Close the file*/ fclose(fp); /* Add fname to the linked list */ submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name); /* remember to free the linked list*/ free_muxes_llist(muxes_head); /* Free strings */ free(verilog_name); return; } /* Give a template for a user-defined module */ static void dump_one_verilog_template_module(FILE* fp, t_spice_model* cur_spice_model) { int iport; int cnt = 0; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } fprintf(fp, "//----- Template Verilog module for %s -----\n", cur_spice_model->name); /* dump module body */ fprintf(fp, "module %s (\n", cur_spice_model->name); /* Dump ports */ for (iport = 0; iport < cur_spice_model->num_port; iport++) { if (0 < cnt) { fprintf(fp, ",\n"); } dump_verilog_generic_port(fp, convert_spice_model_port_type_to_verilog_port_type(cur_spice_model->ports[iport].type), cur_spice_model->ports[iport].lib_name, cur_spice_model->ports[iport].size - 1, 0); cnt++; /* if there is an inv_prefix, we will dump the paired port */ if (NULL == cur_spice_model->ports[iport].inv_prefix) { continue; } if (0 < cnt) { fprintf(fp, ",\n"); } dump_verilog_generic_port(fp, convert_spice_model_port_type_to_verilog_port_type(cur_spice_model->ports[iport].type), cur_spice_model->ports[iport].inv_prefix, cur_spice_model->ports[iport].size - 1, 0); cnt++; } fprintf(fp, ");\n"); fprintf(fp, "\n//------ User-defined Verilog netlist model should start from here! -----\n"); fprintf(fp, "endmodule\n"); fprintf(fp, "\n"); return; } /* Give a template of all the submodules that are user-defined */ static void dump_verilog_submodule_templates(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, int num_spice_model, t_spice_model* spice_models) { int imodel; char* verilog_name = my_strcat(submodule_dir, user_defined_template_verilog_file_name); FILE* fp = NULL; /* Create file */ fp = fopen(verilog_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Verilog netlist %s", __FILE__, __LINE__, user_defined_template_verilog_file_name); exit(1); } dump_verilog_file_header(fp,"User-defined netlists template"); /* Output essential models*/ for (imodel = 0; imodel < num_spice_model; imodel++) { /* Focus on user-defined modules */ if (NULL == spice_models[imodel].verilog_netlist) { continue; } /* Create the port template */ dump_one_verilog_template_module(fp, &spice_models[imodel]); } /* close file */ fclose(fp); /* Free */ my_free(verilog_name); return; } /* Dump verilog files of submodules to be used in FPGA components : * 1. MUXes */ void dump_verilog_submodules(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, t_arch Arch, t_det_routing_arch* routing_arch, t_syn_verilog_opts fpga_verilog_opts) { /* 0. basic units: inverter, buffers and pass-gate logics, */ vpr_printf(TIO_MESSAGE_INFO, "Generating essential modules...\n"); dump_verilog_submodule_essentials(verilog_dir, submodule_dir, Arch.spice->num_spice_model, Arch.spice->spice_models); /* 1. MUXes */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n"); dump_verilog_submodule_muxes(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch, switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog); vpr_printf(TIO_MESSAGE_INFO, "Generating local encoders for multiplexers...\n"); dump_verilog_submodule_local_encoders(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch, switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog); /* 2. LUTes */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of LUTs...\n"); dump_verilog_submodule_luts(verilog_dir, submodule_dir, Arch.spice->num_spice_model, Arch.spice->spice_models, fpga_verilog_opts.include_timing, fpga_verilog_opts.include_signal_init, fpga_verilog_opts.dump_explicit_verilog); /* 3. Hardwires */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n"); dump_verilog_submodule_wires(verilog_dir, submodule_dir, Arch.num_segments, Arch.Segments, Arch.spice->num_spice_model, Arch.spice->spice_models); /* 4. Memories */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of memories...\n"); dump_verilog_submodule_memories(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch, switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog); /* 5. Dump decoder modules only when memory bank is required */ dump_verilog_config_peripherals(cur_sram_orgz_info, verilog_dir, submodule_dir); /* 6. Dump template for all the modules */ if (TRUE == fpga_verilog_opts.print_user_defined_template) { dump_verilog_submodule_templates(cur_sram_orgz_info, verilog_dir, submodule_dir, Arch.spice->num_spice_model, Arch.spice->spice_models); } /* Create a header file to include all the subckts */ vpr_printf(TIO_MESSAGE_INFO,"Generating header file for basic submodules...\n"); dump_verilog_subckt_header_file(submodule_verilog_subckt_file_path_head, submodule_dir, submodule_verilog_file_name); return; }