refactored memory module Verilog generation for scan-chains

This commit is contained in:
tangxifan 2019-10-04 22:45:45 -06:00
parent b082e60c10
commit b905c0c68c
5 changed files with 318 additions and 160 deletions

View File

@ -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<std::string, BasicPort> generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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<BasicPort> 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<std::string, BasicPort> generate_rram_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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<BasicPort> 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<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_spice_model_design_tech& mem_design_tech,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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);
}
}

View File

@ -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 <vector>
#include "device_port.h"
#include "spice_types.h"
#include "module_manager.h"
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const BasicPort& config_bus,
const std::vector<BasicPort>& 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

View File

@ -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<std::string, BasicPort> generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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<std::string, BasicPort> generate_rram_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_spice_model_design_tech& mem_design_tech,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> 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;
}

View File

@ -38,12 +38,5 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
const e_sram_orgz sram_orgz_type, const e_sram_orgz sram_orgz_type,
const size_t& port_size); const size_t& port_size);
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_spice_model_design_tech& mem_design_tech,
const e_sram_orgz& sram_orgz_type);
#endif #endif

View File

@ -43,6 +43,7 @@
#include "mux_utils.h" #include "mux_utils.h"
#include "module_manager.h" #include "module_manager.h"
#include "module_manager_utils.h" #include "module_manager_utils.h"
#include "fpga_x2p_mem_utils.h"
/* Include Verilog support headers*/ /* Include Verilog support headers*/
#include "verilog_global.h" #include "verilog_global.h"
@ -2321,6 +2322,7 @@ static
void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
std::fstream& fp, std::fstream& fp,
t_sram_orgz_info* cur_sram_orgz_info, t_sram_orgz_info* cur_sram_orgz_info,
BasicPort& config_bus,
const ModuleId& sb_module, const ModuleId& sb_module,
const RRGSB& rr_sb, const RRGSB& rr_sb,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
@ -2451,18 +2453,22 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
std::map<std::string, BasicPort> mem_port2port_name_map; std::map<std::string, BasicPort> mem_port2port_name_map;
/* TODO: Make the port2port map generation more generic!!! */ /* TODO: Make the port2port map generation more generic!!! */
std::vector<BasicPort> config_ports; /* Link the SRAM ports of the routing multiplexer to the memory module */
config_ports.push_back(BasicPort(generate_local_config_bus_port_name(), mux_instance_id - 1, mux_instance_id));
std::vector<BasicPort> mem_output_ports; std::vector<BasicPort> mem_output_ports;
mem_output_ports.push_back(mux_config_port); mem_output_ports.push_back(mux_config_port);
mem_output_ports.push_back(mux_config_inv_port); mem_output_ports.push_back(mux_config_inv_port);
mem_port2port_name_map = generate_mem_module_port2port_map(module_manager, mem_module, mem_port2port_name_map = generate_mem_module_port2port_map(module_manager, mem_module,
config_ports, config_bus,
mem_output_ports, mem_output_ports,
circuit_lib.design_tech_type(mux_model), circuit_lib.design_tech_type(mux_model),
cur_sram_orgz_info->type); 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_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_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 -----")); 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, void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
std::fstream& fp, std::fstream& fp,
t_sram_orgz_info* cur_sram_orgz_info, t_sram_orgz_info* cur_sram_orgz_info,
BasicPort& config_bus,
const ModuleId& sb_module, const ModuleId& sb_module,
const RRGSB& rr_sb, const RRGSB& rr_sb,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
@ -2525,7 +2532,7 @@ void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
drive_rr_nodes[DEFAULT_SWITCH_ID]); drive_rr_nodes[DEFAULT_SWITCH_ID]);
} else if (1 < drive_rr_nodes.size()) { } else if (1 < drive_rr_nodes.size()) {
/* Print the multiplexer, fan_in >= 2 */ /* 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, sb_module, rr_sb, circuit_lib, mux_lib,
rr_switches, chan_side, cur_rr_node, rr_switches, chan_side, cur_rr_node,
drive_rr_nodes, 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()); rr_gsb.get_sb_num_conf_bits());
print_verilog_comment(fp, std::string("---- END local wires for SRAM data ports ----")); 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 */ /* TODO: Print routing multiplexers */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(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) { for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
/* We care INC_DIRECTION tracks at this side*/ /* We care INC_DIRECTION tracks at this side*/
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { 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, circuit_lib, mux_lib, rr_switches,
side_manager.get_side(), side_manager.get_side(),
itrack, is_explicit_mapping); 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 */ /* Put an end to the Verilog module */
print_verilog_module_end(fp, module_manager.module_name(module_id)); print_verilog_module_end(fp, module_manager.module_name(module_id));