From b905c0c68c6b3826a6884688f193e9ce53e64ace Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 4 Oct 2019 22:45:45 -0600 Subject: [PATCH] refactored memory module Verilog generation for scan-chains --- .../SRC/fpga_x2p/base/fpga_x2p_mem_utils.cpp | 272 ++++++++++++++++++ .../SRC/fpga_x2p/base/fpga_x2p_mem_utils.h | 25 ++ .../fpga_x2p/base/module_manager_utils.cpp | 147 ---------- .../SRC/fpga_x2p/base/module_manager_utils.h | 7 - .../SRC/fpga_x2p/verilog/verilog_routing.c | 27 +- 5 files changed, 318 insertions(+), 160 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.cpp new file mode 100644 index 000000000..2fd7c9872 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.cpp @@ -0,0 +1,272 @@ +/********************************************************************* + * This file includes functions that are used for + * generating ports for memory modules + *********************************************************************/ +#include "vtr_assert.h" +#include "util.h" +#include "fpga_x2p_naming.h" +#include "fpga_x2p_mem_utils.h" + +/********************************************************************* + * Create a port-to-port map for a CMOS memory module + * + * Configuration Chain + * ------------------- + * + * config_bus (head) config_bus (tail) + * | ^ + * v | + * +-------------------------------------+ + * | CMOS-based Memory Module | + * +-------------------------------------+ + * | | + * v v + * sram_out sram_outb + * + * + * Memory bank + * ----------- + * + * config_bus (BL) config_bus (WL) + * | | + * v v + * +-------------------------------------+ + * | CMOS-based Memory Module | + * +-------------------------------------+ + * | | + * v v + * sram_out sram_outb + * + **********************************************************************/ +static +std::map generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const BasicPort& config_bus, + const std::vector& mem_output_bus_ports, + const e_sram_orgz& sram_orgz_type) { + std::map port2port_name_map; + + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Nothing to do */ + break; + case SPICE_SRAM_SCAN_CHAIN: { + /* Link the head port of the memory module: + * the LSB of config bus port is the head port index + */ + std::vector config_bus_ports; + config_bus_ports.push_back(BasicPort(generate_local_config_bus_port_name(), config_bus.get_msb(), config_bus.get_msb() + 1)); + BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb()); + port2port_name_map[generate_configuration_chain_head_name()] = head_port; + + /* Link the tail port of the memory module: + * the MSB of config bus port is the tail port index + */ + BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb()); + port2port_name_map[generate_configuration_chain_tail_name()] = tail_port; + + /* Link the SRAM output ports of the memory module */ + VTR_ASSERT( 2 == mem_output_bus_ports.size() ); + port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0]; + port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1]; + break; + } + case SPICE_SRAM_MEMORY_BANK: + /* TODO: */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } + + return port2port_name_map; +} + +/********************************************************************* + * Create a port-to-port map for a ReRAM-based memory module + * Memory bank + * ----------- + * + * config_bus (BL) config_bus (WL) + * | | + * v v + * +-------------------------------------+ + * | ReRAM-based Memory Module | + * +-------------------------------------+ + * | | + * v v + * Mem_out Mem_outb + **********************************************************************/ +static +std::map generate_rram_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const BasicPort& config_bus, + const std::vector& mem_output_bus_ports, + const e_sram_orgz& sram_orgz_type) { + std::map port2port_name_map; + + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Not supported */ + break; + case SPICE_SRAM_SCAN_CHAIN: { + /* Link the head port of the memory module: + * the LSB of config bus port is the head port index + */ + std::vector config_bus_ports; + config_bus_ports.push_back(BasicPort(generate_local_config_bus_port_name(), config_bus.get_msb(), config_bus.get_msb() + 1)); + BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb()); + port2port_name_map[generate_configuration_chain_head_name()] = head_port; + + /* Link the tail port of the memory module: + * the MSB of config bus port is the tail port index + */ + BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb()); + port2port_name_map[generate_configuration_chain_tail_name()] = tail_port; + + /* Link the SRAM output ports of the memory module */ + VTR_ASSERT( 2 == mem_output_bus_ports.size() ); + port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0]; + port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1]; + break; + } + case SPICE_SRAM_MEMORY_BANK: + /* TODO: link BL/WL/Reserved Ports to the inputs of a memory module */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } + + return port2port_name_map; +} + +/********************************************************************* + * Create a port-to-port map for a memory module + * The content of the port-to-port map will depend not only + * the design technology of the memory cells but also the + * configuration styles of FPGA fabric. + * Here we will branch on the design technology + **********************************************************************/ +std::map generate_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const BasicPort& config_bus, + const std::vector& mem_output_bus_ports, + const e_spice_model_design_tech& mem_design_tech, + const e_sram_orgz& sram_orgz_type) { + std::map port2port_name_map; + + switch (mem_design_tech) { + case SPICE_MODEL_DESIGN_CMOS: + port2port_name_map = generate_cmos_mem_module_port2port_map(module_manager, mem_module, config_bus, mem_output_bus_ports, sram_orgz_type); + break; + case SPICE_MODEL_DESIGN_RRAM: + port2port_name_map = generate_rram_mem_module_port2port_map(module_manager, mem_module, config_bus, mem_output_bus_ports, sram_orgz_type); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of memory design technology !\n", + __FILE__, __LINE__); + exit(1); + } + + return port2port_name_map; +} + +/********************************************************************* + * Update the LSB and MSB of a configuration bus based on the number of + * memory bits of a CMOS memory module. + **********************************************************************/ +static +void update_cmos_mem_module_config_bus(const e_sram_orgz& sram_orgz_type, + const size_t& num_config_bits, + BasicPort& config_bus) { + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Not supported */ + break; + case SPICE_SRAM_SCAN_CHAIN: + /* Scan-chain of a memory module only has a head and a tail. + * LSB and MSB of configuration bus will be shifted to the next head. + */ + VTR_ASSERT(true == config_bus.rotate(1)); + break; + case SPICE_SRAM_MEMORY_BANK: + /* In this case, a memory module has a number of BL/WL and BLB/WLB (possibly). + * LSB and MSB of configuration bus will be shifted by the number of BL/WL/BLB/WLB. + */ + VTR_ASSERT(true == config_bus.rotate(num_config_bits)); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/********************************************************************* + * Update the LSB and MSB of a configuration bus based on the number of + * memory bits of a ReRAM memory module. + **********************************************************************/ +static +void update_rram_mem_module_config_bus(const e_sram_orgz& sram_orgz_type, + const size_t& num_config_bits, + BasicPort& config_bus) { + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Not supported */ + break; + case SPICE_SRAM_SCAN_CHAIN: + /* Scan-chain of a memory module only has a head and a tail. + * LSB and MSB of configuration bus will be shifted to the next head. + * TODO: this may be changed later!!! + */ + VTR_ASSERT(true == config_bus.rotate(1)); + break; + case SPICE_SRAM_MEMORY_BANK: + /* In this case, a memory module contains unique BL/WL or BLB/WLB, + * which are not shared with other modules + * TODO: this may be changed later!!! + */ + VTR_ASSERT(true == config_bus.rotate(1)); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/********************************************************************* + * Update the LSB and MSB of a configuration bus based on the number of + * memory bits of a module. + * Note that this function is designed to do such simple job, in purpose of + * being independent from adding ports or printing ports. + * As such, this function can be re-used in bitstream generation + * when Verilog generation is not needed. + * DO NOT update the configuration bus in the function of adding/printing ports + **********************************************************************/ +void update_mem_module_config_bus(const e_sram_orgz& sram_orgz_type, + const e_spice_model_design_tech& mem_design_tech, + const size_t& num_config_bits, + BasicPort& config_bus) { + switch (mem_design_tech) { + case SPICE_MODEL_DESIGN_CMOS: + update_cmos_mem_module_config_bus(sram_orgz_type, num_config_bits, config_bus); + break; + case SPICE_MODEL_DESIGN_RRAM: + update_rram_mem_module_config_bus(sram_orgz_type, num_config_bits, config_bus); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of memory design technology !\n", + __FILE__, __LINE__); + exit(1); + } +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.h new file mode 100644 index 000000000..5a25cdcbd --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mem_utils.h @@ -0,0 +1,25 @@ +/******************************************************************** + * Header file for fpga_x2p_mem_utils.cpp + **********************************************************************/ +#ifndef FPGA_X2P_MEM_UTILS_H +#define FPGA_X2P_MEM_UTILS_H + +/* Header files are included for the data types appear in the function declaration below */ +#include +#include "device_port.h" +#include "spice_types.h" +#include "module_manager.h" + +std::map generate_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const BasicPort& config_bus, + const std::vector& mem_output_bus_ports, + const e_spice_model_design_tech& mem_design_tech, + const e_sram_orgz& sram_orgz_type); + +void update_mem_module_config_bus(const e_sram_orgz& sram_orgz_type, + const e_spice_model_design_tech& mem_design_tech, + const size_t& num_config_bits, + BasicPort& config_bus); + +#endif 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 e442b0223..6b7c9bdc9 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 @@ -210,150 +210,3 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager, } } -/********************************************************************* - * Create a port-to-port map for a CMOS memory module - * - * Configuration Chain - * ------------------- - * - * config_bus (head) config_bus (tail) - * | ^ - * v | - * +-------------------------------------+ - * | CMOS-based Memory Module | - * +-------------------------------------+ - * | | - * v v - * sram_out sram_outb - * - * - * Memory bank - * ----------- - * - * config_bus (BL) config_bus (WL) - * | | - * v v - * +-------------------------------------+ - * | CMOS-based Memory Module | - * +-------------------------------------+ - * | | - * v v - * sram_out sram_outb - * - **********************************************************************/ -static -std::map generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager, - const ModuleId& mem_module, - const std::vector& config_bus_ports, - const std::vector& mem_output_bus_ports, - const e_sram_orgz& sram_orgz_type) { - std::map port2port_name_map; - - switch (sram_orgz_type) { - case SPICE_SRAM_STANDALONE: - /* Nothing to do */ - break; - case SPICE_SRAM_SCAN_CHAIN: { - /* Link the head port of the memory module: - * the LSB of config bus port is the head port index - */ - VTR_ASSERT( 1 == config_bus_ports.size() ); - BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb()); - port2port_name_map[generate_configuration_chain_head_name()] = head_port; - - /* Link the tail port of the memory module: - * the MSB of config bus port is the tail port index - */ - BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb()); - port2port_name_map[generate_configuration_chain_tail_name()] = tail_port; - - /* Link the SRAM output ports of the memory module */ - VTR_ASSERT( 2 == mem_output_bus_ports.size() ); - port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0]; - port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1]; - break; - } - case SPICE_SRAM_MEMORY_BANK: - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", - __FILE__, __LINE__); - exit(1); - } - - return port2port_name_map; -} - -/********************************************************************* - * Create a port-to-port map for a ReRAM-based memory module - * Memory bank - * ----------- - * - * config_bus (BL) config_bus (WL) - * | | - * v v - * +-------------------------------------+ - * | ReRAM-based Memory Module | - * +-------------------------------------+ - * | | - * v v - * Mem_out Mem_outb - **********************************************************************/ -static -std::map generate_rram_mem_module_port2port_map(const ModuleManager& module_manager, - const ModuleId& mem_module, - const e_sram_orgz& sram_orgz_type) { - std::map port2port_name_map; - - switch (sram_orgz_type) { - case SPICE_SRAM_STANDALONE: - /* Not supported */ - break; - case SPICE_SRAM_SCAN_CHAIN: - /* TODO: to be supported */ - break; - case SPICE_SRAM_MEMORY_BANK: - /* TODO: link BL/WL/Reserved Ports to the inputs of a memory module */ - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", - __FILE__, __LINE__); - exit(1); - } - - return port2port_name_map; -} - -/********************************************************************* - * Create a port-to-port map for a memory module - * The content of the port-to-port map will depend not only - * the design technology of the memory cells but also the - * configuration styles of FPGA fabric. - * Here we will branch on the design technology - **********************************************************************/ -std::map generate_mem_module_port2port_map(const ModuleManager& module_manager, - const ModuleId& mem_module, - const std::vector& config_bus_ports, - const std::vector& mem_output_bus_ports, - const e_spice_model_design_tech& mem_design_tech, - const e_sram_orgz& sram_orgz_type) { - std::map port2port_name_map; - - switch (mem_design_tech) { - case SPICE_MODEL_DESIGN_CMOS: - port2port_name_map = generate_cmos_mem_module_port2port_map(module_manager, mem_module, config_bus_ports, mem_output_bus_ports, sram_orgz_type); - break; - case SPICE_MODEL_DESIGN_RRAM: - port2port_name_map = generate_rram_mem_module_port2port_map(module_manager, mem_module, sram_orgz_type); - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s,[LINE%d])Invalid type of memory design technology !\n", - __FILE__, __LINE__); - exit(1); - } - - return port2port_name_map; -} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h index bee3e7ff8..17d395cdb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h @@ -38,12 +38,5 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager, const e_sram_orgz sram_orgz_type, const size_t& port_size); -std::map generate_mem_module_port2port_map(const ModuleManager& module_manager, - const ModuleId& mem_module, - const std::vector& config_bus_ports, - const std::vector& mem_output_bus_ports, - const e_spice_model_design_tech& mem_design_tech, - const e_sram_orgz& sram_orgz_type); - #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 d08f5eb15..d784888d1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -43,6 +43,7 @@ #include "mux_utils.h" #include "module_manager.h" #include "module_manager_utils.h" +#include "fpga_x2p_mem_utils.h" /* Include Verilog support headers*/ #include "verilog_global.h" @@ -2321,6 +2322,7 @@ static void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, std::fstream& fp, t_sram_orgz_info* cur_sram_orgz_info, + BasicPort& config_bus, const ModuleId& sb_module, const RRGSB& rr_sb, const CircuitLibrary& circuit_lib, @@ -2451,18 +2453,22 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, std::map mem_port2port_name_map; /* TODO: Make the port2port map generation more generic!!! */ - std::vector config_ports; - config_ports.push_back(BasicPort(generate_local_config_bus_port_name(), mux_instance_id - 1, mux_instance_id)); + /* Link the SRAM ports of the routing multiplexer to the memory module */ std::vector mem_output_ports; mem_output_ports.push_back(mux_config_port); mem_output_ports.push_back(mux_config_inv_port); mem_port2port_name_map = generate_mem_module_port2port_map(module_manager, mem_module, - config_ports, + config_bus, mem_output_ports, circuit_lib.design_tech_type(mux_model), cur_sram_orgz_info->type); + /* Update the config bus for the module */ + update_mem_module_config_bus(cur_sram_orgz_info->type, + circuit_lib.design_tech_type(mux_model), + mux_num_config_bits, + config_bus); - /* Print an instance of the MUX Module */ + /* Print an instance of the memory module associated with the routing multiplexer */ print_verilog_comment(fp, std::string("----- BEGIN Instanciation of memory cells for a routing multiplexer -----")); print_verilog_module_instance(fp, module_manager, sb_module, mem_module, mem_port2port_name_map, use_explicit_mapping); print_verilog_comment(fp, std::string("----- END Instanciation of memory cells for a routing multiplexer -----")); @@ -2491,6 +2497,7 @@ static void print_verilog_unique_switch_box_interc(ModuleManager& module_manager, std::fstream& fp, t_sram_orgz_info* cur_sram_orgz_info, + BasicPort& config_bus, const ModuleId& sb_module, const RRGSB& rr_sb, const CircuitLibrary& circuit_lib, @@ -2525,7 +2532,7 @@ void print_verilog_unique_switch_box_interc(ModuleManager& module_manager, drive_rr_nodes[DEFAULT_SWITCH_ID]); } else if (1 < drive_rr_nodes.size()) { /* Print the multiplexer, fan_in >= 2 */ - print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info, + print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info, config_bus, sb_module, rr_sb, circuit_lib, mux_lib, rr_switches, chan_side, cur_rr_node, drive_rr_nodes, @@ -2725,6 +2732,11 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage rr_gsb.get_sb_num_conf_bits()); print_verilog_comment(fp, std::string("---- END local wires for SRAM data ports ----")); + /* Create a counter for the configuration bus */ + BasicPort config_bus; + /* Counter start from 0 */ + config_bus.set_width(0, 0); + /* TODO: Print routing multiplexers */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side side_manager(side); @@ -2732,7 +2744,8 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { /* We care INC_DIRECTION tracks at this side*/ if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { - print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, module_id, rr_sb, + print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, config_bus, + module_id, rr_sb, circuit_lib, mux_lib, rr_switches, side_manager.get_side(), itrack, is_explicit_mapping); @@ -2740,6 +2753,8 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage } } + /* TODO: Add check code for config_bus. The MSB should match the number of configuration bits!!! */ + /* Put an end to the Verilog module */ print_verilog_module_end(fp, module_manager.module_name(module_id));