Add timing and initialization for simulation
This commit is contained in:
parent
0f87fb9c3f
commit
8ac566ecc0
|
@ -7,6 +7,11 @@ enum e_spice_tech_lib_type {
|
|||
SPICE_LIB_INDUSTRY,SPICE_LIB_ACADEMIA
|
||||
};
|
||||
|
||||
enum spice_model_delay_type {
|
||||
SPICE_MODEL_DELAY_RISE,
|
||||
SPICE_MODEL_DELAY_FALL
|
||||
};
|
||||
|
||||
/*Struct for a SPICE model of a module*/
|
||||
enum e_spice_model_type {
|
||||
SPICE_MODEL_CHAN_WIRE,
|
||||
|
@ -93,8 +98,10 @@ typedef struct s_spice_model t_spice_model;
|
|||
typedef struct s_spice_meas_params t_spice_meas_params;
|
||||
typedef struct s_spice_stimulate_params t_spice_stimulate_params;
|
||||
typedef struct s_spice_mc_variation_params t_spice_mc_variation_params;
|
||||
typedef struct s_spice_model_delay_info t_spice_model_delay_info;
|
||||
typedef struct s_spice_mc_params t_spice_mc_params;
|
||||
typedef struct s_spice_params t_spice_params;
|
||||
typedef struct s_spice_model_tedge t_spice_model_tedge;
|
||||
typedef struct s_spice t_spice;
|
||||
typedef struct s_spice_mux_arch t_spice_mux_arch;
|
||||
typedef struct s_spice_mux_model t_spice_mux_model;
|
||||
|
@ -145,6 +152,16 @@ struct s_spice_model_pass_gate_logic {
|
|||
t_spice_model* spice_model;
|
||||
};
|
||||
|
||||
/* Model the pin-to-pin timing edge */
|
||||
struct s_spice_model_tedge {
|
||||
float trise; /* Rise condition: delay */
|
||||
float tfall; /* Fall condition: delay */
|
||||
t_spice_model_port* from_port;
|
||||
int from_port_pin_number;
|
||||
t_spice_model_port* to_port;
|
||||
int to_port_pin_number;
|
||||
};
|
||||
|
||||
struct s_spice_model_port {
|
||||
enum e_spice_model_port_type type;
|
||||
int size;
|
||||
|
@ -160,6 +177,9 @@ struct s_spice_model_port {
|
|||
t_spice_model* spice_model;
|
||||
char* inv_spice_model_name;
|
||||
t_spice_model* inv_spice_model;
|
||||
/* Timing edeges linked to other t_model_ports */
|
||||
int* num_tedges; /* 1-D Array, show number of tedges of each pin */
|
||||
t_spice_model_tedge*** tedge; /* 3-D array, considering the each pin in this port, [pin_number][num_edges[iedge]] is an edge pointor */
|
||||
};
|
||||
|
||||
struct s_spice_model_wire_param {
|
||||
|
@ -174,6 +194,13 @@ struct s_spice_model_netlist {
|
|||
int included;
|
||||
};
|
||||
|
||||
struct s_spice_model_delay_info {
|
||||
enum spice_model_delay_type type;
|
||||
char* in_port_name;
|
||||
char* out_port_name;
|
||||
char* value;
|
||||
};
|
||||
|
||||
/* Information about design technology */
|
||||
struct s_spice_model_design_tech_info {
|
||||
/* Valid for SRAM technology */
|
||||
|
@ -219,6 +246,10 @@ struct s_spice_model {
|
|||
int num_port;
|
||||
t_spice_model_port* ports;
|
||||
|
||||
/* Delay matrix */
|
||||
int num_delay_info;
|
||||
t_spice_model_delay_info* delay_info;
|
||||
|
||||
/* Wire Model*/
|
||||
t_spice_model_wire_param* wire_param;
|
||||
|
||||
|
|
|
@ -599,6 +599,37 @@ static void ProcessSpiceModelPort(ezxml_t Node,
|
|||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void ProcessSpiceModelDelayInfo(ezxml_t Node,
|
||||
t_spice_model_delay_info* cur_delay_info) {
|
||||
char* delay_str = NULL;
|
||||
|
||||
/* Find the type */
|
||||
if (0 == strcmp(FindProperty(Node, "type", TRUE), "rise")) {
|
||||
cur_delay_info->type = SPICE_MODEL_DELAY_RISE;
|
||||
} else if (0 == strcmp(FindProperty(Node, "type", TRUE), "fall")) {
|
||||
cur_delay_info->type = SPICE_MODEL_DELAY_FALL;
|
||||
} else {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid type of delay_info. Should be [rise|fall].\n",
|
||||
Node->line);
|
||||
exit(1);
|
||||
}
|
||||
ezxml_set_attr(Node, "type", NULL);
|
||||
|
||||
/* Find the input and output ports */
|
||||
cur_delay_info->in_port_name = my_strdup(FindProperty(Node, "in_port", TRUE));
|
||||
ezxml_set_attr(Node, "in_port", NULL);
|
||||
|
||||
cur_delay_info->out_port_name = my_strdup(FindProperty(Node, "out_port", TRUE));
|
||||
ezxml_set_attr(Node, "out_port", NULL);
|
||||
|
||||
/* Find delay matrix */
|
||||
cur_delay_info->value = my_strdup(Node->txt);
|
||||
ezxml_set_txt(Node, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void ProcessSpiceModelWireParam(ezxml_t Parent,
|
||||
t_spice_model_wire_param* wire_param) {
|
||||
if (0 == strcmp("pie",FindProperty(Parent,"model_type",TRUE))) {
|
||||
|
@ -627,7 +658,7 @@ static void ProcessSpiceModelWireParam(ezxml_t Parent,
|
|||
static void ProcessSpiceModel(ezxml_t Parent,
|
||||
t_spice_model* spice_model) {
|
||||
ezxml_t Node, Cur;
|
||||
int iport;
|
||||
int iport, i;
|
||||
|
||||
/* Basic Information*/
|
||||
if (0 == strcmp(FindProperty(Parent,"type",TRUE),"mux")) {
|
||||
|
@ -866,6 +897,17 @@ static void ProcessSpiceModel(ezxml_t Parent,
|
|||
FreeNode(Node);
|
||||
}
|
||||
|
||||
/* Find delay info */
|
||||
spice_model->num_delay_info = CountChildren(Parent, "delay_matrix", 0);
|
||||
/*Alloc*/
|
||||
spice_model->delay_info = (t_spice_model_delay_info*) my_malloc(spice_model->num_delay_info * sizeof(t_spice_model_delay_info));
|
||||
/* Assign each found spice model*/
|
||||
for (i = 0; i < spice_model->num_delay_info; i++) {
|
||||
Cur = FindFirstElement(Parent, "delay_matrix", TRUE);
|
||||
ProcessSpiceModelDelayInfo(Cur, &(spice_model->delay_info[i]));
|
||||
FreeNode(Cur);
|
||||
}
|
||||
|
||||
/* Initialize the counter*/
|
||||
spice_model->cnt = 0;
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ struct s_TokenPair OptionBaseTokenList[] = {
|
|||
{ "fpga_spice_leakage_only", OT_FPGA_SPICE_LEAKAGE_ONLY }, /* Only simulate leakage power in FPGA SPICE */
|
||||
{ "fpga_spice_parasitic_net_estimation_off", OT_FPGA_SPICE_PARASITIC_NET_ESTIMATION_OFF }, /* Xifan TANG: turn off the parasitic net estimation*/
|
||||
{ "fpga_spice_testbench_load_extraction_off", OT_FPGA_SPICE_TESTBENCH_LOAD_EXTRACTION_OFF }, /* Xifan TANG: turn off the parasitic net estimation*/
|
||||
{ "fpga_verilog_include_timing", OT_FPGA_VERILOG_SYN_INCLUDE_TIMING }, /* Include timing constraints in Verilog netlists */
|
||||
{ "fpga_verilog_init_sim", OT_FPGA_VERILOG_INIT_SIM }, /* Allow simulation initialization */
|
||||
/* Xifan TANG: Synthsizable Verilog */
|
||||
{ "fpga_verilog", OT_FPGA_VERILOG_SYN },
|
||||
{ "fpga_verilog_dir", OT_FPGA_VERILOG_SYN_DIR },
|
||||
|
|
|
@ -99,6 +99,8 @@ enum e_OptionBaseToken {
|
|||
OT_FPGA_VERILOG_SYN_PRINT_TOP_TB, /* Xifan TANG: Synthesizable Verilog Dump */
|
||||
OT_FPGA_VERILOG_SYN_PRINT_INPUT_BLIF_TB, /* Xifan TANG: Synthesizable Verilog Dump */
|
||||
OT_FPGA_VERILOG_SYN_TB_SERIAL_CONFIG_MODE, /* Xifan TANG: Synthesizable Verilog Dump */
|
||||
OT_FPGA_VERILOG_SYN_INCLUDE_TIMING, /* Include timing constraint in Verilog*/
|
||||
OT_FPGA_VERILOG_INIT_SIM, /* AA: to allow initialization in simulation */
|
||||
/* mrFPGA: Xifan TANG */
|
||||
OT_SHOW_SRAM,
|
||||
OT_SHOW_PASS_TRANS,
|
||||
|
|
|
@ -516,6 +516,10 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) {
|
|||
return Args;
|
||||
case OT_FPGA_SPICE_RENAME_ILLEGAL_PORT:
|
||||
return Args;
|
||||
case OT_FPGA_VERILOG_SYN_INCLUDE_TIMING:
|
||||
return Args;
|
||||
case OT_FPGA_VERILOG_INIT_SIM:
|
||||
return Args;
|
||||
case OT_FPGA_SPICE_SIGNAL_DENSITY_WEIGHT:
|
||||
return ReadFloat(Args, &Options->signal_density_weight);
|
||||
case OT_FPGA_SPICE_SIM_WINDOW_SIZE:
|
||||
|
|
|
@ -1059,6 +1059,8 @@ static void SetupSynVerilogOpts(t_options Options,
|
|||
syn_verilog_opts->tb_serial_config_mode = FALSE;
|
||||
syn_verilog_opts->print_top_tb = FALSE;
|
||||
syn_verilog_opts->print_input_blif_tb = FALSE;
|
||||
syn_verilog_opts->include_timing = FALSE;
|
||||
syn_verilog_opts->init_sim = FALSE;
|
||||
|
||||
/* Turn on Syn_verilog options */
|
||||
if (Options.Count[OT_FPGA_VERILOG_SYN]) {
|
||||
|
@ -1083,6 +1085,14 @@ static void SetupSynVerilogOpts(t_options Options,
|
|||
syn_verilog_opts->print_input_blif_tb = TRUE;
|
||||
}
|
||||
|
||||
if (Options.Count[OT_FPGA_VERILOG_SYN_INCLUDE_TIMING]) {
|
||||
syn_verilog_opts->include_timing = TRUE;
|
||||
}
|
||||
|
||||
if (Options.Count[OT_FPGA_VERILOG_INIT_SIM]) {
|
||||
syn_verilog_opts->init_sim = TRUE;
|
||||
}
|
||||
|
||||
/* SynVerilog needs the input from spice modeling */
|
||||
if (FALSE == arch->read_xml_spice) {
|
||||
arch->read_xml_spice = syn_verilog_opts->dump_syn_verilog;
|
||||
|
|
|
@ -189,6 +189,8 @@ void vpr_print_usage(void) {
|
|||
vpr_printf(TIO_MESSAGE_INFO, "Synthesizable Verilog Generator Options:\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_dir <directory_path_of_dumped_verilog_files>\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_include_timing\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_init_sim\n");
|
||||
}
|
||||
|
||||
/* Initialize VPR
|
||||
|
|
|
@ -1209,6 +1209,8 @@ struct s_syn_verilog_opts {
|
|||
boolean print_top_tb;
|
||||
boolean print_input_blif_tb;
|
||||
boolean tb_serial_config_mode;
|
||||
boolean include_timing;
|
||||
boolean init_sim;
|
||||
};
|
||||
|
||||
typedef struct s_fpga_spice_opts t_fpga_spice_opts;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "linkedlist.h"
|
||||
#include "fpga_spice_globals.h"
|
||||
#include "fpga_spice_utils.h"
|
||||
#include "fpga_spice_timing_utils.h"
|
||||
#include "fpga_spice_backannotate_utils.h"
|
||||
#include "verilog_api.h"
|
||||
#include "fpga_spice_setup.h"
|
||||
|
@ -573,6 +574,15 @@ void init_check_arch_spice_models(t_arch* arch,
|
|||
}
|
||||
}
|
||||
|
||||
/* 7. Create timing graph for spice models */
|
||||
for (i = 0; i < arch->spice->num_spice_model; i++) {
|
||||
/* See if we need a timing graph */
|
||||
if (0 == arch->spice->spice_models[i].num_delay_info) {
|
||||
continue;
|
||||
}
|
||||
annotate_spice_model_timing(&(arch->spice->spice_models[i]));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
|
||||
/***********************************/
|
||||
/* SPICE Modeling for VPR */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph_util.h"
|
||||
#include "rr_graph.h"
|
||||
#include "rr_graph2.h"
|
||||
#include "vpr_utils.h"
|
||||
#include "token.h"
|
||||
|
||||
/* Include SPICE support headers*/
|
||||
#include "quicksort.h"
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_spice_globals.h"
|
||||
#include "fpga_spice_utils.h"
|
||||
|
||||
/* Build the list of spice_model_ports provided in the cur_spice_model delay_info */
|
||||
t_spice_model_port** get_spice_model_delay_info_ports(t_spice_model* cur_spice_model,
|
||||
char* port_list,
|
||||
int* num_port) {
|
||||
int itok;
|
||||
int num_token = 0;
|
||||
char** tokens = NULL;
|
||||
t_spice_model_port** port = NULL;
|
||||
|
||||
/* Get input ports */
|
||||
tokens = my_strtok(port_list, " ", &num_token);
|
||||
/* allocate in_port */
|
||||
port = (t_spice_model_port**) my_malloc(sizeof(t_spice_model_port*) * num_token);
|
||||
/* Find corresponding spice_model_port */
|
||||
for (itok = 0; itok < num_token; itok++) {
|
||||
port[itok] = find_spice_model_port_by_name(cur_spice_model, tokens[itok]);
|
||||
/* Error out if we cannot find a port */
|
||||
if (NULL == port[itok]) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Fail to find a port listed in delay_info (port_name=%s)!\n",
|
||||
__FILE__, __LINE__, tokens[itok]);
|
||||
exit(1);
|
||||
}
|
||||
/* TODO: Error out if port type does not match */
|
||||
}
|
||||
|
||||
/* give return value */
|
||||
(*num_port) = num_token;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
/* Determine the number of tedges (timing edges) for each output pin of a SPICE model
|
||||
* For each output pin, we need a tedge connected to all the input pins
|
||||
* The number of tedges per pin is the number of input pins
|
||||
*/
|
||||
int get_spice_model_num_tedges_per_pin(t_spice_model* cur_spice_model,
|
||||
enum PORTS port_type) {
|
||||
int iport;
|
||||
int num_tedges = 0;
|
||||
|
||||
/* Get num_edges for each output pin */
|
||||
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
|
||||
switch (port_type) {
|
||||
case IN_PORT:
|
||||
if (SPICE_MODEL_PORT_OUTPUT != cur_spice_model->ports[iport].type) {
|
||||
continue; /* ALL output ports requires a tedge */
|
||||
}
|
||||
num_tedges += cur_spice_model->ports[iport].size;
|
||||
case OUT_PORT:
|
||||
if (SPICE_MODEL_PORT_OUTPUT == cur_spice_model->ports[iport].type) {
|
||||
continue; /* ALL non-output ports requires a tedge */
|
||||
}
|
||||
num_tedges += cur_spice_model->ports[iport].size;
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid port type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return num_tedges;
|
||||
}
|
||||
|
||||
t_spice_model_tedge* get_unused_spice_model_port_tedge(t_spice_model_port* cur_port,
|
||||
int pin_index) {
|
||||
int iedge;
|
||||
|
||||
/* Check the edge array */
|
||||
for (iedge = 0; iedge < cur_port->num_tedges[pin_index]; iedge++) {
|
||||
/* See if this is an unused edge */
|
||||
if (NULL == cur_port->tedge[pin_index][iedge]->from_port) {
|
||||
assert (OPEN == cur_port->tedge[pin_index][iedge]->from_port_pin_number);
|
||||
return cur_port->tedge[pin_index][iedge];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate tedges (timing edges) for a SPICE model
|
||||
* For each output pin, we need a tedge connected to all the input pins
|
||||
*/
|
||||
void alloc_spice_model_num_tedges(t_spice_model* cur_spice_model) {
|
||||
int iport, ipin, iedge;
|
||||
int jport, jpin;
|
||||
int num_out_tedges = 0;
|
||||
int num_in_tedges = 0;
|
||||
|
||||
/* Get num_edges for each output pin */
|
||||
num_out_tedges = get_spice_model_num_tedges_per_pin(cur_spice_model, OUT_PORT);
|
||||
num_in_tedges = get_spice_model_num_tedges_per_pin(cur_spice_model, IN_PORT);
|
||||
|
||||
/* Allocate tedges for output ports */
|
||||
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
|
||||
if ( (SPICE_MODEL_PORT_OUTPUT != cur_spice_model->ports[iport].type)
|
||||
&& (SPICE_MODEL_PORT_INOUT != cur_spice_model->ports[iport].type)) {
|
||||
continue; /* We only care OUTPUT and INOUT ports */
|
||||
}
|
||||
/* allocate num_tedges */
|
||||
cur_spice_model->ports[iport].num_tedges = (int*) my_malloc(sizeof(int) * cur_spice_model->ports[iport].size);
|
||||
for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) {
|
||||
cur_spice_model->ports[iport].num_tedges[ipin] = num_out_tedges;
|
||||
}
|
||||
/* allocate tedges */
|
||||
cur_spice_model->ports[iport].tedge = (t_spice_model_tedge***) my_calloc(cur_spice_model->ports[iport].size, sizeof(t_spice_model_tedge**));
|
||||
for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) {
|
||||
cur_spice_model->ports[iport].tedge[ipin] = (t_spice_model_tedge**) my_calloc(cur_spice_model->ports[iport].num_tedges[ipin], sizeof(t_spice_model_tedge*));
|
||||
/* Allocate tedge and fill the pointor array */
|
||||
for (iedge = 0; iedge < cur_spice_model->ports[iport].num_tedges[ipin]; iedge++) {
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge] = (t_spice_model_tedge*) my_calloc(1, sizeof(t_spice_model_tedge));
|
||||
/* Initialize the to_port information of the tedges */
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->to_port = &(cur_spice_model->ports[iport]);
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->to_port_pin_number = ipin;
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->from_port = NULL;
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->from_port_pin_number = OPEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate tedges for input ports */
|
||||
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
|
||||
if (SPICE_MODEL_PORT_OUTPUT == cur_spice_model->ports[iport].type) {
|
||||
continue; /* We only care non-OUTPUT ports */
|
||||
}
|
||||
/* allocate num_tedges */
|
||||
cur_spice_model->ports[iport].num_tedges = (int*) my_malloc(sizeof(int) * cur_spice_model->ports[iport].size);
|
||||
for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) {
|
||||
cur_spice_model->ports[iport].num_tedges[ipin] = num_in_tedges;
|
||||
}
|
||||
/* allocate tedges */
|
||||
cur_spice_model->ports[iport].tedge = (t_spice_model_tedge***) my_calloc(cur_spice_model->ports[iport].size, sizeof(t_spice_model_tedge**));
|
||||
for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) {
|
||||
cur_spice_model->ports[iport].tedge[ipin] = (t_spice_model_tedge**) my_calloc(cur_spice_model->ports[iport].num_tedges[ipin], sizeof(t_spice_model_tedge*));
|
||||
}
|
||||
}
|
||||
|
||||
/* Find tedge and fill the pointor array */
|
||||
/* Get the unused edge from each output edge */
|
||||
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
|
||||
if (SPICE_MODEL_PORT_OUTPUT == cur_spice_model->ports[iport].type) {
|
||||
continue; /* We only care non-OUTPUT ports */
|
||||
}
|
||||
for (ipin = 0; ipin < cur_spice_model->ports[iport].size; ipin++) {
|
||||
for (iedge = 0; iedge < cur_spice_model->ports[iport].num_tedges[ipin]; iedge++) {
|
||||
/* Find each output edge */
|
||||
for (jport = 0; jport < cur_spice_model->num_port; jport++) {
|
||||
if ( (SPICE_MODEL_PORT_OUTPUT != cur_spice_model->ports[jport].type)
|
||||
&& (SPICE_MODEL_PORT_INOUT != cur_spice_model->ports[jport].type)) {
|
||||
continue; /* We only care OUTPUT and INOUT ports */
|
||||
}
|
||||
for (jpin = 0; jpin < cur_spice_model->ports[jport].size; jpin++) {
|
||||
/* get the first unused edge */
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge] = get_unused_spice_model_port_tedge(&(cur_spice_model->ports[jport]), jpin);
|
||||
assert(NULL != cur_spice_model->ports[iport].tedge[ipin][iedge]);
|
||||
/* Configure the tedge */
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->from_port = &(cur_spice_model->ports[iport]);
|
||||
cur_spice_model->ports[iport].tedge[ipin][iedge]->from_port_pin_number = ipin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Depend on the type of delay, configure the tedge content */
|
||||
void configure_one_tedge_delay(t_spice_model_tedge* cur_tedge,
|
||||
enum spice_model_delay_type delay_type,
|
||||
float delay) {
|
||||
|
||||
switch (delay_type) {
|
||||
case SPICE_MODEL_DELAY_RISE:
|
||||
cur_tedge->trise = delay;
|
||||
break;
|
||||
case SPICE_MODEL_DELAY_FALL:
|
||||
cur_tedge->tfall = delay;
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid delay type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void configure_tedges_delay_matrix(enum spice_model_delay_type delay_type,
|
||||
int num_in_port, t_spice_model_port** in_port,
|
||||
int num_out_port, t_spice_model_port** out_port,
|
||||
float** delay_matrix) {
|
||||
int iedge, iport, ipin;
|
||||
int jport;
|
||||
|
||||
/* Configure timing edges for this spice_model */
|
||||
for (iport = 0; iport < num_in_port; iport++) {
|
||||
for (ipin = 0; ipin < in_port[iport]->size; ipin++) {
|
||||
for (iedge = 0; iedge < in_port[iport]->num_tedges[ipin]; iedge++) {
|
||||
/* check each edge, see if the from_port and to_port match! */
|
||||
/* Src should match! */
|
||||
assert ( in_port[iport] == in_port[iport]->tedge[ipin][iedge]->from_port );
|
||||
for (jport = 0; jport < num_out_port; jport++) {
|
||||
/* Check if des matches */
|
||||
if ( out_port[jport] == in_port[iport]->tedge[ipin][iedge]->to_port ) {
|
||||
configure_one_tedge_delay(in_port[iport]->tedge[ipin][iedge], delay_type, delay_matrix[iport][jport]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate and parse delay_matix */
|
||||
float** fpga_spice_atof_2D(int num_in_port, int num_out_port, char* str) {
|
||||
int i, j;
|
||||
float** delay_matrix = NULL;
|
||||
|
||||
/* allocate */
|
||||
delay_matrix = (float**)my_calloc(num_in_port, sizeof(float*));
|
||||
for (i = 0; i < num_in_port; i++) {
|
||||
delay_matrix[i] = (float*)my_calloc(num_out_port, sizeof(float));
|
||||
}
|
||||
|
||||
my_atof_2D(delay_matrix, num_in_port, num_out_port, str);
|
||||
|
||||
return delay_matrix;
|
||||
}
|
||||
|
||||
void free_2D_matrix(void** delay_matrix,
|
||||
int num_in_port, int num_out_port) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_in_port; i++) {
|
||||
my_free(delay_matrix[i]);
|
||||
}
|
||||
|
||||
my_free(delay_matrix);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build timing graph for a spice_model */
|
||||
void annotate_spice_model_timing(t_spice_model* cur_spice_model) {
|
||||
int i;
|
||||
int num_in_port = 0;
|
||||
t_spice_model_port** in_port = NULL;
|
||||
int num_out_port = 0;
|
||||
t_spice_model_port** out_port = NULL;
|
||||
float** delay_matrix = NULL;
|
||||
|
||||
/* check */
|
||||
assert ( 0 < cur_spice_model->num_delay_info );
|
||||
|
||||
/* Allocate edges */
|
||||
alloc_spice_model_num_tedges(cur_spice_model);
|
||||
|
||||
/* Parse each delay_info */
|
||||
for (i = 0; i < cur_spice_model->num_delay_info; i++) {
|
||||
/* Get input and output ports */
|
||||
in_port = get_spice_model_delay_info_ports(cur_spice_model, cur_spice_model->delay_info[i].in_port_name, &num_in_port);
|
||||
out_port = get_spice_model_delay_info_ports(cur_spice_model, cur_spice_model->delay_info[i].out_port_name, &num_out_port);
|
||||
/* create fpga_spice atof_2D !!! */
|
||||
delay_matrix = fpga_spice_atof_2D(num_in_port, num_out_port, cur_spice_model->delay_info[i].value);
|
||||
/* create tedges with delay_matrix */
|
||||
configure_tedges_delay_matrix(cur_spice_model->delay_info[i].type,
|
||||
num_in_port, in_port,
|
||||
num_out_port, out_port,
|
||||
delay_matrix);
|
||||
/* Free */
|
||||
free_2D_matrix((void**)delay_matrix, num_in_port, num_out_port);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
t_spice_model_port** get_spice_model_delay_info_ports(t_spice_model* cur_spice_model,
|
||||
char* port_list,
|
||||
int* num_port);
|
||||
|
||||
int get_spice_model_num_tedges_per_pin(t_spice_model* cur_spice_model,
|
||||
enum PORTS port_type);
|
||||
|
||||
t_spice_model_tedge* get_unused_spice_model_port_tedge(t_spice_model_port* cur_port,
|
||||
int pin_index);
|
||||
|
||||
void alloc_spice_model_num_tedges(t_spice_model* cur_spice_model);
|
||||
|
||||
void configure_one_tedge_delay(t_spice_model_tedge* cur_tedge,
|
||||
enum spice_model_delay_type delay_type,
|
||||
float delay);
|
||||
|
||||
void configure_tedges_delay_matrix(enum spice_model_delay_type delay_type,
|
||||
int num_in_port, t_spice_model_port** in_port,
|
||||
int num_out_port, t_spice_model_port** out_port,
|
||||
float** delay_matrix);
|
||||
|
||||
float** fpga_spice_atof_2D(int num_in_port, int num_out_port, char* str);
|
||||
|
||||
void free_2D_matrix(void** delay_matrix,
|
||||
int num_in_port, int num_out_port);
|
||||
|
||||
void annotate_spice_model_timing(t_spice_model* cur_spice_model);
|
|
@ -29,6 +29,8 @@
|
|||
#include "fpga_spice_globals.h"
|
||||
#include "spice_globals.h"
|
||||
#include "fpga_spice_utils.h"
|
||||
#include "fpga_spice_timing_utils.h"
|
||||
#include "token.h"
|
||||
|
||||
enum e_dir_err {
|
||||
E_DIR_NOT_EXIST,
|
||||
|
@ -331,6 +333,24 @@ void config_spice_model_port_inv_spice_model(int num_spice_models,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Find a spice model port by given name */
|
||||
t_spice_model_port* find_spice_model_port_by_name(t_spice_model* cur_spice_model,
|
||||
char* port_name) {
|
||||
int iport;
|
||||
t_spice_model_port* port = NULL;
|
||||
int cnt = 0;
|
||||
|
||||
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
|
||||
if (0 == strcmp(cur_spice_model->ports[iport].prefix, port_name)) {
|
||||
port = &(cur_spice_model->ports[iport]);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
assert ((0 == cnt) || (1 == cnt));
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
/* Tasks:
|
||||
|
@ -5853,35 +5873,36 @@ int get_pb_graph_node_wired_lut_logical_block_index(t_pb_graph_node* cur_pb_grap
|
|||
int temp_rr_node_index;
|
||||
int lut_output_vpack_net_num = OPEN;
|
||||
|
||||
num_used_lut_output_pins = 0;
|
||||
/* Find the used output pin of this LUT and rr_node in the graph */
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_output_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_output_pins[iport]; ipin++) {
|
||||
temp_rr_node_index = cur_pb_graph_node->output_pins[iport][ipin].pin_count_in_cluster;
|
||||
if (OPEN != op_pb_rr_graph[temp_rr_node_index].vpack_net_num) { /* TODO: Shit... I do not why the vpack_net_num is not synchronized to the net_num !!! */
|
||||
num_used_lut_output_pins++;
|
||||
lut_output_vpack_net_num = op_pb_rr_graph[temp_rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make sure we only have 1 used output pin */
|
||||
/* vpr_printf(TIO_MESSAGE_INFO, "Wired LUT num_used_lut_output_pins is %d\n", num_used_lut_output_pins); */
|
||||
assert ((1 == num_used_lut_output_pins)
|
||||
&& (OPEN != lut_output_vpack_net_num));
|
||||
num_used_lut_output_pins = 0;
|
||||
/* Find the used output pin of this LUT and rr_node in the graph */
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_output_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_output_pins[iport]; ipin++) {
|
||||
temp_rr_node_index = cur_pb_graph_node->output_pins[iport][ipin].pin_count_in_cluster;
|
||||
if (OPEN != op_pb_rr_graph[temp_rr_node_index].vpack_net_num) { /* TODO: Shit... I do not why the vpack_net_num is not synchronized to the net_num !!! */
|
||||
num_used_lut_output_pins++;
|
||||
lut_output_vpack_net_num = op_pb_rr_graph[temp_rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make sure we only have 1 used output pin */
|
||||
/* vpr_printf(TIO_MESSAGE_INFO, "Wired LUT num_used_lut_output_pins is %d\n", num_used_lut_output_pins); */
|
||||
assert ((1 == num_used_lut_output_pins)
|
||||
&& (OPEN != lut_output_vpack_net_num));
|
||||
|
||||
num_used_lut_input_pins = 0;
|
||||
/* Find the used input pin of this LUT and rr_node in the graph */
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_input_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_input_pins[iport]; ipin++) {
|
||||
temp_rr_node_index = cur_pb_graph_node->input_pins[iport][ipin].pin_count_in_cluster;
|
||||
if (lut_output_vpack_net_num == op_pb_rr_graph[temp_rr_node_index].vpack_net_num) {
|
||||
if (OPEN != op_pb_rr_graph[temp_rr_node_index].vpack_net_num) {
|
||||
num_used_lut_input_pins++;
|
||||
lut_output_vpack_net_num = op_pb_rr_graph[temp_rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make sure we only have 1 used input pin */
|
||||
assert (1 == num_used_lut_input_pins);
|
||||
|
||||
assert (1 == num_used_lut_input_pins);
|
||||
|
||||
/* vpr_printf(TIO_MESSAGE_INFO, "Wired LUT output vpack_net_num is %d\n", lut_output_vpack_net_num); */
|
||||
|
||||
/* Find the used output*/
|
||||
|
|
|
@ -31,6 +31,9 @@ t_spice_model* get_default_spice_model(enum e_spice_model_type default_spice_mod
|
|||
int num_spice_model,
|
||||
t_spice_model* spice_models);
|
||||
|
||||
t_spice_model_port* find_spice_model_port_by_name(t_spice_model* cur_spice_model,
|
||||
char* port_name);
|
||||
|
||||
void config_spice_model_input_output_buffers_pass_gate(int num_spice_models,
|
||||
t_spice_model* spice_model);
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ void vpr_dump_syn_verilog(t_vpr_setup vpr_setup,
|
|||
init_list_include_verilog_netlists(Arch.spice);
|
||||
|
||||
/* Dump internal structures of submodules */
|
||||
dump_verilog_submodules(submodule_dir_path, Arch, &vpr_setup.RoutingArch);
|
||||
dump_verilog_submodules(submodule_dir_path, Arch, &vpr_setup.RoutingArch, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.include_timing, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.init_sim);
|
||||
|
||||
/* Initial global variables about configuration bits */
|
||||
alloc_global_routing_conf_bits();
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include "verilog_global.h"
|
||||
|
||||
char* verilog_netlist_file_postfix = ".v";
|
||||
float verilog_sim_timescale = 1e-9; // Verilog Simulation time scale (minimum time unit) : 1ns
|
||||
char* verilog_timing_preproc_flag = "ENABLE_TIMING"; // the flag to enable timing definition during compilation
|
||||
char* verilog_init_sim_preproc_flag = "INITIALIZATION"; // the flag to enable initialization during simulation
|
||||
|
||||
char* verilog_top_postfix = "_top.v";
|
||||
char* bitstream_verilog_file_postfix = ".bitstream";
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* global parameters for dumping synthesizable verilog */
|
||||
|
||||
extern char* verilog_netlist_file_postfix;
|
||||
extern float verilog_sim_timescale;
|
||||
extern char* verilog_timing_preproc_flag; // the flag to enable timing definition during compilation
|
||||
extern char* verilog_init_sim_preproc_flag; // the flag to enable initialization during simulation
|
||||
|
||||
extern char* verilog_top_postfix;
|
||||
extern char* bitstream_verilog_file_postfix;
|
||||
|
|
|
@ -32,10 +32,93 @@
|
|||
#include "verilog_utils.h"
|
||||
#include "verilog_pbtypes.h"
|
||||
|
||||
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, "\n`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]->prefix, ipin,
|
||||
input_port[iport]->tedge[ipin][iedge]->to_port->prefix,
|
||||
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;
|
||||
}
|
||||
|
||||
void dump_verilog_submodule_init_sim(FILE* fp,
|
||||
t_spice_model* cur_spice_model) {
|
||||
int iport, ipin;
|
||||
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_init_sim_preproc_flag);
|
||||
fprintf(fp, " //------ BEGIN driver initialization -----\n");
|
||||
fprintf(fp, "initial begin\n");
|
||||
|
||||
for (iport = 0; iport < num_input_port; iport++) {
|
||||
fprintf(fp, " $signal_force(\"%s\", \"0\", 0, 1, , 1);\n",
|
||||
input_port[iport]->prefix);
|
||||
}
|
||||
fprintf(fp, "end\n");
|
||||
|
||||
fprintf(fp, " //------ END driver initialization -----\n");
|
||||
fprintf(fp, "`endif\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/***** Subroutines *****/
|
||||
/* Dump a module of inverter or buffer or tapered buffer */
|
||||
void dump_verilog_invbuf_module(FILE* fp,
|
||||
t_spice_model* invbuf_spice_model) {
|
||||
t_spice_model* invbuf_spice_model,
|
||||
boolean include_timing,
|
||||
boolean init_sim) {
|
||||
int ipin, iport, port_cnt;
|
||||
int num_input_port = 0;
|
||||
int num_output_port = 0;
|
||||
|
@ -86,9 +169,9 @@ void dump_verilog_invbuf_module(FILE* fp,
|
|||
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");
|
||||
fprintf(fp, " input [0:0] %s,\n", input_port[0]->prefix);
|
||||
fprintf(fp, " output [0:0] %s\n", output_port[0]->prefix);
|
||||
fprintf(fp, " );\n");
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Assign logics : depending on topology */
|
||||
|
@ -234,6 +317,16 @@ void dump_verilog_invbuf_module(FILE* fp,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/* Print timing info */
|
||||
if (TRUE == include_timing) {
|
||||
dump_verilog_submodule_timing(fp, invbuf_spice_model);
|
||||
}
|
||||
|
||||
/* Print simulation initialization info */
|
||||
if (TRUE == init_sim) {
|
||||
dump_verilog_submodule_init_sim(fp, invbuf_spice_model);
|
||||
}
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
@ -247,7 +340,8 @@ void dump_verilog_invbuf_module(FILE* fp,
|
|||
|
||||
/* Dump a module of pass-gate logic */
|
||||
void dump_verilog_passgate_module(FILE* fp,
|
||||
t_spice_model* passgate_spice_model) {
|
||||
t_spice_model* passgate_spice_model,
|
||||
boolean include_timing) {
|
||||
int iport;
|
||||
int num_input_port = 0;
|
||||
int num_output_port = 0;
|
||||
|
@ -291,11 +385,11 @@ void dump_verilog_passgate_module(FILE* fp,
|
|||
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");
|
||||
fprintf(fp, " input [0:0] in,\n");
|
||||
fprintf(fp, " input [0:0] sel,\n");
|
||||
fprintf(fp, " input [0:0] selb,\n");
|
||||
fprintf(fp, " output [0:0] %s\n", output_port[0]->prefix);
|
||||
fprintf(fp, " );\n");
|
||||
/* Finish dumping ports */
|
||||
|
||||
break;
|
||||
|
@ -309,10 +403,10 @@ void dump_verilog_passgate_module(FILE* fp,
|
|||
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");
|
||||
fprintf(fp, " input [0:0] in,\n");
|
||||
fprintf(fp, " input [0:0] sel,\n");
|
||||
fprintf(fp, " output [0:0] %s\n", output_port[0]->prefix);
|
||||
fprintf(fp, " );\n");
|
||||
/* Finish dumping ports */
|
||||
break;
|
||||
default:
|
||||
|
@ -325,6 +419,11 @@ void dump_verilog_passgate_module(FILE* fp,
|
|||
fprintf(fp, "assign %s = sel? in : 1'bz;\n",
|
||||
output_port[0]->prefix);
|
||||
|
||||
/* Print timing info */
|
||||
if (TRUE == include_timing) {
|
||||
dump_verilog_submodule_timing(fp, passgate_spice_model);
|
||||
}
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
@ -343,7 +442,9 @@ void dump_verilog_passgate_module(FILE* fp,
|
|||
* 3. pass-gate logics */
|
||||
void dump_verilog_submodule_essentials(char* submodule_dir,
|
||||
int num_spice_model,
|
||||
t_spice_model* spice_models) {
|
||||
t_spice_model* spice_models,
|
||||
boolean include_timing,
|
||||
boolean init_sim) {
|
||||
int imodel;
|
||||
char* verilog_name = my_strcat(submodule_dir, essentials_verilog_file_name);
|
||||
FILE* fp = NULL;
|
||||
|
@ -357,6 +458,8 @@ void dump_verilog_submodule_essentials(char* submodule_dir,
|
|||
}
|
||||
dump_verilog_file_header(fp,"Essential gates");
|
||||
|
||||
dump_verilog_preproc(fp, include_timing);
|
||||
|
||||
/* Output essential models*/
|
||||
for (imodel = 0; imodel < num_spice_model; imodel++) {
|
||||
/* By pass user-defined modules */
|
||||
|
@ -364,10 +467,10 @@ void dump_verilog_submodule_essentials(char* submodule_dir,
|
|||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_INVBUF == spice_models[imodel].type) {
|
||||
dump_verilog_invbuf_module(fp, &(spice_models[imodel]));
|
||||
dump_verilog_invbuf_module(fp, &(spice_models[imodel]), include_timing, init_sim);
|
||||
}
|
||||
if (SPICE_MODEL_PASSGATE == spice_models[imodel].type) {
|
||||
dump_verilog_passgate_module(fp, &(spice_models[imodel]));
|
||||
dump_verilog_passgate_module(fp, &(spice_models[imodel]), include_timing);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,11 +513,11 @@ void dump_verilog_cmos_mux_one_basis_module(FILE* fp,
|
|||
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",
|
||||
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",
|
||||
fprintf(fp, " input [0:%d] mem_inv);\n",
|
||||
num_mem - 1);
|
||||
/* Verilog Behavior description for a MUX */
|
||||
fprintf(fp, "//---- Behavior-level description -----\n");
|
||||
|
@ -506,11 +609,11 @@ void dump_verilog_cmos_mux_one_basis_module_structural(FILE* fp,
|
|||
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",
|
||||
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",
|
||||
fprintf(fp, " input [0:%d] mem_inv);\n",
|
||||
num_mem - 1);
|
||||
/* Verilog Behavior description for a MUX */
|
||||
fprintf(fp, "//---- Structure-level description -----\n");
|
||||
|
@ -578,11 +681,11 @@ void dump_verilog_rram_mux_one_basis_module_structural(FILE* fp,
|
|||
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",
|
||||
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",
|
||||
fprintf(fp, " input wire [0:%d] wl);\n",
|
||||
num_mem - 1);
|
||||
|
||||
/* Print internal structure of 4T1R programming structures
|
||||
|
@ -643,11 +746,11 @@ void dump_verilog_rram_mux_one_basis_module(FILE* fp,
|
|||
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",
|
||||
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",
|
||||
fprintf(fp, " input wire [0:%d] wl);\n",
|
||||
num_mem - 1);
|
||||
|
||||
/* Print the internal logics:
|
||||
|
@ -1977,20 +2080,21 @@ void dump_verilog_wire_module(FILE* fp,
|
|||
|
||||
/* Dump one module of a LUT */
|
||||
void dump_verilog_submodule_one_lut(FILE* fp,
|
||||
t_spice_model* verilog_model) {
|
||||
t_spice_model* verilog_model,
|
||||
boolean include_timing) {
|
||||
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, iedge;
|
||||
|
||||
/* Check */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
exit(1);}
|
||||
assert(SPICE_MODEL_LUT == verilog_model->type);
|
||||
|
||||
/* Print module name */
|
||||
|
@ -2053,6 +2157,13 @@ void dump_verilog_submodule_one_lut(FILE* fp,
|
|||
/* End of call LUT MUX */
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Give timing information */
|
||||
if (TRUE == include_timing) {
|
||||
dump_verilog_submodule_timing(fp, verilog_model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Print end of module */
|
||||
fprintf(fp, "endmodule\n");
|
||||
fprintf(fp, "//-----END LUT module, verilog_model_name=%s -----\n", verilog_model->name);
|
||||
|
@ -2064,7 +2175,8 @@ void dump_verilog_submodule_one_lut(FILE* fp,
|
|||
/* Dump verilog top-level module for LUTs */
|
||||
void dump_verilog_submodule_luts(char* submodule_dir,
|
||||
int num_spice_model,
|
||||
t_spice_model* spice_models) {
|
||||
t_spice_model* spice_models,
|
||||
boolean include_timing) {
|
||||
FILE* fp = NULL;
|
||||
char* verilog_name = my_strcat(submodule_dir, luts_verilog_file_name);
|
||||
int imodel;
|
||||
|
@ -2077,6 +2189,8 @@ void dump_verilog_submodule_luts(char* submodule_dir,
|
|||
}
|
||||
dump_verilog_file_header(fp,"Look-Up Tables");
|
||||
|
||||
dump_verilog_preproc(fp, include_timing);
|
||||
|
||||
/* Search for each LUT spice model */
|
||||
for (imodel = 0; imodel < num_spice_model; imodel++) {
|
||||
/* Bypass user-defined spice models */
|
||||
|
@ -2084,7 +2198,7 @@ void dump_verilog_submodule_luts(char* submodule_dir,
|
|||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_LUT == spice_models[imodel].type) {
|
||||
dump_verilog_submodule_one_lut(fp, &(spice_models[imodel]));
|
||||
dump_verilog_submodule_one_lut(fp, &(spice_models[imodel]), include_timing);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2236,13 +2350,17 @@ void dump_verilog_submodule_wires(char* subckt_dir,
|
|||
*/
|
||||
void dump_verilog_submodules(char* submodule_dir,
|
||||
t_arch Arch,
|
||||
t_det_routing_arch* routing_arch) {
|
||||
t_det_routing_arch* routing_arch,
|
||||
boolean include_timing,
|
||||
boolean init_sim) {
|
||||
|
||||
/* 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);
|
||||
Arch.spice->spice_models,
|
||||
include_timing,
|
||||
init_sim);
|
||||
|
||||
/* 1. MUXes */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n");
|
||||
|
@ -2252,7 +2370,8 @@ void dump_verilog_submodules(char* submodule_dir,
|
|||
/* 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);
|
||||
Arch.spice->num_spice_model, Arch.spice->spice_models,
|
||||
include_timing);
|
||||
|
||||
/* 3. Hardwires */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
void dump_verilog_submodules(char* submodule_dir,
|
||||
t_arch Arch,
|
||||
t_det_routing_arch* routing_arch);
|
||||
t_det_routing_arch* routing_arch,
|
||||
boolean include_timing,
|
||||
boolean init_sim);
|
||||
|
|
|
@ -54,7 +54,7 @@ static char* top_netlist_normal_blb_port_postfix = "_blb";
|
|||
static char* top_netlist_normal_wlb_port_postfix = "_wlb";
|
||||
static char* top_netlist_scan_chain_head_prefix = "sc_in";
|
||||
|
||||
static float verilog_sim_timescale = 1e-9; // Verilog Simulation time scale (minimum time unit) : 1ns
|
||||
|
||||
static char* top_tb_reset_port_name = "greset";
|
||||
static char* top_tb_set_port_name = "gset";
|
||||
static char* top_tb_prog_reset_port_name = "prog_reset";
|
||||
|
|
|
@ -141,6 +141,24 @@ void dump_include_user_defined_verilog_netlists(FILE* fp,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Dump preproc */
|
||||
void dump_verilog_preproc(FILE* fp,
|
||||
boolean include_timing) {
|
||||
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* To enable timing */
|
||||
if (TRUE == include_timing) {
|
||||
fprintf(fp, "`define %s 1\n", verilog_timing_preproc_flag);
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_verilog_file_header(FILE* fp,
|
||||
char* usage) {
|
||||
if (NULL == fp) {
|
||||
|
|
|
@ -10,6 +10,9 @@ void dump_include_user_defined_verilog_netlists(FILE* fp,
|
|||
void dump_verilog_file_header(FILE* fp,
|
||||
char* usage);
|
||||
|
||||
void dump_verilog_preproc(FILE* fp,
|
||||
boolean include_timing);
|
||||
|
||||
FILE* verilog_create_one_subckt_file(char* subckt_dir,
|
||||
char* subckt_name_prefix,
|
||||
char* verilog_subckt_file_name_prefix,
|
||||
|
|
|
@ -28,6 +28,13 @@ input blb // Inverted Bit line control signal
|
|||
end
|
||||
end
|
||||
|
||||
`ifdef INITIALIZATION
|
||||
initial begin
|
||||
$signal_force("a", "0", 0, 1, , 1);
|
||||
end
|
||||
`endif
|
||||
|
||||
|
||||
// dout is short-wired to din
|
||||
assign dout = a;
|
||||
//---- doutb is always opposite to dout
|
||||
|
|
Loading…
Reference in New Issue