add mux library builder

This commit is contained in:
tangxifan 2020-02-12 14:58:23 -07:00
parent ce63b1cc62
commit c78d3e9af1
8 changed files with 337 additions and 0 deletions

View File

@ -7,6 +7,7 @@
#include "vpr_device_annotation.h"
#include "vpr_clustering_annotation.h"
#include "vpr_routing_annotation.h"
#include "mux_library.h"
#include "device_rr_gsb.h"
/********************************************************************
@ -44,6 +45,7 @@ class OpenfpgaContext : public Context {
const openfpga::VprClusteringAnnotation& vpr_clustering_annotation() const { return vpr_clustering_annotation_; }
const openfpga::VprRoutingAnnotation& vpr_routing_annotation() const { return vpr_routing_annotation_; }
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
public: /* Public mutators */
openfpga::Arch& mutable_arch() { return arch_; }
openfpga::VprDeviceAnnotation& mutable_vpr_device_annotation() { return vpr_device_annotation_; }
@ -51,6 +53,7 @@ class OpenfpgaContext : public Context {
openfpga::VprClusteringAnnotation& mutable_vpr_clustering_annotation() { return vpr_clustering_annotation_; }
openfpga::VprRoutingAnnotation& mutable_vpr_routing_annotation() { return vpr_routing_annotation_; }
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
private: /* Internal data */
/* Data structure to store information from read_openfpga_arch library */
openfpga::Arch arch_;
@ -69,6 +72,9 @@ class OpenfpgaContext : public Context {
/* Device-level annotation */
openfpga::DeviceRRGSB device_rr_gsb_;
/* Library of physical implmentation of routing multiplexers */
openfpga::MuxLibrary mux_lib_;
};
#endif

View File

@ -13,6 +13,7 @@
#include "annotate_pb_graph.h"
#include "annotate_routing.h"
#include "annotate_rr_graph.h"
#include "mux_library_builder.h"
#include "openfpga_link_arch.h"
/* Include global variables of VPR */
@ -21,6 +22,28 @@
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* A function to identify if the routing resource graph generated by
* VPR is support by OpenFPGA
* - Currently we only support uni-directional
* It means every routing tracks must have a direction
*******************************************************************/
static
bool is_vpr_rr_graph_supported(const RRGraph& rr_graph) {
/* Check if the rr_graph is uni-directional*/
for (const RRNodeId& node : rr_graph.nodes()) {
if (CHANX != rr_graph.node_type(node) && CHANY != rr_graph.node_type(node)) {
continue;
}
if (BI_DIRECTION == rr_graph.node_direction(node)) {
VTR_LOG_ERROR("Routing resource graph is bi-directional. OpenFPGA currently supports uni-directional routing architecture only.\n");
return false;
}
}
return true;
}
/********************************************************************
* Top-level function to link openfpga architecture to VPR, including:
* - physical pb_type
@ -72,9 +95,17 @@ void link_arch(OpenfpgaContext& openfpga_context,
* - RRGSB
* - DeviceRRGSB
*/
if (false == is_vpr_rr_graph_supported(g_vpr_ctx.device().rr_graph)) {
return;
}
annotate_device_rr_gsb(g_vpr_ctx.device(),
openfpga_context.mutable_device_rr_gsb(),
cmd_context.option_enable(cmd, opt_verbose));
/* Build multiplexer library */
openfpga_context.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(),
const_cast<const OpenfpgaContext&>(openfpga_context));
}
} /* end namespace openfpga */

View File

@ -0,0 +1,228 @@
/********************************************************************
* This file includes the functions of builders for MuxLibrary.
*******************************************************************/
#include <cmath>
/* Headers from vtrutil library */
#include "vtr_time.h"
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from readarchopenfpga library */
#include "circuit_types.h"
#include "circuit_library.h"
#include "mux_utils.h"
#include "pb_type_utils.h"
#include "pb_graph_utils.h"
#include "openfpga_rr_graph_utils.h"
#include "mux_library.h"
#include "mux_library_builder.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Update MuxLibrary with the unique multiplexer structures
* found in the global routing architecture
*******************************************************************/
static
void build_routing_arch_mux_library(const DeviceContext& vpr_device_ctx,
const CircuitLibrary& circuit_lib,
const VprDeviceAnnotation& vpr_device_annotation,
MuxLibrary& mux_lib) {
/* 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 (const RRNodeId& node : vpr_device_ctx.rr_graph.nodes()) {
switch (vpr_device_ctx.rr_graph.node_type(node)) {
case IPIN:
case CHANX:
case CHANY: {
/* Have to consider the fan_in only, it is a connection block (multiplexer)*/
if ( (0 == vpr_device_ctx.rr_graph.node_in_edges(node).size())
|| (1 == vpr_device_ctx.rr_graph.node_in_edges(node).size()) ) {
break;
}
/* Find the circuit_model for multiplexers in connection blocks */
std::vector<RRSwitchId> driver_switches = get_rr_graph_driver_switches(vpr_device_ctx.rr_graph, node);
VTR_ASSERT(1 == driver_switches.size());
const CircuitModelId& rr_switch_circuit_model = vpr_device_annotation.rr_switch_circuit_model(driver_switches[0]);
/* we should select a circuit model for the routing resource switch */
VTR_ASSERT(CircuitModelId::INVALID() != rr_switch_circuit_model);
/* Add the mux to mux_library */
mux_lib.add_mux(circuit_lib, rr_switch_circuit_model, vpr_device_ctx.rr_graph.node_in_edges(node).size());
break;
}
default:
/* We do not care other types of rr_node */
break;
}
}
}
/********************************************************************
* For a given pin of a pb_graph_node
* - Identify the interconnect implementation
* - Find the number of inputs for the interconnect implementation
* - Update the mux_library is the implementation is multiplexers
********************************************************************/
static
void build_pb_graph_pin_interconnect_mux_library(t_pb_graph_pin* pb_graph_pin,
t_mode* interconnect_mode,
const CircuitLibrary& circuit_lib,
const VprDeviceAnnotation& vpr_device_annotation,
MuxLibrary& mux_lib) {
/* Find the interconnect in the physical mode that drives this pin */
t_interconnect* physical_interc = pb_graph_pin_interc(pb_graph_pin, interconnect_mode);
/* Bypass if the interc does not indicate multiplexers */
if (MUX_INTERC != vpr_device_annotation.interconnect_physical_type(physical_interc)) {
return;
}
size_t mux_size = pb_graph_pin_inputs(pb_graph_pin, physical_interc).size();
VTR_ASSERT(true == valid_mux_implementation_num_inputs(mux_size));
const CircuitModelId& interc_circuit_model = vpr_device_annotation.interconnect_circuit_model(physical_interc);
VTR_ASSERT(CircuitModelId::INVALID() != interc_circuit_model);
/* Add the mux model to library */
mux_lib.add_mux(circuit_lib, interc_circuit_model, mux_size);
}
/********************************************************************
* Update MuxLibrary with the unique multiplexer structures
* found in programmable logic blocks
********************************************************************/
static
void rec_build_vpr_physical_pb_graph_node_mux_library(t_pb_graph_node* pb_graph_node,
const CircuitLibrary& circuit_lib,
const VprDeviceAnnotation& vpr_device_annotation,
MuxLibrary& mux_lib) {
/* Find the number of inputs for each interconnect of this pb_graph_node
* This is only applicable to each interconnect which will be implemented with multiplexers
*/
t_mode* parent_physical_mode = nullptr;
if (false == pb_graph_node->is_root()) {
parent_physical_mode = vpr_device_annotation.physical_mode(pb_graph_node->parent_pb_graph_node->pb_type);
}
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
build_pb_graph_pin_interconnect_mux_library(&(pb_graph_node->input_pins[iport][ipin]),
parent_physical_mode,
circuit_lib,
vpr_device_annotation,
mux_lib);
}
}
for (int iport = 0; iport < pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_clock_pins[iport]; ++ipin) {
build_pb_graph_pin_interconnect_mux_library(&(pb_graph_node->clock_pins[iport][ipin]),
parent_physical_mode,
circuit_lib,
vpr_device_annotation,
mux_lib);
}
}
/* Return if this is a primitive node */
if (true == is_primitive_pb_type(pb_graph_node->pb_type)) {
return;
}
/* Get the physical mode, primitive node does not have physical mode */
t_mode* physical_mode = vpr_device_annotation.physical_mode(pb_graph_node->pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Note that the output port interconnect should be considered for non-primitive nodes */
for (int iport = 0; iport < pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ++ipin) {
build_pb_graph_pin_interconnect_mux_library(&(pb_graph_node->output_pins[iport][ipin]),
physical_mode,
circuit_lib,
vpr_device_annotation,
mux_lib);
}
}
/* Visit all the child nodes in the physical mode */
for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) {
for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) {
rec_build_vpr_physical_pb_graph_node_mux_library(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]),
circuit_lib, vpr_device_annotation,
mux_lib);
}
}
}
/********************************************************************
* 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 (CIRCUIT_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, CIRCUIT_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(const DeviceContext& vpr_device_ctx,
const OpenfpgaContext& openfpga_ctx) {
vtr::ScopedStartFinishTimer timer("Build a library of physical multiplexers");
/* 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(vpr_device_ctx, openfpga_ctx.arch().circuit_lib,
openfpga_ctx.vpr_device_annotation(),
mux_lib);
/* Step 2: Count the sizes of multiplexers in complex logic blocks */
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
/* By pass nullptr for pb_graph head */
if (nullptr == lb_type.pb_graph_head) {
continue;
}
rec_build_vpr_physical_pb_graph_node_mux_library(lb_type.pb_graph_head,
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.vpr_device_annotation(),
mux_lib);
}
/* Step 3: count the size of multiplexer that will be used in LUTs*/
build_lut_mux_library(mux_lib, openfpga_ctx.arch().circuit_lib);
VTR_LOG("Built a multiplexer library of %lu physical multiplexers.\n",
mux_lib.muxes().size());
VTR_LOG("Maximum multiplexer size is %lu.\n",
mux_lib.max_mux_size());
return mux_lib;
}
} /* End namespace openfpga*/

View File

@ -0,0 +1,23 @@
#ifndef MUX_LIBRARY_BUILDER_H
#define MUX_LIBRARY_BUILDER_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
#include "mux_library.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
MuxLibrary build_device_mux_library(const DeviceContext& vpr_device_ctx,
const OpenfpgaContext& openfpga_ctx);
} /* end namespace openfpga */
#endif

View File

@ -2,6 +2,8 @@
* This file includes most utilized functions for the rr_graph
* data structure in the OpenFPGA context
*******************************************************************/
#include <algorithm>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
@ -63,4 +65,20 @@ vtr::Point<size_t> get_track_rr_node_end_coordinate(const RRGraph& rr_graph,
return end_coordinator;
}
/************************************************************************
* Find the driver switches for a node in the rr_graph
* This function only return unique driver switches
***********************************************************************/
std::vector<RRSwitchId> get_rr_graph_driver_switches(const RRGraph& rr_graph,
const RRNodeId& node) {
std::vector<RRSwitchId> driver_switches;
for (const RREdgeId& edge : rr_graph.node_in_edges(node)) {
if (driver_switches.end() == std::find(driver_switches.begin(), driver_switches.end(), rr_graph.edge_switch(edge))) {
driver_switches.push_back(rr_graph.edge_switch(edge));
}
}
return driver_switches;
}
} /* end namespace openfpga */

View File

@ -23,6 +23,9 @@ vtr::Point<size_t> get_track_rr_node_start_coordinate(const RRGraph& rr_graph,
vtr::Point<size_t> get_track_rr_node_end_coordinate(const RRGraph& rr_graph,
const RRNodeId& track_rr_node);
std::vector<RRSwitchId> get_rr_graph_driver_switches(const RRGraph& rr_graph,
const RRNodeId& node);
} /* end namespace openfpga */
#endif

View File

@ -38,4 +38,29 @@ std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
return inputs;
}
/********************************************************************
* This function aims to find out the interconnect that drives
* a given pb_graph pin when operating in a select mode
*******************************************************************/
t_interconnect* pb_graph_pin_interc(t_pb_graph_pin* pb_graph_pin,
t_mode* selected_mode) {
t_interconnect* interc = nullptr;
/* Search the input edges only, stats on the size of MUX we may need (fan-in) */
for (int iedge = 0; iedge < pb_graph_pin->num_input_edges; ++iedge) {
/* We care the only edges in the selected mode */
if (selected_mode != pb_graph_pin->input_edges[iedge]->interconnect->parent_mode) {
continue;
}
/* There should be one unique interconnect to be found! */
if (nullptr != interc) {
VTR_ASSERT(interc == pb_graph_pin->input_edges[iedge]->interconnect);
} else {
interc = pb_graph_pin->input_edges[iedge]->interconnect;
}
}
return interc;
}
} /* end namespace openfpga */

View File

@ -18,6 +18,9 @@ namespace openfpga {
std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
t_interconnect* selected_interconnect);
t_interconnect* pb_graph_pin_interc(t_pb_graph_pin* pb_graph_pin,
t_mode* selected_mode);
} /* end namespace openfpga */
#endif