Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-02-14 22:22:04 -07:00
commit ee8f5542e9
31 changed files with 2391 additions and 66 deletions

View File

@ -266,7 +266,7 @@
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<direct_connection>
<direct name="adder" circuit_model_name="direct_interc"/>
<direct name="adder" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->

View File

@ -0,0 +1,112 @@
#include "vtr_assert.h"
#include "arch_direct.h"
/************************************************************************
* Member functions for class ArchDirect
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
ArchDirect::ArchDirect() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
ArchDirect::arch_direct_range ArchDirect::directs() const {
return vtr::make_range(direct_ids_.begin(), direct_ids_.end());
}
/************************************************************************
* Public Accessors
***********************************************************************/
ArchDirectId ArchDirect::direct(const std::string& name) const {
if (0 < direct_name2ids_.count(name)) {
return direct_name2ids_.at(name);
}
return ArchDirectId::INVALID();
}
std::string ArchDirect::name(const ArchDirectId& direct_id) const {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return names_[direct_id];
}
CircuitModelId ArchDirect::circuit_model(const ArchDirectId& direct_id) const {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return circuit_models_[direct_id];
}
e_direct_type ArchDirect::type(const ArchDirectId& direct_id) const {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return types_[direct_id];
}
e_direct_direction ArchDirect::x_dir(const ArchDirectId& direct_id) const {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return directions_[direct_id].x();
}
e_direct_direction ArchDirect::y_dir(const ArchDirectId& direct_id) const {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return directions_[direct_id].y();
}
/************************************************************************
* Public Mutators
***********************************************************************/
ArchDirectId ArchDirect::add_direct(const std::string& name) {
if (0 < direct_name2ids_.count(name)) {
return ArchDirectId::INVALID();
}
/* This is a legal name. we can create a new id */
ArchDirectId direct = ArchDirectId(direct_ids_.size());
direct_ids_.push_back(direct);
names_.push_back(name);
circuit_models_.push_back(CircuitModelId::INVALID());
types_.emplace_back(NUM_DIRECT_TYPES);
directions_.emplace_back(vtr::Point<e_direct_direction>(NUM_DIRECT_DIRECTIONS, NUM_DIRECT_DIRECTIONS));
/* Register in the name-to-id map */
direct_name2ids_[name] = direct;
return direct;
}
void ArchDirect::set_circuit_model(const ArchDirectId& direct_id, const CircuitModelId& circuit_model) {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
circuit_models_[direct_id] = circuit_model;
}
void ArchDirect::set_type(const ArchDirectId& direct_id, const e_direct_type& type) {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
types_[direct_id] = type;
}
void ArchDirect::set_direction(const ArchDirectId& direct_id,
const e_direct_direction& x_dir,
const e_direct_direction& y_dir) {
/* validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
directions_[direct_id].set_x(x_dir);
directions_[direct_id].set_y(y_dir);
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool ArchDirect::valid_direct_id(const ArchDirectId& direct_id) const {
return ( size_t(direct_id) < direct_ids_.size() ) && ( direct_id == direct_ids_[direct_id] );
}

View File

@ -0,0 +1,103 @@
#ifndef ARCH_DIRECT_H
#define ARCH_DIRECT_H
#include <map>
#include "vtr_vector.h"
#include "vtr_geometry.h"
#include "circuit_library_fwd.h"
#include "arch_direct_fwd.h"
/********************************************************************
* Define the types of point to point connection between CLBs
* These types are supplementary to the original VPR direct connections
* Here we extend to the cross-row and cross-column connections
********************************************************************/
enum e_direct_type {
INNER_COLUMN,
INNER_ROW,
INTER_COLUMN,
INTER_ROW,
NUM_DIRECT_TYPES
};
constexpr std::array<const char*, NUM_DIRECT_TYPES> DIRECT_TYPE_STRING = {{"inner_column", "inner_row", "inter_column", "inter_row"}};
enum e_direct_direction {
POSITIVE_DIR,
NEGATIVE_DIR,
NUM_DIRECT_DIRECTIONS
};
constexpr std::array<const char*, NUM_DIRECT_DIRECTIONS> DIRECT_DIRECTION_STRING = {{"positive", "negative"}};
/********************************************************************
* A data base to describe the direct connection in OpenFPGA architecture
* For each direct connection, it will include
* - name: the identifier to annotate the original direct connection in VPR architecture
* - circuit model: the circuit model to used to implement this connection
* - type: if this connection should be cross-column or cross-row
* - x-direction: how this connection is going to be applied to adjacent columns
* a positive x-direction means that column A will be connected
* to the column B on the right side of column A
* - y-direction: how this connection is going to be applied to adjacent rows
* a positive y-direction means that row A will be connected
* to the row B on the bottom side of row A
*
* Note that: this is the data structure to be used when parsing the XML
* this is NOT the data structure to be use in core engine
********************************************************************/
class ArchDirect {
public: /* Types */
typedef vtr::vector<ArchDirectId, ArchDirectId>::const_iterator arch_direct_iterator;
/* Create range */
typedef vtr::Range<arch_direct_iterator> arch_direct_range;
public: /* Constructors */
ArchDirect();
public: /* Accessors: aggregates */
arch_direct_range directs() const;
public: /* Public Accessors: Basic data query on directs */
ArchDirectId direct(const std::string& name) const;
std::string name(const ArchDirectId& direct_id) const;
CircuitModelId circuit_model(const ArchDirectId& direct_id) const;
e_direct_type type(const ArchDirectId& direct_id) const;
e_direct_direction x_dir(const ArchDirectId& direct_id) const;
e_direct_direction y_dir(const ArchDirectId& direct_id) const;
public: /* Public Mutators */
ArchDirectId add_direct(const std::string& name);
void set_circuit_model(const ArchDirectId& direct_id, const CircuitModelId& circuit_model);
void set_type(const ArchDirectId& direct_id, const e_direct_type& type);
void set_direction(const ArchDirectId& direct_id,
const e_direct_direction& x_dir,
const e_direct_direction& y_dir);
public: /* Public invalidators/validators */
bool valid_direct_id(const ArchDirectId& direct_id) const;
private: /* Internal data */
vtr::vector<ArchDirectId, ArchDirectId> direct_ids_;
/* Unique name: the identifier to annotate the original direct connection in VPR architecture */
vtr::vector<ArchDirectId, std::string> names_;
/* circuit model: the circuit model to used to implement this connection */
vtr::vector<ArchDirectId, CircuitModelId> circuit_models_;
/* type: if this connection should be cross-column or cross-row */
vtr::vector<ArchDirectId, e_direct_type> types_;
/*
* x-direction: how this connection is going to be applied to adjacent columns
* a positive x-direction means that column A will be connected
* to the column B on the right side of column A
* y-direction: how this connection is going to be applied to adjacent rows
* a positive y-direction means that row A will be connected
* to the row B on the bottom side of row A
*/
vtr::vector<ArchDirectId, vtr::Point<e_direct_direction>> directions_;
/* Fast look-up */
std::map<std::string, ArchDirectId> direct_name2ids_;
};
#endif

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for ArchDirect class, including critical data declaration
* Please include this file only for using any TechnologyLibrary data structure
* Refer to arch_direct.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for ArchDirect to avoid illegal type casting
***********************************************************************/
#ifndef ARCH_DIRECT_FWD_H
#define ARCH_DIRECT_FWD_H
#include "vtr_strong_id.h"
struct arch_direct_id_tag;
typedef vtr::StrongId<arch_direct_id_tag> ArchDirectId;
/* Short declaration of class */
class ArchDirect;
#endif

View File

@ -1,22 +0,0 @@
#ifndef DIRECT_TYPES_H
#define DIRECT_TYPES_H
/********************************************************************
* Define the types of point to point connection between CLBs
* These types are supplementary to the original VPR direct connections
* Here we extend to the cross-row and cross-column connections
********************************************************************/
enum e_point2point_interconnection_type {
NO_P2P,
P2P_DIRECT_COLUMN,
P2P_DIRECT_ROW,
NUM_POINT2POINT_INTERCONNECT_TYPE
};
enum e_point2point_interconnection_dir {
POSITIVE_DIR,
NEGATIVE_DIR,
NUM_POINT2POINT_INTERCONNECT_DIR
};
#endif

View File

@ -8,6 +8,7 @@
#include "technology_library.h"
#include "simulation_setting.h"
#include "config_protocol.h"
#include "arch_direct.h"
#include "pb_type_annotation.h"
/* namespace openfpga begins */
@ -48,7 +49,7 @@ struct Arch {
/* Mapping from the names of direct connection
* to circuit models in circuit library
*/
std::map<std::string, CircuitModelId> direct2circuit;
ArchDirect arch_direct;
/* Pb type annotations
* Bind from operating to physical

View File

@ -94,8 +94,8 @@ openfpga::Arch read_xml_openfpga_arch(const char* arch_file_name) {
openfpga_arch.circuit_lib);
/* Parse the direct circuit definition */
openfpga_arch.direct2circuit = read_xml_direct_circuit(xml_openfpga_arch, loc_data,
openfpga_arch.circuit_lib);
openfpga_arch.arch_direct = read_xml_direct_circuit(xml_openfpga_arch, loc_data,
openfpga_arch.circuit_lib);
/* Parse the pb_type annotation */
openfpga_arch.pb_type_annotations = read_xml_pb_type_annotations(xml_openfpga_arch, loc_data);

View File

@ -185,20 +185,53 @@ std::map<std::string, CircuitModelId> read_xml_routing_segment_circuit(pugi::xml
return seg2circuit;
}
/********************************************************************
* Convert string to the enumerate of direct type
*******************************************************************/
static
e_direct_type string_to_direct_type(const std::string& type_string) {
if (std::string("column") == type_string) {
return INTER_COLUMN;
}
if (std::string("row") == type_string) {
return INTER_ROW;
}
return NUM_DIRECT_TYPES;
}
/********************************************************************
* Convert string to the enumerate of direct direction type
*******************************************************************/
static
e_direct_direction string_to_direct_direction(const std::string& type_string) {
if (std::string("positive") == type_string) {
return POSITIVE_DIR;
}
if (std::string("negative") == type_string) {
return NEGATIVE_DIR;
}
return NUM_DIRECT_DIRECTIONS;
}
/********************************************************************
* Parse XML codes about <direct_connection> to an object of name-to-circuit mapping
* Note: this function should be called AFTER the parsing of circuit library!!!
*******************************************************************/
std::map<std::string, CircuitModelId> read_xml_direct_circuit(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data,
const CircuitLibrary& circuit_lib) {
std::map<std::string, CircuitModelId> direct2circuit;
ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data,
const CircuitLibrary& circuit_lib) {
ArchDirect arch_direct;
/* Parse direct list, this is optional. May not be used */
pugi::xml_node xml_directs= get_single_child(Node, "direct_connection", loc_data, pugiutil::ReqOpt::OPTIONAL);
/* Not found, we can return */
if (!xml_directs) {
return direct2circuit;
return arch_direct;
}
/* Iterate over the children under this node,
@ -219,17 +252,46 @@ std::map<std::string, CircuitModelId> read_xml_direct_circuit(pugi::xml_node& No
circuit_lib, direct_model_name,
CIRCUIT_MODEL_WIRE);
/* Ensure that there is no duplicated seg names defined here */
std::map<std::string, CircuitModelId>::const_iterator it = direct2circuit.find(direct_name);
if (it != direct2circuit.end()) {
/* Add to the Arch direct database */
ArchDirectId direct = arch_direct.add_direct(direct_name);
if (false == arch_direct.valid_direct_id(direct)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_direct),
"Direct name '%s' has been defined more than once!\n",
direct_name.c_str());
}
arch_direct.set_circuit_model(direct, direct_model);
/* Pass all the check, we can add it to the map */
direct2circuit[direct_name] = direct_model;
/* Add more information*/
std::string direct_type_name = get_attribute(xml_direct, "type", loc_data).as_string();
e_direct_type direct_type = string_to_direct_type(direct_type_name);
if (NUM_DIRECT_TYPES == direct_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_direct),
"Direct type '%s' is not support! Acceptable values are [column|row]\n",
direct_type_name.c_str());
}
arch_direct.set_type(direct, direct_type);
std::string x_dir_name = get_attribute(xml_direct, "x_dir", loc_data).as_string();
std::string y_dir_name = get_attribute(xml_direct, "y_dir", loc_data).as_string();
e_direct_direction x_dir = string_to_direct_direction(x_dir_name);
e_direct_direction y_dir = string_to_direct_direction(y_dir_name);
if (NUM_DIRECT_DIRECTIONS == x_dir) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_direct),
"Direct x-direction '%s' is not support! Acceptable values are [positive|column]\n",
x_dir_name.c_str());
}
if (NUM_DIRECT_DIRECTIONS == y_dir) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_direct),
"Direct y-direction '%s' is not support! Acceptable values are [positive|column]\n",
y_dir_name.c_str());
}
arch_direct.set_direction(direct, x_dir, y_dir);
}
return direct2circuit;
return arch_direct;
}

View File

@ -10,6 +10,7 @@
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "circuit_library.h"
#include "arch_direct.h"
/********************************************************************
* Function declaration
@ -26,8 +27,9 @@ std::map<std::string, CircuitModelId> read_xml_routing_segment_circuit(pugi::xml
const pugiutil::loc_data& loc_data,
const CircuitLibrary& circuit_lib);
std::map<std::string, CircuitModelId> read_xml_direct_circuit(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data,
const CircuitLibrary& circuit_lib);
ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data,
const CircuitLibrary& circuit_lib);
#endif

View File

@ -56,8 +56,7 @@ void write_xml_openfpga_arch(const char* fname,
write_xml_routing_segment_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.routing_seg2circuit);
/* Write the direct connection circuit definition */
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.direct2circuit);
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.arch_direct);
/* Write the pb_type annotations */
openfpga::write_xml_pb_type_annotations(fp, fname, openfpga_arch. pb_type_annotations);

View File

@ -38,6 +38,29 @@ void write_xml_routing_component_circuit(std::fstream& fp,
}
}
/********************************************************************
* Write switch circuit model definition in XML format
*******************************************************************/
static
void write_xml_direct_component_circuit(std::fstream& fp,
const char* fname,
const std::string& direct_tag_name,
const CircuitLibrary& circuit_lib,
const ArchDirect& arch_direct,
const ArchDirectId& direct_id) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Iterate over the mapping */
fp << "\t\t" << "<" << direct_tag_name;
write_xml_attribute(fp, "name", arch_direct.name(direct_id).c_str());
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(arch_direct.circuit_model(direct_id)).c_str());
write_xml_attribute(fp, "type", DIRECT_TYPE_STRING[arch_direct.type(direct_id)]);
write_xml_attribute(fp, "x_dir", DIRECT_DIRECTION_STRING[arch_direct.x_dir(direct_id)]);
write_xml_attribute(fp, "y_dir", DIRECT_DIRECTION_STRING[arch_direct.y_dir(direct_id)]);
fp << "/>" << "\n";
}
/********************************************************************
* Write Connection block circuit models in XML format
*******************************************************************/
@ -104,9 +127,9 @@ void write_xml_routing_segment_circuit(std::fstream& fp,
void write_xml_direct_circuit(std::fstream& fp,
const char* fname,
const CircuitLibrary& circuit_lib,
const std::map<std::string, CircuitModelId>& direct2circuit) {
const ArchDirect& arch_direct) {
/* If the direct2circuit is empty, we do not output XML */
if (direct2circuit.empty()) {
if (0 == arch_direct.directs().size()) {
return;
}
@ -117,7 +140,9 @@ void write_xml_direct_circuit(std::fstream& fp,
fp << "\t" << "<direct_connection>" << "\n";
/* Write each direct connection circuit definition */
write_xml_routing_component_circuit(fp, fname, std::string("direct"), circuit_lib, direct2circuit);
for (const ArchDirectId& direct_id : arch_direct.directs()) {
write_xml_direct_component_circuit(fp, fname, std::string("direct"), circuit_lib, arch_direct, direct_id);
}
/* Finish writing the root node */
fp << "\t" << "</direct_connection>" << "\n";

View File

@ -9,6 +9,7 @@
#include <string>
#include "circuit_library.h"
#include "arch_direct.h"
/********************************************************************
* Function declaration
@ -31,6 +32,6 @@ void write_xml_routing_segment_circuit(std::fstream& fp,
void write_xml_direct_circuit(std::fstream& fp,
const char* fname,
const CircuitLibrary& circuit_lib,
const std::map<std::string, CircuitModelId>& direct2circuit);
const ArchDirect& arch_direct);
#endif

View File

@ -524,13 +524,16 @@ void annotate_direct_circuit_models(const DeviceContext& vpr_device_ctx,
for (int idirect = 0; idirect < vpr_device_ctx.arch->num_directs; ++idirect) {
std::string direct_name = vpr_device_ctx.arch->Directs[idirect].name;
CircuitModelId circuit_model = CircuitModelId::INVALID();
/* The name-to-circuit mapping is stored in either cb_switch-to-circuit or sb_switch-to-circuit,
* Try to find one and update the device annotation
*/
if (0 < openfpga_arch.direct2circuit.count(direct_name)) {
circuit_model = openfpga_arch.direct2circuit.at(direct_name);
ArchDirectId direct_id = openfpga_arch.arch_direct.direct(direct_name);
/* Cannot find a direct, no annotation needed for this direct */
if (ArchDirectId::INVALID() == direct_id) {
continue;
}
CircuitModelId circuit_model = openfpga_arch.arch_direct.circuit_model(direct_id);
/* Cannot find a circuit model, error out! */
if (CircuitModelId::INVALID() == circuit_model) {
VTR_LOG_ERROR("Fail to find a circuit model for a direct connection '%s'!\nPlease check your OpenFPGA architecture XML!\n",
@ -547,7 +550,7 @@ void annotate_direct_circuit_models(const DeviceContext& vpr_device_ctx,
}
/* Now update the device annotation */
vpr_device_annotation.add_direct_circuit_model(idirect, circuit_model);
vpr_device_annotation.add_direct_annotation(idirect, direct_id);
VTR_LOGV(verbose_output,
"Binded a direct connection '%s' to circuit model '%s'\n",
direct_name.c_str(),

View File

@ -233,13 +233,12 @@ CircuitModelId VprDeviceAnnotation::rr_segment_circuit_model(const RRSegmentId&
return rr_segment_circuit_models_.at(rr_segment);
}
CircuitModelId VprDeviceAnnotation::direct_circuit_model(const size_t& direct) const {
ArchDirectId VprDeviceAnnotation::direct_annotation(const size_t& direct) const {
/* Ensure that the rr_switch is in the list */
std::map<size_t, CircuitModelId>::const_iterator it = direct_circuit_models_.find(direct);
if (it == direct_circuit_models_.end()) {
return CircuitModelId::INVALID();
if (0 == direct_annotations_.count(direct)) {
return ArchDirectId::INVALID();
}
return direct_circuit_models_.at(direct);
return direct_annotations_.at(direct);
}
/************************************************************************
@ -461,15 +460,14 @@ void VprDeviceAnnotation::add_rr_segment_circuit_model(const RRSegmentId& rr_seg
rr_segment_circuit_models_[rr_segment] = circuit_model;
}
void VprDeviceAnnotation::add_direct_circuit_model(const size_t& direct, const CircuitModelId& circuit_model) {
void VprDeviceAnnotation::add_direct_annotation(const size_t& direct, const ArchDirectId& arch_direct_id) {
/* Warn any override attempt */
std::map<size_t, CircuitModelId>::const_iterator it = direct_circuit_models_.find(direct);
if (it != direct_circuit_models_.end()) {
VTR_LOG_WARN("Override the annotation between direct '%ld' and its circuit_model '%ld'!\n",
size_t(direct), size_t(circuit_model));
if (0 < direct_annotations_.count(direct)) {
VTR_LOG_WARN("Override the annotation between direct '%ld' and its annotation '%ld'!\n",
size_t(direct), size_t(arch_direct_id));
}
direct_circuit_models_[direct] = circuit_model;
direct_annotations_[direct] = arch_direct_id;
}
} /* End namespace openfpga*/

View File

@ -18,6 +18,7 @@
/* Header from openfpgautil library */
#include "openfpga_port.h"
#include "circuit_library.h"
#include "arch_direct.h"
/* Begin namespace openfpga */
namespace openfpga {
@ -71,7 +72,7 @@ class VprDeviceAnnotation {
t_pb_graph_pin* physical_pb_graph_pin(t_pb_graph_pin* pb_graph_pin) const;
CircuitModelId rr_switch_circuit_model(const RRSwitchId& rr_switch) const;
CircuitModelId rr_segment_circuit_model(const RRSegmentId& rr_segment) const;
CircuitModelId direct_circuit_model(const size_t& direct) const;
ArchDirectId direct_annotation(const size_t& direct) const;
public: /* Public mutators */
void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode);
void add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type);
@ -91,7 +92,7 @@ class VprDeviceAnnotation {
void add_physical_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin, t_pb_graph_pin* physical_pb_graph_pin);
void add_rr_switch_circuit_model(const RRSwitchId& rr_switch, const CircuitModelId& circuit_model);
void add_rr_segment_circuit_model(const RRSegmentId& rr_segment, const CircuitModelId& circuit_model);
void add_direct_circuit_model(const size_t& direct, const CircuitModelId& circuit_model);
void add_direct_annotation(const size_t& direct, const ArchDirectId& arch_direct_id);
private: /* Internal data */
/* Pair a regular pb_type to its physical pb_type */
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
@ -173,8 +174,8 @@ class VprDeviceAnnotation {
/* Pair a Routing Segment (rr_segment) to a circuit model */
std::map<RRSegmentId, CircuitModelId> rr_segment_circuit_models_;
/* Pair a direct connection (direct) to a circuit model */
std::map<size_t, CircuitModelId> direct_circuit_models_;
/* Pair a direct connection (direct) to a annotation which contains circuit model id */
std::map<size_t, ArchDirectId> direct_annotations_;
};
} /* End namespace openfpga*/

View File

@ -8,6 +8,7 @@
#include "vpr_clustering_annotation.h"
#include "vpr_routing_annotation.h"
#include "mux_library.h"
#include "tile_direct.h"
#include "module_manager.h"
#include "device_rr_gsb.h"
@ -47,6 +48,7 @@ class OpenfpgaContext : public Context {
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_; }
const openfpga::TileDirect& tile_direct() const { return tile_direct_; }
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
public: /* Public mutators */
openfpga::Arch& mutable_arch() { return arch_; }
@ -56,6 +58,7 @@ class OpenfpgaContext : public Context {
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_; }
openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; }
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
private: /* Internal data */
/* Data structure to store information from read_openfpga_arch library */
@ -67,7 +70,7 @@ class OpenfpgaContext : public Context {
/* Naming fix to netlist */
openfpga::VprNetlistAnnotation vpr_netlist_annotation_;
/* TODO: Pin net fix to cluster results */
/* Pin net fix to cluster results */
openfpga::VprClusteringAnnotation vpr_clustering_annotation_;
/* Routing results annotation */
@ -79,6 +82,9 @@ class OpenfpgaContext : public Context {
/* Library of physical implmentation of routing multiplexers */
openfpga::MuxLibrary mux_lib_;
/* Inner/inter-column/row tile direct connections */
openfpga::TileDirect tile_direct_;
/* Fabric module graph */
openfpga::ModuleManager module_graph_;
};

View File

@ -14,6 +14,7 @@
#include "annotate_routing.h"
#include "annotate_rr_graph.h"
#include "mux_library_builder.h"
#include "build_tile_direct.h"
#include "openfpga_link_arch.h"
/* Include global variables of VPR */
@ -106,6 +107,12 @@ void link_arch(OpenfpgaContext& openfpga_context,
/* Build multiplexer library */
openfpga_context.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(),
const_cast<const OpenfpgaContext&>(openfpga_context));
/* Build tile direct annotation */
openfpga_context.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(),
openfpga_context.arch().arch_direct,
openfpga_context.arch().circuit_lib);
}
} /* end namespace openfpga */

View File

@ -0,0 +1,676 @@
/********************************************************************
* This file include most utilized functions for building connections
* inside the module graph for FPGA fabric
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
/* Headers from openfpgautil library */
#include "openfpga_side_manager.h"
#include "openfpga_reserved_words.h"
#include "openfpga_naming.h"
#include "pb_type_utils.h"
#include "rr_gsb_utils.h"
#include "build_top_module_utils.h"
#include "build_top_module_connection.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Add module nets to connect a GSB to adjacent grid ports/pins
* as well as connection blocks
* This function will create nets for the following types of connections
* between grid output pins of Switch block and adjacent grids
* In this case, the net source is the grid pin, while the net sink
* is the switch block pin
*
* +------------+ +------------+
* | | | |
* | Grid | | Grid |
* | [x][y+1] | | [x+1][y+1] |
* | |----+ +----| |
* +------------+ | | +------------+
* | v v |
* | +------------+ |
* +------>| |<-----+
* | Switch |
* | Block |
* +------>| [x][y] |<-----+
* | +------------+ |
* | ^ ^ |
* | | | |
* +------------+ | | +------------+
* | |----+ +-----| |
* | Grid | | Grid |
* | [x][y] | | [x+1][y] |
* | | | |
* +------------+ +------------+
*
*******************************************************************/
static
void add_top_module_nets_connect_grids_and_sb(ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const RRGSB& rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const bool& compact_routing_hierarchy) {
/* We could have two different coordinators, one is the instance, the other is the module */
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
vtr::Point<size_t> module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(gsb_coord);
module_gsb_coordinate.set_x(unique_mirror.get_x());
module_gsb_coordinate.set_y(unique_mirror.get_y());
}
/* This is the source cb that is added to the top module */
const RRGSB& module_sb = device_rr_gsb.get_gsb(module_gsb_coordinate);
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
/* Collect sink-related information */
std::string sink_sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
size_t sink_sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
/* Connect grid output pins (OPIN) to switch block grid pins */
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
SideManager side_manager(side);
for (size_t inode = 0; inode < module_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
/* Collect source-related information */
/* Generate the grid module name by considering if it locates on the border */
vtr::Point<size_t> grid_coordinate(rr_graph.node_xlow(rr_gsb.get_opin_node(side_manager.get_side(), inode)),
rr_graph.node_ylow(rr_gsb.get_opin_node(side_manager.get_side(), inode)));
std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), grids, grid_coordinate);
ModuleId src_grid_module = module_manager.find_module(src_grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
size_t src_grid_pin_index = rr_graph.node_pin_num(rr_gsb.get_opin_node(side_manager.get_side(), inode));
size_t src_grid_pin_width = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_width_offset[src_grid_pin_index];
size_t src_grid_pin_height = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_height_offset[src_grid_pin_index];
std::string src_grid_port_name = generate_grid_port_name(grid_coordinate, src_grid_pin_width, src_grid_pin_height,
rr_graph.node_side(rr_gsb.get_opin_node(side_manager.get_side(), inode)),
src_grid_pin_index, false);
ModulePortId src_grid_port_id = module_manager.find_module_port(src_grid_module, src_grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_grid_port_id));
BasicPort src_grid_port = module_manager.module_port(src_grid_module, src_grid_port_id);
/* Collect sink-related information */
vtr::Point<size_t> sink_sb_port_coord(rr_graph.node_xlow(module_sb.get_opin_node(side_manager.get_side(), inode)),
rr_graph.node_ylow(module_sb.get_opin_node(side_manager.get_side(), inode)));
std::string sink_sb_port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
rr_graph.node_side(module_sb.get_opin_node(side_manager.get_side(), inode)),
src_grid_pin_index);
ModulePortId sink_sb_port_id = module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_sb_module, sink_sb_port_id));
BasicPort sink_sb_port = module_manager.module_port(sink_sb_module, sink_sb_port_id);
/* Source and sink port should match in size */
VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(top_module);
/* Configure the net source */
module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]);
/* Configure the net sink */
module_manager.add_module_net_sink(top_module, net, sink_sb_module, sink_sb_instance, sink_sb_port_id, sink_sb_port.pins()[pin_id]);
}
}
}
}
/********************************************************************
* Add module nets to connect a GSB to adjacent grid ports/pins
* as well as connection blocks
* This function will create nets for the following types of connections
* between grid output pins of Switch block and adjacent grids
* In this case, the net source is the grid pin, while the net sink
* is the switch block pin
*
* In particular, this function considers the duplicated output pins of grids
* when creating the connecting nets.
* The follow figure shows the different pin postfix to be considered when
* connecting the grid pins to SB inputs
*
* +------------+ +------------+
* | | | |
* | Grid | | Grid |
* | [x][y+1] |lower lower| [x+1][y+1] |
* | |----+ +----| |
* +------------+ | | +------------+
* |lower v v |upper
* | +------------+ |
* +------>| |<-----+
* | Switch |
* | Block |
* +------>| [x][y] |<-----+
* | +------------+ |
* | ^ ^ |
* |lower | | |upper
* +------------+ | | +------------+
* | |----+ +-----| |
* | Grid |upper upper | Grid |
* | [x][y] | | [x+1][y] |
* | | | |
* +------------+ +------------+
*
*******************************************************************/
static
void add_top_module_nets_connect_grids_and_sb_with_duplicated_pins(ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const RRGSB& rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const bool& compact_routing_hierarchy) {
/* We could have two different coordinators, one is the instance, the other is the module */
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
vtr::Point<size_t> module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(gsb_coord);
module_gsb_coordinate.set_x(unique_mirror.get_x());
module_gsb_coordinate.set_y(unique_mirror.get_y());
}
/* This is the source cb that is added to the top module */
const RRGSB& module_sb = device_rr_gsb.get_gsb(module_gsb_coordinate);
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
/* Collect sink-related information */
std::string sink_sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
size_t sink_sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
/* Create a truth table for the postfix to be used regarding to the different side of switch blocks */
std::map<e_side, bool> sb_side2postfix_map;
/* Boolean variable "true" indicates the upper postfix in naming functions
* Boolean variable "false" indicates the lower postfix in naming functions
*/
sb_side2postfix_map[TOP] = false;
sb_side2postfix_map[RIGHT] = true;
sb_side2postfix_map[BOTTOM] = true;
sb_side2postfix_map[LEFT] = false;
/* Connect grid output pins (OPIN) to switch block grid pins */
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
SideManager side_manager(side);
for (size_t inode = 0; inode < module_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
/* Collect source-related information */
/* Generate the grid module name by considering if it locates on the border */
vtr::Point<size_t> grid_coordinate(rr_graph.node_xlow(rr_gsb.get_opin_node(side_manager.get_side(), inode)),
rr_graph.node_ylow(rr_gsb.get_opin_node(side_manager.get_side(), inode)));
std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), grids, grid_coordinate);
ModuleId src_grid_module = module_manager.find_module(src_grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
size_t src_grid_pin_index = rr_graph.node_pin_num(rr_gsb.get_opin_node(side_manager.get_side(), inode));
size_t src_grid_pin_width = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_width_offset[src_grid_pin_index];
size_t src_grid_pin_height = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_height_offset[src_grid_pin_index];
/* Pins for direct connection are NOT duplicated.
* Follow the traditional recipe when adding nets!
* Xifan: I assume that each direct connection pin must have Fc=0.
* For other duplicated pins, we follow the new naming
*/
std::string src_grid_port_name;
if (0. == grids[grid_coordinate.x()][grid_coordinate.y()].type->fc_specs[src_grid_pin_index].fc_value) {
src_grid_port_name = generate_grid_port_name(grid_coordinate, src_grid_pin_width, src_grid_pin_height,
rr_graph.node_side(rr_gsb.get_opin_node(side_manager.get_side(), inode)),
src_grid_pin_index, false);
} else {
src_grid_port_name = generate_grid_duplicated_port_name(src_grid_pin_width, src_grid_pin_height,
rr_graph.node_side(rr_gsb.get_opin_node(side_manager.get_side(), inode)),
src_grid_pin_index, sb_side2postfix_map[side_manager.get_side()]);
}
ModulePortId src_grid_port_id = module_manager.find_module_port(src_grid_module, src_grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_grid_port_id));
BasicPort src_grid_port = module_manager.module_port(src_grid_module, src_grid_port_id);
/* Collect sink-related information */
vtr::Point<size_t> sink_sb_port_coord(rr_graph.node_xlow(module_sb.get_opin_node(side_manager.get_side(), inode)),
rr_graph.node_ylow(module_sb.get_opin_node(side_manager.get_side(), inode)));
std::string sink_sb_port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
rr_graph.node_side(module_sb.get_opin_node(side_manager.get_side(), inode)),
src_grid_pin_index);
ModulePortId sink_sb_port_id = module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_sb_module, sink_sb_port_id));
BasicPort sink_sb_port = module_manager.module_port(sink_sb_module, sink_sb_port_id);
/* Source and sink port should match in size */
VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(top_module);
/* Configure the net source */
module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]);
/* Configure the net sink */
module_manager.add_module_net_sink(top_module, net, sink_sb_module, sink_sb_instance, sink_sb_port_id, sink_sb_port.pins()[pin_id]);
}
}
}
}
/********************************************************************
* This function will create nets for the connections
* between grid input pins and connection blocks
* In this case, the net source is the connection block pin,
* while the net sink is the grid input
*
* +------------+ +------------------+ +------------+
* | | | | | |
* | Grid |<-----| Connection Block |----->| Grid |
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
* | | | [x][y+1] | | |
* +------------+ +------------------+ +------------+
* ^
* |
* +------------+ +------------------+
* | Connection | | |
* | Block | | Switch Block |
* | X-direction| | [x][y] |
* | [x][y] | | |
* +------------+ +------------------+
* |
* v
* +------------+
* | |
* | Grid |
* | [x][y] |
* | |
* +------------+
*
*
* Relationship between source connection block and its unique module
* Take an example of a CBY
*
* grid_pin name should follow unique module of Grid[x][y+1]
* cb_pin name should follow unique module of CBY[x][y+1]
*
* However, instace id should follow the origin Grid and Connection block
*
*
* +------------+ +------------------+
* | | | |
* | Grid |<------------| Connection Block |
* | [x][y+1] | | Y-direction |
* | | | [x][y+1] |
* +------------+ +------------------+
* ^
* || unique mirror
* +------------+ +------------------+
* | | | |
* | Grid |<------------| Connection Block |
* | [i][j+1] | | Y-direction |
* | | | [i][j+1] |
* +------------+ +------------------+
*
*******************************************************************/
static
void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const vtr::Matrix<size_t>& cb_instance_ids,
const bool& compact_routing_hierarchy) {
/* We could have two different coordinators, one is the instance, the other is the module */
vtr::Point<size_t> instance_cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
vtr::Point<size_t> module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
/* Skip those Connection blocks that do not exist */
if (false == rr_gsb.is_cb_exist(cb_type)) {
return;
}
/* Skip if the cb does not contain any configuration bits! */
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
return;
}
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, gsb_coord);
module_gsb_coordinate.set_x(unique_mirror.get_x());
module_gsb_coordinate.set_y(unique_mirror.get_y());
}
/* This is the source cb that is added to the top module */
const RRGSB& module_cb = device_rr_gsb.get_gsb(module_gsb_coordinate);
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
/* Collect source-related information */
std::string src_cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
ModuleId src_cb_module = module_manager.find_module(src_cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(src_cb_module));
/* Instance id should follow the instance cb coordinate */
size_t src_cb_instance = cb_instance_ids[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
/* Iterate over the output pins of the Connection Block */
std::vector<enum e_side> cb_ipin_sides = module_cb.get_cb_ipin_sides(cb_type);
for (size_t iside = 0; iside < cb_ipin_sides.size(); ++iside) {
enum e_side cb_ipin_side = cb_ipin_sides[iside];
for (size_t inode = 0; inode < module_cb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
/* Collect source-related information */
RRNodeId module_ipin_node = module_cb.get_ipin_node(cb_ipin_side, inode);
vtr::Point<size_t> cb_src_port_coord(rr_graph.node_xlow(module_ipin_node),
rr_graph.node_ylow(module_ipin_node));
std::string src_cb_port_name = generate_cb_module_grid_port_name(cb_ipin_side,
rr_graph.node_pin_num(module_ipin_node));
ModulePortId src_cb_port_id = module_manager.find_module_port(src_cb_module, src_cb_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(src_cb_module, src_cb_port_id));
BasicPort src_cb_port = module_manager.module_port(src_cb_module, src_cb_port_id);
/* Collect sink-related information */
/* Note that we use the instance cb pin here!!!
* because it has the correct coordinator for the grid!!!
*/
RRNodeId instance_ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
vtr::Point<size_t> grid_coordinate(rr_graph.node_xlow(instance_ipin_node),
rr_graph.node_ylow(instance_ipin_node));
std::string sink_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), grids, grid_coordinate);
ModuleId sink_grid_module = module_manager.find_module(sink_grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
size_t sink_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
size_t sink_grid_pin_index = rr_graph.node_pin_num(instance_ipin_node);
size_t sink_grid_pin_width = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_width_offset[sink_grid_pin_index];
size_t sink_grid_pin_height = grids[grid_coordinate.x()][grid_coordinate.y()].type->pin_height_offset[sink_grid_pin_index];
std::string sink_grid_port_name = generate_grid_port_name(grid_coordinate, sink_grid_pin_width, sink_grid_pin_height,
rr_graph.node_side(rr_gsb.get_ipin_node(cb_ipin_side, inode)),
sink_grid_pin_index, false);
ModulePortId sink_grid_port_id = module_manager.find_module_port(sink_grid_module, sink_grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_grid_port_id));
BasicPort sink_grid_port = module_manager.module_port(sink_grid_module, sink_grid_port_id);
/* Source and sink port should match in size */
VTR_ASSERT(src_cb_port.get_width() == sink_grid_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < src_cb_port.pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(top_module);
/* Configure the net source */
module_manager.add_module_net_source(top_module, net, src_cb_module, src_cb_instance, src_cb_port_id, src_cb_port.pins()[pin_id]);
/* Configure the net sink */
module_manager.add_module_net_sink(top_module, net, sink_grid_module, sink_grid_instance, sink_grid_port_id, sink_grid_port.pins()[pin_id]);
}
}
}
}
/********************************************************************
* This function will create nets for the connections
* between connection block and switch block pins
* Two cases should be considered:
* a. The switch block pin denotes an input of a routing track
* The net source is an output of a routing track of connection block
* while the net sink is an input of a routing track of switch block
* b. The switch block pin denotes an output of a routing track
* The net source is an output of routing track of switch block
* while the net sink is an input of a routing track of connection block
*
* +------------+ +------------------+ +------------+
* | | | | | |
* | Grid | | Connection Block | | Grid |
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
* | | | [x][y+1] | | |
* +------------+ +------------------+ +------------+
* | ^
* v |
* +------------+ +------------------+ +------------+
* | Connection |----->| |----->| Connection |
* | Block | | Switch Block | | Block |
* | X-direction|<-----| [x][y] |<-----| X-direction|
* | [x][y] | | | | [x+1][y] |
* +------------+ +------------------+ +------------+
* | ^
* v |
* +------------+ +------------------+ +------------+
* | | | | | |
* | Grid | | Connection Block | | Grid |
* | [x][y] | | Y-direction | | [x][y+1] |
* | | | [x][y] | | |
* +------------+ +------------------+ +------------+
*
* Here, to achieve the purpose, we can simply iterate over the
* four sides of switch block and make connections to adjancent
* connection blocks
*
*******************************************************************/
static
void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager,
const ModuleId& top_module,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const RRGSB& rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy) {
/* We could have two different coordinators, one is the instance, the other is the module */
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
vtr::Point<size_t> module_gsb_sb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
/* Skip those Switch blocks that do not exist */
if (false == rr_gsb.is_sb_exist()) {
return;
}
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(gsb_coord);
module_gsb_sb_coordinate.set_x(unique_mirror.get_x());
module_gsb_sb_coordinate.set_y(unique_mirror.get_y());
}
/* This is the source cb that is added to the top module */
const RRGSB& module_sb = device_rr_gsb.get_gsb(module_gsb_sb_coordinate);
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
std::string sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
ModuleId sb_module_id = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module_id));
size_t sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
/* Connect grid output pins (OPIN) to switch block grid pins */
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
SideManager side_manager(side);
/* Iterate over the routing tracks on this side */
/* Early skip: if there is no routing tracks at this side */
if (0 == module_sb.get_chan_width(side_manager.get_side())) {
continue;
}
/* Find the Connection Block module */
/* We find the original connection block and then spot its unique mirror!
* Do NOT use module_sb here!!!
*/
t_rr_type cb_type = find_top_module_cb_type_by_sb_side(side_manager.get_side());
vtr::Point<size_t> instance_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
vtr::Point<size_t> module_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
/* Skip those Connection blocks that do not exist:
* 1. The CB does not exist in the device level! We should skip!
* 2. The CB does exist but we need to make sure if the GSB includes such CBs
* For TOP and LEFT side, check the existence using RRGSB method is_cb_exist()
* FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist()
*/
if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) {
if ( false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
}
if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) {
const RRGSB& adjacent_gsb = device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
if ( false == adjacent_gsb.is_cb_exist(cb_type)) {
continue;
}
}
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
if (true == compact_routing_hierarchy) {
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, module_gsb_cb_coordinate);
module_gsb_cb_coordinate.set_x(unique_mirror.get_x());
module_gsb_cb_coordinate.set_y(unique_mirror.get_y());
}
const RRGSB& module_cb = device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
std::string cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
ModuleId cb_module_id = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module_id));
const RRGSB& instance_cb = device_rr_gsb.get_gsb(instance_gsb_cb_coordinate);
vtr::Point<size_t> instance_cb_coordinate(instance_cb.get_cb_x(cb_type), instance_cb.get_cb_y(cb_type));
size_t cb_instance = cb_instance_ids.at(cb_type)[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
for (size_t itrack = 0; itrack < module_sb.get_chan_width(side_manager.get_side()); ++itrack) {
std::string sb_port_name = generate_sb_module_track_port_name(rr_graph.node_type(module_sb.get_chan_node(side_manager.get_side(), itrack)),
side_manager.get_side(), itrack,
module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
/* Prepare SB-related port information */
ModulePortId sb_port_id = module_manager.find_module_port(sb_module_id, sb_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module_id, sb_port_id));
BasicPort sb_port = module_manager.module_port(sb_module_id, sb_port_id);
/* Prepare CB-related port information */
PORTS cb_port_direction = OUT_PORT;
/* The cb port direction should be opposite to the sb port !!! */
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
cb_port_direction = IN_PORT;
} else {
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
}
std::string cb_port_name = generate_cb_module_track_port_name(cb_type,
itrack,
cb_port_direction);
ModulePortId cb_port_id = module_manager.find_module_port(cb_module_id, cb_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module_id, cb_port_id));
BasicPort cb_port = module_manager.module_port(cb_module_id, cb_port_id);
/* Source and sink port should match in size */
VTR_ASSERT(cb_port.get_width() == sb_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < cb_port.pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(top_module);
/* Configure the net source and sink:
* If sb port is an output (source), cb port is an input (sink)
* If sb port is an input (sink), cb port is an output (source)
*/
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
module_manager.add_module_net_sink(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
module_manager.add_module_net_source(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
} else {
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
module_manager.add_module_net_source(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
module_manager.add_module_net_sink(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
}
}
}
}
}
/********************************************************************
* Add module nets to connect the grid ports/pins to Connection Blocks
* and Switch Blocks
* To make it easy, this function will iterate over all the General
* Switch Blocks (GSBs), through which we can obtain the coordinates
* of all the grids, connection blocks and switch blocks that are
* supposed to be connected tightly.
*
* As such, we have completed all the connection for each grid.
* There is no need to iterate over the grids
*
* +-------------------------+ +---------------------------------+
* | | | Y-direction CB |
* | Grid[x][y+1] | | [x][y + 1] |
* | | +---------------------------------+
* +-------------------------+
* TOP SIDE
* +-------------+ +---------------------------------+
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* | | | |
* | | | OPIN_NODES OPIN_NODES |
* | X-direction | | |
* | CB | LEFT SIDE | Switch Block | RIGHT SIDE
* | [x][y] | | [x][y] |
* | | | |
* | | | CHAN_NODES CHAN_NODES |
* | | | |
* | | | OPIN_NODES OPIN_NODES |
* | | | |
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* +-------------+ +---------------------------------+
* BOTTOM SIDE
*******************************************************************/
void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin) {
vtr::Point<size_t> gsb_range = device_rr_gsb.get_gsb_range();
for (size_t ix = 0; ix < gsb_range.x(); ++ix) {
for (size_t iy = 0; iy < gsb_range.y(); ++iy) {
vtr::Point<size_t> gsb_coordinate(ix, iy);
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
/* Connect the grid pins of the GSB to adjacent grids */
if (false == duplicate_grid_pin) {
add_top_module_nets_connect_grids_and_sb(module_manager, top_module,
grids, grid_instance_ids,
rr_graph, device_rr_gsb, rr_gsb, sb_instance_ids,
compact_routing_hierarchy);
} else {
VTR_ASSERT_SAFE(true == duplicate_grid_pin);
add_top_module_nets_connect_grids_and_sb_with_duplicated_pins(module_manager, top_module,
grids, grid_instance_ids,
rr_graph, device_rr_gsb, rr_gsb, sb_instance_ids,
compact_routing_hierarchy);
}
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
grids, grid_instance_ids,
rr_graph, device_rr_gsb, rr_gsb, CHANX, cb_instance_ids.at(CHANX),
compact_routing_hierarchy);
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
grids, grid_instance_ids,
rr_graph, device_rr_gsb, rr_gsb, CHANY, cb_instance_ids.at(CHANY),
compact_routing_hierarchy);
add_top_module_nets_connect_sb_and_cb(module_manager, top_module,
rr_graph, device_rr_gsb, rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy);
}
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,35 @@
#ifndef BUILD_TOP_MODULE_CONNECTION_H
#define BUILD_TOP_MODULE_CONNECTION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "vtr_geometry.h"
#include "vtr_ndmatrix.h"
#include "device_grid.h"
#include "rr_graph_obj.h"
#include "device_rr_gsb.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
const ModuleId& top_module,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,447 @@
/********************************************************************
* This file includes functions that are used to organize memories
* in the top module of FPGA fabric
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from vpr library */
#include "vpr_utils.h"
#include "rr_gsb_utils.h"
#include "openfpga_reserved_words.h"
#include "openfpga_naming.h"
#include "module_manager_utils.h"
#include "build_top_module_memory.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* This function adds the CBX/CBY of a tile
* to the memory modules and memory instances
* This function is designed for organizing memory modules in top-level
* module
*******************************************************************/
static
void organize_top_module_tile_cb_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const vtr::Matrix<size_t>& cb_instance_ids,
const DeviceRRGSB& device_rr_gsb,
const RRGSB& rr_gsb,
const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
/* If the CB does not exist, we can skip addition */
if ( false == rr_gsb.is_cb_exist(cb_type)) {
return;
}
/* Skip if the cb does not contain any configuration bits! */
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
return;
}
vtr::Point<size_t> cb_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
if (true == compact_routing_hierarchy) {
/* Note: use GSB coordinate when inquire for unique modules!!! */
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, vtr::Point<size_t>(rr_gsb.get_x(), rr_gsb.get_y()));
cb_coord.set_x(unique_mirror.get_cb_x(cb_type));
cb_coord.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coord);
ModuleId cb_module = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
/* Identify if this sub module includes configuration bits,
* we will update the memory module and instance list
*/
if (0 < find_module_num_config_bits(module_manager, cb_module,
circuit_lib, sram_model,
sram_orgz_type)) {
/* Note that use the original CB coodinate for instance id searching ! */
module_manager.add_configurable_child(top_module, cb_module, cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)]);
}
}
/********************************************************************
* This function adds the SB, CBX, CBY and Grid of a tile
* to the memory modules and memory instances
* This function is designed for organizing memory modules in top-level
* module
*******************************************************************/
static
void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const DeviceRRGSB& device_rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy,
const vtr::Point<size_t>& tile_coord,
const e_side& tile_border_side) {
vtr::Point<size_t> gsb_coord_range = device_rr_gsb.get_gsb_range();
vtr::Point<size_t> gsb_coord(tile_coord.x(), tile_coord.y() - 1);
/* We do NOT consider SB and CBs if the gsb is not in the range! */
if ( (gsb_coord.x() < gsb_coord_range.x())
&& (gsb_coord.y() < gsb_coord_range.y()) ) {
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(gsb_coord.x(), gsb_coord.y());
/* Find Switch Block: unique module id and instance id!
* Note that switch block does always exist in a GSB
*/
vtr::Point<size_t> sb_coord(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
if (true == compact_routing_hierarchy) {
const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(sb_coord);
sb_coord.set_x(unique_mirror.get_sb_x());
sb_coord.set_y(unique_mirror.get_sb_y());
}
std::string sb_module_name = generate_switch_block_module_name(sb_coord);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Identify if this sub module includes configuration bits,
* we will update the memory module and instance list
*/
/* If the CB does not exist, we can skip addition */
if ( true == rr_gsb.is_sb_exist()) {
if (0 < find_module_num_config_bits(module_manager, sb_module,
circuit_lib, sram_model,
sram_orgz_type)) {
module_manager.add_configurable_child(top_module, sb_module, sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()]);
}
}
/* Try to find and add CBX and CBY */
organize_top_module_tile_cb_modules(module_manager, top_module, circuit_lib,
sram_orgz_type, sram_model,
cb_instance_ids.at(CHANX),
device_rr_gsb, rr_gsb, CHANX,
compact_routing_hierarchy);
organize_top_module_tile_cb_modules(module_manager, top_module, circuit_lib,
sram_orgz_type, sram_model,
cb_instance_ids.at(CHANY),
device_rr_gsb, rr_gsb, CHANY,
compact_routing_hierarchy);
}
/* Find the module name for this type of grid */
t_physical_tile_type_ptr grid_type = grids[tile_coord.x()][tile_coord.y()].type;
/* Skip EMPTY Grid */
if (true == is_empty_type(grid_type)) {
return;
}
/* Skip width > 1 or height > 1 Grid, which should already been processed when offset=0 */
if ( (0 < grids[tile_coord.x()][tile_coord.y()].width_offset)
|| (0 < grids[tile_coord.x()][tile_coord.y()].height_offset) ) {
return;
}
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), tile_border_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Identify if this sub module includes configuration bits,
* we will update the memory module and instance list
*/
if (0 < find_module_num_config_bits(module_manager, grid_module,
circuit_lib, sram_model,
sram_orgz_type)) {
module_manager.add_configurable_child(top_module, grid_module, grid_instance_ids[tile_coord.x()][tile_coord.y()]);
}
}
/********************************************************************
* Organize the list of memory modules and instances
* This function will record all the sub modules of the top-level module
* (those have memory ports) to two lists:
* 1. memory_modules records the module ids
* 2. memory_instances records the instance ids
* To keep a clean memory connection between sub modules and top-level module,
* the sequence of memory_modules and memory_instances will follow
* a chain of tiles considering their physical location
*
* Inter tile connection:
* +--------------------------------------------------------+
* | +------+------+-----+------+ |
* | | I/O | I/O | ... | I/O | |
* | | TOP | TOP | | TOP | |
* | +------+------+-----+------+ |
* | +---------------------------------->tail |
* | +------+ | +------+------+-----+------+ +------+ |
* | | | | | | | | | | | |
* | | I/O | | | Tile | Tile | ... | Tile | | I/O | |
* | | LEFT | | | [h+1]| [h+2]| | [n] | |RIGHT | |
* | +------+ | +------+------+-----+------+ +------+ |
* | +-------------------------------+ |
* | ... ... ... ... ... | ... |
* | +-------------------------------+ |
* | +------+ | +------+------+-----+------+ +------+ |
* | | | | | | | | | | | |
* | | I/O | | | Tile | Tile | ... | Tile | | I/O | |
* | | LEFT | | | [i+1]| [i+2]| | [j] | |RIGHT | |
* | +------+ | +------+------+-----+------+ +------+ |
* | +-------------------------------+ |
* | +------+ +------+------+-----+------+ | +------+ |
* | | | | | | | | | | | |
* | | I/O | | Tile | Tile | ... | Tile | | | I/O | |
* | | LEFT | | [0] | [1] | | [i] | | |RIGHT | |
* | +------+ +------+------+-----+------+ | +------+ |
* +-------------------------------------------+ |
* +------+------+-----+------+ |
* | I/O | I/O | ... | I/O | |
* |BOTTOM|BOTTOM| |BOTTOM| |
* +------+------+-----+------+ |
* head >-----------------------------------------------+
*
* Inner tile connection
*
* Tile
* +---------------+----------+
* <-+---------------+ + |
* | | | |
* | CLB | | CBY |
* | +-|-+ |
* | | | |
* +---------------+----------+
* | +-+----+-----+---<---
* | CBX | SB |
* | | |
* +---------------+----------+
*
*******************************************************************/
void organize_top_module_memory_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const DeviceRRGSB& device_rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy) {
/* Ensure clean vectors to return */
VTR_ASSERT(true == module_manager.configurable_children(top_module).empty());
/* First, organize the I/O tiles on the border */
/* Special for the I/O tileas on RIGHT and BOTTOM,
* which are only I/O blocks, which do NOT contain CBs and SBs
*/
std::vector<e_side> io_sides{BOTTOM, RIGHT, TOP, LEFT};
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coords;
/* BOTTOM side I/Os */
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
io_coords[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
}
/* RIGHT side I/Os */
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
io_coords[RIGHT].push_back(vtr::Point<size_t>(grids.width() - 1, iy));
}
/* TOP side I/Os
* Special case for TOP side: We need tile at ix = 0, which has a SB!!!
*
* TOP-LEFT CORNER of FPGA fabric
*
* +--------+ +-------+
* | EMPTY | | EMPTY |
* | Grid | | CBX |
* | [0][x] | | |
* +--------+ +-------+
* +--------+ +--------+
* | EMPTY | | SB |
* | CBX | | [0][x] |
* +--------+ +--------+
*
*/
for (size_t ix = grids.width() - 2; ix >= 1; --ix) {
io_coords[TOP].push_back(vtr::Point<size_t>(ix, grids.height() - 1));
}
io_coords[TOP].push_back(vtr::Point<size_t>(0, grids.height() - 1));
/* LEFT side I/Os */
for (size_t iy = grids.height() - 2; iy >= 1; --iy) {
io_coords[LEFT].push_back(vtr::Point<size_t>(0, iy));
}
for (const e_side& io_side : io_sides) {
for (const vtr::Point<size_t>& io_coord : io_coords[io_side]) {
/* Identify the GSB that surrounds the grid */
organize_top_module_tile_memory_modules(module_manager, top_module,
circuit_lib, sram_orgz_type, sram_model,
grids, grid_instance_ids,
device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy,
io_coord, io_side);
}
}
/* For the core grids */
std::vector<vtr::Point<size_t>> core_coords;
bool positive_direction = true;
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
/* For positive direction: -----> */
if (true == positive_direction) {
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
core_coords.push_back(vtr::Point<size_t>(ix, iy));
}
} else {
VTR_ASSERT(false == positive_direction);
/* For negative direction: -----> */
for (size_t ix = grids.width() - 2; ix >= 1; --ix) {
core_coords.push_back(vtr::Point<size_t>(ix, iy));
}
}
/* Flip the positive direction to be negative */
positive_direction = !positive_direction;
}
for (const vtr::Point<size_t>& core_coord : core_coords) {
organize_top_module_tile_memory_modules(module_manager, top_module,
circuit_lib, sram_orgz_type, sram_model,
grids, grid_instance_ids,
device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy,
core_coord, NUM_SIDES);
}
}
/*********************************************************************
* Add the port-to-port connection between all the memory modules
* and their parent module
*
* Create nets to wire the control signals of memory module to
* the configuration ports of primitive module
*
* Configuration Chain
* -------------------
*
* config_bus (head) config_bus (tail)
* | ^
* primitive | |
* +---------------------------------------------+
* | | | |
* | v | |
* | +-------------------------------------+ |
* | | CMOS-based Memory Modules | |
* | +-------------------------------------+ |
* | | | |
* | v v |
* | sram_out sram_outb |
* | |
* +---------------------------------------------+
*
* Memory bank
* -----------
*
* config_bus (BL) config_bus (WL)
* | |
* primitive | |
* +---------------------------------------------+
* | | | |
* | v v |
* | +-------------------------------------+ |
* | | CMOS-based Memory Modules | |
* | +-------------------------------------+ |
* | | | |
* | v v |
* | sram_out sram_outb |
* | |
* +---------------------------------------------+
*
**********************************************************************/
static
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type) {
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* Nothing to do */
break;
case CONFIG_MEM_SCAN_CHAIN: {
add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, CONFIG_MEM_SCAN_CHAIN);
break;
}
case CONFIG_MEM_MEMORY_BANK:
/* TODO: */
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of SRAM organization!\n");
exit(1);
}
}
/********************************************************************
* TODO:
* Add the port-to-port connection between a memory module
* and the configuration bus of a primitive module
*
* Create nets to wire the control signals of memory module to
* the configuration ports of primitive module
*
* Primitive module
* +----------------------------+
* | +--------+ |
* config | | | |
* ports --->|--------------->| Memory | |
* | | Module | |
* | | | |
* | +--------+ |
* +----------------------------+
* The detailed config ports really depend on the type
* of SRAM organization.
*
* The config_bus in the argument is the reserved address of configuration
* bus in the parent_module for this memory module
*
* The configuration bus connection will depend not only
* the design technology of the memory cells but also the
* configuration styles of FPGA fabric.
* Here we will branch on the design technology
*
* Note: this function SHOULD be called after the pb_type_module is created
* and its child module (logic_module and memory_module) is created!
*******************************************************************/
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_design_tech& mem_tech) {
switch (mem_tech) {
case CIRCUIT_MODEL_DESIGN_CMOS:
add_top_module_nets_cmos_memory_config_bus(module_manager, parent_module,
sram_orgz_type);
break;
case CIRCUIT_MODEL_DESIGN_RRAM:
/* TODO: */
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of memory design technology!\n");
exit(1);
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,43 @@
#ifndef BUILD_TOP_MODULE_MEMORY_H
#define BUILD_TOP_MODULE_MEMORY_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include <map>
#include "vtr_ndmatrix.h"
#include "module_manager.h"
#include "circuit_types.h"
#include "circuit_library.h"
#include "device_grid.h"
#include "device_rr_gsb.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void organize_top_module_memory_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids,
const DeviceRRGSB& device_rr_gsb,
const vtr::Matrix<size_t>& sb_instance_ids,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy);
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_design_tech& mem_tech);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,90 @@
/********************************************************************
* This file include most utilized functions for building the module
* graph for FPGA fabric
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
/* Headers from vpr library */
#include "vpr_utils.h"
#include "openfpga_naming.h"
/* Module builder headers */
#include "build_top_module_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Generate the name for a grid block, by considering
* 1. if it locates on the border with given device size
* 2. its type
*
* This function is mainly used in the top-level module generation
*******************************************************************/
std::string generate_grid_block_module_name_in_top_module(const std::string& prefix,
const DeviceGrid& grids,
const vtr::Point<size_t>& grid_coord) {
/* Determine if the grid locates at the border */
vtr::Point<size_t> device_size(grids.width(), grids.height());
e_side border_side = find_grid_border_side(device_size, grid_coord);
return generate_grid_block_module_name(prefix,
std::string(grids[grid_coord.x()][grid_coord.y()].type->name),
is_io_type(grids[grid_coord.x()][grid_coord.y()].type),
border_side);
}
/********************************************************************
* Find the cb_type of a GSB in the top-level module
* depending on the side of SB
* TOP/BOTTOM side: CHANY
* RIGHT/LEFT side: CHANX
*******************************************************************/
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side) {
VTR_ASSERT(NUM_SIDES != sb_side);
if ((TOP == sb_side) || (BOTTOM == sb_side)) {
return CHANY;
}
VTR_ASSERT((RIGHT == sb_side) || (LEFT == sb_side));
return CHANX;
}
/********************************************************************
* Find the GSB coordinate for a CB in the top-level module
* depending on the side of a SB
* TODO: use vtr::Point<size_t> to replace DeviceCoordinator
*******************************************************************/
vtr::Point<size_t> find_top_module_gsb_coordinate_by_sb_side(const RRGSB& rr_gsb,
const e_side& sb_side) {
VTR_ASSERT(NUM_SIDES != sb_side);
vtr::Point<size_t> gsb_coordinate;
if ((TOP == sb_side) || (LEFT == sb_side)) {
gsb_coordinate.set_x(rr_gsb.get_x());
gsb_coordinate.set_y(rr_gsb.get_y());
return gsb_coordinate;
}
VTR_ASSERT((RIGHT == sb_side) || (BOTTOM == sb_side));
/* RIGHT side: x + 1 */
if (RIGHT == sb_side) {
gsb_coordinate.set_x(rr_gsb.get_x() + 1);
gsb_coordinate.set_y(rr_gsb.get_y());
}
/* BOTTOM side: y - 1 */
if (BOTTOM == sb_side) {
gsb_coordinate.set_x(rr_gsb.get_x());
gsb_coordinate.set_y(rr_gsb.get_y() - 1);
}
return gsb_coordinate;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,31 @@
#ifndef BUILD_TOP_MODULE_UTILS_H
#define BUILD_TOP_MODULE_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include <string>
#include "vtr_geometry.h"
#include "device_grid.h"
#include "rr_gsb.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
std::string generate_grid_block_module_name_in_top_module(const std::string& prefix,
const DeviceGrid& grids,
const vtr::Point<size_t>& grid_coord);
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side);
vtr::Point<size_t> find_top_module_gsb_coordinate_by_sb_side(const RRGSB& rr_gsb,
const e_side& sb_side);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,367 @@
/***************************************************************************************
* This file includes functions that build the point-to-point direct connections
* between tiles (programmable blocks)
***************************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_tokenizer.h"
#include "openfpga_port.h"
#include "openfpga_port_parser.h"
/* Headers from vpr library */
#include "vpr_utils.h"
#include "build_tile_direct.h"
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Parse the from tile name from the direct definition
* The definition string should be in the following format:
* <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>]
***************************************************************************************/
static
std::string parse_direct_tile_name(const std::string& direct_tile_inf) {
StringToken tokenizer(direct_tile_inf);
std::vector<std::string> tokens = tokenizer.split('.');
/* We should have only 2 elements and the first is tile name */
if (2 != tokens.size()) {
VTR_LOG_ERROR("Invalid definition on direct tile '%s'!\n\tExpect <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>].\n",
direct_tile_inf.c_str());
}
return tokens[0];
}
/***************************************************************************************
* Check if a pin is located on a given side of physical tile
* If the given side is NUM_SIDES, we will search all the sides
***************************************************************************************/
static
bool is_pin_locate_at_physical_tile_side(t_physical_tile_type_ptr physical_tile,
const size_t& pin_width_offset,
const size_t& pin_height_offset,
const size_t& pin_id,
const e_side& pin_side) {
if (NUM_SIDES == pin_side) {
for (size_t side = 0; side < NUM_SIDES; ++side) {
if (true == physical_tile->pinloc[pin_width_offset][pin_height_offset][side][pin_id]) {
return true;
}
}
}
return physical_tile->pinloc[pin_width_offset][pin_height_offset][size_t(pin_side)][pin_id];
}
/***************************************************************************************
* Find the pin ids of a physical tile based on the given port name, LSB and MSB
***************************************************************************************/
static
std::vector<size_t> find_physical_tile_pin_id(t_physical_tile_type_ptr physical_tile,
const size_t& pin_width_offset,
const size_t& pin_height_offset,
const BasicPort& tile_port,
const e_side& pin_side) {
std::vector<size_t> pin_ids;
/* Walk through the port of the tile */
for (const t_physical_tile_port& physical_tile_port : physical_tile->ports) {
if (std::string(physical_tile_port.name) != tile_port.get_name()) {
continue;
}
/* If the wanted port is invalid, it assumes that we want the full port */
if (false == tile_port.is_valid()) {
for (int ipin = 0; ipin < physical_tile_port.num_pins; ++ipin) {
int pin_id = physical_tile_port.absolute_first_pin_index + ipin;
VTR_ASSERT(pin_id < physical_tile->num_pins);
/* Check if the pin is located on the wanted side */
if (true == is_pin_locate_at_physical_tile_side(physical_tile,
pin_width_offset,
pin_height_offset,
pin_id, pin_side)) {
pin_ids.push_back(pin_id);
}
}
continue;
}
/* Find the LSB and MSB of the pin */
VTR_ASSERT_SAFE(true == tile_port.is_valid());
BasicPort ref_port(physical_tile_port.name, physical_tile_port.num_pins);
if (false == ref_port.contained(tile_port)) {
VTR_LOG_ERROR("Defined direct port '%s[%lu:%lu]' is out of range for physical port '%s[%lu:%lu]'!\n",
tile_port.get_name().c_str(),
tile_port.get_lsb(), tile_port.get_msb(),
ref_port.get_name().c_str(),
ref_port.get_lsb(), ref_port.get_msb());
exit(1);
}
for (const size_t& ipin : tile_port.pins()) {
int pin_id = physical_tile_port.absolute_first_pin_index + ipin;
VTR_ASSERT(pin_id < physical_tile->num_pins);
/* Check if the pin is located on the wanted side */
if (true == is_pin_locate_at_physical_tile_side(physical_tile,
pin_width_offset,
pin_height_offset,
pin_id, pin_side)) {
pin_ids.push_back(pin_id);
}
}
}
return pin_ids;
}
/***************************************************************************************
* Build the point-to-point direct connections based on
* - original VPR arch definition
* This is limited to the inner-column and inner-row connections
*
* Build the inner-column and inner-row connections
*
* +------+
* | Tile |
* +------+ +------+ +------+
* | or | Tile |--->| Tile |
* v +------+ +------+
* +------+
* | Tile |
* +------+
*
***************************************************************************************/
static
void build_inner_column_row_tile_direct(TileDirect& tile_direct,
t_direct_inf& vpr_direct,
const DeviceContext& device_ctx,
const ArchDirectId& arch_direct_id) {
/* Get the source tile and pin information */
std::string from_tile_name = parse_direct_tile_name(std::string(vpr_direct.from_pin));
PortParser from_tile_port_parser(std::string(vpr_direct.from_pin));
const BasicPort& from_tile_port = from_tile_port_parser.port();
/* Get the sink tile and pin information */
std::string to_tile_name = parse_direct_tile_name(std::string(vpr_direct.to_pin));
PortParser to_tile_port_parser(std::string(vpr_direct.to_pin));
const BasicPort& to_tile_port = to_tile_port_parser.port();
/* Walk through the device fabric and find the grid that fit the source */
for (size_t x = 0; x < device_ctx.grid.width(); ++x) {
for (size_t y = 0; y < device_ctx.grid.height(); ++y) {
/* Bypass empty grid */
if (true == is_empty_type(device_ctx.grid[x][y].type)) {
continue;
}
/* Bypass the grid that does not fit the from_tile name */
if (from_tile_name != std::string(device_ctx.grid[x][y].type->name)) {
continue;
}
/* Try to find the pin in this tile */
std::vector<size_t> from_pins = find_physical_tile_pin_id(device_ctx.grid[x][y].type,
device_ctx.grid[x][y].width_offset,
device_ctx.grid[x][y].height_offset,
from_tile_port,
vpr_direct.from_side);
/* If nothing found, we can continue */
if (0 == from_pins.size()) {
continue;
}
/* We should try to the sink grid for inner-column/row direct connections */
vtr::Point<size_t> from_grid_coord(x, y);
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
if ((to_grid_coord.x() >= device_ctx.grid.width())
|| (to_grid_coord.y() >= device_ctx.grid.height())) {
continue;
}
/* Bypass the grid that does not fit the from_tile name */
if (to_tile_name != std::string(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type->name)) {
continue;
}
/* Try to find the pin in this tile */
std::vector<size_t> to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset,
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].height_offset,
to_tile_port,
vpr_direct.to_side);
/* If nothing found, we can continue */
if (0 == to_pins.size()) {
continue;
}
/* If from port and to port do not match in sizes, error out */
if (from_pins.size() != to_pins.size()) {
VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n",
from_tile_port.get_name().c_str(),
from_tile_port.get_lsb(),
from_tile_port.get_msb(),
vpr_direct.name,
to_tile_port.get_name().c_str(),
to_tile_port.get_lsb(),
to_tile_port.get_msb());
exit(1);
}
/* Now add the tile direct */
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type,
from_grid_coord, vpr_direct.from_side, from_pins[ipin],
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
}
}
}
}
/***************************************************************************************
* Build the point-to-point direct connections based on
* - OpenFPGA arch definition
* This is limited to the inter-column and inter-row connections
*
* Build the inter-column and inter-row connections
*
* +------+ +------+
* | Tile | | Tile |
* +------+ +------+
* | ^
* | |
* +-------------
*
* +------+
* | Tile |-------+
* +------+ |
* |
* +------+ |
* | Tile |<------+
* +------+
*
*
***************************************************************************************/
static
void build_inter_column_row_tile_direct(TileDirect& tile_direct,
t_direct_inf& vpr_direct,
const DeviceContext& device_ctx,
const ArchDirect& arch_direct,
const ArchDirectId& arch_direct_id,
const CircuitLibrary& circuit_lib) {
/* Get the source tile and pin information */
std::string from_tile_name = parse_direct_tile_name(std::string(vpr_direct.from_pin));
PortParser from_tile_port_parser(std::string(vpr_direct.from_pin));
const BasicPort& from_tile_port = from_tile_port_parser.port();
/* Get the sink tile and pin information */
std::string to_tile_name = parse_direct_tile_name(std::string(vpr_direct.to_pin));
PortParser to_tile_port_parser(std::string(vpr_direct.to_pin));
const BasicPort& to_tile_port = to_tile_port_parser.port();
/* Walk through the device fabric and find the grid that fit the source */
for (size_t x = 0; x < device_ctx.grid.width(); ++x) {
for (size_t y = 0; y < device_ctx.grid.height(); ++y) {
/* Bypass empty grid */
if (true == is_empty_type(device_ctx.grid[x][y].type)) {
continue;
}
/* Bypass the grid that does not fit the from_tile name */
if (from_tile_name != std::string(device_ctx.grid[x][y].type->name)) {
continue;
}
/* Try to find the pin in this tile */
std::vector<size_t> from_pins = find_physical_tile_pin_id(device_ctx.grid[x][y].type,
device_ctx.grid[x][y].width_offset,
device_ctx.grid[x][y].height_offset,
from_tile_port,
vpr_direct.from_side);
/* If nothing found, we can continue */
if (0 == from_pins.size()) {
continue;
}
/* We should try to the sink grid for inner-column/row direct connections */
vtr::Point<size_t> from_grid_coord(x, y);
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
if ((to_grid_coord.x() >= device_ctx.grid.width())
|| (to_grid_coord.y() >= device_ctx.grid.height())) {
continue;
}
/* Bypass the grid that does not fit the from_tile name */
if (to_tile_name != std::string(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type->name)) {
continue;
}
/* Try to find the pin in this tile */
std::vector<size_t> to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset,
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].height_offset,
to_tile_port,
vpr_direct.to_side);
/* If nothing found, we can continue */
if (0 == to_pins.size()) {
continue;
}
/* If from port and to port do not match in sizes, error out */
if (from_pins.size() != to_pins.size()) {
VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n",
from_tile_port.get_name().c_str(),
from_tile_port.get_lsb(),
from_tile_port.get_msb(),
vpr_direct.name,
to_tile_port.get_name().c_str(),
to_tile_port.get_lsb(),
to_tile_port.get_msb());
exit(1);
}
/* Now add the tile direct */
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type,
from_grid_coord, vpr_direct.from_side, from_pins[ipin],
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
}
}
}
}
/***************************************************************************************
* Top-level functions that build the point-to-point direct connections
* between tiles (programmable blocks)
***************************************************************************************/
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
const ArchDirect& arch_direct,
const CircuitLibrary& circuit_lib) {
vtr::ScopedStartFinishTimer timer("Build the annotation about direct connection between tiles");
TileDirect tile_direct;
/* Walk through each direct definition in the VPR arch */
for (int idirect = 0; idirect < device_ctx.arch->num_directs; ++idirect) {
ArchDirectId arch_direct_id = arch_direct.direct(std::string(device_ctx.arch->Directs[idirect].name));
VTR_ASSERT(ArchDirectId::INVALID() != arch_direct_id);
/* Build from original VPR arch definition */
build_inner_column_row_tile_direct(tile_direct,
device_ctx.arch->Directs[idirect],
device_ctx,
arch_direct_id);
/* TODO: Build from OpenFPGA arch definition */
}
return tile_direct;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,25 @@
#ifndef BUILD_TILE_DIRECT_H
#define BUILD_TILE_DIRECT_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "arch_direct.h"
#include "tile_direct.h"
#include "circuit_library.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
const ArchDirect& arch_direct,
const CircuitLibrary& circuit_lib);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,117 @@
/******************************************************************************
* Memember functions for data structure TileDirect
******************************************************************************/
#include "vtr_assert.h"
#include "tile_direct.h"
/* begin namespace openfpga */
namespace openfpga {
/**************************************************
* Public Accessors
*************************************************/
TileDirect::tile_direct_range TileDirect::directs() const {
return vtr::make_range(direct_ids_.begin(), direct_ids_.end());
}
t_physical_tile_type_ptr TileDirect::from_tile(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return from_tiles_[direct_id];
}
vtr::Point<size_t> TileDirect::from_tile_coordinate(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return from_tile_coords_[direct_id];
}
size_t TileDirect::from_tile_pin(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return from_tile_pins_[direct_id];
}
e_side TileDirect::from_tile_side(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return from_tile_sides_[direct_id];
}
t_physical_tile_type_ptr TileDirect::to_tile(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return to_tiles_[direct_id];
}
vtr::Point<size_t> TileDirect::to_tile_coordinate(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return to_tile_coords_[direct_id];
}
size_t TileDirect::to_tile_pin(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return to_tile_pins_[direct_id];
}
e_side TileDirect::to_tile_side(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return to_tile_sides_[direct_id];
}
ArchDirectId TileDirect::arch_direct(const TileDirectId& direct_id) const {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(direct_id));
return arch_directs_[direct_id];
}
/******************************************************************************
* Private Mutators
******************************************************************************/
TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile,
const vtr::Point<size_t>& from_tile_coord,
const e_side& from_tile_side,
const size_t& from_tile_pin,
t_physical_tile_type_ptr to_tile,
const vtr::Point<size_t>& to_tile_coord,
const e_side& to_tile_side,
const size_t& to_tile_pin) {
/* Create an new id */
TileDirectId direct = TileDirectId(direct_ids_.size());
direct_ids_.push_back(direct);
/* Allocate other attributes */
from_tiles_.push_back(from_tile);
from_tile_coords_.push_back(from_tile_coord);
from_tile_sides_.push_back(from_tile_side);
from_tile_pins_.push_back(from_tile_pin);
to_tiles_.push_back(to_tile);
to_tile_coords_.push_back(to_tile_coord);
to_tile_sides_.push_back(to_tile_side);
to_tile_pins_.push_back(to_tile_pin);
arch_directs_.emplace_back(ArchDirectId::INVALID());
return direct;
}
void TileDirect::set_arch_direct_id(const TileDirectId& tile_direct_id,
const ArchDirectId& arch_direct_id) {
/* Validate the direct_id */
VTR_ASSERT(valid_direct_id(tile_direct_id));
arch_directs_[tile_direct_id] = arch_direct_id;
}
/******************************************************************************
* Private validators/invalidators
******************************************************************************/
bool TileDirect::valid_direct_id(const TileDirectId& direct_id) const {
return ( size_t(direct_id) < direct_ids_.size() ) && ( direct_id == direct_ids_[direct_id] );
}
} /* end namespace openfpga */

View File

@ -0,0 +1,86 @@
#ifndef TILE_DIRECT_H
#define TILE_DIRECT_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_geometry.h"
#include "vtr_vector.h"
/* Headers from readarch library */
#include "physical_types.h"
/* Headers from readarchopenfpga library */
#include "arch_direct.h"
#include "tile_direct_fwd.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* TileDirect object aims to be a database to store all the information
* about direct connection between tiles
* - starting tile and end tile for each point-to-point direct connection
* - circuit model to implement each direct connection
*
* TileDirect is compiled from ArchDirect for a specific FPGA fabric.
*******************************************************************/
class TileDirect {
public: /* Types and ranges */
typedef vtr::vector<TileDirectId, TileDirectId>::const_iterator tile_direct_iterator;
typedef vtr::Range<tile_direct_iterator> tile_direct_range;
public: /* Public aggregators */
tile_direct_range directs() const;
t_physical_tile_type_ptr from_tile(const TileDirectId& direct_id) const;
vtr::Point<size_t> from_tile_coordinate(const TileDirectId& direct_id) const;
e_side from_tile_side(const TileDirectId& direct_id) const;
size_t from_tile_pin(const TileDirectId& direct_id) const;
t_physical_tile_type_ptr to_tile(const TileDirectId& direct_id) const;
vtr::Point<size_t> to_tile_coordinate(const TileDirectId& direct_id) const;
e_side to_tile_side(const TileDirectId& direct_id) const;
size_t to_tile_pin(const TileDirectId& direct_id) const;
ArchDirectId arch_direct(const TileDirectId& direct_id) const;
public: /* Public mutators */
TileDirectId add_direct(t_physical_tile_type_ptr from_tile,
const vtr::Point<size_t>& from_tile_coord,
const e_side& from_tile_side,
const size_t& from_tile_pin,
t_physical_tile_type_ptr to_tile,
const vtr::Point<size_t>& to_tile_coord,
const e_side& to_tile_side,
const size_t& to_tile_pin);
void set_arch_direct_id(const TileDirectId& tile_direct_id,
const ArchDirectId& arch_direct_id);
public: /* Public validators/invalidators */
bool valid_direct_id(const TileDirectId& direct_id) const;
private: /* Internal Data */
vtr::vector<TileDirectId, TileDirectId> direct_ids_;
/* Detailed information about the starting tile
* - tile type description
* - tile coordinate
* - tile pin id
*/
vtr::vector<TileDirectId, t_physical_tile_type_ptr> from_tiles_;
vtr::vector<TileDirectId, vtr::Point<size_t>> from_tile_coords_;
vtr::vector<TileDirectId, e_side> from_tile_sides_;
vtr::vector<TileDirectId, size_t> from_tile_pins_;
/* Detailed information about the ending tile
* - tile type description
* - tile coordinate
* - tile pin id
*/
vtr::vector<TileDirectId, t_physical_tile_type_ptr> to_tiles_;
vtr::vector<TileDirectId, vtr::Point<size_t>> to_tile_coords_;
vtr::vector<TileDirectId, e_side> to_tile_sides_;
vtr::vector<TileDirectId, size_t> to_tile_pins_;
vtr::vector<TileDirectId, ArchDirectId> arch_directs_;
};
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,23 @@
/**************************************************
* This file includes only declarations for
* the data structures for TileDirect
* Please refer to tile_direct.h for more details
*************************************************/
#ifndef TILE_DIRECT_FWD_H
#define TILE_DIRECT_FWD_H
#include "vtr_strong_id.h"
/* begin namespace openfpga */
namespace openfpga {
/* Strong Ids for ModuleManager */
struct tile_direct_id_tag;
typedef vtr::StrongId<tile_direct_id_tag> TileDirectId;
class TileDirect;
} /* end namespace openfpga */
#endif

View File

@ -10,6 +10,9 @@
#include "vtr_log.h"
#include "vtr_assert.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "openfpga_naming.h"
#include "memory_utils.h"
#include "pb_type_utils.h"

View File

@ -0,0 +1,39 @@
/********************************************************************
* This file includes most utilized functions for data structure
* DeviceRRGSB
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
/* Headers from openfpgautil library */
#include "openfpga_side_manager.h"
#include "rr_gsb_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Find if a X-direction or Y-direction Connection Block contains
* routing tracks only (zero configuration bits and routing multiplexers)
*******************************************************************/
bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb,
const t_rr_type& cb_type) {
bool routing_track_only = true;
/* Find routing multiplexers on the sides of a Connection block where IPIN nodes locate */
std::vector<enum e_side> cb_sides = rr_gsb.get_cb_ipin_sides(cb_type);
for (size_t side = 0; side < cb_sides.size(); ++side) {
enum e_side cb_ipin_side = cb_sides[side];
SideManager side_manager(cb_ipin_side);
if (0 < rr_gsb.get_num_ipin_nodes(cb_ipin_side)) {
routing_track_only = false;
break;
}
}
return routing_track_only;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef RR_GSB_UTILS_H
#define RR_GSB_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include <vector>
#include "rr_gsb.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb,
const t_rr_type& cb_type);
} /* end namespace openfpga */
#endif