Merge branch 'refactoring' into dev
This commit is contained in:
commit
741d6d03bf
|
@ -61,7 +61,7 @@ std::string PbTypeAnnotation::idle_mode_name() const {
|
|||
return idle_mode_name_;
|
||||
}
|
||||
|
||||
std::string PbTypeAnnotation::mode_bits() const {
|
||||
std::vector<size_t> PbTypeAnnotation::mode_bits() const {
|
||||
return mode_bits_;
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ void PbTypeAnnotation::set_idle_mode_name(const std::string& name) {
|
|||
idle_mode_name_ = name;
|
||||
}
|
||||
|
||||
void PbTypeAnnotation::set_mode_bits(const std::string& mode_bits) {
|
||||
void PbTypeAnnotation::set_mode_bits(const std::vector<size_t>& mode_bits) {
|
||||
mode_bits_ = mode_bits;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class PbTypeAnnotation {
|
|||
bool is_physical_pb_type() const;
|
||||
std::string physical_mode_name() const;
|
||||
std::string idle_mode_name() const;
|
||||
std::string mode_bits() const;
|
||||
std::vector<size_t> mode_bits() const;
|
||||
std::string circuit_model_name() const;
|
||||
int physical_pb_type_index_factor() const;
|
||||
int physical_pb_type_index_offset() const;
|
||||
|
@ -61,7 +61,7 @@ class PbTypeAnnotation {
|
|||
void set_physical_parent_mode_names(const std::vector<std::string>& names);
|
||||
void set_physical_mode_name(const std::string& name);
|
||||
void set_idle_mode_name(const std::string& name);
|
||||
void set_mode_bits(const std::string& mode_bits);
|
||||
void set_mode_bits(const std::vector<size_t>& mode_bits);
|
||||
void set_circuit_model_name(const std::string& name);
|
||||
void set_physical_pb_type_index_factor(const int& value);
|
||||
void set_physical_pb_type_index_offset(const int& value);
|
||||
|
@ -102,7 +102,7 @@ class PbTypeAnnotation {
|
|||
std::string idle_mode_name_;
|
||||
|
||||
/* Configuration bits to select an operting mode for the circuit mode name */
|
||||
std::string mode_bits_;
|
||||
std::vector<size_t> mode_bits_;
|
||||
|
||||
/* Circuit mode name linked to a physical pb_type.
|
||||
* This is only applicable to the physical pb_type
|
||||
|
|
|
@ -63,6 +63,31 @@ void read_xml_pb_port_annotation(pugi::xml_node& xml_port,
|
|||
pb_type_annotation.set_physical_pin_rotate_offset(name_attr, get_attribute(xml_port, "physical_mode_pin_rotate_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(0));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse mode_bits: convert from string to array of digits
|
||||
* We only allow the bit to either '0' or '1'
|
||||
*******************************************************************/
|
||||
static
|
||||
std::vector<size_t> parse_mode_bits(pugi::xml_node& xml_mode_bits,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const std::string& mode_bit_str) {
|
||||
std::vector<size_t> mode_bits;
|
||||
|
||||
for (const char& bit_char : mode_bit_str) {
|
||||
if ('0' == bit_char) {
|
||||
mode_bits.push_back(0);
|
||||
} else if ('1' == bit_char) {
|
||||
mode_bits.push_back(1);
|
||||
} else {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_mode_bits),
|
||||
"Unexpected '%c' character found in the mode bit '%s'! Only allow either '0' or '1'\n",
|
||||
bit_char, mode_bit_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return mode_bits;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML description for a pb_type annotation under a <pb_type> XML node
|
||||
*******************************************************************/
|
||||
|
@ -119,7 +144,8 @@ void read_xml_pb_type_annotation(pugi::xml_node& xml_pb_type,
|
|||
pb_type_annotation.set_idle_mode_name(get_attribute(xml_pb_type, "idle_mode_name", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string());
|
||||
|
||||
/* Parse mode bits which are applied to both pb_types */
|
||||
pb_type_annotation.set_mode_bits(get_attribute(xml_pb_type, "mode_bits", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string());
|
||||
std::vector<size_t> mode_bit_data = parse_mode_bits(xml_pb_type, loc_data, get_attribute(xml_pb_type, "mode_bits", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string());
|
||||
pb_type_annotation.set_mode_bits(mode_bit_data);
|
||||
|
||||
/* If this is a physical pb_type, circuit model name is an optional attribute,
|
||||
* which is applicable to leaf pb_type in the hierarchy
|
||||
|
|
|
@ -159,7 +159,12 @@ void write_xml_pb_type_annotation(std::fstream& fp,
|
|||
|
||||
/* Output mode_bits */
|
||||
if (!pb_type_annotation.mode_bits().empty()) {
|
||||
write_xml_attribute(fp, "mode_bits", pb_type_annotation.mode_bits().c_str());
|
||||
/* Convert the vector of integer to string */
|
||||
std::string mode_bits_str;
|
||||
for (const size_t& bit : pb_type_annotation.mode_bits()) {
|
||||
mode_bits_str += std::to_string(bit);
|
||||
}
|
||||
write_xml_attribute(fp, "mode_bits", mode_bits_str.c_str());
|
||||
}
|
||||
|
||||
/* Output circuit model name */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "vpr_pb_type_annotation.h"
|
||||
#include "pb_type_utils.h"
|
||||
#include "annotate_pb_graph.h"
|
||||
#include "check_pb_type_annotation.h"
|
||||
#include "annotate_pb_types.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
|
@ -178,88 +179,6 @@ void build_vpr_physical_pb_mode_implicit_annotation(const DeviceContext& vpr_dev
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse pb_type graph to ensure
|
||||
* 1. there is only a physical mode under each pb_type
|
||||
* 2. physical mode appears only when its parent is a physical mode.
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
||||
const bool& expect_physical_mode,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* We do not check any primitive pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* For non-primitive pb_type:
|
||||
* - If we expect a physical mode to exist under this pb_type
|
||||
* we should be able to find one in the annoation
|
||||
* - If we do NOT expect a physical mode, make sure we find
|
||||
* nothing in the annotation
|
||||
*/
|
||||
if (true == expect_physical_mode) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
||||
cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == expect_physical_mode);
|
||||
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
|
||||
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
|
||||
cur_pb_type->name);
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traverse all the modes
|
||||
* - for pb_type children under a physical mode, we expect an physical mode
|
||||
* - for pb_type children under non-physical mode, we expect no physical mode
|
||||
*/
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||
bool expect_child_physical_mode = false;
|
||||
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
expect_child_physical_mode = true && expect_physical_mode;
|
||||
}
|
||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||
expect_child_physical_mode, vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the physical mode annotation for
|
||||
* each pb_type in the device
|
||||
*******************************************************************/
|
||||
static
|
||||
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
|
||||
} else {
|
||||
VTR_LOG("Check physical mode annotation for pb_types failed with %ld errors!\n",
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function aims to make a pair of operating and physical
|
||||
* pb_types:
|
||||
|
@ -500,88 +419,66 @@ void build_vpr_physical_pb_type_implicit_annotation(const DeviceContext& vpr_dev
|
|||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check
|
||||
* - if a primitive pb_type has been mapped to a physical pb_type
|
||||
* - if every port of the pb_type have been linked a port of a physical pb_type
|
||||
* This function aims to link all the ports defined under a physical
|
||||
* pb_type to the ports of circuit model in the circuit library
|
||||
* The binding assumes that pb_type port should be defined with the same name
|
||||
* as the circuit port
|
||||
*******************************************************************/
|
||||
static
|
||||
void check_vpr_physical_primitive_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Find a pb_type '%s' which has not been mapped to any physical pb_type!\n",
|
||||
cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we need to check each port of the pb_type */
|
||||
for (t_port* pb_port : pb_type_ports(cur_pb_type)) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_pb_port(pb_port)) {
|
||||
VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n",
|
||||
pb_port->name, cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse pb_type graph to ensure
|
||||
* 1. there is only a physical mode under each pb_type
|
||||
* 2. physical mode appears only when its parent is a physical mode.
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* Primitive pb_type should always been binded to a physical pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
check_vpr_physical_primitive_pb_type_annotation(cur_pb_type, vpr_pb_type_annotation, num_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Traverse all the modes
|
||||
* - for pb_type children under a physical mode, we expect an physical mode
|
||||
* - for pb_type children under non-physical mode, we expect no physical mode
|
||||
bool link_physical_pb_port_to_circuit_port(t_pb_type* physical_pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
bool link_success = true;
|
||||
/* Iterate over the pb_ports
|
||||
* Note:
|
||||
* - Not every port defined in the circuit model will appear under the pb_type
|
||||
* Some circuit ports are just for physical implementation
|
||||
*/
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_physical_pb_type_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||
vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (t_port* pb_port : pb_type_ports(physical_pb_type)) {
|
||||
CircuitPortId circuit_port = circuit_lib.model_port(circuit_model, std::string(pb_port->name));
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the physical pb_type annotation for
|
||||
* each pb_type in the device
|
||||
* Every pb_type should have been linked to a physical pb_type
|
||||
* and every port of the pb_type have been linked a port of a physical pb_type
|
||||
*******************************************************************/
|
||||
static
|
||||
void check_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
/* If we cannot find a port with the same name, error out */
|
||||
if (CircuitPortId::INVALID() == circuit_port) {
|
||||
VTR_LOG_ERROR("Pb type port '%s' is not found in any port of circuit model '%s'!\n",
|
||||
pb_port->name, circuit_lib.model_name(circuit_model).c_str());
|
||||
link_success = false;
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check physical pb_type annotation for pb_types passed.\n");
|
||||
} else {
|
||||
VTR_LOG("Check physical pb_type annotation for pb_types failed with %ld errors!\n",
|
||||
num_err);
|
||||
|
||||
/* If the port width does not match, error out */
|
||||
if ((size_t)(pb_port->num_pins) != circuit_lib.port_size(circuit_port)) {
|
||||
VTR_LOG_ERROR("Pb type port '%s[%d:%d]' does not match the port '%s[%d:%d]' of circuit model '%s' in size!\n",
|
||||
pb_port->name,
|
||||
0, pb_port->num_pins - 1,
|
||||
circuit_lib.port_prefix(circuit_port).c_str(),
|
||||
0, circuit_lib.port_size(circuit_port) - 1,
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
link_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the port type does not match, error out */
|
||||
if (ERR_PORT == circuit_port_require_pb_port_type(circuit_lib.port_type(circuit_port))) {
|
||||
VTR_LOG_ERROR("Pb type port '%s' type does not match the port type '%s' of circuit model '%s'!\n",
|
||||
pb_port->name,
|
||||
circuit_lib.port_prefix(circuit_port).c_str(),
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
|
||||
link_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reach here, it means that mapping should be ok, update the vpr_pb_type_annotation */
|
||||
vpr_pb_type_annotation.add_pb_circuit_port(pb_port, circuit_port);
|
||||
VTR_LOG("Bind pb type '%s' port '%s' to circuit model '%s' port '%s'\n",
|
||||
physical_pb_type->name,
|
||||
pb_port->name,
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
circuit_lib.port_prefix(circuit_port).c_str());
|
||||
}
|
||||
|
||||
return link_success;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -613,6 +510,11 @@ bool link_physical_pb_type_to_circuit_model(t_pb_type* physical_pb_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Ensure that the pb_type ports can be matched in the circuit model ports */
|
||||
if (false == link_physical_pb_port_to_circuit_port(physical_pb_type, circuit_lib, circuit_model_id, vpr_pb_type_annotation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
|
||||
vpr_pb_type_annotation.add_pb_type_circuit_model(physical_pb_type, circuit_model_id);
|
||||
return true;
|
||||
|
@ -663,6 +565,19 @@ bool link_physical_pb_interconnect_to_circuit_model(t_pb_type* physical_pb_type,
|
|||
physical_pb_type->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Double check the type of circuit model, it should be the same as required physical type */
|
||||
e_circuit_model_type required_circuit_model_type = pb_interconnect_require_circuit_model_type(vpr_pb_type_annotation.interconnect_physical_type(pb_interc));
|
||||
if (circuit_lib.model_type(circuit_model_id) != required_circuit_model_type) {
|
||||
VTR_LOG_ERROR("Circuit model '%s' type '%s' does not match required type '%s' for interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
|
||||
circuit_lib.model_name(circuit_model_id).c_str(),
|
||||
CIRCUIT_MODEL_TYPE_STRING[circuit_lib.model_type(circuit_model_id)],
|
||||
CIRCUIT_MODEL_TYPE_STRING[required_circuit_model_type],
|
||||
pb_interc->name,
|
||||
physical_mode->name,
|
||||
physical_pb_type->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
|
||||
vpr_pb_type_annotation.add_interconnect_circuit_model(pb_interc, circuit_model_id);
|
||||
|
@ -930,6 +845,117 @@ void link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(const DeviceC
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will bind mode selection bits to a primitive pb_type
|
||||
* in the vpr_pb_type_annotation
|
||||
*******************************************************************/
|
||||
static
|
||||
bool link_primitive_pb_type_to_mode_bits(t_pb_type* primitive_pb_type,
|
||||
const PbTypeAnnotation& pb_type_annotation,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Error out if this is not a primitive pb_type */
|
||||
if (false == is_primitive_pb_type(primitive_pb_type)) {
|
||||
VTR_LOG_ERROR("Mode selection is only applicable to primitive pb_type while pb_type '%s' is not primitve !\n",
|
||||
primitive_pb_type->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update the annotation */
|
||||
vpr_pb_type_annotation.add_pb_type_mode_bits(primitive_pb_type, pb_type_annotation.mode_bits());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will link
|
||||
* - pb_type to mode bits by following
|
||||
* the explicit definition in OpenFPGA architecture XML
|
||||
*
|
||||
* Note:
|
||||
* - This function should be executed only AFTER
|
||||
* the physical mode and physical pb_type annotation is completed
|
||||
* the physical pb_type circuit model annotation is completed
|
||||
*******************************************************************/
|
||||
static
|
||||
void link_vpr_pb_type_to_mode_bits_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const Arch& openfpga_arch,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Walk through the pb_type annotation stored in the openfpga arch */
|
||||
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
||||
if (true == pb_type_annotation.mode_bits().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Convert the vector of integer to string */
|
||||
std::string mode_bits_str;
|
||||
for (const size_t& bit : pb_type_annotation.mode_bits()) {
|
||||
mode_bits_str += std::to_string(bit);
|
||||
}
|
||||
|
||||
/* Collect the information about the full hierarchy of physical pb_type to be annotated */
|
||||
std::vector<std::string> target_pb_type_names;
|
||||
std::vector<std::string> target_pb_mode_names;
|
||||
|
||||
if (true == pb_type_annotation.is_operating_pb_type()) {
|
||||
target_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
|
||||
target_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
|
||||
target_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
|
||||
}
|
||||
|
||||
if (true == pb_type_annotation.is_physical_pb_type()) {
|
||||
target_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
||||
target_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
||||
target_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
||||
}
|
||||
|
||||
/* We must have at least one pb_type in the list */
|
||||
VTR_ASSERT_SAFE(0 < target_pb_type_names.size());
|
||||
|
||||
/* Pb type information are located at the logic_block_types in the device context of VPR
|
||||
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
||||
*/
|
||||
bool link_success = false;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
||||
if (target_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
||||
continue;
|
||||
}
|
||||
/* Match the name in the top-level, we go further to search the operating as well as
|
||||
* physical pb_types in the graph */
|
||||
t_pb_type* target_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_pb_type_names,
|
||||
target_pb_mode_names);
|
||||
if (nullptr == target_pb_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only try to bind pb_type to circuit model when it is defined by users */
|
||||
if (true == link_primitive_pb_type_to_mode_bits(target_pb_type,
|
||||
pb_type_annotation, vpr_pb_type_annotation)) {
|
||||
/* Give a message */
|
||||
VTR_LOG("Bind physical pb_type '%s' to mode selection bits '%s'\n",
|
||||
target_pb_type->name,
|
||||
mode_bits_str.c_str());
|
||||
|
||||
link_success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == link_success) {
|
||||
/* Not found, error out! */
|
||||
VTR_LOG_ERROR("Unable to bind pb_type '%s' to mode_selection bits '%s'!\n",
|
||||
target_pb_type_names.back().c_str(),
|
||||
mode_bits_str.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function to link openfpga architecture to VPR, including:
|
||||
* - physical pb_type
|
||||
|
@ -940,6 +966,8 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
|
|||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
|
||||
/* Annotate physical mode to pb_type in the VPR pb_type graph */
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation for physical modes in pb_type...\n");
|
||||
build_vpr_physical_pb_mode_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||
vpr_pb_type_annotation);
|
||||
|
||||
|
@ -953,10 +981,15 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
|
|||
* Must run AFTER physical mode annotation is done and
|
||||
* BEFORE inferring the circuit model for interconnect
|
||||
*/
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation about physical types for pb_type interconnection...");
|
||||
annotate_pb_graph_interconnect_physical_type(vpr_device_ctx,
|
||||
vpr_pb_type_annotation);
|
||||
VTR_LOG("Done\n");
|
||||
|
||||
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph */
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation between operating and physical pb_types...\n");
|
||||
build_vpr_physical_pb_type_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||
vpr_pb_type_annotation);
|
||||
|
||||
|
@ -970,15 +1003,24 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
|
|||
* - physical pb_type to circuit model
|
||||
* - interconnect of physical pb_type to circuit model
|
||||
*/
|
||||
/* TODO: link the pb_type port to circuit model port here! */
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation between physical pb_types and circuit models...\n");
|
||||
link_vpr_pb_type_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||
vpr_pb_type_annotation);
|
||||
link_vpr_pb_interconnect_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||
vpr_pb_type_annotation);
|
||||
link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(vpr_device_ctx, openfpga_arch.circuit_lib,
|
||||
vpr_pb_type_annotation);
|
||||
check_vpr_pb_type_circuit_model_annotation(vpr_device_ctx, openfpga_arch.circuit_lib,
|
||||
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
|
||||
|
||||
/* Link physical pb_type to mode_bits */
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation between physical pb_types and mode selection bits...\n");
|
||||
link_vpr_pb_type_to_mode_bits_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||
vpr_pb_type_annotation);
|
||||
check_vpr_pb_type_mode_bits_annotation(vpr_device_ctx, openfpga_arch.circuit_lib,
|
||||
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
/********************************************************************
|
||||
* This file includes functions to build links between pb_types
|
||||
* in particular to annotate the physical mode and physical pb_type
|
||||
*******************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_time.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "pb_type_utils.h"
|
||||
#include "circuit_library_utils.h"
|
||||
#include "check_pb_type_annotation.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse pb_type graph to ensure
|
||||
* 1. there is only a physical mode under each pb_type
|
||||
* 2. physical mode appears only when its parent is a physical mode.
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
||||
const bool& expect_physical_mode,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* We do not check any primitive pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* For non-primitive pb_type:
|
||||
* - If we expect a physical mode to exist under this pb_type
|
||||
* we should be able to find one in the annoation
|
||||
* - If we do NOT expect a physical mode, make sure we find
|
||||
* nothing in the annotation
|
||||
*/
|
||||
if (true == expect_physical_mode) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
||||
cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == expect_physical_mode);
|
||||
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
|
||||
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
|
||||
cur_pb_type->name);
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traverse all the modes
|
||||
* - for pb_type children under a physical mode, we expect an physical mode
|
||||
* - for pb_type children under non-physical mode, we expect no physical mode
|
||||
*/
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||
bool expect_child_physical_mode = false;
|
||||
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||
expect_child_physical_mode = true && expect_physical_mode;
|
||||
}
|
||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||
expect_child_physical_mode, vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the physical mode annotation for
|
||||
* each pb_type in the device
|
||||
*******************************************************************/
|
||||
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
|
||||
} else {
|
||||
VTR_LOG_ERROR("Check physical mode annotation for pb_types failed with %ld errors!\n",
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check
|
||||
* - if a primitive pb_type has been mapped to a physical pb_type
|
||||
* - if every port of the pb_type have been linked a port of a physical pb_type
|
||||
*******************************************************************/
|
||||
static
|
||||
void check_vpr_physical_primitive_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Find a pb_type '%s' which has not been mapped to any physical pb_type!\n",
|
||||
cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we need to check each port of the pb_type */
|
||||
for (t_port* pb_port : pb_type_ports(cur_pb_type)) {
|
||||
if (nullptr == vpr_pb_type_annotation.physical_pb_port(pb_port)) {
|
||||
VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n",
|
||||
pb_port->name, cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse pb_type graph to ensure
|
||||
* 1. there is only a physical mode under each pb_type
|
||||
* 2. physical mode appears only when its parent is a physical mode.
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* Primitive pb_type should always been binded to a physical pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
check_vpr_physical_primitive_pb_type_annotation(cur_pb_type, vpr_pb_type_annotation, num_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Traverse all the modes */
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_physical_pb_type_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||
vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the physical pb_type annotation for
|
||||
* each pb_type in the device
|
||||
* Every pb_type should have been linked to a physical pb_type
|
||||
* and every port of the pb_type have been linked a port of a physical pb_type
|
||||
*******************************************************************/
|
||||
void check_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check physical pb_type annotation for pb_types passed.\n");
|
||||
} else {
|
||||
VTR_LOG_ERROR("Check physical pb_type annotation for pb_types failed with %ld errors!\n",
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse only the physical mode
|
||||
* and physical pb_types in the graph to ensure
|
||||
* - Every physical pb_type should be linked to a valid circuit model
|
||||
* - Every port of the pb_type have been linked to a valid port of a circuit model
|
||||
* - Every interconnect has been linked to a valid circuit model
|
||||
* in a correct type
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_pb_type_circuit_model_annotation(t_pb_type* cur_pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* Primitive pb_type should always been binded to a physical pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
/* Every physical pb_type should be linked to a valid circuit model */
|
||||
if (CircuitModelId::INVALID() == vpr_pb_type_annotation.pb_type_circuit_model(cur_pb_type)) {
|
||||
VTR_LOG_ERROR("Found a physical pb_type '%s' missing circuit model binding!\n",
|
||||
cur_pb_type->name);
|
||||
num_err++;
|
||||
return; /* Invalid id already, further check is not applicable */
|
||||
}
|
||||
/* Every port of the pb_type have been linked to a valid port of a circuit model */
|
||||
for (t_port* port : pb_type_ports(cur_pb_type)) {
|
||||
if (CircuitPortId::INVALID() == vpr_pb_type_annotation.pb_circuit_port(port)) {
|
||||
VTR_LOG_ERROR("Found a port '%s' of physical pb_type '%s' missing circuit port binding!\n",
|
||||
port->name, cur_pb_type->name);
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Every interconnect in the physical mode has been linked to a valid circuit model in a correct type */
|
||||
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
|
||||
for (t_interconnect* interc : pb_mode_interconnects(physical_mode)) {
|
||||
CircuitModelId interc_circuit_model = vpr_pb_type_annotation.interconnect_circuit_model(interc);
|
||||
if (CircuitModelId::INVALID() == interc_circuit_model) {
|
||||
VTR_LOG_ERROR("Found an interconnect '%s' under physical mode '%s' of pb_type '%s' missing circuit model binding!\n",
|
||||
interc->name,
|
||||
physical_mode->name,
|
||||
cur_pb_type->name);
|
||||
num_err++;
|
||||
continue;
|
||||
}
|
||||
e_circuit_model_type required_circuit_model_type = pb_interconnect_require_circuit_model_type(vpr_pb_type_annotation.interconnect_physical_type(interc));
|
||||
if (circuit_lib.model_type(interc_circuit_model) != required_circuit_model_type) {
|
||||
VTR_LOG_ERROR("Found an interconnect '%s' under physical mode '%s' of pb_type '%s' linked to a circuit model '%s' with a wrong type!\nExpect: '%s' Linked: '%s'\n",
|
||||
interc->name,
|
||||
physical_mode->name,
|
||||
cur_pb_type->name,
|
||||
circuit_lib.model_name(interc_circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_TYPE_STRING[circuit_lib.model_type(interc_circuit_model)],
|
||||
CIRCUIT_MODEL_TYPE_STRING[required_circuit_model_type]);
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traverse only the physical mode */
|
||||
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_pb_type_circuit_model_annotation(&(physical_mode->pb_type_children[ichild]),
|
||||
circuit_lib,
|
||||
vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the circuit model annotation for
|
||||
* each physical pb_type in the device
|
||||
* - Every physical pb_type should be linked to a valid circuit model
|
||||
* - Every port of the pb_type have been linked a valid port of a circuit model
|
||||
* - Every interconnect has been linked to a valid circuit model
|
||||
* in a correct type
|
||||
*******************************************************************/
|
||||
void check_vpr_pb_type_circuit_model_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_pb_type_circuit_model_annotation(lb_type.pb_type, circuit_lib, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check physical pb_type annotation for circuit model passed.\n");
|
||||
} else {
|
||||
VTR_LOG_ERROR("Check physical pb_type annotation for circuit model failed with %ld errors!\n",
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively traverse all the primitive pb_types
|
||||
* in the graph to ensure
|
||||
* - If a primitive pb_type has mode bits, it must have been linked to a physical pb_type
|
||||
* and the circuit model must have a port for mode selection.
|
||||
* And the port size must match the length of mode bits
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_check_vpr_pb_type_mode_bits_annotation(t_pb_type* cur_pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||
size_t& num_err) {
|
||||
/* Primitive pb_type should always been binded to a physical pb_type */
|
||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||
/* Find the physical pb_type
|
||||
* If the physical pb_type has mode selection bits, this pb_type must have as well!
|
||||
*/
|
||||
t_pb_type* physical_pb_type = vpr_pb_type_annotation.physical_pb_type(cur_pb_type);
|
||||
|
||||
if (nullptr == physical_pb_type) {
|
||||
VTR_LOG_ERROR("Find a pb_type '%s' which has not been mapped to any physical pb_type!\n",
|
||||
cur_pb_type->name);
|
||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (vpr_pb_type_annotation.pb_type_mode_bits(cur_pb_type).size() != vpr_pb_type_annotation.pb_type_mode_bits(physical_pb_type).size()) {
|
||||
VTR_LOG_ERROR("Found different sizes of mode_bits for pb_type '%s' and its physical pb_type '%s'\n",
|
||||
cur_pb_type->name,
|
||||
physical_pb_type->name);
|
||||
num_err++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to find a mode selection port for the circuit model linked to the circuit model */
|
||||
CircuitModelId circuit_model = vpr_pb_type_annotation.pb_type_circuit_model(physical_pb_type);
|
||||
if (CircuitModelId::INVALID() == vpr_pb_type_annotation.pb_type_circuit_model(physical_pb_type)) {
|
||||
VTR_LOG_ERROR("Found a physical pb_type '%s' missing circuit model binding!\n",
|
||||
physical_pb_type->name);
|
||||
num_err++;
|
||||
return; /* Invalid id already, further check is not applicable */
|
||||
}
|
||||
|
||||
if (0 == vpr_pb_type_annotation.pb_type_mode_bits(cur_pb_type).size()) {
|
||||
/* No mode bits to be checked! */
|
||||
return;
|
||||
}
|
||||
/* Search the ports of this circuit model and we must have a mode selection port */
|
||||
std::vector<CircuitPortId> mode_select_ports = find_circuit_mode_select_sram_ports(circuit_lib, circuit_model);
|
||||
size_t port_num_mode_bits = 0;
|
||||
for (const CircuitPortId& mode_select_port : mode_select_ports) {
|
||||
port_num_mode_bits += circuit_lib.port_size(mode_select_port);
|
||||
}
|
||||
if (port_num_mode_bits != vpr_pb_type_annotation.pb_type_mode_bits(cur_pb_type).size()) {
|
||||
VTR_LOG_ERROR("Length of mode bits of pb_type '%s' does not match the size(%ld) of mode selection ports of circuit model '%s'!\n",
|
||||
cur_pb_type->name,
|
||||
port_num_mode_bits,
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Traverse all the modes */
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||
rec_check_vpr_pb_type_mode_bits_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||
circuit_lib, vpr_pb_type_annotation,
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will check the mode_bits annotation for each pb_type
|
||||
* - If a primitive pb_type has mode bits, it must have been linked to a physical pb_type
|
||||
* - If a primitive pb_type has mode bits, the circuit model must have
|
||||
* a port for mode selection. And the port size must match the length of mode bits
|
||||
*
|
||||
* Note:
|
||||
* - This function should be run after circuit mode and mode bits annotation
|
||||
* is completed
|
||||
*******************************************************************/
|
||||
void check_vpr_pb_type_mode_bits_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||
/* By pass nullptr for pb_type head */
|
||||
if (nullptr == lb_type.pb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Top pb_type should always has a physical mode! */
|
||||
rec_check_vpr_pb_type_mode_bits_annotation(lb_type.pb_type, circuit_lib, vpr_pb_type_annotation, num_err);
|
||||
}
|
||||
if (0 == num_err) {
|
||||
VTR_LOG("Check pb_type annotation for mode selection bits passed.\n");
|
||||
} else {
|
||||
VTR_LOG_ERROR("Check physical pb_type annotation for mode selection bits failed with %ld errors!\n",
|
||||
num_err);
|
||||
}
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef CHECK_PB_TYPE_ANNOTATION_H
|
||||
#define CHECK_PB_TYPE_ANNOTATION_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "vpr_context.h"
|
||||
#include "openfpga_context.h"
|
||||
#include "vpr_pb_type_annotation.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
void check_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
void check_vpr_pb_type_circuit_model_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
void check_vpr_pb_type_mode_bits_annotation(const DeviceContext& vpr_device_ctx,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -89,12 +89,32 @@ e_interconnect VprPbTypeAnnotation::interconnect_physical_type(t_interconnect* p
|
|||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
|
||||
if (it == interconnect_physical_types_.end()) {
|
||||
/* Return an invalid circuit model id */
|
||||
/* Return an invalid interconnect type */
|
||||
return NUM_INTERC_TYPES;
|
||||
}
|
||||
return interconnect_physical_types_.at(pb_interconnect);
|
||||
}
|
||||
|
||||
CircuitPortId VprPbTypeAnnotation::pb_circuit_port(t_port* pb_port) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_port*, CircuitPortId>::const_iterator it = pb_circuit_ports_.find(pb_port);
|
||||
if (it == pb_circuit_ports_.end()) {
|
||||
/* Return an invalid circuit port id */
|
||||
return CircuitPortId::INVALID();
|
||||
}
|
||||
return pb_circuit_ports_.at(pb_port);
|
||||
}
|
||||
|
||||
std::vector<size_t> VprPbTypeAnnotation::pb_type_mode_bits(t_pb_type* pb_type) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_type*, std::vector<size_t>>::const_iterator it = pb_type_mode_bits_.find(pb_type);
|
||||
if (it == pb_type_mode_bits_.end()) {
|
||||
/* Return an empty vector */
|
||||
return std::vector<size_t>();
|
||||
}
|
||||
return pb_type_mode_bits_.at(pb_type);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public mutators
|
||||
***********************************************************************/
|
||||
|
@ -179,4 +199,26 @@ void VprPbTypeAnnotation::add_interconnect_physical_type(t_interconnect* pb_inte
|
|||
interconnect_physical_types_[pb_interconnect] = physical_type;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_pb_circuit_port(t_port* pb_port, const CircuitPortId& circuit_port) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_port*, CircuitPortId>::const_iterator it = pb_circuit_ports_.find(pb_port);
|
||||
if (it != pb_circuit_ports_.end()) {
|
||||
VTR_LOG_WARN("Override the circuit port mapping for pb_type port '%s'!\n",
|
||||
pb_port->name);
|
||||
}
|
||||
|
||||
pb_circuit_ports_[pb_port] = circuit_port;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_pb_type_mode_bits(t_pb_type* pb_type, const std::vector<size_t>& mode_bits) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_pb_type*, std::vector<size_t>>::const_iterator it = pb_type_mode_bits_.find(pb_type);
|
||||
if (it != pb_type_mode_bits_.end()) {
|
||||
VTR_LOG_WARN("Override the mode bits mapping for pb_type '%s'!\n",
|
||||
pb_type->name);
|
||||
}
|
||||
|
||||
pb_type_mode_bits_[pb_type] = mode_bits;
|
||||
}
|
||||
|
||||
} /* End namespace openfpga*/
|
||||
|
|
|
@ -37,6 +37,8 @@ class VprPbTypeAnnotation {
|
|||
CircuitModelId pb_type_circuit_model(t_pb_type* physical_pb_type) const;
|
||||
CircuitModelId interconnect_circuit_model(t_interconnect* pb_interconnect) const;
|
||||
e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) const;
|
||||
CircuitPortId pb_circuit_port(t_port* pb_port) const;
|
||||
std::vector<size_t> pb_type_mode_bits(t_pb_type* pb_type) 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);
|
||||
|
@ -45,6 +47,8 @@ class VprPbTypeAnnotation {
|
|||
void add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model);
|
||||
void add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model);
|
||||
void add_interconnect_physical_type(t_interconnect* pb_interconnect, const e_interconnect& physical_type);
|
||||
void add_pb_circuit_port(t_port* pb_port, const CircuitPortId& circuit_port);
|
||||
void add_pb_type_mode_bits(t_pb_type* pb_type, const std::vector<size_t>& mode_bits);
|
||||
private: /* Internal data */
|
||||
/* Pair a regular pb_type to its physical pb_type */
|
||||
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
|
||||
|
@ -80,7 +84,7 @@ class VprPbTypeAnnotation {
|
|||
* - if the pb_type is an operating pb_type, the mode bits will be applied
|
||||
* when the operating pb_type is used by packer
|
||||
*/
|
||||
std::map<t_pb_type*, std::vector<bool>> pb_type_mode_bits_;
|
||||
std::map<t_pb_type*, std::vector<size_t>> pb_type_mode_bits_;
|
||||
|
||||
/* Pair a pb_port to its physical pb_port
|
||||
* Note:
|
||||
|
@ -94,6 +98,12 @@ class VprPbTypeAnnotation {
|
|||
*/
|
||||
std::map<t_port*, BasicPort> physical_pb_port_ranges_;
|
||||
|
||||
/* Pair a pb_port to a circuit port in circuit model
|
||||
* Note:
|
||||
* - the parent of physical pb_port MUST be a physical pb_type
|
||||
*/
|
||||
std::map<t_port*, CircuitPortId> pb_circuit_ports_;
|
||||
|
||||
/* Pair a pb_graph_node to a physical pb_graph_node
|
||||
* Note:
|
||||
* - the pb_type of physical pb_graph_node must be a physical pb_type
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
/************************************************************************
|
||||
* Function to perform fundamental operation for the circuit library
|
||||
* These functions are not universal methods for the CircuitLibrary class
|
||||
* They are made to ease the development in some specific purposes
|
||||
* Please classify such functions in this file
|
||||
***********************************************************************/
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtr util library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "circuit_library_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Get the model id of a SRAM model that is used to configure
|
||||
* a circuit model
|
||||
*******************************************************************/
|
||||
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* SRAM model id is stored in the sram ports of a circuit model */
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM);
|
||||
std::vector<CircuitModelId> sram_models;
|
||||
|
||||
/* Create a list of sram models, but avoid duplicated model ids */
|
||||
for (const auto& sram_port : sram_ports) {
|
||||
CircuitModelId sram_model = circuit_lib.port_tri_state_model(sram_port);
|
||||
VTR_ASSERT( true == circuit_lib.valid_model_id(sram_model) );
|
||||
if (sram_models.end() != std::find(sram_models.begin(), sram_models.end(), sram_model)) {
|
||||
continue; /* Already in the list, skip the addition */
|
||||
}
|
||||
/* Not in the list, add it */
|
||||
sram_models.push_back(sram_model);
|
||||
}
|
||||
|
||||
return sram_models;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find regular (not mode select) sram ports of a circuit model
|
||||
*******************************************************************/
|
||||
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM, true);
|
||||
std::vector<CircuitPortId> regular_sram_ports;
|
||||
|
||||
for (const auto& port : sram_ports) {
|
||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||
continue;
|
||||
}
|
||||
regular_sram_ports.push_back(port);
|
||||
}
|
||||
|
||||
return regular_sram_ports;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find mode select sram ports of a circuit model
|
||||
*******************************************************************/
|
||||
std::vector<CircuitPortId> find_circuit_mode_select_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM, true);
|
||||
std::vector<CircuitPortId> mode_select_sram_ports;
|
||||
|
||||
for (const auto& port : sram_ports) {
|
||||
if (false == circuit_lib.port_is_mode_select(port)) {
|
||||
continue;
|
||||
}
|
||||
mode_select_sram_ports.push_back(port);
|
||||
}
|
||||
|
||||
return mode_select_sram_ports;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Find the number of shared configuration bits for a ReRAM circuit
|
||||
* TODO: this function is subjected to be changed due to ReRAM-based SRAM cell design!!!
|
||||
*******************************************************************/
|
||||
static
|
||||
size_t find_rram_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& rram_model,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
size_t num_shared_config_bits = 0;
|
||||
|
||||
/* Branch on the organization of configuration protocol */
|
||||
switch (config_protocol_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
/* Find BL/WL ports */
|
||||
std::vector<CircuitPortId> blb_ports = circuit_lib.model_ports_by_type(rram_model, CIRCUIT_MODEL_PORT_BLB);
|
||||
for (auto blb_port : blb_ports) {
|
||||
num_shared_config_bits = std::max((int)num_shared_config_bits, (int)circuit_lib.port_size(blb_port) - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VTR_LOG_ERROR("Invalid type of configuration protocol!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return num_shared_config_bits;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A generic function to find the number of shared configuration bits
|
||||
* for circuit model
|
||||
* It will return 0 for CMOS circuits
|
||||
* It will return the maximum shared configuration bits across ReRAM models
|
||||
*
|
||||
* Note: This function may give WRONG results when all the SRAM ports
|
||||
* are not properly linked to its circuit models!
|
||||
* So, it should be called after the SRAM linking is done!!!
|
||||
*
|
||||
* IMPORTANT: This function should NOT be used to find the number of shared configuration bits
|
||||
* for a multiplexer, because the multiplexer size is determined during
|
||||
* the FPGA architecture generation (NOT during the XML parsing).
|
||||
*******************************************************************/
|
||||
size_t find_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
size_t num_shared_config_bits = 0;
|
||||
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM);
|
||||
for (auto sram_port : sram_ports) {
|
||||
CircuitModelId sram_model = circuit_lib.port_tri_state_model(sram_port);
|
||||
VTR_ASSERT( true == circuit_lib.valid_model_id(sram_model) );
|
||||
|
||||
/* Depend on the design technolgy of SRAM model, the number of configuration bits will be different */
|
||||
switch (circuit_lib.design_tech_type(sram_model)) {
|
||||
case CIRCUIT_MODEL_DESIGN_CMOS:
|
||||
/* CMOS circuit do not need shared configuration bits */
|
||||
break;
|
||||
case CIRCUIT_MODEL_DESIGN_RRAM:
|
||||
/* RRAM circuit do need shared configuration bits, but it is subjected to the largest one among different SRAM models */
|
||||
num_shared_config_bits = std::max((int)num_shared_config_bits, (int)find_rram_circuit_num_shared_config_bits(circuit_lib, sram_model, config_protocol_type));
|
||||
break;
|
||||
default:
|
||||
VTR_LOG_ERROR("Invalid design technology for SRAM circuit model!\n",
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return num_shared_config_bits;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A generic function to find the number of configuration bits
|
||||
* for circuit model
|
||||
* It will sum up the sizes of all the sram ports
|
||||
*
|
||||
* IMPORTANT: This function should NOT be used to find the number of configuration bits
|
||||
* for a multiplexer, because the multiplexer size is determined during
|
||||
* the FPGA architecture generation (NOT during the XML parsing).
|
||||
*******************************************************************/
|
||||
size_t find_circuit_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
size_t num_config_bits = 0;
|
||||
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_SRAM);
|
||||
for (auto sram_port : sram_ports) {
|
||||
num_config_bits += circuit_lib.port_size(sram_port);
|
||||
}
|
||||
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A generic function to find all the global ports in a circuit library
|
||||
*
|
||||
* IMPORTANT: This function will uniquify the global ports whose share
|
||||
* share the same name !!!
|
||||
*******************************************************************/
|
||||
std::vector<CircuitPortId> find_circuit_library_global_ports(const CircuitLibrary& circuit_lib) {
|
||||
std::vector<CircuitPortId> global_ports;
|
||||
|
||||
for (auto port : circuit_lib.ports()) {
|
||||
/* By pass non-global ports*/
|
||||
if (false == circuit_lib.port_is_global(port)) {
|
||||
continue;
|
||||
}
|
||||
/* Check if a same port with the same name has already been in the list */
|
||||
bool add_to_list = true;
|
||||
for (const auto& global_port : global_ports) {
|
||||
if (0 == circuit_lib.port_prefix(port).compare(circuit_lib.port_prefix(global_port))) {
|
||||
/* Same name, skip list update */
|
||||
add_to_list = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (true == add_to_list) {
|
||||
/* Add the global_port to the list */
|
||||
global_ports.push_back(port);
|
||||
}
|
||||
}
|
||||
|
||||
return global_ports;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A generic function to find all the unique user-defined
|
||||
* Verilog netlists in a circuit library
|
||||
* Netlists with same names will be considered as one
|
||||
*******************************************************************/
|
||||
std::vector<std::string> find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib) {
|
||||
std::vector<std::string> netlists;
|
||||
|
||||
for (const CircuitModelId& model : circuit_lib.models()) {
|
||||
/* Skip empty netlist names */
|
||||
if (true == circuit_lib.model_verilog_netlist(model).empty()) {
|
||||
continue;
|
||||
}
|
||||
/* See if the netlist name is already in the list */
|
||||
std::vector<std::string>::iterator it = std::find(netlists.begin(), netlists.end(), circuit_lib.model_verilog_netlist(model));
|
||||
if (it == netlists.end()) {
|
||||
netlists.push_back(circuit_lib.model_verilog_netlist(model));
|
||||
}
|
||||
}
|
||||
|
||||
return netlists;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,44 @@
|
|||
/********************************************************************
|
||||
* Header file for circuit_library_utils.cpp
|
||||
*******************************************************************/
|
||||
#ifndef CIRCUIT_LIBRARY_UTILS_H
|
||||
#define CIRCUIT_LIBRARY_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
|
||||
#include <vector>
|
||||
#include "circuit_types.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
std::vector<CircuitPortId> find_circuit_mode_select_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t find_circuit_num_shared_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const e_config_protocol_type& sram_orgz_type);
|
||||
|
||||
size_t find_circuit_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
std::vector<CircuitPortId> find_circuit_library_global_ports(const CircuitLibrary& circuit_lib);
|
||||
|
||||
std::vector<std::string> find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -228,4 +228,30 @@ e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_intercon
|
|||
return type_mapping.at(pb_interc_type);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function aims to find the required type for a pb_port
|
||||
* when it is linked to a port of a circuit model
|
||||
* We start from the view of a circuit port here.
|
||||
* This is due to circuit port has more types than a pb_type port
|
||||
* as it is designed for physical implementation
|
||||
* As such, a few types of circuit port may be directed the same type of pb_type port
|
||||
* This is done to make the mapping much simpler than doing in the opposite direction
|
||||
*******************************************************************/
|
||||
enum PORTS circuit_port_require_pb_port_type(const e_circuit_model_port_type& circuit_port_type) {
|
||||
std::map<e_circuit_model_port_type, enum PORTS> type_mapping;
|
||||
|
||||
/* These circuit model ports may be founed in the pb_type ports */
|
||||
type_mapping[CIRCUIT_MODEL_PORT_INPUT] = IN_PORT;
|
||||
type_mapping[CIRCUIT_MODEL_PORT_OUTPUT] = OUT_PORT;
|
||||
type_mapping[CIRCUIT_MODEL_PORT_INOUT] = INOUT_PORT;
|
||||
type_mapping[CIRCUIT_MODEL_PORT_CLOCK] = IN_PORT;
|
||||
|
||||
/* Other circuit model ports should not be found when mapping to the pb_type ports */
|
||||
if (type_mapping.end() == type_mapping.find(circuit_port_type)) {
|
||||
return ERR_PORT;
|
||||
}
|
||||
|
||||
return type_mapping.at(circuit_port_type);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -41,6 +41,8 @@ e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
|
|||
|
||||
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type);
|
||||
|
||||
enum PORTS circuit_port_require_pb_port_type(const e_circuit_model_port_type& circuit_port_type);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue