From 5bb40e7f7420b13e37b2ff482cb99dfa1dc50826 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 25 Sep 2019 21:05:02 -0600 Subject: [PATCH] refactored local wire generation for Switch block --- .../vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp | 75 ++++++++++- .../vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h | 5 + .../fpga_x2p/base/link_arch_circuit_lib.cpp | 8 +- .../fpga_x2p/base/module_manager_utils.cpp | 2 + .../vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp | 30 ++++- .../vpr/SRC/fpga_x2p/base/rr_blocks_utils.h | 2 + .../SRC/fpga_x2p/verilog/verilog_routing.c | 47 +++++-- .../fpga_x2p/verilog/verilog_writer_utils.cpp | 123 ++++++++++++++++++ .../fpga_x2p/verilog/verilog_writer_utils.h | 6 + 9 files changed, 275 insertions(+), 23 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp index db19f59f2..3bb812ae7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp @@ -307,8 +307,6 @@ std::string generate_reserved_sram_port_name(const e_spice_model_port_type& port /********************************************************************* * Generate the port name for a sram port, used for formal verification * The port name is named after the cell name of SRAM in circuit library - * TODO: - * Use the new refactored data structure to replace the t_sram_orgz_info *********************************************************************/ std::string generate_formal_verification_sram_port_name(const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model) { @@ -318,17 +316,14 @@ std::string generate_formal_verification_sram_port_name(const CircuitLibrary& ci } /********************************************************************* - * Generate the port name for a regular sram port + * Generate the port name for a regular sram port which appears in the + * port list of a module * The port name is named after the cell name of SRAM in circuit library - * TODO: - * Use the new refactored data structure to replace the t_sram_orgz_info *********************************************************************/ std::string generate_sram_port_name(const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model, const e_sram_orgz& sram_orgz_type, const e_spice_model_port_type& port_type) { - /* Get memory_model */ - std::string port_name = circuit_lib.model_name(sram_model) + std::string("_"); switch (sram_orgz_type) { @@ -395,3 +390,69 @@ std::string generate_sram_port_name(const CircuitLibrary& circuit_lib, return port_name; } + +/********************************************************************* + * Generate the port name for a regular sram port which is an internal + * wire of a module + * The port name is named after the cell name of SRAM in circuit library + *********************************************************************/ +std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz& sram_orgz_type, + const e_spice_model_port_type& port_type) { + std::string port_name = circuit_lib.model_name(sram_model) + std::string("_"); + + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: { + /* Two types of ports are available: + * (1) Regular output of a SRAM, enabled by port type of INPUT + * (2) Inverted output of a SRAM, enabled by port type of OUTPUT + */ + if (SPICE_MODEL_PORT_INPUT == port_type) { + port_name += std::string("out_local_bus"); + } else { + VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type ); + port_name += std::string("outb_local_bus"); + } + break; + } + case SPICE_SRAM_SCAN_CHAIN: + /* Three types of ports are available: + * (1) Input of Scan-chain Flip-Flops (SCFFs), enabled by port type of INPUT + * (2) Output of a chian of Scan-chain Flip-flops (SCFFs), enabled by port type of OUTPUT + * (2) Inverted output of a chian of Scan-chain Flip-flops (SCFFs), enabled by port type of INOUT + * +------+ +------+ +------+ + * Head --->| SCFF |--->| SCFF |--->| SCFF |---> Tail + * +------+ +------+ +------+ + */ + if (SPICE_MODEL_PORT_INPUT == port_type) { + port_name += std::string("scff_in_local_bus"); + } else if ( SPICE_MODEL_PORT_OUTPUT == port_type ) { + port_name += std::string("scff_out_local_bus"); + } else { + VTR_ASSERT( SPICE_MODEL_PORT_INOUT == port_type ); + port_name += std::string("scff_outb_local_bus"); + } + break; + case SPICE_SRAM_MEMORY_BANK: { + /* Two types of ports are available: + * (1) Regular output of a SRAM, enabled by port type of INPUT + * (2) Inverted output of a SRAM, enabled by port type of OUTPUT + */ + if (SPICE_MODEL_PORT_INPUT == port_type) { + port_name += std::string("out_local_bus"); + } else { + VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type ); + port_name += std::string("outb_local_bus"); + } + break; + } + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization !\n", + __FILE__, __LINE__); + exit(1); + } + + return port_name; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h index 732f47e5f..bf78578d9 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h @@ -77,4 +77,9 @@ std::string generate_sram_port_name(const CircuitLibrary& circuit_lib, const e_sram_orgz& sram_orgz_type, const e_spice_model_port_type& port_type); +std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz& sram_orgz_type, + const e_spice_model_port_type& port_type); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp index 342524903..579ae9631 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp @@ -482,7 +482,7 @@ void link_circuit_library_to_arch(t_arch* arch, /* Check Circuit models first*/ VTR_ASSERT_SAFE( (NULL != arch) && (NULL != arch->spice) ); - /* 1. Link the spice model defined in pb_types and routing switches */ + /* 1. Link the circuit model defined in pb_types and routing switches */ /* Step A: Check routing switches, connection blocks*/ if (0 >= arch->num_cb_switch) { vpr_printf(TIO_MESSAGE_ERROR, @@ -500,7 +500,7 @@ void link_circuit_library_to_arch(t_arch* arch, __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 */ + /* Check the circuit model structure is matched with the structure in switch_inf */ if (0 < check_circuit_model_structure_match_switch_inf(arch->cb_switches[i], arch->spice->circuit_lib)) { exit(1); } @@ -544,7 +544,7 @@ void link_circuit_library_to_arch(t_arch* arch, /* Step C: Find SRAM Model*/ link_sram_inf(&(arch->sram_inf), arch->spice->circuit_lib); - /* Step D: Find the segment spice_model*/ + /* Step D: Find the segment circuit_model*/ for (int i = 0; i < arch->num_segments; i++) { arch->Segments[i].circuit_model = link_circuit_model_by_name_and_type(arch->Segments[i].spice_model_name, arch->spice->circuit_lib, SPICE_MODEL_CHAN_WIRE); @@ -562,7 +562,7 @@ void link_circuit_library_to_arch(t_arch* arch, for (int i = 0; i < arch->num_directs; i++) { arch->Directs[i].circuit_model = link_circuit_model_by_name_and_type(arch->Directs[i].spice_model_name, arch->spice->circuit_lib, SPICE_MODEL_WIRE); - /* Check SPICE model type */ + /* Check Circuit model type */ if (CircuitModelId::INVALID() == arch->Directs[i].circuit_model) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid circuit model name(%s) of CLB to CLB Direct Connection (name=%s) is undefined in circuit models!\n", diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp index bc844ca7c..2694a02a0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp @@ -140,6 +140,8 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_ * 2. Scan-chain Flip-flops: * two ports will be added, which are the head of scan-chain * and the tail of scan-chain + * IMPORTANT: the port size will be forced to 1 in this case + * because the head and tail are both 1-bit ports!!! * 3. Memory decoders: * 2-4 ports will be added, depending on the ports available in the SRAM * Among these, two ports are mandatory: BL and WL diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp index 4965cf482..a078ed535 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp @@ -11,7 +11,7 @@ /********************************************************************* * This function will find the global ports required by a Switch Block - * module. It wil find all the circuit models in the circuit library + * module. It will find all the circuit models in the circuit library * that may be included in the Switch Block * Collect the global ports from the circuit_models and merge with the same name ********************************************************************/ @@ -60,3 +60,31 @@ std::vector find_switch_block_global_ports(const RRGSB& rr_gsb, return global_ports; } + +/********************************************************************* + * This function will find the number of multiplexers required by + * a Switch Block module. + ********************************************************************/ +size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb) { + size_t num_muxes = 0; + /* Walk through the OUTPUT nodes at each side of a GSB, + * get the switch id of incoming edges + * and get the circuit model linked to the switch id + */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + continue; + } + /* Check if this node is driven by a multiplexer */ + if (true == rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) { + continue; + } + /* This means we need a multiplexer, update the counter */ + num_muxes++; + } + } + return num_muxes; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h index 84c451239..d49a55539 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h @@ -14,4 +14,6 @@ std::vector find_switch_block_global_ports(const RRGSB& rr_gsb, const CircuitLibrary& circuit_lib, const std::vector& switch_lib); +size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index d9f135892..8e5ece925 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -48,6 +48,27 @@ #include "verilog_writer_utils.h" #include "verilog_routing.h" +/******************************************************************** + * Print local wires that are used for SRAM configuration + * This function is supposed to be used by Verilog generation + * of switch blocks + * It will count the number of switch blocks, which is the + * port width for local wires when Configuration chain is used + ********************************************************************/ +static +void print_verilog_switch_block_local_sram_wires(std::fstream& fp, + const RRGSB& rr_gsb, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz sram_orgz_type, + const size_t& port_size) { + size_t local_port_size = port_size; + if (SPICE_SRAM_SCAN_CHAIN == sram_orgz_type) { + local_port_size = find_switch_block_number_of_muxes(rr_gsb); + } + print_verilog_local_sram_wires(fp, circuit_lib, sram_model, sram_orgz_type, local_port_size); +} + /********************************************************************* * Generate the Verilog module for a routing channel * Routing track wire, which is 1-input and dual output @@ -2287,13 +2308,15 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage add_reserved_sram_ports_to_module_manager(module_manager, module_id, rr_gsb.get_sb_num_reserved_conf_bits()); } + + /* TODO: this should be added to the cur_sram_orgz_info !!! */ + t_spice_model* mem_model = NULL; + get_sram_orgz_info_mem_model(cur_sram_orgz_info, & mem_model); + CircuitModelId sram_model = circuit_lib.model(mem_model->name); + VTR_ASSERT(CircuitModelId::INVALID() != sram_model); + /* Normal sram ports */ if (0 < rr_gsb.get_sb_num_conf_bits()) { - /* TODO: this should be added to the cur_sram_orgz_info !!! */ - t_spice_model* mem_model = NULL; - get_sram_orgz_info_mem_model(cur_sram_orgz_info, & mem_model); - CircuitModelId sram_model = circuit_lib.model(mem_model->name); - VTR_ASSERT(CircuitModelId::INVALID() != sram_model); add_sram_ports_to_module_manager(module_manager, module_id, circuit_lib, sram_model, cur_sram_orgz_info->type, rr_gsb.get_sb_num_conf_bits()); @@ -2308,12 +2331,14 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage print_verilog_module_declaration(fp, module_manager, module_id); /* Finish printing ports */ - /* TODO: Local wires for memory configurations */ - /* - dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info, - rr_gsb.get_sb_conf_bits_lsb(), - rr_gsb.get_sb_conf_bits_msb()); - */ + print_verilog_comment(fp, std::string("---- BEGIN local wires for SRAM data ports ----")); + /* Local wires for memory configurations */ + print_verilog_switch_block_local_sram_wires(fp, rr_gsb, circuit_lib, sram_model, cur_sram_orgz_info->type, + rr_gsb.get_sb_num_conf_bits()); + print_verilog_comment(fp, std::string("---- END local wires for SRAM data ports ----")); + + /* TODO: Print routing multiplexers */ + /* Put an end to the Verilog module */ print_verilog_module_end(fp, module_manager.module_name(module_id)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp index ce504a143..9f373308e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp @@ -12,6 +12,7 @@ /* FPGA-X2P context header files */ #include "spice_types.h" +#include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" /* FPGA-Verilog context header files */ @@ -646,3 +647,125 @@ void print_verilog_buffer_instance(std::fstream& fp, module_manager.add_child_module(parent_module_id, buffer_module_id); } +/******************************************************************** + * Print local wires that are used for SRAM configuration + * The local wires are strongly dependent on the organization of SRAMs. + * 1. Standalone SRAMs: + * No need for local wires, their outputs are port of the module + * + * Module + * +------------------------------+ + * | Sub-module | + * | +---------------------+ | + * | | sram_out|---->|---->sram_out + * | | | | + * | | sram_out|---->|---->sram_out + * | | | | + * | +---------------------+ | + * +------------------------------+ + * + * 2. Configuration-chain Flip-flops: + * two ports will be added, which are the head of scan-chain + * and the tail of scan-chain + * + * Module + * +-----------------------------------------+ + * | | + * | +------+ +------+ +------+ | + * | +->| CCFF |--->| CCFF | ... | CCFF |-+ | + * | | +------+ | +------+ | +------+ | | + * head--->|-+-----------+------------+-----------+->|--->tail + * | local wire | + * +-----------------------------------------+ + * 3. Memory decoders: + * two ports will be added, which are regular output and inverted output + * Note that the outputs are the data outputs of SRAMs + * BL/WLs of memory decoders are ports of module but not local wires + * + * Module + * +-----------------------------------------+ + * | | + * | +------+ +------+ +------+ | + * | | SRAM | | SRAM | ... | SRAM | | + * | +------+ +------+ +------+ | + * | ^ ^ ^ | + * | | | | | + * BL/WL--->|---------------------------------------->| + * | local wire | + * +-----------------------------------------+ + + * + ********************************************************************/ +void print_verilog_local_sram_wires(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz sram_orgz_type, + const size_t& port_size) { + /* Make sure we have a valid file handler*/ + check_file_handler(fp); + + /* Port size must be at least one! */ + if (0 == port_size) { + return; + } + + /* Depend on the configuraion style */ + switch(sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Nothing to do here */ + break; + case SPICE_SRAM_SCAN_CHAIN: { + /* Generate the name of local wire for the CCFF inputs, CCFF output and inverted output */ + std::vector ccff_ports; + /* [0] => CCFF input */ + ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), port_size)); + /* [1] => CCFF output */ + ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), port_size)); + /* [2] => CCFF inverted output */ + ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INOUT), port_size)); + /* Print local wire definition */ + for (const auto& ccff_port : ccff_ports) { + fp << generate_verilog_port(VERILOG_PORT_WIRE, ccff_port) << ";" << std::endl; + } + /* Connect first CCFF to the head */ + /* Head is always a 1-bit port */ + BasicPort ccff_head_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), 1); + BasicPort ccff_head_local_port(ccff_ports[0].get_name(), 1); + print_verilog_wire_connection(fp, ccff_head_local_port, ccff_head_port, false); + /* Connect last CCFF to the tail */ + /* Tail is always a 1-bit port */ + BasicPort ccff_tail_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), 1); + BasicPort ccff_tail_local_port(ccff_ports[1].get_name(), ccff_ports[1].get_msb(), ccff_ports[1].get_msb()); + print_verilog_wire_connection(fp, ccff_tail_local_port, ccff_tail_port, false); + /* Connect CCFFs into chains */ + /* If port size is 0 or 1, there is no need for the chain connection */ + if (2 > port_size) { + break; + } + /* Cascade the CCFF between head and tail */ + BasicPort ccff_chain_input_port(ccff_ports[0].get_name(), port_size - 1); + BasicPort ccff_chain_output_port(ccff_ports[1].get_name(), 1, port_size - 1); + print_verilog_wire_connection(fp, ccff_chain_output_port, ccff_chain_input_port, false); + break; + } + case SPICE_SRAM_MEMORY_BANK: { + /* Generate the name of local wire for the SRAM output and inverted output */ + std::vector sram_ports; + /* [0] => SRAM output */ + sram_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), port_size)); + /* [1] => SRAM inverted output */ + sram_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), port_size)); + /* Print local wire definition */ + for (const auto& sram_port : sram_ports) { + fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_port) << ";" << std::endl; + } + + break; + } + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h index 8ab7906e0..a272a74f5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h @@ -84,4 +84,10 @@ void print_verilog_buffer_instance(std::fstream& fp, const BasicPort& instance_input_port, const BasicPort& instance_output_port); +void print_verilog_local_sram_wires(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz sram_orgz_type, + const size_t& port_size); + #endif