Merge remote-tracking branch 'lnis_origin/dev' into ganesh_dev
This commit is contained in:
commit
d90329678a
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,8 @@ fpga_flow=vpr_blif
|
||||||
# arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml
|
# arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml
|
||||||
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
|
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
|
||||||
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml
|
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml
|
||||||
|
arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml
|
||||||
|
arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml
|
||||||
|
|
||||||
[BENCHMARKS]
|
[BENCHMARKS]
|
||||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.blif
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.blif
|
||||||
|
@ -28,7 +30,7 @@ bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_mode
|
||||||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.v
|
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.v
|
||||||
bench0_chan_width = 300
|
bench0_chan_width = 300
|
||||||
|
|
||||||
[SCRIPT_PARAM_1]
|
[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
|
||||||
fix_route_chan_width=300
|
fix_route_chan_width=300
|
||||||
vpr_fpga_verilog_include_icarus_simulator=
|
vpr_fpga_verilog_include_icarus_simulator=
|
||||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
||||||
|
@ -44,17 +46,17 @@ vpr_fpga_x2p_compact_routing_hierarchy=
|
||||||
end_flow_with_test=
|
end_flow_with_test=
|
||||||
|
|
||||||
|
|
||||||
# [SCRIPT_PARAM_2]
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
# fix_route_chan_width=200
|
min_route_chan_width=1.3
|
||||||
# vpr_fpga_verilog_include_icarus_simulator=
|
vpr_fpga_verilog_include_icarus_simulator=
|
||||||
# vpr_fpga_verilog_formal_verification_top_netlist=
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
||||||
# vpr_fpga_verilog_include_timing=
|
vpr_fpga_verilog_include_timing=
|
||||||
# vpr_fpga_verilog_include_signal_init=
|
vpr_fpga_verilog_include_signal_init=
|
||||||
# vpr_fpga_verilog_print_autocheck_top_testbench=
|
vpr_fpga_verilog_print_autocheck_top_testbench=
|
||||||
# vpr_fpga_bitstream_generator=
|
vpr_fpga_bitstream_generator=
|
||||||
# vpr_fpga_verilog_print_user_defined_template=
|
vpr_fpga_verilog_print_user_defined_template=
|
||||||
# vpr_fpga_verilog_print_report_timing_tcl=
|
vpr_fpga_verilog_print_report_timing_tcl=
|
||||||
# vpr_fpga_verilog_print_sdc_pnr=
|
vpr_fpga_verilog_print_sdc_pnr=
|
||||||
# vpr_fpga_verilog_print_sdc_analysis=
|
vpr_fpga_verilog_print_sdc_analysis=
|
||||||
# vpr_fpga_x2p_compact_routing_hierarchy=
|
vpr_fpga_x2p_compact_routing_hierarchy=
|
||||||
# end_flow_with_test=
|
end_flow_with_test=
|
||||||
|
|
|
@ -67,6 +67,18 @@ size_t MuxGraph::num_inputs() const {
|
||||||
return num_inputs;
|
return num_inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the node ids of all the inputs of the multiplexer */
|
||||||
|
std::vector<MuxNodeId> MuxGraph::inputs() const {
|
||||||
|
std::vector<MuxNodeId> input_nodes;
|
||||||
|
/* need to check if the graph is valid or not */
|
||||||
|
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||||
|
/* Add the input nodes in each level */
|
||||||
|
for (auto node_per_level : node_lookup_) {
|
||||||
|
input_nodes.insert(input_nodes.end(), node_per_level[MUX_INPUT_NODE].begin(), node_per_level[MUX_INPUT_NODE].end());
|
||||||
|
}
|
||||||
|
return input_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the number of outputs in the MUX graph */
|
/* Find the number of outputs in the MUX graph */
|
||||||
size_t MuxGraph::num_outputs() const {
|
size_t MuxGraph::num_outputs() const {
|
||||||
/* need to check if the graph is valid or not */
|
/* need to check if the graph is valid or not */
|
||||||
|
@ -79,6 +91,36 @@ size_t MuxGraph::num_outputs() const {
|
||||||
return num_outputs;
|
return num_outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the node ids of all the outputs of the multiplexer */
|
||||||
|
std::vector<MuxNodeId> MuxGraph::outputs() const {
|
||||||
|
std::vector<MuxNodeId> output_nodes;
|
||||||
|
/* need to check if the graph is valid or not */
|
||||||
|
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||||
|
/* Add the output nodes in each level */
|
||||||
|
for (auto node_per_level : node_lookup_) {
|
||||||
|
output_nodes.insert(output_nodes.end(), node_per_level[MUX_OUTPUT_NODE].begin(), node_per_level[MUX_OUTPUT_NODE].end());
|
||||||
|
}
|
||||||
|
return output_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the edge between two MUX nodes */
|
||||||
|
std::vector<MuxEdgeId> MuxGraph::find_edges(const MuxNodeId& from_node, const MuxNodeId& to_node) const {
|
||||||
|
std::vector<MuxEdgeId> edges;
|
||||||
|
|
||||||
|
VTR_ASSERT(valid_node_id(from_node));
|
||||||
|
VTR_ASSERT(valid_node_id(to_node));
|
||||||
|
|
||||||
|
for (const auto& edge : node_out_edges_[from_node]) {
|
||||||
|
for (const auto& cand : edge_sink_nodes_[edge]) {
|
||||||
|
if (cand == to_node) {
|
||||||
|
/* This is the wanted edge, add to list */
|
||||||
|
edges.push_back(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the number of levels in the MUX graph */
|
/* Find the number of levels in the MUX graph */
|
||||||
size_t MuxGraph::num_levels() const {
|
size_t MuxGraph::num_levels() const {
|
||||||
|
@ -95,6 +137,20 @@ size_t MuxGraph::num_memory_bits() const {
|
||||||
return mem_ids_.size();
|
return mem_ids_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the mem that control the edge */
|
||||||
|
MuxMemId MuxGraph::find_edge_mem(const MuxEdgeId& edge) const {
|
||||||
|
/* validate the edge */
|
||||||
|
VTR_ASSERT(valid_edge_id(edge));
|
||||||
|
return edge_mem_ids_[edge];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Identify if the edge is controlled by the inverted output of a mem */
|
||||||
|
bool MuxGraph::is_edge_use_inv_mem(const MuxEdgeId& edge) const {
|
||||||
|
/* validate the edge */
|
||||||
|
VTR_ASSERT(valid_edge_id(edge));
|
||||||
|
return edge_inv_mem_[edge];
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the sizes of each branch of a MUX */
|
/* Find the sizes of each branch of a MUX */
|
||||||
std::vector<size_t> MuxGraph::branch_sizes() const {
|
std::vector<size_t> MuxGraph::branch_sizes() const {
|
||||||
std::vector<size_t> branch;
|
std::vector<size_t> branch;
|
||||||
|
@ -147,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_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;
|
||||||
|
|
||||||
|
@ -190,6 +247,8 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
||||||
/* Not found, we add a memory bit and record in the mem-to-mem map */
|
/* Not found, we add a memory bit and record in the mem-to-mem map */
|
||||||
MuxMemId mem_subgraph = mux_graph.add_mem();
|
MuxMemId mem_subgraph = mux_graph.add_mem();
|
||||||
mem2mem_map[mem_origin] = mem_subgraph;
|
mem2mem_map[mem_origin] = mem_subgraph;
|
||||||
|
/* configure the edge */
|
||||||
|
mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem_subgraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
@ -241,6 +300,24 @@ std::vector<MuxGraph> MuxGraph::build_mux_branch_graphs() const {
|
||||||
return branch_graphs;
|
return branch_graphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the input id of a given node */
|
||||||
|
MuxInputId MuxGraph::input_id(const MuxNodeId& node_id) const {
|
||||||
|
/* Validate node id */
|
||||||
|
VTR_ASSERT(valid_node_id(node_id));
|
||||||
|
/* Must be an input */
|
||||||
|
VTR_ASSERT(MUX_INPUT_NODE == node_types_[node_id]);
|
||||||
|
return node_input_ids_[node_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the input id of a given node */
|
||||||
|
MuxOutputId MuxGraph::output_id(const MuxNodeId& node_id) const {
|
||||||
|
/* Validate node id */
|
||||||
|
VTR_ASSERT(valid_node_id(node_id));
|
||||||
|
/* Must be an input */
|
||||||
|
VTR_ASSERT(MUX_OUTPUT_NODE == node_types_[node_id]);
|
||||||
|
return node_output_ids_[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 */
|
||||||
|
@ -287,7 +364,10 @@ std::vector<size_t> MuxGraph::decode_memory_bits(const MuxInputId& input_id) con
|
||||||
/* Visit the next node */
|
/* Visit the next node */
|
||||||
next_node = edge_sink_nodes_[edge][0];
|
next_node = edge_sink_nodes_[edge][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* valid the output */
|
||||||
VTR_ASSERT_SAFE(MUX_OUTPUT_NODE == node_types_[next_node]);
|
VTR_ASSERT_SAFE(MUX_OUTPUT_NODE == node_types_[next_node]);
|
||||||
|
VTR_ASSERT_SAFE(valid_output_id(node_output_ids_[next_node]));
|
||||||
|
|
||||||
return mem_bits;
|
return mem_bits;
|
||||||
}
|
}
|
||||||
|
@ -303,6 +383,7 @@ MuxNodeId MuxGraph::add_node(const enum e_mux_graph_node_type& node_type) {
|
||||||
/* Resize the other node-related vectors */
|
/* Resize the other node-related vectors */
|
||||||
node_types_.push_back(node_type);
|
node_types_.push_back(node_type);
|
||||||
node_input_ids_.push_back(MuxInputId::INVALID());
|
node_input_ids_.push_back(MuxInputId::INVALID());
|
||||||
|
node_output_ids_.push_back(MuxOutputId::INVALID());
|
||||||
node_levels_.push_back(-1);
|
node_levels_.push_back(-1);
|
||||||
node_in_edges_.emplace_back();
|
node_in_edges_.emplace_back();
|
||||||
node_out_edges_.emplace_back();
|
node_out_edges_.emplace_back();
|
||||||
|
@ -427,6 +508,7 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
||||||
/* Number of outputs is definite, add and configure */
|
/* Number of outputs is definite, add and configure */
|
||||||
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
||||||
node_levels_[output_node] = num_levels;
|
node_levels_[output_node] = num_levels;
|
||||||
|
node_output_ids_[output_node] = MuxOutputId(0);
|
||||||
/* Update node lookup */
|
/* Update node lookup */
|
||||||
node_lookup[num_levels].push_back(output_node);
|
node_lookup[num_levels].push_back(output_node);
|
||||||
|
|
||||||
|
@ -542,6 +624,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_output_ids_[output_node] = MuxOutputId(0);
|
||||||
|
|
||||||
for (size_t i = 0; i < mux_size; ++i) {
|
for (size_t i = 0; i < mux_size; ++i) {
|
||||||
MuxNodeId input_node = add_node(MUX_INPUT_NODE);
|
MuxNodeId input_node = add_node(MUX_INPUT_NODE);
|
||||||
|
@ -664,7 +747,7 @@ bool MuxGraph::valid_mem_id(const MuxMemId& mem) const {
|
||||||
return size_t(mem) < mem_ids_.size() && mem_ids_[mem] == mem;
|
return size_t(mem) < mem_ids_.size() && mem_ids_[mem] == mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate an input id (from which data path signal will be progagated to the output */
|
/* validate an input id (from which data path signal will be progagated to the output) */
|
||||||
bool MuxGraph::valid_input_id(const MuxInputId& input_id) const {
|
bool MuxGraph::valid_input_id(const MuxInputId& input_id) const {
|
||||||
for (const auto& lvl : node_lookup_) {
|
for (const auto& lvl : node_lookup_) {
|
||||||
for (const auto& node : lvl[MUX_INPUT_NODE]) {
|
for (const auto& node : lvl[MUX_INPUT_NODE]) {
|
||||||
|
@ -677,6 +760,19 @@ bool MuxGraph::valid_input_id(const MuxInputId& input_id) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* validate an output id */
|
||||||
|
bool MuxGraph::valid_output_id(const MuxOutputId& output_id) const {
|
||||||
|
for (const auto& lvl : node_lookup_) {
|
||||||
|
for (const auto& node : lvl[MUX_OUTPUT_NODE]) {
|
||||||
|
if (size_t(output_id) > size_t(node_output_ids_[node])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MuxGraph::valid_node_lookup() const {
|
bool MuxGraph::valid_node_lookup() const {
|
||||||
return node_lookup_.empty();
|
return node_lookup_.empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,20 @@ class MuxGraph {
|
||||||
public: /* Public accessors: Data query */
|
public: /* Public accessors: Data query */
|
||||||
/* Find the number of inputs in the MUX graph */
|
/* Find the number of inputs in the MUX graph */
|
||||||
size_t num_inputs() const;
|
size_t num_inputs() const;
|
||||||
|
std::vector<MuxNodeId> inputs() const;
|
||||||
/* Find the number of outputs in the MUX graph */
|
/* Find the number of outputs in the MUX graph */
|
||||||
size_t num_outputs() const;
|
size_t num_outputs() const;
|
||||||
|
std::vector<MuxNodeId> outputs() const;
|
||||||
|
/* Find the edge between two MUX nodes */
|
||||||
|
std::vector<MuxEdgeId> find_edges(const MuxNodeId& from_node, const MuxNodeId& to_node) const;
|
||||||
/* Find the number of levels in the MUX graph */
|
/* Find the number of levels in the MUX graph */
|
||||||
size_t num_levels() const;
|
size_t num_levels() const;
|
||||||
/* Find the number of SRAMs in the MUX graph */
|
/* Find the number of SRAMs in the MUX graph */
|
||||||
size_t num_memory_bits() const;
|
size_t num_memory_bits() const;
|
||||||
|
/* Find the mem that control the edge */
|
||||||
|
MuxMemId find_edge_mem(const MuxEdgeId& edge) const;
|
||||||
|
/* Identify if the edge is controlled by the inverted output of a mem */
|
||||||
|
bool is_edge_use_inv_mem(const MuxEdgeId& edge) const;
|
||||||
/* Find the sizes of each branch of a MUX */
|
/* Find the sizes of each branch of a MUX */
|
||||||
std::vector<size_t> branch_sizes() const;
|
std::vector<size_t> branch_sizes() const;
|
||||||
/* Generate MUX graphs for its branches */
|
/* Generate MUX graphs for its branches */
|
||||||
|
@ -76,6 +84,10 @@ class MuxGraph {
|
||||||
std::vector<MuxGraph> build_mux_branch_graphs() const;
|
std::vector<MuxGraph> build_mux_branch_graphs() const;
|
||||||
/* Get the node id of a given input */
|
/* Get the node id of a given input */
|
||||||
MuxNodeId node_id(const MuxInputId& input_id) const;
|
MuxNodeId node_id(const MuxInputId& input_id) const;
|
||||||
|
/* Get the input id of a given node */
|
||||||
|
MuxInputId input_id(const MuxNodeId& node_id) const;
|
||||||
|
/* Get the output id of a given node */
|
||||||
|
MuxOutputId output_id(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 */
|
||||||
|
@ -106,6 +118,7 @@ class MuxGraph {
|
||||||
bool valid_edge_id(const MuxEdgeId& edge) const;
|
bool valid_edge_id(const MuxEdgeId& edge) const;
|
||||||
bool valid_mem_id(const MuxMemId& mem) const;
|
bool valid_mem_id(const MuxMemId& mem) const;
|
||||||
bool valid_input_id(const MuxInputId& input_id) const;
|
bool valid_input_id(const MuxInputId& input_id) const;
|
||||||
|
bool valid_output_id(const MuxOutputId& output_id) const;
|
||||||
/* validate/invalidate node lookup */
|
/* validate/invalidate node lookup */
|
||||||
bool valid_node_lookup() const;
|
bool valid_node_lookup() const;
|
||||||
void invalidate_node_lookup();
|
void invalidate_node_lookup();
|
||||||
|
@ -115,6 +128,7 @@ class MuxGraph {
|
||||||
vtr::vector<MuxNodeId, MuxNodeId> node_ids_; /* Unique ids for each node */
|
vtr::vector<MuxNodeId, MuxNodeId> node_ids_; /* Unique ids for each node */
|
||||||
vtr::vector<MuxNodeId, enum e_mux_graph_node_type> node_types_; /* type of each node, input/output/internal */
|
vtr::vector<MuxNodeId, enum e_mux_graph_node_type> node_types_; /* type of each node, input/output/internal */
|
||||||
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, 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, 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 */
|
||||||
|
|
|
@ -13,11 +13,13 @@ struct mux_node_id_tag;
|
||||||
struct mux_edge_id_tag;
|
struct mux_edge_id_tag;
|
||||||
struct mux_mem_id_tag;
|
struct mux_mem_id_tag;
|
||||||
struct mux_input_id_tag;
|
struct mux_input_id_tag;
|
||||||
|
struct mux_output_id_tag;
|
||||||
|
|
||||||
typedef vtr::StrongId<mux_node_id_tag> MuxNodeId;
|
typedef vtr::StrongId<mux_node_id_tag> MuxNodeId;
|
||||||
typedef vtr::StrongId<mux_edge_id_tag> MuxEdgeId;
|
typedef vtr::StrongId<mux_edge_id_tag> MuxEdgeId;
|
||||||
typedef vtr::StrongId<mux_mem_id_tag> MuxMemId;
|
typedef vtr::StrongId<mux_mem_id_tag> MuxMemId;
|
||||||
typedef vtr::StrongId<mux_input_id_tag> MuxInputId;
|
typedef vtr::StrongId<mux_input_id_tag> MuxInputId;
|
||||||
|
typedef vtr::StrongId<mux_output_id_tag> MuxOutputId;
|
||||||
|
|
||||||
class MuxGraph;
|
class MuxGraph;
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,16 @@ CircuitModelId MuxLibrary::mux_circuit_model(const MuxId& mux_id) const {
|
||||||
return mux_circuit_models_[mux_id];
|
return mux_circuit_models_[mux_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the maximum mux size among the mux graphs */
|
||||||
|
size_t MuxLibrary::max_mux_size() const {
|
||||||
|
/* Iterate over all the mux graphs and find their sizes */
|
||||||
|
size_t max_mux_size = 0;
|
||||||
|
for (const auto& mux : mux_ids_) {
|
||||||
|
max_mux_size = std::max(max_mux_size, mux_graphs_[mux].num_inputs());
|
||||||
|
}
|
||||||
|
return max_mux_size;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Private mutators:
|
* Private mutators:
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
|
@ -27,6 +27,8 @@ class MuxLibrary {
|
||||||
const MuxGraph& mux_graph(const MuxId& mux_id) const;
|
const MuxGraph& mux_graph(const MuxId& mux_id) const;
|
||||||
/* Get a mux circuit model id */
|
/* Get a mux circuit model id */
|
||||||
CircuitModelId mux_circuit_model(const MuxId& mux_id) const;
|
CircuitModelId mux_circuit_model(const MuxId& mux_id) const;
|
||||||
|
/* Find the maximum mux size */
|
||||||
|
size_t max_mux_size() const;
|
||||||
public: /* Public mutators */
|
public: /* Public mutators */
|
||||||
/* Add a mux to the library */
|
/* Add a mux to the library */
|
||||||
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes the functions of builders for MuxLibrary.
|
||||||
|
*******************************************************************/
|
||||||
|
#include <cmath>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
|
||||||
|
/* Device-level header files */
|
||||||
|
#include "util.h"
|
||||||
|
#include "vpr_types.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
/* FPGA-X2P context header files */
|
||||||
|
#include "fpga_x2p_utils.h"
|
||||||
|
|
||||||
|
#include "spice_types.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "mux_library.h"
|
||||||
|
#include "mux_library_builder.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Update MuxLibrary with the unique multiplexer structures
|
||||||
|
* found in the global routing architecture
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void build_routing_arch_mux_library(MuxLibrary& mux_lib,
|
||||||
|
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||||
|
t_switch_inf* switches,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
t_det_routing_arch* routing_arch) {
|
||||||
|
/* Current Version: Support Uni-directional routing architecture only*/
|
||||||
|
if (UNI_DIRECTIONAL != routing_arch->directionality) {
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(FILE:%s, LINE[%d]) FPGA X2P Only supports uni-directional routing architecture.\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The routing path is.
|
||||||
|
* OPIN ----> CHAN ----> ... ----> CHAN ----> IPIN
|
||||||
|
* Each edge is a switch, for IPIN, the switch is a connection block,
|
||||||
|
* for the rest is a switch box
|
||||||
|
*/
|
||||||
|
/* Count the sizes of muliplexers in routing architecture */
|
||||||
|
for (int inode = 0; inode < LL_num_rr_nodes; inode++) {
|
||||||
|
t_rr_node& node = LL_rr_node[inode];
|
||||||
|
switch (node.type) {
|
||||||
|
case IPIN: {
|
||||||
|
/* Have to consider the fan_in only, it is a connection block (multiplexer)*/
|
||||||
|
VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in));
|
||||||
|
if ( (0 == node.fan_in) || (1 == node.fan_in)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Find the circuit_model for multiplexers in connection blocks */
|
||||||
|
const CircuitModelId& cb_switch_circuit_model = switches[node.driver_switch].circuit_model;
|
||||||
|
/* we should select a circuit model for the connection box*/
|
||||||
|
VTR_ASSERT(CircuitModelId::INVALID() != cb_switch_circuit_model);
|
||||||
|
/* Add the mux to mux_library */
|
||||||
|
mux_lib.add_mux(circuit_lib, cb_switch_circuit_model, node.fan_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHANX:
|
||||||
|
case CHANY: {
|
||||||
|
/* Channels are the same, have to consider the fan_in as well,
|
||||||
|
* it could be a switch box if previous rr_node is a channel
|
||||||
|
* or it could be a connection box if previous rr_node is a IPIN or OPIN
|
||||||
|
*/
|
||||||
|
VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in));
|
||||||
|
if ((0 == node.fan_in) || (1 == node.fan_in)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Find the spice_model for multiplexers in switch blocks*/
|
||||||
|
const CircuitModelId& sb_switch_circuit_model = switches[node.driver_switch].circuit_model;
|
||||||
|
/* we should select a circuit model for the Switch box*/
|
||||||
|
VTR_ASSERT(CircuitModelId::INVALID() != sb_switch_circuit_model);
|
||||||
|
/* Add the mux to mux_library */
|
||||||
|
mux_lib.add_mux(circuit_lib, sb_switch_circuit_model, node.fan_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* We do not care other types of rr_node */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Update MuxLibrary with the unique multiplexer structures
|
||||||
|
* found in programmable logic blocks
|
||||||
|
********************************************************************/
|
||||||
|
static
|
||||||
|
void build_pb_type_mux_library_rec(MuxLibrary& mux_lib,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
t_pb_type* cur_pb_type) {
|
||||||
|
VTR_ASSERT(nullptr != cur_pb_type);
|
||||||
|
|
||||||
|
/* If there is spice_model_name, this is a leaf node!*/
|
||||||
|
if (TRUE == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
/* What annoys me is VPR create a sub pb_type for each lut which suppose to be a leaf node
|
||||||
|
* This may bring software convience but ruins circuit modeling
|
||||||
|
*/
|
||||||
|
VTR_ASSERT(CircuitModelId::INVALID() != cur_pb_type->phy_pb_type->circuit_model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traversal the hierarchy, find all the multiplexer from the interconnection part */
|
||||||
|
for (int imode = 0; imode < cur_pb_type->num_modes; imode++) {
|
||||||
|
/* Then we have to statisitic the interconnections*/
|
||||||
|
for (int jinterc = 0; jinterc < cur_pb_type->modes[imode].num_interconnect; jinterc++) {
|
||||||
|
/* Check the num_mux and fan_in of an interconnection */
|
||||||
|
VTR_ASSERT ((0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux)
|
||||||
|
|| (0 < cur_pb_type->modes[imode].interconnect[jinterc].num_mux));
|
||||||
|
if (0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CircuitModelId& interc_circuit_model = cur_pb_type->modes[imode].interconnect[jinterc].circuit_model;
|
||||||
|
VTR_ASSERT(CircuitModelId::INVALID() != interc_circuit_model);
|
||||||
|
/* Add the mux model to library */
|
||||||
|
mux_lib.add_mux(circuit_lib, interc_circuit_model, cur_pb_type->modes[imode].interconnect[jinterc].fan_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go recursively to the lower level */
|
||||||
|
for (int imode = 0; imode < cur_pb_type->num_modes; imode++) {
|
||||||
|
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ichild++) {
|
||||||
|
build_pb_type_mux_library_rec(mux_lib, circuit_lib,
|
||||||
|
&cur_pb_type->modes[imode].pb_type_children[ichild]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Update MuxLibrary with the unique multiplexers required by
|
||||||
|
* LUTs in the circuit library
|
||||||
|
********************************************************************/
|
||||||
|
static
|
||||||
|
void build_lut_mux_library(MuxLibrary& mux_lib,
|
||||||
|
const CircuitLibrary& circuit_lib) {
|
||||||
|
/* Find all the circuit models which are LUTs in the circuit library */
|
||||||
|
for (const auto& circuit_model : circuit_lib.models()) {
|
||||||
|
/* Bypass non-LUT circuit models */
|
||||||
|
if (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Find the MUX size required by the LUT */
|
||||||
|
/* Get input ports which are not global ports! */
|
||||||
|
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||||
|
VTR_ASSERT(1 == input_ports.size());
|
||||||
|
/* MUX size = 2^lut_size */
|
||||||
|
size_t lut_mux_size = (size_t)pow(2., (double)(circuit_lib.port_size(input_ports[0])));
|
||||||
|
/* Add mux to the mux library */
|
||||||
|
mux_lib.add_mux(circuit_lib, circuit_model, lut_mux_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Statistic for all the multiplexers in FPGA
|
||||||
|
* We determine the sizes and its structure (according to spice_model) for each type of multiplexers
|
||||||
|
* We search multiplexers in Switch Blocks, Connection blocks and Configurable Logic Blocks
|
||||||
|
* In additional to multiplexers, this function also consider crossbars.
|
||||||
|
* All the statistics are stored in a linked list, as a return value
|
||||||
|
*/
|
||||||
|
MuxLibrary build_device_mux_library(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||||
|
t_switch_inf* switches,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
t_det_routing_arch* routing_arch) {
|
||||||
|
/* MuxLibrary to store the information of Multiplexers*/
|
||||||
|
MuxLibrary mux_lib;
|
||||||
|
|
||||||
|
/* Step 1: We should check the multiplexer spice models defined in routing architecture.*/
|
||||||
|
build_routing_arch_mux_library(mux_lib, LL_num_rr_nodes, LL_rr_node, switches, circuit_lib, routing_arch);
|
||||||
|
|
||||||
|
/* Step 2: Count the sizes of multiplexers in complex logic blocks */
|
||||||
|
for (int itype = 0; itype < num_types; itype++) {
|
||||||
|
if (NULL != type_descriptors[itype].pb_type) {
|
||||||
|
build_pb_type_mux_library_rec(mux_lib, circuit_lib, type_descriptors[itype].pb_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 3: count the size of multiplexer that will be used in LUTs*/
|
||||||
|
build_lut_mux_library(mux_lib, circuit_lib);
|
||||||
|
|
||||||
|
return mux_lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes the function declaration of builders
|
||||||
|
* for MuxLibrary.
|
||||||
|
* See details in mux_library_builder.cpp
|
||||||
|
*******************************************************************/
|
||||||
|
#ifndef MUX_LIBRARY_BUILDER_H
|
||||||
|
#define MUX_LIBRARY_BUILDER_H
|
||||||
|
|
||||||
|
MuxLibrary build_device_mux_library(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||||
|
t_switch_inf* switches,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
t_det_routing_arch* routing_arch);
|
||||||
|
|
||||||
|
#endif
|
|
@ -29,6 +29,7 @@ std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
|
const size_t& branch_mux_size,
|
||||||
const std::string& postfix) {
|
const std::string& postfix) {
|
||||||
/* If the tgate spice model of this MUX is a MUX2 standard cell,
|
/* If the tgate spice model of this MUX is a MUX2 standard cell,
|
||||||
* the mux_subckt name will be the name of the standard cell
|
* the mux_subckt name will be the name of the standard cell
|
||||||
|
@ -38,6 +39,7 @@ std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circui
|
||||||
VTR_ASSERT (SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(subckt_model));
|
VTR_ASSERT (SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(subckt_model));
|
||||||
return circuit_lib.model_name(subckt_model);
|
return circuit_lib.model_name(subckt_model);
|
||||||
}
|
}
|
||||||
|
std::string branch_postfix = postfix + "_size" + std::to_string(branch_mux_size);
|
||||||
|
|
||||||
return generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_size, postfix);
|
return generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
|
const size_t& branch_mux_size,
|
||||||
const std::string& posfix);
|
const std::string& posfix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -50,6 +50,32 @@ std::vector<BasicPort> ModuleManager::module_ports_by_type(const ModuleId& modul
|
||||||
return ports;
|
return ports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the module id by a given name, return invalid if not found */
|
||||||
|
ModuleId ModuleManager::find_module(const std::string& name) const {
|
||||||
|
if (name_id_map_.find(name) != name_id_map_.end()) {
|
||||||
|
/* Find it, return the id */
|
||||||
|
return name_id_map_.at(name);
|
||||||
|
}
|
||||||
|
/* Not found, return an invalid id */
|
||||||
|
return ModuleId::INVALID();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the number of instances of a child module in the parent module */
|
||||||
|
size_t ModuleManager::num_instance(const ModuleId& parent_module, const ModuleId& child_module) const {
|
||||||
|
/* 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 num_child_instances_[parent_module][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Not found, return a zero */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Public Mutators
|
* Public Mutators
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -69,6 +95,7 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
||||||
names_.push_back(name);
|
names_.push_back(name);
|
||||||
parents_.emplace_back();
|
parents_.emplace_back();
|
||||||
children_.emplace_back();
|
children_.emplace_back();
|
||||||
|
num_child_instances_.emplace_back();
|
||||||
|
|
||||||
port_ids_.emplace_back();
|
port_ids_.emplace_back();
|
||||||
ports_.emplace_back();
|
ports_.emplace_back();
|
||||||
|
@ -116,10 +143,14 @@ void ModuleManager::add_child_module(const ModuleId& parent_module, const Module
|
||||||
parents_[child_module].push_back(parent_module);
|
parents_[child_module].push_back(parent_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModuleId>::iterator child_it = std::find(children_[child_module].begin(), children_[child_module].end(), child_module);
|
std::vector<ModuleId>::iterator child_it = std::find(children_[parent_module].begin(), children_[parent_module].end(), child_module);
|
||||||
if (child_it == children_[parent_module].end()) {
|
if (child_it == children_[parent_module].end()) {
|
||||||
/* 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 */
|
||||||
|
} else {
|
||||||
|
/* Increase the counter of instances */
|
||||||
|
num_child_instances_[parent_module][child_it - children_[parent_module].begin()]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ class ModuleManager {
|
||||||
std::string module_name(const ModuleId& module_id) const;
|
std::string module_name(const ModuleId& module_id) const;
|
||||||
std::string module_port_type_str(const enum e_module_port_type& port_type) const;
|
std::string module_port_type_str(const enum e_module_port_type& port_type) const;
|
||||||
std::vector<BasicPort> module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
|
std::vector<BasicPort> module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
|
||||||
|
ModuleId find_module(const std::string& name) const;
|
||||||
|
/* Find the number of instances of a child module in the parent module */
|
||||||
|
size_t num_instance(const ModuleId& parent_module, const ModuleId& child_module) const;
|
||||||
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);
|
||||||
|
@ -55,6 +58,7 @@ class ModuleManager {
|
||||||
vtr::vector<ModuleId, std::string> names_; /* Unique identifier for each Module */
|
vtr::vector<ModuleId, std::string> names_; /* Unique identifier for each Module */
|
||||||
vtr::vector<ModuleId, std::vector<ModuleId>> parents_; /* Parent modules that include the module */
|
vtr::vector<ModuleId, std::vector<ModuleId>> 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, 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 */
|
||||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */
|
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "fpga_bitstream.h"
|
#include "fpga_bitstream.h"
|
||||||
|
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
|
#include "mux_library.h"
|
||||||
|
#include "mux_library_builder.h"
|
||||||
|
|
||||||
/* Include SynVerilog headers */
|
/* Include SynVerilog headers */
|
||||||
#include "verilog_global.h"
|
#include "verilog_global.h"
|
||||||
|
@ -153,6 +155,10 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
||||||
/* Module manager for the Verilog modules created */
|
/* Module manager for the Verilog modules created */
|
||||||
ModuleManager module_manager;
|
ModuleManager module_manager;
|
||||||
|
|
||||||
|
/* Build Multiplexer library */
|
||||||
|
MuxLibrary mux_lib = build_device_mux_library(num_rr_nodes, rr_node, switch_inf, Arch.spice->circuit_lib, &vpr_setup.RoutingArch);
|
||||||
|
|
||||||
|
/* 0. basic units: inverter, buffers and pass-gate logics, */
|
||||||
/* Check if the routing architecture we support*/
|
/* Check if the routing architecture we support*/
|
||||||
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
||||||
vpr_printf(TIO_MESSAGE_ERROR, "FPGA synthesizable Verilog dumping only support uni-directional routing architecture!\n");
|
vpr_printf(TIO_MESSAGE_ERROR, "FPGA synthesizable Verilog dumping only support uni-directional routing architecture!\n");
|
||||||
|
@ -274,7 +280,7 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
||||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||||
|
|
||||||
/* Dump internal structures of submodules */
|
/* Dump internal structures of submodules */
|
||||||
dump_verilog_submodules(module_manager, sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
dump_verilog_submodules(module_manager, mux_lib, sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
||||||
Arch, &vpr_setup.RoutingArch,
|
Arch, &vpr_setup.RoutingArch,
|
||||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||||
|
|
||||||
|
|
|
@ -507,7 +507,7 @@ void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
||||||
/* Create file */
|
/* Create file */
|
||||||
vpr_printf(TIO_MESSAGE_INFO,
|
vpr_printf(TIO_MESSAGE_INFO,
|
||||||
"Generating Verilog netlist (%s) for essential gates...\n",
|
"Generating Verilog netlist (%s) for essential gates...\n",
|
||||||
__FILE__, __LINE__, essentials_verilog_file_name);
|
__FILE__, __LINE__, verilog_fname.c_str());
|
||||||
|
|
||||||
print_verilog_file_header(fp, "Essential gates");
|
print_verilog_file_header(fp, "Essential gates");
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
/* Device-level header files */
|
/* Device-level header files */
|
||||||
#include "mux_graph.h"
|
#include "mux_graph.h"
|
||||||
|
#include "module_manager.h"
|
||||||
#include "physical_types.h"
|
#include "physical_types.h"
|
||||||
#include "vpr_types.h"
|
#include "vpr_types.h"
|
||||||
|
|
||||||
|
@ -25,16 +26,169 @@
|
||||||
#include "verilog_writer_utils.h"
|
#include "verilog_writer_utils.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;
|
||||||
|
}
|
||||||
|
/* TODO: 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
|
||||||
|
* for a multiplexer with the given size
|
||||||
|
*********************************************************************/
|
||||||
|
static
|
||||||
|
void generate_verilog_cmos_mux_branch_body_behavioral(std::fstream& fp,
|
||||||
|
const BasicPort& input_port,
|
||||||
|
const BasicPort& output_port,
|
||||||
|
const BasicPort& mem_port,
|
||||||
|
const MuxGraph& mux_graph,
|
||||||
|
const size_t& default_mem_val) {
|
||||||
|
/* Make sure we have a valid file handler*/
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
/* Verilog Behavior description for a MUX */
|
||||||
|
print_verilog_comment(fp, std::string("---- Behavioral-level description -----"));
|
||||||
|
|
||||||
|
/* Add an internal register for the output */
|
||||||
|
BasicPort outreg_port("out_reg", mux_graph.num_outputs());
|
||||||
|
/* Print the port */
|
||||||
|
fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, outreg_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
/* Generate the case-switch table */
|
||||||
|
fp << "\talways @(" << generate_verilog_port(VERILOG_PORT_CONKT, input_port) << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << ")" << std::endl;
|
||||||
|
fp << "\tcase (" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << ")" << std::endl;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
/* For each case, generate the logic levels for all the inputs */
|
||||||
|
/* In each case, only one mem is enabled */
|
||||||
|
fp << "\t\t" << mem_port.get_width() << "'b";
|
||||||
|
std::string case_code(mem_port.get_width(), default_mem_val);
|
||||||
|
|
||||||
|
/* Find the mem_id controlling the edge */
|
||||||
|
MuxMemId mux_mem = mux_graph.find_edge_mem(edges[0]);
|
||||||
|
/* Flip a bit by the mem_id */
|
||||||
|
if (false == mux_graph.is_edge_use_inv_mem(edges[0])) {
|
||||||
|
case_code[size_t(mux_mem)] = '1';
|
||||||
|
} else {
|
||||||
|
case_code[size_t(mux_mem)] = '0';
|
||||||
|
}
|
||||||
|
fp << case_code << ": " << generate_verilog_port(VERILOG_PORT_CONKT, outreg_port) << " <= ";
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_CONKT, cur_input_port) << ";" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default case: outputs are at high-impedance state 'z' */
|
||||||
|
std::string default_case(mux_graph.num_outputs(), 'z');
|
||||||
|
fp << "\t\tdefault: " << generate_verilog_port(VERILOG_PORT_CONKT, outreg_port) << " <= ";
|
||||||
|
fp << mux_graph.num_outputs() << "'b" << default_case << ";" << std::endl;
|
||||||
|
|
||||||
|
/* End the case */
|
||||||
|
fp << "\tendcase" << std::endl;
|
||||||
|
|
||||||
|
/* Wire registers to output ports */
|
||||||
|
fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << " = ";
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_CONKT, outreg_port) << ";" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
* Generate Verilog codes modeling an branch circuit
|
* Generate Verilog codes modeling an branch circuit
|
||||||
* for a multiplexer with the given size
|
* for a multiplexer with the given size
|
||||||
**********************************************/
|
* Support structural and behavioral Verilog codes
|
||||||
|
*********************************************************************/
|
||||||
static
|
static
|
||||||
void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
void generate_verilog_cmos_mux_branch_module(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
|
std::fstream& fp,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_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(circuit_model);
|
||||||
|
|
||||||
|
@ -44,12 +198,7 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
|
||||||
std::vector<CircuitPortId> tgate_global_ports = circuit_lib.model_global_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true);
|
std::vector<CircuitPortId> tgate_global_ports = circuit_lib.model_global_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true);
|
||||||
VTR_ASSERT(3 == tgate_input_ports.size());
|
|
||||||
VTR_ASSERT(1 == tgate_output_ports.size());
|
|
||||||
|
|
||||||
/* Make sure we have a valid file handler*/
|
/* Make sure we have a valid file handler*/
|
||||||
check_file_handler(fp);
|
check_file_handler(fp);
|
||||||
|
@ -68,105 +217,51 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
||||||
/* MUX graph must have only 1 level*/
|
/* MUX graph must have only 1 level*/
|
||||||
VTR_ASSERT(1 == mux_graph.num_levels());
|
VTR_ASSERT(1 == mux_graph.num_levels());
|
||||||
|
|
||||||
/* Print Verilog module */
|
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||||
print_verilog_module_definition(fp, module_name);
|
ModuleId module_id = module_manager.add_module(module_name);
|
||||||
|
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||||
/* Create port information */
|
/* Add module ports */
|
||||||
/* Configure each input port */
|
/* Add each global port */
|
||||||
BasicPort input_port("in", num_inputs);
|
|
||||||
|
|
||||||
/* Configure each output port */
|
|
||||||
BasicPort output_port("out", num_outputs);
|
|
||||||
|
|
||||||
/* Configure each memory port */
|
|
||||||
BasicPort mem_port("mem", num_mems);
|
|
||||||
BasicPort mem_inv_port("mem_inv", num_mems);
|
|
||||||
|
|
||||||
/* TODO: Generate global ports */
|
|
||||||
for (const auto& port : tgate_global_ports) {
|
for (const auto& port : tgate_global_ports) {
|
||||||
/* Configure each global port */
|
/* Configure each global port */
|
||||||
BasicPort basic_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||||
/* Print port */
|
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl;
|
|
||||||
}
|
}
|
||||||
|
/* Add each input port */
|
||||||
|
BasicPort input_port("in", num_inputs);
|
||||||
|
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
/* Add each output port */
|
||||||
|
BasicPort output_port("out", num_outputs);
|
||||||
|
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
/* Add each memory port */
|
||||||
|
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);
|
||||||
|
|
||||||
/* TODO: add a module to the Module Manager */
|
/* dump module definition + ports */
|
||||||
|
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||||
|
|
||||||
/* Port list */
|
/* Print the internal logic in either structural or behavioral Verilog codes */
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, input_port) << "," << std::endl;
|
if (true == use_structural_verilog) {
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_OUTPUT, output_port) << "," << std::endl;
|
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);
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_port) << "," << std::endl;
|
|
||||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_inv_port) << std::endl;
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
|
|
||||||
/* Verilog Behavior description for a MUX */
|
|
||||||
print_verilog_comment(fp, std::string("---- Structure-level description -----"));
|
|
||||||
/* Special case: only one memory, switch case is simpler
|
|
||||||
* When mem = 1, propagate input 0;
|
|
||||||
* when mem = 0, propagate input 1;
|
|
||||||
*/
|
|
||||||
/* TODO: we should output the netlist following the connections in mux_graph */
|
|
||||||
if (1 == num_mems) {
|
|
||||||
/* Transmission gates are connected to each input and also the output*/
|
|
||||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_0 ";
|
|
||||||
/* Dump explicit port map if required */
|
|
||||||
/* TODO: add global port support for tgate model */
|
|
||||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
|
||||||
fp << " (";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[0]" << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
} else {
|
} else {
|
||||||
fp << " (";
|
VTR_ASSERT_SAFE(false == use_structural_verilog);
|
||||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
/* Get the default value of SRAM ports */
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
std::vector<CircuitPortId> non_mode_select_sram_ports;
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
/* We should have only have 1 sram port except those are mode_bits */
|
||||||
fp << ");" << std::endl;
|
for (const auto& port : sram_ports) {
|
||||||
}
|
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||||
/* Transmission gates are connected to each input and also the output*/
|
continue;
|
||||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_1 ";
|
|
||||||
/* Dump explicit port map if required */
|
|
||||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
|
||||||
fp << " (";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[1]" << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
} else {
|
|
||||||
fp << " (";
|
|
||||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Other cases, we need to follow the rules:
|
|
||||||
* When mem[k] is enabled, switch on input[k]
|
|
||||||
* Only one memory bit is enabled!
|
|
||||||
*/
|
|
||||||
for (size_t i = 0; i < num_mems; i++) {
|
|
||||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_" << i << " ";
|
|
||||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
|
||||||
fp << " (";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[" << i << "]" << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << "mem[" << i << "]" << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << "mem_inv[" << i << "]" << "),";
|
|
||||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
} else {
|
|
||||||
fp << " (";
|
|
||||||
fp << "in[" << i << "]";
|
|
||||||
fp << ", " << "mem[" << i << "]";
|
|
||||||
fp << ", " << "mem_inv[" << i << "]";
|
|
||||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
|
||||||
fp << ");" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
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! */
|
||||||
|
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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put an end to the Verilog module */
|
/* Put an end to the Verilog module */
|
||||||
|
@ -177,27 +272,20 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
||||||
* Generate Verilog codes modeling an branch circuit
|
* Generate Verilog codes modeling an branch circuit
|
||||||
* for a multiplexer with the given size
|
* for a multiplexer with the given size
|
||||||
**********************************************/
|
**********************************************/
|
||||||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
static
|
||||||
|
void generate_verilog_mux_branch_module(ModuleManager& module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
|
std::fstream& fp,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
const MuxGraph& mux_graph) {
|
const MuxGraph& mux_graph) {
|
||||||
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, verilog_mux_basis_posfix);
|
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_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(circuit_model)) {
|
||||||
case SPICE_MODEL_DESIGN_CMOS:
|
case SPICE_MODEL_DESIGN_CMOS:
|
||||||
if (true == circuit_lib.dump_structural_verilog(circuit_model)) {
|
generate_verilog_cmos_mux_branch_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph,
|
||||||
generate_verilog_cmos_mux_branch_module_structural(fp, circuit_lib, circuit_model, module_name, mux_graph);
|
circuit_lib.dump_structural_verilog(circuit_model));
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
dump_verilog_cmos_mux_one_basis_module(fp, mux_basis_subckt_name,
|
|
||||||
mux_size,
|
|
||||||
num_input_basis_subckt,
|
|
||||||
cur_spice_model,
|
|
||||||
special_basis);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SPICE_MODEL_DESIGN_RRAM:
|
case SPICE_MODEL_DESIGN_RRAM:
|
||||||
/* If requested, we can dump structural verilog for basis module */
|
/* If requested, we can dump structural verilog for basis module */
|
||||||
|
@ -222,3 +310,68 @@ void generate_verilog_mux_branch_module(std::fstream& fp,
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Generate Verilog modules for all the unique
|
||||||
|
* multiplexers in the FPGA device
|
||||||
|
**********************************************/
|
||||||
|
void print_verilog_submodule_muxes(ModuleManager& module_manager,
|
||||||
|
const MuxLibrary& mux_lib,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
char* verilog_dir,
|
||||||
|
char* submodule_dir) {
|
||||||
|
|
||||||
|
/* TODO: Generate modules into a .bak file now. Rename after it is verified */
|
||||||
|
std::string verilog_fname(my_strcat(submodule_dir, muxes_verilog_file_name));
|
||||||
|
verilog_fname += ".bak";
|
||||||
|
|
||||||
|
/* Create the file stream */
|
||||||
|
std::fstream fp;
|
||||||
|
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||||
|
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
/* Print out debugging information for if the file is not opened/created properly */
|
||||||
|
vpr_printf(TIO_MESSAGE_INFO,
|
||||||
|
"Creating Verilog netlist for Multiplexers (%s) ...\n",
|
||||||
|
verilog_fname.c_str());
|
||||||
|
|
||||||
|
print_verilog_file_header(fp, "Multiplexers");
|
||||||
|
|
||||||
|
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||||
|
|
||||||
|
/* Generate basis sub-circuit for unique branches shared by the multiplexers */
|
||||||
|
for (auto mux : mux_lib.muxes()) {
|
||||||
|
const MuxGraph& mux_graph = mux_lib.mux_graph(mux);
|
||||||
|
CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux);
|
||||||
|
/* Create a mux graph for the branch circuit */
|
||||||
|
std::vector<MuxGraph> branch_mux_graphs = mux_graph.build_mux_branch_graphs();
|
||||||
|
/* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */
|
||||||
|
for (auto branch_mux_graph : branch_mux_graphs) {
|
||||||
|
generate_verilog_mux_branch_module(module_manager, circuit_lib, fp, mux_circuit_model,
|
||||||
|
mux_graph.num_inputs(), branch_mux_graph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump MUX graph one by one */
|
||||||
|
|
||||||
|
/* Close the file steam */
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* Scan-chain configuration circuit does not need any BLs/WLs!
|
||||||
|
* SRAM MUX does not need any reserved BL/WLs!
|
||||||
|
*/
|
||||||
|
/* Determine reserved Bit/Word Lines if a memory bank is specified,
|
||||||
|
* At least 1 BL/WL should be reserved!
|
||||||
|
*/
|
||||||
|
try_update_sram_orgz_info_reserved_blwl(cur_sram_orgz_info,
|
||||||
|
mux_lib.max_mux_size(), mux_lib.max_mux_size());
|
||||||
|
|
||||||
|
/* TODO: Add fname to the linked list when debugging is finished */
|
||||||
|
/*
|
||||||
|
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,13 @@
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
#include "mux_graph.h"
|
#include "mux_graph.h"
|
||||||
#include "mux_library.h"
|
#include "mux_library.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
|
||||||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
void print_verilog_submodule_muxes(ModuleManager& module_manager,
|
||||||
|
const MuxLibrary& mux_lib,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
const size_t& mux_size,
|
char* verilog_dir,
|
||||||
const MuxGraph& mux_graph);
|
char* submodule_dir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "fpga_x2p_globals.h"
|
#include "fpga_x2p_globals.h"
|
||||||
#include "fpga_x2p_mux_utils.h"
|
#include "fpga_x2p_mux_utils.h"
|
||||||
#include "fpga_x2p_bitstream_utils.h"
|
#include "fpga_x2p_bitstream_utils.h"
|
||||||
|
#include "mux_library.h"
|
||||||
|
|
||||||
/* Include verilog utils */
|
/* Include verilog utils */
|
||||||
#include "verilog_global.h"
|
#include "verilog_global.h"
|
||||||
|
@ -2232,7 +2233,9 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
/* Print the muxes netlist*/
|
/* Print the muxes netlist*/
|
||||||
fp = fopen(verilog_name, "w");
|
fp = fopen(verilog_name, "w");
|
||||||
if (NULL == fp) {
|
if (NULL == fp) {
|
||||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create subckt SPICE netlist %s",__FILE__, __LINE__, verilog_name);
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(FILE:%s,LINE[%d])Failure in create subckt SPICE netlist %s",
|
||||||
|
__FILE__, __LINE__, verilog_name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Generate the descriptions*/
|
/* Generate the descriptions*/
|
||||||
|
@ -2292,41 +2295,6 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
temp = temp->next;
|
temp = temp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate modules into a .bak file now. Rename after it is verified */
|
|
||||||
std::string verilog_fname(my_strcat(submodule_dir, muxes_verilog_file_name));
|
|
||||||
verilog_fname += ".bak";
|
|
||||||
|
|
||||||
/* Create the file stream */
|
|
||||||
std::fstream sfp;
|
|
||||||
sfp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
|
||||||
|
|
||||||
/* Print out debugging information for if the file is not opened/created properly */
|
|
||||||
vpr_printf(TIO_MESSAGE_INFO,
|
|
||||||
"Creating Verilog netlist for Multiplexers (%s) ...\n",
|
|
||||||
verilog_fname.c_str());
|
|
||||||
check_file_handler(sfp);
|
|
||||||
|
|
||||||
/* TODO: this conversion is temporary. Will be removed after code reconstruction */
|
|
||||||
MuxLibrary mux_lib = convert_mux_arch_to_library(spice->circuit_lib, muxes_head);
|
|
||||||
|
|
||||||
/* Generate basis sub-circuit for unique branches shared by the multiplexers */
|
|
||||||
for (auto mux : mux_lib.muxes()) {
|
|
||||||
const MuxGraph& mux_graph = mux_lib.mux_graph(mux);
|
|
||||||
CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux);
|
|
||||||
/* Create a mux graph for the branch circuit */
|
|
||||||
std::vector<MuxGraph> branch_mux_graphs = mux_graph.build_mux_branch_graphs();
|
|
||||||
/* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */
|
|
||||||
for (auto branch_mux_graph : branch_mux_graphs) {
|
|
||||||
generate_verilog_mux_branch_module(sfp, spice->circuit_lib, mux_circuit_model,
|
|
||||||
mux_graph.num_inputs(), branch_mux_graph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dump MUX graph one by one */
|
|
||||||
|
|
||||||
/* Close the file steam */
|
|
||||||
sfp.close();
|
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* Scan-chain configuration circuit does not need any BLs/WLs!
|
* Scan-chain configuration circuit does not need any BLs/WLs!
|
||||||
* SRAM MUX does not need any reserved BL/WLs!
|
* SRAM MUX does not need any reserved BL/WLs!
|
||||||
|
@ -3507,6 +3475,7 @@ void dump_verilog_submodule_templates(t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
* 1. MUXes
|
* 1. MUXes
|
||||||
*/
|
*/
|
||||||
void dump_verilog_submodules(ModuleManager& module_manager,
|
void dump_verilog_submodules(ModuleManager& module_manager,
|
||||||
|
const MuxLibrary& mux_lib,
|
||||||
t_sram_orgz_info* cur_sram_orgz_info,
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
char* verilog_dir,
|
char* verilog_dir,
|
||||||
char* submodule_dir,
|
char* submodule_dir,
|
||||||
|
@ -3514,7 +3483,6 @@ void dump_verilog_submodules(ModuleManager& module_manager,
|
||||||
t_det_routing_arch* routing_arch,
|
t_det_routing_arch* routing_arch,
|
||||||
t_syn_verilog_opts fpga_verilog_opts) {
|
t_syn_verilog_opts fpga_verilog_opts) {
|
||||||
|
|
||||||
/* 0. basic units: inverter, buffers and pass-gate logics, */
|
|
||||||
vpr_printf(TIO_MESSAGE_INFO, "Generating essential modules...\n");
|
vpr_printf(TIO_MESSAGE_INFO, "Generating essential modules...\n");
|
||||||
print_verilog_submodule_essentials(module_manager,
|
print_verilog_submodule_essentials(module_manager,
|
||||||
std::string(verilog_dir),
|
std::string(verilog_dir),
|
||||||
|
@ -3525,6 +3493,10 @@ void dump_verilog_submodules(ModuleManager& module_manager,
|
||||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n");
|
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n");
|
||||||
dump_verilog_submodule_muxes(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
dump_verilog_submodule_muxes(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
||||||
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
||||||
|
|
||||||
|
print_verilog_submodule_muxes(module_manager, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info,
|
||||||
|
verilog_dir, submodule_dir);
|
||||||
|
|
||||||
vpr_printf(TIO_MESSAGE_INFO, "Generating local encoders for multiplexers...\n");
|
vpr_printf(TIO_MESSAGE_INFO, "Generating local encoders for multiplexers...\n");
|
||||||
dump_verilog_submodule_local_encoders(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
dump_verilog_submodule_local_encoders(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
||||||
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
#define VERILOG_SUBMODULES_H
|
#define VERILOG_SUBMODULES_H
|
||||||
|
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
|
#include "mux_library.h"
|
||||||
|
|
||||||
void dump_verilog_submodules(ModuleManager& module_manager,
|
void dump_verilog_submodules(ModuleManager& module_manager,
|
||||||
|
const MuxLibrary& mux_lib,
|
||||||
t_sram_orgz_info* cur_sram_orgz_info,
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
char* verilog_dir,
|
char* verilog_dir,
|
||||||
char* submodule_dir,
|
char* submodule_dir,
|
||||||
|
|
|
@ -55,7 +55,7 @@ void print_verilog_include_defines_preproc_file(std::fstream& fp,
|
||||||
|
|
||||||
fp << "//------ Include defines: preproc flags -----" << std::endl;
|
fp << "//------ Include defines: preproc flags -----" << std::endl;
|
||||||
fp << "`include \"" << include_file_path << "\"" << std::endl;
|
fp << "`include \"" << include_file_path << "\"" << std::endl;
|
||||||
fp << "//------ End Include defines: preproc flags -----" << std::endl;
|
fp << "//------ End Include defines: preproc flags -----" << std::endl << std::endl;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ void print_verilog_module_definition(std::fstream& fp,
|
||||||
const std::string& module_name) {
|
const std::string& module_name) {
|
||||||
check_file_handler(fp);
|
check_file_handler(fp);
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("//----- Verilog module for " + module_name + " -----"));
|
print_verilog_comment(fp, std::string("----- Verilog module for " + module_name + " -----"));
|
||||||
fp << "module " << module_name << "(" << std::endl;
|
fp << "module " << module_name << "(" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +102,11 @@ void print_verilog_module_ports(std::fstream& fp,
|
||||||
for (const auto& port : module_manager.module_ports_by_type(module_id, kv.first)) {
|
for (const auto& port : module_manager.module_ports_by_type(module_id, kv.first)) {
|
||||||
if (0 != port_cnt) {
|
if (0 != port_cnt) {
|
||||||
/* Do not dump a comma for the first port */
|
/* Do not dump a comma for the first port */
|
||||||
fp << ", //----- " << module_manager.module_port_type_str(kv.first) << " -----" << std::endl;
|
fp << "," << std::endl;
|
||||||
}
|
}
|
||||||
/* Print port */
|
/* Print port */
|
||||||
fp << "\t" << generate_verilog_port(kv.second, port) << std::endl;
|
fp << "\t//----- " << module_manager.module_port_type_str(kv.first) << " -----" << std::endl;
|
||||||
|
fp << "\t" << generate_verilog_port(kv.second, port);
|
||||||
port_cnt++;
|
port_cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +126,64 @@ void print_verilog_module_declaration(std::fstream& fp,
|
||||||
fp << std::endl << ");" << std::endl;
|
fp << std::endl << ");" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* Print an instance for a Verilog module
|
||||||
|
***********************************************/
|
||||||
|
void print_verilog_module_instance(std::fstream& fp,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module_id, const ModuleId& child_module_id,
|
||||||
|
const std::map<std::string, BasicPort>& port2port_name_map,
|
||||||
|
const bool& explicit_port_map) {
|
||||||
|
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
/* Print module name */
|
||||||
|
fp << "\t" << module_manager.module_name(child_module_id) << " ";
|
||||||
|
/* Print instance name, <name>_<num_instance_in_parent_module> */
|
||||||
|
fp << module_manager.module_name(child_module_id) << "_" << module_manager.num_instance(parent_module_id, child_module_id) << "_" << " (" << std::endl;
|
||||||
|
|
||||||
|
/* Print each port with/without explicit port map */
|
||||||
|
/* port type2type mapping */
|
||||||
|
std::map<ModuleManager::e_module_port_type, enum e_dump_verilog_port_type> port_type2type_map;
|
||||||
|
port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_CONKT;
|
||||||
|
port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_CONKT;
|
||||||
|
port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_CONKT;
|
||||||
|
port_type2type_map[ModuleManager::MODULE_OUTPUT_PORT] = VERILOG_PORT_CONKT;
|
||||||
|
port_type2type_map[ModuleManager::MODULE_CLOCK_PORT] = VERILOG_PORT_CONKT;
|
||||||
|
|
||||||
|
/* Port sequence: global, inout, input, output and clock ports, */
|
||||||
|
size_t port_cnt = 0;
|
||||||
|
for (const auto& kv : port_type2type_map) {
|
||||||
|
for (const auto& port : module_manager.module_ports_by_type(child_module_id, kv.first)) {
|
||||||
|
if (0 != port_cnt) {
|
||||||
|
/* Do not dump a comma for the first port */
|
||||||
|
fp << "," << std::endl;
|
||||||
|
}
|
||||||
|
/* Print port */
|
||||||
|
fp << "\t\t";
|
||||||
|
/* if explicit port map is required, output the port name */
|
||||||
|
if (true == explicit_port_map) {
|
||||||
|
fp << "." << port.get_name() << "(";
|
||||||
|
}
|
||||||
|
/* Try to find the instanced port name in the name map */
|
||||||
|
if (port2port_name_map.find(port.get_name()) != port2port_name_map.end()) {
|
||||||
|
/* Found it, we assign the port name */
|
||||||
|
fp << generate_verilog_port(kv.second, port2port_name_map.at(port.get_name()));
|
||||||
|
} else {
|
||||||
|
/* Not found, we give the default port name */
|
||||||
|
fp << generate_verilog_port(kv.second, port);
|
||||||
|
}
|
||||||
|
/* if explicit port map is required, output the pair of branket */
|
||||||
|
if (true == explicit_port_map) {
|
||||||
|
fp << ")";
|
||||||
|
}
|
||||||
|
port_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print an end to the instance */
|
||||||
|
fp << "\t" << ");" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
* Print an end line for a Verilog module
|
* Print an end line for a Verilog module
|
||||||
|
@ -134,7 +193,7 @@ void print_verilog_module_end(std::fstream& fp,
|
||||||
check_file_handler(fp);
|
check_file_handler(fp);
|
||||||
|
|
||||||
fp << "endmodule" << std::endl;
|
fp << "endmodule" << std::endl;
|
||||||
print_verilog_comment(fp, std::string("//----- END Verilog module for " + module_name + " -----"));
|
print_verilog_comment(fp, std::string("----- END Verilog module for " + module_name + " -----"));
|
||||||
fp << std::endl;
|
fp << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,12 @@ void print_verilog_module_ports(std::fstream& fp,
|
||||||
void print_verilog_module_declaration(std::fstream& fp,
|
void print_verilog_module_declaration(std::fstream& fp,
|
||||||
const ModuleManager& module_manager, const ModuleId& module_id);
|
const ModuleManager& module_manager, const ModuleId& module_id);
|
||||||
|
|
||||||
|
void print_verilog_module_instance(std::fstream& fp,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module_id, const ModuleId& child_module_id,
|
||||||
|
const std::map<std::string, BasicPort>& port2port_name_map,
|
||||||
|
const bool& explicit_port_map);
|
||||||
|
|
||||||
void print_verilog_module_end(std::fstream& fp,
|
void print_verilog_module_end(std::fstream& fp,
|
||||||
const std::string& module_name);
|
const std::string& module_name);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue