start refactoring bitstream generator

This commit is contained in:
tangxifan 2019-10-24 21:01:11 -06:00
parent 13c62fdcf8
commit 838173f3c4
11 changed files with 658 additions and 21 deletions

View File

@ -1,6 +1,8 @@
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "util.h"
/*General Purpose Linked List*/
typedef struct s_llist t_llist;
struct s_llist

View File

@ -3,6 +3,7 @@
* data structures in mux_graph.h
*************************************************/
#include <cmath>
#include <list>
#include <map>
#include <algorithm>
@ -482,6 +483,21 @@ MuxNodeId MuxGraph::node_id(const MuxInputId& input_id) const {
return MuxNodeId::INVALID();
}
/* Get the node id of a given output */
MuxNodeId MuxGraph::node_id(const MuxOutputId& output_id) const {
/* Use the node_lookup to accelerate the search */
for (const auto& lvl : node_lookup_) {
for (const auto& cand_node : lvl[MUX_OUTPUT_NODE]) {
if (output_id == node_output_ids_[cand_node]) {
return cand_node;
}
}
}
return MuxNodeId::INVALID();
}
/* Get the node id w.r.t. the node level and node_index at the level
* Return an invalid value if not found
*/
@ -516,19 +532,41 @@ MuxNodeId MuxGraph::node_id(const size_t& node_level, const size_t& node_index_a
return ret_node;
}
/* Decode memory bits based on an input id */
std::vector<size_t> MuxGraph::decode_memory_bits(const MuxInputId& input_id) const {
/* Decode memory bits based on an input id and an output id */
std::vector<bool> MuxGraph::decode_memory_bits(const MuxInputId& input_id,
const MuxOutputId& output_id) const {
/* initialize the memory bits: TODO: support default value */
std::vector<size_t> mem_bits(mem_ids_.size(), 0);
std::vector<bool> mem_bits(mem_ids_.size(), false);
/* valid the input */
/* valid the input and output */
VTR_ASSERT_SAFE(valid_input_id(input_id));
VTR_ASSERT_SAFE(valid_output_id(output_id));
/* Route the input to the output and update mem */
MuxNodeId next_node = node_id(input_id);
while ( 0 < node_out_edges_[next_node].size() ) {
VTR_ASSERT_SAFE (1 == node_out_edges_[next_node].size());
MuxEdgeId edge = node_out_edges_[next_node][0];
/* Mark all the nodes as not visited */
vtr::vector<MuxNodeId, bool> visited(nodes().size(), false);
/* Create a queue for Breadth-First Search */
std::list<MuxNodeId> queue;
/* Mark the input node as visited and enqueue it */
visited[node_id(input_id)] = true;
queue.push_back(node_id(input_id));
/* Create a flag to indicate if the route is success or not */
bool route_success = false;
while(!queue.empty()) {
/* Dequeue a mux node from queue,
* we will walk through all the fan-in of this node in this loop
*/
MuxNodeId node_to_expand = queue.front();
queue.pop_front();
/* Get all fan-in nodes of the dequeued node
* If the node has not been visited,
* then mark it visited and enqueue it
*/
VTR_ASSERT_SAFE (1 == node_out_edges_[node_to_expand].size());
MuxEdgeId edge = node_out_edges_[node_to_expand][0];
/* Configure the mem bits:
* if inv_mem is enabled, it means 0 to enable this edge
@ -537,25 +575,113 @@ std::vector<size_t> MuxGraph::decode_memory_bits(const MuxInputId& input_id) con
MuxMemId mem = edge_mem_ids_[edge];
VTR_ASSERT_SAFE (valid_mem_id(mem));
if (true == edge_inv_mem_[edge]) {
mem_bits[size_t(mem)] = 0;
mem_bits[size_t(mem)] = false;
} else {
mem_bits[size_t(mem)] = 1;
mem_bits[size_t(mem)] = true;
}
/* each edge must have 1 fan-out */
VTR_ASSERT_SAFE (1 == edge_sink_nodes_[edge].size());
/* Visit the next node */
next_node = edge_sink_nodes_[edge][0];
/* Get the fan-out node */
MuxNodeId next_node = edge_sink_nodes_[edge][0];
/* If next node is the output node we want, we can finish here */
if (next_node == node_id(output_id)) {
route_success = true;
break;
}
/* valid the output */
VTR_ASSERT_SAFE(MUX_OUTPUT_NODE == node_types_[next_node]);
VTR_ASSERT_SAFE(valid_output_id(node_output_ids_[next_node]));
/* Add next node to the queue if not visited yet */
if (false == visited[next_node]) {
visited[next_node] = true;
queue.push_back(next_node);
}
}
/* Routing must be success! */
VTR_ASSERT(true == route_success);
return mem_bits;
}
/* Find the input node that the memory bits will route an output node to
* This function backward propagate from the output node to an input node
* assuming the memory bits are applied
*/
MuxInputId MuxGraph::find_input_node_driven_by_output_node(const std::map<MuxMemId, bool>& memory_bits,
const MuxOutputId& output_id) const {
/* Ensure that the memory bits fit the size of memory bits in this MUX */
VTR_ASSERT(memory_bits.size() == mem_ids_.size());
/* valid the output */
VTR_ASSERT_SAFE(valid_output_id(output_id));
/* Start from the output node */
/* Mark all the nodes as not visited */
vtr::vector<MuxNodeId, bool> visited(nodes().size(), false);
/* Create a queue for Breadth-First Search */
std::list<MuxNodeId> queue;
/* Mark the output node as visited and enqueue it */
visited[node_id(output_id)] = true;
queue.push_back(node_id(output_id));
/* Record the destination input id */
MuxInputId des_input_id = MuxInputId::INVALID();
while(!queue.empty()) {
/* Dequeue a mux node from queue,
* we will walk through all the fan-in of this node in this loop
*/
MuxNodeId node_to_expand = queue.front();
queue.pop_front();
/* Get all fan-in nodes of the dequeued node
* If the node has not been visited,
* then mark it visited and enqueue it
*/
MuxEdgeId next_edge = MuxEdgeId::INVALID();
for (const MuxEdgeId& edge : node_in_edges_[node_to_expand]) {
/* Configure the mem bits and find the edge that will propagate the signal
* if inv_mem is enabled, it means false to enable this edge
* otherwise, it is true to enable this edge
*/
MuxMemId mem = edge_mem_ids_[edge];
VTR_ASSERT_SAFE (valid_mem_id(mem));
if (edge_inv_mem_[edge] == !memory_bits.at(mem)) {
next_edge = edge;
break;
}
}
/* We must have a valid next edge */
VTR_ASSERT(MuxEdgeId::INVALID() != next_edge);
/* each edge must have 1 fan-out */
VTR_ASSERT_SAFE (1 == edge_src_nodes_[next_edge].size());
/* Get the fan-in node */
MuxNodeId next_node = edge_src_nodes_[next_edge][0];
/* If next node is an input node, we can finish here */
if (true == is_node_input(next_node)) {
des_input_id = input_id(next_node);
break;
}
/* Add next node to the queue if not visited yet */
if (false == visited[next_node]) {
visited[next_node] = true;
queue.push_back(next_node);
}
}
/* Routing must be success! */
VTR_ASSERT(MuxInputId::INVALID() != des_input_id);
return des_input_id;
}
/**************************************************
* Private mutators: basic operations
*************************************************/

View File

@ -27,6 +27,7 @@
#ifndef MUX_GRAPH_H
#define MUX_GRAPH_H
#include <map>
#include "vtr_vector.h"
#include "vtr_range.h"
#include "mux_graph_fwd.h"
@ -105,6 +106,8 @@ class MuxGraph {
std::vector<MuxGraph> build_mux_branch_graphs() const;
/* Get the node id of a given input */
MuxNodeId node_id(const MuxInputId& input_id) const;
/* Get the node id of a given output */
MuxNodeId node_id(const MuxOutputId& output_id) const;
/* Get the node id w.r.t. the node level and node_index at the level */
MuxNodeId node_id(const size_t& node_level, const size_t& node_index_at_level) const;
/* Get the input id of a given node */
@ -115,8 +118,19 @@ class MuxGraph {
MuxOutputId output_id(const MuxNodeId& node_id) const;
/* Identify if the node is an output of the MUX */
bool is_node_output(const MuxNodeId& node_id) const;
/* Decode memory bits based on an input id */
std::vector<size_t> decode_memory_bits(const MuxInputId& input_id) const;
/* Decode memory bits based on an input id and an output id
* This function will start from the input node
* and do a forward propagation until reaching the output node
*/
std::vector<bool> decode_memory_bits(const MuxInputId& input_id,
const MuxOutputId& output_id) const;
/* Find the input node that the memory bits will route an output node to
* This function backward propagate from the output node to an input node
* assuming the memory bits are applied
* Note: This function is mainly used for decoding LUT MUXes
*/
MuxInputId find_input_node_driven_by_output_node(const std::map<MuxMemId, bool>& memory_bits,
const MuxOutputId& output_id) const;
private: /* Private mutators : basic operations */
/* Add a unconfigured node to the MuxGraph */
MuxNodeId add_node(const enum e_mux_graph_node_type& node_type);

View File

@ -30,6 +30,7 @@
#include "mux_library_builder.h"
#include "build_module_graph.h"
#include "build_device_bitstream.h"
#include "spice_api.h"
#include "verilog_api.h"
@ -82,6 +83,18 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup,
device_size, grids,
rr_switches, clb2clb_directs, device_rr_gsb);
/* Build bitstream database if needed */
BitstreamManager bitstream_manager;
if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream)
&&(FALSE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.do_spice)
&&(FALSE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_syn_verilog)) {
bitstream_manager = build_device_bitstream(vpr_setup, Arch, module_manager,
Arch.spice->circuit_lib, mux_lib,
device_size, grids,
rr_switches, rr_node, device_rr_gsb);
}
/* Xifan TANG: SPICE Modeling, SPICE Netlist Output */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.do_spice) {
vpr_fpga_spice(vpr_setup, Arch, vpr_setup.FileNameOpts.CircuitName);

View File

@ -0,0 +1,91 @@
/********************************************************************
* This file includes functions to build bitstream from a mapped
* FPGA fabric.
* We decode the bitstream from configuration of routing multiplexers
* and Look-Up Tables (LUTs) which locate in CLBs and global routing architecture
*******************************************************************/
#include <vector>
#include <time.h>
#include "vtr_assert.h"
#include "util.h"
#include "fpga_x2p_naming.h"
#include "build_routing_bitstream.h"
#include "build_device_bitstream.h"
/********************************************************************
* Top-level function to build a bistream from the FPGA device
* 1. It will organize the bitstream w.r.t. the hierarchy of module graphs
* describing the FPGA fabric
* 2. It will decode configuration bits from routing multiplexers used in
* global routing architecture
* 3. It will decode configuration bits from routing multiplexers and LUTs
* used in CLBs
*
* Note: this function create a bitstream which is binding to the module graphs
* of the FPGA fabric that FPGA-X2P generates!
* But it can be used to output a generic bitstream for VPR mapping FPGA
*******************************************************************/
BitstreamManager build_device_bitstream(const t_vpr_setup& vpr_setup,
const t_arch& arch,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const DeviceRRGSB& L_device_rr_gsb) {
/* Check if the routing architecture we support*/
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
vpr_printf(TIO_MESSAGE_ERROR,
"FPGA X2P only supports uni-directional routing architecture!\n");
exit(1);
}
/* We don't support mrFPGA */
#ifdef MRFPGA_H
if (is_mrFPGA) {
vpr_printf(TIO_MESSAGE_ERROR,
"FPGA X2P does not support mrFPGA!\n");
exit(1);
}
#endif
/* Bistream builder formally starts*/
vpr_printf(TIO_MESSAGE_INFO, "\nStart building bitstream for FPGA fabric...\n");
/* Bitstream manager to be built */
BitstreamManager bitstream_manager;
/* Start time count */
clock_t t_start = clock();
/* Assign the SRAM model applied to the FPGA fabric */
VTR_ASSERT(NULL != arch.sram_inf.verilog_sram_inf_orgz); /* Check !*/
t_spice_model* mem_model = arch.sram_inf.verilog_sram_inf_orgz->spice_model;
/* initialize the SRAM organization information struct */
CircuitModelId sram_model = arch.spice->circuit_lib.model(mem_model->name);
VTR_ASSERT(CircuitModelId::INVALID() != sram_model);
/* Create the top-level block for bitstream
* This is related to the top-level module of fpga
*/
std::string top_block_name = generate_fpga_top_module_name();
ConfigBlockId top_block = bitstream_manager.add_block(top_block_name);
/* Create bitstream from routing architectures */
build_routing_bitstream(bitstream_manager, module_manager, circuit_lib, mux_lib, rr_switches, L_rr_node, L_device_rr_gsb);
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"Building bitstream took %g seconds\n",
run_time_sec);
return bitstream_manager;
}

View File

@ -0,0 +1,26 @@
/********************************************************************
* Header file for build_device_bitstream.cpp
*******************************************************************/
#ifndef BUILD_DEVICE_BITSTREAM_H
#define BUILD_DEVICE_BITSTREAM_H
#include <vector>
#include "bitstream_manager.h"
#include "vpr_types.h"
#include "module_manager.h"
#include "circuit_library.h"
#include "mux_library.h"
#include "rr_blocks.h"
BitstreamManager build_device_bitstream(const t_vpr_setup& vpr_setup,
const t_arch& arch,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& grids,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const DeviceRRGSB& L_device_rr_gsb);
#endif

View File

@ -0,0 +1,105 @@
/********************************************************************
* This file includes functions to build bitstream from routing multiplexers
* which are based on different technology
*******************************************************************/
#include "vtr_assert.h"
#include "mux_utils.h"
#include "fpga_x2p_types.h"
#include "build_mux_bitstream.h"
/********************************************************************
* Find the default path id of a MUX
* This is applied when the path id specified is DEFAULT_PATH_ID,
* which is not correlated to the MUX implementation
* This function is binding the default path id to the implemented structure
* 1. If the MUX has a constant input, the default path id will be
* directed to the last input of the MUX, which is the constant input
* 2. If the MUX does not have a constant input, the default path id
* will the first input of the MUX.
*
* Restriction:
* we assume the default path is the first input of the MUX
* Change if this is not what you want
*******************************************************************/
size_t find_mux_default_path_id(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size) {
size_t default_path_id;
if (TRUE == circuit_lib.mux_add_const_input(mux_model)) {
default_path_id = mux_size; /* When there is a constant input, use the last path */
} else {
default_path_id = DEFAULT_MUX_PATH_ID; /* When there is no constant input, use the default one */
}
return default_path_id;
}
/********************************************************************
* This function generates bitstream for a CMOS routing multiplexer
* Thanks to MuxGraph object has already describe the internal multiplexing
* structure, bitstream generation is simply done by routing the signal
* to from a given input to the output
* All the memory bits can be generated by an API of MuxGraph
*
* To be generic, this function only returns a vector bit values
* without touching an bitstream-relate data structure
*******************************************************************/
static
std::vector<bool> build_cmos_mux_bitstream(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxLibrary& mux_lib,
const size_t& mux_size,
const int& path_id) {
/* Note that the size of implemented mux could be different than the mux size we see here,
* due to the constant inputs
* We will find the input size of implemented MUX and fetch the graph-based representation in MUX library
*/
size_t implemented_mux_size = find_mux_implementation_num_inputs(circuit_lib, mux_model, mux_size);
MuxId mux_graph_id = mux_lib.mux_graph(mux_model, implemented_mux_size);
const MuxGraph mux_graph = mux_lib.mux_graph(mux_graph_id);
size_t datapath_id = path_id;
/* Find the path_id related to the implementation */
if (DEFAULT_PATH_ID == path_id) {
datapath_id = find_mux_default_path_id(circuit_lib, mux_model, implemented_mux_size);
} else {
VTR_ASSERT( datapath_id < mux_size);
}
/* We should have only one output for this MUX! */
VTR_ASSERT(1 == mux_graph.outputs().size());
/* Generate the memory bits */
return mux_graph.decode_memory_bits(MuxInputId(datapath_id), mux_graph.output_id(mux_graph.outputs()[0]));
}
/********************************************************************
* This function generates bitstream for a routing multiplexer
* supporting both CMOS and ReRAM multiplexer designs
*******************************************************************/
std::vector<bool> build_mux_bitstream(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxLibrary& mux_lib,
const size_t& mux_size,
const int& path_id) {
std::vector<bool> mux_bitstream;
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
mux_bitstream = build_cmos_mux_bitstream(circuit_lib, mux_model, mux_lib, mux_size, path_id);
break;
case SPICE_MODEL_DESIGN_RRAM:
/* TODO: ReRAM MUX needs a different bitstream generation strategy */
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());
exit(1);
}
return mux_bitstream;
}

View File

@ -0,0 +1,21 @@
/********************************************************************
* Header file for build_mux_bitstream.cpp
*******************************************************************/
#ifndef BUILD_MUX_BITSTREAM_H
#define BUILD_MUX_BITSTREAM_H
#include <vector>
#include "circuit_library.h"
#include "mux_library.h"
size_t find_mux_default_path_id(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size);
std::vector<bool> build_mux_bitstream(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const MuxLibrary& mux_lib,
const size_t& mux_size,
const int& path_id);
#endif

View File

@ -0,0 +1,214 @@
/********************************************************************
* This file includes functions to build bitstream from global routing
* architecture of a mapped FPGA fabric
* We decode the bitstream from configuration of routing multiplexers
* which locate in global routing architecture
*******************************************************************/
#include <vector>
#include <time.h>
#include "vtr_assert.h"
#include "util.h"
#include "mux_utils.h"
#include "fpga_x2p_types.h"
#include "fpga_x2p_naming.h"
#include "fpga_x2p_utils.h"
#include "build_mux_bitstream.h"
#include "build_routing_bitstream.h"
/********************************************************************
* This function generates bitstream for a routing multiplexer
* This function will identify if a node indicates a routing multiplexer
* If not a routing multiplexer, no bitstream is needed here
* If yes, we will generate the bitstream for the routing multiplexer
*******************************************************************/
static
void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const RRGSB& rr_gsb,
t_rr_node* cur_rr_node,
const std::vector<t_rr_node*>& drive_rr_nodes,
const int& switch_index) {
/* Check current rr_node is CHANX or CHANY*/
VTR_ASSERT((CHANX == cur_rr_node->type)||(CHANY == cur_rr_node->type));
/* Find the circuit model id of the mux, we need its design technology which matters the bitstream generation */
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();
/* Find out which routing path is used in this MUX */
int path_id = DEFAULT_PATH_ID;
for (size_t inode = 0; inode < drive_rr_nodes.size(); ++inode) {
if (drive_rr_nodes[inode] == &(L_rr_node[cur_rr_node->prev_node])) {
path_id = (int)inode;
break;
}
}
/* Ensure that our path id makes sense! */
VTR_ASSERT( (DEFAULT_PATH_ID == path_id)
|| ( (DEFAULT_PATH_ID < path_id) && (path_id < (int)datapath_mux_size) )
);
/* Generate bitstream depend on both technology and structure of this MUX */
std::vector<bool> mux_bitstream = build_mux_bitstream(circuit_lib, mux_model, mux_lib, datapath_mux_size, path_id);
/* Add the bistream to the bitstream manager */
for (const bool& bit : mux_bitstream) {
bitstream_manager.add_bit(bit);
}
}
/********************************************************************
* This function generates bitstream for an interconnection,
* i.e., a routing multiplexer, in a Switch Block
* This function will identify if a node indicates a routing multiplexer
* If not a routing multiplexer, no bitstream is needed here
* If yes, we will generate the bitstream for the routing multiplexer
*******************************************************************/
static
void build_switch_block_interc_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const RRGSB& rr_gsb,
const e_side& chan_side,
const size_t& chan_node_id) {
std::vector<t_rr_node*> drive_rr_nodes;
/* Get the node */
t_rr_node* cur_rr_node = rr_gsb.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_gsb.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())
|| (0 == drive_rr_nodes.size()) ) {
/* No bitstream generation required by a special direct connection*/
return;
} else if (1 < drive_rr_nodes.size()) {
/* This is a routing multiplexer! Generate bitstream */
build_switch_block_mux_bitstream(bitstream_manager, module_manager,
circuit_lib, mux_lib, rr_switches, L_rr_node,
rr_gsb, cur_rr_node, drive_rr_nodes,
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID]);
} /*Nothing should be done else*/
}
/********************************************************************
* This function generates bitstream for a Switch Block
* and add it to the bitstream manager
* This function will spot all the routing multiplexers in a Switch Block
* using a simple but effective rule:
* The fan-in of each output node.
* If there are more than 2 fan-in, there is a routing multiplexer
*
* Note that the output nodes typically spread over all the sides of a Switch Block
* So, we will iterate over that.
*******************************************************************/
static
void build_switch_block_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const RRGSB& rr_sb) {
/* TODO: Create a block for the bitstream which corresponds to the Switch block */
/* Iterate over all the multiplexers */
for (size_t side = 0; side < rr_sb.get_num_sides(); ++side) {
Side side_manager(side);
for (size_t itrack = 0; itrack < rr_sb.get_chan_width(side_manager.get_side()); ++itrack) {
VTR_ASSERT( (CHANX == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)
|| (CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type));
/* Only output port indicates a routing multiplexer */
if (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
continue;
}
build_switch_block_interc_bitstream(bitstream_manager, module_manager,
circuit_lib, mux_lib, rr_switches, L_rr_node,
rr_sb, side_manager.get_side(), itrack);
}
}
}
/********************************************************************
* Top-level function to create bitstream for global routing architecture
* Two major tasks:
* 1. Generate bitstreams for Switch Blocks
* 2. Generate bitstreams for both X-direction and Y-direction Connection Blocks
*******************************************************************/
void build_routing_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const DeviceRRGSB& L_device_rr_gsb) {
/* Generate bitstream for each switch blocks
* To organize the bitstream in blocks, we create a block for each switch block
* and give names which are same as they are in top-level module managers
*/
vpr_printf(TIO_MESSAGE_INFO,
"Generating bitstream for Switch blocks...\n");
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
build_switch_block_bitstream(bitstream_manager, module_manager,
circuit_lib, mux_lib, rr_switches, L_rr_node,
rr_gsb);
}
}
/* Generate bitstream for each connection blocks
* To organize the bitstream in blocks, we create a block for each connection block
* and give names which are same as they are in top-level module managers
*/
DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range();
vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Connection blocks ...\n");
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < cb_range.get_y(); ++iy) {
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
/* X - channels [1...nx][0..ny]*/
if ((TRUE == is_cb_exist(CHANX, ix, iy))
&&(true == rr_gsb.is_cb_exist(CHANX))) {
/*
fpga_spice_generate_bitstream_routing_connection_box_subckt(fp,
rr_gsb, CHANX,
cur_sram_orgz_info);
*/
}
/* Y - channels [1...ny][0..nx]*/
if ((TRUE == is_cb_exist(CHANY, ix, iy))
&&(true == rr_gsb.is_cb_exist(CHANY))) {
/*
fpga_spice_generate_bitstream_routing_connection_box_subckt(fp,
rr_gsb, CHANY,
cur_sram_orgz_info);
*/
}
}
}
}

View File

@ -0,0 +1,23 @@
/********************************************************************
* Header file for build_routing_bitstream.cpp
*******************************************************************/
#ifndef BUILD_ROUTING_BITSTREAM_H
#define BUILD_ROUTING_BITSTREAM_H
#include <vector>
#include "bitstream_manager.h"
#include "vpr_types.h"
#include "module_manager.h"
#include "circuit_library.h"
#include "mux_library.h"
#include "rr_blocks.h"
void build_routing_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const std::vector<t_switch_inf>& rr_switches,
t_rr_node* L_rr_node,
const DeviceRRGSB& L_device_rr_gsb);
#endif

View File

@ -51,7 +51,8 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
#endif
/* Module Graph builder formally starts*/
vpr_printf(TIO_MESSAGE_INFO, "\nStart building module graphs for FPGA fabric...\n");
vpr_printf(TIO_MESSAGE_INFO,
"\nStart building module graphs for FPGA fabric...\n");
/* Module manager to be built */
ModuleManager module_manager;
@ -135,8 +136,9 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO, "Building module graphs took %g seconds\n", run_time_sec);
vpr_printf(TIO_MESSAGE_INFO,
"Building module graphs took %g seconds\n",
run_time_sec);
return module_manager;
}