447 lines
17 KiB
C
447 lines
17 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 "route_common.h"
|
|
|
|
/* Include spice support headers*/
|
|
#include "read_xml_spice_util.h"
|
|
#include "linkedlist.h"
|
|
#include "fpga_x2p_types.h"
|
|
#include "fpga_x2p_utils.h"
|
|
#include "fpga_x2p_pbtypes_utils.h"
|
|
#include "fpga_x2p_backannotate_utils.h"
|
|
#include "fpga_x2p_globals.h"
|
|
#include "fpga_bitstream.h"
|
|
|
|
|
|
/* Include SPICE generator headers */
|
|
#include "spice_globals.h"
|
|
#include "spice_subckt.h"
|
|
#include "spice_pbtypes.h"
|
|
#include "spice_heads.h"
|
|
#include "spice_lut.h"
|
|
#include "spice_top_netlist.h"
|
|
#include "spice_mux_testbench.h"
|
|
#include "spice_grid_testbench.h"
|
|
#include "spice_routing_testbench.h"
|
|
#include "spice_primitive_testbench.h"
|
|
#include "spice_run_scripts.h"
|
|
|
|
/* For mrFPGA */
|
|
#ifdef MRFPGA_H
|
|
#include "mrfpga_globals.h"
|
|
#endif
|
|
|
|
/* RUN HSPICE Shell Script Name */
|
|
static char* default_spice_dir_path = "spice_netlists/";
|
|
static char* spice_top_tb_dir_name = "top_tb/";
|
|
static char* spice_grid_tb_dir_name = "grid_tb/";
|
|
static char* spice_pb_mux_tb_dir_name = "pb_mux_tb/";
|
|
static char* spice_cb_mux_tb_dir_name = "cb_mux_tb/";
|
|
static char* spice_sb_mux_tb_dir_name = "sb_mux_tb/";
|
|
static char* spice_cb_tb_dir_name = "cb_tb/";
|
|
static char* spice_sb_tb_dir_name = "sb_tb/";
|
|
static char* spice_lut_tb_dir_name = "lut_tb/";
|
|
static char* spice_hardlogic_tb_dir_name = "hardlogic_tb/";
|
|
static char* spice_io_tb_dir_name = "io_tb/";
|
|
|
|
/***** Subroutines Declarations *****/
|
|
static
|
|
void init_list_include_netlists(t_spice* spice);
|
|
|
|
static
|
|
void free_spice_tb_llist();
|
|
|
|
/***** Subroutines *****/
|
|
|
|
static
|
|
void init_list_include_netlists(t_spice* spice) {
|
|
int i, j, cur;
|
|
int to_include = 0;
|
|
int num_to_include = 0;
|
|
|
|
/* Initialize */
|
|
for (i = 0; i < spice->num_include_netlist; i++) {
|
|
FreeSpiceModelNetlist(&(spice->include_netlists[i]));
|
|
}
|
|
my_free(spice->include_netlists);
|
|
spice->include_netlists = NULL;
|
|
spice->num_include_netlist = 0;
|
|
|
|
/* Generate include netlist list */
|
|
vpr_printf(TIO_MESSAGE_INFO, "Listing SPICE Netlist Names to be included...\n");
|
|
for (i = 0; i < spice->num_spice_model; i++) {
|
|
if (NULL != spice->spice_models[i].model_netlist) {
|
|
/* Check if this netlist name has already existed in the list */
|
|
to_include = 1;
|
|
for (j = 0; j < i; j++) {
|
|
if (NULL == spice->spice_models[j].model_netlist) {
|
|
continue;
|
|
}
|
|
if (0 == strcmp(spice->spice_models[j].model_netlist, spice->spice_models[i].model_netlist)) {
|
|
to_include = 0;
|
|
break;
|
|
}
|
|
}
|
|
/* Increamental */
|
|
if (1 == to_include) {
|
|
num_to_include++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* realloc */
|
|
spice->include_netlists = (t_spice_model_netlist*)my_realloc(spice->include_netlists,
|
|
sizeof(t_spice_model_netlist)*(num_to_include + spice->num_include_netlist));
|
|
|
|
/* Fill the new included netlists */
|
|
cur = spice->num_include_netlist;
|
|
for (i = 0; i < spice->num_spice_model; i++) {
|
|
if (NULL != spice->spice_models[i].model_netlist) {
|
|
/* Check if this netlist name has already existed in the list */
|
|
to_include = 1;
|
|
for (j = 0; j < i; j++) {
|
|
if (NULL == spice->spice_models[j].model_netlist) {
|
|
continue;
|
|
}
|
|
if (0 == strcmp(spice->spice_models[j].model_netlist, spice->spice_models[i].model_netlist)) {
|
|
to_include = 0;
|
|
break;
|
|
}
|
|
}
|
|
/* Increamental */
|
|
if (1 == to_include) {
|
|
spice->include_netlists[cur].path = my_strdup(spice->spice_models[i].model_netlist);
|
|
spice->include_netlists[cur].included = 0;
|
|
vpr_printf(TIO_MESSAGE_INFO, "[%d] %s\n", cur+1, spice->include_netlists[cur].path);
|
|
cur++;
|
|
}
|
|
}
|
|
}
|
|
/* Check */
|
|
assert(cur == (num_to_include + spice->num_include_netlist));
|
|
/* Update */
|
|
spice->num_include_netlist += num_to_include;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void free_spice_tb_llist() {
|
|
t_llist* temp = tb_head;
|
|
|
|
while (temp) {
|
|
my_free(((t_spicetb_info*)(temp->dptr))->tb_name);
|
|
my_free(temp->dptr);
|
|
temp->dptr = NULL;
|
|
temp = temp->next;
|
|
}
|
|
free_llist(tb_head);
|
|
|
|
return;
|
|
}
|
|
|
|
/***** Main Function *****/
|
|
void vpr_fpga_spice(t_vpr_setup vpr_setup,
|
|
t_arch Arch,
|
|
char* circuit_name) {
|
|
clock_t t_start;
|
|
clock_t t_end;
|
|
float run_time_sec;
|
|
|
|
int num_clocks = Arch.spice->spice_params.stimulate_params.num_clocks;
|
|
int vpr_crit_path_delay = Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay;
|
|
|
|
char* spice_dir_formatted = NULL;
|
|
char* include_dir_path = NULL;
|
|
char* subckt_dir_path = NULL;
|
|
char* top_netlist_path = NULL;
|
|
char* include_dir_name = vpr_setup.FPGA_SPICE_Opts.SpiceOpts.include_dir;
|
|
char* subckt_dir_name = vpr_setup.FPGA_SPICE_Opts.SpiceOpts.subckt_dir;
|
|
char* chomped_circuit_name = NULL;
|
|
char* chomped_spice_dir = NULL;
|
|
char* top_testbench_dir_path = NULL;
|
|
char* pb_mux_testbench_dir_path = NULL;
|
|
char* cb_mux_testbench_dir_path = NULL;
|
|
char* sb_mux_testbench_dir_path = NULL;
|
|
char* cb_testbench_dir_path = NULL;
|
|
char* sb_testbench_dir_path = NULL;
|
|
char* grid_testbench_dir_path = NULL;
|
|
char* lut_testbench_dir_path = NULL;
|
|
char* hardlogic_testbench_dir_path = NULL;
|
|
char* io_testbench_dir_path = NULL;
|
|
char* top_testbench_file = NULL;
|
|
char* bitstream_file_name = NULL;
|
|
char* bitstream_file_path = NULL;
|
|
|
|
/* Check if the routing architecture we support*/
|
|
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
|
vpr_printf(TIO_MESSAGE_ERROR, "FPGA SPICE netlists only support uni-directional routing architecture!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* We don't support mrFPGA */
|
|
#ifdef MRFPGA_H
|
|
if (is_mrFPGA) {
|
|
vpr_printf(TIO_MESSAGE_ERROR, "FPGA SPICE netlists do not support mrFPGA!\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
/* assign the global variable of SRAM model */
|
|
assert(NULL != Arch.sram_inf.spice_sram_inf_orgz); /* Check !*/
|
|
sram_spice_model = Arch.sram_inf.spice_sram_inf_orgz->spice_model;
|
|
sram_spice_orgz_type = Arch.sram_inf.spice_sram_inf_orgz->type;
|
|
/* initialize the SRAM organization information struct */
|
|
sram_spice_orgz_info = alloc_one_sram_orgz_info();
|
|
init_sram_orgz_info(sram_spice_orgz_info, sram_spice_orgz_type, sram_spice_model, nx + 2, ny + 2);
|
|
/* Report error: SPICE part only support standalone SRAMs */
|
|
if (SPICE_SRAM_STANDALONE != sram_spice_orgz_info->type) {
|
|
vpr_printf(TIO_MESSAGE_ERROR, "Currently FPGA SPICE netlist only support standalone SRAM organization!\n");
|
|
exit(1);
|
|
}
|
|
/* Check all the SRAM port is using the correct SRAM SPICE MODEL */
|
|
config_spice_models_sram_port_spice_model(Arch.spice->num_spice_model,
|
|
Arch.spice->spice_models,
|
|
Arch.sram_inf.spice_sram_inf_orgz->spice_model);
|
|
|
|
/* Assign global variables of input and output pads */
|
|
iopad_spice_model = find_iopad_spice_model(Arch.spice->num_spice_model, Arch.spice->spice_models);
|
|
assert(NULL != iopad_spice_model);
|
|
|
|
/* Initial Arch SPICE MODELS*/
|
|
/* zero the counter of each spice_model */
|
|
zero_spice_models_cnt(Arch.spice->num_spice_model, Arch.spice->spice_models);
|
|
|
|
/* Move to the top-level function: vpr_fpga_spice_tool_suits */
|
|
/* init_check_arch_spice_models(&Arch, &vpr_setup.RoutingArch); */
|
|
init_list_include_netlists(Arch.spice);
|
|
|
|
/* Initialize the number of configuration bits of all the grids */
|
|
init_grids_num_conf_bits(sram_spice_orgz_info);
|
|
init_grids_num_iopads();
|
|
|
|
/* Add keyword checking */
|
|
/* Move to the top-level function: vpr_fpga_spice_tool_suits */
|
|
/* check_keywords_conflict(Arch); */
|
|
|
|
/*Process the circuit name*/
|
|
split_path_prog_name(circuit_name,'/',&chomped_spice_dir ,&chomped_circuit_name);
|
|
|
|
/* Update the global variable :
|
|
* the number of mutli-thread used in SPICE simulator */
|
|
spice_sim_multi_thread_num = vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_sim_multi_thread_num;
|
|
|
|
/* FPGA-SPICE formally starts*/
|
|
vpr_printf(TIO_MESSAGE_INFO, "\nFPGA-SPICE starts...\n");
|
|
|
|
/* Start Clocking*/
|
|
t_start = clock();
|
|
|
|
/* Format the directory path */
|
|
if (NULL != vpr_setup.FPGA_SPICE_Opts.SpiceOpts.spice_dir) {
|
|
spice_dir_formatted = format_dir_path(vpr_setup.FPGA_SPICE_Opts.SpiceOpts.spice_dir);
|
|
} else {
|
|
spice_dir_formatted = format_dir_path(my_strcat(format_dir_path(chomped_spice_dir),
|
|
default_spice_dir_path));
|
|
}
|
|
|
|
/*Initial directory organization*/
|
|
/* Process include directory */
|
|
(include_dir_path) = my_strcat(spice_dir_formatted,include_dir_name);
|
|
/* Process subckt directory */
|
|
(subckt_dir_path) = my_strcat(spice_dir_formatted,subckt_dir_name);
|
|
|
|
/* Check the spice folders exists if not we create it.*/
|
|
create_dir_path(spice_dir_formatted);
|
|
create_dir_path(include_dir_path);
|
|
create_dir_path(subckt_dir_path);
|
|
|
|
/* Generate Header files */
|
|
spice_print_headers(include_dir_path, vpr_crit_path_delay, num_clocks, *(Arch.spice));
|
|
|
|
/* Generate sub circuits: Inverter, Buffer, Transmission Gate, LUT, DFF, SRAM, MUX*/
|
|
generate_spice_subckts(subckt_dir_path, &Arch ,&vpr_setup.RoutingArch, vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
|
|
|
/* Print MUX testbench if needed */
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_pb_mux_testbench) {
|
|
pb_mux_testbench_dir_path = my_strcat(spice_dir_formatted, spice_pb_mux_tb_dir_name);
|
|
create_dir_path(pb_mux_testbench_dir_path);
|
|
spice_print_mux_testbench(pb_mux_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
SPICE_PB_MUX_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(pb_mux_testbench_dir_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_cb_mux_testbench) {
|
|
cb_mux_testbench_dir_path = my_strcat(spice_dir_formatted, spice_cb_mux_tb_dir_name);
|
|
create_dir_path(cb_mux_testbench_dir_path);
|
|
spice_print_mux_testbench(cb_mux_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch, SPICE_CB_MUX_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(cb_mux_testbench_dir_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_sb_mux_testbench) {
|
|
sb_mux_testbench_dir_path = my_strcat(spice_dir_formatted, spice_sb_mux_tb_dir_name);
|
|
create_dir_path(sb_mux_testbench_dir_path);
|
|
spice_print_mux_testbench(sb_mux_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch, SPICE_SB_MUX_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(sb_mux_testbench_dir_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_cb_testbench) {
|
|
cb_testbench_dir_path = my_strcat(spice_dir_formatted, spice_cb_tb_dir_name);
|
|
create_dir_path(cb_testbench_dir_path);
|
|
spice_print_cb_testbench(cb_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(cb_testbench_dir_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_sb_testbench) {
|
|
sb_testbench_dir_path = my_strcat(spice_dir_formatted, spice_sb_tb_dir_name);
|
|
create_dir_path(sb_testbench_dir_path);
|
|
spice_print_sb_testbench(sb_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(sb_testbench_dir_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_lut_testbench) {
|
|
lut_testbench_dir_path = my_strcat(spice_dir_formatted, spice_lut_tb_dir_name);
|
|
create_dir_path(lut_testbench_dir_path);
|
|
spice_print_primitive_testbench(lut_testbench_dir_path,
|
|
chomped_circuit_name, include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
SPICE_LUT_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(lut_testbench_dir_path);
|
|
}
|
|
|
|
/* Print hardlogic testbench file if needed */
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_hardlogic_testbench) {
|
|
hardlogic_testbench_dir_path = my_strcat(spice_dir_formatted, spice_hardlogic_tb_dir_name);
|
|
create_dir_path(hardlogic_testbench_dir_path);
|
|
spice_print_primitive_testbench(hardlogic_testbench_dir_path,
|
|
chomped_circuit_name, include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
SPICE_HARDLOGIC_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(hardlogic_testbench_dir_path);
|
|
}
|
|
|
|
/* Print IO testbench file if needed */
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_io_testbench) {
|
|
io_testbench_dir_path = my_strcat(spice_dir_formatted, spice_io_tb_dir_name);
|
|
create_dir_path(io_testbench_dir_path);
|
|
spice_print_primitive_testbench(io_testbench_dir_path,
|
|
chomped_circuit_name, include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
SPICE_IO_TB,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(io_testbench_dir_path);
|
|
}
|
|
|
|
|
|
/* Print Grid testbench if needed */
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_grid_testbench) {
|
|
grid_testbench_dir_path = my_strcat(spice_dir_formatted, spice_grid_tb_dir_name);
|
|
create_dir_path(grid_testbench_dir_path);
|
|
spice_print_grid_testbench(grid_testbench_dir_path, chomped_circuit_name,
|
|
include_dir_path, subckt_dir_path,
|
|
rr_node_indices, num_clocks, Arch,
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(grid_testbench_dir_path);
|
|
}
|
|
|
|
/* Print Netlists of the given FPGA*/
|
|
if (vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_print_top_testbench) {
|
|
top_testbench_file = my_strcat(chomped_circuit_name, spice_top_testbench_postfix);
|
|
/* Process top_netlist_path */
|
|
top_testbench_dir_path = my_strcat(spice_dir_formatted, spice_top_tb_dir_name);
|
|
create_dir_path(top_testbench_dir_path);
|
|
top_netlist_path = my_strcat(top_testbench_dir_path, top_testbench_file);
|
|
spice_print_top_netlist(chomped_circuit_name, top_netlist_path,
|
|
include_dir_path, subckt_dir_path,
|
|
num_rr_nodes, rr_node, rr_node_indices, num_clocks, *(Arch.spice),
|
|
vpr_setup.FPGA_SPICE_Opts.SpiceOpts.fpga_spice_leakage_only);
|
|
/* Free */
|
|
my_free(top_testbench_dir_path);
|
|
my_free(top_testbench_file);
|
|
my_free(top_netlist_path);
|
|
}
|
|
|
|
if (vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream) {
|
|
if (NULL == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.bitstream_output_file) {
|
|
bitstream_file_name = my_strcat(chomped_circuit_name, fpga_spice_bitstream_output_file_postfix);
|
|
bitstream_file_path = my_strcat(spice_dir_formatted, bitstream_file_name);
|
|
} else {
|
|
bitstream_file_path = my_strdup(vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.bitstream_output_file);
|
|
}
|
|
/* Dump bitstream file */
|
|
dump_fpga_spice_bitstream(bitstream_file_path, chomped_circuit_name, sram_spice_orgz_info);
|
|
/* Free */
|
|
my_free(bitstream_file_name);
|
|
my_free(bitstream_file_path);
|
|
}
|
|
|
|
/* Generate a shell script for running HSPICE simulations */
|
|
fprint_run_hspice_shell_script(*(Arch.spice), vpr_setup.FPGA_SPICE_Opts.SpiceOpts.simulator_path,
|
|
spice_dir_formatted, subckt_dir_path);
|
|
|
|
/* END Clocking*/
|
|
t_end = clock();
|
|
|
|
run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
|
vpr_printf(TIO_MESSAGE_INFO, "SPICE netlists dumping took %g seconds\n", run_time_sec);
|
|
|
|
/* Free sram_orgz_info */
|
|
free_sram_orgz_info(sram_spice_orgz_info,
|
|
sram_spice_orgz_info->type);
|
|
/* Free tb_llist */
|
|
free_spice_tb_llist();
|
|
/* Free */
|
|
my_free(spice_dir_formatted);
|
|
my_free(include_dir_path);
|
|
my_free(subckt_dir_path);
|
|
|
|
return;
|
|
}
|