plug in MUX module graph generation, still local encoders contain dangling net, bug fixing
This commit is contained in:
parent
520e145af2
commit
b2f57ecf81
|
@ -45,15 +45,24 @@ MuxGraph::node_range MuxGraph::nodes() const {
|
||||||
|
|
||||||
/* Find the non-input nodes */
|
/* Find the non-input nodes */
|
||||||
std::vector<MuxNodeId> MuxGraph::non_input_nodes() const {
|
std::vector<MuxNodeId> MuxGraph::non_input_nodes() const {
|
||||||
|
/* Must be an valid graph */
|
||||||
|
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||||
std::vector<MuxNodeId> node_list;
|
std::vector<MuxNodeId> node_list;
|
||||||
for (const auto& node : nodes()) {
|
|
||||||
|
/* Build the node list, level by level */
|
||||||
|
for (size_t level = 0; level < num_node_levels(); ++level) {
|
||||||
|
for (size_t node_type = 0; node_type < size_t(NUM_MUX_NODE_TYPES); ++node_type) {
|
||||||
/* Bypass any nodes which are not OUTPUT and INTERNAL */
|
/* Bypass any nodes which are not OUTPUT and INTERNAL */
|
||||||
if (MUX_INPUT_NODE == node_types_[node]) {
|
if (size_t(MUX_INPUT_NODE) == node_type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Reach here, this is either an OUTPUT or INTERNAL node */
|
/* Reach here, this is either an OUTPUT or INTERNAL node */
|
||||||
|
for (auto node : node_lookup_[level][node_type]) {
|
||||||
node_list.push_back(node);
|
node_list.push_back(node);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return node_list;
|
return node_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,15 +445,29 @@ MuxInputId MuxGraph::input_id(const MuxNodeId& node_id) const {
|
||||||
return node_input_ids_[node_id];
|
return node_input_ids_[node_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the input id of a given node */
|
/* Identify if the node is an input of the MUX */
|
||||||
|
bool MuxGraph::is_node_input(const MuxNodeId& node_id) const {
|
||||||
|
/* Validate node id */
|
||||||
|
VTR_ASSERT(true == valid_node_id(node_id));
|
||||||
|
return (MUX_INPUT_NODE == node_types_[node_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the output id of a given node */
|
||||||
MuxOutputId MuxGraph::output_id(const MuxNodeId& node_id) const {
|
MuxOutputId MuxGraph::output_id(const MuxNodeId& node_id) const {
|
||||||
/* Validate node id */
|
/* Validate node id */
|
||||||
VTR_ASSERT(valid_node_id(node_id));
|
VTR_ASSERT(valid_node_id(node_id));
|
||||||
/* Must be an input */
|
/* Must be an output */
|
||||||
VTR_ASSERT(MUX_OUTPUT_NODE == node_types_[node_id]);
|
VTR_ASSERT(MUX_OUTPUT_NODE == node_types_[node_id]);
|
||||||
return node_output_ids_[node_id];
|
return node_output_ids_[node_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Identify if the node is an output of the MUX */
|
||||||
|
bool MuxGraph::is_node_output(const MuxNodeId& node_id) const {
|
||||||
|
/* Validate node id */
|
||||||
|
VTR_ASSERT(true == valid_node_id(node_id));
|
||||||
|
return (MUX_OUTPUT_NODE == node_types_[node_id]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the node id of a given input */
|
/* Get the node id of a given input */
|
||||||
MuxNodeId MuxGraph::node_id(const MuxInputId& input_id) const {
|
MuxNodeId MuxGraph::node_id(const MuxInputId& input_id) const {
|
||||||
/* Use the node_lookup to accelerate the search */
|
/* Use the node_lookup to accelerate the search */
|
||||||
|
@ -1045,7 +1068,7 @@ bool MuxGraph::valid_output_id(const MuxOutputId& output_id) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MuxGraph::valid_level(const size_t& level) const {
|
bool MuxGraph::valid_level(const size_t& level) const {
|
||||||
return level < num_levels();
|
return level < num_node_levels();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MuxGraph::valid_node_lookup() const {
|
bool MuxGraph::valid_node_lookup() const {
|
||||||
|
|
|
@ -109,8 +109,12 @@ class MuxGraph {
|
||||||
MuxNodeId node_id(const size_t& node_level, const size_t& node_index_at_level) const;
|
MuxNodeId node_id(const size_t& node_level, const size_t& node_index_at_level) const;
|
||||||
/* Get the input id of a given node */
|
/* Get the input id of a given node */
|
||||||
MuxInputId input_id(const MuxNodeId& node_id) const;
|
MuxInputId input_id(const MuxNodeId& node_id) const;
|
||||||
|
/* Identify if the node is an input of the MUX */
|
||||||
|
bool is_node_input(const MuxNodeId& node_id) const;
|
||||||
/* Get the output id of a given node */
|
/* Get the output id of a given node */
|
||||||
MuxOutputId output_id(const MuxNodeId& node_id) const;
|
MuxOutputId output_id(const MuxNodeId& node_id) const;
|
||||||
|
/* Identify if the node is an output of the MUX */
|
||||||
|
bool is_node_output(const MuxNodeId& node_id) const;
|
||||||
/* Decode memory bits based on an input id */
|
/* Decode memory bits based on an input id */
|
||||||
std::vector<size_t> decode_memory_bits(const MuxInputId& input_id) const;
|
std::vector<size_t> decode_memory_bits(const MuxInputId& input_id) const;
|
||||||
private: /* Private mutators : basic operations */
|
private: /* Private mutators : basic operations */
|
||||||
|
|
|
@ -33,6 +33,19 @@ std::string generate_mux_node_name(const size_t& node_level,
|
||||||
return node_name;
|
return node_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* Generate the instance name for a branch circuit in multiplexing structure
|
||||||
|
* Case 1 : If there is an intermediate buffer followed by,
|
||||||
|
* the node name will be mux_l<node_level>_in_buf
|
||||||
|
* Case 1 : If there is NO intermediate buffer followed by,
|
||||||
|
* the node name will be mux_l<node_level>_in
|
||||||
|
***********************************************/
|
||||||
|
std::string generate_mux_branch_instance_name(const size_t& node_level,
|
||||||
|
const size_t& node_index_at_level,
|
||||||
|
const bool& add_buffer_postfix) {
|
||||||
|
return std::string(generate_mux_node_name(node_level, add_buffer_postfix) + "_" + std::to_string(node_index_at_level) + "_");
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
* Generate the module name for a multiplexer in Verilog format
|
* Generate the module name for a multiplexer in Verilog format
|
||||||
* Different circuit model requires different names:
|
* Different circuit model requires different names:
|
||||||
|
@ -936,3 +949,24 @@ std::string generate_fpga_top_module_name() {
|
||||||
std::string generate_fpga_top_netlist_name(const std::string& postfix) {
|
std::string generate_fpga_top_netlist_name(const std::string& postfix) {
|
||||||
return std::string("fpga_top" + postfix);
|
return std::string("fpga_top" + postfix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Generate the module name for a constant generator
|
||||||
|
* either VDD or GND, depending on the input argument
|
||||||
|
********************************************************************/
|
||||||
|
std::string generate_const_value_module_name(const size_t& const_val) {
|
||||||
|
if (0 == const_val) {
|
||||||
|
return std::string("gnd");
|
||||||
|
}
|
||||||
|
|
||||||
|
VTR_ASSERT (1 == const_val);
|
||||||
|
return std::string("vdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Generate the output port name for a constant generator module
|
||||||
|
* either VDD or GND, depending on the input argument
|
||||||
|
********************************************************************/
|
||||||
|
std::string generate_const_value_module_output_port_name(const size_t& const_val) {
|
||||||
|
return generate_const_value_module_name(const_val);
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
std::string generate_mux_node_name(const size_t& node_level,
|
std::string generate_mux_node_name(const size_t& node_level,
|
||||||
const bool& add_buffer_postfix);
|
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,
|
std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
|
@ -165,4 +169,8 @@ std::string generate_fpga_top_module_name();
|
||||||
|
|
||||||
std::string generate_fpga_top_netlist_name(const std::string& postfix);
|
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -175,20 +175,53 @@ ModuleId ModuleManager::find_module(const std::string& name) const {
|
||||||
|
|
||||||
/* Find the number of instances of a child module in the parent module */
|
/* 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 ModuleManager::num_instance(const ModuleId& parent_module, const ModuleId& child_module) const {
|
||||||
/* validate both module ids */
|
size_t child_index = find_child_module_index_in_parent_module(parent_module, child_module);
|
||||||
VTR_ASSERT(valid_module_id(parent_module));
|
if (size_t(-1) == child_index) {
|
||||||
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 num_child_instances_[parent_module][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Not found, return a zero */
|
/* Not found, return a zero */
|
||||||
return 0;
|
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 */
|
/* Find if a port is a wire connection */
|
||||||
bool ModuleManager::port_is_wire(const ModuleId& module, const ModulePortId& port) const {
|
bool ModuleManager::port_is_wire(const ModuleId& module, const ModulePortId& port) const {
|
||||||
/* validate both module id and port id*/
|
/* validate both module id and port id*/
|
||||||
|
@ -309,6 +342,24 @@ vtr::vector<ModuleNetSinkId, size_t> ModuleManager::net_sink_pins(const ModuleId
|
||||||
return net_sink_pin_ids_[module][net];
|
return net_sink_pin_ids_[module][net];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* 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
|
* Public Mutators
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -329,6 +380,7 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
||||||
parents_.emplace_back();
|
parents_.emplace_back();
|
||||||
children_.emplace_back();
|
children_.emplace_back();
|
||||||
num_child_instances_.emplace_back();
|
num_child_instances_.emplace_back();
|
||||||
|
child_instance_names_.emplace_back();
|
||||||
|
|
||||||
port_ids_.emplace_back();
|
port_ids_.emplace_back();
|
||||||
ports_.emplace_back();
|
ports_.emplace_back();
|
||||||
|
@ -442,9 +494,13 @@ void ModuleManager::add_child_module(const ModuleId& parent_module, const Module
|
||||||
/* Update the child module of parent module */
|
/* Update the child module of parent module */
|
||||||
children_[parent_module].push_back(child_module);
|
children_[parent_module].push_back(child_module);
|
||||||
num_child_instances_[parent_module].push_back(1); /* By default give one */
|
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 {
|
} else {
|
||||||
/* Increase the counter of instances */
|
/* Increase the counter of instances */
|
||||||
num_child_instances_[parent_module][child_it - children_[parent_module].begin()]++;
|
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 */
|
/* Update fast look-up for nets */
|
||||||
|
@ -456,6 +512,24 @@ void ModuleManager::add_child_module(const ModuleId& parent_module, const Module
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 net to the connection graph of the module */
|
/* Add a net to the connection graph of the module */
|
||||||
ModuleNetId ModuleManager::create_module_net(const ModuleId& module) {
|
ModuleNetId ModuleManager::create_module_net(const ModuleId& module) {
|
||||||
/* Validate the module id */
|
/* Validate the module id */
|
||||||
|
|
|
@ -80,6 +80,12 @@ class ModuleManager {
|
||||||
ModuleId find_module(const std::string& name) const;
|
ModuleId find_module(const std::string& name) const;
|
||||||
/* Find the number of instances of a child module in the parent module */
|
/* 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;
|
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 */
|
/* Find if a port is a wire connection */
|
||||||
bool port_is_wire(const ModuleId& module, const ModulePortId& port) const;
|
bool port_is_wire(const ModuleId& module, const ModulePortId& port) const;
|
||||||
/* Find if a port is register */
|
/* Find if a port is register */
|
||||||
|
@ -109,6 +115,8 @@ class ModuleManager {
|
||||||
vtr::vector<ModuleNetSinkId, ModulePortId> net_sink_ports(const ModuleId& module, const ModuleNetId& net) const;
|
vtr::vector<ModuleNetSinkId, ModulePortId> net_sink_ports(const ModuleId& module, const ModuleNetId& net) const;
|
||||||
/* Find the sink pin indices of a net */
|
/* Find the sink pin indices of a net */
|
||||||
vtr::vector<ModuleNetSinkId, size_t> net_sink_pins(const ModuleId& module, const ModuleNetId& net) const;
|
vtr::vector<ModuleNetSinkId, size_t> net_sink_pins(const ModuleId& module, const ModuleNetId& net) const;
|
||||||
|
private: /* Private accessors */
|
||||||
|
size_t find_child_module_index_in_parent_module(const ModuleId& parent_module, const ModuleId& child_module) const;
|
||||||
public: /* Public mutators */
|
public: /* Public mutators */
|
||||||
/* Add a module */
|
/* Add a module */
|
||||||
ModuleId add_module(const std::string& name);
|
ModuleId add_module(const std::string& name);
|
||||||
|
@ -125,6 +133,8 @@ class ModuleManager {
|
||||||
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
||||||
/* Add a child module to a parent module */
|
/* Add a child module to a parent module */
|
||||||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_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 net to the connection graph of the module */
|
/* Add a net to the connection graph of the module */
|
||||||
ModuleNetId create_module_net(const ModuleId& module);
|
ModuleNetId create_module_net(const ModuleId& module);
|
||||||
/* Set the name of net */
|
/* Set the name of net */
|
||||||
|
@ -153,6 +163,7 @@ class ModuleManager {
|
||||||
vtr::vector<ModuleId, std::vector<ModuleId>> parents_; /* Parent modules that include the 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<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<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 */
|
||||||
|
|
||||||
/* Port-level data */
|
/* Port-level data */
|
||||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
|
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
/* Strong Ids for ModuleManager */
|
/* Strong Ids for ModuleManager */
|
||||||
struct module_id_tag;
|
struct module_id_tag;
|
||||||
|
struct instance_id_tag; /* TODO: use instance id in module_manager */
|
||||||
struct module_port_id_tag;
|
struct module_port_id_tag;
|
||||||
struct module_pin_id_tag;
|
struct module_pin_id_tag;
|
||||||
struct module_net_id_tag;
|
struct module_net_id_tag;
|
||||||
|
@ -17,6 +18,7 @@ struct module_net_src_id_tag;
|
||||||
struct module_net_sink_id_tag;
|
struct module_net_sink_id_tag;
|
||||||
|
|
||||||
typedef vtr::StrongId<module_id_tag> ModuleId;
|
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_port_id_tag> ModulePortId;
|
||||||
typedef vtr::StrongId<module_pin_id_tag> ModulePinId;
|
typedef vtr::StrongId<module_pin_id_tag> ModulePinId;
|
||||||
typedef vtr::StrongId<module_net_id_tag> ModuleNetId;
|
typedef vtr::StrongId<module_net_id_tag> ModuleNetId;
|
||||||
|
|
|
@ -217,3 +217,33 @@ void build_user_defined_modules(ModuleManager& module_manager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* 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) {
|
||||||
|
|
||||||
|
/* VDD */
|
||||||
|
build_constant_generator_module(module_manager, 1);
|
||||||
|
|
||||||
|
/* GND */
|
||||||
|
build_constant_generator_module(module_manager, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -11,4 +11,6 @@ void build_user_defined_modules(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const std::vector<t_segment_inf>& routing_segments);
|
const std::vector<t_segment_inf>& routing_segments);
|
||||||
|
|
||||||
|
void build_constant_generator_modules(ModuleManager& module_manager);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "build_essential_modules.h"
|
#include "build_essential_modules.h"
|
||||||
#include "build_decoder_modules.h"
|
#include "build_decoder_modules.h"
|
||||||
|
#include "build_mux_modules.h"
|
||||||
#include "build_module_graph.h"
|
#include "build_module_graph.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -66,6 +67,10 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
|
||||||
for (int i = 0; i < arch.num_segments; ++i) {
|
for (int i = 0; i < arch.num_segments; ++i) {
|
||||||
L_segment_vec.push_back(arch.Segments[i]);
|
L_segment_vec.push_back(arch.Segments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add constant generator modules: VDD and GND */
|
||||||
|
build_constant_generator_modules(module_manager);
|
||||||
|
|
||||||
/* Register all the user-defined modules in the module manager
|
/* Register all the user-defined modules in the module manager
|
||||||
* This should be done prior to other steps in this function,
|
* This should be done prior to other steps in this function,
|
||||||
* because they will be instanciated by other primitive modules
|
* because they will be instanciated by other primitive modules
|
||||||
|
@ -78,7 +83,8 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
|
||||||
/* Build local encoders for multiplexers, this MUST be called before multiplexer building */
|
/* 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_mux_local_decoder_modules(module_manager, mux_lib, arch.spice->circuit_lib);
|
||||||
|
|
||||||
/* TODO: Build multiplexer modules */
|
/* Build multiplexer modules */
|
||||||
|
build_mux_modules(module_manager, mux_lib, arch.spice->circuit_lib);
|
||||||
|
|
||||||
/* TODO: Build LUT modules */
|
/* TODO: Build LUT modules */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
||||||
|
/***********************************************
|
||||||
|
* Header file for verilog_mux.cpp
|
||||||
|
**********************************************/
|
||||||
|
|
||||||
|
#ifndef BUILD_MUX_MODULES_H
|
||||||
|
#define BUILD_MUX_MODULES_H
|
||||||
|
|
||||||
|
/* Include other header files which are dependency on the function declared below */
|
||||||
|
#include "spice_types.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "mux_graph.h"
|
||||||
|
#include "mux_library.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
|
||||||
|
void build_mux_modules(ModuleManager& module_manager,
|
||||||
|
const MuxLibrary& mux_lib,
|
||||||
|
const CircuitLibrary& circuit_lib);
|
||||||
|
|
||||||
|
#endif
|
|
@ -62,11 +62,30 @@ BasicPort generate_verilog_port_for_module_net(const ModuleManager& module_manag
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reach here, this is a local wire */
|
/* Reach here, this is a local wire */
|
||||||
|
|
||||||
std::string net_name;
|
std::string net_name;
|
||||||
|
|
||||||
|
if (false == module_manager.net_name(module_id, module_net).empty()) {
|
||||||
|
net_name = module_manager.net_name(module_id, module_net);
|
||||||
|
printf("net_name:%s\n", net_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
/* Each net must only one 1 source */
|
/* Each net must only one 1 source */
|
||||||
|
if (1 != module_manager.net_source_modules(module_id, module_net).size()) {
|
||||||
|
for (auto src_module : module_manager.net_source_modules(module_id, module_net)) {
|
||||||
|
printf("net_source_module: %s\n",
|
||||||
|
module_manager.module_name(src_module).c_str());
|
||||||
|
}
|
||||||
|
for (auto sink_module : module_manager.net_sink_modules(module_id, module_net)) {
|
||||||
|
printf("net_sink_module: %s\n",
|
||||||
|
module_manager.module_name(sink_module).c_str());
|
||||||
|
for (auto sink_port : module_manager.net_sink_ports(module_id, module_net)) {
|
||||||
|
printf("\tnet_sink_port: %s\n",
|
||||||
|
module_manager.module_port(sink_module, sink_port).get_name().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VTR_ASSERT(1 == module_manager.net_source_modules(module_id, module_net).size());
|
VTR_ASSERT(1 == module_manager.net_source_modules(module_id, module_net).size());
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the source module */
|
/* Get the source module */
|
||||||
ModuleId net_src_module = module_manager.net_source_modules(module_id, module_net)[ModuleNetSrcId(0)];
|
ModuleId net_src_module = module_manager.net_source_modules(module_id, module_net)[ModuleNetSrcId(0)];
|
||||||
|
@ -102,6 +121,12 @@ std::vector<BasicPort> find_verilog_module_local_wires(const ModuleManager& modu
|
||||||
|
|
||||||
/* Local wires come from the child modules */
|
/* Local wires come from the child modules */
|
||||||
for (ModuleNetId module_net : module_manager.module_nets(module_id)) {
|
for (ModuleNetId module_net : module_manager.module_nets(module_id)) {
|
||||||
|
/* Bypass dangling nets */
|
||||||
|
if ( (0 == module_manager.net_source_modules(module_id, module_net).size())
|
||||||
|
&& (0 == module_manager.net_source_modules(module_id, module_net).size()) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* We only care local wires */
|
/* We only care local wires */
|
||||||
if (false == module_net_is_local_wire(module_manager, module_id, module_net)) {
|
if (false == module_net_is_local_wire(module_manager, module_id, module_net)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -260,8 +285,15 @@ void write_verilog_instance_to_file(std::fstream& fp,
|
||||||
|
|
||||||
/* Print module name */
|
/* Print module name */
|
||||||
fp << "\t" << module_manager.module_name(child_module) << " ";
|
fp << "\t" << module_manager.module_name(child_module) << " ";
|
||||||
/* Print instance name, <name>_<num_instance_in_parent_module> */
|
/* Print instance name:
|
||||||
|
* if we have an instance name, use it;
|
||||||
|
* if not, we use a default name <name>_<num_instance_in_parent_module>
|
||||||
|
*/
|
||||||
|
if (true == module_manager.instance_name(parent_module, child_module, instance_id).empty()) {
|
||||||
fp << module_manager.module_name(child_module) << "_" << instance_id << "_" << " (" << std::endl;
|
fp << module_manager.module_name(child_module) << "_" << instance_id << "_" << " (" << std::endl;
|
||||||
|
} else {
|
||||||
|
fp << module_manager.instance_name(parent_module, child_module, instance_id) << " (" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Print each port with/without explicit port map */
|
/* Print each port with/without explicit port map */
|
||||||
/* port type2type mapping */
|
/* port type2type mapping */
|
||||||
|
|
|
@ -28,86 +28,9 @@
|
||||||
/* FPGA-Verilog context header files */
|
/* FPGA-Verilog context header files */
|
||||||
#include "verilog_global.h"
|
#include "verilog_global.h"
|
||||||
#include "verilog_writer_utils.h"
|
#include "verilog_writer_utils.h"
|
||||||
|
#include "verilog_module_writer.h"
|
||||||
#include "verilog_mux.h"
|
#include "verilog_mux.h"
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* Generate structural Verilog codes (consist of transmission-gates or
|
|
||||||
* pass-transistor) modeling an branch circuit
|
|
||||||
* for a multiplexer with the given size
|
|
||||||
*********************************************************************/
|
|
||||||
static
|
|
||||||
void generate_verilog_cmos_mux_branch_body_structural(ModuleManager& module_manager,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
std::fstream& fp,
|
|
||||||
const CircuitModelId& tgate_model,
|
|
||||||
const ModuleId& module_id,
|
|
||||||
const BasicPort& input_port,
|
|
||||||
const BasicPort& output_port,
|
|
||||||
const BasicPort& mem_port,
|
|
||||||
const BasicPort& mem_inv_port,
|
|
||||||
const MuxGraph& mux_graph) {
|
|
||||||
/* Make sure we have a valid file handler*/
|
|
||||||
check_file_handler(fp);
|
|
||||||
|
|
||||||
/* Get the module id of tgate in Module manager */
|
|
||||||
ModuleId tgate_module_id = module_manager.find_module(circuit_lib.model_name(tgate_model));
|
|
||||||
VTR_ASSERT(ModuleId::INVALID() != tgate_module_id);
|
|
||||||
|
|
||||||
/* TODO: move to check_circuit_library? Get model ports of tgate */
|
|
||||||
std::vector<CircuitPortId> tgate_input_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true);
|
|
||||||
std::vector<CircuitPortId> tgate_output_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_OUTPUT, true);
|
|
||||||
VTR_ASSERT(3 == tgate_input_ports.size());
|
|
||||||
VTR_ASSERT(1 == tgate_output_ports.size());
|
|
||||||
|
|
||||||
/* Verilog Behavior description for a MUX */
|
|
||||||
print_verilog_comment(fp, std::string("---- Structure-level description -----"));
|
|
||||||
|
|
||||||
/* Output the netlist following the connections in mux_graph */
|
|
||||||
/* Iterate over the inputs */
|
|
||||||
for (const auto& mux_input : mux_graph.inputs()) {
|
|
||||||
BasicPort cur_input_port(input_port.get_name(), size_t(mux_graph.input_id(mux_input)), size_t(mux_graph.input_id(mux_input)));
|
|
||||||
/* Iterate over the outputs */
|
|
||||||
for (const auto& mux_output : mux_graph.outputs()) {
|
|
||||||
BasicPort cur_output_port(output_port.get_name(), size_t(mux_graph.output_id(mux_output)), size_t(mux_graph.output_id(mux_output)));
|
|
||||||
/* if there is a connection between the input and output, a tgate will be outputted */
|
|
||||||
std::vector<MuxEdgeId> edges = mux_graph.find_edges(mux_input, mux_output);
|
|
||||||
/* There should be only one edge or no edge*/
|
|
||||||
VTR_ASSERT((1 == edges.size()) || (0 == edges.size()));
|
|
||||||
/* No need to output tgates if there are no edges between two nodes */
|
|
||||||
if (0 == edges.size()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Output a tgate use a module manager */
|
|
||||||
/* Create a port-to-port name map */
|
|
||||||
std::map<std::string, BasicPort> port2port_name_map;
|
|
||||||
/* input port */
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_input_ports[0])] = cur_input_port;
|
|
||||||
/* output port */
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_output_ports[0])] = cur_output_port;
|
|
||||||
/* Find the mem_id controlling the edge */
|
|
||||||
MuxMemId mux_mem = mux_graph.find_edge_mem(edges[0]);
|
|
||||||
BasicPort cur_mem_port(mem_port.get_name(), size_t(mux_mem), size_t(mux_mem));
|
|
||||||
BasicPort cur_mem_inv_port(mem_inv_port.get_name(), size_t(mux_mem), size_t(mux_mem));
|
|
||||||
/* mem port */
|
|
||||||
if (false == mux_graph.is_edge_use_inv_mem(edges[0])) {
|
|
||||||
/* wire mem to mem of module, and wire mem_inv to mem_inv of module */
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_input_ports[1])] = cur_mem_port;
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_input_ports[2])] = cur_mem_inv_port;
|
|
||||||
} else {
|
|
||||||
/* wire mem_inv to mem of module, wire mem to mem_inv of module */
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_input_ports[1])] = cur_mem_inv_port;
|
|
||||||
port2port_name_map[circuit_lib.port_lib_name(tgate_input_ports[2])] = cur_mem_port;
|
|
||||||
}
|
|
||||||
/* Output an instance of the module */
|
|
||||||
print_verilog_module_instance(fp, module_manager, module_id, tgate_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(tgate_model));
|
|
||||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
|
||||||
* update the module manager with the relationship between the parent and child modules
|
|
||||||
*/
|
|
||||||
module_manager.add_child_module(module_id, tgate_module_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* Generate behavior-level Verilog codes modeling an branch circuit
|
* Generate behavior-level Verilog codes modeling an branch circuit
|
||||||
* for a multiplexer with the given size
|
* for a multiplexer with the given size
|
||||||
|
@ -186,15 +109,14 @@ void generate_verilog_cmos_mux_branch_body_behavioral(std::fstream& fp,
|
||||||
* Support structural and behavioral Verilog codes
|
* Support structural and behavioral Verilog codes
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
static
|
static
|
||||||
void generate_verilog_cmos_mux_branch_module(ModuleManager& module_manager,
|
void print_verilog_cmos_mux_branch_module_behavioral(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
std::fstream& fp,
|
std::fstream& fp,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& mux_model,
|
||||||
const std::string& module_name,
|
const std::string& module_name,
|
||||||
const MuxGraph& mux_graph,
|
const MuxGraph& mux_graph) {
|
||||||
const bool& use_structural_verilog) {
|
|
||||||
/* Get the tgate model */
|
/* Get the tgate model */
|
||||||
CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(circuit_model);
|
CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(mux_model);
|
||||||
|
|
||||||
/* Skip output if the tgate model is a MUX2, it is handled by essential-gate generator */
|
/* Skip output if the tgate model is a MUX2, it is handled by essential-gate generator */
|
||||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
|
if (SPICE_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
|
||||||
|
@ -202,8 +124,6 @@ void generate_verilog_cmos_mux_branch_module(ModuleManager& module_manager,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CircuitPortId> tgate_global_ports = circuit_lib.model_global_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true, true);
|
|
||||||
|
|
||||||
/* Make sure we have a valid file handler*/
|
/* Make sure we have a valid file handler*/
|
||||||
check_file_handler(fp);
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
@ -222,51 +142,27 @@ void generate_verilog_cmos_mux_branch_module(ModuleManager& module_manager,
|
||||||
VTR_ASSERT(1 == mux_graph.num_levels());
|
VTR_ASSERT(1 == mux_graph.num_levels());
|
||||||
|
|
||||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||||
ModuleId module_id = module_manager.add_module(module_name);
|
ModuleId mux_module = module_manager.find_module(module_name);
|
||||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
VTR_ASSERT(true == module_manager.valid_module_id(mux_module));
|
||||||
/* Add module ports */
|
/* Find module ports */
|
||||||
/* Add each global port */
|
/* Find each input port */
|
||||||
for (const auto& port : tgate_global_ports) {
|
|
||||||
/* Configure each global port */
|
|
||||||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
|
||||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
|
||||||
}
|
|
||||||
/* Add each input port */
|
|
||||||
BasicPort input_port("in", num_inputs);
|
BasicPort input_port("in", num_inputs);
|
||||||
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
/* Find each output port */
|
||||||
/* Add each output port */
|
|
||||||
BasicPort output_port("out", num_outputs);
|
BasicPort output_port("out", num_outputs);
|
||||||
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
/* Find each memory port */
|
||||||
/* Add each memory port */
|
|
||||||
BasicPort mem_port("mem", num_mems);
|
BasicPort mem_port("mem", num_mems);
|
||||||
module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
BasicPort mem_inv_port("mem_inv", num_mems);
|
|
||||||
module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
|
|
||||||
/* dump module definition + ports */
|
/* dump module definition + ports */
|
||||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
print_verilog_module_declaration(fp, module_manager, mux_module);
|
||||||
|
|
||||||
/* Print the internal logic in either structural or behavioral Verilog codes */
|
/* Print the internal logic in behavioral Verilog codes */
|
||||||
if (true == use_structural_verilog) {
|
|
||||||
generate_verilog_cmos_mux_branch_body_structural(module_manager, circuit_lib, fp, tgate_model, module_id, input_port, output_port, mem_port, mem_inv_port, mux_graph);
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT_SAFE(false == use_structural_verilog);
|
|
||||||
/* Get the default value of SRAM ports */
|
/* Get the default value of SRAM ports */
|
||||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
|
std::vector<CircuitPortId> regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, mux_model);
|
||||||
std::vector<CircuitPortId> non_mode_select_sram_ports;
|
VTR_ASSERT(1 == regular_sram_ports.size());
|
||||||
/* We should have only have 1 sram port except those are mode_bits */
|
std::string mem_default_val = std::to_string(circuit_lib.port_default_value(regular_sram_ports[0]));
|
||||||
for (const auto& port : sram_ports) {
|
|
||||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
non_mode_select_sram_ports.push_back(port);
|
|
||||||
}
|
|
||||||
VTR_ASSERT(1 == non_mode_select_sram_ports.size());
|
|
||||||
std::string mem_default_val = std::to_string(circuit_lib.port_default_value(non_mode_select_sram_ports[0]));
|
|
||||||
/* Mem string must be only 1-bit! */
|
/* Mem string must be only 1-bit! */
|
||||||
VTR_ASSERT(1 == mem_default_val.length());
|
VTR_ASSERT(1 == mem_default_val.length());
|
||||||
generate_verilog_cmos_mux_branch_body_behavioral(fp, input_port, output_port, mem_port, mux_graph, mem_default_val[0]);
|
generate_verilog_cmos_mux_branch_body_behavioral(fp, input_port, output_port, mem_port, mux_graph, mem_default_val[0]);
|
||||||
}
|
|
||||||
|
|
||||||
/* Put an end to the Verilog module */
|
/* Put an end to the Verilog module */
|
||||||
print_verilog_module_end(fp, module_name);
|
print_verilog_module_end(fp, module_name);
|
||||||
|
@ -638,35 +534,22 @@ void generate_verilog_rram_mux_branch_module(ModuleManager& module_manager,
|
||||||
VTR_ASSERT(1 == mux_wl_ports.size());
|
VTR_ASSERT(1 == mux_wl_ports.size());
|
||||||
|
|
||||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||||
ModuleId module_id = module_manager.add_module(module_name);
|
ModuleId module_id = module_manager.find_module(module_name);
|
||||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
VTR_ASSERT(true == module_manager.valid_module_id(module_id));
|
||||||
|
|
||||||
/* Add module ports */
|
/* Find each input port */
|
||||||
/* Add each global programming enable/disable ports */
|
|
||||||
std::vector<CircuitPortId> prog_enable_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true, true);
|
|
||||||
for (const auto& port : prog_enable_ports) {
|
|
||||||
/* Configure each global port */
|
|
||||||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
|
||||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add each input port */
|
|
||||||
BasicPort input_port(circuit_lib.port_lib_name(mux_input_ports[0]), num_inputs);
|
BasicPort input_port(circuit_lib.port_lib_name(mux_input_ports[0]), num_inputs);
|
||||||
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
|
|
||||||
/* Add each output port */
|
/* Find each output port */
|
||||||
BasicPort output_port(circuit_lib.port_lib_name(mux_output_ports[0]), num_outputs);
|
BasicPort output_port(circuit_lib.port_lib_name(mux_output_ports[0]), num_outputs);
|
||||||
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
|
||||||
|
|
||||||
/* Add RRAM programming ports,
|
/* Find RRAM programming ports,
|
||||||
* RRAM MUXes require one more pair of BLB and WL
|
* RRAM MUXes require one more pair of BLB and WL
|
||||||
* to configure the memories. See schematic for details
|
* to configure the memories. See schematic for details
|
||||||
*/
|
*/
|
||||||
BasicPort blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), num_mems + 1);
|
BasicPort blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), num_mems + 1);
|
||||||
module_manager.add_port(module_id, blb_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
|
|
||||||
BasicPort wl_port(circuit_lib.port_lib_name(mux_wl_ports[0]), num_mems + 1);
|
BasicPort wl_port(circuit_lib.port_lib_name(mux_wl_ports[0]), num_mems + 1);
|
||||||
module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
|
|
||||||
/* dump module definition + ports */
|
/* dump module definition + ports */
|
||||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||||
|
@ -690,442 +573,38 @@ static
|
||||||
void generate_verilog_mux_branch_module(ModuleManager& module_manager,
|
void generate_verilog_mux_branch_module(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
std::fstream& fp,
|
std::fstream& fp,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& mux_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
const MuxGraph& mux_graph) {
|
const MuxGraph& mux_graph) {
|
||||||
std::string module_name = generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
|
std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
|
||||||
|
|
||||||
/* Multiplexers built with different technology is in different organization */
|
/* Multiplexers built with different technology is in different organization */
|
||||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||||
case SPICE_MODEL_DESIGN_CMOS:
|
case SPICE_MODEL_DESIGN_CMOS:
|
||||||
generate_verilog_cmos_mux_branch_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph,
|
if (true == circuit_lib.dump_structural_verilog(mux_model)) {
|
||||||
circuit_lib.dump_structural_verilog(circuit_model));
|
/* Structural verilog can be easily generated by module writer */
|
||||||
|
ModuleId mux_module = module_manager.find_module(module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(mux_module));
|
||||||
|
write_verilog_module_to_file(fp, module_manager, mux_module, circuit_lib.dump_explicit_port_map(mux_model));
|
||||||
|
/* Add an empty line as a splitter */
|
||||||
|
fp << std::endl;
|
||||||
|
} else {
|
||||||
|
/* Behavioral verilog requires customized generation */
|
||||||
|
print_verilog_cmos_mux_branch_module_behavioral(module_manager, circuit_lib, fp, mux_model, module_name, mux_graph);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SPICE_MODEL_DESIGN_RRAM:
|
case SPICE_MODEL_DESIGN_RRAM:
|
||||||
generate_verilog_rram_mux_branch_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph,
|
generate_verilog_rram_mux_branch_module(module_manager, circuit_lib, fp, mux_model, module_name, mux_graph,
|
||||||
circuit_lib.dump_structural_verilog(circuit_model));
|
circuit_lib.dump_structural_verilog(mux_model));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vpr_printf(TIO_MESSAGE_ERROR,
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
|
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
|
||||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* Generate the standard-cell-based internal logic (multiplexing structure)
|
|
||||||
* for a multiplexer or LUT in Verilog codes
|
|
||||||
* This function will :
|
|
||||||
* 1. build a multiplexing structure by instanciating standard cells MUX2
|
|
||||||
* 2. add intermediate buffers between multiplexing stages if specified.
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager& module_manager,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
std::fstream& fp,
|
|
||||||
const ModuleId& module_id,
|
|
||||||
const CircuitModelId& circuit_model,
|
|
||||||
const CircuitModelId& std_cell_model,
|
|
||||||
const MuxGraph& mux_graph) {
|
|
||||||
/* Make sure we have a valid file handler*/
|
|
||||||
check_file_handler(fp);
|
|
||||||
|
|
||||||
/* TODO: these are duplicated codes, find a way to simplify it!!!
|
|
||||||
* Get the regular (non-mode-select) sram ports from the mux
|
|
||||||
*/
|
|
||||||
std::vector<CircuitPortId> mux_regular_sram_ports;
|
|
||||||
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true)) {
|
|
||||||
/* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
|
|
||||||
* Here we just bypass it.
|
|
||||||
*/
|
|
||||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mux_regular_sram_ports.push_back(port);
|
|
||||||
}
|
|
||||||
VTR_ASSERT(1 == mux_regular_sram_ports.size());
|
|
||||||
|
|
||||||
/* Find the input ports and output ports of the standard cell */
|
|
||||||
std::vector<CircuitPortId> std_cell_input_ports = circuit_lib.model_ports_by_type(std_cell_model, SPICE_MODEL_PORT_INPUT, true);
|
|
||||||
std::vector<CircuitPortId> std_cell_output_ports = circuit_lib.model_ports_by_type(std_cell_model, SPICE_MODEL_PORT_OUTPUT, true);
|
|
||||||
/* Quick check the requirements on port map */
|
|
||||||
VTR_ASSERT(3 == std_cell_input_ports.size());
|
|
||||||
VTR_ASSERT(1 == std_cell_output_ports.size());
|
|
||||||
|
|
||||||
/* Build the location map of intermediate buffers */
|
|
||||||
std::vector<bool> inter_buffer_location_map = build_mux_intermediate_buffer_location_map(circuit_lib, circuit_model, mux_graph.num_node_levels());
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Internal Logic of a CMOS MUX module based on Standard Cells -----"));
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Internal wires of a CMOS MUX module -----"));
|
|
||||||
/* Print local wires which are the nodes in the mux graph */
|
|
||||||
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
|
|
||||||
/* Print the internal wires located at this level */
|
|
||||||
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
|
|
||||||
/* Identify if an intermediate buffer is needed */
|
|
||||||
if (false == inter_buffer_location_map[level]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
|
|
||||||
}
|
|
||||||
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
|
|
||||||
/* Iterate over all the internal nodes and output nodes in the mux graph */
|
|
||||||
for (const auto& node : mux_graph.non_input_nodes()) {
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of a branch CMOS MUX modules -----"));
|
|
||||||
/* Get the size of branch circuit
|
|
||||||
* Instanciate an branch circuit by the size (fan-in) of the node
|
|
||||||
*/
|
|
||||||
size_t branch_size = mux_graph.node_in_edges(node).size();
|
|
||||||
|
|
||||||
/* Get the nodes which drive the root_node */
|
|
||||||
std::vector<MuxNodeId> input_nodes;
|
|
||||||
for (const auto& edge : mux_graph.node_in_edges(node)) {
|
|
||||||
/* Get the nodes drive the edge */
|
|
||||||
for (const auto& src_node : mux_graph.edge_src_nodes(edge)) {
|
|
||||||
input_nodes.push_back(src_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Number of inputs should match the branch_input_size!!! */
|
|
||||||
VTR_ASSERT(input_nodes.size() == branch_size);
|
|
||||||
|
|
||||||
/* Get the node level and index in the current level */
|
|
||||||
size_t output_node_level = mux_graph.node_level(node);
|
|
||||||
size_t output_node_index_at_level = mux_graph.node_index_at_level(node);
|
|
||||||
|
|
||||||
/* Get the mems in the branch circuits */
|
|
||||||
std::vector<MuxMemId> mems;
|
|
||||||
for (const auto& edge : mux_graph.node_in_edges(node)) {
|
|
||||||
/* Get the mem control the edge */
|
|
||||||
MuxMemId mem = mux_graph.find_edge_mem(edge);
|
|
||||||
/* Add the mem if it is not in the list */
|
|
||||||
if (mems.end() == std::find(mems.begin(), mems.end(), mem)) {
|
|
||||||
mems.push_back(mem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Instanciate the branch module, which is a standard cell MUX2
|
|
||||||
* We follow a fixed port map:
|
|
||||||
* TODO: the port map could be more flexible?
|
|
||||||
* input_port[0] of MUX2 standard cell is wired to input_node[0]
|
|
||||||
* input_port[1] of MUX2 standard cell is wired to input_node[1]
|
|
||||||
* output_port[0] of MUX2 standard cell is wired to output_node[0]
|
|
||||||
* input_port[2] of MUX2 standard cell is wired to mem_node[0]
|
|
||||||
*/
|
|
||||||
std::string branch_module_name= circuit_lib.model_name(std_cell_model);
|
|
||||||
/* Get the moduleId for the submodule */
|
|
||||||
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
|
|
||||||
/* We must have one */
|
|
||||||
VTR_ASSERT(ModuleId::INVALID() != branch_module_id);
|
|
||||||
|
|
||||||
/* Create a port-to-port map */
|
|
||||||
std::map<std::string, BasicPort> port2port_name_map;
|
|
||||||
|
|
||||||
/* To match the standard cell MUX2: We should have only 2 input_nodes */
|
|
||||||
VTR_ASSERT(2 == input_nodes.size());
|
|
||||||
/* Build the link between input_node[0] and std_cell_input_port[0]
|
|
||||||
* Build the link between input_node[1] and std_cell_input_port[1]
|
|
||||||
*/
|
|
||||||
for (const auto& input_node : input_nodes) {
|
|
||||||
/* Generate the port info of each input node */
|
|
||||||
size_t input_node_level = mux_graph.node_level(input_node);
|
|
||||||
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
|
|
||||||
BasicPort instance_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
|
||||||
|
|
||||||
/* Link nodes to input ports for the branch module */
|
|
||||||
std::string module_input_port_name = circuit_lib.port_lib_name(std_cell_input_ports[&input_node - &input_nodes[0]]);
|
|
||||||
port2port_name_map[module_input_port_name] = instance_input_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build the link between output_node[0] and std_cell_output_port[0] */
|
|
||||||
{ /* Create a code block to accommodate the local variables */
|
|
||||||
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
std::string module_output_port_name = circuit_lib.port_lib_name(std_cell_output_ports[0]);
|
|
||||||
port2port_name_map[module_output_port_name] = instance_output_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To match the standard cell MUX2: We should have only 1 mem_node */
|
|
||||||
VTR_ASSERT(1 == mems.size());
|
|
||||||
/* Build the link between mem_node[0] and std_cell_intput_port[2] */
|
|
||||||
for (const auto& mem : mems) {
|
|
||||||
/* Generate the port info of each mem node */
|
|
||||||
BasicPort instance_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
|
|
||||||
std::string module_mem_port_name = circuit_lib.port_lib_name(std_cell_input_ports[2]);
|
|
||||||
/* If use local decoders, we should use another name for the mem port */
|
|
||||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
|
||||||
instance_mem_port.set_name(generate_mux_local_decoder_data_port_name());
|
|
||||||
}
|
|
||||||
port2port_name_map[module_mem_port_name] = instance_mem_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output an instance of the module */
|
|
||||||
print_verilog_module_instance(fp, module_manager, module_id, branch_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(std_cell_model));
|
|
||||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
|
||||||
* update the module manager with the relationship between the parent and child modules
|
|
||||||
*/
|
|
||||||
module_manager.add_child_module(module_id, branch_module_id);
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Instanciation of a branch CMOS MUX modules -----"));
|
|
||||||
|
|
||||||
if (false == inter_buffer_location_map[output_node_level]) {
|
|
||||||
continue; /* No need for intermediate buffers */
|
|
||||||
}
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of a intermediate buffer modules -----"));
|
|
||||||
|
|
||||||
/* Now we need to add intermediate buffers by instanciating the modules */
|
|
||||||
CircuitModelId buffer_model = circuit_lib.lut_intermediate_buffer_model(circuit_model);
|
|
||||||
/* We must have a valid model id */
|
|
||||||
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
|
|
||||||
|
|
||||||
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
|
|
||||||
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Instanciation of a intermediate buffer modules -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Internal Logic of a CMOS MUX module based on Standard Cells -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* Generate the pass-transistor/transmission-gate -based internal logic
|
|
||||||
* (multiplexing structure) for a multiplexer or LUT in Verilog codes
|
|
||||||
* This function will :
|
|
||||||
* 1. build a multiplexing structure by instanciating the branch circuits
|
|
||||||
* generated before
|
|
||||||
* 2. add intermediate buffers between multiplexing stages if specified.
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager& module_manager,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
std::fstream& fp,
|
|
||||||
const ModuleId& module_id,
|
|
||||||
const CircuitModelId& circuit_model,
|
|
||||||
const MuxGraph& mux_graph) {
|
|
||||||
/* Make sure we have a valid file handler*/
|
|
||||||
check_file_handler(fp);
|
|
||||||
|
|
||||||
/* Find the actual mux size */
|
|
||||||
size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs());
|
|
||||||
|
|
||||||
/* Get the regular (non-mode-select) sram ports from the mux */
|
|
||||||
std::vector<CircuitPortId> mux_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model);
|
|
||||||
VTR_ASSERT(1 == mux_regular_sram_ports.size());
|
|
||||||
|
|
||||||
/* Build the location map of intermediate buffers */
|
|
||||||
std::vector<bool> inter_buffer_location_map = build_mux_intermediate_buffer_location_map(circuit_lib, circuit_model, mux_graph.num_node_levels());
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Internal Logic of a CMOS MUX module based on Pass-transistor/Transmission-gates -----"));
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Internal wires of a CMOS MUX module -----"));
|
|
||||||
/* Print local wires which are the nodes in the mux graph */
|
|
||||||
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
|
|
||||||
/* Print the internal wires located at this level */
|
|
||||||
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
|
|
||||||
/* Identify if an intermediate buffer is needed */
|
|
||||||
if (false == inter_buffer_location_map[level]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
|
|
||||||
}
|
|
||||||
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
|
|
||||||
/* Iterate over all the internal nodes and output nodes in the mux graph */
|
|
||||||
for (const auto& node : mux_graph.non_input_nodes()) {
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of a branch CMOS MUX module -----"));
|
|
||||||
/* Get the size of branch circuit
|
|
||||||
* Instanciate an branch circuit by the size (fan-in) of the node
|
|
||||||
*/
|
|
||||||
size_t branch_size = mux_graph.node_in_edges(node).size();
|
|
||||||
|
|
||||||
/* Get the node level and index in the current level */
|
|
||||||
size_t output_node_level = mux_graph.node_level(node);
|
|
||||||
size_t output_node_index_at_level = mux_graph.node_index_at_level(node);
|
|
||||||
|
|
||||||
/* Get the nodes which drive the root_node */
|
|
||||||
std::vector<MuxNodeId> input_nodes;
|
|
||||||
for (const auto& edge : mux_graph.node_in_edges(node)) {
|
|
||||||
/* Get the nodes drive the edge */
|
|
||||||
for (const auto& src_node : mux_graph.edge_src_nodes(edge)) {
|
|
||||||
input_nodes.push_back(src_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Number of inputs should match the branch_input_size!!! */
|
|
||||||
VTR_ASSERT(input_nodes.size() == branch_size);
|
|
||||||
|
|
||||||
/* Get the mems in the branch circuits */
|
|
||||||
std::vector<MuxMemId> mems;
|
|
||||||
for (const auto& edge : mux_graph.node_in_edges(node)) {
|
|
||||||
/* Get the mem control the edge */
|
|
||||||
MuxMemId mem = mux_graph.find_edge_mem(edge);
|
|
||||||
/* Add the mem if it is not in the list */
|
|
||||||
if (mems.end() == std::find(mems.begin(), mems.end(), mem)) {
|
|
||||||
mems.push_back(mem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Instanciate the branch module which is a tgate-based module
|
|
||||||
*/
|
|
||||||
std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
|
|
||||||
/* Get the moduleId for the submodule */
|
|
||||||
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
|
|
||||||
/* We must have one */
|
|
||||||
VTR_ASSERT(ModuleId::INVALID() != branch_module_id);
|
|
||||||
|
|
||||||
/* Create a port-to-port map */
|
|
||||||
std::map<std::string, BasicPort> port2port_name_map;
|
|
||||||
/* TODO: the branch module name should NOT be hard-coded. Use the port lib_name given by users! */
|
|
||||||
|
|
||||||
/* All the input node names organized in bus */
|
|
||||||
std::vector<BasicPort> branch_node_input_ports;
|
|
||||||
for (const auto& input_node : input_nodes) {
|
|
||||||
/* Generate the port info of each input node */
|
|
||||||
size_t input_node_level = mux_graph.node_level(input_node);
|
|
||||||
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
|
|
||||||
BasicPort branch_node_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
|
||||||
branch_node_input_ports.push_back(branch_node_input_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the port info for the input */
|
|
||||||
/* TODO: the naming could be more flexible? */
|
|
||||||
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_mux_node_name(output_node_level, false) + "_in"));
|
|
||||||
/* If we have more than 1 port in the combined instance ports ,
|
|
||||||
* output a local wire */
|
|
||||||
if (1 < combine_verilog_ports(branch_node_input_ports).size()) {
|
|
||||||
/* Print a local wire for the merged ports */
|
|
||||||
fp << "\t" << generate_verilog_local_wire(instance_input_port, branch_node_input_ports) << std::endl;
|
|
||||||
} else {
|
|
||||||
/* Safety check */
|
|
||||||
VTR_ASSERT(1 == combine_verilog_ports(branch_node_input_ports).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link nodes to input ports for the branch module */
|
|
||||||
ModulePortId module_input_port_id = module_manager.find_module_port(branch_module_id, "in");
|
|
||||||
VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id);
|
|
||||||
/* Get the port from module */
|
|
||||||
BasicPort module_input_port = module_manager.module_port(branch_module_id, module_input_port_id);
|
|
||||||
port2port_name_map[module_input_port.get_name()] = instance_input_port;
|
|
||||||
|
|
||||||
/* Link nodes to output ports for the branch module */
|
|
||||||
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
|
|
||||||
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
|
|
||||||
/* Get the port from module */
|
|
||||||
BasicPort module_output_port = module_manager.module_port(branch_module_id, module_output_port_id);
|
|
||||||
port2port_name_map[module_output_port.get_name()] = instance_output_port;
|
|
||||||
|
|
||||||
/* All the mem node names organized in bus */
|
|
||||||
std::vector<BasicPort> branch_node_mem_ports;
|
|
||||||
for (const auto& mem : mems) {
|
|
||||||
/* Generate the port info of each mem node */
|
|
||||||
BasicPort branch_node_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
|
|
||||||
/* If use local decoders, we should use another name for the mem port */
|
|
||||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
|
||||||
branch_node_mem_port.set_name(generate_mux_local_decoder_data_port_name());
|
|
||||||
}
|
|
||||||
branch_node_mem_ports.push_back(branch_node_mem_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the port info for the input */
|
|
||||||
/* TODO: the naming could be more flexible? */
|
|
||||||
BasicPort instance_mem_port = generate_verilog_bus_port(branch_node_mem_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem"));
|
|
||||||
/* If we have more than 1 port in the combined instance ports ,
|
|
||||||
* output a local wire */
|
|
||||||
if (1 < combine_verilog_ports(branch_node_mem_ports).size()) {
|
|
||||||
/* Print a local wire for the merged ports */
|
|
||||||
fp << "\t" << generate_verilog_local_wire(instance_mem_port, branch_node_mem_ports) << std::endl;
|
|
||||||
} else {
|
|
||||||
/* Safety check */
|
|
||||||
VTR_ASSERT(1 == combine_verilog_ports(branch_node_mem_ports).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link nodes to input ports for the branch module */
|
|
||||||
/* TODO: the naming could be more flexible? */
|
|
||||||
ModulePortId module_mem_port_id = module_manager.find_module_port(branch_module_id, "mem");
|
|
||||||
VTR_ASSERT(ModulePortId::INVALID() != module_mem_port_id);
|
|
||||||
/* Get the port from module */
|
|
||||||
BasicPort module_mem_port = module_manager.module_port(branch_module_id, module_mem_port_id);
|
|
||||||
port2port_name_map[module_mem_port.get_name()] = instance_mem_port;
|
|
||||||
|
|
||||||
/* TODO: the postfix _inv can be soft coded in the circuit library as a port_inv_postfix */
|
|
||||||
/* Create the port info for the mem_inv */
|
|
||||||
std::vector<BasicPort> branch_node_mem_inv_ports;
|
|
||||||
for (const auto& mem : mems) {
|
|
||||||
/* Generate the port info of each mem node */
|
|
||||||
BasicPort branch_node_mem_inv_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]) + "_inv", size_t(mem), size_t(mem));
|
|
||||||
/* If use local decoders, we should use another name for the mem port */
|
|
||||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
|
||||||
branch_node_mem_inv_port.set_name(generate_mux_local_decoder_data_inv_port_name());
|
|
||||||
}
|
|
||||||
branch_node_mem_inv_ports.push_back(branch_node_mem_inv_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the port info for the input */
|
|
||||||
/* TODO: the naming could be more flexible? */
|
|
||||||
BasicPort instance_mem_inv_port = generate_verilog_bus_port(branch_node_mem_inv_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem_inv"));
|
|
||||||
/* If we have more than 1 port in the combined instance ports ,
|
|
||||||
* output a local wire */
|
|
||||||
if (1 < combine_verilog_ports(branch_node_mem_inv_ports).size()) {
|
|
||||||
/* Print a local wire for the merged ports */
|
|
||||||
fp << "\t" << generate_verilog_local_wire(instance_mem_port, branch_node_mem_inv_ports) << std::endl;
|
|
||||||
} else {
|
|
||||||
/* Safety check */
|
|
||||||
VTR_ASSERT(1 == combine_verilog_ports(branch_node_mem_inv_ports).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link nodes to input ports for the branch module */
|
|
||||||
/* TODO: the naming could be more flexible? */
|
|
||||||
ModulePortId module_mem_inv_port_id = module_manager.find_module_port(branch_module_id, "mem_inv");
|
|
||||||
VTR_ASSERT(ModulePortId::INVALID() != module_mem_inv_port_id);
|
|
||||||
/* Get the port from module */
|
|
||||||
BasicPort module_mem_inv_port = module_manager.module_port(branch_module_id, module_mem_inv_port_id);
|
|
||||||
port2port_name_map[module_mem_inv_port.get_name()] = instance_mem_inv_port;
|
|
||||||
|
|
||||||
/* Output an instance of the module */
|
|
||||||
print_verilog_module_instance(fp, module_manager, module_id, branch_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
|
|
||||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
|
||||||
* update the module manager with the relationship between the parent and child modules
|
|
||||||
*/
|
|
||||||
module_manager.add_child_module(module_id, branch_module_id);
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Instanciation of a branch CMOS MUX module -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
|
|
||||||
if (false == inter_buffer_location_map[output_node_level]) {
|
|
||||||
continue; /* No need for intermediate buffers */
|
|
||||||
}
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of an intermediate buffer modules -----"));
|
|
||||||
|
|
||||||
/* Now we need to add intermediate buffers by instanciating the modules */
|
|
||||||
CircuitModelId buffer_model = circuit_lib.lut_intermediate_buffer_model(circuit_model);
|
|
||||||
/* We must have a valid model id */
|
|
||||||
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
|
|
||||||
|
|
||||||
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
|
||||||
|
|
||||||
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Instanciation of an intermediate buffer module -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("---- END Internal Logic of a CMOS MUX module based on Pass-transistor/Transmission-gates -----"));
|
|
||||||
fp << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Generate the input bufferes for a multiplexer or LUT in Verilog codes
|
* Generate the input bufferes for a multiplexer or LUT in Verilog codes
|
||||||
* 1. If input are required to be buffered (specified by users),
|
* 1. If input are required to be buffered (specified by users),
|
||||||
|
@ -1297,196 +776,6 @@ void generate_verilog_cmos_mux_module_output_buffers(ModuleManager& module_manag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* Generate Verilog codes modeling a CMOS multiplexer with the given size
|
|
||||||
* The Verilog module will consist of three parts:
|
|
||||||
* 1. instances of the branch circuits of multiplexers which are generated before
|
|
||||||
* This builds up the multiplexing structure
|
|
||||||
* 2. Input buffers/inverters
|
|
||||||
* 3. Output buffers/inverters
|
|
||||||
*********************************************************************/
|
|
||||||
static
|
|
||||||
void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
std::fstream& fp,
|
|
||||||
const CircuitModelId& circuit_model,
|
|
||||||
const std::string& module_name,
|
|
||||||
const MuxGraph& mux_graph) {
|
|
||||||
/* Get the global ports required by MUX (and any submodules) */
|
|
||||||
std::vector<CircuitPortId> mux_global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true, true);
|
|
||||||
/* Get the input ports from the mux */
|
|
||||||
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
|
||||||
/* Get the output ports from the mux */
|
|
||||||
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
|
||||||
/* Get the sram ports from the mux
|
|
||||||
* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
|
|
||||||
* Here we just bypass it.
|
|
||||||
*/
|
|
||||||
std::vector<CircuitPortId> mux_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model);
|
|
||||||
|
|
||||||
/* Make sure we have a valid file handler*/
|
|
||||||
check_file_handler(fp);
|
|
||||||
|
|
||||||
/* Generate the Verilog netlist according to the mux_graph */
|
|
||||||
/* Find out the number of data-path inputs */
|
|
||||||
size_t num_inputs = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs());
|
|
||||||
/* Find out the number of outputs */
|
|
||||||
size_t num_outputs = mux_graph.num_outputs();
|
|
||||||
/* Find out the number of memory bits */
|
|
||||||
size_t num_mems = mux_graph.num_memory_bits();
|
|
||||||
|
|
||||||
/* The size of of memory ports depend on
|
|
||||||
* if a local encoder is used for the mux or not
|
|
||||||
* Multiplexer local encoders are applied to memory bits at each stage
|
|
||||||
*/
|
|
||||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
|
||||||
num_mems = 0;
|
|
||||||
for (const auto& lvl : mux_graph.levels()) {
|
|
||||||
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
|
|
||||||
num_mems += find_mux_local_decoder_addr_size(data_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check codes to ensure the port of Verilog netlists will match */
|
|
||||||
/* MUX graph must have only 1 output */
|
|
||||||
VTR_ASSERT(1 == mux_input_ports.size());
|
|
||||||
/* A quick check on the model ports */
|
|
||||||
if ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|
|
||||||
|| ((SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
|
||||||
&& (false == circuit_lib.is_lut_fracturable(circuit_model))) ) {
|
|
||||||
VTR_ASSERT(1 == mux_output_ports.size());
|
|
||||||
VTR_ASSERT(1 == circuit_lib.port_size(mux_output_ports[0]));
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT_SAFE( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
|
||||||
&& (true == circuit_lib.is_lut_fracturable(circuit_model)) );
|
|
||||||
for (const auto& port : mux_output_ports) {
|
|
||||||
VTR_ASSERT(0 < circuit_lib.port_size(port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
|
||||||
ModuleId module_id = module_manager.add_module(module_name);
|
|
||||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
|
||||||
/* Add module ports */
|
|
||||||
/* Add each global port */
|
|
||||||
for (const auto& port : mux_global_ports) {
|
|
||||||
/* Configure each global port */
|
|
||||||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
|
||||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
|
||||||
}
|
|
||||||
/* Add each input port
|
|
||||||
* Treat MUX and LUT differently
|
|
||||||
* 1. MUXes: we do not have a specific input/output sizes, it is inferred by architecture
|
|
||||||
* 2. LUTes: we do have specific input/output sizes,
|
|
||||||
* but the inputs of MUXes are the SRAM ports of LUTs
|
|
||||||
* and the SRAM ports of MUXes are the inputs of LUTs
|
|
||||||
*/
|
|
||||||
size_t input_port_cnt = 0;
|
|
||||||
for (const auto& port : mux_input_ports) {
|
|
||||||
BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs);
|
|
||||||
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
/* Update counter */
|
|
||||||
input_port_cnt++;
|
|
||||||
}
|
|
||||||
/* Double check: We should have only 1 input port generated here! */
|
|
||||||
VTR_ASSERT(1 == input_port_cnt);
|
|
||||||
|
|
||||||
for (const auto& port : mux_output_ports) {
|
|
||||||
BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs);
|
|
||||||
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
|
|
||||||
output_port.set_width(circuit_lib.port_size(port));
|
|
||||||
}
|
|
||||||
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sram_port_cnt = 0;
|
|
||||||
for (const auto& port : mux_sram_ports) {
|
|
||||||
BasicPort mem_port(circuit_lib.port_lib_name(port), num_mems);
|
|
||||||
module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), num_mems);
|
|
||||||
module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
|
|
||||||
/* Update counter */
|
|
||||||
sram_port_cnt++;
|
|
||||||
}
|
|
||||||
VTR_ASSERT(1 == sram_port_cnt);
|
|
||||||
|
|
||||||
/* dump module definition + ports */
|
|
||||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
|
||||||
|
|
||||||
/* Add local decoder instance here */
|
|
||||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
|
||||||
BasicPort decoder_data_port(generate_mux_local_decoder_data_port_name(), mux_graph.num_memory_bits());
|
|
||||||
BasicPort decoder_data_inv_port(generate_mux_local_decoder_data_inv_port_name(), mux_graph.num_memory_bits());
|
|
||||||
/* Print local wires to bridge the port of module and memory inputs
|
|
||||||
* of each MUX branch instance
|
|
||||||
*/
|
|
||||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_port) << ";" << std::endl;
|
|
||||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_inv_port) << ";" << std::endl;
|
|
||||||
|
|
||||||
/* Local port to record the LSB and MSB of each level, here, we deposite (0, 0) */
|
|
||||||
BasicPort lvl_addr_port(circuit_lib.port_lib_name(mux_sram_ports[0]), 0);
|
|
||||||
BasicPort lvl_data_port(decoder_data_port.get_name(), 0);
|
|
||||||
BasicPort lvl_data_inv_port(decoder_data_inv_port.get_name(), 0);
|
|
||||||
for (const auto& lvl : mux_graph.levels()) {
|
|
||||||
size_t addr_size = find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
|
|
||||||
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
|
|
||||||
/* Update the LSB and MSB of addr and data port for the current level */
|
|
||||||
lvl_addr_port.rotate(addr_size);
|
|
||||||
lvl_data_port.rotate(data_size);
|
|
||||||
lvl_data_inv_port.rotate(data_size);
|
|
||||||
/* Print the instance of local decoder */
|
|
||||||
std::string decoder_module_name = generate_mux_local_decoder_subckt_name(addr_size, data_size);
|
|
||||||
ModuleId decoder_module = module_manager.find_module(decoder_module_name);
|
|
||||||
VTR_ASSERT(ModuleId::INVALID() != decoder_module);
|
|
||||||
|
|
||||||
/* Create a port-to-port map */
|
|
||||||
std::map<std::string, BasicPort> decoder_port2port_name_map;
|
|
||||||
decoder_port2port_name_map[generate_mux_local_decoder_addr_port_name()] = lvl_addr_port;
|
|
||||||
decoder_port2port_name_map[generate_mux_local_decoder_data_port_name()] = lvl_data_port;
|
|
||||||
decoder_port2port_name_map[generate_mux_local_decoder_data_inv_port_name()] = lvl_data_inv_port;
|
|
||||||
|
|
||||||
/* Print an instance of the MUX Module */
|
|
||||||
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a local decoder -----"));
|
|
||||||
print_verilog_module_instance(fp, module_manager, module_id, decoder_module, decoder_port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
|
|
||||||
print_verilog_comment(fp, std::string("----- END Instanciation of a local decoder -----"));
|
|
||||||
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(module_id, decoder_module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print the internal logic in Verilog codes */
|
|
||||||
/* Print the Multiplexing structure in Verilog codes
|
|
||||||
* Separated generation strategy on using standard cell MUX2 or TGATE,
|
|
||||||
* 1. MUX2 has a fixed port map: input_port[0] and input_port[1] is the data_path input
|
|
||||||
* 2. Branch TGATE-based module has a fixed port name
|
|
||||||
* TODO: the naming could be more flexible?
|
|
||||||
*/
|
|
||||||
/* Get the tgate model */
|
|
||||||
CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(circuit_model);
|
|
||||||
/* Instanciate the branch module:
|
|
||||||
* Case 1: the branch module is a standard cell MUX2
|
|
||||||
* Case 2: the branch module is a tgate-based module
|
|
||||||
*/
|
|
||||||
std::string branch_module_name;
|
|
||||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
|
|
||||||
VTR_ASSERT(SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(tgate_model));
|
|
||||||
generate_verilog_cmos_mux_module_mux2_multiplexing_structure(module_manager, circuit_lib, fp, module_id, circuit_model, tgate_model, mux_graph);
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT(SPICE_MODEL_PASSGATE == circuit_lib.model_type(tgate_model));
|
|
||||||
generate_verilog_cmos_mux_module_tgate_multiplexing_structure(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print the input and output buffers in Verilog codes */
|
|
||||||
generate_verilog_cmos_mux_module_input_buffers(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
|
|
||||||
generate_verilog_cmos_mux_module_output_buffers(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
|
|
||||||
|
|
||||||
/* Put an end to the Verilog module */
|
|
||||||
print_verilog_module_end(fp, module_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Generate the 4T1R-based internal logic
|
* Generate the 4T1R-based internal logic
|
||||||
* (multiplexing structure) for a multiplexer in Verilog codes
|
* (multiplexing structure) for a multiplexer in Verilog codes
|
||||||
|
@ -1880,26 +1169,31 @@ static
|
||||||
void generate_verilog_mux_module(ModuleManager& module_manager,
|
void generate_verilog_mux_module(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
std::fstream& fp,
|
std::fstream& fp,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& mux_model,
|
||||||
const MuxGraph& mux_graph) {
|
const MuxGraph& mux_graph) {
|
||||||
std::string module_name = generate_mux_subckt_name(circuit_lib, circuit_model,
|
std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model,
|
||||||
find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()),
|
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
|
||||||
std::string(""));
|
std::string(""));
|
||||||
|
|
||||||
/* Multiplexers built with different technology is in different organization */
|
/* Multiplexers built with different technology is in different organization */
|
||||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||||
case SPICE_MODEL_DESIGN_CMOS:
|
case SPICE_MODEL_DESIGN_CMOS: {
|
||||||
/* SRAM-based Multiplexer Verilog module generation */
|
/* Use Verilog writer to print the module to file */
|
||||||
generate_verilog_cmos_mux_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph);
|
ModuleId mux_module = module_manager.find_module(module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(mux_module));
|
||||||
|
write_verilog_module_to_file(fp, module_manager, mux_module, circuit_lib.dump_explicit_port_map(mux_model));
|
||||||
|
/* Add an empty line as a splitter */
|
||||||
|
fp << std::endl;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SPICE_MODEL_DESIGN_RRAM:
|
case SPICE_MODEL_DESIGN_RRAM:
|
||||||
/* TODO: RRAM-based Multiplexer Verilog module generation */
|
/* TODO: RRAM-based Multiplexer Verilog module generation */
|
||||||
generate_verilog_rram_mux_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph);
|
generate_verilog_rram_mux_module(module_manager, circuit_lib, fp, mux_model, module_name, mux_graph);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vpr_printf(TIO_MESSAGE_ERROR,
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
|
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
|
||||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue