diff --git a/libopenfpga/libarchopenfpga/src/pb_type_annotation.cpp b/libopenfpga/libarchopenfpga/src/pb_type_annotation.cpp index 98fad3dd0..da494f77f 100644 --- a/libopenfpga/libarchopenfpga/src/pb_type_annotation.cpp +++ b/libopenfpga/libarchopenfpga/src/pb_type_annotation.cpp @@ -31,7 +31,8 @@ std::vector PbTypeAnnotation::operating_parent_mode_names() const { } bool PbTypeAnnotation::is_operating_pb_type() const { - return true == operating_pb_type_name_.empty(); + return (false == operating_pb_type_name_.empty()) + && (false == physical_pb_type_name_.empty()); } @@ -48,7 +49,8 @@ std::vector PbTypeAnnotation::physical_parent_mode_names() const { } bool PbTypeAnnotation::is_physical_pb_type() const { - return true == physical_pb_type_name_.empty(); + return (true == operating_pb_type_name_.empty()) + && (false == physical_pb_type_name_.empty()); } std::string PbTypeAnnotation::physical_mode_name() const { @@ -75,7 +77,15 @@ int PbTypeAnnotation::physical_pb_type_index_offset() const { return physical_pb_type_index_offset_; } -BasicPort PbTypeAnnotation::physical_pb_type_ports(const std::string& port_name) const { +std::vector PbTypeAnnotation::port_names() const { + std::vector 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::const_iterator it = operating_pb_type_ports_.find(port_name); if (it == operating_pb_type_ports_.end()) { /* Return an empty port */ @@ -84,7 +94,7 @@ BasicPort PbTypeAnnotation::physical_pb_type_ports(const std::string& port_name) return operating_pb_type_ports_.at(port_name); } -int PbTypeAnnotation::physical_pin_rotate_offsets(const std::string& port_name) const { +int PbTypeAnnotation::physical_pin_rotate_offset(const std::string& port_name) const { std::map::const_iterator it = physical_pin_rotate_offsets_.find(port_name); if (it == physical_pin_rotate_offsets_.end()) { /* Return a zero offset which is default */ @@ -93,6 +103,14 @@ int PbTypeAnnotation::physical_pin_rotate_offsets(const std::string& port_name) return physical_pin_rotate_offsets_.at(port_name); } +std::vector PbTypeAnnotation::interconnect_names() const { + std::vector 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::const_iterator it = interconnect_circuit_model_names_.find(interc_name); if (it == interconnect_circuit_model_names_.end()) { diff --git a/libopenfpga/libarchopenfpga/src/pb_type_annotation.h b/libopenfpga/libarchopenfpga/src/pb_type_annotation.h index 8849ef273..e03201cde 100644 --- a/libopenfpga/libarchopenfpga/src/pb_type_annotation.h +++ b/libopenfpga/libarchopenfpga/src/pb_type_annotation.h @@ -47,8 +47,10 @@ class PbTypeAnnotation { std::string circuit_model_name() const; int physical_pb_type_index_factor() const; int physical_pb_type_index_offset() const; - BasicPort physical_pb_type_ports(const std::string& port_name) const; - int physical_pin_rotate_offsets(const std::string& port_name) const; + std::vector 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 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); diff --git a/libopenfpga/libarchopenfpga/src/read_xml_pb_type_annotation.cpp b/libopenfpga/libarchopenfpga/src/read_xml_pb_type_annotation.cpp index 25e1e12f8..253053bf5 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_pb_type_annotation.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_pb_type_annotation.cpp @@ -75,7 +75,6 @@ void read_xml_pb_type_annotation(pugi::xml_node& xml_pb_type, /* 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(); - const std::string& physical_mode_name_attr = get_attribute(xml_pb_type, "physical_mode_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()) @@ -122,9 +121,11 @@ void read_xml_pb_type_annotation(pugi::xml_node& xml_pb_type, /* 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 a mandatory attribute */ + /* 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).as_string()); + 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 */ diff --git a/libopenfpga/libarchopenfpga/src/write_xml_openfpga_arch.cpp b/libopenfpga/libarchopenfpga/src/write_xml_openfpga_arch.cpp index e262735e4..b71853156 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_openfpga_arch.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_openfpga_arch.cpp @@ -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 << "" << "\n"; /* Write the simulation */ diff --git a/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.cpp b/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.cpp new file mode 100644 index 000000000..a771c782d --- /dev/null +++ b/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.cpp @@ -0,0 +1,224 @@ +/******************************************************************** + * This file includes functions that outputs pb_type annotations to XML format + *******************************************************************/ +/* Headers from system goes first */ +#include +#include + +/* 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 += 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" << "" << "\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" << "" << "\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" << "" << "\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" << "\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& 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 + */ + fp << "\t" << "" << "\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" << "" << "\n"; +} + +} /* namespace openfpga ends */ diff --git a/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.h b/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.h new file mode 100644 index 000000000..e40b5ad4e --- /dev/null +++ b/libopenfpga/libarchopenfpga/src/write_xml_pb_type_annotation.h @@ -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 +#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& pb_type_annotations); + +} /* namespace openfpga ends */ + +#endif diff --git a/libopenfpga/libarchopenfpga/src/write_xml_utils.cpp b/libopenfpga/libarchopenfpga/src/write_xml_utils.cpp index ad887e10c..e4d32e720 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_utils.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_utils.cpp @@ -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 diff --git a/libopenfpga/libarchopenfpga/src/write_xml_utils.h b/libopenfpga/libarchopenfpga/src/write_xml_utils.h index a827727e4..3976d78b9 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_utils.h +++ b/libopenfpga/libarchopenfpga/src/write_xml_utils.h @@ -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); diff --git a/libopenfpga/libopenfpgautil/src/openfpga_pb_parser.cpp b/libopenfpga/libopenfpgautil/src/openfpga_pb_parser.cpp index ee674b928..3c174f589 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_pb_parser.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_pb_parser.cpp @@ -67,6 +67,7 @@ void PbParser::parse() { /* 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); diff --git a/libopenfpga/libopenfpgautil/src/openfpga_port_parser.cpp b/libopenfpga/libopenfpgautil/src/openfpga_port_parser.cpp index 78f357b82..2006275dc 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_port_parser.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_port_parser.cpp @@ -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;