OpenFPGA/vpr7_x2p/vpr/SRC/device/mux_library_builder.cpp

187 lines
7.9 KiB
C++

/********************************************************************
* This file includes the functions of builders for MuxLibrary.
*******************************************************************/
#include <cmath>
#include <stdio.h>
#include "vtr_assert.h"
/* Device-level header files */
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
/* FPGA-X2P context header files */
#include "fpga_x2p_utils.h"
#include "spice_types.h"
#include "circuit_library.h"
#include "mux_library.h"
#include "mux_library_builder.h"
/********************************************************************
* Update MuxLibrary with the unique multiplexer structures
* found in the global routing architecture
*******************************************************************/
static
void build_routing_arch_mux_library(MuxLibrary& mux_lib,
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_switch_inf* switches,
const CircuitLibrary& circuit_lib,
t_det_routing_arch* routing_arch) {
/* Current Version: Support Uni-directional routing architecture only*/
if (UNI_DIRECTIONAL != routing_arch->directionality) {
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s, LINE[%d]) FPGA X2P Only supports uni-directional routing architecture.\n",
__FILE__, __LINE__);
exit(1);
}
/* The routing path is.
* OPIN ----> CHAN ----> ... ----> CHAN ----> IPIN
* Each edge is a switch, for IPIN, the switch is a connection block,
* for the rest is a switch box
*/
/* Count the sizes of muliplexers in routing architecture */
for (int inode = 0; inode < LL_num_rr_nodes; inode++) {
t_rr_node& node = LL_rr_node[inode];
switch (node.type) {
case IPIN: {
/* Have to consider the fan_in only, it is a connection block (multiplexer)*/
VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in));
if ( (0 == node.fan_in) || (1 == node.fan_in)) {
break;
}
/* Find the circuit_model for multiplexers in connection blocks */
const CircuitModelId& cb_switch_circuit_model = switches[node.driver_switch].circuit_model;
/* we should select a circuit model for the connection box*/
VTR_ASSERT(CircuitModelId::INVALID() != cb_switch_circuit_model);
/* Add the mux to mux_library */
mux_lib.add_mux(circuit_lib, cb_switch_circuit_model, node.fan_in);
break;
}
case CHANX:
case CHANY: {
/* Channels are the same, have to consider the fan_in as well,
* it could be a switch box if previous rr_node is a channel
* or it could be a connection box if previous rr_node is a IPIN or OPIN
*/
VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in));
if ((0 == node.fan_in) || (1 == node.fan_in)) {
break;
}
/* Find the spice_model for multiplexers in switch blocks*/
const CircuitModelId& sb_switch_circuit_model = switches[node.driver_switch].circuit_model;
/* we should select a circuit model for the Switch box*/
VTR_ASSERT(CircuitModelId::INVALID() != sb_switch_circuit_model);
/* Add the mux to mux_library */
mux_lib.add_mux(circuit_lib, sb_switch_circuit_model, node.fan_in);
break;
}
default:
/* We do not care other types of rr_node */
break;
}
}
}
/********************************************************************
* Update MuxLibrary with the unique multiplexer structures
* found in programmable logic blocks
********************************************************************/
static
void build_pb_type_mux_library_rec(MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
t_pb_type* cur_pb_type) {
VTR_ASSERT(nullptr != cur_pb_type);
/* If there is spice_model_name, this is a leaf node!*/
if (TRUE == is_primitive_pb_type(cur_pb_type)) {
/* What annoys me is VPR create a sub pb_type for each lut which suppose to be a leaf node
* This may bring software convience but ruins circuit modeling
*/
VTR_ASSERT(CircuitModelId::INVALID() != cur_pb_type->phy_pb_type->circuit_model);
return;
}
/* Traversal the hierarchy, find all the multiplexer from the interconnection part */
for (int imode = 0; imode < cur_pb_type->num_modes; imode++) {
/* Then we have to statisitic the interconnections*/
for (int jinterc = 0; jinterc < cur_pb_type->modes[imode].num_interconnect; jinterc++) {
/* Check the num_mux and fan_in of an interconnection */
VTR_ASSERT ((0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux)
|| (0 < cur_pb_type->modes[imode].interconnect[jinterc].num_mux));
if (0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) {
continue;
}
CircuitModelId& interc_circuit_model = cur_pb_type->modes[imode].interconnect[jinterc].circuit_model;
VTR_ASSERT(CircuitModelId::INVALID() != interc_circuit_model);
/* Add the mux model to library */
mux_lib.add_mux(circuit_lib, interc_circuit_model, cur_pb_type->modes[imode].interconnect[jinterc].fan_in);
}
}
/* Go recursively to the lower level */
for (int imode = 0; imode < cur_pb_type->num_modes; imode++) {
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ichild++) {
build_pb_type_mux_library_rec(mux_lib, circuit_lib,
&cur_pb_type->modes[imode].pb_type_children[ichild]);
}
}
}
/********************************************************************
* Update MuxLibrary with the unique multiplexers required by
* LUTs in the circuit library
********************************************************************/
static
void build_lut_mux_library(MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib) {
/* Find all the circuit models which are LUTs in the circuit library */
for (const auto& circuit_model : circuit_lib.models()) {
/* Bypass non-LUT circuit models */
if (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) {
continue;
}
/* Find the MUX size required by the LUT */
/* Get input ports which are not global ports! */
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
VTR_ASSERT(1 == input_ports.size());
/* MUX size = 2^lut_size */
size_t lut_mux_size = (size_t)pow(2., (double)(circuit_lib.port_size(input_ports[0])));
/* Add mux to the mux library */
mux_lib.add_mux(circuit_lib, circuit_model, lut_mux_size);
}
}
/* Statistic for all the multiplexers in FPGA
* We determine the sizes and its structure (according to spice_model) for each type of multiplexers
* We search multiplexers in Switch Blocks, Connection blocks and Configurable Logic Blocks
* In additional to multiplexers, this function also consider crossbars.
* All the statistics are stored in a linked list, as a return value
*/
MuxLibrary build_device_mux_library(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_switch_inf* switches,
const CircuitLibrary& circuit_lib,
t_det_routing_arch* routing_arch) {
/* MuxLibrary to store the information of Multiplexers*/
MuxLibrary mux_lib;
/* Step 1: We should check the multiplexer spice models defined in routing architecture.*/
build_routing_arch_mux_library(mux_lib, LL_num_rr_nodes, LL_rr_node, switches, circuit_lib, routing_arch);
/* Step 2: Count the sizes of multiplexers in complex logic blocks */
for (int itype = 0; itype < num_types; itype++) {
if (NULL != type_descriptors[itype].pb_type) {
build_pb_type_mux_library_rec(mux_lib, circuit_lib, type_descriptors[itype].pb_type);
}
}
/* Step 3: count the size of multiplexer that will be used in LUTs*/
build_lut_mux_library(mux_lib, circuit_lib);
return mux_lib;
}