/***********************************/ /* 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 "route_common.h" /* Include spice support headers*/ #include "linkedlist.h" #include "fpga_x2p_globals.h" #include "fpga_x2p_types.h" #include "spice_globals.h" #include "fpga_x2p_utils.h" #include "spice_utils.h" #include "spice_mux.h" #include "spice_lut.h" #include "spice_pbtypes.h" #include "spice_routing.h" #include "spice_subckt.h" /***** Local Subroutines *****/ static int search_tapbuf_llist_same_settings(t_llist* head, t_spice_model_buffer* output_buf); static int generate_spice_basics(char* subckt_dir, t_spice spice); /* Generate the NMOS and PMOS */ int generate_spice_nmos_pmos(char* subckt_dir, t_spice_tech_lib tech_lib) { FILE* fp = NULL; char* sp_name = my_strcat(subckt_dir,nmos_pmos_spice_file_name); /* Standard transistors */ t_spice_transistor_type* nmos_trans = NULL; t_spice_transistor_type* pmos_trans = NULL; /* I/O transistors */ t_spice_transistor_type* io_nmos_trans = NULL; t_spice_transistor_type* io_pmos_trans = NULL; /* Spot NMOS*/ nmos_trans = find_mosfet_tech_lib(tech_lib,SPICE_TRANS_NMOS); if (NULL == nmos_trans) { vpr_printf(TIO_MESSAGE_ERROR,"NMOS transistor is not defined in architecture XML!\n"); exit(1); } /* Spot PMOS*/ pmos_trans = find_mosfet_tech_lib(tech_lib,SPICE_TRANS_PMOS); if (NULL == pmos_trans) { vpr_printf(TIO_MESSAGE_ERROR,"PMOS transistor is not defined in architecture XML!\n"); exit(1); } fp = fopen(sp_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in SPICE netlist for NMOS and PMOS subckt: %s \n", __FILE__, __LINE__, nmos_pmos_spice_file_name); exit(1); } fprint_spice_head(fp,"Standard and I/O NMOS and PMOS"); /* print sub circuit for PMOS*/ fprintf(fp,"* Standard NMOS\n"); fprintf(fp,".subckt %s drain gate source bulk L=nl W=wn\n", nmos_subckt_name); fprintf(fp,"%s1 drain gate source bulk %s L=L W=W\n", tech_lib.model_ref, nmos_trans->model_name); fprintf(fp,".eom %s\n", nmos_subckt_name); fprintf(fp,"\n"); /* Print sub circuit for PMOS*/ fprintf(fp,"* Standard PMOS\n"); fprintf(fp,".subckt %s drain gate source bulk L=pl W=wp\n", pmos_subckt_name); fprintf(fp,"%s1 drain gate source bulk %s L=L W=W\n", tech_lib.model_ref, pmos_trans->model_name); fprintf(fp,".eom %s\n", pmos_subckt_name); /* Spot I/O NMOS*/ io_nmos_trans = find_mosfet_tech_lib(tech_lib,SPICE_TRANS_IO_NMOS); if (NULL == io_nmos_trans) { vpr_printf(TIO_MESSAGE_WARNING,"I/O NMOS transistor is not defined in architecture XML!\n"); } else { /* print sub circuit for NMOS*/ fprintf(fp,"* I/O NMOS\n"); fprintf(fp,".subckt %s drain gate source bulk L=io_nl W=io_wn\n", io_nmos_subckt_name); fprintf(fp,"%s1 drain gate source bulk %s L=L W=W\n", tech_lib.model_ref, io_nmos_trans->model_name); fprintf(fp,".eom %s\n", io_nmos_subckt_name); } /* Spot I/O PMOS*/ io_pmos_trans = find_mosfet_tech_lib(tech_lib,SPICE_TRANS_IO_PMOS); if (NULL == io_pmos_trans) { vpr_printf(TIO_MESSAGE_WARNING,"I/O PMOS transistor is not defined in architecture XML!\n"); } else { /* print sub circuit for PMOS*/ fprintf(fp,"* I/O PMOS\n"); fprintf(fp,".subckt %s drain gate source bulk L=io_pl W=io_wp\n", io_pmos_subckt_name); fprintf(fp,"%s1 drain gate source bulk %s L=L W=W\n", tech_lib.model_ref, io_pmos_trans->model_name); fprintf(fp,".eom %s\n", io_pmos_subckt_name); } fclose(fp); return 1; } static int search_tapbuf_llist_same_settings(t_llist* head, t_spice_model_buffer* output_buf) { t_llist* temp = head; t_spice_model_buffer* cur_out_buf = NULL; /* check */ if ((NULL == output_buf)||(NULL == head)) { return 0; } assert(NULL != output_buf); assert(TRUE == output_buf->tapered_buf); while(temp) { cur_out_buf = (t_spice_model_buffer*)(temp->dptr); assert(TRUE == cur_out_buf->tapered_buf); if ((cur_out_buf->tap_buf_level == output_buf->tap_buf_level) &&(cur_out_buf->f_per_stage == output_buf->f_per_stage)) { return 1; } temp = temp->next; } return 0; } /* Generate the subckt for a normal tapered buffer */ void generate_spice_subckt_tapbuf(FILE* fp, t_spice_model_buffer* output_buf) { int istage, j; if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create top SPICE netlist %s",__FILE__, __LINE__, basics_spice_file_name); exit(1); } assert(NULL != output_buf); assert(TRUE == output_buf->tapered_buf); assert(0 < output_buf->tap_buf_level); assert(0 < output_buf->f_per_stage); /* Definition line */ fprintf(fp, ".subckt tapbuf_level%d_f%d in out svdd sgnd\n", output_buf->tap_buf_level, output_buf->f_per_stage); /* Main body of tapered buffer */ fprintf(fp, "Rinv_in in in_lvl0 0\n"); /* Print each stage */ for (istage = 0; istage < output_buf->tap_buf_level; istage++) { for (j = 0; j < output_buf->size * pow(output_buf->f_per_stage,istage); j++) { fprintf(fp, "Xinv_lvl%d_no%d in_lvl%d in_lvl%d svdd sgnd inv\n", istage, j, istage, istage + 1); } } fprintf(fp, "Rinv_out in_lvl%d out 0\n", output_buf->tap_buf_level); /* End of subckt*/ fprintf(fp, ".eom\n\n"); return; } /* Generate the subckt for a power-gated tapered buffer */ void generate_spice_subckt_powergated_tapbuf(FILE* fp, t_spice_model_buffer* output_buf) { int istage, j; if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create top SPICE netlist %s",__FILE__, __LINE__, basics_spice_file_name); exit(1); } assert(NULL != output_buf); assert(TRUE == output_buf->exist); assert(TRUE == output_buf->tapered_buf); assert(0 < output_buf->tap_buf_level); assert(0 < output_buf->f_per_stage); /* Definition line */ fprintf(fp, ".subckt pg_tapbuf_level%d_f%d en enb in out svdd sgnd\n", output_buf->tap_buf_level, output_buf->f_per_stage); /* Main body of tapered buffer */ fprintf(fp, "Rinv_in in in_lvl0 0\n"); /* Print each stage */ for (istage = 0; istage < output_buf->tap_buf_level; istage++) { for (j = 0; j < output_buf->size * pow(output_buf->f_per_stage,istage); j++) { fprintf(fp, "Xinv_lvl%d_no%d en enb in_lvl%d in_lvl%d svdd sgnd pg_inv size=1 pg_size=1\n", istage, j, istage, istage + 1); } } fprintf(fp, "Rinv_out in_lvl%d out 0\n", output_buf->tap_buf_level); /* End of subckt*/ fprintf(fp, ".eom\n\n"); /* Generate a power-gated tap_buf */ return; } static int generate_spice_basics(char* subckt_dir, t_spice spice) { FILE* fp = NULL; char* sp_name = my_strcat(subckt_dir, basics_spice_file_name); int imodel = 0; t_llist* tapered_bufs_head = NULL; t_llist* temp = NULL; fp = fopen(sp_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create top SPICE netlist %s",__FILE__, __LINE__, basics_spice_file_name); exit(1); } fprint_spice_head(fp,"Inverter, Buffer, Trans. Gate"); /* TODO: support power-gated inverter and buffer ! * We have two options: * 1. Add power-gate transistors to each inverter/buffer * 2. Add huge power-gate transistors to the VDD and GND of inverters */ /* Inverter */ fprintf(fp,"* Inverter\n"); fprintf(fp,".subckt inv in out svdd sgnd size=1\n"); fprintf(fp,"Xn0_inv out in sgnd sgnd %s L=nl W=\'size*wn\'\n",nmos_subckt_name); fprintf(fp,"Xp0_inv out in svdd svdd %s L=pl W=\'size*beta*wp\'\n",pmos_subckt_name); fprintf(fp,".eom inv\n"); fprintf(fp,"\n"); /* Power-gated Inverter */ fprintf(fp,"* Powergated Inverter\n"); fprintf(fp,".subckt pg_inv en enb in out svdd sgnd size=1 pg_size=1\n"); fprintf(fp,"Xn0_inv out in sgnd_pg sgnd %s L=nl W=\'size*wn\'\n",nmos_subckt_name); fprintf(fp,"Xp0_inv out in svdd_pg svdd %s L=pl W=\'size*beta*wp\'\n",pmos_subckt_name); fprintf(fp,"Xn0_inv_pg sgnd_pg en sgnd sgnd %s L=nl W=\'pg_size*wn\'\n",nmos_subckt_name); fprintf(fp,"Xp0_inv_pg svdd_pg enb svdd svdd %s L=pl W=\'pg_size*beta*wp\'\n",pmos_subckt_name); fprintf(fp,".eom inv\n"); fprintf(fp,"\n"); /* Buffer */ fprintf(fp,"* Buffer\n"); fprintf(fp,".subckt buf in out svdd sgnd size=2 base_size=1\n"); fprintf(fp,"Xinv0 in mid svdd sgnd inv base_size='base_size'\n"); fprintf(fp,"Xinv1 mid out svdd sgnd inv size='size*base_size'\n"); fprintf(fp,".eom buf\n"); fprintf(fp,"\n"); /* Power-gated Buffer */ fprintf(fp,"* Power-gated Buffer\n"); fprintf(fp,".subckt pg_buf en enb in out svdd sgnd size=2 pg_size=2\n"); fprintf(fp,"Xinv0 en enb in mid svdd sgnd pg_inv size=1 pg_size=1\n"); fprintf(fp,"Xinv1 en enb mid out svdd sgnd pg_inv size=size pg_size=size\n"); fprintf(fp,".eom buf\n"); fprintf(fp,"\n"); /* Transmission Gate*/ fprintf(fp,"* Transmission Gate (Complementary Pass Transistor)\n"); fprintf(fp,".subckt cpt in out sel sel_inv svdd sgnd nmos_size=1 pmos_size=1\n"); fprintf(fp,"Xn0_cpt in sel out sgnd %s L=nl W=\'nmos_size*wn\'\n", nmos_subckt_name); fprintf(fp,"Xp0_cpt in sel_inv out svdd %s L=pl W=\'pmos_size*wp\'\n", pmos_subckt_name); fprintf(fp,".eom cpt\n"); fprintf(fp,"\n"); /* Tapered buffered support */ for (imodel = 0; imodel < spice.num_spice_model; imodel++) { /* Bypass basic components */ if (SPICE_MODEL_INVBUF != spice.spice_models[imodel].type) { continue; } /* Bypass un tapered buffers */ if (TRUE != spice.spice_models[imodel].design_tech_info.buffer_info->tapered_buf) { continue; } if (NULL == tapered_bufs_head) { tapered_bufs_head = create_llist(1); tapered_bufs_head->dptr = (void*)spice.spice_models[imodel].design_tech_info.buffer_info; } else if (FALSE == search_tapbuf_llist_same_settings(tapered_bufs_head, spice.spice_models[imodel].design_tech_info.buffer_info)) { temp = insert_llist_node(tapered_bufs_head); temp->dptr = (void*)spice.spice_models[imodel].design_tech_info.buffer_info; } } /* Print all the tapered_buf */ temp = tapered_bufs_head; while(temp) { generate_spice_subckt_tapbuf(fp, (t_spice_model_buffer*)(temp->dptr)); temp = temp->next; } fclose(fp); /* Free */ temp = tapered_bufs_head; while(temp) { temp->dptr = NULL; temp = temp->next; } free_llist(tapered_bufs_head); return 1; } void generate_spice_rram_veriloga(char* subckt_dir, t_spice spice) { FILE* fp = NULL; char* sp_name = NULL; int imodel, write_model; /* Check if we need such a verilogA model */ write_model = 0; for (imodel = 0; imodel < spice.num_spice_model; imodel++) { if (SPICE_MODEL_DESIGN_RRAM == spice.spice_models[imodel].design_tech) { write_model = 1; break; } } if (0 == write_model) { return; } else { rram_design_tech = 1; } sp_name = my_strcat(subckt_dir, rram_veriloga_file_name); /* Open a File */ fp = fopen(sp_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create SPICE netlist %s",__FILE__, __LINE__, wires_spice_file_name); exit(1); } fprintf(fp,"// RRAM Behavior VerilogA Mode\n"); /* Include the headers of VerilogA */ fprintf(fp, "`include \"constants.vams\"\n"); fprintf(fp, "`include \"disciplines.vams\"\n"); /* Model */ fprintf(fp, "\n"); fprintf(fp, "module rram_behavior(TE, BE, SRAM, SRAM_INV);\n"); fprintf(fp, "input SRAM, SRAM_INV;\n"); fprintf(fp, "inout TE, BE;\n"); fprintf(fp, "electrical TE, BE, SRAM, SRAM_INV;\n"); fprintf(fp, "// Design Parameters\n"); fprintf(fp, "parameter integer initial_state = 0 from [0:1];\n"); fprintf(fp, "parameter real switch_thres = 1.8 from (0:inf);\n"); fprintf(fp, "parameter real ron = 1e3 from (0:inf);\n"); fprintf(fp, "parameter real roff = 1e6 from (0:inf);\n"); fprintf(fp, "// Local Parameters\n"); fprintf(fp, "real res = roff;\n"); fprintf(fp, "real voltage_tolerence = 0;\n"); fprintf(fp, "integer state = 0;\n"); fprintf(fp, "\n"); fprintf(fp, "analog begin\n"); fprintf(fp, " // Initial\n"); fprintf(fp, " @(initial_step) begin\n"); fprintf(fp, " state = initial_state;\n"); fprintf(fp, " end\n"); fprintf(fp, " // State\n"); fprintf(fp, " if (V(SRAM,SRAM_INV) < voltage_tolerence*switch_thres) begin\n"); fprintf(fp, " state = 0;\n"); fprintf(fp, " end else begin\n"); fprintf(fp, " state = 1;\n"); fprintf(fp, " end\n"); fprintf(fp, " //LRS\n"); fprintf(fp, " if (1 == state) begin\n"); fprintf(fp, " res = ron;\n"); fprintf(fp, " //HRS\n"); fprintf(fp, " end else begin\n"); fprintf(fp, " res = roff;\n"); fprintf(fp, " end\n"); fprintf(fp, " // Correlated Resistance with TE and BE\n"); fprintf(fp, " I(TE,BE) <+ V(TE,BE) / res;\n"); fprintf(fp, "end\n"); fprintf(fp, "endmodule\n"); /* Close File */ fclose(fp); /* Free */ my_free(sp_name); return; } void fprint_spice_wire_model(FILE* fp, char* wire_subckt_name, t_spice_model spice_model, float res_total, float cap_total) { float res_per_level = 0.; float cap_per_level = 0.; int i; int num_input_port = 0; int num_output_port = 0; t_spice_model_port** input_port = NULL; t_spice_model_port** output_port = NULL; /* Ensure a valid file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n", __FILE__, __LINE__); exit(1); } /* Check the wire model*/ assert(NULL != spice_model.wire_param); assert(0 < spice_model.wire_param->level); /* Find the input port, output port*/ input_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE); output_port = find_spice_model_ports(&spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE); /* Asserts*/ assert(1 == num_input_port); assert(1 == num_output_port); assert(1 == input_port[0]->size); assert(1 == output_port[0]->size); /* print the spice model*/ fprintf(fp, "* Wire, spice_model_name=%s\n", spice_model.name); switch (spice_model.type) { case SPICE_MODEL_CHAN_WIRE: /* Add an output at middle point for connecting CB inputs */ fprintf(fp, ".subckt %s %s %s mid_out svdd sgnd\n", wire_subckt_name, input_port[0]->prefix, output_port[0]->prefix); break; case SPICE_MODEL_WIRE: /* Add an output at middle point for connecting CB inputs */ fprintf(fp, ".subckt %s %s %s svdd sgnd\n", wire_subckt_name, input_port[0]->prefix, output_port[0]->prefix); /* Direct shortcut */ if ((0. == cap_per_level)&&(0. == res_per_level) &&(0 == spice_model.input_buffer->exist) &&(0 == spice_model.output_buffer->exist)) { fprintf(fp, "Rshortcut %s %s 0\n", input_port[0]->prefix, output_port[0]->prefix); /* Finish*/ fprintf(fp, ".eom\n"); fprintf(fp, "\n"); return; } break; default: vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid type of spice_model! Expect [chan_wire|wire].\n", __FILE__, __LINE__); exit(1); } /* Determine which type of model to print*/ switch (spice_model.wire_param->type) { case WIRE_MODEL_PIE : /* Determine the resistance and capacitance of each level*/ res_per_level = res_total/((float)(2*spice_model.wire_param->level)); cap_per_level = cap_total/((float)(spice_model.wire_param->level + 1)); if ((0. == cap_per_level)&&(0. == res_per_level)) { /* Special: if R and C are all zeros, we use a zero-voltage source instead */ fprintf(fp, "Vshortcut pie_wire_in%d pie_wire_in%d 0\n", 0, spice_model.wire_param->level); if (SPICE_MODEL_CHAN_WIRE == spice_model.type) { fprintf(fp, "* Connect the output of middle point\n"); fprintf(fp, "Vmid_out_ckt pie_wire_in0 mid_out 0\n"); } i = spice_model.wire_param->level; break; } if (0. != cap_per_level) { fprintf(fp, "Clvin pie_wire_in0 sgnd \'%s%s/%d\'\n", spice_model.name, design_param_postfix_wire_param_cap_val, spice_model.wire_param->level + 1); } for (i = 0; i < spice_model.wire_param->level; i++) { fprintf(fp, "Rlv%d_idx0 pie_wire_in%d pie_wire_in%d_inter \'%s%s/%d\'\n", i, i, i, spice_model.name, design_param_postfix_wire_param_res_val, 2* spice_model.wire_param->level); fprintf(fp, "Rlv%d_idx1 pie_wire_in%d_inter pie_wire_in%d \'%s%s/%d\'\n", i, i, i + 1, spice_model.name, design_param_postfix_wire_param_res_val, 2* spice_model.wire_param->level); if (0. != cap_per_level) { fprintf(fp, "Clv%d_idx1 pie_wire_in%d sgnd \'%s%s/%d\'\n", i, i + 1, spice_model.name, design_param_postfix_wire_param_cap_val, spice_model.wire_param->level + 1); } } if (SPICE_MODEL_CHAN_WIRE == spice_model.type) { /*Connect the middle point */ fprintf(fp, "* Connect the output of middle point\n"); if (0 == spice_model.wire_param->level%2) { fprintf(fp, "Vmid_out_ckt pie_wire_in%d mid_out 0\n", spice_model.wire_param->level/2); } else if (1 == spice_model.wire_param->level%2) { fprintf(fp, "Vmid_out_ckt pie_wire_in%d_inter mid_out 0\n", spice_model.wire_param->level/2); } } break; case WIRE_MODEL_T : /* Determine the resistance and capacitance of each level*/ res_per_level = res_total/((float)(2*spice_model.wire_param->level)); cap_per_level = cap_total/((float)(spice_model.wire_param->level)); if ((0. == cap_per_level)&&(0. == res_per_level)) { fprintf(fp, "Vshortcut pie_wire_in%d pie_wire_in%d 0\n", 0, spice_model.wire_param->level); if (SPICE_MODEL_CHAN_WIRE == spice_model.type) { fprintf(fp, "* Connect the output of middle point\n"); fprintf(fp, "Vmid_out_ckt pie_wire_in0 mid_out 0\n"); } i = spice_model.wire_param->level; break; } for (i = 0; i < spice_model.wire_param->level; i++) { fprintf(fp, "Rlv%d_idx0 pie_wire_in%d pie_wire_in%d_inter \'%s%s/%d\'\n", i, i, i, spice_model.name, design_param_postfix_wire_param_res_val, 2 * spice_model.wire_param->level); if (0. != cap_per_level) { fprintf(fp, "Clv%d_idx1 pie_wire_in%d_inter sgnd \'%s%s/%d\'\n", i, i, spice_model.name, design_param_postfix_wire_param_cap_val, spice_model.wire_param->level); } fprintf(fp, "Rlv%d_idx2 pie_wire_in%d_inter pie_wire_in%d \'%s%s/%d\'\n", i, i, i + 1, spice_model.name, design_param_postfix_wire_param_res_val, 2 * spice_model.wire_param->level); } if (SPICE_MODEL_CHAN_WIRE == spice_model.type) { /*Connect the middle point */ fprintf(fp, "* Connect the output of middle point\n"); if (0 == spice_model.wire_param->level%2) { fprintf(fp, "Vmid_out_ckt pie_wire_in%d mid_out 0\n", spice_model.wire_param->level/2); } else if (1 == spice_model.wire_param->level%2) { fprintf(fp, "Vmid_out_ckt pie_wire_in%d_inter mid_out 0\n", spice_model.wire_param->level/2); } } break; default: vpr_printf(TIO_MESSAGE_INFO,"(File:%s,[LINE%d])Invalid SPICE Wire Model type of spice_model(%s).\n", __FILE__, __LINE__, spice_model.name); exit(1); } assert(i == spice_model.wire_param->level); /* Add input, output buffers*/ assert(NULL != spice_model.input_buffer); if (spice_model.input_buffer->exist) { switch (spice_model.input_buffer->type) { case SPICE_MODEL_BUF_INV: /* Each inv: svdd sgnd size=param*/ fprintf(fp, "Xinv_in "); /* Given name*/ fprintf(fp, "%s ", input_port[0]->prefix); /* input port */ fprintf(fp, "pie_wire_in0 "); /* output port*/ fprintf(fp, "svdd sgnd inv size=\'%s%s\'", spice_model.name, design_param_postfix_input_buf_size); /* subckt name */ fprintf(fp, "\n"); break; case SPICE_MODEL_BUF_BUF: /* TODO: what about tapered buffer, can we support? */ /* Each buf: svdd sgnd size=param*/ fprintf(fp, "Xbuf_in "); /* Given name*/ fprintf(fp, "%s ", input_port[0]->prefix); /* input port */ fprintf(fp, "pie_wire_in0 "); /* output port*/ fprintf(fp, "svdd sgnd buf size=\'%s%s\'", spice_model.name, design_param_postfix_output_buf_size); /* subckt name */ fprintf(fp, "\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n", __FILE__, __LINE__); exit(1); } } else { /* There is no buffer, I create a zero voltage source between*/ /* V 0*/ fprintf(fp, "Rin %s pie_wire_in0 0\n", input_port[0]->prefix); } assert(NULL != spice_model.output_buffer); if (spice_model.output_buffer->exist) { switch (spice_model.output_buffer->type) { case SPICE_MODEL_BUF_INV: /* Each inv: svdd sgnd size=param*/ fprintf(fp, "Xinv_out "); /* Given name*/ fprintf(fp, "pie_wire_in%d ", spice_model.wire_param->level); /* input port */ fprintf(fp, "%s ", output_port[0]->prefix); /* output port*/ fprintf(fp, "svdd sgnd inv size=\'%s%s\'", spice_model.name, design_param_postfix_output_buf_size); /* subckt name */ fprintf(fp, "\n"); break; case SPICE_MODEL_BUF_BUF: /* TODO: what about tapered buffer, can we support? */ /* Each buf: svdd sgnd size=param*/ fprintf(fp, "Xbuf_out "); /* Given name*/ fprintf(fp, "pie_wire_in%d ", spice_model.wire_param->level); /* input port */ fprintf(fp, "%s ", output_port[0]->prefix); /* output port*/ fprintf(fp, "svdd sgnd buf size=\'%s%s\'", spice_model.name, design_param_postfix_output_buf_size); /* subckt name */ fprintf(fp, "\n"); break; default: vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type for spice_model_buffer.\n", __FILE__, __LINE__); exit(1); } } else { /* There is no buffer, I create a zero voltage source between*/ /* V 0*/ fprintf(fp, "Rout pie_wire_in%d %s 0\n", spice_model.wire_param->level, output_port[0]->prefix); } /* Finish*/ fprintf(fp, ".eom\n"); fprintf(fp, "\n"); return; } void generate_spice_wires(char* subckt_dir, int num_segments, t_segment_inf* segments, int num_spice_model, t_spice_model* spice_models) { FILE* fp = NULL; char* sp_name = my_strcat(subckt_dir, wires_spice_file_name); char* seg_wire_subckt_name = NULL; char* seg_index_str = NULL; int iseg, imodel, len_seg_subckt_name; fp = fopen(sp_name, "w"); if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create SPICE netlist %s",__FILE__, __LINE__, wires_spice_file_name); exit(1); } fprint_spice_head(fp,"Wires"); /* Output wire models*/ for (imodel = 0; imodel < num_spice_model; imodel++) { if (SPICE_MODEL_WIRE == spice_models[imodel].type) { assert(NULL != spice_models[imodel].wire_param); fprint_spice_wire_model(fp, spice_models[imodel].name, spice_models[imodel], spice_models[imodel].wire_param->res_val, spice_models[imodel].wire_param->cap_val); } } /* Create wire models for routing segments*/ fprintf(fp,"* Wire models for segments in routing \n"); for (iseg = 0; iseg < num_segments; iseg++) { assert(NULL != segments[iseg].spice_model); assert(SPICE_MODEL_CHAN_WIRE == segments[iseg].spice_model->type); assert(NULL != segments[iseg].spice_model->wire_param); /* Give a unique name for subckt of wire_model of segment, * spice_model name is unique, and segment name is unique as well */ seg_index_str = my_itoa(iseg); len_seg_subckt_name = strlen(segments[iseg].spice_model->name) + 4 + strlen(seg_index_str) + 1; /* '\0'*/ seg_wire_subckt_name = (char*)my_malloc(sizeof(char)*len_seg_subckt_name); sprintf(seg_wire_subckt_name,"%s_seg%s", segments[iseg].spice_model->name, seg_index_str); fprint_spice_wire_model(fp, seg_wire_subckt_name, *(segments[iseg].spice_model), segments[iseg].Rmetal, segments[iseg].Cmetal); } /* Close the file handler */ fclose(fp); /*Free*/ my_free(seg_index_str); my_free(seg_wire_subckt_name); return; } /* Generate the sub circuits for FPGA SPICE Modeling * Tasks: * 1. NMOS and PMOS * 2. Basics: Inverter and Buffers, transmission gates, rc_segements * 3. Multiplexers * 4. Look-Up Tables * 5. Flip-flops */ void generate_spice_subckts(char* subckt_dir, t_arch* arch, t_det_routing_arch* routing_arch, boolean compact_routing_hierarchy) { /* 1.Generate NMOS, PMOS and transmission gate */ vpr_printf(TIO_MESSAGE_INFO,"Writing SPICE NMOS and PMOS...\n"); generate_spice_nmos_pmos(subckt_dir, arch->spice->tech_lib); /* 2. Generate Inverter, Buffer, and transmission gates*/ vpr_printf(TIO_MESSAGE_INFO,"Writing SPICE Basic subckts...\n"); generate_spice_basics(subckt_dir, *(arch->spice)); /* 2.5 Generate RRAM Verilog-A model*/ vpr_printf(TIO_MESSAGE_INFO, "Writing RRAM Behavior Verilog-A model...\n"); generate_spice_rram_veriloga(subckt_dir, (*(arch->spice))); /* 3. Generate Multiplexers */ vpr_printf(TIO_MESSAGE_INFO,"Writing SPICE Multiplexers...\n"); generate_spice_muxes(subckt_dir, routing_arch->num_switch, switch_inf, arch->spice, routing_arch); /* 4. Generate Wires*/ vpr_printf(TIO_MESSAGE_INFO,"Writing SPICE Wires...\n"); generate_spice_wires(subckt_dir, arch->num_segments, arch->Segments, arch->spice->num_spice_model, arch->spice->spice_models); /* 5. Generate LUTs */ vpr_printf(TIO_MESSAGE_INFO,"Writing SPICE LUTs...\n"); generate_spice_luts(subckt_dir, arch->spice->num_spice_model, arch->spice->spice_models); /* 6. Generate Routing architecture*/ vpr_printf(TIO_MESSAGE_INFO, "Writing Routing Resources....\n"); generate_spice_routing_resources(subckt_dir, (*arch), routing_arch, num_rr_nodes, rr_node, rr_node_indices); /* 7. Generate Logic Blocks */ vpr_printf(TIO_MESSAGE_INFO,"Writing Logic Blocks...\n"); generate_spice_logic_blocks(subckt_dir, arch); return; }