OpenFPGA/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c

4112 lines
158 KiB
C

/***********************************/
/* Synthesizable Verilog Dumping */
/* Xifan TANG, EPFL/LSI */
/***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include <algorithm>
/* 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_mux.h"
#include "verilog_essential_gates.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: <given_name> <input0> <input1> <output> <sram> <sram_inv> svdd sgnd <subckt_name> */
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: <given_name> <input0> <output> svdd sgnd <subckt_name> 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: <given_name> <input0> <input1> <output> <sram> <sram_inv> svdd sgnd <subckt_name> */
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 <mux_spice_model_name>_<structure>_size<input_size>
* 2. LUTs, the naming rule is <lut_spice_model_name>_mux_size<sram_port_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: <given_name> <input0> <output> svdd sgnd <subckt_name> 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<given_name> <input> <output> 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: <given_name> <input0> <output> svdd sgnd <subckt_name> 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<given_name> <input> <output> 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: <given_name> <input0> <input1> <output> <sram> <sram_inv> svdd sgnd <subckt_name> */
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: <given_name> <input0> <input1> <output> <sram> <sram_inv> svdd sgnd <subckt_name> */
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: <given_name> <input0> <output> svdd sgnd <subckt_name> 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<given_name> <input> <output> 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: <given_name> <input0> <output> svdd sgnd <subckt_name> 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<given_name> <input> <output> 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 <mux_spice_model_name>_<structure>_size<input_size>
* 2. LUTs, the naming rule is <lut_spice_model_name>_mux_size<sram_port_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<MuxGraph> 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,
mux_graph.num_inputs(), 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<int> 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<int>::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");
/* To be removed when testing passed
dump_verilog_submodule_essentials(verilog_dir, submodule_dir,
Arch.spice->num_spice_model,
Arch.spice->spice_models);
*/
print_verilog_submodule_essentials(std::string(verilog_dir),
std::string(submodule_dir),
Arch.spice->circuit_lib);
/* 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;
}