Merge remote-tracking branch 'origin/dev' into heterogeneous
This commit is contained in:
commit
640922accd
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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,10 +927,34 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -189,20 +189,20 @@ int multilevel_mux_last_level_input_num(int num_level, int num_input_per_unit,
|
|||
|
||||
/***************************************************************************************
|
||||
* Find the number of inputs for a encoder with a given output size
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* 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
|
||||
***************************************************************************************/
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* 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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -994,7 +994,7 @@ void dump_verilog_cmos_mux_multilevel_structure(FILE* fp,
|
|||
if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) {
|
||||
/* Get the number of inputs */
|
||||
int num_outputs = cur_num_input_basis;
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
/* Find the decoder name */
|
||||
fprintf(fp, "%s %s_%d_ (",
|
||||
generate_verilog_decoder_subckt_name(num_inputs, num_outputs),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue