/***********************************/ /* SPICE Modeling for VPR */ /* Xifan TANG, EPFL/LSI */ /***********************************/ #include #include #include #include #include #include #include #include /* 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; }