add mux library builder
This commit is contained in:
parent
ce63b1cc62
commit
c78d3e9af1
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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*/
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue