From 9cf8683acdb2dfb6b30f3e4e7892bb3b9205504c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 22 Oct 2019 15:31:08 -0600 Subject: [PATCH] add module generation for memories --- .../fpga_x2p/base/module_manager_utils.cpp | 5 +- .../module_builder/build_memory_modules.cpp | 685 ++++++++++++++++++ .../module_builder/build_memory_modules.h | 20 + .../module_builder/build_module_graph.cpp | 5 +- .../vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp | 6 +- .../vpr/SRC/fpga_x2p/verilog/verilog_lut.h | 3 +- .../SRC/fpga_x2p/verilog/verilog_memory.cpp | 439 +---------- .../vpr/SRC/fpga_x2p/verilog/verilog_memory.h | 4 +- .../vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp | 19 +- .../vpr/SRC/fpga_x2p/verilog/verilog_mux.h | 3 +- .../SRC/fpga_x2p/verilog/verilog_submodules.c | 11 +- 11 files changed, 762 insertions(+), 438 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.h 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 f7e6b7c8b..ac5561032 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 @@ -565,7 +565,8 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man } } -/* Connect all the memory modules under the parent module in a chain +/******************************************************************** + * Connect all the memory modules under the parent module in a chain * * +--------+ +--------+ +--------+ * ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail @@ -579,7 +580,7 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man * For the rest of memory modules: * net source is the configuration chain tail of the previous memory module * net sink is the configuration chain head of the next memory module - */ + *********************************************************************/ void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager, const ModuleId& parent_module, const std::vector& memory_modules, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp new file mode 100644 index 000000000..25cc6d877 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp @@ -0,0 +1,685 @@ +/********************************************************************* + * This file includes functions to generate Verilog submodules for + * the memories that are affiliated to multiplexers and other programmable + * circuit models, such as IOPADs, LUTs, etc. + ********************************************************************/ +#include +#include + +#include "util.h" +#include "vtr_assert.h" + +/* Device-level header files */ +#include "mux_graph.h" +#include "module_manager.h" +#include "physical_types.h" +#include "vpr_types.h" +#include "circuit_library_utils.h" +#include "module_manager_utils.h" +#include "mux_utils.h" + +/* FPGA-X2P context header files */ +#include "spice_types.h" +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" + +/* FPGA-Verilog context header files */ +#include "verilog_global.h" +#include "build_memory_modules.h" + +/********************************************************************* + * Add module nets to connect an input port of a memory module to + * an input port of its child module + * Restriction: this function is really designed for memory modules + * 1. It assumes that input port name of child module is the same as memory module + * 2. It assumes exact pin-to-pin mapping: + * j-th pin of input port of the i-th child module is wired to the j + i*W -th + * pin of input port of the memory module, where W is the size of port + ********************************************************************/ +static +void add_module_input_nets_to_mem_modules(ModuleManager& module_manager, + const ModuleId& mem_module, + const CircuitLibrary& circuit_lib, + const std::vector& circuit_ports, + const ModuleId& child_module, + const size_t& child_index, + const size_t& child_instance) { + /* Wire inputs of parent module to inputs of child modules */ + for (const auto& port : circuit_ports) { + ModulePortId src_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port)); + ModulePortId sink_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port)); + for (size_t pin_id = 0; pin_id < module_manager.module_port(mem_module, sink_port_id).pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(mem_module); + /* Source pin is shifted by the number of memories */ + size_t src_pin_id = child_index * circuit_lib.port_size(port) + module_manager.module_port(mem_module, src_port_id).pins()[pin_id]; + /* Source node of the input net is the input of memory module */ + module_manager.add_module_net_source(mem_module, net, mem_module, 0, src_port_id, src_pin_id); + /* Sink node of the input net is the input of sram module */ + size_t sink_pin_id = module_manager.module_port(child_module, sink_port_id).pins()[pin_id]; + module_manager.add_module_net_sink(mem_module, net, child_module, child_instance, sink_port_id, sink_pin_id); + } + } +} + +/********************************************************************* + * Add module nets to connect an output port of a memory module to + * an output port of its child module + * Restriction: this function is really designed for memory modules + * 1. It assumes that output port name of child module is the same as memory module + * 2. It assumes exact pin-to-pin mapping: + * j-th pin of output port of the i-th child module is wired to the j + i*W -th + * pin of output port of the memory module, where W is the size of port + ********************************************************************/ +static +void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, + const ModuleId& mem_module, + const CircuitLibrary& circuit_lib, + const std::vector& circuit_ports, + const ModuleId& child_module, + const size_t& child_index, + const size_t& child_instance) { + /* Wire inputs of parent module to inputs of child modules */ + for (const auto& port : circuit_ports) { + ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port)); + ModulePortId sink_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port)); + for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(mem_module); + /* Source pin is shifted by the number of memories */ + size_t src_pin_id = module_manager.module_port(child_module, src_port_id).pins()[pin_id]; + /* Source node of the input net is the input of memory module */ + module_manager.add_module_net_source(mem_module, net, child_module, child_instance, src_port_id, src_pin_id); + /* Sink node of the input net is the input of sram module */ + size_t sink_pin_id = child_index * circuit_lib.port_size(port) + module_manager.module_port(mem_module, sink_port_id).pins()[pin_id]; + module_manager.add_module_net_sink(mem_module, net, mem_module, 0, sink_port_id, sink_pin_id); + } + } +} + +/********************************************************************* + * Add module nets to connect an output port of a configuration-chain + * memory module to an output port of its child module + * Restriction: this function is really designed for memory modules + * 1. It assumes that output port name of child module is the same as memory module + * 2. It assumes exact pin-to-pin mapping: + * j-th pin of output port of the i-th child module is wired to the j + i*W -th + * pin of output port of the memory module, where W is the size of port + * 3. It assumes fixed port name for output ports + ********************************************************************/ +static +void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, + const ModuleId& mem_module, + const std::string& mem_module_output_name, + const CircuitLibrary& circuit_lib, + const CircuitPortId& circuit_port, + const ModuleId& child_module, + const size_t& child_index, + const size_t& child_instance) { + /* Wire inputs of parent module to inputs of child modules */ + ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(circuit_port)); + ModulePortId sink_port_id = module_manager.find_module_port(mem_module, mem_module_output_name); + for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(mem_module); + /* Source pin is shifted by the number of memories */ + size_t src_pin_id = module_manager.module_port(child_module, src_port_id).pins()[pin_id]; + /* Source node of the input net is the input of memory module */ + module_manager.add_module_net_source(mem_module, net, child_module, child_instance, src_port_id, src_pin_id); + /* Sink node of the input net is the input of sram module */ + size_t sink_pin_id = child_index * circuit_lib.port_size(circuit_port) + module_manager.module_port(mem_module, sink_port_id).pins()[pin_id]; + module_manager.add_module_net_sink(mem_module, net, mem_module, 0, sink_port_id, sink_pin_id); + } +} + +/******************************************************************** + * Connect all the memory modules under the parent module in a chain + * + * +--------+ +--------+ +--------+ + * ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail + * | Module | | Module | | Module | + * | [0] | | [1] | | [N-1] | + * +--------+ +--------+ +--------+ + * For the 1st memory module: + * net source is the configuration chain head of the primitive module + * net sink is the configuration chain head of the next memory module + * + * For the rest of memory modules: + * net source is the configuration chain tail of the previous memory module + * net sink is the configuration chain head of the next memory module + * + * Note that: + * This function is designed for memory modules ONLY! + * Do not use it to replace the + * add_module_nets_cmos_memory_chain_config_bus() !!! + *********************************************************************/ +static +void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const CircuitLibrary& circuit_lib, + const CircuitPortId& model_input_port, + const CircuitPortId& model_output_port) { + for (size_t mem_index = 0; mem_index < memory_modules.size(); ++mem_index) { + ModuleId net_src_module_id; + size_t net_src_instance_id; + ModulePortId net_src_port_id; + + ModuleId net_sink_module_id; + size_t net_sink_instance_id; + ModulePortId net_sink_port_id; + + if (0 == mem_index) { + /* Find the port name of configuration chain head */ + std::string src_port_name = generate_configuration_chain_head_name(); + net_src_module_id = parent_module; + net_src_instance_id = 0; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = circuit_lib.port_lib_name(model_input_port); + net_sink_module_id = memory_modules[mem_index]; + net_sink_instance_id = memory_instances[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } else { + /* Find the port name of previous memory module */ + std::string src_port_name = circuit_lib.port_lib_name(model_output_port); + net_src_module_id = memory_modules[mem_index - 1]; + net_src_instance_id = memory_instances[mem_index - 1]; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = circuit_lib.port_lib_name(model_input_port); + net_sink_module_id = memory_modules[mem_index]; + net_sink_instance_id = memory_instances[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } + + /* Get the pin id for source port */ + BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); + /* Get the pin id for sink port */ + BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); + /* Port sizes of source and sink should match */ + VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { + /* Create a net and add source and sink to it */ + ModuleNetId net = module_manager.create_module_net(parent_module); + /* Add net source */ + module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + /* Add net sink */ + module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + } + } + + /* For the last memory module: + * net source is the configuration chain tail of the previous memory module + * net sink is the configuration chain tail of the primitive module + */ + /* Find the port name of previous memory module */ + std::string src_port_name = circuit_lib.port_lib_name(model_output_port); + ModuleId net_src_module_id = memory_modules.back(); + size_t net_src_instance_id = memory_instances.back(); + ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = generate_configuration_chain_tail_name(); + ModuleId net_sink_module_id = parent_module; + size_t net_sink_instance_id = 0; + ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + + /* Get the pin id for source port */ + BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); + /* Get the pin id for sink port */ + BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); + /* Port sizes of source and sink should match */ + VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { + /* Create a net and add source and sink to it */ + ModuleNetId net = module_manager.create_module_net(parent_module); + /* Add net source */ + module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + /* Add net sink */ + module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + } +} + +/********************************************************************* + * Flat memory modules + * + * in[0] in[1] in[N] + * | | | + * v v v + * +-------+ +-------+ +-------+ + * | SRAM | | SRAM | ... | SRAM | + * | [0] | | [1] | | [N-1] | + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +------------------------------------+ + * | Multiplexer Configuration port | + * + ********************************************************************/ +static +void build_memory_standalone_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& module_name, + const CircuitModelId& sram_model, + const size_t& num_mems) { + /* Get the global ports required by the SRAM */ + std::vector global_port_types; + global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); + global_port_types.push_back(SPICE_MODEL_PORT_INPUT); + std::vector sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false); + /* Get the input ports from the SRAM */ + std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); + /* Get the output ports from the SRAM */ + std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); + + /* Create a module and add to the module manager */ + ModuleId mem_module = module_manager.add_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + + /* Add each input port */ + for (const auto& port : sram_input_ports) { + BasicPort input_port(circuit_lib.port_lib_name(port), num_mems); + module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT); + } + /* Add each output port: port width should match the number of memories */ + for (const auto& port : sram_output_ports) { + BasicPort output_port(circuit_lib.port_lib_name(port), num_mems); + module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); + } + + /* Find the sram module in the module manager */ + ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); + + /* Instanciate each submodule */ + for (size_t i = 0; i < num_mems; ++i) { + size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module); + module_manager.add_child_module(mem_module, sram_mem_module); + + /* Build module nets */ + /* Wire inputs of parent module to inputs of child modules */ + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_input_ports, sram_mem_module, i, sram_mem_instance); + /* Wire inputs of parent module to outputs of child modules */ + add_module_output_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_output_ports, sram_mem_module, i, sram_mem_instance); + } + + /* Add global ports to the pb_module: + * This is a much easier job after adding sub modules (instances), + * we just need to find all the global ports from the child modules and build a list of it + */ + add_module_global_ports_from_child_modules(module_manager, mem_module); +} + +/********************************************************************* + * Scan-chain organization + * + * +-------+ +-------+ +-------+ + * scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain + * input&clock | [0] | | [1] | | [N-1] | output + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +-----------------------------------------+ + * | Multiplexer Configuration port | + * + ********************************************************************/ +static +void build_memory_chain_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& module_name, + const CircuitModelId& sram_model, + const size_t& num_mems) { + + /* Get the input ports from the SRAM */ + std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); + /* Should have only 1 input port */ + VTR_ASSERT( 1 == sram_input_ports.size() ); + /* Get the output ports from the SRAM */ + std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); + /* Should have only 1 or 2 output port */ + VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) ); + + /* Create a module and add to the module manager */ + ModuleId mem_module = module_manager.add_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + + /* Add an input port, which is the head of configuration chain in the module */ + /* TODO: restriction!!! + * consider only the first input of the CCFF model as the D port, + * which will be connected to the head of the chain + */ + BasicPort chain_head_port(generate_configuration_chain_head_name(), + circuit_lib.port_size(sram_input_ports[0])); + module_manager.add_port(mem_module, chain_head_port, ModuleManager::MODULE_INPUT_PORT); + /* Add an output port, which is the tail of configuration chain in the module */ + /* TODO: restriction!!! + * consider only the first output of the CCFF model as the Q port, + * which will be connected to the tail of the chain + */ + BasicPort chain_tail_port(generate_configuration_chain_tail_name(), + circuit_lib.port_size(sram_output_ports[0])); + module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_INPUT_PORT); + + /* Add each output port: port width should match the number of memories */ + for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { + std::string port_name; + if (0 == iport) { + port_name = generate_configuration_chain_data_out_name(); + } else { + VTR_ASSERT( 1 == iport); + port_name = generate_configuration_chain_inverted_data_out_name(); + } + BasicPort output_port(port_name, num_mems); + module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); + } + + /* Find the sram module in the module manager */ + ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); + + std::vector memory_modules; + std::vector memory_instances; + + /* Instanciate each submodule */ + for (size_t i = 0; i < num_mems; ++i) { + size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module); + module_manager.add_child_module(mem_module, sram_mem_module); + memory_modules.push_back(sram_mem_module); + memory_instances.push_back(sram_mem_instance); + + /* Build module nets to wire outputs of sram modules to outputs of memory module */ + for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { + std::string port_name; + if (0 == iport) { + port_name = generate_configuration_chain_data_out_name(); + } else { + VTR_ASSERT( 1 == iport); + port_name = generate_configuration_chain_inverted_data_out_name(); + } + add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, port_name, circuit_lib, sram_output_ports[iport], + sram_mem_module, i, sram_mem_instance); + } + } + + /* Build module nets to wire the configuration chain */ + add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, memory_modules, memory_instances, + circuit_lib, sram_input_ports[0], sram_output_ports[0]); + + + /* Add global ports to the pb_module: + * This is a much easier job after adding sub modules (instances), + * we just need to find all the global ports from the child modules and build a list of it + */ + add_module_global_ports_from_child_modules(module_manager, mem_module); +} + +/********************************************************************* + * Memory bank organization + * + * Bit lines(BL/BLB) Word lines (WL/WLB) + * | | + * v v + * +------------------------------------+ + * | Memory Module Configuration port | + * +------------------------------------+ + * | | | + * v v v + * +-------+ +-------+ +-------+ + * | SRAM | | SRAM | ... | SRAM | + * | [0] | | [1] | | [N-1] | + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +------------------------------------+ + * | Multiplexer Configuration port | + * + ********************************************************************/ +static +void build_memory_bank_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& module_name, + const CircuitModelId& sram_model, + const size_t& num_mems) { + /* Get the global ports required by the SRAM */ + std::vector global_port_types; + global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); + global_port_types.push_back(SPICE_MODEL_PORT_INPUT); + std::vector sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false); + /* Get the input ports from the SRAM */ + std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); + /* A SRAM cell with BL/WL should not have any input */ + VTR_ASSERT( 0 == sram_input_ports.size() ); + /* Get the output ports from the SRAM */ + std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); + /* Get the BL/WL ports from the SRAM */ + std::vector sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true); + std::vector sram_blb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BLB, true); + std::vector sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_WL, true); + std::vector sram_wlb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_WLB, true); + + /* Create a module and add to the module manager */ + ModuleId mem_module = module_manager.add_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + + /* Add module ports: the ports come from the SRAM modules */ + /* Add each input port */ + for (const auto& port : sram_input_ports) { + BasicPort input_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT); + } + /* Add each output port: port width should match the number of memories */ + for (const auto& port : sram_output_ports) { + BasicPort output_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); + } + /* Add each output port: port width should match the number of memories */ + for (const auto& port : sram_bl_ports) { + BasicPort bl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, bl_port, ModuleManager::MODULE_INPUT_PORT); + } + for (const auto& port : sram_blb_ports) { + BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, blb_port, ModuleManager::MODULE_INPUT_PORT); + } + for (const auto& port : sram_wl_ports) { + BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, wl_port, ModuleManager::MODULE_INPUT_PORT); + } + for (const auto& port : sram_wlb_ports) { + BasicPort wlb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + module_manager.add_port(mem_module, wlb_port, ModuleManager::MODULE_INPUT_PORT); + } + + /* Find the sram module in the module manager */ + ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); + + /* Instanciate each submodule */ + for (size_t i = 0; i < num_mems; ++i) { + /* Memory seed module instanciation */ + size_t sram_instance = module_manager.num_instance(mem_module, sram_mem_module); + module_manager.add_child_module(mem_module, sram_mem_module); + + /* Build module nets */ + /* Wire inputs of parent module to inputs of child modules */ + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_input_ports, sram_mem_module, i, sram_instance); + /* Wire inputs of parent module to outputs of child modules */ + add_module_output_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_output_ports, sram_mem_module, i, sram_instance); + /* Wire BL/WLs of parent module to BL/WLs of child modules */ + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_bl_ports, sram_mem_module, i, sram_instance); + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_blb_ports, sram_mem_module, i, sram_instance); + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_wl_ports, sram_mem_module, i, sram_instance); + add_module_input_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_wlb_ports, sram_mem_module, i, sram_instance); + } + + /* TODO: if a local memory decoder is required, instanciate it here */ + + /* Add global ports to the pb_module: + * This is a much easier job after adding sub modules (instances), + * we just need to find all the global ports from the child modules and build a list of it + */ + add_module_global_ports_from_child_modules(module_manager, mem_module); +} + + +/********************************************************************* + * Generate Verilog modules for the memories that are used + * by a circuit model + * The organization of memory circuit will depend on the style of + * configuration protocols + * Currently, we support + * 1. Flat SRAM organization + * 2. Configuration chain + * 3. Memory bank (memory decoders) + ********************************************************************/ +static +void build_memory_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const e_sram_orgz& sram_orgz_type, + const std::string& module_name, + const CircuitModelId& sram_model, + const size_t& num_mems) { + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + build_memory_standalone_module(module_manager, circuit_lib, + module_name, sram_model, num_mems); + break; + case SPICE_SRAM_SCAN_CHAIN: + build_memory_chain_module(module_manager, circuit_lib, + module_name, sram_model, num_mems); + break; + case SPICE_SRAM_MEMORY_BANK: + build_memory_bank_module(module_manager, circuit_lib, + module_name, sram_model, num_mems); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, LINE%d) Invalid SRAM organization!\n", + __FILE__, __LINE__); + } +} + + +/********************************************************************* + * Generate Verilog modules for the memories that are used + * by multiplexers + * + * +----------------+ + * mem_in --->| Memory Module |---> mem_out + * +----------------+ + * | | ... | | + * v v v v SRAM ports of multiplexer + * +---------------------+ + * in--->| Multiplexer Module |---> out + * +---------------------+ + ********************************************************************/ +static +void build_mux_memory_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const e_sram_orgz& sram_orgz_type, + const CircuitModelId& mux_model, + const MuxGraph& mux_graph) { + /* Find the actual number of configuration bits, based on the mux graph + * Due to the use of local decoders inside mux, this may be + */ + size_t num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type); + /* Multiplexers built with different technology is in different organization */ + switch (circuit_lib.design_tech_type(mux_model)) { + case SPICE_MODEL_DESIGN_CMOS: { + /* Generate module name */ + std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model, + find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()), + std::string(verilog_mem_posfix)); + + /* Get the sram ports from the mux */ + std::vector sram_models = find_circuit_sram_models(circuit_lib, mux_model); + VTR_ASSERT( 1 == sram_models.size() ); + + build_memory_module(module_manager, circuit_lib, sram_orgz_type, module_name, sram_models[0], num_config_bits); + break; + } + case SPICE_MODEL_DESIGN_RRAM: + /* We do not need a memory submodule for RRAM MUX, + * RRAM are embedded in the datapath + * TODO: generate local encoders for RRAM-based multiplexers here!!! + */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n", + __FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str()); + exit(1); + } +} + +/********************************************************************* + * Build modules for + * the memories that are affiliated to multiplexers and other programmable + * circuit models, such as IOPADs, LUTs, etc. + * + * We keep the memory modules separated from the multiplexers and other + * programmable circuit models, for the sake of supporting + * various configuration schemes. + * By following such organiztion, the Verilog modules of the circuit models + * implements the functionality (circuit logic) only, while the memory Verilog + * modules implements the memory circuits as well as configuration protocols. + * For example, the local decoders of multiplexers are implemented in the + * memory modules. + * Take another example, the memory circuit can implement the scan-chain or + * memory-bank organization for the memories. + ********************************************************************/ +void build_memory_modules(ModuleManager& module_manager, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const e_sram_orgz& sram_orgz_type) { + + /* Create the memory circuits for the multiplexer */ + for (auto mux : mux_lib.muxes()) { + const MuxGraph& mux_graph = mux_lib.mux_graph(mux); + CircuitModelId mux_model = mux_lib.mux_circuit_model(mux); + /* Bypass the non-MUX circuit models (i.e., LUTs). + * They should be handled in a different way + * Memory circuits of LUT includes both regular and mode-select ports + */ + if (SPICE_MODEL_MUX != circuit_lib.model_type(mux_model)) { + continue; + } + /* Create a Verilog module for the memories used by the multiplexer */ + build_mux_memory_module(module_manager, circuit_lib, sram_orgz_type, mux_model, mux_graph); + } + + /* Create the memory circuits for non-MUX circuit models. + * In this case, the memory modules are designed to interface + * the mode-select ports + */ + for (const auto& model : circuit_lib.models()) { + /* Bypass MUXes, they have already been considered */ + if (SPICE_MODEL_MUX == circuit_lib.model_type(model)) { + continue; + } + /* Bypass those modules without any SRAM ports */ + std::vector sram_ports = circuit_lib.model_ports_by_type(model, SPICE_MODEL_PORT_SRAM, true); + if (0 == sram_ports.size()) { + continue; + } + /* Find the name of memory module */ + /* Get the total number of SRAMs */ + size_t num_mems = 0; + for (const auto& port : sram_ports) { + num_mems += circuit_lib.port_size(port); + } + /* Get the circuit model for the memory circuit used by the multiplexer */ + std::vector sram_models = find_circuit_sram_models(circuit_lib, model); + /* Should have only 1 SRAM model */ + VTR_ASSERT( 1 == sram_models.size() ); + + /* Create the module name for the memory block */ + std::string module_name = generate_memory_module_name(circuit_lib, model, sram_models[0], std::string(verilog_mem_posfix)); + + /* Create a Verilog module for the memories used by the circuit model */ + build_memory_module(module_manager, circuit_lib, sram_orgz_type, module_name, sram_models[0], num_mems); + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.h new file mode 100644 index 000000000..3597c5d95 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.h @@ -0,0 +1,20 @@ +/*********************************************** + * Header file for verilog_memory.cpp + **********************************************/ + +#ifndef BUILD_MEMORY_MODULE_H +#define BUILD_MEMORY_MODULE_H + +/* Include other header files which are dependency on the function declared below */ + +#include "circuit_library.h" +#include "mux_graph.h" +#include "mux_library.h" +#include "module_manager.h" + +void build_memory_modules(ModuleManager& module_manager, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const e_sram_orgz& sram_orgz_type); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp index d4196672d..666e42876 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp @@ -15,6 +15,7 @@ #include "build_mux_modules.h" #include "build_lut_modules.h" #include "build_wire_modules.h" +#include "build_memory_modules.h" #include "build_module_graph.h" /******************************************************************** @@ -94,7 +95,9 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, /* Build wire modules */ build_wire_modules(module_manager, arch.spice->circuit_lib, L_segment_vec); - /* TODO: Build memory modules */ + /* Build memory modules */ + build_memory_modules(module_manager, mux_lib, arch.spice->circuit_lib, + arch.sram_inf.verilog_sram_inf_orgz->type); /* TODO: Build grid and programmable block modules */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp index b5fa63060..7bd605d01 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp @@ -31,7 +31,8 @@ void print_verilog_submodule_luts(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const std::string& verilog_dir, - const std::string& submodule_dir) { + const std::string& submodule_dir, + const bool& use_explicit_port_map) { /* TODO: remove .bak when this part is completed and tested */ std::string verilog_fname = submodule_dir + luts_verilog_file_name + ".bak"; @@ -61,7 +62,8 @@ void print_verilog_submodule_luts(ModuleManager& module_manager, /* Find the module id */ ModuleId lut_module = module_manager.find_module(circuit_lib.model_name(lut_model)); VTR_ASSERT(true == module_manager.valid_module_id(lut_module)); - write_verilog_module_to_file(fp, module_manager, lut_module, circuit_lib.dump_explicit_port_map(lut_model)); + write_verilog_module_to_file(fp, module_manager, lut_module, + use_explicit_port_map || circuit_lib.dump_explicit_port_map(lut_model)); } /* Close the file handler */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h index d6a8dba35..6eee42b61 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h @@ -15,6 +15,7 @@ void print_verilog_submodule_luts(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const std::string& verilog_dir, - const std::string& submodule_dir); + const std::string& submodule_dir, + const bool& use_explicit_port_map); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp index 09c2501f3..c898aac26 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp @@ -25,410 +25,9 @@ /* FPGA-Verilog context header files */ #include "verilog_global.h" #include "verilog_writer_utils.h" +#include "verilog_module_writer.h" #include "verilog_memory.h" -/********************************************************************* - * Flat memory modules - * - * in[0] in[1] in[N] - * | | | - * v v v - * +-------+ +-------+ +-------+ - * | SRAM | | SRAM | ... | SRAM | - * | [0] | | [1] | | [N-1] | - * +-------+ +-------+ +-------+ - * | | ... | - * v v v - * +------------------------------------+ - * | Multiplexer Configuration port | - * - ********************************************************************/ -static -void print_verilog_memory_standalone_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::fstream& fp, - const std::string& module_name, - const CircuitModelId& sram_model, - const size_t& num_mems) { - /* Make sure we have a valid file handler*/ - check_file_handler(fp); - - /* Create a module and add to the module manager */ - ModuleId module_id = module_manager.add_module(module_name); - VTR_ASSERT(ModuleId::INVALID() != module_id); - /* Get the global ports required by the SRAM */ - std::vector global_port_types; - global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); - global_port_types.push_back(SPICE_MODEL_PORT_INPUT); - std::vector sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false); - /* Get the input ports from the SRAM */ - std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); - /* Get the output ports from the SRAM */ - std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); - - /* Add module ports: the ports come from the SRAM modules */ - /* Add each global port */ - for (const auto& port : sram_global_ports) { - /* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); - } - /* Add each input port */ - for (const auto& port : sram_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); - } - /* Add each output port: port width should match the number of memories */ - for (const auto& port : sram_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); - } - - /* dump module definition + ports */ - print_verilog_module_declaration(fp, module_manager, module_id); - /* Finish dumping ports */ - - /* Find the sram module in the module manager */ - ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model)); - - /* Instanciate each submodule */ - for (size_t i = 0; i < num_mems; ++i) { - /* Create a port-to-port map */ - std::map port2port_name_map; - /* Map instance inputs [i] to SRAM module input */ - for (const auto& port : sram_input_ports) { - BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port; - } - /* Map instance outputs [i] to SRAM module input */ - for (const auto& port : sram_output_ports) { - BasicPort instance_output_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_output_port; - } - - /* Output an instance of the module */ - print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_model)); - /* IMPORTANT: this update MUST be called after the instance outputting!!!! - * update the module manager with the relationship between the parent and child modules - */ - module_manager.add_child_module(module_id, sram_module_id); - } - - /* Put an end to the Verilog module */ - print_verilog_module_end(fp, module_name); -} - -/********************************************************************* - * Scan-chain organization - * - * +-------+ +-------+ +-------+ - * scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain - * input&clock | [0] | | [1] | | [N-1] | output - * +-------+ +-------+ +-------+ - * | | ... | - * v v v - * +-----------------------------------------+ - * | Multiplexer Configuration port | - * - ********************************************************************/ -static -void print_verilog_memory_chain_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::fstream& fp, - const std::string& module_name, - const CircuitModelId& sram_model, - const size_t& num_mems) { - /* Make sure we have a valid file handler*/ - check_file_handler(fp); - - /* Create a module and add to the module manager */ - ModuleId module_id = module_manager.add_module(module_name); - VTR_ASSERT(ModuleId::INVALID() != module_id); - /* Get the global ports required by the SRAM */ - std::vector global_port_types; - global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); - global_port_types.push_back(SPICE_MODEL_PORT_INPUT); - std::vector sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false); - /* Get the input ports from the SRAM */ - std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); - /* Should have only 1 input port */ - VTR_ASSERT( 1 == sram_input_ports.size() ); - /* Get the output ports from the SRAM */ - std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); - /* Should have only 1 or 2 output port */ - VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) ); - - /* Add module ports: the ports come from the SRAM modules */ - /* Add each global port */ - for (const auto& port : sram_global_ports) { - /* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); - } - /* Add an input port, which is the head of configuration chain in the module */ - /* TODO: restriction!!! - * consider only the first input of the CCFF model as the D port, - * which will be connected to the head of the chain - */ - BasicPort chain_head_port(generate_configuration_chain_head_name(), - circuit_lib.port_size(sram_input_ports[0])); - module_manager.add_port(module_id, chain_head_port, ModuleManager::MODULE_INPUT_PORT); - /* Add an output port, which is the tail of configuration chain in the module */ - /* TODO: restriction!!! - * consider only the first output of the CCFF model as the Q port, - * which will be connected to the tail of the chain - */ - BasicPort chain_tail_port(generate_configuration_chain_tail_name(), - circuit_lib.port_size(sram_output_ports[0])); - module_manager.add_port(module_id, chain_tail_port, ModuleManager::MODULE_INPUT_PORT); - /* Add each output port: port width should match the number of memories */ - for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { - std::string port_name; - if (0 == iport) { - port_name = generate_configuration_chain_data_out_name(); - } else { - VTR_ASSERT( 1 == iport); - port_name = generate_configuration_chain_inverted_data_out_name(); - } - BasicPort output_port(port_name, num_mems); - module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); - } - - /* dump module definition + ports */ - print_verilog_module_declaration(fp, module_manager, module_id); - /* Finish dumping ports */ - - /* Find the sram module in the module manager */ - ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model)); - - /* Instanciate each submodule */ - for (size_t i = 0; i < num_mems; ++i) { - /* Create a port-to-port map */ - std::map port2port_name_map; - /* Map instance inputs [i] to SRAM module input */ - for (const auto& port : sram_input_ports) { - BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port; - } - /* Map instance outputs [i] to SRAM module input */ - for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { - std::string port_name; - if (0 == iport) { - port_name = generate_configuration_chain_data_out_name(); - } else { - VTR_ASSERT( 1 == iport); - port_name = generate_configuration_chain_inverted_data_out_name(); - } - BasicPort instance_output_port(port_name, i, i); - port2port_name_map[circuit_lib.port_lib_name(sram_output_ports[iport])] = instance_output_port; - } - - /* Output an instance of the module */ - print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_model)); - /* IMPORTANT: this update MUST be called after the instance outputting!!!! - * update the module manager with the relationship between the parent and child modules - */ - module_manager.add_child_module(module_id, sram_module_id); - } - - /* Wire the memory cells into a chain - * The head of the chain will be wired to the input port of the first CCFF - * The tail of the chain will be wired to the output port of the last CCFF - * The output of each CCFF will be wired to the input of the next CCFFF in the chain - */ - BasicPort first_ccff_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 0, 0); - print_verilog_wire_connection(fp, first_ccff_input_port, chain_head_port, false); - - BasicPort last_ccff_output_port(generate_configuration_chain_data_out_name(), num_mems - 1, num_mems - 1); - print_verilog_wire_connection(fp, chain_tail_port, last_ccff_output_port, false); - - BasicPort chain_output_port(generate_configuration_chain_data_out_name(), 0, num_mems - 2); - BasicPort chain_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 1, num_mems - 1); - print_verilog_wire_connection(fp, chain_input_port, chain_output_port, false); - - /* Put an end to the Verilog module */ - print_verilog_module_end(fp, module_name); -} - -/********************************************************************* - * Memory bank organization - * - * Bit lines(BL/BLB) Word lines (WL/WLB) - * | | - * v v - * +------------------------------------+ - * | Memory Module Configuration port | - * +------------------------------------+ - * | | | - * v v v - * +-------+ +-------+ +-------+ - * | SRAM | | SRAM | ... | SRAM | - * | [0] | | [1] | | [N-1] | - * +-------+ +-------+ +-------+ - * | | ... | - * v v v - * +------------------------------------+ - * | Multiplexer Configuration port | - * - ********************************************************************/ -static -void print_verilog_memory_bank_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::fstream& fp, - const std::string& module_name, - const CircuitModelId& sram_model, - const size_t& num_mems) { - /* Make sure we have a valid file handler*/ - check_file_handler(fp); - - /* Create a module and add to the module manager */ - ModuleId module_id = module_manager.add_module(module_name); - VTR_ASSERT(ModuleId::INVALID() != module_id); - /* Get the global ports required by the SRAM */ - std::vector global_port_types; - global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); - global_port_types.push_back(SPICE_MODEL_PORT_INPUT); - std::vector sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false); - /* Get the input ports from the SRAM */ - std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true); - /* A SRAM cell with BL/WL should not have any input */ - VTR_ASSERT( 0 == sram_input_ports.size() ); - /* Get the output ports from the SRAM */ - std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true); - /* Get the BL/WL ports from the SRAM */ - std::vector sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true); - std::vector sram_blb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BLB, true); - std::vector sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_WL, true); - std::vector sram_wlb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_WLB, true); - - /* Add module ports: the ports come from the SRAM modules */ - /* Add each global port */ - for (const auto& port : sram_global_ports) { - /* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); - } - /* Add each input port */ - for (const auto& port : sram_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); - } - /* Add each output port: port width should match the number of memories */ - for (const auto& port : sram_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); - } - /* Add each output port: port width should match the number of memories */ - for (const auto& port : sram_bl_ports) { - BasicPort bl_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, bl_port, ModuleManager::MODULE_INPUT_PORT); - } - for (const auto& port : sram_blb_ports) { - BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, blb_port, ModuleManager::MODULE_INPUT_PORT); - } - for (const auto& port : sram_wl_ports) { - BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); - } - for (const auto& port : sram_wlb_ports) { - BasicPort wlb_port(circuit_lib.port_lib_name(port), num_mems); - module_manager.add_port(module_id, wlb_port, ModuleManager::MODULE_INPUT_PORT); - } - - /* dump module definition + ports */ - print_verilog_module_declaration(fp, module_manager, module_id); - /* Finish dumping ports */ - - /* Find the sram module in the module manager */ - ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model)); - - /* Instanciate each submodule */ - for (size_t i = 0; i < num_mems; ++i) { - /* Create a port-to-port map */ - std::map port2port_name_map; - /* Map instance inputs [i] to SRAM module input */ - for (const auto& port : sram_input_ports) { - BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port; - } - /* Map instance outputs [i] to SRAM module input */ - for (const auto& port : sram_output_ports) { - BasicPort instance_output_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_output_port; - } - /* Map instance BL[i] and WL[i] to SRAM module input */ - for (const auto& port : sram_bl_ports) { - BasicPort instance_bl_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_bl_port; - } - for (const auto& port : sram_blb_ports) { - BasicPort instance_blb_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_blb_port; - } - for (const auto& port : sram_wl_ports) { - BasicPort instance_wl_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_wl_port; - } - for (const auto& port : sram_wlb_ports) { - BasicPort instance_wlb_port(circuit_lib.port_lib_name(port), i, i); - port2port_name_map[circuit_lib.port_lib_name(port)] = instance_wlb_port; - } - - /* Output an instance of the module */ - print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_model)); - /* IMPORTANT: this update MUST be called after the instance outputting!!!! - * update the module manager with the relationship between the parent and child modules - */ - module_manager.add_child_module(module_id, sram_module_id); - } - - /* TODO: if a local memory decoder is required, instanciate it here */ - - /* Put an end to the Verilog module */ - print_verilog_module_end(fp, module_name); -} - - -/********************************************************************* - * Generate Verilog modules for the memories that are used - * by a circuit model - * The organization of memory circuit will depend on the style of - * configuration protocols - * Currently, we support - * 1. Flat SRAM organization - * 2. Configuration chain - * 3. Memory bank (memory decoders) - ********************************************************************/ -static -void print_verilog_memory_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - const e_sram_orgz& sram_orgz_type, - std::fstream& fp, - const std::string& module_name, - const CircuitModelId& sram_model, - const size_t& num_mems) { - switch (sram_orgz_type) { - case SPICE_SRAM_STANDALONE: - print_verilog_memory_standalone_module(module_manager, circuit_lib, fp, - module_name, sram_model, num_mems); - break; - case SPICE_SRAM_SCAN_CHAIN: - print_verilog_memory_chain_module(module_manager, circuit_lib, fp, - module_name, sram_model, num_mems); - break; - case SPICE_SRAM_MEMORY_BANK: - print_verilog_memory_bank_module(module_manager, circuit_lib, fp, - module_name, sram_model, num_mems); - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, LINE%d) Invalid SRAM organization!\n", - __FILE__, __LINE__); - } -} - - /********************************************************************* * Generate Verilog modules for the memories that are used * by multiplexers @@ -445,14 +44,10 @@ void print_verilog_memory_module(ModuleManager& module_manager, static void print_verilog_mux_memory_module(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, - const e_sram_orgz& sram_orgz_type, std::fstream& fp, const CircuitModelId& mux_model, - const MuxGraph& mux_graph) { - /* Find the actual number of configuration bits, based on the mux graph - * Due to the use of local decoders inside mux, this may be - */ - size_t num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type); + const MuxGraph& mux_graph, + const bool& use_explicit_port_map) { /* Multiplexers built with different technology is in different organization */ switch (circuit_lib.design_tech_type(mux_model)) { case SPICE_MODEL_DESIGN_CMOS: { @@ -460,12 +55,14 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager, std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model, find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()), std::string(verilog_mem_posfix)); + ModuleId mem_module = module_manager.find_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + /* Write the module content in Verilog format */ + write_verilog_module_to_file(fp, module_manager, mem_module, + use_explicit_port_map || circuit_lib.dump_explicit_port_map(mux_model)); - /* Get the sram ports from the mux */ - std::vector sram_models = find_circuit_sram_models(circuit_lib, mux_model); - VTR_ASSERT( 1 == sram_models.size() ); - - print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_config_bits); + /* Add an empty line as a splitter */ + fp << std::endl; break; } case SPICE_MODEL_DESIGN_RRAM: @@ -502,9 +99,9 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager, void print_verilog_submodule_memories(ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const e_sram_orgz& sram_orgz_type, const std::string& verilog_dir, - const std::string& submodule_dir) { + const std::string& submodule_dir, + const bool& use_explicit_port_map) { /* Plug in with the mux subckt */ std::string verilog_fname(submodule_dir + memories_verilog_file_name); verilog_fname += ".bak"; @@ -536,7 +133,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager, continue; } /* Create a Verilog module for the memories used by the multiplexer */ - print_verilog_mux_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, mux_model, mux_graph); + print_verilog_mux_memory_module(module_manager, circuit_lib, fp, mux_model, mux_graph, use_explicit_port_map); } /* Create the memory circuits for non-MUX circuit models. @@ -577,8 +174,14 @@ void print_verilog_submodule_memories(ModuleManager& module_manager, /* Create the module name for the memory block */ std::string module_name = generate_memory_module_name(circuit_lib, model, sram_models[0], std::string(verilog_mem_posfix)); - /* Create a Verilog module for the memories used by the circuit model */ - print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_mems); + ModuleId mem_module = module_manager.find_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + /* Write the module content in Verilog format */ + write_verilog_module_to_file(fp, module_manager, mem_module, + use_explicit_port_map || circuit_lib.dump_explicit_port_map(model)); + + /* Add an empty line as a splitter */ + fp << std::endl; } /* Close the file stream */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h index eee29cb23..bfba1c391 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h @@ -16,8 +16,8 @@ void print_verilog_submodule_memories(ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const e_sram_orgz& sram_orgz_type, const std::string& verilog_dir, - const std::string& submodule_dir); + const std::string& submodule_dir, + const bool& use_explicit_port_map); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index 232d7fdf4..413d57e5a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -575,7 +575,8 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager, std::fstream& fp, const CircuitModelId& mux_model, const size_t& mux_size, - const MuxGraph& mux_graph) { + const MuxGraph& mux_graph, + const bool& use_explicit_port_map) { std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix); /* Multiplexers built with different technology is in different organization */ @@ -585,7 +586,8 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager, /* Structural verilog can be easily generated by module writer */ ModuleId mux_module = module_manager.find_module(module_name); VTR_ASSERT(true == module_manager.valid_module_id(mux_module)); - write_verilog_module_to_file(fp, module_manager, mux_module, circuit_lib.dump_explicit_port_map(mux_model)); + write_verilog_module_to_file(fp, module_manager, mux_module, + use_explicit_port_map || circuit_lib.dump_explicit_port_map(mux_model)); /* Add an empty line as a splitter */ fp << std::endl; } else { @@ -1170,7 +1172,8 @@ void generate_verilog_mux_module(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, std::fstream& fp, const CircuitModelId& mux_model, - const MuxGraph& mux_graph) { + const MuxGraph& mux_graph, + const bool& use_explicit_port_map) { std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model, find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()), std::string("")); @@ -1181,7 +1184,8 @@ void generate_verilog_mux_module(ModuleManager& module_manager, /* Use Verilog writer to print the module to file */ ModuleId mux_module = module_manager.find_module(module_name); VTR_ASSERT(true == module_manager.valid_module_id(mux_module)); - write_verilog_module_to_file(fp, module_manager, mux_module, circuit_lib.dump_explicit_port_map(mux_model)); + write_verilog_module_to_file(fp, module_manager, mux_module, + use_explicit_port_map || circuit_lib.dump_explicit_port_map(mux_model)); /* Add an empty line as a splitter */ fp << std::endl; break; @@ -1208,7 +1212,8 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, t_sram_orgz_info* cur_sram_orgz_info, const std::string& verilog_dir, - const std::string& submodule_dir) { + const std::string& submodule_dir, + const bool& use_explicit_port_map) { /* TODO: Generate modules into a .bak file now. Rename after it is verified */ std::string verilog_fname(submodule_dir + muxes_verilog_file_name); @@ -1239,7 +1244,7 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager, for (auto branch_mux_graph : branch_mux_graphs) { generate_verilog_mux_branch_module(module_manager, circuit_lib, fp, mux_circuit_model, find_mux_num_datapath_inputs(circuit_lib, mux_circuit_model, mux_graph.num_inputs()), - branch_mux_graph); + branch_mux_graph, use_explicit_port_map); } } @@ -1248,7 +1253,7 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager, const MuxGraph& mux_graph = mux_lib.mux_graph(mux); CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux); /* Create MUX circuits */ - generate_verilog_mux_module(module_manager, circuit_lib, fp, mux_circuit_model, mux_graph); + generate_verilog_mux_module(module_manager, circuit_lib, fp, mux_circuit_model, mux_graph, use_explicit_port_map); } /* Close the file stream */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h index 2db3e1f45..51f3c7d7b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h @@ -18,6 +18,7 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, t_sram_orgz_info* cur_sram_orgz_info, const std::string& verilog_dir, - const std::string& submodule_dir); + const std::string& submodule_dir, + const bool& use_explicit_port_map); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index 91080490b..a4199308d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -3283,7 +3283,9 @@ void dump_verilog_submodules(ModuleManager& module_manager, */ print_verilog_submodule_mux_local_decoders(module_manager, mux_lib, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir)); - print_verilog_submodule_muxes(module_manager, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info, std::string(verilog_dir), std::string(submodule_dir)); + print_verilog_submodule_muxes(module_manager, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info, + std::string(verilog_dir), std::string(submodule_dir), + fpga_verilog_opts.dump_explicit_verilog); /* 2. LUTes */ @@ -3293,7 +3295,8 @@ void dump_verilog_submodules(ModuleManager& module_manager, fpga_verilog_opts.include_timing, fpga_verilog_opts.include_signal_init, fpga_verilog_opts.dump_explicit_verilog); - print_verilog_submodule_luts(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir)); + print_verilog_submodule_luts(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir), + fpga_verilog_opts.dump_explicit_verilog); /* 3. Hardwires */ print_verilog_submodule_wires(module_manager, Arch.spice->circuit_lib, L_segment_vec, std::string(verilog_dir), std::string(submodule_dir)); @@ -3303,8 +3306,8 @@ void dump_verilog_submodules(ModuleManager& module_manager, dump_verilog_submodule_memories(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch, switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog); print_verilog_submodule_memories(module_manager, mux_lib, Arch.spice->circuit_lib, - cur_sram_orgz_info->type, - std::string(verilog_dir), std::string(submodule_dir)); + std::string(verilog_dir), std::string(submodule_dir), + fpga_verilog_opts.dump_explicit_verilog); /* 5. Dump template for all the modules */ if (TRUE == fpga_verilog_opts.print_user_defined_template) {