developed subgraph extraction and start refactoring mux generation

This commit is contained in:
tangxifan 2019-08-19 20:13:18 -06:00
parent bee070d7cc
commit 69039aa742
10 changed files with 297 additions and 10 deletions

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -156,4 +156,3 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis
return mux_lib;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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!

View File

@ -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) {

View File

@ -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);