start integrating module graph builder

This commit is contained in:
tangxifan 2020-02-12 17:53:23 -07:00
parent 13fadd0f91
commit f11832b8cf
19 changed files with 4899 additions and 13 deletions

View File

@ -7,7 +7,7 @@
#include "device_rr_gsb.h" #include "device_rr_gsb.h"
#include "device_rr_gsb_utils.h" #include "device_rr_gsb_utils.h"
//#include "build_device_module.h" #include "build_device_module.h"
#include "openfpga_build_fabric.h" #include "openfpga_build_fabric.h"
/* Include global variables of VPR */ /* Include global variables of VPR */
@ -67,9 +67,10 @@ void build_fabric(OpenfpgaContext& openfpga_context,
compress_routing_hierarchy(openfpga_context, cmd_context.option_enable(cmd, opt_verbose)); compress_routing_hierarchy(openfpga_context, cmd_context.option_enable(cmd, opt_verbose));
} }
/* VTR_LOG("\n");
openfpga_context.mutable_module_graph() = build_device_module_graph();
*/ openfpga_context.mutable_module_graph() = build_device_module_graph(g_vpr_ctx.device(),
const_cast<const OpenfpgaContext&>(openfpga_context));
} }
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -8,6 +8,7 @@
#include "vpr_clustering_annotation.h" #include "vpr_clustering_annotation.h"
#include "vpr_routing_annotation.h" #include "vpr_routing_annotation.h"
#include "mux_library.h" #include "mux_library.h"
#include "module_manager.h"
#include "device_rr_gsb.h" #include "device_rr_gsb.h"
/******************************************************************** /********************************************************************
@ -46,6 +47,7 @@ class OpenfpgaContext : public Context {
const openfpga::VprRoutingAnnotation& vpr_routing_annotation() const { return vpr_routing_annotation_; } const openfpga::VprRoutingAnnotation& vpr_routing_annotation() const { return vpr_routing_annotation_; }
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; } const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; } const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
public: /* Public mutators */ public: /* Public mutators */
openfpga::Arch& mutable_arch() { return arch_; } openfpga::Arch& mutable_arch() { return arch_; }
openfpga::VprDeviceAnnotation& mutable_vpr_device_annotation() { return vpr_device_annotation_; } openfpga::VprDeviceAnnotation& mutable_vpr_device_annotation() { return vpr_device_annotation_; }
@ -54,6 +56,7 @@ class OpenfpgaContext : public Context {
openfpga::VprRoutingAnnotation& mutable_vpr_routing_annotation() { return vpr_routing_annotation_; } openfpga::VprRoutingAnnotation& mutable_vpr_routing_annotation() { return vpr_routing_annotation_; }
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; } openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; } openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
private: /* Internal data */ private: /* Internal data */
/* Data structure to store information from read_openfpga_arch library */ /* Data structure to store information from read_openfpga_arch library */
openfpga::Arch arch_; openfpga::Arch arch_;
@ -75,6 +78,9 @@ class OpenfpgaContext : public Context {
/* Library of physical implmentation of routing multiplexers */ /* Library of physical implmentation of routing multiplexers */
openfpga::MuxLibrary mux_lib_; openfpga::MuxLibrary mux_lib_;
/* Fabric module graph */
openfpga::ModuleManager module_graph_;
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,262 @@
/************************************************
* Header file for fpga_x2p_naming.cpp
* Include functions to generate module/port names
* for Verilog and SPICE netlists
***********************************************/
#ifndef OPENFPGA_NAMING_H
#define OPENFPGA_NAMING_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "vtr_geometry.h"
#include "circuit_library.h"
#include "device_grid.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
std::string generate_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);
std::string generate_mux_branch_instance_name(const size_t& node_level,
const size_t& node_index_at_level,
const bool& add_buffer_postfix);
std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const std::string& posfix) ;
std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const size_t& branch_mux_size,
const std::string& posfix);
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
const size_t& data_size);
std::string generate_segment_wire_subckt_name(const std::string& wire_model_name,
const size_t& segment_id);
std::string generate_segment_wire_mid_output_name(const std::string& regular_output_name);
std::string generate_memory_module_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const CircuitModelId& sram_model,
const std::string& postfix);
std::string generate_routing_block_netlist_name(const std::string& prefix,
const size_t& block_id,
const std::string& postfix);
std::string generate_routing_block_netlist_name(const std::string& prefix,
const vtr::Point<size_t>& block_id,
const std::string& postfix);
std::string generate_connection_block_netlist_name(const t_rr_type& cb_type,
const vtr::Point<size_t>& coordinate,
const std::string& postfix);
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
const size_t& block_id);
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
const vtr::Point<size_t>& coordinate);
std::string generate_routing_track_port_name(const t_rr_type& chan_type,
const vtr::Point<size_t>& coordinate,
const size_t& track_id,
const PORTS& port_direction);
std::string generate_sb_module_track_port_name(const t_rr_type& chan_type,
const e_side& module_side,
const size_t& track_id,
const PORTS& port_direction);
std::string generate_cb_module_track_port_name(const t_rr_type& chan_type,
const size_t& track_id,
const PORTS& port_direction);
std::string generate_routing_track_middle_output_port_name(const t_rr_type& chan_type,
const vtr::Point<size_t>& coordinate,
const size_t& track_id);
std::string generate_switch_block_module_name(const vtr::Point<size_t>& coordinate);
std::string generate_connection_block_module_name(const t_rr_type& cb_type,
const vtr::Point<size_t>& coordinate);
std::string generate_sb_mux_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,
const std::string& postfix);
std::string generate_sb_memory_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,
const std::string& postfix);
std::string generate_cb_mux_instance_name(const std::string& prefix,
const e_side& cb_side,
const size_t& pin_id,
const std::string& postfix);
std::string generate_cb_memory_instance_name(const std::string& prefix,
const e_side& cb_side,
const size_t& pin_id,
const std::string& postfix);
std::string generate_pb_mux_instance_name(const std::string& prefix,
t_pb_graph_pin* pb_graph_pin,
const std::string& postfix);
std::string generate_pb_memory_instance_name(const std::string& prefix,
t_pb_graph_pin* pb_graph_pin,
const std::string& postfix);
std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
const size_t& width,
const size_t& height,
const e_side& side,
const size_t& pin_id,
const bool& for_top_netlist);
std::string generate_grid_duplicated_port_name(const size_t& width,
const size_t& height,
const e_side& side,
const size_t& pin_id,
const bool& upper_port);
std::string generate_grid_module_port_name(const size_t& pin_id);
std::string generate_grid_side_port_name(const DeviceGrid& grids,
const vtr::Point<size_t>& coordinate,
const e_side& side,
const size_t& pin_id);
std::string generate_sb_module_grid_port_name(const e_side& sb_side,
const e_side& grid_side,
const size_t& pin_id);
std::string generate_cb_module_grid_port_name(const e_side& cb_side,
const size_t& pin_id);
std::string generate_reserved_sram_port_name(const e_circuit_model_port_type& port_type);
std::string generate_formal_verification_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model);
std::string generate_configuration_chain_head_name();
std::string generate_configuration_chain_tail_name();
std::string generate_configuration_chain_data_out_name();
std::string generate_configuration_chain_inverted_data_out_name();
std::string generate_mux_local_decoder_addr_port_name();
std::string generate_mux_local_decoder_data_port_name();
std::string generate_mux_local_decoder_data_inv_port_name();
std::string generate_local_config_bus_port_name();
std::string generate_sram_port_name(const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_port_type& port_type);
std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_port_type& port_type);
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id);
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& bus_id,
const bool& inverted);
std::string generate_local_sram_port_name(const std::string& port_prefix,
const size_t& instance_id,
const e_circuit_model_port_type& port_type);
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const e_circuit_model_port_type& port_type);
std::string generate_grid_block_prefix(const std::string& prefix,
const e_side& io_side);
std::string generate_grid_block_netlist_name(const std::string& block_name,
const bool& is_block_io,
const e_side& io_side,
const std::string& postfix);
std::string generate_grid_block_module_name(const std::string& prefix,
const std::string& block_name,
const bool& is_block_io,
const e_side& io_side);
std::string generate_grid_block_instance_name(const std::string& prefix,
const std::string& block_name,
const bool& is_block_io,
const e_side& io_side,
const vtr::Point<size_t>& grid_coord);
std::string generate_physical_block_module_name(const std::string& prefix,
t_pb_type* physical_pb_type);
std::string generate_physical_block_instance_name(const std::string& prefix,
t_pb_type* pb_type,
const size_t& index);
std::string generate_grid_physical_block_module_name(const std::string& prefix,
t_pb_type* pb_type,
const e_side& border_side);
std::string generate_grid_physical_block_instance_name(const std::string& prefix,
t_pb_type* pb_type,
const e_side& border_side,
const size_t& index);
e_side find_grid_border_side(const vtr::Point<size_t>& device_size,
const vtr::Point<size_t>& grid_coordinate);
bool is_core_grid_on_given_border_side(const vtr::Point<size_t>& device_size,
const vtr::Point<size_t>& grid_coordinate,
const e_side& border_side);
std::string generate_pb_type_port_name(t_port* pb_type_port);
std::string generate_fpga_global_io_port_name(const std::string& prefix,
const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
std::string generate_fpga_top_module_name();
std::string generate_fpga_top_netlist_name(const std::string& postfix);
std::string generate_const_value_module_name(const size_t& const_val);
std::string generate_const_value_module_output_port_name(const size_t& const_val);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,104 @@
/********************************************************************
* This file includes the main function to build module graphs
* for the FPGA fabric
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
#include "build_essential_modules.h"
//#include "build_decoder_modules.h"
//#include "build_mux_modules.h"
//#include "build_lut_modules.h"
//#include "build_wire_modules.h"
//#include "build_memory_modules.h"
//#include "build_grid_modules.h"
//#include "build_routing_modules.h"
//#include "build_top_module.h"
#include "build_device_module.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* The main function to be called for building module graphs
* for a FPGA fabric
*******************************************************************/
ModuleManager build_device_module_graph(const DeviceContext& vpr_device_ctx,
const OpenfpgaContext& openfpga_ctx) {
vtr::ScopedStartFinishTimer timer("Build fabric module graph");
/* Module manager to be built */
ModuleManager module_manager;
CircuitModelId sram_model = openfpga_ctx.arch().config_protocol.memory_model();
VTR_ASSERT(true == openfpga_ctx.arch().circuit_lib.valid_model_id(sram_model));
/* Add constant generator modules: VDD and GND */
build_constant_generator_modules(module_manager);
/* Register all the user-defined modules in the module manager
* This should be done prior to other steps in this function,
* because they will be instanciated by other primitive modules
*/
build_user_defined_modules(module_manager, openfpga_ctx.arch().circuit_lib);
/* Build elmentary modules */
build_essential_modules(module_manager, openfpga_ctx.arch().circuit_lib);
/* Build local encoders for multiplexers, this MUST be called before multiplexer building */
//build_mux_local_decoder_modules(module_manager, mux_lib, arch.spice->circuit_lib);
/* Build multiplexer modules */
//build_mux_modules(module_manager, mux_lib, arch.spice->circuit_lib);
/* Build LUT modules */
//build_lut_modules(module_manager, arch.spice->circuit_lib);
/* Build wire modules */
//build_wire_modules(module_manager, arch.spice->circuit_lib);
/* Build memory modules */
//build_memory_modules(module_manager, mux_lib, arch.spice->circuit_lib,
// arch.sram_inf.verilog_sram_inf_orgz->type);
/* Build grid and programmable block modules */
//build_grid_modules(module_manager, arch.spice->circuit_lib, mux_lib,
// arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
// TRUE == vpr_setup.FPGA_SPICE_Opts.duplicate_grid_pin);
//if (TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy) {
// build_unique_routing_modules(module_manager, L_device_rr_gsb, arch.spice->circuit_lib,
// arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
// vpr_setup.RoutingArch, rr_switches);
//} else {
// VTR_ASSERT(FALSE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
// build_flatten_routing_modules(module_manager, L_device_rr_gsb, arch.spice->circuit_lib,
// arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
// vpr_setup.RoutingArch, rr_switches);
//}
/* Build FPGA fabric top-level module */
//build_top_module(module_manager, arch.spice->circuit_lib,
// device_size, grids, L_device_rr_gsb,
// clb2clb_directs,
// arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
// TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy,
// TRUE == vpr_setup.FPGA_SPICE_Opts.duplicate_grid_pin);
/* Now a critical correction has to be done!
* In the module construction, we always use prefix of ports because they are binded
* to the ports in architecture description (logic blocks etc.)
* To interface with standard cell, we should
* rename the ports of primitive modules using lib_name instead of prefix
* (which have no children and are probably linked to a standard cell!)
*/
//rename_primitive_module_port_names(module_manager, arch.spice->circuit_lib);
return module_manager;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,22 @@
#ifndef BUILD_DEVICE_MODULE_H
#define BUILD_DEVICE_MODULE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
ModuleManager build_device_module_graph(const DeviceContext& vpr_device_ctx,
const OpenfpgaContext& openfpga_ctx);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,271 @@
/********************************************************************
* This function includes the module builders for essential logic gates
* which are the leaf circuit model in the circuit library
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
#include "openfpga_naming.h"
#include "module_manager_utils.h"
#include "build_essential_modules.h"
/* begin namespace openfpga */
namespace openfpga {
/************************************************
* Build a module of inverter or buffer
* or tapered buffer to a file
***********************************************/
static
void build_invbuf_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
/* Find the input port, output port and global inputs*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
/* Make sure:
* There is only 1 input port and 1 output port,
* each size of which is 1
*/
VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
/* TODO: move the check codes to check_circuit_library.h */
/* If the circuit model is power-gated, we need to find at least one global config_enable signals */
if (true == circuit_lib.is_power_gated(circuit_model)) {
/* Check all the ports we have are good for a power-gated circuit model */
size_t num_err = 0;
/* We need at least one global port */
if (0 == global_ports.size()) {
num_err++;
}
/* All the global ports should be config_enable */
for (const auto& port : global_ports) {
if (false == circuit_lib.port_is_config_enable(port)) {
num_err++;
}
}
/* Report errors if there are any */
if (0 < num_err) {
VTR_LOG_ERROR("Inverter/buffer circuit model '%s' is power-gated. At least one config-enable global port is required!\n",
circuit_lib.model_name(circuit_model).c_str());
exit(1);
}
}
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
VTR_ASSERT(true == module_manager.valid_module_id(module_id));
}
/************************************************
* Build a module of a pass-gate,
* either transmission-gate or pass-transistor
***********************************************/
static
void build_passgate_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
/* Find the input port, output port*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
switch (circuit_lib.pass_gate_logic_type(circuit_model)) {
case CIRCUIT_MODEL_PASS_GATE_TRANSMISSION:
/* Make sure:
* There is only 3 input port (in, sel, selb),
* each size of which is 1
*/
VTR_ASSERT( 3 == input_ports.size() );
for (const auto& input_port : input_ports) {
VTR_ASSERT(1 == circuit_lib.port_size(input_port));
}
break;
case CIRCUIT_MODEL_PASS_GATE_TRANSISTOR:
/* Make sure:
* There is only 2 input port (in, sel),
* each size of which is 1
*/
VTR_ASSERT( 2 == input_ports.size() );
for (const auto& input_port : input_ports) {
VTR_ASSERT(1 == circuit_lib.port_size(input_port));
}
break;
default:
VTR_LOG_ERROR("Invalid topology for circuit model '%s'!\n",
circuit_lib.model_name(circuit_model).c_str());
exit(1);
}
/* Make sure:
* There is only 1 output port,
* each size of which is 1
*/
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
VTR_ASSERT(true == module_manager.valid_module_id(module_id));
}
/************************************************
* Build a module of a logic gate
* which are standard cells
* Supported gate types:
* 1. N-input AND
* 2. N-input OR
* 3. 2-input MUX
***********************************************/
static
void build_gate_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
/* Find the input port, output port*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
/* Make sure:
* There is only 1 output port,
* each size of which is 1
*/
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
VTR_ASSERT(true == module_manager.valid_module_id(module_id));
}
/************************************************
* Generate the modules for essential gates
* include inverters, buffers, transmission-gates,
* etc.
***********************************************/
void build_essential_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib) {
vtr::ScopedStartFinishTimer timer("Build essential (inverter/buffer/logic gate) modules...");
for (const auto& circuit_model : circuit_lib.models()) {
/* Add essential modules upon on demand: only when it is not yet in the module library */
ModuleId module = module_manager.find_module(circuit_lib.model_name(circuit_model));
if (true == module_manager.valid_module_id(module)) {
continue;
}
if (CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) {
build_invbuf_module(module_manager, circuit_lib, circuit_model);
continue;
}
if (CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(circuit_model)) {
build_passgate_module(module_manager, circuit_lib, circuit_model);
continue;
}
if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(circuit_model)) {
build_gate_module(module_manager, circuit_lib, circuit_model);
continue;
}
}
}
/*********************************************************************
* Register all the user-defined modules in the module manager
* Walk through the circuit library and add user-defined circuit models
* to the module_manager
********************************************************************/
void build_user_defined_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib) {
vtr::ScopedStartFinishTimer timer("Build user-defined modules");
/* Iterate over Verilog modules */
for (const auto& model : circuit_lib.models()) {
/* We only care about user-defined models */
if ( (true == circuit_lib.model_verilog_netlist(model).empty())
&& (true == circuit_lib.model_circuit_netlist(model).empty()) ) {
continue;
}
/* Skip Routing channel wire models because they need a different name. Do it later */
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) {
continue;
}
/* Reach here, the model requires a user-defined Verilog netlist,
* Register it in the module_manager
*/
add_circuit_model_to_module_manager(module_manager, circuit_lib, model);
}
}
/*********************************************************************
* This function will build a constant generator modules
* and add it to the module manager
* It could be either
* 1. VDD or 2. GND
* Each module will have only one output port
********************************************************************/
static
void build_constant_generator_module(ModuleManager& module_manager,
const size_t& const_value) {
ModuleId const_module = module_manager.add_module(generate_const_value_module_name(const_value));
/* Add one output port */
BasicPort const_output_port(generate_const_value_module_output_port_name(const_value), 1);
module_manager.add_port(const_module, const_output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/*********************************************************************
* This function will add two constant generator modules
* to the module manager
* 1. VDD
* 2. GND
********************************************************************/
void build_constant_generator_modules(ModuleManager& module_manager) {
vtr::ScopedStartFinishTimer timer("Build constant generator modules");
/* VDD */
build_constant_generator_module(module_manager, 1);
/* GND */
build_constant_generator_module(module_manager, 0);
}
/*********************************************************************
* This function will rename the ports of primitive modules
* using lib_name instead of prefix
* Primitive modules are defined as those modules in the module manager
* which have user defined netlists
********************************************************************/
void rename_primitive_module_port_names(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib) {
for (const CircuitModelId& model : circuit_lib.models()) {
/* We only care about user-defined models */
if ( (true == circuit_lib.model_verilog_netlist(model).empty())
&& (true == circuit_lib.model_circuit_netlist(model).empty()) ) {
continue;
}
/* Skip Routing channel wire models because they need a different name. Do it later */
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) {
continue;
}
/* Find the module in module manager */
ModuleId module = module_manager.find_module(circuit_lib.model_name(model));
/* We must find one! */
VTR_ASSERT(true == module_manager.valid_module_id(module));
/* Rename all the ports to use lib_name! */
for (const CircuitPortId& model_port : circuit_lib.model_ports(model)) {
/* Find the module port in module manager. We used prefix when creating the ports */
ModulePortId module_port = module_manager.find_module_port(module, circuit_lib.port_prefix(model_port));
/* We must find one! */
VTR_ASSERT(true == module_manager.valid_module_port_id(module, module_port));
/* Name it with lib_name */
module_manager.set_module_port_name(module, module_port, circuit_lib.port_lib_name(model_port));
}
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,30 @@
#ifndef BUILD_ESSENTIAL_MODULES_H
#define BUILD_ESSENTIAL_MODULES_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "circuit_library.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void build_essential_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib);
void build_user_defined_modules(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib);
void build_constant_generator_modules(ModuleManager& module_manager);
void rename_primitive_module_port_names(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,777 @@
/******************************************************************************
* Memember functions for data structure ModuleManager
******************************************************************************/
#include <string>
#include <numeric>
#include <algorithm>
#include "vtr_assert.h"
#include "circuit_library.h"
#include "module_manager.h"
/* begin namespace openfpga */
namespace openfpga {
/******************************************************************************
* Public Constructors
******************************************************************************/
/**************************************************
* Public Accessors : Aggregates
*************************************************/
/* Find all the modules */
ModuleManager::module_range ModuleManager::modules() const {
return vtr::make_range(ids_.begin(), ids_.end());
}
/* Find all the ports belonging to a module */
ModuleManager::module_port_range ModuleManager::module_ports(const ModuleId& module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module));
return vtr::make_range(port_ids_[module].begin(), port_ids_[module].end());
}
/* Find all the nets belonging to a module */
ModuleManager::module_net_range ModuleManager::module_nets(const ModuleId& module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module));
return vtr::make_range(net_ids_[module].begin(), net_ids_[module].end());
}
/* Find all the child modules under a parent module */
std::vector<ModuleId> ModuleManager::child_modules(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return children_[parent_module];
}
/* Find all the instances under a parent module */
std::vector<size_t> ModuleManager::child_module_instances(const ModuleId& parent_module, const ModuleId& child_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
/* Ensure that the child module is in the child list of parent module */
size_t child_index = children_[parent_module].size();
for (size_t i = 0; i < children_[parent_module].size(); ++i) {
if (child_module == children_[parent_module][i]) {
child_index = i;
break;
}
}
VTR_ASSERT(child_index != children_[parent_module].size());
/* Create a vector, with sequentially increasing numbers */
std::vector<size_t> instance_range(num_child_instances_[parent_module][child_index], 0);
std::iota(instance_range.begin(), instance_range.end(), 0);
return instance_range;
}
/* Find all the configurable child modules under a parent module */
std::vector<ModuleId> ModuleManager::configurable_children(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return configurable_children_[parent_module];
}
/* Find all the instances of configurable child modules under a parent module */
std::vector<size_t> ModuleManager::configurable_child_instances(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return configurable_child_instances_[parent_module];
}
/* Find the source ids of modules */
ModuleManager::module_net_src_range ModuleManager::module_net_sources(const ModuleId& module, const ModuleNetId& net) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_net_id(module, net));
return vtr::make_range(net_src_ids_[module][net].begin(), net_src_ids_[module][net].end());
}
/* Find the sink ids of modules */
ModuleManager::module_net_sink_range ModuleManager::module_net_sinks(const ModuleId& module, const ModuleNetId& net) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_net_id(module, net));
return vtr::make_range(net_sink_ids_[module][net].begin(), net_sink_ids_[module][net].end());
}
/******************************************************************************
* Public Accessors
******************************************************************************/
/* Return number of modules */
size_t ModuleManager::num_modules() const {
return ids_.size();
}
/* Return number of net of a module */
size_t ModuleManager::num_nets(const ModuleId& module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module));
return net_ids_[module].size();
}
/* Find the name of a module */
std::string ModuleManager::module_name(const ModuleId& module_id) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module_id));
return names_[module_id];
}
/* Get the string of a module port type */
std::string ModuleManager::module_port_type_str(const enum e_module_port_type& port_type) const {
std::array<const char*, NUM_MODULE_PORT_TYPES> MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "GPIO PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}};
return MODULE_PORT_TYPE_STRING[port_type];
}
/* Find a list of ports of a module by a given types */
std::vector<BasicPort> ModuleManager::module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module_id));
std::vector<BasicPort> ports;
for (const auto& port : port_ids_[module_id]) {
/* Skip unmatched ports */
if (port_type != port_types_[module_id][port]) {
continue;
}
ports.push_back(ports_[module_id][port]);
}
return ports;
}
/* Find a list of port ids of a module by a given types */
std::vector<ModulePortId> ModuleManager::module_port_ids_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module_id));
std::vector<ModulePortId> port_ids;
for (const auto& port : port_ids_[module_id]) {
/* Skip unmatched ports */
if (port_type != port_types_[module_id][port]) {
continue;
}
port_ids.push_back(port_ids_[module_id][port]);
}
return port_ids;
}
/* Find a port of a module by a given name */
ModulePortId ModuleManager::find_module_port(const ModuleId& module_id, const std::string& port_name) const {
/* Validate the module id */
VTR_ASSERT(valid_module_id(module_id));
/* Iterate over the ports of the module */
for (const auto& port : port_ids_[module_id]) {
if (0 == port_name.compare(ports_[module_id][port].get_name())) {
/* Find it, return the id */
return port;
}
}
/* Not found, return an invalid id */
return ModulePortId::INVALID();
}
/* Find the Port information with a given port id */
BasicPort ModuleManager::module_port(const ModuleId& module_id, const ModulePortId& port_id) const {
/* Validate the module and port id */
VTR_ASSERT(valid_module_port_id(module_id, port_id));
return ports_[module_id][port_id];
}
/* Find the module id by a given name, return invalid if not found */
ModuleId ModuleManager::find_module(const std::string& name) const {
if (name_id_map_.find(name) != name_id_map_.end()) {
/* Find it, return the id */
return name_id_map_.at(name);
}
/* Not found, return an invalid id */
return ModuleId::INVALID();
}
/* Find the number of instances of a child module in the parent module */
size_t ModuleManager::num_instance(const ModuleId& parent_module, const ModuleId& child_module) const {
size_t child_index = find_child_module_index_in_parent_module(parent_module, child_module);
if (size_t(-1) == child_index) {
/* Not found, return a zero */
return 0;
}
return num_child_instances_[parent_module][child_index];
}
/* Find the instance name of a child module */
std::string ModuleManager::instance_name(const ModuleId& parent_module, const ModuleId& child_module,
const size_t& instance_id) const {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Find the index of child module in the child list of parent module */
size_t child_index = find_child_module_index_in_parent_module(parent_module, child_module);
VTR_ASSERT (child_index < children_[parent_module].size());
/* Ensure that instance id is valid */
VTR_ASSERT (instance_id < num_instance(parent_module, child_module));
return child_instance_names_[parent_module][child_index][instance_id];
}
/* Find the instance id of a given instance name */
size_t ModuleManager::instance_id(const ModuleId& parent_module, const ModuleId& child_module,
const std::string& instance_name) const {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Find the index of child module in the child list of parent module */
size_t child_index = find_child_module_index_in_parent_module(parent_module, child_module);
VTR_ASSERT (child_index < children_[parent_module].size());
/* Search the instance name list and try to find a match */
for (size_t name_id = 0; name_id < child_instance_names_[parent_module][child_index].size(); ++name_id) {
const std::string& name = child_instance_names_[parent_module][child_index][name_id];
if (0 == name.compare(instance_name)) {
return name_id;
}
}
/* Not found, return an invalid name */
return size_t(-1);
}
/* Find if a port is a wire connection */
bool ModuleManager::port_is_wire(const ModuleId& module, const ModulePortId& port) const {
/* validate both module id and port id*/
VTR_ASSERT(valid_module_port_id(module, port));
return port_is_wire_[module][port];
}
/* Find if a port is register */
bool ModuleManager::port_is_register(const ModuleId& module, const ModulePortId& port) const {
/* validate both module id and port id*/
VTR_ASSERT(valid_module_port_id(module, port));
return port_is_register_[module][port];
}
/* Return the pre-processing flag of a port */
std::string ModuleManager::port_preproc_flag(const ModuleId& module, const ModulePortId& port) const {
/* validate both module id and port id*/
VTR_ASSERT(valid_module_port_id(module, port));
return port_preproc_flags_[module][port];
}
/* Find a net from an instance of a module */
ModuleNetId ModuleManager::module_instance_port_net(const ModuleId& parent_module,
const ModuleId& child_module, const size_t& child_instance,
const ModulePortId& child_port, const size_t& child_pin) const {
/* Validate parent_module */
VTR_ASSERT(valid_module_id(parent_module));
/* Validate child_module */
VTR_ASSERT(valid_module_id(child_module));
/* Validate instance id */
if (child_module == parent_module) {
/* Assume a default instance id as zero */
VTR_ASSERT(0 == child_instance);
} else {
VTR_ASSERT(child_instance < num_instance(parent_module, child_module));
}
/* Validate child_port */
VTR_ASSERT(valid_module_port_id(child_module, child_port));
/* Validate child_pin */
VTR_ASSERT(child_pin < module_port(child_module, child_port).get_width());
return net_lookup_[parent_module][child_module][child_instance][child_port][child_pin];
}
/* Find the name of net */
std::string ModuleManager::net_name(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_names_[module][net];
}
/* Find the source modules of a net */
vtr::vector<ModuleNetSrcId, ModuleId> ModuleManager::net_source_modules(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_src_module_ids_[module][net];
}
/* Find the ids of source instances of a net */
vtr::vector<ModuleNetSrcId, size_t> ModuleManager::net_source_instances(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_src_instance_ids_[module][net];
}
/* Find the source ports of a net */
vtr::vector<ModuleNetSrcId, ModulePortId> ModuleManager::net_source_ports(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_src_port_ids_[module][net];
}
/* Find the source pin indices of a net */
vtr::vector<ModuleNetSrcId, size_t> ModuleManager::net_source_pins(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_src_pin_ids_[module][net];
}
/* Identify if a pin of a port in a module already exists in the net source list*/
bool ModuleManager::net_source_exist(const ModuleId& module, const ModuleNetId& net,
const ModuleId& src_module, const size_t& instance_id,
const ModulePortId& src_port, const size_t& src_pin) {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
/* Iterate over each source of the net.
* If a net source has the same src_module, instance_id, src_port and src_pin,
* we can say that the source has already been added to this net!
*/
for (const ModuleNetSrcId& net_src : module_net_sources(module, net)) {
if ( (src_module == net_source_modules(module, net)[net_src])
&& (instance_id == net_source_instances(module, net)[net_src])
&& (src_port == net_source_ports(module, net)[net_src])
&& (src_pin == net_source_pins(module, net)[net_src]) ) {
return true;
}
}
/* Reach here, it means nothing has been found. Return false */
return false;
}
/* Find the sink modules of a net */
vtr::vector<ModuleNetSinkId, ModuleId> ModuleManager::net_sink_modules(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_sink_module_ids_[module][net];
}
/* Find the ids of sink instances of a net */
vtr::vector<ModuleNetSinkId, size_t> ModuleManager::net_sink_instances(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_sink_instance_ids_[module][net];
}
/* Find the sink ports of a net */
vtr::vector<ModuleNetSinkId, ModulePortId> ModuleManager::net_sink_ports(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_sink_port_ids_[module][net];
}
/* Find the sink pin indices of a net */
vtr::vector<ModuleNetSinkId, size_t> ModuleManager::net_sink_pins(const ModuleId& module, const ModuleNetId& net) const {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
return net_sink_pin_ids_[module][net];
}
/* Identify if a pin of a port in a module already exists in the net sink list*/
bool ModuleManager::net_sink_exist(const ModuleId& module, const ModuleNetId& net,
const ModuleId& sink_module, const size_t& instance_id,
const ModulePortId& sink_port, const size_t& sink_pin) {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
/* Iterate over each sink of the net.
* If a net sink has the same sink_module, instance_id, sink_port and sink_pin,
* we can say that the sink has already been added to this net!
*/
for (const ModuleNetSinkId& net_sink : module_net_sinks(module, net)) {
if ( (sink_module == net_sink_modules(module, net)[net_sink])
&& (instance_id == net_sink_instances(module, net)[net_sink])
&& (sink_port == net_sink_ports(module, net)[net_sink])
&& (sink_pin == net_sink_pins(module, net)[net_sink]) ) {
return true;
}
}
/* Reach here, it means nothing has been found. Return false */
return false;
}
/******************************************************************************
* Private Accessors
******************************************************************************/
size_t ModuleManager::find_child_module_index_in_parent_module(const ModuleId& parent_module, const ModuleId& child_module) const {
/* validate both module ids */
VTR_ASSERT(valid_module_id(parent_module));
VTR_ASSERT(valid_module_id(child_module));
/* Try to find the child_module in the children list of parent_module*/
for (size_t i = 0; i < children_[parent_module].size(); ++i) {
if (child_module == children_[parent_module][i]) {
/* Found, return the number of instances */
return i;
}
}
/* Not found: return an valid value */
return size_t(-1);
}
/******************************************************************************
* Public Mutators
******************************************************************************/
/* Add a module */
ModuleId ModuleManager::add_module(const std::string& name) {
/* Find if the name has been used. If used, return an invalid Id and report error! */
std::map<std::string, ModuleId>::iterator it = name_id_map_.find(name);
if (it != name_id_map_.end()) {
return ModuleId::INVALID();
}
/* Create an new id */
ModuleId module = ModuleId(ids_.size());
ids_.push_back(module);
/* Allocate other attributes */
names_.push_back(name);
parents_.emplace_back();
children_.emplace_back();
num_child_instances_.emplace_back();
child_instance_names_.emplace_back();
configurable_children_.emplace_back();
configurable_child_instances_.emplace_back();
port_ids_.emplace_back();
ports_.emplace_back();
port_types_.emplace_back();
port_is_wire_.emplace_back();
port_is_register_.emplace_back();
port_preproc_flags_.emplace_back();
net_ids_.emplace_back();
net_names_.emplace_back();
net_src_ids_.emplace_back();
net_src_module_ids_.emplace_back();
net_src_instance_ids_.emplace_back();
net_src_port_ids_.emplace_back();
net_src_pin_ids_.emplace_back();
net_sink_ids_.emplace_back();
net_sink_module_ids_.emplace_back();
net_sink_instance_ids_.emplace_back();
net_sink_port_ids_.emplace_back();
net_sink_pin_ids_.emplace_back();
/* Register in the name-to-id map */
name_id_map_[name] = module;
/* Build port lookup */
port_lookup_.emplace_back();
port_lookup_[module].resize(NUM_MODULE_PORT_TYPES);
/* Build fast look-up for nets */
net_lookup_.emplace_back();
/* Reserve the instance 0 for the module */
net_lookup_[module][module].emplace_back();
/* Return the new id */
return module;
}
/* Add a port to a module */
ModulePortId ModuleManager::add_port(const ModuleId& module,
const BasicPort& port_info, const enum e_module_port_type& port_type) {
/* Validate the id of module */
VTR_ASSERT( valid_module_id(module) );
/* Add port and fill port attributes */
ModulePortId port = ModulePortId(port_ids_[module].size());
port_ids_[module].push_back(port);
ports_[module].push_back(port_info);
port_types_[module].push_back(port_type);
port_is_wire_[module].push_back(false);
port_is_register_[module].push_back(false);
port_preproc_flags_[module].emplace_back(); /* Create an empty string for the pre-processing flags */
/* Update fast look-up for port */
port_lookup_[module][port_type].push_back(port);
/* Update fast look-up for nets */
VTR_ASSERT_SAFE(1 == net_lookup_[module][module].size());
net_lookup_[module][module][0][port].resize(port_info.get_width(), ModuleNetId::INVALID());
return port;
}
/* Set a name for a module port */
void ModuleManager::set_module_port_name(const ModuleId& module, const ModulePortId& module_port,
const std::string& port_name) {
/* Validate the id of module port */
VTR_ASSERT( valid_module_port_id(module, module_port) );
ports_[module][module_port].set_name(port_name);
}
/* Set a name for a module */
void ModuleManager::set_module_name(const ModuleId& module, const std::string& name) {
/* Validate the id of module */
VTR_ASSERT( valid_module_id(module) );
names_[module] = name;
}
/* Set a port to be a wire */
void ModuleManager::set_port_is_wire(const ModuleId& module, const std::string& port_name, const bool& is_wire) {
/* Find the port */
ModulePortId port = find_module_port(module, port_name);
/* Must find something, otherwise drop an error */
VTR_ASSERT(ModulePortId::INVALID() != port);
port_is_wire_[module][port] = is_wire;
}
/* Set a port to be a register */
void ModuleManager::set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register) {
/* Find the port */
ModulePortId port = find_module_port(module, port_name);
/* Must find something, otherwise drop an error */
VTR_ASSERT(ModulePortId::INVALID() != port);
port_is_register_[module][port] = is_register;
}
/* Set the preprocessing flag for a port */
void ModuleManager::set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag) {
/* Must find something, otherwise drop an error */
VTR_ASSERT(valid_module_port_id(module, port));
port_preproc_flags_[module][port] = preproc_flag;
}
/* Add a child module to a parent module */
void ModuleManager::add_child_module(const ModuleId& parent_module, const ModuleId& child_module) {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Try to find if the parent module is already in the list */
std::vector<ModuleId>::iterator parent_it = std::find(parents_[child_module].begin(), parents_[child_module].end(), parent_module);
if (parent_it == parents_[child_module].end()) {
/* Update the parent module of child module */
parents_[child_module].push_back(parent_module);
}
std::vector<ModuleId>::iterator child_it = std::find(children_[parent_module].begin(), children_[parent_module].end(), child_module);
if (child_it == children_[parent_module].end()) {
/* Update the child module of parent module */
children_[parent_module].push_back(child_module);
num_child_instances_[parent_module].push_back(1); /* By default give one */
/* Update the instance name list */
child_instance_names_[parent_module].emplace_back();
child_instance_names_[parent_module].back().emplace_back();
} else {
/* Increase the counter of instances */
num_child_instances_[parent_module][child_it - children_[parent_module].begin()]++;
child_instance_names_[parent_module][child_it - children_[parent_module].begin()].emplace_back();
}
/* Update fast look-up for nets */
size_t instance_id = net_lookup_[parent_module][child_module].size();
net_lookup_[parent_module][child_module].emplace_back();
/* Find the ports for the child module and update the fast look-up */
for (ModulePortId child_port : port_ids_[child_module]) {
net_lookup_[parent_module][child_module][instance_id][child_port].resize(ports_[child_module][child_port].get_width(), ModuleNetId::INVALID());
}
}
/* Set the instance name of a child module */
void ModuleManager::set_child_instance_name(const ModuleId& parent_module,
const ModuleId& child_module,
const size_t& instance_id,
const std::string& instance_name) {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Ensure that the instance id is in range */
VTR_ASSERT ( instance_id < num_instance(parent_module, child_module));
/* Try to find the child_module in the children list of parent_module*/
size_t child_index = find_child_module_index_in_parent_module(parent_module, child_module);
/* We must find something! */
VTR_ASSERT(size_t(-1) != child_index);
/* Set the name */
child_instance_names_[parent_module][child_index][instance_id] = instance_name;
}
/* Add a configurable child module to module
* Note: this function should be called after add_child_module!
* It will check if the child module does exist in the parent module
* And the instance id is in range or not
*/
void ModuleManager::add_configurable_child(const ModuleId& parent_module,
const ModuleId& child_module,
const size_t& child_instance) {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Ensure that the instance id is in range */
VTR_ASSERT ( child_instance < num_instance(parent_module, child_module));
configurable_children_[parent_module].push_back(child_module);
configurable_child_instances_[parent_module].push_back(child_instance);
}
/* Add a net to the connection graph of the module */
ModuleNetId ModuleManager::create_module_net(const ModuleId& module) {
/* Validate the module id */
VTR_ASSERT ( valid_module_id(module) );
/* Create an new id */
ModuleNetId net = ModuleNetId(net_ids_[module].size());
net_ids_[module].push_back(net);
/* Allocate net-related data structures */
net_names_[module].emplace_back();
net_src_ids_[module].emplace_back();
net_src_module_ids_[module].emplace_back();
net_src_instance_ids_[module].emplace_back();
net_src_port_ids_[module].emplace_back();
net_src_pin_ids_[module].emplace_back();
net_sink_ids_[module].emplace_back();
net_sink_module_ids_[module].emplace_back();
net_sink_instance_ids_[module].emplace_back();
net_sink_port_ids_[module].emplace_back();
net_sink_pin_ids_[module].emplace_back();
return net;
}
/* Set the name of net */
void ModuleManager::set_net_name(const ModuleId& module, const ModuleNetId& net,
const std::string& name) {
/* Validate module net */
VTR_ASSERT(valid_module_net_id(module, net));
net_names_[module][net] = name;
}
/* Add a source to a net in the connection graph */
ModuleNetSrcId ModuleManager::add_module_net_source(const ModuleId& module, const ModuleNetId& net,
const ModuleId& src_module, const size_t& instance_id,
const ModulePortId& src_port, const size_t& src_pin) {
/* Validate the module and net id */
VTR_ASSERT(valid_module_net_id(module, net));
/* Create a new id for src node */
ModuleNetSrcId net_src = ModuleNetSrcId(net_src_ids_[module][net].size());
net_src_ids_[module][net].push_back(net_src);
/* Validate the source module */
VTR_ASSERT(valid_module_id(src_module));
net_src_module_ids_[module][net].push_back(src_module);
/* if it has the same id as module, our instance id will be by default 0 */
size_t src_instance_id = instance_id;
if (src_module == module) {
src_instance_id = 0;
net_src_instance_ids_[module][net].push_back(src_instance_id);
} else {
/* Check the instance id of the src module */
VTR_ASSERT (src_instance_id < num_instance(module, src_module));
net_src_instance_ids_[module][net].push_back(src_instance_id);
}
/* Validate the port exists in the src module */
VTR_ASSERT(valid_module_port_id(src_module, src_port));
net_src_port_ids_[module][net].push_back(src_port);
/* Validate the pin id is in the range of the port width */
VTR_ASSERT(src_pin < module_port(src_module, src_port).get_width());
net_src_pin_ids_[module][net].push_back(src_pin);
/* Update fast look-up for nets */
net_lookup_[module][src_module][src_instance_id][src_port][src_pin] = net;
return net_src;
}
/* Add a sink to a net in the connection graph */
ModuleNetSinkId ModuleManager::add_module_net_sink(const ModuleId& module, const ModuleNetId& net,
const ModuleId& sink_module, const size_t& instance_id,
const ModulePortId& sink_port, const size_t& sink_pin) {
/* Validate the module and net id */
VTR_ASSERT(valid_module_net_id(module, net));
/* Create a new id for sink node */
ModuleNetSinkId net_sink = ModuleNetSinkId(net_sink_ids_[module][net].size());
net_sink_ids_[module][net].push_back(net_sink);
/* Validate the source module */
VTR_ASSERT(valid_module_id(sink_module));
net_sink_module_ids_[module][net].push_back(sink_module);
/* if it has the same id as module, our instance id will be by default 0 */
size_t sink_instance_id = instance_id;
if (sink_module == module) {
sink_instance_id = 0;
net_sink_instance_ids_[module][net].push_back(sink_instance_id);
} else {
/* Check the instance id of the src module */
VTR_ASSERT (sink_instance_id < num_instance(module, sink_module));
net_sink_instance_ids_[module][net].push_back(sink_instance_id);
}
/* Validate the port exists in the sink module */
VTR_ASSERT(valid_module_port_id(sink_module, sink_port));
net_sink_port_ids_[module][net].push_back(sink_port);
/* Validate the pin id is in the range of the port width */
VTR_ASSERT(sink_pin < module_port(sink_module, sink_port).get_width());
net_sink_pin_ids_[module][net].push_back(sink_pin);
/* Update fast look-up for nets */
net_lookup_[module][sink_module][sink_instance_id][sink_port][sink_pin] = net;
return net_sink;
}
/******************************************************************************
* Private validators/invalidators
******************************************************************************/
bool ModuleManager::valid_module_id(const ModuleId& module) const {
return ( size_t(module) < ids_.size() ) && ( module == ids_[module] );
}
bool ModuleManager::valid_module_port_id(const ModuleId& module, const ModulePortId& port) const {
if (false == valid_module_id(module)) {
return false;
}
return ( size_t(port) < port_ids_[module].size() ) && ( port == port_ids_[module][port] );
}
bool ModuleManager::valid_module_net_id(const ModuleId& module, const ModuleNetId& net) const {
if (false == valid_module_id(module)) {
return false;
}
return ( size_t(net) < net_ids_[module].size() ) && ( net == net_ids_[module][net] );
}
void ModuleManager::invalidate_name2id_map() {
name_id_map_.clear();
}
void ModuleManager::invalidate_port_lookup() {
port_lookup_.clear();
}
void ModuleManager::invalidate_net_lookup() {
net_lookup_.clear();
}
} /* end namespace openfpga */

View File

@ -0,0 +1,238 @@
#ifndef MODULE_MANAGER_H
#define MODULE_MANAGER_H
#include <string>
#include <map>
#include "vtr_vector.h"
#include "module_manager_fwd.h"
#include "openfpga_port.h"
/* begin namespace openfpga */
namespace openfpga {
/******************************************************************************
* This files includes data structures for module management.
* It keeps a list of modules that have been generated, the port map of the modules,
* parents and children of each modules. This will ease instanciation of modules
* with explicit port map and outputting a hierarchy of modules
*
* Module includes the basic information:
* 1. unique identifier
* 2. module name: which should be unique
* 3. port list: basic information of all the ports belonging to the module
* 4. port types: types of each port, which will matter how we output the ports
* 5. parent modules: ids of parent modules
* 6. children modules: ids of child modules
******************************************************************************/
class ModuleManager {
public: /* Private data structures */
enum e_module_port_type {
MODULE_GLOBAL_PORT, /* Global inputs */
MODULE_GPIO_PORT, /* General-purpose IOs, which are data IOs of the fabric */
MODULE_INOUT_PORT, /* Normal (non-global) inout ports */
MODULE_INPUT_PORT, /* Normal (non-global) input ports */
MODULE_OUTPUT_PORT, /* Normal (non-global) output ports */
MODULE_CLOCK_PORT, /* Nromal (non-global) clock ports*/
NUM_MODULE_PORT_TYPES
};
public: /* Public Constructors */
public: /* Types and ranges */
typedef vtr::vector<ModuleId, ModuleId>::const_iterator module_iterator;
typedef vtr::vector<ModulePortId, ModulePortId>::const_iterator module_port_iterator;
typedef vtr::vector<ModuleNetId, ModuleNetId>::const_iterator module_net_iterator;
typedef vtr::vector<ModuleNetSrcId, ModuleNetSrcId>::const_iterator module_net_src_iterator;
typedef vtr::vector<ModuleNetSinkId, ModuleNetSinkId>::const_iterator module_net_sink_iterator;
typedef vtr::Range<module_iterator> module_range;
typedef vtr::Range<module_port_iterator> module_port_range;
typedef vtr::Range<module_net_iterator> module_net_range;
typedef vtr::Range<module_net_src_iterator> module_net_src_range;
typedef vtr::Range<module_net_sink_iterator> module_net_sink_range;
public: /* Public aggregators */
/* Find all the modules */
module_range modules() const;
/* Find all the ports belonging to a module */
module_port_range module_ports(const ModuleId& module) const;
/* Find all the nets belonging to a module */
module_net_range module_nets(const ModuleId& module) const;
/* Find all the child modules under a parent module */
std::vector<ModuleId> child_modules(const ModuleId& parent_module) const;
/* Find all the instances under a parent module */
std::vector<size_t> child_module_instances(const ModuleId& parent_module, const ModuleId& child_module) const;
/* Find all the configurable child modules under a parent module */
std::vector<ModuleId> configurable_children(const ModuleId& parent_module) const;
/* Find all the instances of configurable child modules under a parent module */
std::vector<size_t> configurable_child_instances(const ModuleId& parent_module) const;
/* Find the source ids of modules */
module_net_src_range module_net_sources(const ModuleId& module, const ModuleNetId& net) const;
/* Find the sink ids of modules */
module_net_sink_range module_net_sinks(const ModuleId& module, const ModuleNetId& net) const;
public: /* Public accessors */
size_t num_modules() const;
size_t num_nets(const ModuleId& module) const;
std::string module_name(const ModuleId& module_id) const;
std::string module_port_type_str(const enum e_module_port_type& port_type) const;
std::vector<BasicPort> module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
std::vector<ModulePortId> module_port_ids_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
/* Find a port of a module by a given name */
ModulePortId find_module_port(const ModuleId& module_id, const std::string& port_name) const;
/* Find the Port information with a given port id */
BasicPort module_port(const ModuleId& module_id, const ModulePortId& port_id) const;
/* Find a module by a given name */
ModuleId find_module(const std::string& name) const;
/* Find the number of instances of a child module in the parent module */
size_t num_instance(const ModuleId& parent_module, const ModuleId& child_module) const;
/* Find the instance name of a child module */
std::string instance_name(const ModuleId& parent_module, const ModuleId& child_module,
const size_t& instance_id) const;
/* Find the instance id of a given instance name */
size_t instance_id(const ModuleId& parent_module, const ModuleId& child_module,
const std::string& instance_name) const;
/* Find if a port is a wire connection */
bool port_is_wire(const ModuleId& module, const ModulePortId& port) const;
/* Find if a port is register */
bool port_is_register(const ModuleId& module, const ModulePortId& port) const;
/* Return the pre-processing flag of a port */
std::string port_preproc_flag(const ModuleId& module, const ModulePortId& port) const;
/* Find a net from an instance of a module */
ModuleNetId module_instance_port_net(const ModuleId& parent_module,
const ModuleId& child_module, const size_t& child_instance,
const ModulePortId& child_port, const size_t& child_pin) const;
/* Find the name of net */
std::string net_name(const ModuleId& module, const ModuleNetId& net) const;
/* Find the source modules of a net */
vtr::vector<ModuleNetSrcId, ModuleId> net_source_modules(const ModuleId& module, const ModuleNetId& net) const;
/* Find the ids of source instances of a net */
vtr::vector<ModuleNetSrcId, size_t> net_source_instances(const ModuleId& module, const ModuleNetId& net) const;
/* Find the source ports of a net */
vtr::vector<ModuleNetSrcId, ModulePortId> net_source_ports(const ModuleId& module, const ModuleNetId& net) const;
/* Find the source pin indices of a net */
vtr::vector<ModuleNetSrcId, size_t> net_source_pins(const ModuleId& module, const ModuleNetId& net) const;
/* Identify if a pin of a port in a module already exists in the net source list*/
bool net_source_exist(const ModuleId& module, const ModuleNetId& net,
const ModuleId& src_module, const size_t& instance_id,
const ModulePortId& src_port, const size_t& src_pin);
/* Find the sink modules of a net */
vtr::vector<ModuleNetSinkId, ModuleId> net_sink_modules(const ModuleId& module, const ModuleNetId& net) const;
/* Find the ids of sink instances of a net */
vtr::vector<ModuleNetSinkId, size_t> net_sink_instances(const ModuleId& module, const ModuleNetId& net) const;
/* Find the sink ports of a net */
vtr::vector<ModuleNetSinkId, ModulePortId> net_sink_ports(const ModuleId& module, const ModuleNetId& net) const;
/* Find the sink pin indices of a net */
vtr::vector<ModuleNetSinkId, size_t> net_sink_pins(const ModuleId& module, const ModuleNetId& net) const;
/* Identify if a pin of a port in a module already exists in the net sink list*/
bool net_sink_exist(const ModuleId& module, const ModuleNetId& net,
const ModuleId& sink_module, const size_t& instance_id,
const ModulePortId& sink_port, const size_t& sink_pin);
private: /* Private accessors */
size_t find_child_module_index_in_parent_module(const ModuleId& parent_module, const ModuleId& child_module) const;
public: /* Public mutators */
/* Add a module */
ModuleId add_module(const std::string& name);
/* Add a port to a module */
ModulePortId add_port(const ModuleId& module,
const BasicPort& port_info, const enum e_module_port_type& port_type);
/* Set a name for a module port */
void set_module_port_name(const ModuleId& module, const ModulePortId& module_port, const std::string& port_name);
/* Set a name for a module */
void set_module_name(const ModuleId& module, const std::string& name);
/* Set a port to be a wire */
void set_port_is_wire(const ModuleId& module, const std::string& port_name, const bool& is_wire);
/* Set a port to be a register */
void set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register);
/* Set the preprocessing flag for a port */
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
/* Add a child module to a parent module */
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
/* Set the instance name of a child module */
void set_child_instance_name(const ModuleId& parent_module, const ModuleId& child_module, const size_t& instance_id, const std::string& instance_name);
/* Add a configurable child module to module */
void add_configurable_child(const ModuleId& module, const ModuleId& child_module, const size_t& child_instance);
/* Add a net to the connection graph of the module */
ModuleNetId create_module_net(const ModuleId& module);
/* Set the name of net */
void set_net_name(const ModuleId& module, const ModuleNetId& net,
const std::string& name);
/* Add a source to a net in the connection graph */
ModuleNetSrcId add_module_net_source(const ModuleId& module, const ModuleNetId& net,
const ModuleId& src_module, const size_t& instance_id,
const ModulePortId& src_port, const size_t& src_pin);
/* Add a sink to a net in the connection graph */
ModuleNetSinkId add_module_net_sink(const ModuleId& module, const ModuleNetId& net,
const ModuleId& sink_module, const size_t& instance_id,
const ModulePortId& sink_port, const size_t& sink_pin);
public: /* Public validators/invalidators */
bool valid_module_id(const ModuleId& module) const;
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
bool valid_module_net_id(const ModuleId& module, const ModuleNetId& net) const;
private: /* Private validators/invalidators */
void invalidate_name2id_map();
void invalidate_port_lookup();
void invalidate_net_lookup();
private: /* Internal data */
/* Module-level data */
vtr::vector<ModuleId, ModuleId> ids_; /* Unique identifier for each Module */
vtr::vector<ModuleId, std::string> names_; /* Unique identifier for each Module */
vtr::vector<ModuleId, std::vector<ModuleId>> parents_; /* Parent modules that include the module */
vtr::vector<ModuleId, std::vector<ModuleId>> children_; /* Child modules that this module contain */
vtr::vector<ModuleId, std::vector<size_t>> num_child_instances_; /* Number of children instance in each child module */
vtr::vector<ModuleId, std::vector<std::vector<std::string>>> child_instance_names_; /* Number of children instance in each child module */
/* Configurable child modules are used to record the position of configurable modules in bitstream
* The sequence of children in the list denotes which one is configured first, etc.
* Note that the sequence can be totally different from the children_ list
* This is really dependent how the configuration protocol is organized
* which should be made by users/designers
*/
vtr::vector<ModuleId, std::vector<ModuleId>> configurable_children_; /* Child modules with configurable memory bits that this module contain */
vtr::vector<ModuleId, std::vector<size_t>> configurable_child_instances_; /* Instances of child modules with configurable memory bits that this module contain */
/* Port-level data */
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */
vtr::vector<ModuleId, vtr::vector<ModulePortId, enum e_module_port_type>> port_types_; /* Type of ports */
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_wire_; /* If the port is a wire, use for Verilog port definition. If enabled: <port_type> reg <port_name> */
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_register_; /* If the port is a register, use for Verilog port definition. If enabled: <port_type> reg <port_name> */
vtr::vector<ModuleId, vtr::vector<ModulePortId, std::string>> port_preproc_flags_; /* If a port is available only when a pre-processing flag is enabled. This is to record the pre-processing flags */
/* Graph-level data:
* We use nets to model the connection between pins of modules and instances.
* To avoid large memory footprint, we do NOT create pins,
* To enable fast look-up on pins, we create a fast look-up
*/
vtr::vector<ModuleId, vtr::vector<ModuleNetId, ModuleNetId>> net_ids_; /* List of nets for each Module */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, std::string>> net_names_; /* Name of net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSrcId, ModuleNetSrcId>>> net_src_ids_; /* Unique id of the source that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSrcId, ModuleId>>> net_src_module_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSrcId, size_t>>> net_src_instance_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSrcId, ModulePortId>>> net_src_port_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSrcId, size_t>>> net_src_pin_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSinkId, ModuleNetSinkId>>> net_sink_ids_; /* Unique ids of the sink that the net drives */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSinkId, ModuleId>>> net_sink_module_ids_; /* Pin ids that the net drives */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSinkId, size_t>>> net_sink_instance_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSinkId, ModulePortId>>> net_sink_port_ids_; /* Pin ids that drive the net */
vtr::vector<ModuleId, vtr::vector<ModuleNetId, vtr::vector<ModuleNetSinkId, size_t>>> net_sink_pin_ids_; /* Pin ids that drive the net */
/* fast look-up for module */
std::map<std::string, ModuleId> name_id_map_;
/* fast look-up for ports */
typedef vtr::vector<ModuleId, std::vector<std::vector<ModulePortId>>> PortLookup;
mutable PortLookup port_lookup_; /* [module_ids][port_types][port_ids] */
/* fast look-up for nets */
typedef vtr::vector<ModuleId, std::map<ModuleId, std::vector<std::map<ModulePortId, std::vector<ModuleNetId>>>>> NetLookup;
mutable NetLookup net_lookup_; /* [module_ids][module_ids][instance_ids][port_ids][pin_ids] */
};
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,35 @@
/**************************************************
* This file includes only declarations for
* the data structures for module managers
* Please refer to module_manager.h for more details
*************************************************/
#ifndef MODULE_MANAGER_FWD_H
#define MODULE_MANAGER_FWD_H
#include "vtr_strong_id.h"
/* begin namespace openfpga */
namespace openfpga {
/* Strong Ids for ModuleManager */
struct module_id_tag;
struct instance_id_tag; /* TODO: use instance id in module_manager */
struct module_port_id_tag;
struct module_pin_id_tag;
struct module_net_id_tag;
struct module_net_src_id_tag;
struct module_net_sink_id_tag;
typedef vtr::StrongId<module_id_tag> ModuleId;
typedef vtr::StrongId<instance_id_tag> InstanceId;
typedef vtr::StrongId<module_port_id_tag> ModulePortId;
typedef vtr::StrongId<module_pin_id_tag> ModulePinId;
typedef vtr::StrongId<module_net_id_tag> ModuleNetId;
typedef vtr::StrongId<module_net_src_id_tag> ModuleNetSrcId;
typedef vtr::StrongId<module_net_sink_id_tag> ModuleNetSinkId;
class ModuleManager;
} /* end namespace openfpga */
#endif

View File

@ -4,9 +4,10 @@
* They are made to ease the development in some specific purposes * They are made to ease the development in some specific purposes
* Please classify such functions in this file * Please classify such functions in this file
***********************************************************************/ ***********************************************************************/
#include <algorithm> #include <algorithm>
/* Headers from vtr util library */ /* Headers from vtrutil library */
#include "vtr_assert.h" #include "vtr_assert.h"
#include "vtr_log.h" #include "vtr_log.h"
@ -83,11 +84,11 @@ std::vector<CircuitPortId> find_circuit_mode_select_sram_ports(const CircuitLibr
static static
size_t find_rram_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib, size_t find_rram_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& rram_model, const CircuitModelId& rram_model,
const e_config_protocol_type& config_protocol_type) { const e_config_protocol_type& sram_orgz_type) {
size_t num_shared_config_bits = 0; size_t num_shared_config_bits = 0;
/* Branch on the organization of configuration protocol */ /* Branch on the organization of configuration protocol */
switch (config_protocol_type) { switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE: case CONFIG_MEM_STANDALONE:
case CONFIG_MEM_SCAN_CHAIN: case CONFIG_MEM_SCAN_CHAIN:
break; break;
@ -100,7 +101,7 @@ size_t find_rram_circuit_num_shared_config_bits(const CircuitLibrary& circuit_li
break; break;
} }
default: default:
VTR_LOG_ERROR("Invalid type of configuration protocol!\n"); VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1); exit(1);
} }
@ -123,7 +124,7 @@ size_t find_rram_circuit_num_shared_config_bits(const CircuitLibrary& circuit_li
*******************************************************************/ *******************************************************************/
size_t find_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib, size_t find_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model, const CircuitModelId& circuit_model,
const e_config_protocol_type& config_protocol_type) { const e_config_protocol_type& sram_orgz_type) {
size_t num_shared_config_bits = 0; size_t num_shared_config_bits = 0;
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM); std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM);
@ -138,11 +139,10 @@ size_t find_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
break; break;
case CIRCUIT_MODEL_DESIGN_RRAM: case CIRCUIT_MODEL_DESIGN_RRAM:
/* RRAM circuit do need shared configuration bits, but it is subjected to the largest one among different SRAM models */ /* RRAM circuit do need shared configuration bits, but it is subjected to the largest one among different SRAM models */
num_shared_config_bits = std::max((int)num_shared_config_bits, (int)find_rram_circuit_num_shared_config_bits(circuit_lib, sram_model, config_protocol_type)); num_shared_config_bits = std::max((int)num_shared_config_bits, (int)find_rram_circuit_num_shared_config_bits(circuit_lib, sram_model, sram_orgz_type));
break; break;
default: default:
VTR_LOG_ERROR("Invalid design technology for SRAM circuit model!\n", VTR_LOG_ERROR("Invalid design technology for SRAM model!\n");
circuit_lib.model_name(circuit_model).c_str());
exit(1); exit(1);
} }
} }

View File

@ -7,7 +7,6 @@
/******************************************************************** /********************************************************************
* Include header files that are required by function declaration * Include header files that are required by function declaration
*******************************************************************/ *******************************************************************/
#include <vector> #include <vector>
#include "circuit_types.h" #include "circuit_types.h"
#include "circuit_library.h" #include "circuit_library.h"

View File

@ -0,0 +1,385 @@
/*********************************************************************
* This file includes functions that are used for
* generating ports for memory modules
*********************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_naming.h"
#include "memory_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/*********************************************************************
* Create a port-to-port map for a CMOS memory module
*
* Configuration Chain
* -------------------
*
* config_bus (head) config_bus (tail)
* | ^
* v |
* +-------------------------------------+
* | CMOS-based Memory Module |
* +-------------------------------------+
* | |
* v v
* sram_out sram_outb
*
*
* Memory bank
* -----------
*
* config_bus (BL) config_bus (WL)
* | |
* v v
* +-------------------------------------+
* | CMOS-based Memory Module |
* +-------------------------------------+
* | |
* v v
* sram_out sram_outb
*
**********************************************************************/
static
std::map<std::string, BasicPort> generate_cmos_mem_module_port2port_map(const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_config_protocol_type& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Nothing to do */
break;
case CONFIG_MEM_SCAN_CHAIN: {
/* Link the head port of the memory module:
* the LSB of config bus port is the head port index
*/
std::vector<BasicPort> config_bus_ports;
config_bus_ports.push_back(BasicPort(generate_local_config_bus_port_name(), config_bus.get_msb(), config_bus.get_msb() + 1));
BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb());
port2port_name_map[generate_configuration_chain_head_name()] = head_port;
/* Link the tail port of the memory module:
* the MSB of config bus port is the tail port index
*/
BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb());
port2port_name_map[generate_configuration_chain_tail_name()] = tail_port;
/* Link the SRAM output ports of the memory module */
VTR_ASSERT( 2 == mem_output_bus_ports.size() );
port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0];
port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1];
break;
}
case CONFIG_MEM_MEMORY_BANK:
/* TODO: */
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1);
}
return port2port_name_map;
}
/*********************************************************************
* Create a port-to-port map for a ReRAM-based memory module
* Memory bank
* -----------
*
* config_bus (BL) config_bus (WL)
* | |
* v v
* +-------------------------------------+
* | ReRAM-based Memory Module |
* +-------------------------------------+
* | |
* v v
* Mem_out Mem_outb
**********************************************************************/
static
std::map<std::string, BasicPort> generate_rram_mem_module_port2port_map(const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_config_protocol_type& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Not supported */
break;
case CONFIG_MEM_SCAN_CHAIN: {
/* Link the head port of the memory module:
* the LSB of config bus port is the head port index
*/
std::vector<BasicPort> config_bus_ports;
config_bus_ports.push_back(BasicPort(generate_local_config_bus_port_name(), config_bus.get_msb(), config_bus.get_msb() + 1));
BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb());
port2port_name_map[generate_configuration_chain_head_name()] = head_port;
/* Link the tail port of the memory module:
* the MSB of config bus port is the tail port index
*/
BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb());
port2port_name_map[generate_configuration_chain_tail_name()] = tail_port;
/* Link the SRAM output ports of the memory module */
VTR_ASSERT( 2 == mem_output_bus_ports.size() );
port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0];
port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1];
break;
}
case CONFIG_MEM_MEMORY_BANK:
/* TODO: link BL/WL/Reserved Ports to the inputs of a memory module */
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1);
}
return port2port_name_map;
}
/*********************************************************************
* Create a port-to-port map for a memory module
* The content of the port-to-port map will depend not only
* the design technology of the memory cells but also the
* configuration styles of FPGA fabric.
* Here we will branch on the design technology
**********************************************************************/
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_circuit_model_design_tech& mem_design_tech,
const e_config_protocol_type& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (mem_design_tech) {
case CIRCUIT_MODEL_DESIGN_CMOS:
port2port_name_map = generate_cmos_mem_module_port2port_map(config_bus, mem_output_bus_ports, sram_orgz_type);
break;
case CIRCUIT_MODEL_DESIGN_RRAM:
port2port_name_map = generate_rram_mem_module_port2port_map(config_bus, mem_output_bus_ports, sram_orgz_type);
break;
default:
VTR_LOG_ERROR("Invalid type of memory design technology!\n");
exit(1);
}
return port2port_name_map;
}
/*********************************************************************
* Update the LSB and MSB of a configuration bus based on the number of
* memory bits of a CMOS memory module.
**********************************************************************/
static
void update_cmos_mem_module_config_bus(const e_config_protocol_type& sram_orgz_type,
const size_t& num_config_bits,
BasicPort& config_bus) {
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Not supported */
break;
case CONFIG_MEM_SCAN_CHAIN:
/* Scan-chain of a memory module only has a head and a tail.
* LSB and MSB of configuration bus will be shifted to the next head.
*/
VTR_ASSERT(true == config_bus.rotate(1));
break;
case CONFIG_MEM_MEMORY_BANK:
/* In this case, a memory module has a number of BL/WL and BLB/WLB (possibly).
* LSB and MSB of configuration bus will be shifted by the number of BL/WL/BLB/WLB.
*/
VTR_ASSERT(true == config_bus.rotate(num_config_bits));
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1);
}
}
/*********************************************************************
* Update the LSB and MSB of a configuration bus based on the number of
* memory bits of a ReRAM memory module.
**********************************************************************/
static
void update_rram_mem_module_config_bus(const e_config_protocol_type& sram_orgz_type,
BasicPort& config_bus) {
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Not supported */
break;
case CONFIG_MEM_SCAN_CHAIN:
/* Scan-chain of a memory module only has a head and a tail.
* LSB and MSB of configuration bus will be shifted to the next head.
* TODO: this may be changed later!!!
*/
VTR_ASSERT(true == config_bus.rotate(1));
break;
case CONFIG_MEM_MEMORY_BANK:
/* In this case, a memory module contains unique BL/WL or BLB/WLB,
* which are not shared with other modules
* TODO: this may be changed later!!!
*/
VTR_ASSERT(true == config_bus.rotate(1));
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1);
}
}
/*********************************************************************
* Update the LSB and MSB of a configuration bus based on the number of
* memory bits of a module.
* Note that this function is designed to do such simple job, in purpose of
* being independent from adding ports or printing ports.
* As such, this function can be re-used in bitstream generation
* when Verilog generation is not needed.
* DO NOT update the configuration bus in the function of adding/printing ports
**********************************************************************/
void update_mem_module_config_bus(const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_design_tech& mem_design_tech,
const size_t& num_config_bits,
BasicPort& config_bus) {
switch (mem_design_tech) {
case CIRCUIT_MODEL_DESIGN_CMOS:
update_cmos_mem_module_config_bus(sram_orgz_type, num_config_bits, config_bus);
break;
case CIRCUIT_MODEL_DESIGN_RRAM:
update_rram_mem_module_config_bus(sram_orgz_type, config_bus);
break;
default:
VTR_LOG_ERROR("Invalid type of memory design technology!\n");
exit(1);
}
}
/********************************************************************
* Check if the MSB of a configuration bus of a switch block
* matches the expected value
********************************************************************/
bool check_mem_config_bus(const e_config_protocol_type& sram_orgz_type,
const BasicPort& config_bus,
const size_t& local_expected_msb) {
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Not supported */
return false;
break;
case CONFIG_MEM_SCAN_CHAIN:
/* TODO: comment on why
*/
return (local_expected_msb == config_bus.get_msb());
break;
case CONFIG_MEM_MEMORY_BANK:
/* TODO: comment on why
*/
return (local_expected_msb == config_bus.get_msb());
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization!\n");
exit(1);
}
/* Reach here, it means something goes wrong, return a false value */
return false;
}
/********************************************************************
* Generate a list of ports that are used for SRAM configuration to a module
* The type and names of added ports strongly depend on the
* organization of SRAMs.
* 1. Standalone SRAMs:
* two ports will be added, which are regular output and inverted output
* 2. Scan-chain Flip-flops:
* two ports will be added, which are the head of scan-chain
* and the tail of scan-chain
* IMPORTANT: the port size will be forced to 1 in this case
* because the head and tail are both 1-bit ports!!!
* 3. Memory decoders:
* 2-4 ports will be added, depending on the ports available in the SRAM
* Among these, two ports are mandatory: BL and WL
* The other two ports are optional: BLB and WLB
* Note that the constraints are correletated to the checking rules
* in check_circuit_library()
********************************************************************/
std::vector<std::string> generate_sram_port_names(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type sram_orgz_type) {
std::vector<std::string> sram_port_names;
/* Prepare a list of port types to be added, the port type will be used to create port names */
std::vector<e_circuit_model_port_type> model_port_types;
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
model_port_types.push_back(CIRCUIT_MODEL_PORT_INPUT);
model_port_types.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
break;
case CONFIG_MEM_SCAN_CHAIN:
model_port_types.push_back(CIRCUIT_MODEL_PORT_INPUT);
model_port_types.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
break;
case CONFIG_MEM_MEMORY_BANK: {
std::vector<e_circuit_model_port_type> ports_to_search;
ports_to_search.push_back(CIRCUIT_MODEL_PORT_BL);
ports_to_search.push_back(CIRCUIT_MODEL_PORT_WL);
ports_to_search.push_back(CIRCUIT_MODEL_PORT_BLB);
ports_to_search.push_back(CIRCUIT_MODEL_PORT_WLB);
/* Try to find a BL/WL/BLB/WLB port and update the port types/module port types to be added */
for (const auto& port_to_search : ports_to_search) {
std::vector<CircuitPortId> found_port = circuit_lib.model_ports_by_type(sram_model, port_to_search);
if (0 == found_port.size()) {
continue;
}
model_port_types.push_back(port_to_search);
}
break;
}
default:
VTR_LOG_ERROR("Invalid type of SRAM organization !\n");
exit(1);
}
/* Add ports to the module manager */
for (size_t iport = 0; iport < model_port_types.size(); ++iport) {
/* Create a port */
std::string port_name = generate_sram_port_name(sram_orgz_type, model_port_types[iport]);
sram_port_names.push_back(port_name);
}
return sram_port_names;
}
/********************************************************************
* Generate a list of ports that are used for SRAM configuration to a module
* 1. Standalone SRAMs:
* use the suggested port_size
* 2. Scan-chain Flip-flops:
* IMPORTANT: the port size will be forced to 1 in this case
* 3. Memory decoders:
* use the suggested port_size
********************************************************************/
size_t generate_sram_port_size(const e_config_protocol_type sram_orgz_type,
const size_t& num_config_bits) {
size_t sram_port_size = num_config_bits;
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
break;
case CONFIG_MEM_SCAN_CHAIN:
/* CCFF head/tail are single-bit ports */
sram_port_size = 1;
break;
case CONFIG_MEM_MEMORY_BANK:
break;
default:
VTR_LOG_ERROR("Invalid type of SRAM organization !\n");
exit(1);
}
return sram_port_size;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,42 @@
#ifndef MEMORY_UTILS_H
#define MEMORY_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "openfpga_port.h"
#include "circuit_types.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const BasicPort& config_bus,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_circuit_model_design_tech& mem_design_tech,
const e_config_protocol_type& sram_orgz_type);
void update_mem_module_config_bus(const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_design_tech& mem_design_tech,
const size_t& num_config_bits,
BasicPort& config_bus);
bool check_mem_config_bus(const e_config_protocol_type& sram_orgz_type,
const BasicPort& config_bus,
const size_t& local_expected_msb);
std::vector<std::string> generate_sram_port_names(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type sram_orgz_type);
size_t generate_sram_port_size(const e_config_protocol_type sram_orgz_type,
const size_t& num_config_bits);
} /* end namespace openfpga */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
/******************************************************************************
* This files includes declarations for most utilized functions
* for data structures for module management.
******************************************************************************/
#ifndef MODULE_MANAGER_UTILS_H
#define MODULE_MANAGER_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
/* Headers from readarch library */
#include "physical_types.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
/* Headers from readarchopenfpga library */
#include "circuit_types.h"
#include "circuit_library.h"
#include "module_manager.h"
#include "vpr_device_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
const std::string& module_name);
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model);
void add_reserved_sram_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
const size_t& port_size);
void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const std::string& preproc_flag,
const size_t& port_size);
void add_sram_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type sram_orgz_type,
const size_t& num_config_bits);
void add_primitive_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type,
const VprDeviceAnnotation& vpr_device_annotation);
void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type);
bool module_net_is_local_wire(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);
bool module_net_include_output_short_connection(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);
bool module_net_include_local_short_connection(const ModuleManager& module_manager,
const ModuleId& module_id, const ModuleNetId& module_net);
void add_primitive_pb_type_module_nets(ModuleManager& module_manager,
const ModuleId& pb_type_module,
const ModuleId& child_module,
const size_t& child_instance_id,
const CircuitLibrary& circuit_lib,
t_pb_type* cur_pb_type,
const VprDeviceAnnotation& vpr_device_annotation);
void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const ModuleId& logic_module,
const size_t& logic_instance_id,
const ModuleId& memory_module,
const size_t& memory_instance_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& logic_model);
void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type);
void add_module_nets_memory_config_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_design_tech& mem_tech);
size_t find_module_num_shared_config_bits(const ModuleManager& module_manager,
const ModuleId& module_id);
size_t find_module_num_config_bits(const ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type);
void add_module_global_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id);
void add_module_gpio_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id);
size_t find_module_num_shared_config_bits_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id);
size_t find_module_num_config_bits_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type);
} /* end namespace openfpga */
#endif

View File

@ -254,4 +254,52 @@ enum PORTS circuit_port_require_pb_port_type(const e_circuit_model_port_type& ci
return type_mapping.at(circuit_port_type); return type_mapping.at(circuit_port_type);
} }
/********************************************************************
* Return a list of ports of a pb_type which matches the ports defined
* in its linked circuit model
* This function will only care if the port type matches
*******************************************************************/
std::vector<t_port*> find_pb_type_ports_match_circuit_model_port_type(t_pb_type* pb_type,
const e_circuit_model_port_type& port_type,
const VprDeviceAnnotation& vpr_device_annotation) {
std::vector<t_port*> ports;
for (int iport = 0; iport < pb_type->num_ports; ++iport) {
/* Check the circuit_port id of the port ? */
VTR_ASSERT(CircuitPortId::INVALID() != vpr_device_annotation.pb_circuit_port(&(pb_type->ports[iport])));
switch (port_type) {
case CIRCUIT_MODEL_PORT_INPUT:
if ( (IN_PORT == pb_type->ports[iport].type)
&& (0 == pb_type->ports[iport].is_clock) ) {
ports.push_back(&pb_type->ports[iport]);
}
break;
case CIRCUIT_MODEL_PORT_OUTPUT:
if ( (OUT_PORT == pb_type->ports[iport].type)
&& (0 == pb_type->ports[iport].is_clock) ) {
ports.push_back(&pb_type->ports[iport]);
}
break;
case CIRCUIT_MODEL_PORT_INOUT:
if ( (INOUT_PORT == pb_type->ports[iport].type)
&& (0 == pb_type->ports[iport].is_clock) ) {
ports.push_back(&pb_type->ports[iport]);
}
break;
case CIRCUIT_MODEL_PORT_CLOCK:
if ( (IN_PORT == pb_type->ports[iport].type)
&& (1 == pb_type->ports[iport].is_clock) ) {
ports.push_back(&pb_type->ports[iport]);
}
break;
/* Configuration ports are not in pb_type definition */
default:
VTR_LOG_ERROR("Invalid type for port!\n");
exit(1);
}
}
return ports;
}
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "physical_types.h" #include "physical_types.h"
#include "vpr_device_annotation.h"
#include "circuit_library.h" #include "circuit_library.h"
/******************************************************************** /********************************************************************
@ -43,6 +44,10 @@ e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_intercon
enum PORTS circuit_port_require_pb_port_type(const e_circuit_model_port_type& circuit_port_type); enum PORTS circuit_port_require_pb_port_type(const e_circuit_model_port_type& circuit_port_type);
std::vector<t_port*> find_pb_type_ports_match_circuit_model_port_type(t_pb_type* pb_type,
const e_circuit_model_port_type& port_type,
const VprDeviceAnnotation& vpr_device_annotation);
} /* end namespace openfpga */ } /* end namespace openfpga */
#endif #endif