diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml new file mode 100644 index 000000000..4d26f30ad --- /dev/null +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml @@ -0,0 +1,1042 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + 10e-12 10e-12 + + + 10e-12 10e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255e-12 + 255e-12 + 255e-12 + 255e-12 + 255e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202e-12 + 202e-12 + 202e-12 + 202e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.cin clb.cin_trick clb.regin clb.clk + clb.I0[9:0] clb.I1[9:0] clb.O[9:0] + clb.cout clb.regout clb.I2[9:0] clb.I3[9:0] clb.O[19:10] + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf index d766554b4..d796d6c8a 100644 --- a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf +++ b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf @@ -18,6 +18,8 @@ fpga_flow=vpr_blif # 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 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] 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_chan_width = 300 -[SCRIPT_PARAM_1] +[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH] fix_route_chan_width=300 vpr_fpga_verilog_include_icarus_simulator= vpr_fpga_verilog_formal_verification_top_netlist= @@ -44,17 +46,17 @@ vpr_fpga_x2p_compact_routing_hierarchy= end_flow_with_test= -# [SCRIPT_PARAM_2] -# fix_route_chan_width=200 -# vpr_fpga_verilog_include_icarus_simulator= -# vpr_fpga_verilog_formal_verification_top_netlist= -# vpr_fpga_verilog_include_timing= -# vpr_fpga_verilog_include_signal_init= -# vpr_fpga_verilog_print_autocheck_top_testbench= -# vpr_fpga_bitstream_generator= -# vpr_fpga_verilog_print_user_defined_template= -# vpr_fpga_verilog_print_report_timing_tcl= -# vpr_fpga_verilog_print_sdc_pnr= -# vpr_fpga_verilog_print_sdc_analysis= -# vpr_fpga_x2p_compact_routing_hierarchy= -# end_flow_with_test= \ No newline at end of file +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +min_route_chan_width=1.3 +vpr_fpga_verilog_include_icarus_simulator= +vpr_fpga_verilog_formal_verification_top_netlist= +vpr_fpga_verilog_include_timing= +vpr_fpga_verilog_include_signal_init= +vpr_fpga_verilog_print_autocheck_top_testbench= +vpr_fpga_bitstream_generator= +vpr_fpga_verilog_print_user_defined_template= +vpr_fpga_verilog_print_report_timing_tcl= +vpr_fpga_verilog_print_sdc_pnr= +vpr_fpga_verilog_print_sdc_analysis= +vpr_fpga_x2p_compact_routing_hierarchy= +end_flow_with_test= diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp index a6879d770..281747188 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp @@ -67,6 +67,18 @@ size_t MuxGraph::num_inputs() const { return num_inputs; } +/* Return the node ids of all the inputs of the multiplexer */ +std::vector MuxGraph::inputs() const { + std::vector 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 */ size_t MuxGraph::num_outputs() const { /* need to check if the graph is valid or not */ @@ -79,6 +91,36 @@ size_t MuxGraph::num_outputs() const { return num_outputs; } +/* Return the node ids of all the outputs of the multiplexer */ +std::vector MuxGraph::outputs() const { + std::vector 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 MuxGraph::find_edges(const MuxNodeId& from_node, const MuxNodeId& to_node) const { + std::vector 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 */ size_t MuxGraph::num_levels() const { @@ -95,6 +137,20 @@ size_t MuxGraph::num_memory_bits() const { 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 */ std::vector MuxGraph::branch_sizes() const { std::vector branch; @@ -147,6 +203,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const { /* Add output nodes to subgraph */ MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE); mux_graph.node_levels_[to_node_subgraph] = 1; + mux_graph.node_output_ids_[to_node_subgraph] = MuxOutputId(0); /* Update the node-to-node map */ 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 */ MuxMemId mem_subgraph = mux_graph.add_mem(); 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 */ @@ -241,6 +300,24 @@ std::vector MuxGraph::build_mux_branch_graphs() const { 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 */ MuxNodeId MuxGraph::node_id(const MuxInputId& input_id) const { /* Use the node_lookup to accelerate the search */ @@ -287,7 +364,10 @@ std::vector MuxGraph::decode_memory_bits(const MuxInputId& input_id) con /* Visit the next node */ next_node = edge_sink_nodes_[edge][0]; } + + /* valid the output */ VTR_ASSERT_SAFE(MUX_OUTPUT_NODE == node_types_[next_node]); + VTR_ASSERT_SAFE(valid_output_id(node_output_ids_[next_node])); 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 */ node_types_.push_back(node_type); node_input_ids_.push_back(MuxInputId::INVALID()); + node_output_ids_.push_back(MuxOutputId::INVALID()); node_levels_.push_back(-1); node_in_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 */ MuxNodeId output_node = add_node(MUX_OUTPUT_NODE); node_levels_[output_node] = num_levels; + node_output_ids_[output_node] = MuxOutputId(0); /* Update node lookup */ 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); node_levels_[output_node] = 1; + node_output_ids_[output_node] = MuxOutputId(0); for (size_t i = 0; i < mux_size; ++i) { 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; } -/* 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 { for (const auto& lvl : node_lookup_) { for (const auto& node : lvl[MUX_INPUT_NODE]) { @@ -677,6 +760,19 @@ bool MuxGraph::valid_input_id(const MuxInputId& input_id) const { 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 { return node_lookup_.empty(); } diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.h b/vpr7_x2p/vpr/SRC/device/mux_graph.h index 0b76da5da..10f758809 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.h +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.h @@ -63,12 +63,20 @@ class MuxGraph { public: /* Public accessors: Data query */ /* Find the number of inputs in the MUX graph */ size_t num_inputs() const; + std::vector inputs() const; /* Find the number of outputs in the MUX graph */ size_t num_outputs() const; + std::vector outputs() const; + /* Find the edge between two MUX nodes */ + std::vector find_edges(const MuxNodeId& from_node, const MuxNodeId& to_node) const; /* Find the number of levels in the MUX graph */ size_t num_levels() const; /* Find the number of SRAMs in the MUX graph */ 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 */ std::vector branch_sizes() const; /* Generate MUX graphs for its branches */ @@ -76,6 +84,10 @@ class MuxGraph { std::vector build_mux_branch_graphs() const; /* Get the node id of a given input */ 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 */ std::vector decode_memory_bits(const MuxInputId& input_id) const; private: /* Private mutators : basic operations */ @@ -106,6 +118,7 @@ class MuxGraph { bool valid_edge_id(const MuxEdgeId& edge) const; bool valid_mem_id(const MuxMemId& mem) const; bool valid_input_id(const MuxInputId& input_id) const; + bool valid_output_id(const MuxOutputId& output_id) const; /* validate/invalidate node lookup */ bool valid_node_lookup() const; void invalidate_node_lookup(); @@ -115,6 +128,7 @@ class MuxGraph { vtr::vector node_ids_; /* Unique ids for each node */ vtr::vector node_types_; /* type of each node, input/output/internal */ vtr::vector node_input_ids_; /* Unique ids for each node as an input of the MUX */ + vtr::vector node_output_ids_; /* Unique ids for each node as an input of the MUX */ vtr::vector node_levels_; /* at which level, each node belongs to */ vtr::vector> node_in_edges_; /* ids of incoming edges to each node */ vtr::vector> node_out_edges_; /* ids of outgoing edges from each node */ diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph_fwd.h b/vpr7_x2p/vpr/SRC/device/mux_graph_fwd.h index 815102e6d..fca07ca2a 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph_fwd.h +++ b/vpr7_x2p/vpr/SRC/device/mux_graph_fwd.h @@ -13,11 +13,13 @@ struct mux_node_id_tag; struct mux_edge_id_tag; struct mux_mem_id_tag; struct mux_input_id_tag; +struct mux_output_id_tag; typedef vtr::StrongId MuxNodeId; typedef vtr::StrongId MuxEdgeId; typedef vtr::StrongId MuxMemId; typedef vtr::StrongId MuxInputId; +typedef vtr::StrongId MuxOutputId; class MuxGraph; diff --git a/vpr7_x2p/vpr/SRC/device/mux_library.cpp b/vpr7_x2p/vpr/SRC/device/mux_library.cpp index 04ef5c378..ee51b087b 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_library.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_library.cpp @@ -43,6 +43,16 @@ CircuitModelId MuxLibrary::mux_circuit_model(const MuxId& mux_id) const { 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: *************************************************/ diff --git a/vpr7_x2p/vpr/SRC/device/mux_library.h b/vpr7_x2p/vpr/SRC/device/mux_library.h index 7ffefba09..8f4ec71d8 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_library.h +++ b/vpr7_x2p/vpr/SRC/device/mux_library.h @@ -27,6 +27,8 @@ class MuxLibrary { const MuxGraph& mux_graph(const MuxId& mux_id) const; /* Get a mux circuit model id */ CircuitModelId mux_circuit_model(const MuxId& mux_id) const; + /* Find the maximum mux size */ + size_t max_mux_size() const; public: /* Public mutators */ /* Add a mux to the library */ void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size); diff --git a/vpr7_x2p/vpr/SRC/device/mux_library_builder.cpp b/vpr7_x2p/vpr/SRC/device/mux_library_builder.cpp new file mode 100644 index 000000000..9dc462572 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/mux_library_builder.cpp @@ -0,0 +1,186 @@ +/******************************************************************** + * This file includes the functions of builders for MuxLibrary. + *******************************************************************/ +#include +#include +#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 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; +} + + + diff --git a/vpr7_x2p/vpr/SRC/device/mux_library_builder.h b/vpr7_x2p/vpr/SRC/device/mux_library_builder.h new file mode 100644 index 000000000..8a0965dd4 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/mux_library_builder.h @@ -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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp index 0881d5221..769a49dad 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp @@ -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, const CircuitModelId& circuit_model, const size_t& mux_size, + const size_t& branch_mux_size, const std::string& postfix) { /* 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 @@ -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)); 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); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h index ff91f4854..bd67c61f4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h @@ -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, const CircuitModelId& circuit_model, const size_t& mux_size, + const size_t& branch_mux_size, const std::string& posfix); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp index 6ec50b62b..5b56823c1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp @@ -50,6 +50,32 @@ std::vector ModuleManager::module_ports_by_type(const ModuleId& modul 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 ******************************************************************************/ @@ -69,6 +95,7 @@ ModuleId ModuleManager::add_module(const std::string& name) { names_.push_back(name); parents_.emplace_back(); children_.emplace_back(); + num_child_instances_.emplace_back(); port_ids_.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); } - std::vector::iterator child_it = std::find(children_[child_module].begin(), children_[child_module].end(), child_module); + std::vector::iterator child_it = std::find(children_[parent_module].begin(), children_[parent_module].end(), child_module); if (child_it == children_[parent_module].end()) { /* Update the child module of parent 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()]++; } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h index a73204daf..a3be0e5a8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h @@ -37,6 +37,9 @@ class ModuleManager { 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::vector 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 */ /* Add a module */ ModuleId add_module(const std::string& name); @@ -55,6 +58,7 @@ class ModuleManager { vtr::vector names_; /* Unique identifier for each Module */ vtr::vector> parents_; /* Parent modules that include the module */ vtr::vector> children_; /* Child modules that this module contain */ + vtr::vector> num_child_instances_; /* Number of children instance in each child module */ vtr::vector> port_ids_; /* List of ports for each Module */ vtr::vector> ports_; /* List of ports for each Module */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index abbae27ac..a6257608a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -33,6 +33,8 @@ #include "fpga_bitstream.h" #include "module_manager.h" +#include "mux_library.h" +#include "mux_library_builder.h" /* Include SynVerilog headers */ #include "verilog_global.h" @@ -153,6 +155,10 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, /* Module manager for the Verilog modules created */ 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*/ if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) { 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); /* 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, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp index 8aba48226..a94828c5e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp @@ -507,7 +507,7 @@ void print_verilog_submodule_essentials(ModuleManager& module_manager, /* Create file */ vpr_printf(TIO_MESSAGE_INFO, "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"); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index dce86830a..70ca6f78d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -12,6 +12,7 @@ /* Device-level header files */ #include "mux_graph.h" +#include "module_manager.h" #include "physical_types.h" #include "vpr_types.h" @@ -25,16 +26,169 @@ #include "verilog_writer_utils.h" #include "verilog_mux.h" -/*********************************************** - * Generate Verilog codes modeling an branch circuit +/********************************************************************* + * 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_module_structural(std::fstream& fp, - const CircuitLibrary& circuit_lib, - const CircuitModelId& circuit_model, - const std::string& module_name, - const MuxGraph& mux_graph) { +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 tgate_input_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true); + std::vector 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 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 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 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 + * for a multiplexer with the given size + * Support structural and behavioral Verilog codes + *********************************************************************/ +static +void generate_verilog_cmos_mux_branch_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + std::fstream& fp, + const CircuitModelId& circuit_model, + const std::string& module_name, + const MuxGraph& mux_graph, + const bool& use_structural_verilog) { /* Get the tgate 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; } - /* Get model ports of tgate */ - std::vector tgate_input_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true); - std::vector tgate_output_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_OUTPUT, true); std::vector 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*/ 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*/ VTR_ASSERT(1 == mux_graph.num_levels()); - /* Print Verilog module */ - print_verilog_module_definition(fp, module_name); - - /* Create port information */ - /* Configure each input 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 */ + /* Create a Verilog Module based on the circuit model, and add to module manager */ + ModuleId module_id = module_manager.add_module(module_name); + VTR_ASSERT(ModuleId::INVALID() != module_id); + /* Add module ports */ + /* Add each global port */ for (const auto& port : tgate_global_ports) { /* Configure each global port */ - BasicPort basic_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - /* Print port */ - fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl; + BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); } + /* Add each input port */ + BasicPort input_port("in", num_inputs); + 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 */ - fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, input_port) << "," << std::endl; - fp << "\t" << generate_verilog_port(VERILOG_PORT_OUTPUT, output_port) << "," << std::endl; - 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 { - fp << " ("; - fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port); - fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port); - fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port); - fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port); - fp << ");" << std::endl; - } - /* 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) << "_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; - } + /* Print the internal logic in either structural or behavioral Verilog codes */ + if (true == use_structural_verilog) { + generate_verilog_cmos_mux_branch_body_structural(module_manager, circuit_lib, fp, tgate_model, module_id, input_port, output_port, mem_port, mem_inv_port, mux_graph); } else { - /* 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; + VTR_ASSERT_SAFE(false == use_structural_verilog); + /* Get the default value of SRAM ports */ + std::vector sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true); + std::vector non_mode_select_sram_ports; + /* We should have only have 1 sram port except those are mode_bits */ + for (const auto& port : sram_ports) { + if (true == circuit_lib.port_is_mode_select(port)) { + continue; } + non_mode_select_sram_ports.push_back(port); } + VTR_ASSERT(1 == non_mode_select_sram_ports.size()); + std::string mem_default_val = std::to_string(circuit_lib.port_default_value(non_mode_select_sram_ports[0])); + /* Mem string must be only 1-bit! */ + 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 */ @@ -177,27 +272,20 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp, * Generate Verilog codes modeling an branch circuit * 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, + std::fstream& fp, const CircuitModelId& circuit_model, const size_t& mux_size, 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 */ switch (circuit_lib.design_tech_type(circuit_model)) { case SPICE_MODEL_DESIGN_CMOS: - if (true == circuit_lib.dump_structural_verilog(circuit_model)) { - generate_verilog_cmos_mux_branch_module_structural(fp, circuit_lib, circuit_model, module_name, mux_graph); - } else { - /* - dump_verilog_cmos_mux_one_basis_module(fp, mux_basis_subckt_name, - mux_size, - num_input_basis_subckt, - cur_spice_model, - special_basis); - */ - } + generate_verilog_cmos_mux_branch_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph, + circuit_lib.dump_structural_verilog(circuit_model)); break; case SPICE_MODEL_DESIGN_RRAM: /* If requested, we can dump structural verilog for basis module */ @@ -222,3 +310,68 @@ void generate_verilog_mux_branch_module(std::fstream& fp, 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 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); + */ +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h index c7dfd4bf8..8b30d6820 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.h @@ -11,11 +11,13 @@ #include "circuit_library.h" #include "mux_graph.h" #include "mux_library.h" +#include "module_manager.h" -void generate_verilog_mux_branch_module(std::fstream& fp, - const CircuitLibrary& circuit_lib, - const CircuitModelId& circuit_model, - const size_t& mux_size, - const MuxGraph& mux_graph); +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); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index 230306d3c..7bd065cbe 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -29,6 +29,7 @@ #include "fpga_x2p_globals.h" #include "fpga_x2p_mux_utils.h" #include "fpga_x2p_bitstream_utils.h" +#include "mux_library.h" /* Include verilog utils */ #include "verilog_global.h" @@ -2228,11 +2229,13 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info, /* Alloc the muxes*/ muxes_head = stats_spice_muxes(num_switch, switches, spice, routing_arch); - + /* Print the muxes netlist*/ fp = fopen(verilog_name, "w"); 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); } /* Generate the descriptions*/ @@ -2292,41 +2295,6 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info, 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 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: * Scan-chain configuration circuit does not need any BLs/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 */ void dump_verilog_submodules(ModuleManager& module_manager, + const MuxLibrary& mux_lib, t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, @@ -3514,7 +3483,6 @@ void dump_verilog_submodules(ModuleManager& module_manager, t_det_routing_arch* routing_arch, 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"); print_verilog_submodule_essentials(module_manager, 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"); 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); + + 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"); 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); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.h index 1e6aa814b..3d6a30e99 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.h @@ -2,8 +2,10 @@ #define VERILOG_SUBMODULES_H #include "module_manager.h" +#include "mux_library.h" void dump_verilog_submodules(ModuleManager& module_manager, + const MuxLibrary& mux_lib, t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* submodule_dir, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp index 81c9bed5f..8747b8c18 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp @@ -55,7 +55,7 @@ void print_verilog_include_defines_preproc_file(std::fstream& fp, fp << "//------ Include defines: preproc flags -----" << 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; } @@ -77,7 +77,7 @@ void print_verilog_module_definition(std::fstream& fp, const std::string& module_name) { 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; } @@ -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)) { if (0 != port_cnt) { /* 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 */ - 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++; } } @@ -125,6 +126,64 @@ void print_verilog_module_declaration(std::fstream& fp, 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& 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, _ */ + 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 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 @@ -134,7 +193,7 @@ void print_verilog_module_end(std::fstream& fp, check_file_handler(fp); 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; } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h index 3f65fb726..03626e4b6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h @@ -28,6 +28,12 @@ void print_verilog_module_ports(std::fstream& fp, void print_verilog_module_declaration(std::fstream& fp, 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& port2port_name_map, + const bool& explicit_port_map); + void print_verilog_module_end(std::fstream& fp, const std::string& module_name);