OpenFPGA/vpr7_x2p/vpr/SRC/fpga_x2p/spice/spice_api.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;
}