diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp index 5f82e12ae..6eeb5fa7c 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp @@ -819,6 +819,13 @@ CircuitModelId CircuitLibrary::port_tri_state_model(const CircuitPortId& circuit return port_tri_state_model_ids_[circuit_port_id]; } +/* Return circuit model name which is used to tri-state a port */ +std::string CircuitLibrary::port_tri_state_model_name(const CircuitPortId& circuit_port_id) const { + /* validate the circuit_port_id */ + VTR_ASSERT(valid_circuit_port_id(circuit_port_id)); + return port_tri_state_model_names_[circuit_port_id]; +} + /* Return the id of parent circuit model for a circuit port */ CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const { /* validate the circuit_port_id */ diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.h b/vpr7_x2p/libarchfpga/SRC/circuit_library.h index 30ae83aab..220be6a97 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.h +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.h @@ -287,6 +287,7 @@ class CircuitLibrary { std::vector port_lut_output_masks(const CircuitPortId& circuit_port_id) const; std::string port_tri_state_map(const CircuitPortId& circuit_port_id) const; CircuitModelId port_tri_state_model(const CircuitPortId& circuit_port_id) const; + std::string port_tri_state_model_name(const CircuitPortId& circuit_port_id) const; CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const; std::string model_name(const CircuitPortId& port_id) const; public: /* Public Accessors: Timing graph */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c index c7a5df808..bdc3bbfbb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c @@ -3148,6 +3148,39 @@ void config_spice_models_sram_port_spice_model(int num_spice_model, return; } +/******************************************************************** + * Link the circuit model of SRAM ports of each circuit model + * to a default SRAM circuit model. + * This function aims to ease the XML writing, allowing users to skip + * the circuit model definition for SRAM ports that are used by default + * TODO: Maybe deprecated as we prefer strict definition + *******************************************************************/ +void config_circuit_models_sram_port_to_default_sram_model(CircuitLibrary& circuit_lib, + const CircuitModelId& default_sram_model) { + for (const auto& model : circuit_lib.models()) { + for (const auto& port : circuit_lib.model_ports(model)) { + /* Bypass non SRAM ports */ + if (SPICE_MODEL_PORT_SRAM != circuit_lib.port_type(port)) { + continue; + } + /* Write for the default SRAM SPICE model! */ + circuit_lib.set_port_tri_state_model_id(port, default_sram_model); + /* Only show warning when we try to override the given spice_model_name ! */ + if (circuit_lib.port_tri_state_model_name(port).empty()) { + continue; + } + /* Give a warning !!! */ + if (0 != circuit_lib.model_name(default_sram_model).compare(circuit_lib.port_tri_state_model_name(port))) { + vpr_printf(TIO_MESSAGE_WARNING, + "Overwrite SRAM circuit model for circuit model port (name:%s, port:%s) to be the correct one (name:%s)!\n", + circuit_lib.model_name(model).c_str(), + circuit_lib.port_prefix(port).c_str(), + circuit_lib.model_name(default_sram_model).c_str()); + } + } + } +} + void determine_sb_port_coordinator(t_sb cur_sb_info, int side, int* port_x, int* port_y) { /* Check */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h index 8d0408bcd..8a5a0a9e4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h @@ -362,6 +362,9 @@ void config_spice_models_sram_port_spice_model(int num_spice_model, t_spice_model* spice_models, t_spice_model* default_sram_spice_model); +void config_circuit_models_sram_port_to_default_sram_model(CircuitLibrary& circuit_lib, + const CircuitModelId& default_sram_model); + void determine_sb_port_coordinator(t_sb cur_sb_info, int side, int* port_x, int* port_y); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index a6257608a..19c80b25e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -236,6 +236,7 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, config_spice_models_sram_port_spice_model(Arch.spice->num_spice_model, Arch.spice->spice_models, Arch.sram_inf.verilog_sram_inf_orgz->spice_model); + config_circuit_models_sram_port_to_default_sram_model(Arch.spice->circuit_lib, Arch.sram_inf.verilog_sram_inf_orgz->circuit_model); /* Assign global variables of input and output pads */ iopad_verilog_model = find_iopad_spice_model(Arch.spice->num_spice_model, Arch.spice->spice_models); 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 fde7d9d03..2dea66cc5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp @@ -26,6 +26,258 @@ #include "verilog_writer_utils.h" #include "verilog_memory.h" +/********************************************************************* + * Generate Verilog modules for the memories that are used + * by CMOS (SRAM-based) multiplexers + * We support: + * 1. 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 | + * + * 2. TODO: Local decoders + * + * in[0] in[1] in[N] + * | | | + * v v v + * +-------+ +-------+ +-------+ + * | SRAM | | SRAM | ... | SRAM | + * | [0] | | [1] | | [N-1] | + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +------------------------------------+ + * | Local decoders | + * +------------------------------------+ + * | | ... | + * v v v + * +------------------------------------+ + * | Multiplexer Configuration port | + * + * 3. TODO: Scan-chain organization + * + * in[0] in[1] in[N] + * | | | + * v v v + * +-------+ +-------+ +-------+ + * scan-chain--->| SRAM |--->| SRAM |--->... --->| SRAM |---->scan-chain + * input&clock | [0] | | [1] | | [N-1] | output + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +-----------------------------------------+ + * | Multiplexer Configuration port | + * + * 4. TODO: Memory bank organization + * + * Bit lines Word lines + * | | + * v v + * +------------------------------------+ + * | Multiplexer Configuration port | + * +------------------------------------+ + * | | | + * v v v + * +-------+ +-------+ +-------+ + * | SRAM | | SRAM | ... | SRAM | + * | [0] | | [1] | | [N-1] | + * +-------+ +-------+ +-------+ + * | | ... | + * v v v + * +------------------------------------+ + * | Multiplexer Configuration port | + + * + ********************************************************************/ +static +void print_verilog_cmos_mux_memory_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + std::fstream& fp, + const CircuitModelId& mux_model, + const MuxGraph& mux_graph) { + /* Make sure we have a valid file handler*/ + check_file_handler(fp); + + /* Generate module name */ + std::string module_name = generate_verilog_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 mux_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true); + VTR_ASSERT( 1 == mux_sram_ports.size() ); + /* Get the circuit model for the memory circuit used by the multiplexer */ + CircuitModelId sram_model = circuit_lib.port_tri_state_model(mux_sram_ports[0]); + VTR_ASSERT(CircuitModelId::INVALID() != sram_model); + + /* 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 sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true, true); + /* 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); + /* 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); + + /* Find the number of SRAMs in the module, this is also the port width */ + size_t num_mems = mux_graph.num_memory_bits(); + + /* 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: port width should match the number of memories */ + 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); + } + + /* Put an end to the Verilog module */ + print_verilog_module_end(fp, module_name); +} + +/********************************************************************* + * 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 print_verilog_mux_memory_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + std::fstream& fp, + const CircuitModelId& mux_model, + const MuxGraph& mux_graph) { + /* Multiplexers built with different technology is in different organization */ + switch (circuit_lib.design_tech_type(mux_model)) { + case SPICE_MODEL_DESIGN_CMOS: + print_verilog_cmos_mux_memory_module(module_manager, circuit_lib, fp, mux_model, mux_graph); + 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); + } +} + + +/********************************************************************* + * Generate Verilog 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 print_verilog_submodule_memories(ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, @@ -55,7 +307,6 @@ void print_verilog_submodule_memories(ModuleManager& module_manager, for (auto mux : mux_lib.muxes()) { const MuxGraph& mux_graph = mux_lib.mux_graph(mux); CircuitModelId mux_model = mux_lib.mux_circuit_model(mux); - /* Create a Verilog module for the memories used by the multiplexer */ /* 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 @@ -63,6 +314,8 @@ void print_verilog_submodule_memories(ModuleManager& module_manager, if (SPICE_MODEL_MUX != circuit_lib.model_type(mux_model)) { continue; } + /* Create a Verilog module for the memories used by the multiplexer */ + print_verilog_mux_memory_module(module_manager, circuit_lib, fp, mux_model, mux_graph); } /* Create the memory circuits for non-MUX circuit models.