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

2265 lines
88 KiB
C
Raw Normal View History

2018-07-26 12:28:21 -05:00
/***********************************/
/* 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 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_spice_utils.h"
#include "spice_mux.h"
#include "fpga_spice_globals.h"
/* Include verilog utils */
#include "verilog_global.h"
#include "verilog_utils.h"
#include "verilog_pbtypes.h"
/***** Subroutines *****/
/* Dump a module of inverter or buffer or tapered buffer */
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_global_ports(fp, invbuf_spice_model, TRUE, FALSE)) {
fprintf(fp, ",\n");
}
/* Dump ports */
fprintf(fp, "input %s,\n", input_port[0]->prefix);
fprintf(fp, "output %s\n", output_port[0]->prefix);
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]->prefix);
fprintf(fp, "always @(");
/* Power-gate port first*/
for (iport = 0; iport < num_powergate_port; iport++) {
fprintf(fp, "%s,", powergate_port[iport]->prefix);
}
fprintf(fp, "%s) begin\n",
input_port[0]->prefix);
/* 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]->prefix,
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]->prefix,
ipin);
port_cnt++; /* Update port counter*/
}
}
}
fprintf(fp, ") begin\n");
fprintf(fp, "\t\tassign %s_reg = ~%s;\n",
output_port[0]->prefix,
input_port[0]->prefix);
fprintf(fp, "\tend else begin\n");
fprintf(fp, "\t\tassign %s_reg = 1'bz;\n",
output_port[0]->prefix);
fprintf(fp, "\tend\n");
fprintf(fp, "end\n");
fprintf(fp, "assign %s = %s_reg;\n",
output_port[0]->prefix,
output_port[0]->prefix);
} else {
fprintf(fp, "assign %s = ~%s;\n",
output_port[0]->prefix,
input_port[0]->prefix);
}
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]->prefix);
fprintf(fp, "always @(");
/* Power-gate port first*/
for (iport = 0; iport < num_powergate_port; iport++) {
fprintf(fp, "%s,", powergate_port[iport]->prefix);
}
fprintf(fp, "%s) begin\n",
input_port[0]->prefix);
/* 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]->prefix,
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]->prefix,
ipin);
port_cnt++; /* Update port counter*/
}
}
}
fprintf(fp, ") begin\n");
fprintf(fp, "\t\tassign %s_reg = %s;\n",
output_port[0]->prefix,
input_port[0]->prefix);
fprintf(fp, "\tend else begin\n");
fprintf(fp, "\t\tassign %s_reg = 1'bz;\n",
output_port[0]->prefix);
fprintf(fp, "\tend\n");
fprintf(fp, "end\n");
fprintf(fp, "assign %s = %s_reg;\n",
output_port[0]->prefix,
output_port[0]->prefix);
2018-09-21 20:00:22 -05:00
} else if (FALSE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf) {
2018-07-26 12:28:21 -05:00
fprintf(fp, "assign %s = %s;\n",
output_port[0]->prefix,
input_port[0]->prefix);
2018-09-21 20:00:22 -05:00
} else {
assert (TRUE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf);
fprintf(fp, "assign %s = ",
output_port[0]->prefix);
/* 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]->prefix);
2018-07-26 12:28:21 -05:00
}
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);
}
fprintf(fp, "endmodule\n");
fprintf(fp, "\n");
/* Free */
my_free(input_port);
my_free(output_port);
return;
}
/* Dump a module of pass-gate logic */
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);
/* 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 in,\n");
fprintf(fp, "input sel,\n");
fprintf(fp, "input selb,\n");
fprintf(fp, "output %s\n", output_port[0]->prefix);
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 in,\n");
fprintf(fp, "input sel,\n");
fprintf(fp, "output %s\n", output_port[0]->prefix);
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 = sel? in : 1'bz;\n",
output_port[0]->prefix);
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 */
void dump_verilog_submodule_essentials(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");
/* 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]));
}
}
/* Close file handler*/
fclose(fp);
/* Free */
return;
}
/* Dump a CMOS MUX basis module */
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)) {
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) {
2018-09-04 18:31:30 -05:00
int i;
2018-07-26 12:28:21 -05:00
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;
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);
}
/* 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)) {
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, "//---- 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 (in[0], mem[0], mem_inv[0], out);\n",
tgate_module_name, tgate_module_name);
fprintf(fp, " %s %s_1 (in[1], mem_inv[0], mem[0], out);\n",
tgate_module_name, tgate_module_name);
} 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 (in[%d], mem[%d], mem_inv[%d], out);\n",
tgate_module_name, tgate_module_name, i,
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;
2018-09-04 18:31:30 -05:00
int i;
2018-07-26 12:28:21 -05:00
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)) {
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 (in[%d], wl[%d], bl[%d], out);\n",
progTE_module_name, progTE_module_name, i,
i, i, i);
}
/* RIGHT part */
fprintf(fp, "%s %s_%d (out, wl[%d], 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 */
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)) {
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 */
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
*/
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);
/* Corner case: Error out MUX_SIZE = 2, automatcially give a one-level structure */
2018-09-17 12:25:54 -05:00
/*
2018-07-26 12:28:21 -05:00
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);
}
2018-09-17 12:25:54 -05:00
*/
2018-07-26 12:28:21 -05:00
/* Prepare the basis subckt name:
*/
mux_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_mux_model->spice_model->name) + 5
+ strlen(my_itoa(spice_mux_model->size)) + strlen(verilog_mux_basis_posfix) + 1));
sprintf(mux_basis_subckt_name, "%s_size%d%s",
spice_mux_model->spice_model->name, spice_mux_model->size, verilog_mux_basis_posfix);
special_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_mux_model->spice_model->name) + 5
+ strlen(my_itoa(spice_mux_model->size)) + strlen(verilog_mux_special_basis_posfix) + 1));
sprintf(special_basis_subckt_name, "%s_size%d%s",
spice_mux_model->spice_model->name, 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.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;
}
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) {
int i, j, level, nextlevel;
int nextj, out_idx;
int mux_basis_cnt = 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;
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);
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 */
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, 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], %s_inv[%d]);\n", sram_port[0]->prefix, i, sram_port[0]->prefix, i); /* 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);
return;
}
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) {
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);
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);
/* 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)) {
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 */
fprintf(fp, "%s[%d:%d], %s_inv[%d:%d] ",
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);
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)) {
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, sram_idx, sram_idx + cur_num_input_basis -1,
sram_port[0]->prefix, sram_idx, sram_idx + cur_num_input_basis -1);
fprintf(fp, ");\n");
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;
}
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) {
/* 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 */
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "//----- MUX inputs -----\n");
fprintf(fp, "mux2_l%d_in[0:%d], ", 1, spice_mux_arch.num_input - 1); /* input0 */
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* output */
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) {
fprintf(fp, "%s[0:%d], %s_inv[0:%d] ",
sram_port[0]->prefix, 0,
sram_port[0]->prefix, 0); /* sram sram_inv */
} else {
fprintf(fp, "%s[0:%d], %s_inv[0:%d] ",
sram_port[0]->prefix, spice_mux_arch.num_input - 1,
sram_port[0]->prefix, spice_mux_arch.num_input - 1); /* sram sram_inv */
}
fprintf(fp, "\n");
fprintf(fp, ");\n");
return;
}
void dump_verilog_cmos_mux_submodule(FILE* fp,
int mux_size,
t_spice_model spice_model,
t_spice_mux_arch spice_mux_arch) {
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;
/* Find the basis subckt*/
char* mux_basis_subckt_name = NULL;
char* mux_special_basis_subckt_name = NULL;
mux_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model.name) + 5
+ strlen(my_itoa(mux_size)) + strlen(verilog_mux_basis_posfix) + 1));
sprintf(mux_basis_subckt_name, "%s_size%d%s",
spice_model.name, mux_size, verilog_mux_basis_posfix);
mux_special_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model.name) + 5
+ strlen(my_itoa(spice_mux_arch.num_input))
+ strlen(verilog_mux_special_basis_posfix) + 1));
sprintf(mux_special_basis_subckt_name, "%s_size%d%s",
spice_model.name, spice_mux_arch.num_input, 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*/
assert(1 == num_input_port);
assert(1 == num_output_port);
assert(1 == num_sram_port);
assert(1 == output_port[0]->size);
/* 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,
/* sram_verilog_orgz_info->type, */
mux_size);
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)) {
fprintf(fp, ",\n");
}
/* Print input ports*/
assert(mux_size == num_conf_bits);
fprintf(fp, "input wire [0:%d] %s,\n", num_conf_bits - 1, input_port[0]->prefix);
/* Print output ports*/
fprintf(fp, "output wire %s,\n", output_port[0]->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.structure));
fprintf(fp, "module %s_size%d (", spice_model.name, 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 %s,\n", 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");
/* Print internal architecture*/
switch (spice_model.design_tech_info.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);
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);
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);
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) {
switch (spice_model.input_buffer->type) {
case SPICE_MODEL_BUF_INV:
/* Each inv: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s inv%d (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "%s[%d], ", input_port[0]->prefix, i); /* input port */
fprintf(fp, "mux2_l%d_in[%d]); ", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/
fprintf(fp, "\n");
break;
case SPICE_MODEL_BUF_BUF:
/* TODO: what about tapered buffer, can we support? */
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf%d (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "%s[%d], ", input_port[0]->prefix, i); /* input port */
fprintf(fp, "mux2_l%d_in[%d]); ", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/
fprintf(fp, "\n");
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n",
__FILE__, __LINE__);
exit(1);
}
} 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]);
}
}
/* Output buffer*/
if (1 == spice_model.output_buffer->exist) {
switch (spice_model.output_buffer->type) {
case SPICE_MODEL_BUF_INV:
if (TRUE == spice_model.output_buffer->tapered_buf) {
break;
}
/* Each inv: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s inv_out (",
spice_model.output_buffer->spice_model_name); /* Given name*/
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
break;
case SPICE_MODEL_BUF_BUF:
if (TRUE == spice_model.output_buffer->tapered_buf) {
break;
}
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf_out (",
spice_model.output_buffer->spice_model_name); /* Given name*/
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n",
__FILE__, __LINE__);
exit(1);
}
/* Tapered buffer support */
if (TRUE == spice_model.output_buffer->tapered_buf) {
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf_out (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
}
} 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 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.
*/
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)) {
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;
}
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, sram_idx;
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;
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);
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)) {
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)) {
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;
}
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)) {
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,
/* sram_verilog_orgz_info->type,*/
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;
}
void dump_verilog_rram_mux_submodule(FILE* fp,
int mux_size,
t_spice_model spice_model,
t_spice_mux_arch spice_mux_arch) {
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;
/* Find the basis subckt*/
char* mux_basis_subckt_name = NULL;
char* mux_special_basis_subckt_name = NULL;
mux_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model.name) + 5
+ strlen(my_itoa(mux_size)) + strlen(verilog_mux_basis_posfix) + 1));
sprintf(mux_basis_subckt_name, "%s_size%d%s",
spice_model.name, mux_size, verilog_mux_basis_posfix);
mux_special_basis_subckt_name = (char*)my_malloc(sizeof(char)*(strlen(spice_model.name) + 5
+ strlen(my_itoa(spice_mux_arch.num_input))
+ strlen(verilog_mux_special_basis_posfix) + 1));
sprintf(mux_special_basis_subckt_name, "%s_size%d%s",
spice_model.name, spice_mux_arch.num_input, 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.structure));
fprintf(fp, "module %s_size%d( \n", spice_model.name, mux_size);
}
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, &spice_model, TRUE, 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,
/* sram_verilog_orgz_info->type,*/
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.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) {
switch (spice_model.input_buffer->type) {
case SPICE_MODEL_BUF_INV:
/* Each inv: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s inv%d (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "%s[%d], ", input_port[0]->prefix, i); /* input port */
fprintf(fp, "mux2_l%d_in[%d]);", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/
fprintf(fp, "\n");
break;
case SPICE_MODEL_BUF_BUF:
/* TODO: what about tapered buffer, can we support? */
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf%d (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "%s[%d], ", input_port[0]->prefix, i); /* input port */
fprintf(fp, "mux2_l%d_in[%d)];", spice_mux_arch.input_level[i], spice_mux_arch.input_offset[i]); /* output port*/
fprintf(fp, "\n");
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n",
__FILE__, __LINE__);
exit(1);
}
} 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]);
}
}
/* Output buffer*/
if (1 == spice_model.output_buffer->exist) {
switch (spice_model.output_buffer->type) {
case SPICE_MODEL_BUF_INV:
if (TRUE == spice_model.output_buffer->tapered_buf) {
break;
}
/* Each inv: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s inv_out (",
spice_model.output_buffer->spice_model_name); /* Given name*/
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
break;
case SPICE_MODEL_BUF_BUF:
if (TRUE == spice_model.output_buffer->tapered_buf) {
break;
}
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf_out (",
spice_model.output_buffer->spice_model_name); /* Given name*/
/* Dump global ports */
if (0 < rec_dump_verilog_spice_model_global_ports(fp, spice_model.output_buffer->spice_model, FALSE, FALSE)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0, 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n",
__FILE__, __LINE__);
exit(1);
}
/* Tapered buffer support */
if (TRUE == spice_model.output_buffer->tapered_buf) {
/* Each buf: <given_name> <input0> <output> svdd sgnd <subckt_name> size=param*/
fprintf(fp, "%s buf_out (",
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)) {
fprintf(fp, ",\n");
}
fprintf(fp, "mux2_l%d_in[%d], ", 0 , 0); /* input port */
fprintf(fp, "%s );", output_port[0]->prefix); /* Output port*/
fprintf(fp, "\n");
}
} 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 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
*/
void dump_verilog_mux_module(FILE* fp,
t_spice_mux_model* spice_mux_model) {
/* 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 */
2018-09-17 12:25:54 -05:00
/*
2018-07-26 12:28:21 -05:00
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);
}
2018-09-17 12:25:54 -05:00
*/
2018-07-26 12:28:21 -05:00
/* 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));
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));
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 */
/**/
void dump_verilog_submodule_muxes(char* submodule_dir,
int num_switch,
t_switch_inf* switches,
t_spice* spice,
t_det_routing_arch* routing_arch) {
/* 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");
/* 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_num_level);
if ((num_input_basis * cur_spice_mux_model->spice_model->design_tech_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_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);
/* 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;
}
/* 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(sram_verilog_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);
/* remember to free the linked list*/
free_muxes_llist(muxes_head);
/* Free strings */
free(verilog_name);
/* Close the file*/
fclose(fp);
return;
}
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)) {
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)) {
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 */
void dump_verilog_submodule_one_lut(FILE* fp,
t_spice_model* verilog_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;
/* 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)) {
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*/
assert(1 == num_input_port);
assert(1 == num_output_port);
assert(1 == num_sram_port);
assert(1 == output_port[0]->size);
/* input port */
fprintf(fp, "input wire [0:%d] %s,\n",
input_port[0]->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_out,\n",
sram_port[0]->size - 1, sram_port[0]->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[0]->size - 1, sram_port[0]->prefix);
/* End of port list */
fprintf(fp, ");\n");
/* Create inverted input port */
fprintf(fp, " wire [0:%d] %s_b;\n",
input_port[0]->size - 1, input_port[0]->prefix);
/* Create inverters between input port and its inversion */
fprintf(fp, " assign %s_b = ~ %s;\n",
input_port[0]->prefix, input_port[0]->prefix);
/* 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 */
fprintf(fp, " %s_out,",
sram_port[0]->prefix);
/* Connect MUX output to LUT output */
fprintf(fp, " %s,",
output_port[0]->prefix);
/* Connect MUX configuration port to LUT inputs */
fprintf(fp, " %s,",
input_port[0]->prefix);
/* Connect MUX inverted configuration port to inverted LUT inputs */
fprintf(fp, " %s_b",
input_port[0]->prefix);
/* End of call LUT MUX */
fprintf(fp, ");\n");
/* Print end of module */
fprintf(fp, "endmodule\n");
fprintf(fp, "//-----END LUT module, verilog_model_name=%s -----\n", verilog_model->name);
fprintf(fp, "\n");
return;
}
/* Dump verilog top-level module for LUTs */
void dump_verilog_submodule_luts(char* submodule_dir,
int num_spice_model,
t_spice_model* spice_models) {
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");
/* 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]));
}
}
/* Close the file handler */
fclose(fp);
return;
}
/* Dump a submodule which is a constant vdd */
void dump_verilog_hard_wired_vdd(FILE* fp,
t_spice_model verilog_model) {
int num_output_port = 0;
t_spice_model_port** output_port = NULL;
/* Find the input port, output port*/
output_port = find_spice_model_ports(&verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
/* Asserts*/
assert(1 == num_output_port);
assert(1 == output_port[0]->size);
/* 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);
}
/* print the spice model*/
fprintf(fp, "//-----Hard-wired VDD module, verilog_model_name=%s -----\n", verilog_model.name);
fprintf(fp, "module %s(output wire %s);\n", verilog_model.name, output_port[0]->prefix);
/* Constant logic 1*/
fprintf(fp, "assign %s = 1\'b1;\n", output_port[0]->prefix);
/* Finish*/
fprintf(fp, "endmodule\n");
fprintf(fp, "//-----END VDD module, verilog_model_name=%s -----\n", verilog_model.name);
fprintf(fp, "\n");
return;
}
/* Dump a submodule which is a constant vdd */
void dump_verilog_hard_wired_gnd(FILE* fp,
t_spice_model verilog_model) {
int num_output_port = 0;
t_spice_model_port** output_port = NULL;
/* Find the input port, output port*/
output_port = find_spice_model_ports(&verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
/* Asserts*/
assert(1 == num_output_port);
assert(1 == output_port[0]->size);
/* 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);
}
/* print the spice model*/
fprintf(fp, "//-----Hard-wired GND module, verilog_model_name=%s -----\n", verilog_model.name);
fprintf(fp, "module %s(output wire %s);\n", verilog_model.name, output_port[0]->prefix);
/* Constant logic 1*/
fprintf(fp, "assign %s = 1\'b0;\n", output_port[0]->prefix);
/* Finish*/
fprintf(fp, "endmodule\n");
fprintf(fp, "//-----END GND module, verilog_model_name=%s -----\n", verilog_model.name);
fprintf(fp, "\n");
return;
}
void dump_verilog_submodule_wires(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");
/* 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);
/*Free*/
my_free(seg_index_str);
my_free(seg_wire_subckt_name);
return;
}
/* Dump verilog files of submodules to be used in FPGA components :
* 1. MUXes
*/
void dump_verilog_submodules(char* submodule_dir,
t_arch Arch,
t_det_routing_arch* routing_arch) {
/* 0. basic units: inverter, buffers and pass-gate logics, */
vpr_printf(TIO_MESSAGE_INFO, "Generating essential modules...\n");
dump_verilog_submodule_essentials(submodule_dir,
Arch.spice->num_spice_model,
Arch.spice->spice_models);
/* 1. MUXes */
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n");
dump_verilog_submodule_muxes(submodule_dir, routing_arch->num_switch,
switch_inf, Arch.spice, routing_arch);
/* 2. LUTes */
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of LUTs...\n");
dump_verilog_submodule_luts(submodule_dir,
Arch.spice->num_spice_model, Arch.spice->spice_models);
/* 3. Hardwires */
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");
dump_verilog_submodule_wires(submodule_dir, Arch.num_segments, Arch.Segments,
Arch.spice->num_spice_model, Arch.spice->spice_models);
return;
}