start integrating module graph builder
This commit is contained in:
parent
13fadd0f91
commit
f11832b8cf
|
@ -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 */
|
||||||
|
|
|
@ -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
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 */
|
|
@ -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
|
@ -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
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue