diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp index eb978750c..30a4c9b51 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp @@ -3,6 +3,7 @@ * data structures in mux_graph.h *************************************************/ #include +#include #include #include "util.h" @@ -15,7 +16,7 @@ *************************************************/ /************************************************** - * Constructor + * Public Constructors *************************************************/ /* Create an object based on a Circuit Model which is MUX */ @@ -26,20 +27,28 @@ MuxGraph::MuxGraph(const CircuitLibrary& circuit_lib, build_mux_graph(circuit_lib, circuit_model, mux_size); } +/************************************************** + * Private Constructors + *************************************************/ +/* Create an empty graph */ +MuxGraph::MuxGraph() { + return; +} + /************************************************** * Public Accessors : Aggregates *************************************************/ //Accessors MuxGraph::node_range MuxGraph::nodes() const { - return vtr::make_range(node_ids_.begin(), node_ids_.end()); + return vtr::make_range(node_ids_.begin(), node_ids_.end()); } MuxGraph::edge_range MuxGraph::edges() const { - return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); + return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); } MuxGraph::mem_range MuxGraph::memories() const { - return vtr::make_range(mem_ids_.begin(), mem_ids_.end()); + return vtr::make_range(mem_ids_.begin(), mem_ids_.end()); } /************************************************** @@ -93,7 +102,7 @@ std::vector MuxGraph::branch_sizes() const { std::vector::iterator it; it = std::find(branch.begin(), branch.end(), branch_size); /* if already exists a branch with the same size, skip updating the vector */ - if (it == branch.end()) { + if (it != branch.end()) { continue; } branch.push_back(branch_size); @@ -105,6 +114,117 @@ std::vector MuxGraph::branch_sizes() const { return branch; } +/* Build a subgraph from the given node + * The strategy is very simple, we just + * extract a 1-level graph from here + */ +MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const { + /* Validate the node */ + VTR_ASSERT_SAFE(this->valid_node_id(root_node)); + + /* Generate an empty graph */ + MuxGraph mux_graph; + + /* A map to record node-to-node mapping from origin graph to subgraph */ + std::map node2node_map; + + /* A map to record edge-to-edge mapping from origin graph to subgraph */ + std::map edge2edge_map; + + /* Add output nodes to subgraph */ + MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE); + mux_graph.node_levels_[to_node_subgraph] = 0; + /* Update the node-to-node map */ + node2node_map[root_node] = to_node_subgraph; + + /* Add input nodes and edges to subgraph */ + size_t input_cnt = 0; + for (auto edge_origin : this->node_in_edges_[root_node]) { + VTR_ASSERT_SAFE(1 == edge_src_nodes_[edge_origin].size()); + /* Add nodes */ + MuxNodeId from_node_origin = this->edge_src_nodes_[edge_origin][0]; + MuxNodeId from_node_subgraph = mux_graph.add_node(MUX_INPUT_NODE); + /* Configure the nodes */ + mux_graph.node_levels_[from_node_subgraph] = 0; + mux_graph.node_input_ids_[from_node_subgraph] = MuxInputId(input_cnt); + input_cnt++; + /* Update the node-to-node map */ + node2node_map[from_node_origin] = from_node_subgraph; + + /* Add edges */ + MuxEdgeId edge_subgraph = mux_graph.add_edge(node2node_map[from_node_origin], node2node_map[root_node]); + edge2edge_map[edge_origin] = edge_subgraph; + /* Configure edges */ + mux_graph.edge_types_[edge_subgraph] = this->edge_types_[edge_origin]; + mux_graph.edge_inv_mem_[edge_subgraph] = this->edge_inv_mem_[edge_origin]; + } + + /* A map to record mem-to-mem mapping from origin graph to subgraph */ + std::map mem2mem_map; + + /* Add memory bits and configure edges */ + for (auto edge_origin : this->node_in_edges_[root_node]) { + MuxMemId mem_origin = this->edge_mem_ids_[edge_origin]; + /* Try to find if the mem is already in the list */ + std::map::iterator it = mem2mem_map.find(mem_origin); + if (it != mem2mem_map.end()) { + /* Found, we skip mem addition. But make sure we have a valid one */ + VTR_ASSERT_SAFE(MuxMemId::INVALID() != mem2mem_map[mem_origin]); + /* configure the edge */ + mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem2mem_map[mem_origin]; + continue; + } + /* 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; + } + + return mux_graph; +} + +/* Generate MUX graphs for its branches + * Similar to the branch_sizes() method, + * we search all the internal nodes and + * find out what are the input sizes of + * the branches. + * Then we extract unique subgraphs and return + */ +std::vector MuxGraph::build_mux_branch_graphs() const { + std::map branch_done; /* A map showing the status of graph generation */ + + std::vector branch_graphs; + + /* Visit each internal nodes/output nodes and find the the number of incoming edges */ + for (auto node : node_ids_ ) { + /* Bypass input nodes */ + if ( (MUX_OUTPUT_NODE != node_types_[node]) + && (MUX_INTERNAL_NODE != node_types_[node]) ) { + continue; + } + + size_t branch_size = node_in_edges_[node].size(); + + /* make sure the branch size is valid */ + VTR_ASSERT_SAFE(valid_mux_implementation_num_inputs(branch_size)); + + /* check if the branch have been done in sub-graph extraction! */ + std::map::iterator it = branch_done.find(branch_size); + /* if it is done, we can skip */ + if (it != branch_done.end()) { + VTR_ASSERT(branch_done[branch_size]); + continue; + } + + /* Generate a subgraph and push back */ + branch_graphs.push_back(subgraph(node)); + + /* Mark it is done for this branch size */ + branch_done[branch_size] = true; + } + + return branch_graphs; +} + /* 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 */ diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.h b/vpr7_x2p/vpr/SRC/device/mux_graph.h index dad40aaf7..fc5dd1f98 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.h +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.h @@ -48,11 +48,14 @@ class MuxGraph { typedef vtr::Range node_range; typedef vtr::Range edge_range; typedef vtr::Range mem_range; - public: /* Constructors */ + public: /* Public Constructors */ /* Create an object based on a Circuit Model which is MUX */ MuxGraph(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size); + private: /* Private Constructors*/ + /* Create an empty graph */ + MuxGraph(); public: /* Public accessors: Aggregates */ node_range nodes() const; edge_range edges() const; @@ -66,6 +69,9 @@ class MuxGraph { size_t num_memory_bits() const; /* Find the sizes of each branch of a MUX */ std::vector branch_sizes() const; + /* Generate MUX graphs for its branches */ + MuxGraph subgraph(const MuxNodeId& node) const; + std::vector build_mux_branch_graphs() const; /* Get the node id of a given input */ MuxNodeId node_id(const MuxInputId& input_id) const; /* Decode memory bits based on an input id */ diff --git a/vpr7_x2p/vpr/SRC/device/mux_library.cpp b/vpr7_x2p/vpr/SRC/device/mux_library.cpp index 717d1aac7..04ef5c378 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_library.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_library.cpp @@ -11,6 +11,12 @@ * Member functions for the class MuxLibrary *************************************************/ +/************************************************** + * Public accessors: aggregates + *************************************************/ +MuxLibrary::mux_range MuxLibrary::muxes() const { + return vtr::make_range(mux_ids_.begin(), mux_ids_.end()); +} /************************************************** * Public accessors: data query @@ -31,6 +37,12 @@ const MuxGraph& MuxLibrary::mux_graph(const MuxId& mux_id) const { return mux_graphs_[mux_id]; } +/* Get a mux circuit model id */ +CircuitModelId MuxLibrary::mux_circuit_model(const MuxId& mux_id) const { + VTR_ASSERT_SAFE(valid_mux_id(mux_id)); + return mux_circuit_models_[mux_id]; +} + /************************************************** * Private mutators: *************************************************/ @@ -47,6 +59,8 @@ void MuxLibrary::add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId mux_ids_.push_back(mux); /* Add a mux graph */ mux_graphs_.push_back(MuxGraph(circuit_lib, circuit_model, mux_size)); + /* Recorde mux cirucit model id */ + mux_circuit_models_.push_back(circuit_model); /* update mux_lookup*/ mux_lookup_[circuit_model][mux_size] = mux; diff --git a/vpr7_x2p/vpr/SRC/device/mux_library.h b/vpr7_x2p/vpr/SRC/device/mux_library.h index 3c3b0329a..7ffefba09 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_library.h +++ b/vpr7_x2p/vpr/SRC/device/mux_library.h @@ -15,10 +15,18 @@ #include "mux_library_fwd.h" class MuxLibrary { + public: /* Types and ranges */ + typedef vtr::vector::const_iterator mux_iterator; + + typedef vtr::Range mux_range; + public: /* Public accessors: Aggregates */ + mux_range muxes() const; public: /* Public accessors */ /* Get a MUX graph (read-only) */ MuxId mux_graph(const CircuitModelId& circuit_model, const size_t& mux_size) const; const MuxGraph& mux_graph(const MuxId& mux_id) const; + /* Get a mux circuit model id */ + CircuitModelId mux_circuit_model(const MuxId& mux_id) 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); @@ -35,6 +43,7 @@ class MuxLibrary { /* MUX graph-based desription */ vtr::vector mux_ids_; /* Unique identifier for each mux graph */ vtr::vector mux_graphs_; /* Graphs describing MUX internal structures */ + vtr::vector mux_circuit_models_; /* circuit model id in circuit library */ /* Local encoder description */ //vtr::vector mux_local_encoders_; /* Graphs describing MUX internal structures */ diff --git a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp index cc5b04ec8..29cb0e5ec 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp @@ -156,4 +156,3 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis return mux_lib; } - diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.cpp new file mode 100644 index 000000000..e5fe1cc66 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.cpp @@ -0,0 +1,72 @@ +/*********************************************** + * This file includes functions to generate + * Verilog submodules for multiplexers. + * including both fundamental submodules + * such as a branch in a multiplexer + * and the full multiplexer + **********************************************/ + +#include "util.h" +#include "vtr_assert.h" + +#include "verilog_submodule_mux.h" + + +/*********************************************** + * Generate Verilog codes 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 MuxGraph& mux_graph) { + return; +} + +/*********************************************** + * Generate Verilog codes modeling an branch circuit + * for a multiplexer with the given size + **********************************************/ +void generate_verilog_mux_branch_module(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model, + const MuxGraph& mux_graph) { + /* 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, 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); + */ + } + break; + case SPICE_MODEL_DESIGN_RRAM: + /* If requested, we can dump structural verilog for basis module */ + /* + if (true == circuit_lib.dump_structural_verilog(circuit_model)) { + dump_verilog_rram_mux_one_basis_module_structural(fp, mux_basis_subckt_name, + num_input_basis_subckt, + cur_spice_model); + } else { + dump_verilog_rram_mux_one_basis_module(fp, mux_basis_subckt_name, + num_input_basis_subckt, + cur_spice_model); + } + */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n", + __FILE__, __LINE__, circuit_lib.circuit_model_name(circuit_model)); + exit(1); + } + + return; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.h new file mode 100644 index 000000000..6e7e84b30 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_mux.h @@ -0,0 +1,20 @@ +/*********************************************** + * Header file for verilog_submodule_mux.cpp + **********************************************/ + +#ifndef VERILOG_SUBMODULE_MUX_H +#define VERILOG_SUBMODULE_MUX_H + +/* Include other header files which are dependency on the function declared below */ +#include + +#include "circuit_library.h" +#include "mux_graph.h" +#include "mux_library.h" + +void generate_verilog_mux_branch_module(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model, + const MuxGraph& mux_graph); + +#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 d9183c91e..c1f2944f9 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -39,6 +39,7 @@ #include "verilog_submodules.h" #include "mux_utils.h" +#include "verilog_submodule_mux.h" /***** Subroutines *****/ @@ -2765,9 +2766,6 @@ 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); - /* TODO: this is temporary. Will be removed after code reconstruction */ - MuxLibrary mux_lib = convert_mux_arch_to_library(spice->circuit_lib, muxes_head); - /* Print the muxes netlist*/ fp = fopen(verilog_name, "w"); if (NULL == fp) { @@ -2831,6 +2829,40 @@ 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, 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! diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c index 947bee272..dc62b3797 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c @@ -144,6 +144,17 @@ void dump_include_user_defined_verilog_netlists(FILE* fp, return; } +void check_file_handler(const std::fstream& fp) { + /* Make sure we have a valid file handler*/ + /* Print out debugging information for if the file is not opened/created properly */ + if (!fp.is_open() || !fp.good()) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Failure in create file!\n", + __FILE__, __LINE__); + exit(1); + } +} + void dump_verilog_file_header(FILE* fp, char* usage) { if (NULL == fp) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h index 0a10d29a8..06aaba142 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h @@ -1,6 +1,8 @@ #ifndef VERILOG_UTILS_H #define VERILOG_UTILS_H +#include + void init_list_include_verilog_netlists(t_spice* spice); void init_include_user_defined_verilog_netlists(t_spice spice); @@ -8,6 +10,8 @@ void init_include_user_defined_verilog_netlists(t_spice spice); void dump_include_user_defined_verilog_netlists(FILE* fp, t_spice spice); +void check_file_handler(const std::fstream& fp); + void dump_verilog_file_header(FILE* fp, char* usage);