Skip to content

Commit

Permalink
keep refactoring the memory Verilog generation
Browse files Browse the repository at this point in the history
  • Loading branch information
tangxifan committed Sep 13, 2019
1 parent 56f40cf commit 99c30fa
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 1 deletion.
7 changes: 7 additions & 0 deletions vpr7_x2p/libarchfpga/SRC/circuit_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions vpr7_x2p/libarchfpga/SRC/circuit_library.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ class CircuitLibrary {
std::vector<size_t> 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 */
Expand Down
33 changes: 33 additions & 0 deletions vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
255 changes: 254 additions & 1 deletion vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CircuitPortId> 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<CircuitPortId> 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<CircuitPortId> 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<CircuitPortId> 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<CircuitPortId> sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true);
std::vector<CircuitPortId> sram_blb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BLB, true);
std::vector<CircuitPortId> sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_WL, true);
std::vector<CircuitPortId> 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<std::string, BasicPort> 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,
Expand Down Expand Up @@ -55,14 +307,15 @@ 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
*/
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.
Expand Down

0 comments on commit 99c30fa

Please sign in to comment.