OpenFPGA/vpr7_rram/vpr/SRC/fpga_spice/fpga_spice_setup.c

1301 lines
53 KiB
C

/***********************************/
/* 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 <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 spice support headers*/
#include "linkedlist.h"
#include "fpga_spice_globals.h"
#include "fpga_spice_utils.h"
#include "fpga_spice_backannotate_utils.h"
#include "syn_verilog_api.h"
#include "fpga_spice_setup.h"
/***** Subroutines Declarations *****/
static
int map_pb_type_port_to_spice_model_ports(t_pb_type* cur_pb_type,
t_spice_model* cur_spice_model);
static
void match_pb_types_spice_model_rec(t_pb_type* cur_pb_type,
int num_spice_model,
t_spice_model* spice_models);
static
void init_and_check_one_sram_inf_orgz(t_sram_inf_orgz* cur_sram_inf_orgz,
int num_spice_model,
t_spice_model* spice_models);
static
void init_and_check_sram_inf(t_arch* arch,
t_det_routing_arch* routing_arch);
static
t_llist* check_and_add_one_global_port_to_llist(t_llist* old_head,
t_spice_model_port* candidate_port);
static
void rec_stat_pb_type_keywords(t_pb_type* cur_pb_type,
int* num_keyword);
static
void rec_add_pb_type_keywords_to_list(t_pb_type* cur_pb_type,
int* cur,
char** keywords,
char* prefix);
static
int check_conflict_syntax_char_in_string(t_llist* LL_reserved_syntax_char_head,
char* str_to_check);
static
void check_spice_model_name_conflict_syntax_char(t_arch Arch,
t_llist* LL_reseved_syntax_char_head);
static
t_llist* init_llist_verilog_and_spice_syntax_char();
static
boolean is_verilog_and_spice_syntax_conflict_char(t_llist* LL_reserved_syntax_char_head,
char ref_char);
static
int check_and_rename_logical_block_and_net_names(t_llist* LL_reserved_syntax_char_head,
char* circuit_name,
boolean rename_illegal_port,
int LL_num_logical_blocks, t_logical_block* LL_logical_block,
int LL_num_clb_nets, t_net* LL_clb_net,
int LL_num_vpack_nets, t_net* LL_vpack_net);
/***** Subroutines *****/
/* Map (synchronize) pb_type ports to SPICE model ports
*/
static
int map_pb_type_port_to_spice_model_ports(t_pb_type* cur_pb_type,
t_spice_model* cur_spice_model) {
int iport;
t_port* cur_pb_type_port = NULL;
/* Check */
assert(NULL != cur_pb_type);
/* Initialize each port */
for (iport = 0; iport < cur_pb_type->num_ports; iport++) {
cur_pb_type->ports[iport].spice_model_port = NULL;
}
/* Return if SPICE_MODEL is NULL */
if (NULL == cur_spice_model) {
return 0;
}
/* For each port, find a SPICE model port, which has the same name and port size */
for (iport = 0; iport < cur_spice_model->num_port; iport++) {
cur_pb_type_port =
find_pb_type_port_match_spice_model_port(cur_pb_type,
&(cur_spice_model->ports[iport]));
/* Not every spice_model_port can find a mapped pb_type_port.
* Since a pb_type only includes necessary ports in technology mapping.
* ports for physical designs may be ignored !
*/
if (NULL != cur_pb_type_port) {
cur_pb_type_port->spice_model_port = &(cur_spice_model->ports[iport]);
}
}
/* Although some spice_model_port may not have a corresponding pb_type_port
* but each pb_type_port should be mapped to a spice_model_port
*/
for (iport = 0; iport < cur_pb_type->num_ports; iport++) {
if (NULL == cur_pb_type->ports[iport].spice_model_port) {
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Pb_type(%s) Port(%s) cannot find a corresponding port in SPICE model(%s)\n",
__FILE__, __LINE__, cur_pb_type->name, cur_pb_type->ports[iport].name,
cur_spice_model->name);
exit(1);
}
}
return cur_pb_type->num_ports;
}
/* Find spice_model_name definition in pb_types
* Try to match the name with defined spice_models
*/
static
void match_pb_types_spice_model_rec(t_pb_type* cur_pb_type,
int num_spice_model,
t_spice_model* spice_models) {
int imode, ipb, jinterc;
if (NULL == cur_pb_type) {
vpr_printf(TIO_MESSAGE_WARNING,"(File:%s,LINE[%d])cur_pb_type is null pointor!\n",__FILE__,__LINE__);
return;
}
/* If there is a spice_model_name, this is a leaf node!*/
if (NULL != cur_pb_type->spice_model_name) {
/* What annoys me is VPR create a sub pb_type for each lut which suppose to be a leaf node
* This may bring software convience but ruins SPICE modeling
*/
/* Let's find a matched spice model!*/
printf("INFO: matching cur_pb_type=%s with spice_model_name=%s...\n",cur_pb_type->name, cur_pb_type->spice_model_name);
assert(NULL == cur_pb_type->spice_model);
cur_pb_type->spice_model = find_name_matched_spice_model(cur_pb_type->spice_model_name, num_spice_model, spice_models);
if (NULL == cur_pb_type->spice_model) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Fail to find a defined SPICE model called %s, in pb_type(%s)!\n",__FILE__, __LINE__, cur_pb_type->spice_model_name, cur_pb_type->name);
exit(1);
}
/* Map pb_type ports to SPICE model ports*/
map_pb_type_port_to_spice_model_ports(cur_pb_type,cur_pb_type->spice_model);
return;
}
/* Traversal the hierarchy*/
for (imode = 0; imode < cur_pb_type->num_modes; imode++) {
/* Task 1: Find the interconnections and match the spice_model */
for (jinterc = 0; jinterc < cur_pb_type->modes[imode].num_interconnect; jinterc++) {
assert(NULL == cur_pb_type->modes[imode].interconnect[jinterc].spice_model);
/* If the spice_model_name is not defined, we use the default*/
if (NULL == cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name) {
switch (cur_pb_type->modes[imode].interconnect[jinterc].type) {
case DIRECT_INTERC:
cur_pb_type->modes[imode].interconnect[jinterc].spice_model =
get_default_spice_model(SPICE_MODEL_WIRE,num_spice_model,spice_models);
break;
case COMPLETE_INTERC:
/* Special for Completer Interconnection:
* 1. The input number is 1, this infers a direct interconnection.
* 2. The input number is larger than 1, this infers multplexers
* according to interconnect[j].num_mux identify the number of input at this level
*/
if (0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) {
cur_pb_type->modes[imode].interconnect[jinterc].spice_model =
get_default_spice_model(SPICE_MODEL_WIRE,num_spice_model,spice_models);
} else {
cur_pb_type->modes[imode].interconnect[jinterc].spice_model =
get_default_spice_model(SPICE_MODEL_MUX,num_spice_model,spice_models);
}
break;
case MUX_INTERC:
cur_pb_type->modes[imode].interconnect[jinterc].spice_model =
get_default_spice_model(SPICE_MODEL_MUX,num_spice_model,spice_models);
break;
default:
break;
}
vpr_printf(TIO_MESSAGE_INFO,"INFO: Link a SPICE model (%s) for Interconnect (%s)!\n",
cur_pb_type->modes[imode].interconnect[jinterc].spice_model->name, cur_pb_type->modes[imode].interconnect[jinterc].name);
} else {
cur_pb_type->modes[imode].interconnect[jinterc].spice_model =
find_name_matched_spice_model(cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, num_spice_model, spice_models);
vpr_printf(TIO_MESSAGE_INFO,"INFO: Link a SPICE model (%s) for Interconnect (%s)!\n",
cur_pb_type->modes[imode].interconnect[jinterc].spice_model->name, cur_pb_type->modes[imode].interconnect[jinterc].name);
if (NULL == cur_pb_type->modes[imode].interconnect[jinterc].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Fail to find a defined SPICE model called %s, in pb_type(%s)!\n",
__FILE__, __LINE__, cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, cur_pb_type->name);
exit(1);
}
switch (cur_pb_type->modes[imode].interconnect[jinterc].type) {
case DIRECT_INTERC:
if (SPICE_MODEL_WIRE != cur_pb_type->modes[imode].interconnect[jinterc].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Invalid type of matched SPICE model called %s, in pb_type(%s)! Sould be wire!\n",
__FILE__, __LINE__, cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, cur_pb_type->name);
exit(1);
}
break;
case COMPLETE_INTERC:
if (0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) {
if (SPICE_MODEL_WIRE != cur_pb_type->modes[imode].interconnect[jinterc].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Invalid type of matched SPICE model called %s, in pb_type(%s)! Sould be wire!\n",
__FILE__, __LINE__, cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, cur_pb_type->name);
exit(1);
}
} else {
if (SPICE_MODEL_MUX != cur_pb_type->modes[imode].interconnect[jinterc].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Invalid type of matched SPICE model called %s, in pb_type(%s)! Sould be MUX!\n",
__FILE__, __LINE__, cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, cur_pb_type->name);
exit(1);
}
}
break;
case MUX_INTERC:
if (SPICE_MODEL_MUX != cur_pb_type->modes[imode].interconnect[jinterc].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d]) Invalid type of matched SPICE model called %s, in pb_type(%s)! Sould be MUX!\n",
__FILE__, __LINE__, cur_pb_type->modes[imode].interconnect[jinterc].spice_model_name, cur_pb_type->name);
exit(1);
}
break;
default:
break;
}
}
}
/* Task 2: Find the child pb_type, do matching recursively */
//if (1 == cur_pb_type->modes[imode].define_spice_model) {
for (ipb = 0; ipb < cur_pb_type->modes[imode].num_pb_type_children; ipb++) {
match_pb_types_spice_model_rec(&cur_pb_type->modes[imode].pb_type_children[ipb],
num_spice_model,
spice_models);
}
//}
}
return;
}
static
void init_and_check_one_sram_inf_orgz(t_sram_inf_orgz* cur_sram_inf_orgz,
int num_spice_model,
t_spice_model* spice_models) {
/* If cur_sram_inf_orgz is not initialized, do nothing */
if (NULL == cur_sram_inf_orgz) {
return;
}
/* For SRAM */
if (NULL == cur_sram_inf_orgz->spice_model_name) {
cur_sram_inf_orgz->spice_model = get_default_spice_model(SPICE_MODEL_SRAM,
num_spice_model,
spice_models);
} else {
cur_sram_inf_orgz->spice_model =
find_name_matched_spice_model(cur_sram_inf_orgz->spice_model_name,
num_spice_model,
spice_models);
}
if (NULL == cur_sram_inf_orgz->spice_model) {
if (NULL == cur_sram_inf_orgz->spice_model_name) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) Cannot find any SRAM spice model!\n",
__FILE__ ,__LINE__);
exit(1);
} else {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of SRAM is undefined in SPICE models!\n",
__FILE__ ,__LINE__, cur_sram_inf_orgz->spice_model_name);
exit(1);
}
}
/* Check the type of SRAM_SPICE_MODEL */
switch (cur_sram_inf_orgz->type) {
case SPICE_SRAM_STANDALONE:
vpr_printf(TIO_MESSAGE_INFO, "INFO: Checking if SRAM spice model fit standalone organization...\n");
if (SPICE_MODEL_SRAM != cur_sram_inf_orgz->spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) Standalone SRAM organization requires a SPICE model(type=sram)!\n",
__FILE__, __LINE__);
exit(1);
}
/* TODO: check SRAM ports */
check_sram_spice_model_ports(cur_sram_inf_orgz->spice_model, FALSE);
break;
case SPICE_SRAM_SCAN_CHAIN:
vpr_printf(TIO_MESSAGE_INFO, "INFO: Checking if SRAM spice model fit scan-chain organization...\n");
if (SPICE_MODEL_SCFF != cur_sram_inf_orgz->spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) Scan-chain SRAM organization requires a SPICE model(type=sff)!\n",
__FILE__, __LINE__);
exit(1);
}
/* TODO: check Scan-chain Flip-flop ports */
check_ff_spice_model_ports(cur_sram_inf_orgz->spice_model, TRUE);
/* TODO: RRAM Scan-chain is not supported yet. Now just forbidden this option */
if (SPICE_MODEL_DESIGN_RRAM == cur_sram_inf_orgz->spice_model->design_tech) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) RRAM-based Scan-chain Flip-flop has not been supported yet!\n",
__FILE__, __LINE__);
exit(1);
}
break;
case SPICE_SRAM_MEMORY_BANK:
vpr_printf(TIO_MESSAGE_INFO, "INFO: Checking if SRAM spice model fit memory-bank organization...\n");
if (SPICE_MODEL_SRAM != cur_sram_inf_orgz->spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) Memory-bank SRAM organization requires a SPICE model(type=sram)!\n",
__FILE__, __LINE__);
exit(1);
}
/* TODO: check if this one has bit lines and word lines */
check_sram_spice_model_ports(cur_sram_inf_orgz->spice_model, TRUE);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) Invalid SRAM organization type!\n",
__FILE__, __LINE__);
exit(1);
}
return;
}
static
void init_and_check_sram_inf(t_arch* arch,
t_det_routing_arch* routing_arch) {
/* We have two branches:
* 1. SPICE SRAM organization information
* 2. Verilog SRAM organization information
*/
init_and_check_one_sram_inf_orgz(arch->sram_inf.spice_sram_inf_orgz,
arch->spice->num_spice_model,
arch->spice->spice_models);
init_and_check_one_sram_inf_orgz(arch->sram_inf.verilog_sram_inf_orgz,
arch->spice->num_spice_model,
arch->spice->spice_models);
return;
}
/* Initialize and check spice models in architecture
* Tasks:
* 1. Link the spice model defined in pb_types and routing switches
* 2. Add default spice model (MUX) if needed
*/
void init_check_arch_spice_models(t_arch* arch,
t_det_routing_arch* routing_arch) {
int i, iport;
vpr_printf(TIO_MESSAGE_INFO,"Initializing and checking SPICE models...\n");
/* Check Spice models first*/
assert(NULL != arch);
assert(NULL != arch->spice);
if ((0 == arch->spice->num_spice_model)||(0 > arch->spice->num_spice_model)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])SPICE models are not defined! Miss this part in architecture file.\n",__FILE__,__LINE__);
exit(1);
}
assert(NULL != arch->spice->spice_models);
/* Find default spice model*/
/* MUX */
if (NULL == get_default_spice_model(SPICE_MODEL_MUX,
arch->spice->num_spice_model,
arch->spice->spice_models)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Fail to find the default MUX SPICE Model! Should define it in architecture file\n",__FILE__,__LINE__);
exit(1);
}
/* Channel Wire */
if (NULL == get_default_spice_model(SPICE_MODEL_CHAN_WIRE,
arch->spice->num_spice_model,
arch->spice->spice_models)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Fail to find the default Channel Wire SPICE Model! Should define it in architecture file\n",__FILE__,__LINE__);
exit(1);
}
/* Wire */
if (NULL == get_default_spice_model(SPICE_MODEL_WIRE,
arch->spice->num_spice_model,
arch->spice->spice_models)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Fail to find the default Wire SPICE Model! Should define it in architecture file\n",__FILE__,__LINE__);
exit(1);
}
/* Link the input/output buffer spice models to higher level spice models
* Configure (fill information) the input/output buffers of high level spice models */
config_spice_model_input_output_buffers_pass_gate(arch->spice->num_spice_model,
arch->spice->spice_models);
/* Find inversion spice_model for ports */
config_spice_model_port_inv_spice_model(arch->spice->num_spice_model,
arch->spice->spice_models);
/* 1. Link the spice model defined in pb_types and routing switches */
/* Step A: Check routing switches, connection blocks*/
if ((0 == arch->num_cb_switch)||(0 > arch->num_cb_switch)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) Define Switches for Connection Blocks is mandatory in SPICE model support! Miss this part in architecture file.\n",__FILE__,__LINE__);
exit(1);
}
for (i = 0; i < arch->num_cb_switch; i++) {
arch->cb_switches[i].spice_model =
find_name_matched_spice_model(arch->cb_switches[i].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
if (NULL == arch->cb_switches[i].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of Switch(%s) is undefined in SPICE models!\n",__FILE__ ,__LINE__, arch->cb_switches[i].spice_model_name, arch->cb_switches[i].name);
exit(1);
}
/* Check the spice model structure is matched with the structure in switch_inf */
if (FALSE == check_spice_model_structure_match_switch_inf(arch->cb_switches[i])) {
exit(1);
}
}
/* Step B: Check switch list: Switch Box*/
if ((0 == arch->num_switches)||(0 > arch->num_switches)) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) Define Switches for Switch Boxes is mandatory in SPICE model support! Miss this part in architecture file.\n",__FILE__,__LINE__);
exit(1);
}
for (i = 0; i < arch->num_switches; i++) {
arch->Switches[i].spice_model =
find_name_matched_spice_model(arch->Switches[i].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
if (NULL == arch->Switches[i].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of Switch(%s) is undefined in SPICE models!\n",__FILE__ ,__LINE__, arch->Switches[i].spice_model_name, arch->Switches[i].name);
exit(1);
}
/* Check the spice model structure is matched with the structure in switch_inf */
if (FALSE == check_spice_model_structure_match_switch_inf(arch->Switches[i])) {
exit(1);
}
}
/* Update the switches in detailed routing architecture settings*/
for (i = 0; i < routing_arch->num_switch; i++) {
if (NULL == switch_inf[i].spice_model_name) {
switch_inf[i].spice_model = get_default_spice_model(SPICE_MODEL_MUX,
arch->spice->num_spice_model,
arch->spice->spice_models);
continue;
}
switch_inf[i].spice_model =
find_name_matched_spice_model(switch_inf[i].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
if (NULL == switch_inf[i].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of Switch(%s) is undefined in SPICE models!\n",__FILE__ ,__LINE__, switch_inf[i].spice_model_name, switch_inf[i].name);
exit(1);
}
}
/* Step C: Find SRAM Model*/
init_and_check_sram_inf(arch, routing_arch);
/* Step D: Find the segment spice_model*/
for (i = 0; i < arch->num_segments; i++) {
if (NULL == arch->Segments[i].spice_model_name) {
arch->Segments[i].spice_model =
get_default_spice_model(SPICE_MODEL_CHAN_WIRE,
arch->spice->num_spice_model,
arch->spice->spice_models);
continue;
} else {
arch->Segments[i].spice_model =
find_name_matched_spice_model(arch->Segments[i].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
}
if (NULL == arch->Segments[i].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of Segment(Length:%d) is undefined in SPICE models!\n",
__FILE__ ,__LINE__,
arch->Segments[i].spice_model_name,
arch->Segments[i].length);
exit(1);
} else if (SPICE_MODEL_CHAN_WIRE != arch->Segments[i].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid SPICE model(%s) type of Segment(Length:%d)! Should be chan_wire!\n",
__FILE__ , __LINE__,
arch->Segments[i].spice_model_name,
arch->Segments[i].length);
exit(1);
}
}
/* Step E: Direct connections between CLBs */
for (i = 0; i < arch->num_directs; i++) {
if (NULL == arch->Directs[i].spice_model_name) {
arch->Directs[i].spice_model =
get_default_spice_model(SPICE_MODEL_WIRE,
arch->spice->num_spice_model,
arch->spice->spice_models);
continue;
} else {
arch->Directs[i].spice_model =
find_name_matched_spice_model(arch->Directs[i].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
}
/* Check SPICE model type */
if (NULL == arch->Directs[i].spice_model) {
vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid SPICE model name(%s) of CLB to CLB Direct Connection (name=%s) is undefined in SPICE models!\n",
__FILE__ ,__LINE__,
arch->Directs[i].spice_model_name,
arch->Directs[i].name);
exit(1);
} else if (SPICE_MODEL_CHAN_WIRE != arch->Directs[i].spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid SPICE model(%s) type of CLB to CLB Direct Connection (name=%s)! Should be chan_wire!\n",
__FILE__ , __LINE__,
arch->Directs[i].spice_model_name,
arch->Directs[i].name);
exit(1);
}
/* Copy it to clb2clb_directs */
clb2clb_direct[i].spice_model = arch->Directs[i].spice_model;
}
/* 2. Search Complex Blocks (Pb_Types), Link spice_model according to the spice_model_name*/
for (i = 0; i < num_types; i++) {
if (type_descriptors[i].pb_type) {
match_pb_types_spice_model_rec(type_descriptors[i].pb_type,
arch->spice->num_spice_model,
arch->spice->spice_models);
}
}
/* 3. Initial grid_index_low/high for each spice_model */
for (i = 0; i < arch->spice->num_spice_model; i++) {
alloc_spice_model_grid_index_low_high(&(arch->spice->spice_models[i]));
alloc_spice_model_routing_index_low_high(&(arch->spice->spice_models[i]));
}
/* 4. zero the counter of each spice_model */
zero_spice_models_cnt(arch->spice->num_spice_model, arch->spice->spice_models);
/* 5. zero all index low high */
/*
zero_spice_model_grid_index_low_high(arch->spice->num_spice_model, arch->spice->spice_models);
zero_spice_models_routing_index_low_high(arch->spice->num_spice_model, arch->spice->spice_models);
*/
/* 6. Check each port of a spice model and create link to another spice model */
for (i = 0; i < arch->spice->num_spice_model; i++) {
for (iport = 0; iport < arch->spice->spice_models[i].num_port; iport++) {
/* Set to NULL pointor first */
arch->spice->spice_models[i].ports[iport].spice_model = NULL;
if (NULL != arch->spice->spice_models[i].ports[iport].spice_model_name) {
arch->spice->spice_models[i].ports[iport].spice_model =
find_name_matched_spice_model(arch->spice->spice_models[i].ports[iport].spice_model_name,
arch->spice->num_spice_model,
arch->spice->spice_models);
}
}
}
return;
}
/* Statistics reserved names in pb_types to the list*/
static
void rec_stat_pb_type_keywords(t_pb_type* cur_pb_type,
int* num_keyword) {
int imode, ipb, jpb;
assert((0 == (*num_keyword))||(0 < (*num_keyword)));
assert(NULL != num_keyword);
assert(NULL != cur_pb_type);
for (ipb = 0; ipb < cur_pb_type->num_pb; ipb++) {
for (imode = 0; imode < cur_pb_type->num_modes; imode++) {
/* pb_type_name[num_pb]_mode[mode_name]*/
(*num_keyword) += 1;
for (jpb = 0; jpb < cur_pb_type->modes[imode].num_pb_type_children; jpb++) {
if (NULL == cur_pb_type->modes[imode].pb_type_children[jpb].spice_model) {
rec_stat_pb_type_keywords(&(cur_pb_type->modes[imode].pb_type_children[jpb]),
num_keyword);
}
}
}
}
return;
}
/* Add reserved names in pb_types to the list*/
static
void rec_add_pb_type_keywords_to_list(t_pb_type* cur_pb_type,
int* cur,
char** keywords,
char* prefix) {
int imode, ipb, jpb;
char* formatted_prefix = format_spice_node_prefix(prefix);
char* pass_on_prefix = NULL;
assert(NULL != cur);
assert((0 == (*cur))||(0 < (*cur)));
assert(NULL != keywords);
assert(NULL != cur_pb_type);
/* pb_type_name[num_pb]_mode[mode_name]*/
// num_keyword += cur_pb_type->num_pb * cur_pb_type->num_modes;
for (ipb = 0; ipb < cur_pb_type->num_pb; ipb++) {
for (imode = 0; imode < cur_pb_type->num_modes; imode++) {
keywords[(*cur)] = (char*)my_malloc(sizeof(char)*
(strlen(formatted_prefix) + strlen(cur_pb_type->name) + 1 + strlen(my_itoa(ipb)) + 7
+ strlen(cur_pb_type->modes[imode].name) + 2));
sprintf(keywords[(*cur)], "%s%s[%d]_mode[%s]", formatted_prefix, cur_pb_type->name, ipb, cur_pb_type->modes[imode].name);
pass_on_prefix = my_strdup(keywords[(*cur)]);
(*cur)++;
for (jpb = 0; jpb < cur_pb_type->modes[imode].num_pb_type_children; jpb++) {
if (NULL == cur_pb_type->modes[imode].pb_type_children[jpb].spice_model) {
rec_add_pb_type_keywords_to_list(&(cur_pb_type->modes[imode].pb_type_children[jpb]),
cur, keywords, pass_on_prefix);
my_free(pass_on_prefix);
}
}
}
}
my_free(formatted_prefix);
return;
}
/* This function checks conflicts between
* 1. SPICE model names and reserved sub-circuit names
*/
void check_keywords_conflict(t_arch Arch) {
int num_keyword = 0;
char**keywords;
int conflict = 0;
int num_keyword_per_grid = 0;
int cur, iseg, imodel, i, iport;
int ix, iy, iz;
t_pb_type* cur_pb_type = NULL;
char* prefix = NULL;
t_llist* temp = NULL;
t_spice_model_port* cur_global_port = NULL;
/* Generate the list of reserved names */
num_keyword = 0;
keywords = NULL;
/* Reserved names: grid names */
/* Reserved names: pb_type names */
for (ix = 0; ix < (nx + 2); ix++) {
for (iy = 0; iy < (ny + 2); iy++) {
/* by_pass the empty */
if (EMPTY_TYPE != grid[ix][iy].type) {
num_keyword += 1; /* plus grid[ix][iy]*/
for (iz = 0; iz < grid[ix][iy].type->capacity; iz++) {
num_keyword_per_grid = 0;
/* Per grid, type_descriptor.name[i]*/
/* Go recursive pb_graph_node, until the leaf which defines a spice_model */
cur_pb_type = grid[ix][iy].type->pb_type;
rec_stat_pb_type_keywords(cur_pb_type, &num_keyword_per_grid);
num_keyword += num_keyword_per_grid;
}
}
}
}
/* Reserved names: switch boxes, connection boxes, channels */
/* Channels -X */
num_keyword += (ny+1) * nx;
/* Channels -Y */
num_keyword += (nx+1) * ny;
/* Switch Boxes */
/* sb[ix][iy]*/
num_keyword += (nx + 1)*(ny + 1);
/* Connection Boxes */
/* cbx[ix][iy] */
num_keyword += (ny+1) * nx;
/* cby[ix][iy] */
num_keyword += (nx+1) * ny;
/* internal names: inv, buf, cpt, vpr_nmos, vpr_pmos, wire_segments */
num_keyword += 5 + Arch.num_segments;
/* Include keywords of global ports */
temp = global_ports_head;
while (NULL != temp) {
cur_global_port = (t_spice_model_port*)(temp->dptr);
num_keyword += cur_global_port->size;
temp = temp->next;
}
/* Malloc */
keywords = (char**)my_malloc(sizeof(char*)*num_keyword);
/* Add reserved names to the list */
cur = 0;
for (i = 0; i < num_keyword; i++) {
keywords[i] = NULL;
}
/* Include keywords of global ports */
temp = global_ports_head;
while (NULL != temp) {
cur_global_port = (t_spice_model_port*)(temp->dptr);
for (iport = 0; iport < cur_global_port->size; iport++) {
keywords[cur] = (char*)my_malloc(sizeof(char)*
(strlen(cur_global_port->prefix) + 2 + strlen(my_itoa(iport)) + 1));
sprintf(keywords[cur], "%s[%d]", cur_global_port->prefix, iport);
cur++;
}
temp = temp->next;
}
/* internal names: inv, buf, cpt, vpr_nmos, vpr_pmos, wire_segments */
keywords[cur] = "inv"; cur++;
keywords[cur] = "buf"; cur++;
keywords[cur] = "cpt"; cur++;
keywords[cur] = "vpr_nmos"; cur++;
keywords[cur] = "vpr_pmos"; cur++;
for (iseg = 0; iseg < Arch.num_segments; iseg++) {
keywords[cur] = (char*)my_malloc(sizeof(char)*
(strlen(Arch.Segments[iseg].spice_model->name) + 4 + strlen(my_itoa(iseg)) + 1));
sprintf(keywords[cur], "%s_seg%d", Arch.Segments[iseg].spice_model->name, iseg);
cur++;
}
/* Reserved names: switch boxes, connection boxes, channels */
/* Channels -X */
for (iy = 0; iy < (ny + 1); iy++) {
for (ix = 1; ix < (nx + 1); ix++) {
/* chanx[ix][iy]*/
keywords[cur] = (char*)my_malloc(sizeof(char)* (6 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(keywords[cur], "chanx[%d][%d]", ix, iy);
cur++;
}
}
/* Channels -Y */
for (ix = 0; ix < (nx + 1); ix++) {
for (iy = 1; iy < (ny + 1); iy++) {
/* chany[ix][iy]*/
keywords[cur] = (char*)my_malloc(sizeof(char)* (6 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(keywords[cur], "chany[%d][%d]", ix, iy);
cur++;
}
}
/* Connection Box */
/* cbx[ix][iy]*/
for (iy = 0; iy < (ny + 1); iy++) {
for (ix = 1; ix < (nx + 1); ix++) {
/* cbx[ix][iy]*/
keywords[cur] = (char*)my_malloc(sizeof(char)* (4 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(keywords[cur], "cbx[%d][%d]", ix, iy);
cur++;
}
}
/* cby[ix][iy]*/
for (ix = 0; ix < (nx + 1); ix++) {
for (iy = 1; iy < (ny + 1); iy++) {
/* cby[ix][iy]*/
keywords[cur] = (char*)my_malloc(sizeof(char)* (4 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(keywords[cur], "cby[%d][%d]", ix, iy);
cur++;
}
}
/* Switch Boxes */
for (ix = 0; ix < (nx + 1); ix++) {
for (iy = 0; iy < (ny + 1); iy++) {
/* sb[ix][iy]*/
keywords[cur] = (char*)my_malloc(sizeof(char)* (3 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(keywords[cur], "sb[%d][%d]", ix, iy);
cur++;
}
}
/* Reserved names: grid names */
/* Reserved names: pb_type names */
for (ix = 0; ix < (nx + 2); ix++) {
for (iy = 0; iy < (ny + 2); iy++) {
/* by_pass the empty */
if (EMPTY_TYPE != grid[ix][iy].type) {
prefix = (char*)my_malloc(sizeof(char)* (5 + strlen(my_itoa(ix)) + 2 + strlen(my_itoa(iy)) + 2));
sprintf(prefix, "grid[%d][%d]", ix, iy);
/* plus grid[ix][iy]*/
keywords[cur] = my_strdup(prefix);
cur++;
for (iz = 0; iz < grid[ix][iy].type->capacity; iz++) {
/* Per grid, type_descriptor.name[i]*/
/* Go recursive pb_graph_node, until the leaf which defines a spice_model */
cur_pb_type = grid[ix][iy].type->pb_type;
rec_add_pb_type_keywords_to_list(cur_pb_type, &cur, keywords, prefix);
}
my_free(prefix);
}
}
}
/* assert */
assert(cur == num_keyword);
/* Check the keywords conflicted with defined spice_model names */
for (imodel = 0; imodel < Arch.spice->num_spice_model; imodel++) {
for (i = 0; i < num_keyword; i++) {
if (0 == strcmp(Arch.spice->spice_models[imodel].name, keywords[i])) {
vpr_printf(TIO_MESSAGE_ERROR, "Keyword Conflicted! Spice Model Name: %s\n", keywords[i]);
conflict++;
}
}
}
assert((0 == conflict)||(0 < conflict));
if (0 < conflict) {
vpr_printf(TIO_MESSAGE_ERROR, "Found %d conflicted keywords!\n", conflict);
exit(1);
}
return;
}
/* Need to check if we already a global port with the same name in the list!
* This could happen where two spice models share the same global port
* If this is a new name in the list, we add this global port.
* Otherwise, we do nothing
*/
static
t_llist* check_and_add_one_global_port_to_llist(t_llist* old_head,
t_spice_model_port* candidate_port) {
boolean is_new_global_port = TRUE;
t_llist* temp = old_head;
t_llist* new_head = NULL;
while (NULL != temp) {
if (0 == strcmp(candidate_port->prefix,
((t_spice_model_port*)(temp->dptr))->prefix) ) {
/* Find a same global port name, we do nothing, return directly */
is_new_global_port = FALSE;
return old_head;
}
/* Go to the next */
temp = temp->next;
}
new_head = insert_llist_node_before_head(old_head);
new_head->dptr = (void*)(candidate_port);
return new_head;
}
/* Create and Initialize the global ports
* Search all the ports defined under spice_models
* if a port is defined to be global, we add its pointer to the linked list
*/
static
t_llist* init_llist_global_ports(t_spice* spice) {
int imodel, iport;
t_llist* head = NULL;
/* Traverse all the spice models */
for (imodel = 0; imodel < spice->num_spice_model; imodel++) {
for (iport = 0; iport < spice->spice_models[imodel].num_port; iport++) {
if (TRUE == spice->spice_models[imodel].ports[iport].is_global) {
/* Check each global signal has non conflicted flags :
* At most one of the properties: is_config_enable, is_set and is_reset, can be true */
assert(2 > (spice->spice_models[imodel].ports[iport].is_set
+ spice->spice_models[imodel].ports[iport].is_reset
+ spice->spice_models[imodel].ports[iport].is_config_enable));
/* Add to linked list, the organization will be first-in last-out
* First element would be the tail of linked list
*/
head = check_and_add_one_global_port_to_llist(head,&(spice->spice_models[imodel].ports[iport]));
}
}
}
return head;
}
/* Check how many conflicts of syntax char in a string */
static
int check_conflict_syntax_char_in_string(t_llist* LL_reserved_syntax_char_head,
char* str_to_check) {
int num_conflicts = 0;
int len_str_to_check = strlen(str_to_check);
int ichar = 0;
for (ichar = 0; ichar < len_str_to_check; ichar++) {
if (TRUE == is_verilog_and_spice_syntax_conflict_char(LL_reserved_syntax_char_head,
str_to_check[ichar])) {
/* Print warning */
vpr_printf(TIO_MESSAGE_ERROR, "String (%s) contains conflicted chars[%c] which is not allowed by Verilog and SPICE!\n",
str_to_check, str_to_check[ichar]);
num_conflicts++;
}
}
return num_conflicts;
}
/* Check if each spice_model name contains any syntax char, which is reseved by SPICE or Verilog */
static
void check_spice_model_name_conflict_syntax_char(t_arch Arch,
t_llist* LL_reserved_syntax_char_head) {
int imodel, iport;
int num_conflicts = 0;
/* Check spice_model one by one */
for (imodel = 0; imodel < Arch.spice->num_spice_model; imodel++) {
/* Check spice_model->name */
num_conflicts += check_conflict_syntax_char_in_string(LL_reserved_syntax_char_head,
Arch.spice->spice_models[imodel].name);
/* Check spice_model->prefix */
num_conflicts += check_conflict_syntax_char_in_string(LL_reserved_syntax_char_head,
Arch.spice->spice_models[imodel].prefix);
/* Check each port name */
for (iport = 0; iport < Arch.spice->spice_models[imodel].num_port; iport++) {
num_conflicts += check_conflict_syntax_char_in_string(LL_reserved_syntax_char_head,
Arch.spice->spice_models[imodel].ports[iport].prefix);
}
}
if (0 < num_conflicts) {
/* Print warning */
vpr_printf(TIO_MESSAGE_ERROR, "Fail in syntax char checking, conflicts have been detected!\n");
exit(1);
}
return;
}
/* Initialize a linked-list for syntax char of Verilog and SPICE */
static
t_llist* init_llist_verilog_and_spice_syntax_char() {
t_llist* new_head = NULL;
int num_syntax_chars = 0;
char* syntax_chars = NULL;
t_reserved_syntax_char* new_syntax_char = NULL;
int ichar = 0;
syntax_chars = my_strdup(".,:;\'\"+-<>()[]{}!@#$%^&*~`?/");
num_syntax_chars = strlen(syntax_chars);
/* Create a new element */
for (ichar = 0; ichar < num_syntax_chars; ichar++) {
new_syntax_char = (t_reserved_syntax_char*)(my_malloc(sizeof(t_reserved_syntax_char)));
new_head = insert_llist_node_before_head(new_head);
new_head->dptr = (void*)new_syntax_char;
init_reserved_syntax_char(new_syntax_char, syntax_chars[ichar], TRUE, TRUE);
}
return new_head;
}
/* Check if a char violates the syntax of Verilog and SPICE */
static
boolean is_verilog_and_spice_syntax_conflict_char(t_llist* LL_reserved_syntax_char_head,
char ref_char) {
boolean syntax_conflict = FALSE;
t_llist* temp = LL_reserved_syntax_char_head;
t_reserved_syntax_char* cur_syntax_char = NULL;
/* Search the conflict linked list ? */
while (NULL != temp) {
cur_syntax_char = (t_reserved_syntax_char*)(temp->dptr);
if (ref_char == cur_syntax_char->syntax_char) {
syntax_conflict = TRUE;
break;
}
/* go to the next */
temp = temp->next;
}
return syntax_conflict;
}
/* Check and rename the name of each IO logical block
* if the current name violates syntax of SPICE or Verilog
*/
static
int check_and_rename_logical_block_and_net_names(t_llist* LL_reserved_syntax_char_head,
char* circuit_name,
boolean rename_illegal_port,
int LL_num_logical_blocks, t_logical_block* LL_logical_block,
int LL_num_clb_nets, t_net* LL_clb_net,
int LL_num_vpack_nets, t_net* LL_vpack_net) {
FILE* fp = NULL;
int iblock, inet, ichar, name_str_len, num_violations;
char renamed_char = '_';
boolean io_renamed = FALSE;
boolean io_violate_syntax = FALSE;
char* temp_io_name = NULL;
char* renaming_report_file_path = NULL;
vpr_printf(TIO_MESSAGE_INFO, "Check IO pad names, to avoid violate SPICE or Verilog Syntax...\n");
num_violations = 0;
/* Check if the path exists*/
renaming_report_file_path = my_strcat(circuit_name, renaming_report_postfix);
fp = fopen(renaming_report_file_path,"w");
if (NULL == fp) {
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create renaming report %s!",
__FILE__, __LINE__, renaming_report_file_path);
exit(1);
}
fprintf(fp, "------- Logical block renaming report BEGIN ----------\n");
for (iblock = 0; iblock < LL_num_logical_blocks; iblock++) {
/* Bypass non-IO logical blocks */
/*
if ((VPACK_INPAD != logical_block[iblock].type)&&(VPACK_OUTPAD != logical_block[iblock].type)) {
continue;
}
*/
/* initialize the flag */
io_renamed = FALSE;
io_violate_syntax = FALSE;
/* Keep a copy of previous name */
temp_io_name = my_strdup(LL_logical_block[iblock].name);
/* Check names character by charcter */
name_str_len = strlen(LL_logical_block[iblock].name); /* exclude the last character: \0, which does require to be checked */
for (ichar = 0; ichar < name_str_len; ichar++) {
/* Check syntax senstive list, if violates, rename it to be '_' */
if (TRUE == is_verilog_and_spice_syntax_conflict_char(LL_reserved_syntax_char_head, LL_logical_block[iblock].name[ichar])) {
num_violations++;
io_violate_syntax = TRUE;
if ( TRUE == rename_illegal_port) {
LL_logical_block[iblock].name[ichar] = renamed_char;
io_renamed = TRUE;
}
}
}
/* Print a warning if */
if (TRUE == io_renamed) {
fprintf(fp, "[RENAMING%d] Logical block (Name: %s) is renamed to %s\n",
num_violations,
temp_io_name, LL_logical_block[iblock].name);
} else if (TRUE == io_violate_syntax) {
fprintf(fp, "[RENAMING%d] Logical block name %s violates syntax rules \n",
num_violations,
temp_io_name);
}
/* Free */
my_free(temp_io_name);
}
fprintf(fp, "-------Logical block renaming report END ----------\n\n");
fprintf(fp, "-------CLB_NET renaming report BEGIN ----------\n");
/* Change the net name in the clb_net and vpack_net info as well !!! */
for (inet = 0; inet < LL_num_clb_nets; inet++) {
/* initialize the flag */
io_renamed = FALSE;
io_violate_syntax = FALSE;
/* Keep a copy of previous name */
temp_io_name = my_strdup(LL_clb_net[inet].name);
/* Check names character by charcter */
name_str_len = strlen(LL_clb_net[inet].name); /* exclude the last character: \0, which does require to be checked */
for (ichar = 0; ichar < name_str_len; ichar++) {
/* Check syntax senstive list, if violates, rename it to be '_' */
if (TRUE == is_verilog_and_spice_syntax_conflict_char(LL_reserved_syntax_char_head, LL_clb_net[inet].name[ichar])) {
num_violations++;
io_violate_syntax = TRUE;
if ( TRUE == rename_illegal_port) {
LL_clb_net[inet].name[ichar] = renamed_char;
io_renamed = TRUE;
}
}
}
/* Print a warning if */
if (TRUE == io_renamed) {
fprintf(fp, "[RENAMING%d] clb_net (Name: %s) is renamed to %s\n",
num_violations,
temp_io_name, LL_clb_net[inet].name);
} else if (TRUE == io_violate_syntax) {
fprintf(fp, "[RENAMING%d] clb_net name %s violates syntax rules \n",
num_violations,
temp_io_name);
}
/* Free */
my_free(temp_io_name);
}
fprintf(fp, "-------CLB_NET renaming report END ----------\n\n");
fprintf(fp, "-------VPACK_NET renaming report BEGIN ----------\n");
for (inet = 0; inet < LL_num_vpack_nets; inet++) {
/* initialize the flag */
io_renamed = FALSE;
io_violate_syntax = FALSE;
/* Keep a copy of previous name */
temp_io_name = my_strdup(LL_vpack_net[inet].name);
/* Check names character by charcter */
name_str_len = strlen(LL_vpack_net[inet].name); /* exclude the last character: \0, which does require to be checked */
for (ichar = 0; ichar < name_str_len; ichar++) {
/* Check syntax senstive list, if violates, rename it to be '_' */
if (TRUE == is_verilog_and_spice_syntax_conflict_char(LL_reserved_syntax_char_head, LL_vpack_net[inet].name[ichar])) {
num_violations++;
io_violate_syntax = TRUE;
if ( TRUE == rename_illegal_port) {
LL_vpack_net[inet].name[ichar] = renamed_char;
io_renamed = TRUE;
}
}
}
/* Print a warning if */
if (TRUE == io_renamed) {
fprintf(fp, "[RENAMING%d] vpack_net (Name: %s) is renamed to %s\n",
num_violations,
temp_io_name, LL_vpack_net[inet].name);
} else if (TRUE == io_violate_syntax) {
fprintf(fp, "[RENAMING%d] vpack_net name %s violates syntax rules \n",
num_violations,
temp_io_name);
}
/* Free */
my_free(temp_io_name);
}
fprintf(fp, "-------VPACK_NET renaming report END ----------\n");
if ((0 < num_violations) && ( FALSE == rename_illegal_port )) {
vpr_printf(TIO_MESSAGE_ERROR, "Detect %d port violate syntax rules while renaming port is disabled\n", num_violations);
exit(1);
}
/* close fp */
fclose(fp);
vpr_printf(TIO_MESSAGE_INFO, "Renaming report is generated in %s\n",
renaming_report_file_path);
return num_violations;
}
static
void spice_net_info_add_density_weight(float signal_density_weight) {
int inet;
/* a weight of 1. means no change. directly return */
if ( 1. == signal_density_weight ) {
return;
}
for (inet = 0; inet < num_logical_nets; inet++) {
assert( NULL != vpack_net[inet].spice_net_info );
/* By pass PIs since their signal density is usually high */
if ( TRUE == is_net_pi(&(vpack_net[inet])) ) {
continue;
}
vpack_net[inet].spice_net_info->density *= signal_density_weight;
}
for (inet = 0; inet < num_nets; inet++) {
assert( NULL != clb_net[inet].spice_net_info );
/* By pass PIs since their signal density is usually high */
if ( TRUE == is_net_pi(&(vpack_net[clb_to_vpack_net_mapping[inet]])) ) {
continue;
}
clb_net[inet].spice_net_info->density *= signal_density_weight;
}
}
void fpga_spice_free(t_arch* Arch) {
/* Free index low and high */
free_spice_model_grid_index_low_high(Arch->spice->num_spice_model, Arch->spice->spice_models);
free_spice_model_routing_index_low_high(Arch->spice->num_spice_model, Arch->spice->spice_models);
}
/* Top-level function of FPGA-SPICE setup */
void fpga_spice_setup(t_vpr_setup vpr_setup,
t_arch* Arch) {
int num_clocks = 0;
float vpr_crit_path_delay = 0.;
float vpr_clock_freq = 0.;
float vpr_clock_period = 0.;
vpr_printf(TIO_MESSAGE_INFO, "\nFPGA-SPICE Tool suites Initilization begins...\n");
/* Initialize Arch SPICE MODELS*/
init_check_arch_spice_models(Arch, &(vpr_setup.RoutingArch));
/* Create and initialize a linked list for global ports */
global_ports_head = init_llist_global_ports(Arch->spice);
vpr_printf(TIO_MESSAGE_INFO, "Detect %d global ports...\n",
find_length_llist(global_ports_head) );
/* Build llist for verilog and spice syntax char */
vpr_printf(TIO_MESSAGE_INFO, "Initialize reserved Verilog and SPICE syntax chars...\n");
reserved_syntax_char_head = init_llist_verilog_and_spice_syntax_char();
/* Initialize verilog netlist to be included */
/* Add keyword checking */
check_keywords_conflict(*Arch);
/* TODO: check spice_model names conflict with SPICE or Verilog syntax */
vpr_printf(TIO_MESSAGE_INFO, "Checking spice_model compatible with syntax chars...\n");
check_spice_model_name_conflict_syntax_char(*Arch,
reserved_syntax_char_head);
/* Check and rename io names to avoid violating SPICE or Verilog syntax */
check_and_rename_logical_block_and_net_names(reserved_syntax_char_head,
vpr_setup.FileNameOpts.CircuitName,
vpr_setup.FPGA_SPICE_Opts.rename_illegal_port,
num_logical_blocks, logical_block,
num_nets, clb_net,
num_logical_nets, vpack_net);
/* Check Activity file is valid */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.read_act_file) {
if (1 == try_access_file(vpr_setup.FileNameOpts.ActFile)) {
vpr_printf(TIO_MESSAGE_ERROR,"Activity file (%s) does not exists! Please provide a valid file path!\n",
vpr_setup.FileNameOpts.ActFile);
exit(1);
} else {
vpr_printf(TIO_MESSAGE_INFO,"Check Activity file (%s) is a valid file path!\n",
vpr_setup.FileNameOpts.ActFile);
}
}
/* Update global options:
* 1. run_parasitic_net_estimation
* 2. run_testbench_load_extraction
*/
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_parasitic_net_estimation_off) {
run_parasitic_net_estimation = FALSE;
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_testbench_load_extraction_off) {
run_testbench_load_extraction = FALSE;
vpr_printf(TIO_MESSAGE_WARNING, "SPICE testbench load extraction is turned off...Accuracy loss may be expected!\n");
}
/* Backannotation for post routing information */
spice_backannotate_vpr_post_route_info(vpr_setup.RoutingArch,
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_parasitic_net_estimation_off);
/* Auto check the density and recommend sim_num_clock_cylce */
vpr_crit_path_delay = get_critical_path_delay()/1e9;
assert(vpr_crit_path_delay > 0.);
/* if we don't have global clock, clock_freqency should be set to 0.*/
num_clocks = count_netlist_clocks();
if (0 == num_clocks) {
/* This could a combinational circuit */
vpr_clock_freq = 1. / vpr_crit_path_delay;
} else {
assert(1 == num_clocks);
vpr_clock_freq = 1. / vpr_crit_path_delay;
}
Arch->spice->spice_params.stimulate_params.num_clocks = num_clocks;
Arch->spice->spice_params.stimulate_params.vpr_crit_path_delay = vpr_crit_path_delay;
vpr_clock_period = 1./vpr_clock_freq;
auto_select_num_sim_clock_cycle(Arch->spice, vpr_setup.FPGA_SPICE_Opts.sim_window_size);
/* Determine the clock period */
if (OPEN == Arch->spice->spice_params.stimulate_params.op_clock_freq) {
/* warning the negative slack ! TODO: move to the general check part??? */
if (0. > Arch->spice->spice_params.stimulate_params.sim_clock_freq_slack) {
assert(0. < (1 + Arch->spice->spice_params.stimulate_params.sim_clock_freq_slack));
vpr_printf(TIO_MESSAGE_WARNING, "Slack for clock frequency(=%g) is less than 0! The simulation may fail!\n",
Arch->spice->spice_params.stimulate_params.sim_clock_freq_slack);
}
Arch->spice->spice_params.stimulate_params.op_clock_freq = 1./(vpr_clock_period *(1. + Arch->spice->spice_params.stimulate_params.sim_clock_freq_slack));
} else {
/* Simulate clock frequency should be larger than 0 !*/
assert(0. < Arch->spice->spice_params.stimulate_params.op_clock_freq);
}
vpr_printf(TIO_MESSAGE_INFO, "Use Operation Clock freqency %.2f [MHz] in SPICE simulation.\n",
Arch->spice->spice_params.stimulate_params.op_clock_freq / 1e6);
vpr_printf(TIO_MESSAGE_INFO, "Use Programming Clock freqency %.2f [MHz] in SPICE simulation.\n",
Arch->spice->spice_params.stimulate_params.prog_clock_freq / 1e6);
/* Add weights to spice_net density */
if (!(0 < vpr_setup.FPGA_SPICE_Opts.signal_density_weight)) {
vpr_printf(TIO_MESSAGE_ERROR, "Signal_density_weight(currently is %.2f) should be a positive number!.\n",
vpr_setup.FPGA_SPICE_Opts.signal_density_weight);
exit(1);
}
if (1 != vpr_setup.FPGA_SPICE_Opts.signal_density_weight) {
vpr_printf(TIO_MESSAGE_INFO, "Add %.2f weight to signal density...\n",
vpr_setup.FPGA_SPICE_Opts.signal_density_weight);
spice_net_info_add_density_weight(vpr_setup.FPGA_SPICE_Opts.signal_density_weight);
}
return;
}