Add timing and initialization for simulation

This commit is contained in:
Aur??Lien ALACCHI 2018-12-04 17:32:09 -07:00
parent 0f87fb9c3f
commit 8ac566ecc0
22 changed files with 687 additions and 64 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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 },

View File

@ -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,

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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*/

View File

@ -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);

View File

@ -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();

View File

@ -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";

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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";

View File

@ -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) {

View File

@ -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,

View File

@ -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