developed subgraph extraction and start refactoring mux generation
This commit is contained in:
parent
bee070d7cc
commit
69039aa742
|
@ -3,6 +3,7 @@
|
|||
* data structures in mux_graph.h
|
||||
*************************************************/
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#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<size_t> MuxGraph::branch_sizes() const {
|
|||
std::vector<size_t>::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<size_t> 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<MuxNodeId, MuxNodeId> node2node_map;
|
||||
|
||||
/* A map to record edge-to-edge mapping from origin graph to subgraph */
|
||||
std::map<MuxEdgeId, MuxEdgeId> 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<MuxMemId, MuxMemId> 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<MuxMemId, MuxMemId>::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> MuxGraph::build_mux_branch_graphs() const {
|
||||
std::map<size_t, bool> branch_done; /* A map showing the status of graph generation */
|
||||
|
||||
std::vector<MuxGraph> 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<size_t, bool>::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 */
|
||||
|
|
|
@ -48,11 +48,14 @@ class MuxGraph {
|
|||
typedef vtr::Range<node_iterator> node_range;
|
||||
typedef vtr::Range<edge_iterator> edge_range;
|
||||
typedef vtr::Range<mem_iterator> 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<size_t> branch_sizes() const;
|
||||
/* Generate MUX graphs for its branches */
|
||||
MuxGraph subgraph(const MuxNodeId& node) const;
|
||||
std::vector<MuxGraph> 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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -15,10 +15,18 @@
|
|||
#include "mux_library_fwd.h"
|
||||
|
||||
class MuxLibrary {
|
||||
public: /* Types and ranges */
|
||||
typedef vtr::vector<MuxId, MuxId>::const_iterator mux_iterator;
|
||||
|
||||
typedef vtr::Range<mux_iterator> 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<MuxId, MuxId> mux_ids_; /* Unique identifier for each mux graph */
|
||||
vtr::vector<MuxId, MuxGraph> mux_graphs_; /* Graphs describing MUX internal structures */
|
||||
vtr::vector<MuxId, CircuitModelId> mux_circuit_models_; /* circuit model id in circuit library */
|
||||
|
||||
/* Local encoder description */
|
||||
//vtr::vector<MuxLocalDecoderId, Decoder> mux_local_encoders_; /* Graphs describing MUX internal structures */
|
||||
|
|
|
@ -156,4 +156,3 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis
|
|||
|
||||
return mux_lib;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 <fstream>
|
||||
|
||||
#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
|
|
@ -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<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, 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!
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef VERILOG_UTILS_H
|
||||
#define VERILOG_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue