add frac_lut outputs to mux_graph generation
This commit is contained in:
parent
b6bb433edc
commit
fde9c8b4ec
|
@ -662,6 +662,20 @@ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
||||||
return port_is_prog_[circuit_port_id];
|
return port_is_prog_[circuit_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return which level the output port locates at a LUT multiplexing structure */
|
||||||
|
size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id) const {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
return port_lut_frac_level_[circuit_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return indices of internal nodes in a LUT multiplexing structure to which the output port is wired to */
|
||||||
|
std::vector<size_t> CircuitLibrary::port_lut_output_masks(const CircuitPortId& circuit_port_id) const {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
return port_lut_output_masks_[circuit_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the id of parent circuit model for a circuit port */
|
/* Return the id of parent circuit model for a circuit port */
|
||||||
CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const {
|
CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const {
|
||||||
/* validate the circuit_port_id */
|
/* validate the circuit_port_id */
|
||||||
|
|
|
@ -270,6 +270,8 @@ class CircuitLibrary {
|
||||||
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
||||||
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
||||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||||
|
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
||||||
|
std::vector<size_t> port_lut_output_masks(const CircuitPortId& circuit_port_id) const;
|
||||||
CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const;
|
CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const;
|
||||||
std::string model_name(const CircuitPortId& port_id) const;
|
std::string model_name(const CircuitPortId& port_id) const;
|
||||||
public: /* Public Accessors: Timing graph */
|
public: /* Public Accessors: Timing graph */
|
||||||
|
|
|
@ -203,6 +203,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
||||||
/* Add output nodes to subgraph */
|
/* Add output nodes to subgraph */
|
||||||
MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE);
|
MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE);
|
||||||
mux_graph.node_levels_[to_node_subgraph] = 1;
|
mux_graph.node_levels_[to_node_subgraph] = 1;
|
||||||
|
mux_graph.node_ids_at_level_[to_node_subgraph] = 0;
|
||||||
mux_graph.node_output_ids_[to_node_subgraph] = MuxOutputId(0);
|
mux_graph.node_output_ids_[to_node_subgraph] = MuxOutputId(0);
|
||||||
/* Update the node-to-node map */
|
/* Update the node-to-node map */
|
||||||
node2node_map[root_node] = to_node_subgraph;
|
node2node_map[root_node] = to_node_subgraph;
|
||||||
|
@ -216,6 +217,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
||||||
MuxNodeId from_node_subgraph = mux_graph.add_node(MUX_INPUT_NODE);
|
MuxNodeId from_node_subgraph = mux_graph.add_node(MUX_INPUT_NODE);
|
||||||
/* Configure the nodes */
|
/* Configure the nodes */
|
||||||
mux_graph.node_levels_[from_node_subgraph] = 0;
|
mux_graph.node_levels_[from_node_subgraph] = 0;
|
||||||
|
mux_graph.node_ids_at_level_[from_node_subgraph] = input_cnt;
|
||||||
mux_graph.node_input_ids_[from_node_subgraph] = MuxInputId(input_cnt);
|
mux_graph.node_input_ids_[from_node_subgraph] = MuxInputId(input_cnt);
|
||||||
input_cnt++;
|
input_cnt++;
|
||||||
/* Update the node-to-node map */
|
/* Update the node-to-node map */
|
||||||
|
@ -385,6 +387,7 @@ MuxNodeId MuxGraph::add_node(const enum e_mux_graph_node_type& node_type) {
|
||||||
node_input_ids_.push_back(MuxInputId::INVALID());
|
node_input_ids_.push_back(MuxInputId::INVALID());
|
||||||
node_output_ids_.push_back(MuxOutputId::INVALID());
|
node_output_ids_.push_back(MuxOutputId::INVALID());
|
||||||
node_levels_.push_back(-1);
|
node_levels_.push_back(-1);
|
||||||
|
node_ids_at_level_.push_back(-1);
|
||||||
node_in_edges_.emplace_back();
|
node_in_edges_.emplace_back();
|
||||||
node_out_edges_.emplace_back();
|
node_out_edges_.emplace_back();
|
||||||
|
|
||||||
|
@ -523,6 +526,7 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
||||||
* Last level should expand from output_node
|
* Last level should expand from output_node
|
||||||
* Other levels will expand from internal nodes!
|
* Other levels will expand from internal nodes!
|
||||||
*/
|
*/
|
||||||
|
size_t node_cnt_per_level = 0; /* A counter to record node indices at each level */
|
||||||
for (MuxNodeId seed_node : node_lookup[lvl + 1]) {
|
for (MuxNodeId seed_node : node_lookup[lvl + 1]) {
|
||||||
/* Add a new node and connect to seed_node, until we reach the num_inputs_per_branch */
|
/* Add a new node and connect to seed_node, until we reach the num_inputs_per_branch */
|
||||||
for (size_t i = 0; i < num_inputs_per_branch; ++i) {
|
for (size_t i = 0; i < num_inputs_per_branch; ++i) {
|
||||||
|
@ -533,6 +537,9 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
||||||
|
|
||||||
/* Node level is deterministic */
|
/* Node level is deterministic */
|
||||||
node_levels_[expand_node] = lvl;
|
node_levels_[expand_node] = lvl;
|
||||||
|
node_ids_at_level_[expand_node] = node_cnt_per_level;
|
||||||
|
/* update level node counter */
|
||||||
|
node_cnt_per_level++;
|
||||||
|
|
||||||
/* Create an edge and connect the two nodes */
|
/* Create an edge and connect the two nodes */
|
||||||
MuxEdgeId edge = add_edge(expand_node, seed_node);
|
MuxEdgeId edge = add_edge(expand_node, seed_node);
|
||||||
|
@ -624,6 +631,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
||||||
*/
|
*/
|
||||||
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
||||||
node_levels_[output_node] = 1;
|
node_levels_[output_node] = 1;
|
||||||
|
node_ids_at_level_[output_node] = 0;
|
||||||
node_output_ids_[output_node] = MuxOutputId(0);
|
node_output_ids_[output_node] = MuxOutputId(0);
|
||||||
|
|
||||||
for (size_t i = 0; i < mux_size; ++i) {
|
for (size_t i = 0; i < mux_size; ++i) {
|
||||||
|
@ -631,6 +639,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
||||||
/* All the node belong to level 0 (we have only 1 level) */
|
/* All the node belong to level 0 (we have only 1 level) */
|
||||||
node_input_ids_[input_node] = MuxInputId(i);
|
node_input_ids_[input_node] = MuxInputId(i);
|
||||||
node_levels_[input_node] = 0;
|
node_levels_[input_node] = 0;
|
||||||
|
node_ids_at_level_[input_node] = i;
|
||||||
|
|
||||||
/* We definitely know how many edges we need,
|
/* We definitely know how many edges we need,
|
||||||
* the same as mux_size, add a edge connecting two nodes
|
* the same as mux_size, add a edge connecting two nodes
|
||||||
|
@ -647,6 +656,64 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
||||||
/* Finish building the graph for a one-level multiplexer */
|
/* Finish building the graph for a one-level multiplexer */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert some internal nodes to be additional outputs
|
||||||
|
* according to the fracturable LUT port definition
|
||||||
|
* We will iterate over each output port of a circuit model
|
||||||
|
* and find the frac_level and output_mask
|
||||||
|
* Then, the internal nodes at the frac_level will be converted
|
||||||
|
* to output nodes with a given output_mask
|
||||||
|
*/
|
||||||
|
void MuxGraph::add_fracturable_outputs(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model) {
|
||||||
|
/* Iterate over output ports */
|
||||||
|
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true)) {
|
||||||
|
/* Get the fracturable_level */
|
||||||
|
size_t frac_level = circuit_lib.port_lut_frac_level(port);
|
||||||
|
/* Bypass invalid frac_level */
|
||||||
|
if (size_t(-1) == frac_level) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Iterate over output masks */
|
||||||
|
for (const auto& output_idx : circuit_lib.port_lut_output_masks(port)) {
|
||||||
|
size_t num_matched_nodes = 0;
|
||||||
|
/* Iterate over node and find the internal nodes, which match the frac_level and output_idx */
|
||||||
|
for (const auto& node : node_lookup_[frac_level][MUX_INTERNAL_NODE]) {
|
||||||
|
if (node_ids_at_level_[node] != output_idx) {
|
||||||
|
/* Bypass condition */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Reach here, this is the node we want
|
||||||
|
* Convert it to output nodes and update the counter
|
||||||
|
*/
|
||||||
|
node_types_[node] = MUX_OUTPUT_NODE;
|
||||||
|
node_output_ids_[node] = MuxOutputId(num_outputs());
|
||||||
|
num_matched_nodes++;
|
||||||
|
}
|
||||||
|
/* Either find 1 or 0 matched nodes */
|
||||||
|
if (0 != num_matched_nodes) {
|
||||||
|
/* We should find only one node that matches! */
|
||||||
|
VTR_ASSERT(1 == num_matched_nodes);
|
||||||
|
/* Rebuild the node look-up */
|
||||||
|
build_node_lookup();
|
||||||
|
continue; /* Finish here, go to next */
|
||||||
|
}
|
||||||
|
/* Sometime the wanted node is already an output, do a double check */
|
||||||
|
for (const auto& node : node_lookup_[frac_level][MUX_OUTPUT_NODE]) {
|
||||||
|
if (node_ids_at_level_[node] != output_idx) {
|
||||||
|
/* Bypass condition */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Reach here, this is the node we want
|
||||||
|
* Just update the counter
|
||||||
|
*/
|
||||||
|
num_matched_nodes++;
|
||||||
|
}
|
||||||
|
/* We should find only one node that matches! */
|
||||||
|
VTR_ASSERT(1 == num_matched_nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Build the graph for a given multiplexer model */
|
/* Build the graph for a given multiplexer model */
|
||||||
void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
|
@ -699,6 +766,12 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||||
|
|
||||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||||
build_node_lookup();
|
build_node_lookup();
|
||||||
|
|
||||||
|
/* For fracturable LUTs, we need to add more outputs to the MUX graph */
|
||||||
|
if ( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
||||||
|
&& (true == circuit_lib.is_lut_fracturable(circuit_model)) ) {
|
||||||
|
add_fracturable_outputs(circuit_lib, circuit_model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build fast node lookup */
|
/* Build fast node lookup */
|
||||||
|
|
|
@ -110,6 +110,9 @@ class MuxGraph {
|
||||||
void build_mux_graph(const CircuitLibrary& circuit_lib,
|
void build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const size_t& mux_size);
|
const size_t& mux_size);
|
||||||
|
/* Convert some internal node to outputs according to fracturable LUT circuit design specifications */
|
||||||
|
void add_fracturable_outputs(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model);
|
||||||
/* Build fast node lookup */
|
/* Build fast node lookup */
|
||||||
void build_node_lookup();
|
void build_node_lookup();
|
||||||
private: /* Private validators */
|
private: /* Private validators */
|
||||||
|
@ -130,6 +133,7 @@ class MuxGraph {
|
||||||
vtr::vector<MuxNodeId, MuxInputId> node_input_ids_; /* Unique ids for each node as an input of the MUX */
|
vtr::vector<MuxNodeId, MuxInputId> node_input_ids_; /* Unique ids for each node as an input of the MUX */
|
||||||
vtr::vector<MuxNodeId, MuxOutputId> node_output_ids_; /* Unique ids for each node as an input of the MUX */
|
vtr::vector<MuxNodeId, MuxOutputId> node_output_ids_; /* Unique ids for each node as an input of the MUX */
|
||||||
vtr::vector<MuxNodeId, size_t> node_levels_; /* at which level, each node belongs to */
|
vtr::vector<MuxNodeId, size_t> node_levels_; /* at which level, each node belongs to */
|
||||||
|
vtr::vector<MuxNodeId, size_t> node_ids_at_level_; /* the index at the level that each node belongs to */
|
||||||
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_in_edges_; /* ids of incoming edges to each node */
|
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_in_edges_; /* ids of incoming edges to each node */
|
||||||
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_out_edges_; /* ids of outgoing edges from each node */
|
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_out_edges_; /* ids of outgoing edges from each node */
|
||||||
|
|
||||||
|
|
|
@ -732,7 +732,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
||||||
/* MUX graph must have only 1 output */
|
/* MUX graph must have only 1 output */
|
||||||
VTR_ASSERT(1 == mux_input_ports.size());
|
VTR_ASSERT(1 == mux_input_ports.size());
|
||||||
VTR_ASSERT(1 == mux_input_ports.size());
|
VTR_ASSERT(1 == mux_input_ports.size());
|
||||||
VTR_ASSERT(1 == num_outputs);
|
|
||||||
/* A quick check on the model ports */
|
/* A quick check on the model ports */
|
||||||
if ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|
if ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|
||||||
|| ((SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
|| ((SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
||||||
|
@ -810,7 +809,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
||||||
print_verilog_module_end(fp, module_name);
|
print_verilog_module_end(fp, module_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************
|
/***********************************************
|
||||||
* Generate Verilog codes modeling a multiplexer
|
* Generate Verilog codes modeling a multiplexer
|
||||||
* with the given graph-level description
|
* with the given graph-level description
|
||||||
|
|
Loading…
Reference in New Issue