Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-01-26 15:55:42 -07:00
commit de38e8ecd9
15 changed files with 1092 additions and 23 deletions

View File

@ -265,24 +265,54 @@
<routing_segment>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<!--direct_connection>
<direct_connection>
<direct name="adder" circuit_model_name="direct_interc"/>
</direct_connection-->
<complex_blocks>
<pb_type name="io" physical_mode_name="io_phy"/>
<mode name="io[io_phy]" disable_in_packing="true"/>
</direct_connection>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="io_phy" idle_mode_name="inpad"/>
<pb_type name="io[io_phy].iopad" circuit_model_name="iopad" mode_bits="1"/>
<pb_type name="io[io_phy].inpad" physical_pb_type_name="iopad" mode_bits="1"/>
<pb_type name="io[io_phy].outpad" physical_pb_type_name="iopad" mode_bits="0"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar0" circuit_model_name="mux_2level"/>
<interconnect name="crossbar1" circuit_model_name="mux_2level"/>
<interconnect name="crossbar2" circuit_model_name="mux_2level"/>
<interconnect name="crossbar3" circuit_model_name="mux_2level"/>
<interconnect name="crossbar4" circuit_model_name="mux_2level"/>
<interconnect name="crossbar5" circuit_model_name="mux_2level"/>
</pb_type>
<pb_type name="clb.fle" physical_mode_name="fle_phy" idle_mode_name="n2_lut5"/>
<pb_type name="clb.fle[fle_phy].frac_logic.frac_lut6" mode_bits="11" circuit_model_name="frac_lut6"/>
<pb_type name="clb.fle[fle_phy].frac_logic.adder_phy" circuit_model_name="adder"/>
<pb_type name="clb.fle[fle_phy].frac_logic.ff_phy" circuit_model_name="static_dff"/>
<mode name="fle_phy" disabled_in_packing="true"/>
<pb_type name="lut5" mode_bits="01" physical_pb_type_name="frac_lut6" physical_pb_type_index_factor="0.5"/>
<input name="in" physical_mode_pin="in[5:0]"/>
<output name="out" physical_mode_pin="lut5_out" physical_mode_pin_rotate_offset="1"/>
</complex_blocks>
<pb_type name="clb.fle[n2_lut5].lut5_inter.ble5[blut5].flut5.lut5" mode_bits="01" physical_pb_type_name="clb.fle[fle_phy].frac_logic.frac_lut6" physical_pb_type_index_factor="0.5">
<!-- If not specified, we by default assume the physical mode pin share the same name -->
<port name="in" physical_mode_port="in[4:0]"/>
<port name="out" physical_mode_port="lut5_out" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut5].lut5_inter.ble5[blut5].flut5.ff" physical_pb_type_name="clb.fle[fle_phy].frac_logic.ff_phy"/>
<pb_type name="clb.fle[n2_lut5].lut5_inter.ble5[arithmetic].arithemetic.lut4" mode_bits="11" physical_pb_type_name="clb.fle[fle_phy].frac_logic.frac_lut6">
<!-- If not specified, we by default assume the physical mode pin share the same name -->
<port name="in" physical_mode_port="in[3:0]"/>
<port name="out" physical_mode_port="lut4_out" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut5].lut5_inter.ble5[arithmetic].arithemetic.adder" physical_pb_type_name="clb.fle[fle_phy].frac_logic.adder_phy"/>
<pb_type name="clb.fle[n2_lut5].lut5_inter.ble5[arithmetic].arithemetic.ff" physical_pb_type_name="clb.fle[fle_phy].frac_logic.ff_phy"/>
<pb_type name="clb.fle[n1_lut6].ble6.lut6" mode_bits="00" physical_pb_type_name="clb.fle[fle_phy].frac_logic.frac_lut6">
<!-- If not specified, we by default assume the physical mode pin share the same name -->
<port name="in" physical_mode_port="in[5:0]"/>
<port name="out" physical_mode_port="lut6_out"/>
</pb_type>
<pb_type name="clb.fle[n1_lut6].ble6.ff" physical_pb_type_name="clb.fle[fle_phy].frac_logic.ff_phy" physical_pb_type_index_factor="2" physical_pb_type_index_offset="1"/>
<pb_type name="clb.fle[shift_register].ble6_shift.ff" physical_pb_type_name="clb.fle[fle_phy].frac_logic.ff_phy"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>
<openfpga_simulation_setting>
<clock_setting>

View File

@ -1,12 +1,14 @@
#ifndef OPENFPGA_ARCH_H
#define OPENFPGA_ARCH_H
#include <vector>
#include <map>
#include "circuit_library.h"
#include "technology_library.h"
#include "simulation_setting.h"
#include "config_protocol.h"
#include "pb_type_annotation.h"
/* namespace openfpga begins */
namespace openfpga {
@ -47,6 +49,12 @@ struct Arch {
* to circuit models in circuit library
*/
std::map<std::string, CircuitModelId> direct2circuit;
/* Pb type annotations
* Bind from operating to physical
* Bind from physical to circuit model
*/
std::vector<PbTypeAnnotation> pb_type_annotations;
};
} /* namespace openfpga ends */

View File

@ -0,0 +1,215 @@
/************************************************************************
* Member functions for class PbTypeAnnotation
***********************************************************************/
#include "vtr_log.h"
#include "vtr_assert.h"
#include "pb_type_annotation.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Constructors
***********************************************************************/
PbTypeAnnotation::PbTypeAnnotation() {
return;
}
/************************************************************************
* Public Accessors
***********************************************************************/
std::string PbTypeAnnotation::operating_pb_type_name() const {
return operating_pb_type_name_;
}
std::vector<std::string> PbTypeAnnotation::operating_parent_pb_type_names() const {
return operating_parent_pb_type_names_;
}
std::vector<std::string> PbTypeAnnotation::operating_parent_mode_names() const {
return operating_parent_mode_names_;
}
bool PbTypeAnnotation::is_operating_pb_type() const {
return (false == operating_pb_type_name_.empty())
&& (false == physical_pb_type_name_.empty());
}
std::string PbTypeAnnotation::physical_pb_type_name() const {
return physical_pb_type_name_;
}
std::vector<std::string> PbTypeAnnotation::physical_parent_pb_type_names() const {
return physical_parent_pb_type_names_;
}
std::vector<std::string> PbTypeAnnotation::physical_parent_mode_names() const {
return physical_parent_mode_names_;
}
bool PbTypeAnnotation::is_physical_pb_type() const {
return (true == operating_pb_type_name_.empty())
&& (false == physical_pb_type_name_.empty());
}
std::string PbTypeAnnotation::physical_mode_name() const {
return physical_mode_name_;
}
std::string PbTypeAnnotation::idle_mode_name() const {
return idle_mode_name_;
}
std::string PbTypeAnnotation::mode_bits() const {
return mode_bits_;
}
std::string PbTypeAnnotation::circuit_model_name() const {
return circuit_model_name_;
}
int PbTypeAnnotation::physical_pb_type_index_factor() const {
return physical_pb_type_index_factor_;
}
int PbTypeAnnotation::physical_pb_type_index_offset() const {
return physical_pb_type_index_offset_;
}
std::vector<std::string> PbTypeAnnotation::port_names() const {
std::vector<std::string> keys;
for (auto const& element : operating_pb_type_ports_) {
keys.push_back(element.first);
}
return keys;
}
BasicPort PbTypeAnnotation::physical_pb_type_port(const std::string& port_name) const {
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(port_name);
if (it == operating_pb_type_ports_.end()) {
/* Return an empty port */
return BasicPort();
}
return operating_pb_type_ports_.at(port_name);
}
int PbTypeAnnotation::physical_pin_rotate_offset(const std::string& port_name) const {
std::map<std::string, int>::const_iterator it = physical_pin_rotate_offsets_.find(port_name);
if (it == physical_pin_rotate_offsets_.end()) {
/* Return a zero offset which is default */
return 0;
}
return physical_pin_rotate_offsets_.at(port_name);
}
std::vector<std::string> PbTypeAnnotation::interconnect_names() const {
std::vector<std::string> keys;
for (auto const& element : interconnect_circuit_model_names_) {
keys.push_back(element.first);
}
return keys;
}
std::string PbTypeAnnotation::interconnect_circuit_model_name(const std::string& interc_name) const {
std::map<std::string, std::string>::const_iterator it = interconnect_circuit_model_names_.find(interc_name);
if (it == interconnect_circuit_model_names_.end()) {
return std::string();
}
return interconnect_circuit_model_names_.at(interc_name);
}
/************************************************************************
* Public Mutators
***********************************************************************/
void PbTypeAnnotation::set_operating_pb_type_name(const std::string& name) {
operating_pb_type_name_ = name;
}
void PbTypeAnnotation::set_operating_parent_pb_type_names(const std::vector<std::string>& names) {
operating_parent_pb_type_names_ = names;
}
void PbTypeAnnotation::set_operating_parent_mode_names(const std::vector<std::string>& names) {
operating_parent_mode_names_ = names;
}
void PbTypeAnnotation::set_physical_pb_type_name(const std::string& name) {
physical_pb_type_name_ = name;
}
void PbTypeAnnotation::set_physical_parent_pb_type_names(const std::vector<std::string>& names) {
physical_parent_pb_type_names_ = names;
}
void PbTypeAnnotation::set_physical_parent_mode_names(const std::vector<std::string>& names) {
physical_parent_mode_names_ = names;
}
void PbTypeAnnotation::set_physical_mode_name(const std::string& name) {
physical_mode_name_ = name;
}
void PbTypeAnnotation::set_idle_mode_name(const std::string& name) {
idle_mode_name_ = name;
}
void PbTypeAnnotation::set_mode_bits(const std::string& mode_bits) {
mode_bits_ = mode_bits;
}
void PbTypeAnnotation::set_circuit_model_name(const std::string& name) {
VTR_ASSERT(true == is_physical_pb_type());
circuit_model_name_ = name;
}
void PbTypeAnnotation::set_physical_pb_type_index_factor(const int& value) {
VTR_ASSERT(true == is_operating_pb_type());
physical_pb_type_index_factor_ = value;
}
void PbTypeAnnotation::set_physical_pb_type_index_offset(const int& value) {
VTR_ASSERT(true == is_operating_pb_type());
physical_pb_type_index_offset_ = value;
}
void PbTypeAnnotation::add_pb_type_port_pair(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port) {
/* Give a warning if the operating_pb_port_name already exist */
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
/* Give a warning if the interconnection name already exist */
if (it != operating_pb_type_ports_.end()) {
VTR_LOG_WARN("Redefine operating pb type port '%s' with physical pb type port '%s'\n",
operating_pb_port_name.c_str(), physical_pb_port.get_name().c_str());
}
operating_pb_type_ports_[operating_pb_port_name] = physical_pb_port;
}
void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const int& physical_pin_rotate_offset) {
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
/* Give a warning if the interconnection name already exist */
if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("Operating pb type port '%s' does not exist! Ignore physical pin rotate offset '%d'\n",
operating_pb_port_name.c_str(), physical_pin_rotate_offset);
return;
}
physical_pin_rotate_offsets_[operating_pb_port_name] = physical_pin_rotate_offset;
}
void PbTypeAnnotation::add_interconnect_circuit_model_pair(const std::string& interc_name,
const std::string& circuit_model_name) {
std::map<std::string, std::string>::const_iterator it = interconnect_circuit_model_names_.find(interc_name);
/* Give a warning if the interconnection name already exist */
if (it != interconnect_circuit_model_names_.end()) {
VTR_LOG_WARN("Redefine interconnect '%s' with circuit model '%s'\n",
interc_name.c_str(), circuit_model_name.c_str());
}
interconnect_circuit_model_names_[interc_name] = circuit_model_name;
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,160 @@
#ifndef PB_TYPE_ANNOTATION_H
#define PB_TYPE_ANNOTATION_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <vector>
#include <map>
#include "openfpga_port.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* This file include the declaration of data structures
* to store physical pb_type annotation, including
* 1. the binding between operating pb_type and physical_pb_type
* this also cover the binding between pins of any pair of pb_types
* 2. the binding between physical pb_type and circuit models
* 3. the binding between interconnect under pb_types and circuit models
* This is only applicable to physical pb_types
*
* Each PhysicalPbAnnotation includes the binding for ONLY a pb_type
* defined in the architecture XML
*
* Note:
* 1. Keep this data structure as general as possible. It is supposed
* to contain the raw data from architecture XML! If you want to link
* to other data structures, please create another one in other header files
*******************************************************************/
class PbTypeAnnotation {
public: /* Constructor */
PbTypeAnnotation();
public: /* Public accessors */
std::string operating_pb_type_name() const;
std::vector<std::string> operating_parent_pb_type_names() const;
std::vector<std::string> operating_parent_mode_names() const;
bool is_operating_pb_type() const;
std::string physical_pb_type_name() const;
std::vector<std::string> physical_parent_pb_type_names() const;
std::vector<std::string> physical_parent_mode_names() const;
bool is_physical_pb_type() const;
std::string physical_mode_name() const;
std::string idle_mode_name() const;
std::string mode_bits() const;
std::string circuit_model_name() const;
int physical_pb_type_index_factor() const;
int physical_pb_type_index_offset() const;
std::vector<std::string> port_names() const;
BasicPort physical_pb_type_port(const std::string& port_name) const;
int physical_pin_rotate_offset(const std::string& port_name) const;
std::vector<std::string> interconnect_names() const;
std::string interconnect_circuit_model_name(const std::string& interc_name) const;
public: /* Public mutators */
void set_operating_pb_type_name(const std::string& name);
void set_operating_parent_pb_type_names(const std::vector<std::string>& names);
void set_operating_parent_mode_names(const std::vector<std::string>& names);
void set_physical_pb_type_name(const std::string& name);
void set_physical_parent_pb_type_names(const std::vector<std::string>& names);
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_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);
void add_pb_type_port_pair(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port);
void set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const int& physical_pin_rotate_offset);
void add_interconnect_circuit_model_pair(const std::string& interc_name,
const std::string& circuit_model_name);
private: /* Internal data */
/* Binding between physical pb_type and operating pb_type
* both operating and physial pb_type names contain the full names
* defined in the hierarchy of pb_types
* e.g.
* clb.fle[frac_logic].frac_lut6
* ^
* |
* mode_name
*
* The pb_type name 'frac_lut6' will be stored in
* either operating or physical pb_type_name
* The parent pb_type and mode names will be stored in
* either operating or physical parent_pb_type_name and parent_mode_names
*
*/
std::string operating_pb_type_name_;
std::vector<std::string> operating_parent_pb_type_names_;
std::vector<std::string> operating_parent_mode_names_;
std::string physical_pb_type_name_;
std::vector<std::string> physical_parent_pb_type_names_;
std::vector<std::string> physical_parent_mode_names_;
/* Identify which mode is the physical implementation of an operating pb_type */
std::string physical_mode_name_;
/* Identify in which mode is the pb_type will operate when it is not used */
std::string idle_mode_name_;
/* Configuration bits to select an operting mode for the circuit mode name */
std::string mode_bits_;
/* Circuit mode name linked to a physical pb_type.
* This is only applicable to the physical pb_type
*/
std::string circuit_model_name_;
/* The factor aims to align the indices for pb_type between operating and physical modes,
* especially when an operating mode contains multiple pb_type (num_pb>1)
* that are linked to the same physical pb_type.
* When number of physical_pb_type is larger than 1,
* the index of pb_type will be multipled by the given factor.
*
* For example, a factor of 2 is used to map
* operating pb_type adder[5] with a full path clb.fle[arith].adder[5]
* to physical pb_type adder[10] with a full path clb.fle[physical].adder[10]
*/
int physical_pb_type_index_factor_;
/* The offset aims to align the indices for pb_type between operating and physical modes,
* especially when an operating mode contains multiple pb_type (num_pb>1)
* that are linked to the same physical pb_type.
* When number of physical_pb_type is larger than 1,
* the index of pb_type will be shifted by the given factor.
*
* For example, an offset of 1 is used to map
* operating pb_type adder[0] with a full path clb.fle[arith].adder[0]
* to physical pb_type adder[1] with a full path clb.fle[physical].adder[1]
*/
int physical_pb_type_index_offset_;
/* Link from the pins under an operating pb_type to physical pb_type */
std::map<std::string, BasicPort> operating_pb_type_ports_;
/* The offset aims to align the pin indices for port of pb_type
* between operating and physical modes, especially when an operating
* mode contains multiple pb_type (num_pb>1) that are linked to
* the same physical pb_type.
* When physical_mode_pin_rotate_offset is larger than zero,
* the pin index of pb_type (whose index is large than 1)
* will be shifted by the given offset.
*
* For example, an offset of 1 is used to map
* operating pb_type adder[0].pin[0] with a full path clb.fle[arith].adder[0]
* to physical pb_type adder[0].pin[1] with a full path clb.fle[physical].adder[0]
*/
std::map<std::string, int> physical_pin_rotate_offsets_;
/* Link between the interconnects under this pb_type and circuit model names */
std::map<std::string, std::string> interconnect_circuit_model_names_;
};
} /* namespace openfpga ends */
#endif

View File

@ -21,6 +21,7 @@
#include "read_xml_simulation_setting.h"
#include "read_xml_config_protocol.h"
#include "read_xml_routing_circuit.h"
#include "read_xml_pb_type_annotation.h"
#include "read_xml_openfpga_arch.h"
#include "openfpga_arch_linker.h"
@ -85,10 +86,13 @@ openfpga::Arch read_xml_openfpga_arch(const char* arch_file_name) {
openfpga_arch.routing_seg2circuit = read_xml_routing_segment_circuit(xml_openfpga_arch, loc_data,
openfpga_arch.circuit_lib);
/* Parse the routing segment circuit definition */
/* Parse the direct circuit definition */
openfpga_arch.direct2circuit = 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);
/* Second node should be <openfpga_simulation_setting> */
auto xml_simulation_settings = get_single_child(doc, "openfpga_simulation_setting", loc_data);

View File

@ -0,0 +1,190 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML modeling OpenFPGA architecture to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
/* Headers from openfpga util library */
#include "openfpga_port_parser.h"
#include "openfpga_pb_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "read_xml_pb_type_annotation.h"
/********************************************************************
* Parse XML description for an interconnection annotation
* under a <pb_type> XML node
*******************************************************************/
static
void read_xml_interc_annotation(pugi::xml_node& xml_interc,
const pugiutil::loc_data& loc_data,
openfpga::PbTypeAnnotation& pb_type_annotation) {
/* We have two mandatory XML attribute
* 1. name of the interconnect
* 2. circuit model name of the interconnect
*/
const std::string& name_attr = get_attribute(xml_interc, "name", loc_data).as_string();
const std::string& circuit_model_name_attr = get_attribute(xml_interc, "circuit_model_name", loc_data).as_string();
pb_type_annotation.add_interconnect_circuit_model_pair(name_attr, circuit_model_name_attr);
}
/********************************************************************
* Parse XML description for a pb_type port annotation
* under a <pb_type> XML node
*******************************************************************/
static
void read_xml_pb_port_annotation(pugi::xml_node& xml_port,
const pugiutil::loc_data& loc_data,
openfpga::PbTypeAnnotation& pb_type_annotation) {
/* We have two mandatory XML attribute
* 1. name of the port
* 2. name of the port to be binded in physical mode
*/
const std::string& name_attr = get_attribute(xml_port, "name", loc_data).as_string();
const std::string& physical_mode_port_attr = get_attribute(xml_port, "physical_mode_port", loc_data).as_string();
/* Parse the mode port using openfpga port parser */
openfpga::PortParser port_parser(physical_mode_port_attr);
pb_type_annotation.add_pb_type_port_pair(name_attr, port_parser.port());
/* We have an optional attribute: physical_mode_pin_rotate_offset */
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 XML description for a pb_type annotation under a <pb_type> XML node
*******************************************************************/
static
void read_xml_pb_type_annotation(pugi::xml_node& xml_pb_type,
const pugiutil::loc_data& loc_data,
std::vector<openfpga::PbTypeAnnotation>& pb_type_annotations) {
openfpga::PbTypeAnnotation pb_type_annotation;
/* Find the name of pb_type */
const std::string& name_attr = get_attribute(xml_pb_type, "name", loc_data).as_string();
const std::string& physical_name_attr = get_attribute(xml_pb_type, "physical_pb_type_name", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string();
/* If both names are not empty, this is a operating pb_type */
if ( (false == name_attr.empty())
&& (false == physical_name_attr.empty()) ) {
/* Parse the attributes for operating pb_type */
openfpga::PbParser operating_pb_parser(name_attr);
pb_type_annotation.set_operating_pb_type_name(operating_pb_parser.leaf());
if (0 < operating_pb_parser.parents().size()) {
pb_type_annotation.set_operating_parent_pb_type_names(operating_pb_parser.parents());
}
if (0 < operating_pb_parser.modes().size()) {
pb_type_annotation.set_operating_parent_mode_names(operating_pb_parser.modes());
}
openfpga::PbParser physical_pb_parser(physical_name_attr);
pb_type_annotation.set_physical_pb_type_name(physical_pb_parser.leaf());
if (0 < physical_pb_parser.parents().size()) {
pb_type_annotation.set_physical_parent_pb_type_names(physical_pb_parser.parents());
}
if (0 < physical_pb_parser.modes().size()) {
pb_type_annotation.set_physical_parent_mode_names(physical_pb_parser.modes());
}
}
/* If there is only a name, this is a physical pb_type */
if ( (false == name_attr.empty())
&& (true == physical_name_attr.empty()) ) {
openfpga::PbParser physical_pb_parser(name_attr);
pb_type_annotation.set_physical_pb_type_name(physical_pb_parser.leaf());
if (0 < physical_pb_parser.parents().size()) {
pb_type_annotation.set_physical_parent_pb_type_names(physical_pb_parser.parents());
}
if (0 < physical_pb_parser.modes().size()) {
pb_type_annotation.set_physical_parent_mode_names(physical_pb_parser.modes());
}
}
/* Parse physical mode name which are applied to both pb_types */
pb_type_annotation.set_physical_mode_name(get_attribute(xml_pb_type, "physical_mode_name", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string());
/* Parse idle mode name which are applied to both pb_types */
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());
/* If this is a physical pb_type, circuit model name is an optional attribute,
* which is applicable to leaf pb_type in the hierarchy
*/
if (true == pb_type_annotation.is_physical_pb_type()) {
pb_type_annotation.set_circuit_model_name(get_attribute(xml_pb_type, "circuit_model_name", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string());
}
/* If this is an operating pb_type, index factor and offset may be optional needed */
if (true == pb_type_annotation.is_operating_pb_type()) {
pb_type_annotation.set_physical_pb_type_index_factor(get_attribute(xml_pb_type, "physical_pb_type_index_factor", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
pb_type_annotation.set_physical_pb_type_index_offset(get_attribute(xml_pb_type, "physical_pb_type_index_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(0));
}
/* Parse all the interconnect-to-circuit binding under this node
* All the bindings are defined in child node <interconnect>
*/
size_t num_intercs = count_children(xml_pb_type, "interconnect", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (0 < num_intercs) {
pugi::xml_node xml_interc = get_first_child(xml_pb_type, "interconnect", loc_data);
while (xml_interc) {
read_xml_interc_annotation(xml_interc, loc_data, pb_type_annotation);
xml_interc = xml_interc.next_sibling(xml_interc.name());
}
}
/* Parse all the port-to-port binding from operating pb_type to physical pb_type under this node
* All the bindings are defined in child node <port>
* This is only applicable to operating pb_type
*/
if (true == pb_type_annotation.is_operating_pb_type()) {
size_t num_ports = count_children(xml_pb_type, "port", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (0 < num_ports) {
pugi::xml_node xml_port = get_first_child(xml_pb_type, "port", loc_data);
while (xml_port) {
read_xml_pb_port_annotation(xml_port, loc_data, pb_type_annotation);
xml_port = xml_port.next_sibling(xml_port.name());
}
}
}
/* Finish parsing and add it to the vector */
pb_type_annotations.push_back(pb_type_annotation);
}
/********************************************************************
* Top function to parse XML description about pb_type annotation
*******************************************************************/
std::vector<openfpga::PbTypeAnnotation> read_xml_pb_type_annotations(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data) {
std::vector<openfpga::PbTypeAnnotation> pb_type_annotations;
/* Parse configuration protocol root node */
pugi::xml_node xml_annotations = get_single_child(Node, "pb_type_annotations", loc_data);
/* Iterate over the children under this node,
* each child should be named after <pb_type>
*/
for (pugi::xml_node xml_pb_type : xml_annotations.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_pb_type.name() != std::string("pb_type")) {
bad_tag(xml_pb_type, loc_data, xml_annotations, {"pb_type"});
}
read_xml_pb_type_annotation(xml_pb_type, loc_data, pb_type_annotations);
}
return pb_type_annotations;
}

View File

@ -0,0 +1,17 @@
#ifndef READ_XML_PB_TYPE_ANNOTATION_H
#define READ_XML_PB_TYPE_ANNOTATION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "pb_type_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
std::vector<openfpga::PbTypeAnnotation> read_xml_pb_type_annotations(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data);
#endif

View File

@ -16,6 +16,7 @@
#include "write_xml_simulation_setting.h"
#include "write_xml_config_protocol.h"
#include "write_xml_routing_circuit.h"
#include "write_xml_pb_type_annotation.h"
#include "write_xml_openfpga_arch.h"
/********************************************************************
@ -57,6 +58,10 @@ void write_xml_openfpga_arch(const char* fname,
/* Write the direct connection circuit definition */
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.direct2circuit);
/* Write the pb_type annotations */
openfpga::write_xml_pb_type_annotations(fp, fname, openfpga_arch. pb_type_annotations);
fp << "</openfpga_architecture>" << "\n";
/* Write the simulation */

View File

@ -0,0 +1,224 @@
/********************************************************************
* This file includes functions that outputs pb_type annotations to XML format
*******************************************************************/
/* Headers from system goes first */
#include <string>
#include <algorithm>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_digest.h"
/* Headers from readarchopenfpga library */
#include "write_xml_utils.h"
#include "write_xml_pb_type_annotation.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* Generate the full hierarchy name for a operating pb_type
*******************************************************************/
static
std::string generate_operating_pb_type_hierarchy_name(const PbTypeAnnotation& pb_type_annotation) {
/* Iterate over the parent_pb_type and modes names, they should well match */
VTR_ASSERT_SAFE(pb_type_annotation.operating_parent_pb_type_names().size() == pb_type_annotation.operating_parent_mode_names().size());
std::string hie_name;
for (size_t i = 0 ; i < pb_type_annotation.operating_parent_pb_type_names().size(); ++i) {
hie_name += pb_type_annotation.operating_parent_pb_type_names()[i];
hie_name += std::string("[");
hie_name += pb_type_annotation.operating_parent_mode_names()[i];
hie_name += std::string("]");
hie_name += std::string(".");
}
/* Add the leaf pb_type */
hie_name += pb_type_annotation.operating_pb_type_name();
return hie_name;
}
/********************************************************************
* Generate the full hierarchy name for a operating pb_type
*******************************************************************/
static
std::string generate_physical_pb_type_hierarchy_name(const PbTypeAnnotation& pb_type_annotation) {
/* Iterate over the parent_pb_type and modes names, they should well match */
VTR_ASSERT_SAFE(pb_type_annotation.physical_parent_pb_type_names().size() == pb_type_annotation.physical_parent_mode_names().size());
std::string hie_name;
for (size_t i = 0 ; i < pb_type_annotation.physical_parent_pb_type_names().size(); ++i) {
hie_name += pb_type_annotation.physical_parent_pb_type_names()[i];
hie_name += std::string("[");
hie_name += pb_type_annotation.physical_parent_mode_names()[i];
hie_name += std::string("]");
hie_name += std::string(".");
}
/* Add the leaf pb_type */
hie_name += pb_type_annotation.physical_pb_type_name();
return hie_name;
}
/********************************************************************
* Generate the full hierarchy name for a operating pb_type
*******************************************************************/
static
std::string generate_physical_pb_port_name(const BasicPort& pb_port) {
std::string port_name;
/* Output format: <port_name>[<LSB>:<MSB>] */
port_name += pb_port.get_name();
port_name += std::string("[");
port_name += std::to_string(pb_port.get_lsb());
port_name += std::string(":");
port_name += std::to_string(pb_port.get_msb());
port_name += std::string("]");
return port_name;
}
/********************************************************************
* A writer to output an pb_type interconnection annotation to XML format
*******************************************************************/
static
void write_xml_interconnect_annotation(std::fstream& fp,
const char* fname,
const openfpga::PbTypeAnnotation& pb_type_annotation,
const std::string& interc_name) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
fp << "\t\t\t" << "<interconnect";
write_xml_attribute(fp, "name", interc_name.c_str());
write_xml_attribute(fp, "circuit_model_name", pb_type_annotation.interconnect_circuit_model_name(interc_name).c_str());
fp << "/>" << "\n";
}
/********************************************************************
* A writer to output an pb_type port annotation to XML format
*******************************************************************/
static
void write_xml_pb_port_annotation(std::fstream& fp,
const char* fname,
const openfpga::PbTypeAnnotation& pb_type_annotation,
const std::string& port_name) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
fp << "\t\t\t" << "<port";
write_xml_attribute(fp, "name", port_name.c_str());
write_xml_attribute(fp, "physical_mode_port", generate_physical_pb_port_name(pb_type_annotation.physical_pb_type_port(port_name)).c_str());
write_xml_attribute(fp, "physical_mode_pin_rotate_offset", pb_type_annotation.physical_pin_rotate_offset(port_name));
fp << "/>" << "\n";
}
/********************************************************************
* A writer to output a device variation in a technology library to XML format
*******************************************************************/
static
void write_xml_pb_type_annotation(std::fstream& fp,
const char* fname,
const openfpga::PbTypeAnnotation& pb_type_annotation) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
fp << "\t\t" << "<pb_type";
/* Write up name of the pb_type, which is different by the type of pb_type
* 1. operating pb_type, we output name, physical_pb_type_name
* 1. physical pb_type, we output name
*/
if (true == pb_type_annotation.is_operating_pb_type()) {
write_xml_attribute(fp, "name", generate_operating_pb_type_hierarchy_name(pb_type_annotation).c_str());
write_xml_attribute(fp, "physical_pb_type_name", generate_physical_pb_type_hierarchy_name(pb_type_annotation).c_str());
}
if (true == pb_type_annotation.is_physical_pb_type()) {
write_xml_attribute(fp, "name", generate_physical_pb_type_hierarchy_name(pb_type_annotation).c_str());
}
/* Output physical mode name */
if (!pb_type_annotation.physical_mode_name().empty()) {
write_xml_attribute(fp, "physical_mode_name", pb_type_annotation.physical_mode_name().c_str());
}
/* Output idle mode name */
if (!pb_type_annotation.idle_mode_name().empty()) {
write_xml_attribute(fp, "idle_mode_name", pb_type_annotation.idle_mode_name().c_str());
}
/* Output mode_bits */
if (!pb_type_annotation.mode_bits().empty()) {
write_xml_attribute(fp, "mode_bits", pb_type_annotation.mode_bits().c_str());
}
/* Output circuit model name */
if (!pb_type_annotation.circuit_model_name().empty()) {
write_xml_attribute(fp, "circuit_model_name", pb_type_annotation.circuit_model_name().c_str());
}
/* Output physical mode index factor and offset, only applicable to operating mode */
if (true == pb_type_annotation.is_operating_pb_type()) {
write_xml_attribute(fp, "physical_pb_type_index_factor", pb_type_annotation.physical_pb_type_index_factor());
write_xml_attribute(fp, "physical_pb_type_index_offset", pb_type_annotation.physical_pb_type_index_offset());
}
/* If there are interconnect definition or port definition, output them
* Otherwise we can finish here
*/
if ( (0 == pb_type_annotation.interconnect_names().size())
&& (0 == pb_type_annotation.port_names().size()) ) {
fp << "/>" << "\n";
return;
}
fp << ">" << "\n";
/* Output interconnects if there are any */
for (const std::string& interc_name : pb_type_annotation.interconnect_names()) {
write_xml_interconnect_annotation(fp, fname, pb_type_annotation, interc_name);
}
/* Output pb_type ports if there are any */
for (const std::string& port_name : pb_type_annotation.port_names()) {
write_xml_pb_port_annotation(fp, fname, pb_type_annotation, port_name);
}
fp << "\t\t</pb_type>" << "\n";
}
/********************************************************************
* A writer to output a number of pb_type annotations to XML format
*******************************************************************/
void write_xml_pb_type_annotations(std::fstream& fp,
const char* fname,
const std::vector<PbTypeAnnotation>& pb_type_annotations) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node for pb_type annotations,
* we apply a tab becuase pb_type annotations is just a subnode
* under the root node <openfpga_arch>
*/
fp << "\t" << "<pb_type_annotations>" << "\n";
/* Write device model one by one */
for (const PbTypeAnnotation& pb_type_annotation : pb_type_annotations) {
write_xml_pb_type_annotation(fp, fname, pb_type_annotation);
}
/* Write the root node for pb_type annotations */
fp << "\t" << "</pb_type_annotations>" << "\n";
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,22 @@
#ifndef WRITE_XML_PB_TYPE_ANNOTATION_H
#define WRITE_XML_PB_TYPE_ANNOTATION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <fstream>
#include "pb_type_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* namespace openfpga begins */
namespace openfpga {
void write_xml_pb_type_annotations(std::fstream& fp,
const char* fname,
const std::vector<PbTypeAnnotation>& pb_type_annotations);
} /* namespace openfpga ends */
#endif

View File

@ -46,6 +46,21 @@ void write_xml_attribute(std::fstream& fp,
fp << "\"";
}
/********************************************************************
* A most utilized function to write an XML attribute to file
* This accepts the value as a float
*******************************************************************/
void write_xml_attribute(std::fstream& fp,
const char* attr,
const int& value) {
/* Validate the file stream */
openfpga::valid_file_stream(fp);
fp << " " << attr << "=\"";
fp << value;
fp << "\"";
}
/********************************************************************
* A most utilized function to write an XML attribute to file
* This accepts the value as a float

View File

@ -18,6 +18,10 @@ void write_xml_attribute(std::fstream& fp,
const char* attr,
const bool& value);
void write_xml_attribute(std::fstream& fp,
const char* attr,
const int& value);
void write_xml_attribute(std::fstream& fp,
const char* attr,
const float& value);

View File

@ -0,0 +1,118 @@
/************************************************************************
* Member functions for Pb parsers
***********************************************************************/
#include <cstring>
#include "vtr_assert.h"
#include "openfpga_tokenizer.h"
#include "openfpga_pb_parser.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Member functions for PbParser class
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
PbParser::PbParser (const std::string& data) {
set_default_bracket();
set_default_delim();
set_data(data);
}
/************************************************************************
* Public Accessors
***********************************************************************/
/* Get the data string */
std::string PbParser::data() const {
return data_;
}
std::string PbParser::leaf() const {
return leaf_;
}
std::vector<std::string> PbParser::parents() const {
return parents_;
}
std::vector<std::string> PbParser::modes() const {
return modes_;
}
/************************************************************************
* Public Mutators
***********************************************************************/
void PbParser::set_data(const std::string& data) {
data_ = data;
parse();
}
/************************************************************************
* Internal Mutators
***********************************************************************/
/* Parse the data */
void PbParser::parse() {
/* Create a tokenizer */
StringToken tokenizer(data_);
/* Split the data into <pb_type>[<mode>] */
std::vector<std::string> pb_tokens = tokenizer.split(delim_);
/* The last pb is the leaf node.
* It should NOT be empty and should NOT contain any brackets!
*/
VTR_ASSERT(0 < pb_tokens.size());
VTR_ASSERT(false == pb_tokens.back().empty());
VTR_ASSERT(pb_tokens.back().find(bracket_.x()) == std::string::npos);
VTR_ASSERT(pb_tokens.back().find(bracket_.y()) == std::string::npos);
/* Pass the check, we assign the value */
leaf_ = pb_tokens.back();
/* Split the rest of pb_tokens, split the pb_type and mode_name */
for (size_t itok = 0; itok < pb_tokens.size() - 1; ++itok) {
/* Create a tokenizer */
StringToken pb_tokenizer(pb_tokens[itok]);
std::vector<std::string> tokens = pb_tokenizer.split(bracket_.x());
/* Make sure we have a port name! */
VTR_ASSERT_SAFE ((1 == tokens.size()) || (2 == tokens.size()));
/* Store the pb_type name */
parents_.push_back(tokens[0]);
/* If we only have one token, the mode name is the default mode
* Here we use the default keyword 'default'
* from VPR function ProcessMode() in libarchfpga
*/
if (1 == tokens.size()) {
modes_.push_back(std::string("default"));
continue; /* We can finish here */
}
/* If there is a mode name, extract it */
VTR_ASSERT_SAFE (2 == tokens.size());
/* Chomp the ']' */
pb_tokenizer.set_data(tokens[1]);
std::vector<std::string> mode_tokens = pb_tokenizer.split(bracket_.y());
/* Make sure we have only one mode name inside */
VTR_ASSERT(1 == mode_tokens.size());
modes_.push_back(mode_tokens[0]);
}
}
void PbParser::set_default_bracket() {
bracket_.set_x('[');
bracket_.set_y(']');
}
void PbParser::set_default_delim() {
delim_ = '.';
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,56 @@
#ifndef OPENFPGA_PB_PARSER_H
#define OPENFPGA_PB_PARSER_H
/********************************************************************
* Include header files that are required by data structure declaration
*******************************************************************/
#include <string>
#include <vector>
#include "vtr_geometry.h"
#include "openfpga_tokenizer.h"
/************************************************************************
* This file includes parsers for pb_type definition in the architecture XML
* language.
***********************************************************************/
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Class PbParser: pb_type name with full hierarchy parser
* Supported pb_type definition:
* 1. <pb_type>[<mode>].<sub_pb_type>[<mode>] ... .<leaf_pb_type>
* 2. <pb_type>.<sub_pb_type> ... .<leaf_pb_type>
* where each pb_type may be specified by a mode or use the default mode
* (mode name not given)
***********************************************************************/
class PbParser{
public : /* Constructors*/
PbParser (const std::string& data);
public : /* Public Accessors */
std::string data() const;
std::string leaf() const;
std::vector<std::string> parents() const;
std::vector<std::string> modes() const;
public : /* Public Mutators */
void set_data(const std::string& data);
private : /* Private Mutators */
void parse();
void set_default_bracket();
void set_default_delim();
private: /* Internal data */
std::string data_; /* Lines to be splited */
vtr::Point<char> bracket_;
char delim_;
std::vector<std::string> parents_;
std::vector<std::string> modes_;
std::string leaf_;
};
} /* namespace openfpga ends */
#endif

View File

@ -64,7 +64,7 @@ void PortParser::parse() {
/* If we only have one token */
if (1 == port_tokens.size()) {
port_.set_width(0);
port_.set_width(1);
return; /* We can finish here */
}
@ -75,21 +75,22 @@ void PortParser::parse() {
VTR_ASSERT_SAFE (1 == port_tokens.size());
/* Split the pin string now */
tokenizer.set_data(port_tokens[0]);
tokenizer.set_data(pin_tokens[0]);
pin_tokens = tokenizer.split(delim_);
/* Check if we have LSB and MSB or just one */
if ( 1 == pin_tokens.size() ) {
/* Single pin */
port_.set_width(stoi(pin_tokens[0]), stoi(pin_tokens[0]));
port_.set_width(std::stoi(pin_tokens[0]), std::stoi(pin_tokens[0]));
} else if ( 2 == pin_tokens.size() ) {
/* A number of pin */
port_.set_width(stoi(pin_tokens[0]), stoi(pin_tokens[1]));
}
/* Re-order to ensure LSB <= MSB */
if (false == port_.is_valid()) {
port_.revert();
/* A number of pins.
* Note that we always use the LSB for token[0] and MSB for token[1]
*/
if (std::stoi(pin_tokens[1]) < std::stoi(pin_tokens[0])) {
port_.set_width(std::stoi(pin_tokens[1]), std::stoi(pin_tokens[0]));
} else {
port_.set_width(std::stoi(pin_tokens[0]), std::stoi(pin_tokens[1]));
}
}
return;