Merge remote-tracking branch 'origin/dev' into heterogeneous

This commit is contained in:
AurelienUoU 2019-09-27 16:54:13 -06:00
commit 640922accd
19 changed files with 1175 additions and 36 deletions

View File

@ -471,11 +471,12 @@ class CircuitLibrary {
public: /* Internal mutators: build fast look-ups */
void build_model_lookup();
void build_model_port_lookup();
private: /* Internal invalidators/validators */
/* Validators */
public: /* Public invalidators/validators */
bool valid_model_id(const CircuitModelId& model_id) const;
bool valid_circuit_port_id(const CircuitPortId& circuit_port_id) const;
bool valid_circuit_pin_id(const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
private: /* Internal invalidators/validators */
/* Validators */
bool valid_edge_id(const CircuitEdgeId& edge_id) const;
bool valid_delay_type(const CircuitModelId& model_id, const enum spice_model_delay_type& delay_type) const;
bool valid_circuit_edge_id(const CircuitEdgeId& circuit_edge_id) const;

View File

@ -0,0 +1,75 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: circuit_library_utils.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/09/27 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* Function to perform fundamental operation for the circuit library
* These functions are not universal methods for the CircuitLibrary class
* They are made to ease the development in some specific purposes
* Please classify such functions in this file
***********************************************************************/
/* Header files should be included in a sequence */
/* Standard header files required go first */
#include <algorithm>
#include "vtr_assert.h"
#include "util.h"
#include "circuit_library_utils.h"
/********************************************************************
* Get the model id of a SRAM model that is used to configure
* a circuit model
*******************************************************************/
std::vector<CircuitModelId> get_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
/* SRAM model id is stored in the sram ports of a circuit model */
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM);
std::vector<CircuitModelId> sram_models;
/* Create a list of sram models, but avoid duplicated model ids */
for (const auto& sram_port : sram_ports) {
CircuitModelId sram_model = circuit_lib.port_tri_state_model(sram_port);
VTR_ASSERT( true == circuit_lib.valid_model_id(sram_model) );
if (sram_models.end() != std::find(sram_models.begin(), sram_models.end(), sram_model)) {
continue; /* Already in the list, skip the addition */
}
/* Not in the list, add it */
sram_models.push_back(sram_model);
}
return sram_models;
}

View File

@ -0,0 +1,16 @@
/********************************************************************
* Header file for circuit_library_utils.cpp
*******************************************************************/
#ifndef CIRCUIT_LIBRARY_UTILS_H
#define CIRCUIT_LIBRARY_UTILS_H
/* Header files should be included in a sequence */
/* Standard header files required go first */
#include <vector>
#include "circuit_library.h"
std::vector<CircuitModelId> get_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
#endif

View File

@ -65,6 +65,14 @@ MuxGraph::mem_range MuxGraph::memories() const {
return vtr::make_range(mem_ids_.begin(), mem_ids_.end());
}
std::vector<size_t> MuxGraph::levels() const {
std::vector<size_t> graph_levels;
for (size_t lvl = 0; lvl < num_levels(); ++lvl) {
graph_levels.push_back(lvl);
}
return graph_levels;
}
/**************************************************
* Public Accessors: Data query
*************************************************/
@ -158,6 +166,14 @@ size_t MuxGraph::num_memory_bits() const {
return mem_ids_.size();
}
/* Find the number of SRAMs at a level in the MUX graph */
size_t MuxGraph::num_memory_bits_at_level(const size_t& level) const {
/* need to check if the graph is valid or not */
VTR_ASSERT_SAFE(valid_level(level));
VTR_ASSERT_SAFE(valid_mux_graph());
return mem_lookup_[level].size();
}
/* Find the number of nodes at a given level in the MUX graph */
size_t MuxGraph::num_nodes_at_level(const size_t& level) const {
/* validate the level numbers */
@ -310,6 +326,7 @@ 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();
mux_graph.set_mem_level(mem_subgraph, 0);
mem2mem_map[mem_origin] = mem_subgraph;
/* configure the edge */
mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem_subgraph;
@ -317,6 +334,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
/* Since the graph is finalized, it is time to build the fast look-up */
mux_graph.build_node_lookup();
mux_graph.build_mem_lookup();
return mux_graph;
}
@ -519,11 +537,20 @@ MuxMemId MuxGraph::add_mem() {
MuxMemId mem = MuxMemId(mem_ids_.size());
/* Push to the node list */
mem_ids_.push_back(mem);
mem_levels_.push_back(size_t(-1));
/* Resize the other node-related vectors */
return mem;
}
/* Configure the level of a memory */
void MuxGraph::set_mem_level(const MuxMemId& mem, const size_t& level) {
/* Make sure we have valid edge and mem */
VTR_ASSERT( valid_mem_id(mem) );
mem_levels_[mem] = level;
}
/* Link an edge to a memory bit */
void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) {
/* Make sure we have valid edge and mem */
@ -593,8 +620,11 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
num_mems_per_level = 1;
}
/* Number of memory bits is definite, add them */
for (size_t i = 0; i < num_mems_per_level * num_levels; ++i) {
add_mem();
for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) {
for (size_t imem = 0; imem < num_mems_per_level; ++imem) {
MuxMemId mem = add_mem();
mem_levels_[mem] = ilvl;
}
}
/* Create a fast node lookup locally.
@ -747,6 +777,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
/* Create a memory bit*/
MuxMemId mem = add_mem();
mem_levels_[mem] = 0;
/* Link the edge to a memory bit */
set_edge_mem_id(edge, mem);
}
@ -863,6 +894,7 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
/* Since the graph is finalized, it is time to build the fast look-up */
build_node_lookup();
build_mem_lookup();
/* For fracturable LUTs, we need to add more outputs to the MUX graph */
if ( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
@ -895,11 +927,35 @@ void MuxGraph::build_node_lookup() {
}
}
/* Build fast mem lookup */
void MuxGraph::build_mem_lookup() {
/* Invalidate the mem lookup if necessary */
invalidate_mem_lookup();
/* Find the maximum number of levels */
size_t num_levels = 0;
for (auto mem : memories()) {
num_levels = std::max((int)mem_levels_[mem], (int)num_levels);
}
/* Resize mem_lookup */
mem_lookup_.resize(num_levels + 1);
for (auto mem : memories()) {
/* Categorize mem nodes into mem_lookup */
mem_lookup_[mem_levels_[mem]].push_back(mem);
}
}
/* Invalidate (empty) the node fast lookup*/
void MuxGraph::invalidate_node_lookup() {
node_lookup_.clear();
}
/* Invalidate (empty) the mem fast lookup*/
void MuxGraph::invalidate_mem_lookup() {
mem_lookup_.clear();
}
/**************************************************
* Private validators
*************************************************/

View File

@ -62,6 +62,7 @@ class MuxGraph {
std::vector<MuxNodeId> non_input_nodes() const;
edge_range edges() const;
mem_range memories() const;
std::vector<size_t> levels() const;
public: /* Public accessors: Data query */
/* Find the number of inputs in the MUX graph */
size_t num_inputs() const;
@ -76,6 +77,8 @@ class MuxGraph {
size_t num_node_levels() const;
/* Find the number of SRAMs in the MUX graph */
size_t num_memory_bits() const;
/* Find the number of SRAMs at a level in the MUX graph */
size_t num_memory_bits_at_level(const size_t& level) const;
/* Find the number of nodes at a given level in the MUX graph */
size_t num_nodes_at_level(const size_t& level) const;
/* Find the level of a node */
@ -112,6 +115,8 @@ class MuxGraph {
MuxEdgeId add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node);
/* Add a memory bit to the MuxGraph */
MuxMemId add_mem();
/* Configure the level of a memory */
void set_mem_level(const MuxMemId& mem, const size_t& level);
/* Link an edge to a mem */
void set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem);
private: /* Private mutators : graph builders */
@ -130,6 +135,8 @@ class MuxGraph {
const CircuitModelId& circuit_model);
/* Build fast node lookup */
void build_node_lookup();
/* Build fast mem lookup */
void build_mem_lookup();
private: /* Private validators */
/* valid ids */
bool valid_node_id(const MuxNodeId& node) const;
@ -141,6 +148,7 @@ class MuxGraph {
/* validate/invalidate node lookup */
bool valid_node_lookup() const;
void invalidate_node_lookup();
void invalidate_mem_lookup();
/* validate graph */
bool valid_mux_graph() const;
private: /* Internal data */
@ -161,10 +169,13 @@ class MuxGraph {
vtr::vector<MuxEdgeId, bool> edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */
vtr::vector<MuxMemId, MuxMemId> mem_ids_; /* ids of configuration memories */
vtr::vector<MuxMemId, size_t> mem_levels_; /* ids of configuration memories */
/* fast look-up */
typedef std::vector<std::vector<std::vector<MuxNodeId>>> NodeLookup;
mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */
typedef std::vector<std::vector<MuxMemId>> MemLookup;
mutable MemLookup mem_lookup_; /* [num_levels][num_mems_per_level] */
};
#endif

View File

@ -32,8 +32,9 @@ class MuxLibrary {
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);
private: /* Private accessors */
public: /* Public validators */
bool valid_mux_id(const MuxId& mux) const;
private: /* Private accessors */
bool valid_mux_lookup() const;
bool valid_mux_circuit_model_id(const CircuitModelId& circuit_model) const;
bool valid_mux_size(const CircuitModelId& circuit_model, const size_t& mux_size) const;

View File

@ -3,10 +3,12 @@
* that are used to implement a multiplexer
*************************************************/
#include <cmath>
#include <algorithm>
#include "spice_types.h"
#include "util.h"
#include "vtr_assert.h"
#include "decoder_library_utils.h"
#include "mux_utils.h"
/* Validate the number of inputs for a multiplexer implementation,
@ -237,3 +239,150 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis
return mux_lib;
}
/**************************************************
* Find the number of reserved configuration bits for a multiplexer
* The reserved configuration bits is only used by ReRAM-based multiplexers
* It is actually the shared BL/WLs among ReRAMs
*************************************************/
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph) {
if (SPICE_MODEL_DESIGN_RRAM != circuit_lib.design_tech_type(mux_model)) {
return 0;
}
std::vector<size_t> mux_branch_sizes = mux_graph.branch_sizes();
/* For tree-like multiplexers: they have two shared configuration bits */
if ( (1 == mux_branch_sizes.size())
&& (2 == mux_branch_sizes[0]) ) {
return mux_branch_sizes[0];
}
/* One-level multiplexer */
if ( 1 == mux_graph.num_levels() ) {
return mux_graph.num_inputs();
}
/* Multi-level multiplexers: TODO: This should be better tested and clarified
* Now the multi-level multiplexers are treated as cascaded one-level multiplexers
* Use the maximum branch sizes and multiply it by the number of levels
*/
std::vector<size_t>::iterator max_mux_branch_size = std::max_element(mux_branch_sizes.begin(), mux_branch_sizes.end());
return mux_graph.num_levels() * (*max_mux_branch_size);
}
/**************************************************
* Find the number of configuration bits for a CMOS multiplexer
* In general, the number of configuration bits is
* the number of memory bits for a mux_graph
* However, when local decoders are used,
* the number of configuration bits are reduced to log2(X)
*************************************************/
static
size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph,
const e_sram_orgz& sram_orgz_type) {
size_t num_config_bits = 0;
switch (sram_orgz_type) {
case SPICE_SRAM_MEMORY_BANK:
case SPICE_SRAM_SCAN_CHAIN:
case SPICE_SRAM_STANDALONE:
num_config_bits = mux_graph.num_memory_bits();
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d])Invalid type of SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
if (false == circuit_lib.mux_use_local_encoder(mux_model)) {
return num_config_bits;
}
num_config_bits = 0;
/* Multiplexer local encoders are applied to memory bits at each stage */
for (const auto& lvl : mux_graph.levels()) {
num_config_bits += find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
}
return num_config_bits;
}
/**************************************************
* Find the number of configuration bits for a RRAM multiplexer
* In general, the number of configuration bits is
* the number of levels for a mux_graph
* This is due to only the last BL/WL of the multiplexer is
* independent from each other
* However, when local decoders are used,
* the number of configuration bits should be consider all the
* shared(reserved) configuration bits and independent bits
*************************************************/
static
size_t find_rram_mux_num_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph,
const e_sram_orgz& sram_orgz_type) {
size_t num_config_bits = 0;
switch (sram_orgz_type) {
case SPICE_SRAM_MEMORY_BANK:
/* In memory bank, by intensively share the Bit/Word Lines,
* we only need 1 additional BL and WL for each MUX level.
*/
num_config_bits = mux_graph.num_levels();
break;
case SPICE_SRAM_SCAN_CHAIN:
case SPICE_SRAM_STANDALONE:
/* Currently we DO NOT SUPPORT THESE, given an invalid number */
num_config_bits = size_t(-1);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d])Invalid type of SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
if (true == circuit_lib.mux_use_local_encoder(mux_model)) {
/* TODO: this is a to-do work for ReRAM-based multiplexers and FPGAs
* The number of states of a local decoder only depends on how many
* memory bits that the multiplexer will have
* This may NOT be correct!!!
*/
return find_mux_local_decoder_addr_size(mux_graph.num_memory_bits());
}
return num_config_bits;
}
/**************************************************
* Find the number of configuration bits for
* a routing multiplexer
* Two cases are considered here.
* They are placed in different branches (sub-functions)
* in order to be easy in extending to new technology!
*************************************************/
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph,
const e_sram_orgz& sram_orgz_type) {
size_t num_config_bits = size_t(-1);
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
num_config_bits = find_cmos_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
break;
case SPICE_MODEL_DESIGN_RRAM:
num_config_bits = find_rram_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s)\n",
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
exit(1);
}
return num_config_bits;
}

View File

@ -37,4 +37,13 @@ std::vector<bool> build_mux_intermediate_buffer_location_map(const CircuitLibrar
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head);
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph);
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph,
const e_sram_orgz& sram_orgz_type);
#endif

View File

@ -202,7 +202,7 @@ int multilevel_mux_last_level_input_num(int num_level, int num_input_per_unit,
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
* We plus 1, which is all-zero condition for outputs
***************************************************************************************/
****************************************************************************************/
int determine_mux_local_encoder_num_inputs(int num_outputs) {
return ceil(log(num_outputs) / log(2));
}

View File

@ -259,28 +259,28 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
const size_t& pin_id,
const bool& for_top_netlist) {
if (true == for_top_netlist) {
std::string port_name = "grid_";
std::string port_name = std::string("grid_");
port_name += std::to_string(coordinate.x());
port_name += "__";
port_name += std::string("__");
port_name += std::to_string(coordinate.y());
port_name += "__pin_";
port_name += std::string("__pin_");
port_name += std::to_string(height);
port_name += "__";
port_name += std::string("__");
port_name += std::to_string(size_t(side));
port_name += "__";
port_name += std::string("__");
port_name += std::to_string(pin_id);
port_name += "_";
port_name += std::string("_");
return port_name;
}
/* For non-top netlist */
VTR_ASSERT( false == for_top_netlist );
Side side_manager(side);
std::string port_name = std::string(side_manager.to_string());
port_name += "_height_";
port_name += std::string("_height_");
port_name += std::to_string(height);
port_name += "__pin_";
port_name += std::string("__pin_");
port_name += std::to_string(pin_id);
port_name += "_";
port_name += std::string("_");
return port_name;
}
@ -456,3 +456,66 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
return port_name;
}
/*********************************************************************
* Generate the port name for the input bus of a routing multiplexer
* This is very useful in Verilog code generation where the inputs of
* a routing multiplexer may come from different ports.
* On the other side, the datapath input of a routing multiplexer
* is defined as a bus port.
* Therefore, to interface, a bus port is required, and this function
* give a name to the bus port
* To keep the bus port name unique to each multiplexer we will instance,
* a mux_instance_id should be provided by user
*********************************************************************/
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id) {
std::string postfix = std::string("_") + std::to_string(mux_instance_id) + std::string("_inbus");
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
}
/*********************************************************************
* Generate the name of a bus port which is wired to the configuration
* ports of a routing multiplexer
* This port is supposed to be used locally inside a Verilog/SPICE module
*********************************************************************/
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& bus_id,
const bool& inverted) {
std::string postfix = std::string("_configbus") + std::to_string(bus_id);
/* Add a bar to the end of the name for inverted bus ports */
if (true == inverted) {
postfix += std::string("_b");
}
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
}
/*********************************************************************
* Generate the port name for a SRAM port of a routing multiplexer
* This name is used for local wires that connecting SRAM ports
* of routing multiplexers inside a Verilog/SPICE module
* Note that the SRAM ports of routing multiplexers share the same naming
* convention regardless of their configuration style
*********************************************************************/
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const e_spice_model_port_type& port_type) {
std::string postfix = std::string("_") + std::to_string(mux_instance_id) + std::string("_");
if (SPICE_MODEL_PORT_INPUT == port_type) {
postfix += std::string("out");
} else {
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
postfix += std::string("outb");
}
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
}

View File

@ -82,4 +82,21 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
const e_sram_orgz& sram_orgz_type,
const e_spice_model_port_type& port_type);
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id);
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& bus_id,
const bool& inverted);
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const e_spice_model_port_type& port_type);
#endif

View File

@ -64,9 +64,10 @@ class ModuleManager {
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
/* Add a child module to a parent module */
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
private: /* Private validators/invalidators */
public: /* Public validators/invalidators */
bool valid_module_id(const ModuleId& module) const;
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
private: /* Private validators/invalidators */
void invalidate_name2id_map();
void invalidate_port_lookup();
private: /* Internal data */

View File

@ -118,7 +118,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type,
const std::string& preproc_flag,
const size_t& port_size) {
/* Create a port */

View File

@ -28,7 +28,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type,
const std::string& preproc_flag,
const size_t& port_size);

View File

@ -83,7 +83,7 @@
* | |
* v v
* +------------------------------------+
* | Multiplexer Configuration port |
* | Memory Module Configuration port |
* +------------------------------------+
* | | |
* v v v
@ -133,7 +133,14 @@ void print_verilog_memory_module(ModuleManager& module_manager,
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: port width should match the number of memories */
/* TODO: when Configuration-chain style is selected, the port map should be different!
* It should have only a head as input, a tail as output and other regular output ports
*/
/* Add each input port: port width should match the number of memories
* The number of inputs will not match the number of memory bits of a multiplexer
* when local decoders are used.
* It should be calculated by the decoder builders!
*/
for (const auto& port : sram_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
@ -206,8 +213,11 @@ void print_verilog_memory_module(ModuleManager& module_manager,
* update the module manager with the relationship between the parent and child modules
*/
module_manager.add_child_module(module_id, sram_module_id);
/* TODO: Wire the memory cells into a chain, when Configuration-chain style is selected!!! */
}
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}

View File

@ -11,6 +11,7 @@
#include <unistd.h>
#include <string.h>
#include <vector>
#include <map>
#include <fstream>
#include <algorithm>
@ -39,6 +40,7 @@
#include "fpga_x2p_bitstream_utils.h"
#include "fpga_x2p_globals.h"
#include "fpga_x2p_naming.h"
#include "mux_utils.h"
#include "module_manager.h"
#include "module_manager_utils.h"
@ -2145,6 +2147,391 @@ void update_routing_connection_box_conf_bits(t_sram_orgz_info* cur_sram_orgz_inf
return;
}
/*********************************************************************
* Generate a port for a routing track of a swtich block
********************************************************************/
static
BasicPort generate_verilog_unique_switch_box_chan_port(const RRGSB& rr_sb,
const e_side& chan_side,
t_rr_node* cur_rr_node,
const PORTS& cur_rr_node_direction) {
/* Get the index in sb_info of cur_rr_node */
int index = rr_sb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
/* Make sure this node is included in this sb_info */
VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side));
DeviceCoordinator chan_rr_node_coordinator = rr_sb.get_side_block_coordinator(chan_side);
vtr::Point<size_t> chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y());
std::string chan_port_name = generate_routing_track_port_name(rr_sb.get_chan_node(chan_side, index)->type,
chan_port_coord, index,
rr_sb.get_chan_node_direction(chan_side, index));
return BasicPort(chan_port_name, 1); /* Every track has a port size of 1 */
}
/*********************************************************************
* Generate an input port for routing multiplexer inside the switch block
* In addition to give the Routing Resource node of the input
* Users should provide the side of input, which is different case by case:
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
* be the side of the node on its grid!
* For example, the input pin is on the top side of a switch block
* but on the right side of a switch block
* +--------+
* | |
* | Grid |---+
* | | |
* +--------+ v input_pin
* +----------------+
* | Switch Block |
* +----------------+
* 2. When the input is a routing track, the input_side should be
* the side of the node locating on the switch block
********************************************************************/
static
BasicPort generate_switch_block_input_port(const RRGSB& rr_sb,
const e_side& input_side,
t_rr_node* input_rr_node) {
BasicPort input_port;
/* Generate the input port object */
switch (input_rr_node->type) {
/* case SOURCE: */
case OPIN: {
/* Find the coordinator (grid_x and grid_y) for the input port */
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
std::string input_port_name = generate_grid_side_port_name(input_port_coord,
input_side,
input_rr_node->ptc_num);
input_port.set_name(input_port_name);
input_port.set_width(1); /* Every grid output has a port size of 1 */
break;
}
case CHANX:
case CHANY: {
input_port = generate_verilog_unique_switch_box_chan_port(rr_sb, input_side, input_rr_node, IN_PORT);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
return input_port;
}
/*********************************************************************
* Generate a list of input ports for routing multiplexer inside the switch block
********************************************************************/
static
std::vector<BasicPort> generate_switch_block_input_ports(const RRGSB& rr_sb,
const std::vector<t_rr_node*>& input_rr_nodes) {
std::vector<BasicPort> input_ports;
for (auto input_rr_node : input_rr_nodes) {
enum e_side input_pin_side = NUM_SIDES;
switch (input_rr_node->type) {
case OPIN:
input_pin_side = rr_sb.get_opin_node_grid_side(input_rr_node);
break;
case CHANX:
case CHANY: {
/* The input could be at any side of the switch block, find it */
int index = -1;
rr_sb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
VTR_ASSERT(NUM_SIDES != input_pin_side);
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
input_ports.push_back(generate_switch_block_input_port(rr_sb, input_pin_side, input_rr_node));
}
return input_ports;
}
/*********************************************************************
* Print a short interconneciton in switch box
* There are two cases should be noticed.
* 1. The actual fan-in of cur_rr_node is 0. In this case,
the cur_rr_node need to be short connected to itself which is on the opposite side of this switch
* 2. The actual fan-in of cur_rr_node is 0. In this case,
* The cur_rr_node need to connected to the drive_rr_node
********************************************************************/
static
void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
const RRGSB& rr_sb,
const e_side& chan_side,
t_rr_node* cur_rr_node,
t_rr_node* drive_rr_node) {
/* Check the file handler*/
check_file_handler(fp);
/* Find the name of output port */
BasicPort output_port = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT);
enum e_side input_pin_side = chan_side;
/* Generate the input port object */
switch (drive_rr_node->type) {
case OPIN:
input_pin_side = rr_sb.get_opin_node_grid_side(drive_rr_node);
break;
case CHANX:
case CHANY: {
/* This should be an input in the data structure of RRGSB */
if (cur_rr_node == drive_rr_node) {
/* To be strict, the input should locate on the opposite side.
* Use the else part if this may change in some architecture.
*/
Side side_manager(chan_side);
input_pin_side = side_manager.get_opposite();
} else {
/* The input could be at any side of the switch block, find it */
int index = -1;
rr_sb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index);
}
break;
}
default: /* SOURCE, IPIN, SINK are invalid*/
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
__FILE__, __LINE__);
exit(1);
}
/* Find the name of input port */
BasicPort input_port = generate_switch_block_input_port(rr_sb, input_pin_side, drive_rr_node);
/* Print the wire connection in Verilog format */
print_verilog_comment(fp, std::string("----- Short connection " + output_port.get_name() + " -----"));
print_verilog_wire_connection(fp, output_port, input_port, false);
fp << std::endl;
}
/*********************************************************************
* Print a Verilog instance of a routing multiplexer as well as
* associated memory modules for a connection inside a switch block
********************************************************************/
static
void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
std::fstream& fp,
t_sram_orgz_info* cur_sram_orgz_info,
const ModuleId& sb_module,
const RRGSB& rr_sb,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
const e_side& chan_side,
t_rr_node* cur_rr_node,
const std::vector<t_rr_node*>& drive_rr_nodes,
const size_t& switch_index,
const bool& use_explicit_mapping) {
/* Check the file handler*/
check_file_handler(fp);
/* Check */
/* Check current rr_node is CHANX or CHANY*/
VTR_ASSERT((CHANX == cur_rr_node->type)||(CHANY == cur_rr_node->type));
/* Get the circuit model id of the routing multiplexer */
CircuitModelId mux_model = rr_switches[switch_index].circuit_model;
/* Find the input size of the implementation of a routing multiplexer */
size_t datapath_mux_size = drive_rr_nodes.size();
/* Get the multiplexing graph from the Mux Library */
MuxId mux_id = mux_lib.mux_graph(mux_model, datapath_mux_size);
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
/* Find the module name of the multiplexer and try to find it in the module manager */
std::string mux_module_name = generate_verilog_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string(""));
ModuleId mux_module = module_manager.find_module(mux_module_name);
VTR_ASSERT (true == module_manager.valid_module_id(mux_module));
/* Get the MUX instance id from the module manager */
size_t mux_instance_id = module_manager.num_instance(sb_module, mux_module);
/* Print the input bus for the inputs of a multiplexer
* We use the datapath input size (mux_size) to name the bus
* just to following the naming convention when the tool is built
* The bus port size should be the input size of multiplexer implementation
*/
BasicPort inbus_port;
inbus_port.set_name(generate_mux_input_bus_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id));
inbus_port.set_width(datapath_mux_size);
/* Generate input ports that are wired to the input bus of the routing multiplexer */
std::vector<BasicPort> mux_input_ports = generate_switch_block_input_ports(rr_sb, drive_rr_nodes);
/* Connect input ports to bus */
print_verilog_comment(fp, std::string("----- BEGIN A local bus wire for multiplexer inputs -----"));
fp << generate_verilog_local_wire(inbus_port, mux_input_ports) << std::endl;
print_verilog_comment(fp, std::string("----- END A local bus wire for multiplexer inputs -----"));
fp << std::endl;
/* Find the number of reserved configuration bits for the routing multiplexer */
size_t mux_num_reserved_config_bits = find_mux_num_reserved_config_bits(circuit_lib, mux_model, mux_graph);
/* Find the number of configuration bits for the routing multiplexer */
size_t mux_num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, cur_sram_orgz_info->type);
/* Print the configuration bus for the routing multiplexers */
print_verilog_comment(fp, std::string("----- BEGIN Local wires to group configuration ports -----"));
print_verilog_mux_config_bus(fp, circuit_lib, mux_model, cur_sram_orgz_info->type,
datapath_mux_size, mux_instance_id,
mux_num_reserved_config_bits, mux_num_config_bits);
print_verilog_comment(fp, std::string("----- END Local wires to group configuration ports -----"));
fp << std::endl;
/* Dump ports visible only during formal verification */
print_verilog_comment(fp, std::string("----- BEGIN Local wires used in only formal verification purpose -----"));
print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag));
/* Print the SRAM configuration ports for formal verification */
/* TODO: align with the port width of formal verification port of SB module */
print_verilog_formal_verification_mux_sram_ports_wiring(fp, circuit_lib, mux_model,
datapath_mux_size, mux_instance_id, mux_num_config_bits);
print_verilog_endif(fp);
print_verilog_comment(fp, std::string("----- END Local wires used in only formal verification purpose -----"));
fp << std::endl;
/* Instanciate the MUX Module */
/* Create port-to-port map */
std::map<std::string, BasicPort> mux_port2port_name_map;
/* Link input bus port to Switch Block inputs */
std::vector<CircuitPortId> mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true);
VTR_ASSERT(1 == mux_model_input_ports.size());
/* Use the port name convention in the circuit library */
mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_input_ports[0])] = inbus_port;
/* Link output port to Switch Block outputs */
std::vector<CircuitPortId> mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true);
VTR_ASSERT(1 == mux_model_output_ports.size());
/* Use the port name convention in the circuit library */
mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_output_ports[0])] = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT);
/* Link SRAM port to different configuraton port for the routing multiplexer
* Different design technology requires different configuration bus!
*/
std::vector<CircuitPortId> mux_model_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true);
VTR_ASSERT( 1 == mux_model_sram_ports.size() );
/* For the regular SRAM port, module port use the same name */
std::string mux_module_sram_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]);
BasicPort mux_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
mux_num_config_bits);
mux_port2port_name_map[mux_module_sram_port_name] = mux_config_port;
/* For the inverted SRAM port */
std::string mux_module_sram_inv_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]) + std::string("_inv");
BasicPort mux_config_inv_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
mux_num_config_bits);
mux_port2port_name_map[mux_module_sram_inv_port_name] = mux_config_inv_port;
/* Print an instance of the MUX Module */
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a routing multiplexer -----"));
print_verilog_module_instance(fp, module_manager, sb_module, mux_module, mux_port2port_name_map, use_explicit_mapping);
print_verilog_comment(fp, std::string("----- END Instanciation of a routing multiplexer -----"));
fp << std::endl;
/* 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(sb_module, mux_module);
/* TODO: Instanciate memory modules */
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
/* Call the memory module defined for this SRAM-based MUX! */
/*
mem_subckt_name = generate_verilog_mux_subckt_name(verilog_model, mux_size, verilog_mem_posfix);
dump_verilog_mem_sram_submodule(fp, cur_sram_orgz_info,
verilog_model, mux_size, mem_model,
cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
is_explicit_mapping);
*/
break;
case SPICE_MODEL_DESIGN_RRAM:
/* RRAM-based MUX does not need any SRAM dumping
* But we have to get the number of configuration bits required by this MUX
* and update the number of memory bits
*/
/*
update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info, cur_num_sram + num_mux_conf_bits);
update_sram_orgz_info_num_blwl(cur_sram_orgz_info,
cur_bl + num_mux_conf_bits,
cur_wl + num_mux_conf_bits);
*/
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid design technology for circuit model (%s)!\n",
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
}
/* Create the path of the input of multiplexer in the hierarchy
* TODO: this MUST be deprecated later because module manager is created to handle these problems!!!
*/
std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/")
+ mux_module_name + std::string("_")
+ std::to_string(mux_instance_id) + std::string("_/in");
cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str());
}
/*********************************************************************
* Print the Verilog modules for a interconnection inside switch block
* The interconnection could be either a wire or a routing multiplexer,
* which depends on the fan-in of the rr_nodes in the switch block
********************************************************************/
static
void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
std::fstream& fp,
t_sram_orgz_info* cur_sram_orgz_info,
const ModuleId& sb_module,
const RRGSB& rr_sb,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
const e_side& chan_side,
const size_t& chan_node_id,
const bool& use_explicit_mapping) {
std::vector<t_rr_node*> drive_rr_nodes;
/* Get the node */
t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id);
/* Determine if the interc lies inside a channel wire, that is interc between segments */
if (false == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
for (int i = 0; i < cur_rr_node->num_drive_rr_nodes; ++i) {
drive_rr_nodes.push_back(cur_rr_node->drive_rr_nodes[i]);
}
/* Special: if there are zero-driver nodes. We skip here */
if (0 == drive_rr_nodes.size()) {
return;
}
}
if (0 == drive_rr_nodes.size()) {
/* Print a special direct connection*/
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
cur_rr_node);
} else if (1 == drive_rr_nodes.size()) {
/* Print a direct connection*/
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
drive_rr_nodes[DEFAULT_SWITCH_ID]);
} else if (1 < drive_rr_nodes.size()) {
/* Print the multiplexer, fan_in >= 2 */
print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info,
sb_module, rr_sb, circuit_lib, mux_lib,
rr_switches, chan_side, cur_rr_node,
drive_rr_nodes,
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
use_explicit_mapping);
} /*Nothing should be done else*/
}
/*********************************************************************
* Generate the Verilog module for a Switch Box.
* A Switch Box module consists of following ports:
@ -2322,7 +2709,6 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage
rr_gsb.get_sb_num_conf_bits());
/* Add ports only visible during formal verification to the module */
add_formal_verification_sram_ports_to_module_manager(module_manager, module_id, circuit_lib, sram_model,
cur_sram_orgz_info->type,
std::string(verilog_formal_verification_preproc_flag),
rr_gsb.get_sb_num_conf_bits());
}
@ -2338,6 +2724,19 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage
print_verilog_comment(fp, std::string("---- END local wires for SRAM data ports ----"));
/* TODO: Print routing multiplexers */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
print_verilog_comment(fp, std::string("----- " + side_manager.to_string() + " side Routing Multiplexers -----"));
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
/* We care INC_DIRECTION tracks at this side*/
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, module_id, rr_sb,
circuit_lib, mux_lib, rr_switches,
side_manager.get_side(),
itrack, is_explicit_mapping);
}
}
}
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_manager.module_name(module_id));

View File

@ -9,6 +9,7 @@
#include "vtr_assert.h"
/* Device-level header files */
#include "circuit_library_utils.h"
/* FPGA-X2P context header files */
#include "spice_types.h"
@ -449,7 +450,7 @@ std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports) {
if (&port != &merged_ports[0]) {
verilog_line += ", ";
}
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, port);
}
verilog_line += "}";
@ -769,3 +770,319 @@ void print_verilog_local_sram_wires(std::fstream& fp,
exit(1);
}
}
/*********************************************************************
* Print a number of bus ports which are wired to the configuration
* ports of a CMOS (SRAM-based) routing multiplexer
* This port is supposed to be used locally inside a Verilog/SPICE module
*
* For standalone configuration style:
* ------------------------------------
* No bus needed
*
* For configuration-chain configuration style:
* --------------------------------------------
*
* Module Port
* |
* v
* bus_port --------+----------------+----> ...
* | |
* sram_outputs v v
* +-----------+ +-----------+
* | Memory | | Memory |
* | Module[0] | | Module[1] | ...
* +-----------+ +-----------+
* | |
* v v
* +-----------+ +-----------+
* | Routing | | Routing |
* | MUX [0] | | MUX[1] | ...
* +-----------+ +-----------+
*
* For memory-bank configuration style:
* ------------------------------------
*
* Module Port
* |
* v
* bus_port --------+----------------+----> ...
* | |
* bl/wl/../sram_ports v v
* +-----------+ +-----------+
* | Memory | | Memory |
* | Module[0] | | Module[1] | ...
* +-----------+ +-----------+
* | |
* v v
* +-----------+ +-----------+
* | Routing | | Routing |
* | MUX [0] | | MUX[1] | ...
* +-----------+ +-----------+
*
*********************************************************************/
static
void print_verilog_cmos_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const e_sram_orgz& sram_orgz_type,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_conf_bits) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
switch(sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
/* Not need for configuration bus
* The configuration ports of SRAM are directly wired to the ports of modules
*/
break;
case SPICE_SRAM_SCAN_CHAIN: {
/* To support chain-like configuration protocol, two configuration buses should be outputted
* One for the regular SRAM ports of a routing multiplexer
* The other for the inverted SRAM ports of a routing multiplexer
*/
BasicPort config_port(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_port) << ";" << std::endl;
BasicPort inverted_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_config_port) << ";" << std::endl;
break;
}
case SPICE_SRAM_MEMORY_BANK: {
/* To support memory-bank configuration, SRAM outputs are supposed to be exposed to the upper level as buses
* In addition, the BL/WL ports should be grouped and be exposed to the upper level as buses
*/
/* Print configuration bus to group BL/WLs */
BasicPort bl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, false),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, bl_bus) << ";" << std::endl;
BasicPort wl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, false),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wl_bus) << ";" << std::endl;
/* Print bus to group SRAM outputs, this is to interface memory cells to routing multiplexers */
BasicPort sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_output_bus) << ";" << std::endl;
BasicPort inverted_sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_sram_output_bus) << ";" << std::endl;
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
std::vector<CircuitPortId> blb_ports = circuit_lib.model_ports_by_type(sram_models[0], SPICE_MODEL_PORT_BLB);
std::vector<CircuitPortId> wlb_ports = circuit_lib.model_ports_by_type(sram_models[0], SPICE_MODEL_PORT_WLB);
/* Connect SRAM BL/WLs to bus */
BasicPort mux_bl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BL),
num_conf_bits);
print_verilog_wire_connection(fp, bl_bus, mux_bl_wire, false);
BasicPort mux_wl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WL),
num_conf_bits);
print_verilog_wire_connection(fp, wl_bus, mux_wl_wire, false);
/* Print configuration bus to group BLBs, if the ports are available in SRAM models */
if (0 < blb_ports.size()) {
BasicPort blb_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, true),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, blb_bus) << ";" << std::endl;
/* Connect SRAM BLBs to bus */
BasicPort mux_blb_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BLB),
num_conf_bits);
print_verilog_wire_connection(fp, blb_bus, mux_blb_wire, false);
}
/* Print configuration bus to group WLBs, if the ports are available in SRAM models */
if (0 < wlb_ports.size()) {
BasicPort wlb_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, true),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wlb_bus) << ";" << std::endl;
/* Connect SRAM WLBs to bus */
BasicPort mux_wlb_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WLB),
num_conf_bits);
print_verilog_wire_connection(fp, wlb_bus, mux_wlb_wire, false);
}
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
}
/*********************************************************************
* Print a number of bus ports which are wired to the configuration
* ports of a ReRAM-based routing multiplexer
* This port is supposed to be used locally inside a Verilog/SPICE module
*
* Currently support:
* For memory-bank configuration style:
* ------------------------------------
* Different than CMOS routing multiplexers, ReRAM multiplexers require
* reserved BL/WLs to be grouped in buses
*
* Module Port
* |
* v
* regular/reserved bus_port --+----------------+----> ...
* | |
* bl/wl/../sram_ports v v
* +-----------+ +-----------+
* | Memory | | Memory |
* | Module[0] | | Module[1] | ...
* +-----------+ +-----------+
* | |
* v v
* +-----------+ +-----------+
* | Routing | | Routing |
* | MUX [0] | | MUX[1] | ...
* +-----------+ +-----------+
*
*********************************************************************/
static
void print_verilog_rram_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const e_sram_orgz& sram_orgz_type,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_reserved_conf_bits,
const size_t& num_conf_bits) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
switch(sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
/* Not need for configuration bus
* The configuration ports of SRAM are directly wired to the ports of modules
*/
break;
case SPICE_SRAM_SCAN_CHAIN: {
/* Not supported yet.
* Configuration chain may be only applied to ReRAM-based multiplexers with local decoders
*/
break;
}
case SPICE_SRAM_MEMORY_BANK: {
/* This is currently most used in ReRAM FPGAs */
/* Print configuration bus to group reserved BL/WLs */
BasicPort reserved_bl_bus(generate_reserved_sram_port_name(SPICE_MODEL_PORT_BL),
num_reserved_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, reserved_bl_bus) << ";" << std::endl;
BasicPort reserved_wl_bus(generate_reserved_sram_port_name(SPICE_MODEL_PORT_WL),
num_reserved_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, reserved_wl_bus) << ";" << std::endl;
/* Print configuration bus to group BL/WLs */
BasicPort bl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, false),
num_conf_bits + num_reserved_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, bl_bus) << ";" << std::endl;
BasicPort wl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, false),
num_conf_bits + num_reserved_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wl_bus) << ";" << std::endl;
/* Print bus to group SRAM outputs, this is to interface memory cells to routing multiplexers */
BasicPort sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_output_bus) << ";" << std::endl;
BasicPort inverted_sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_sram_output_bus) << ";" << std::endl;
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
/* Wire the reserved configuration bits to part of bl/wl buses */
BasicPort bl_bus_reserved_bits(bl_bus.get_name(), num_reserved_conf_bits);
print_verilog_wire_connection(fp, bl_bus_reserved_bits, reserved_bl_bus, false);
BasicPort wl_bus_reserved_bits(wl_bus.get_name(), num_reserved_conf_bits);
print_verilog_wire_connection(fp, wl_bus_reserved_bits, reserved_wl_bus, false);
/* Connect SRAM BL/WLs to bus */
BasicPort mux_bl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BL),
num_conf_bits);
BasicPort bl_bus_regular_bits(bl_bus.get_name(), num_reserved_conf_bits, num_reserved_conf_bits + num_conf_bits - 1);
print_verilog_wire_connection(fp, bl_bus_regular_bits, mux_bl_wire, false);
BasicPort mux_wl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WL),
num_conf_bits);
BasicPort wl_bus_regular_bits(wl_bus.get_name(), num_reserved_conf_bits, num_reserved_conf_bits + num_conf_bits - 1);
print_verilog_wire_connection(fp, wl_bus_regular_bits, mux_wl_wire, false);
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
}
/*********************************************************************
* Print a number of bus ports which are wired to the configuration
* ports of a routing multiplexer
*********************************************************************/
void print_verilog_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const e_sram_orgz& sram_orgz_type,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_reserved_conf_bits,
const size_t& num_conf_bits) {
/* Depend on the design technology of this MUX:
* bus connections are different
* SRAM MUX: bus is connected to the output ports of SRAM
* RRAM MUX: bus is connected to the BL/WL of MUX
* TODO: Maybe things will become even more complicated,
* the bus connections may depend on the type of configuration circuit...
* Currently, this is fine.
*/
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
print_verilog_cmos_mux_config_bus(fp, circuit_lib, mux_model, sram_orgz_type, mux_size, mux_instance_id, num_conf_bits);
break;
case SPICE_MODEL_DESIGN_RRAM:
print_verilog_rram_mux_config_bus(fp, circuit_lib, mux_model, sram_orgz_type, mux_size, mux_instance_id, num_reserved_conf_bits, num_conf_bits);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid design technology for routing multiplexer!\n",
__FILE__, __LINE__);
exit(1);
}
}
/*********************************************************************
* Print a wire to connect MUX configuration ports
* This function connects the sram ports to the ports of a Verilog module
* used for formal verification
*********************************************************************/
void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_conf_bits) {
BasicPort mux_sram_output(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
BasicPort formal_verification_port(generate_formal_verification_sram_port_name(circuit_lib, sram_models[0]),
num_conf_bits);
print_verilog_wire_connection(fp, mux_sram_output, formal_verification_port, false);
}

View File

@ -90,4 +90,20 @@ void print_verilog_local_sram_wires(std::fstream& fp,
const e_sram_orgz sram_orgz_type,
const size_t& port_size);
void print_verilog_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const e_sram_orgz& sram_orgz_type,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_reserved_conf_bits,
const size_t& num_conf_bits);
void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_conf_bits);
#endif