refactoring MUX Verilog instanciation in Switch block

This commit is contained in:
tangxifan 2019-09-27 16:05:47 -06:00
parent dbe1625267
commit 167778cf57
4 changed files with 133 additions and 25 deletions

View File

@ -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,11 +927,35 @@ 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
*************************************************/

View File

@ -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

View File

@ -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,8 +297,14 @@ 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;

View File

@ -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());
}