refactoring MUX Verilog instanciation in Switch block
This commit is contained in:
parent
dbe1625267
commit
167778cf57
|
@ -65,6 +65,14 @@ MuxGraph::mem_range MuxGraph::memories() const {
|
|||
return vtr::make_range(mem_ids_.begin(), mem_ids_.end());
|
||||
}
|
||||
|
||||
std::vector<size_t> MuxGraph::levels() const {
|
||||
std::vector<size_t> graph_levels;
|
||||
for (size_t lvl = 0; lvl < num_levels(); ++lvl) {
|
||||
graph_levels.push_back(lvl);
|
||||
}
|
||||
return graph_levels;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public Accessors: Data query
|
||||
*************************************************/
|
||||
|
@ -158,6 +166,14 @@ size_t MuxGraph::num_memory_bits() const {
|
|||
return mem_ids_.size();
|
||||
}
|
||||
|
||||
/* Find the number of SRAMs at a level in the MUX graph */
|
||||
size_t MuxGraph::num_memory_bits_at_level(const size_t& level) const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_level(level));
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
return mem_lookup_[level].size();
|
||||
}
|
||||
|
||||
/* Find the number of nodes at a given level in the MUX graph */
|
||||
size_t MuxGraph::num_nodes_at_level(const size_t& level) const {
|
||||
/* validate the level numbers */
|
||||
|
@ -310,6 +326,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
}
|
||||
/* Not found, we add a memory bit and record in the mem-to-mem map */
|
||||
MuxMemId mem_subgraph = mux_graph.add_mem();
|
||||
mux_graph.set_mem_level(mem_subgraph, 0);
|
||||
mem2mem_map[mem_origin] = mem_subgraph;
|
||||
/* configure the edge */
|
||||
mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem_subgraph;
|
||||
|
@ -317,6 +334,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
mux_graph.build_node_lookup();
|
||||
mux_graph.build_mem_lookup();
|
||||
|
||||
return mux_graph;
|
||||
}
|
||||
|
@ -519,11 +537,20 @@ MuxMemId MuxGraph::add_mem() {
|
|||
MuxMemId mem = MuxMemId(mem_ids_.size());
|
||||
/* Push to the node list */
|
||||
mem_ids_.push_back(mem);
|
||||
mem_levels_.push_back(size_t(-1));
|
||||
/* Resize the other node-related vectors */
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Configure the level of a memory */
|
||||
void MuxGraph::set_mem_level(const MuxMemId& mem, const size_t& level) {
|
||||
/* Make sure we have valid edge and mem */
|
||||
VTR_ASSERT( valid_mem_id(mem) );
|
||||
|
||||
mem_levels_[mem] = level;
|
||||
}
|
||||
|
||||
/* Link an edge to a memory bit */
|
||||
void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) {
|
||||
/* Make sure we have valid edge and mem */
|
||||
|
@ -593,8 +620,11 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
|||
num_mems_per_level = 1;
|
||||
}
|
||||
/* Number of memory bits is definite, add them */
|
||||
for (size_t i = 0; i < num_mems_per_level * num_levels; ++i) {
|
||||
add_mem();
|
||||
for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) {
|
||||
for (size_t imem = 0; imem < num_mems_per_level; ++imem) {
|
||||
MuxMemId mem = add_mem();
|
||||
mem_levels_[mem] = ilvl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a fast node lookup locally.
|
||||
|
@ -747,6 +777,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
|||
|
||||
/* Create a memory bit*/
|
||||
MuxMemId mem = add_mem();
|
||||
mem_levels_[mem] = 0;
|
||||
/* Link the edge to a memory bit */
|
||||
set_edge_mem_id(edge, mem);
|
||||
}
|
||||
|
@ -863,6 +894,7 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
|||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
build_node_lookup();
|
||||
build_mem_lookup();
|
||||
|
||||
/* For fracturable LUTs, we need to add more outputs to the MUX graph */
|
||||
if ( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
||||
|
@ -895,10 +927,34 @@ void MuxGraph::build_node_lookup() {
|
|||
}
|
||||
}
|
||||
|
||||
/* Build fast mem lookup */
|
||||
void MuxGraph::build_mem_lookup() {
|
||||
/* Invalidate the mem lookup if necessary */
|
||||
invalidate_mem_lookup();
|
||||
|
||||
/* Find the maximum number of levels */
|
||||
size_t num_levels = 0;
|
||||
for (auto mem : memories()) {
|
||||
num_levels = std::max((int)mem_levels_[mem], (int)num_levels);
|
||||
}
|
||||
|
||||
/* Resize mem_lookup */
|
||||
mem_lookup_.resize(num_levels + 1);
|
||||
for (auto mem : memories()) {
|
||||
/* Categorize mem nodes into mem_lookup */
|
||||
mem_lookup_[mem_levels_[mem]].push_back(mem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the node fast lookup*/
|
||||
void MuxGraph::invalidate_node_lookup() {
|
||||
node_lookup_.clear();
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the mem fast lookup*/
|
||||
void MuxGraph::invalidate_mem_lookup() {
|
||||
mem_lookup_.clear();
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private validators
|
||||
|
|
|
@ -62,6 +62,7 @@ class MuxGraph {
|
|||
std::vector<MuxNodeId> non_input_nodes() const;
|
||||
edge_range edges() const;
|
||||
mem_range memories() const;
|
||||
std::vector<size_t> levels() const;
|
||||
public: /* Public accessors: Data query */
|
||||
/* Find the number of inputs in the MUX graph */
|
||||
size_t num_inputs() const;
|
||||
|
@ -76,6 +77,8 @@ class MuxGraph {
|
|||
size_t num_node_levels() const;
|
||||
/* Find the number of SRAMs in the MUX graph */
|
||||
size_t num_memory_bits() const;
|
||||
/* Find the number of SRAMs at a level in the MUX graph */
|
||||
size_t num_memory_bits_at_level(const size_t& level) const;
|
||||
/* Find the number of nodes at a given level in the MUX graph */
|
||||
size_t num_nodes_at_level(const size_t& level) const;
|
||||
/* Find the level of a node */
|
||||
|
@ -112,6 +115,8 @@ class MuxGraph {
|
|||
MuxEdgeId add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node);
|
||||
/* Add a memory bit to the MuxGraph */
|
||||
MuxMemId add_mem();
|
||||
/* Configure the level of a memory */
|
||||
void set_mem_level(const MuxMemId& mem, const size_t& level);
|
||||
/* Link an edge to a mem */
|
||||
void set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem);
|
||||
private: /* Private mutators : graph builders */
|
||||
|
@ -130,6 +135,8 @@ class MuxGraph {
|
|||
const CircuitModelId& circuit_model);
|
||||
/* Build fast node lookup */
|
||||
void build_node_lookup();
|
||||
/* Build fast mem lookup */
|
||||
void build_mem_lookup();
|
||||
private: /* Private validators */
|
||||
/* valid ids */
|
||||
bool valid_node_id(const MuxNodeId& node) const;
|
||||
|
@ -141,6 +148,7 @@ class MuxGraph {
|
|||
/* validate/invalidate node lookup */
|
||||
bool valid_node_lookup() const;
|
||||
void invalidate_node_lookup();
|
||||
void invalidate_mem_lookup();
|
||||
/* validate graph */
|
||||
bool valid_mux_graph() const;
|
||||
private: /* Internal data */
|
||||
|
@ -161,10 +169,13 @@ class MuxGraph {
|
|||
vtr::vector<MuxEdgeId, bool> edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */
|
||||
|
||||
vtr::vector<MuxMemId, MuxMemId> mem_ids_; /* ids of configuration memories */
|
||||
vtr::vector<MuxMemId, size_t> mem_levels_; /* ids of configuration memories */
|
||||
|
||||
/* fast look-up */
|
||||
typedef std::vector<std::vector<std::vector<MuxNodeId>>> NodeLookup;
|
||||
mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */
|
||||
typedef std::vector<std::vector<MuxMemId>> MemLookup;
|
||||
mutable MemLookup mem_lookup_; /* [num_levels][num_mems_per_level] */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -283,6 +283,7 @@ size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
|||
const MuxGraph& mux_graph,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
size_t num_config_bits = 0;
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
|
@ -296,10 +297,16 @@ size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (true == circuit_lib.mux_use_local_encoder(mux_model)) {
|
||||
num_config_bits = find_mux_local_decoder_addr_size(mux_graph.num_memory_bits());
|
||||
if (false == circuit_lib.mux_use_local_encoder(mux_model)) {
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
num_config_bits = 0;
|
||||
/* Multiplexer local encoders are applied to memory bits at each stage */
|
||||
for (const auto& lvl : mux_graph.levels()) {
|
||||
num_config_bits += find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
|
||||
}
|
||||
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -2328,7 +2329,7 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
|||
t_rr_node* cur_rr_node,
|
||||
const std::vector<t_rr_node*>& drive_rr_nodes,
|
||||
const size_t& switch_index,
|
||||
const bool& is_explicit_mapping) {
|
||||
const bool& use_explicit_mapping) {
|
||||
/* Check the file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
|
@ -2341,11 +2342,9 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
|||
|
||||
/* Find the input size of the implementation of a routing multiplexer */
|
||||
size_t datapath_mux_size = drive_rr_nodes.size();
|
||||
size_t impl_mux_size = find_mux_implementation_num_inputs(circuit_lib, mux_model, datapath_mux_size);
|
||||
VTR_ASSERT(true == valid_mux_implementation_num_inputs(impl_mux_size));
|
||||
|
||||
/* Get the multiplexing graph from the Mux Library */
|
||||
MuxId mux_id = mux_lib.mux_graph(mux_model, impl_mux_size);
|
||||
MuxId mux_id = mux_lib.mux_graph(mux_model, datapath_mux_size);
|
||||
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
|
||||
|
||||
/* Find the module name of the multiplexer and try to find it in the module manager */
|
||||
|
@ -2365,19 +2364,12 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
|||
inbus_port.set_name(generate_mux_input_bus_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id));
|
||||
inbus_port.set_width(datapath_mux_size);
|
||||
|
||||
/* Create the path of the input of multiplexer in the hierarchy
|
||||
* TODO: this MUST be deprecated later because module manager is created to handle these problems!!!
|
||||
*/
|
||||
std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/")
|
||||
+ mux_module_name + std::string("_")
|
||||
+ std::to_string(mux_instance_id) + std::string("_/in");
|
||||
cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str());
|
||||
|
||||
/* Generate input ports that are wired to the input bus of the routing multiplexer */
|
||||
std::vector<BasicPort> mux_input_ports = generate_switch_block_input_ports(rr_sb, drive_rr_nodes);
|
||||
/* Connect input ports to bus */
|
||||
print_verilog_comment(fp, std::string("----- A local bus wire for multiplexer inputs -----"));
|
||||
print_verilog_comment(fp, std::string("----- BEGIN A local bus wire for multiplexer inputs -----"));
|
||||
fp << generate_verilog_local_wire(inbus_port, mux_input_ports) << std::endl;
|
||||
print_verilog_comment(fp, std::string("----- END A local bus wire for multiplexer inputs -----"));
|
||||
fp << std::endl;
|
||||
|
||||
/* Find the number of reserved configuration bits for the routing multiplexer */
|
||||
|
@ -2387,32 +2379,66 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
|||
size_t mux_num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, cur_sram_orgz_info->type);
|
||||
|
||||
/* Print the configuration bus for the routing multiplexers */
|
||||
print_verilog_comment(fp, std::string("----- Local wires to group configuration ports -----"));
|
||||
print_verilog_comment(fp, std::string("----- BEGIN Local wires to group configuration ports -----"));
|
||||
print_verilog_mux_config_bus(fp, circuit_lib, mux_model, cur_sram_orgz_info->type,
|
||||
datapath_mux_size, mux_instance_id,
|
||||
mux_num_reserved_config_bits, mux_num_config_bits);
|
||||
print_verilog_comment(fp, std::string("----- END Local wires to group configuration ports -----"));
|
||||
fp << std::endl;
|
||||
|
||||
/* Dump ports visible only during formal verification */
|
||||
print_verilog_comment(fp, std::string("----- Local wires used in only formal verification purpose -----"));
|
||||
print_verilog_comment(fp, std::string("----- BEGIN Local wires used in only formal verification purpose -----"));
|
||||
print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag));
|
||||
/* Print the SRAM configuration ports for formal verification */
|
||||
/* TODO: align with the port width of formal verification port of SB module */
|
||||
print_verilog_formal_verification_mux_sram_ports_wiring(fp, circuit_lib, mux_model,
|
||||
datapath_mux_size, mux_instance_id, mux_num_config_bits);
|
||||
print_verilog_endif(fp);
|
||||
print_verilog_comment(fp, std::string("----- END Local wires used in only formal verification purpose -----"));
|
||||
fp << std::endl;
|
||||
|
||||
/* TODO: Instanciate the MUX Module */
|
||||
/* TODO: create port-to-port map */
|
||||
/* Instanciate the MUX Module */
|
||||
/* Create port-to-port map */
|
||||
std::map<std::string, BasicPort> mux_port2port_name_map;
|
||||
|
||||
/* Link input bus port to Switch Block inputs */
|
||||
std::vector<CircuitPortId> mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
VTR_ASSERT(1 == mux_model_input_ports.size());
|
||||
/* Use the port name convention in the circuit library */
|
||||
mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_input_ports[0])] = inbus_port;
|
||||
|
||||
/* Link output port to Switch Block outputs */
|
||||
std::vector<CircuitPortId> mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
VTR_ASSERT(1 == mux_model_output_ports.size());
|
||||
/* Use the port name convention in the circuit library */
|
||||
mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_output_ports[0])] = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT);
|
||||
|
||||
/* Link SRAM port to different configuraton port for the routing multiplexer
|
||||
* Different design technology requires different configuration bus!
|
||||
dump_verilog_mux_config_bus_ports(fp, verilog_model, cur_sram_orgz_info,
|
||||
mux_size, cur_num_sram, num_mux_reserved_conf_bits,
|
||||
num_mux_conf_bits, is_explicit_mapping);
|
||||
*/
|
||||
/* TODO: Print an instance of the MUX Module */
|
||||
std::vector<CircuitPortId> mux_model_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true);
|
||||
VTR_ASSERT( 1 == mux_model_sram_ports.size() );
|
||||
/* For the regular SRAM port, module port use the same name */
|
||||
std::string mux_module_sram_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]);
|
||||
BasicPort mux_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
|
||||
mux_num_config_bits);
|
||||
mux_port2port_name_map[mux_module_sram_port_name] = mux_config_port;
|
||||
|
||||
/* For the inverted SRAM port */
|
||||
std::string mux_module_sram_inv_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]) + std::string("_inv");
|
||||
BasicPort mux_config_inv_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
|
||||
mux_num_config_bits);
|
||||
mux_port2port_name_map[mux_module_sram_inv_port_name] = mux_config_inv_port;
|
||||
|
||||
/* Print an instance of the MUX Module */
|
||||
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a routing multiplexer -----"));
|
||||
print_verilog_module_instance(fp, module_manager, sb_module, mux_module, mux_port2port_name_map, use_explicit_mapping);
|
||||
print_verilog_comment(fp, std::string("----- END Instanciation of a routing multiplexer -----"));
|
||||
fp << std::endl;
|
||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
||||
* update the module manager with the relationship between the parent and child modules
|
||||
*/
|
||||
module_manager.add_child_module(sb_module, mux_module);
|
||||
|
||||
/* TODO: Instanciate memory modules */
|
||||
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||
|
@ -2443,6 +2469,14 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
|||
"(File:%s,[LINE%d])Invalid design technology for circuit model (%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
|
||||
}
|
||||
|
||||
/* Create the path of the input of multiplexer in the hierarchy
|
||||
* TODO: this MUST be deprecated later because module manager is created to handle these problems!!!
|
||||
*/
|
||||
std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/")
|
||||
+ mux_module_name + std::string("_")
|
||||
+ std::to_string(mux_instance_id) + std::string("_/in");
|
||||
cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue