finish XML parser and writer for pb_type annotation

This commit is contained in:
tangxifan 2020-01-26 15:54:49 -07:00
parent 1cba141dd0
commit 7d4b07421d
10 changed files with 312 additions and 19 deletions

View File

@ -31,7 +31,8 @@ std::vector<std::string> PbTypeAnnotation::operating_parent_mode_names() const {
} }
bool PbTypeAnnotation::is_operating_pb_type() 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<std::string> PbTypeAnnotation::physical_parent_mode_names() const {
} }
bool PbTypeAnnotation::is_physical_pb_type() 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 { 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_; return physical_pb_type_index_offset_;
} }
BasicPort PbTypeAnnotation::physical_pb_type_ports(const std::string& port_name) const { 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); std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(port_name);
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
/* Return an empty port */ /* 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); 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<std::string, int>::const_iterator it = physical_pin_rotate_offsets_.find(port_name); std::map<std::string, int>::const_iterator it = physical_pin_rotate_offsets_.find(port_name);
if (it == physical_pin_rotate_offsets_.end()) { if (it == physical_pin_rotate_offsets_.end()) {
/* Return a zero offset which is default */ /* 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); 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::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); std::map<std::string, std::string>::const_iterator it = interconnect_circuit_model_names_.find(interc_name);
if (it == interconnect_circuit_model_names_.end()) { if (it == interconnect_circuit_model_names_.end()) {

View File

@ -47,8 +47,10 @@ class PbTypeAnnotation {
std::string circuit_model_name() const; std::string circuit_model_name() const;
int physical_pb_type_index_factor() const; int physical_pb_type_index_factor() const;
int physical_pb_type_index_offset() const; int physical_pb_type_index_offset() const;
BasicPort physical_pb_type_ports(const std::string& port_name) const; std::vector<std::string> port_names() const;
int physical_pin_rotate_offsets(const std::string& port_name) 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; std::string interconnect_circuit_model_name(const std::string& interc_name) const;
public: /* Public mutators */ public: /* Public mutators */
void set_operating_pb_type_name(const std::string& name); void set_operating_pb_type_name(const std::string& name);

View File

@ -75,7 +75,6 @@ void read_xml_pb_type_annotation(pugi::xml_node& xml_pb_type,
/* Find the name of 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& 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_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 both names are not empty, this is a operating pb_type */
if ( (false == name_attr.empty()) 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 */ /* 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()); 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()) { 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 */ /* If this is an operating pb_type, index factor and offset may be optional needed */

View File

@ -16,6 +16,7 @@
#include "write_xml_simulation_setting.h" #include "write_xml_simulation_setting.h"
#include "write_xml_config_protocol.h" #include "write_xml_config_protocol.h"
#include "write_xml_routing_circuit.h" #include "write_xml_routing_circuit.h"
#include "write_xml_pb_type_annotation.h"
#include "write_xml_openfpga_arch.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 the direct connection circuit definition */
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.direct2circuit); write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.direct2circuit);
/* Write the pb_type annotations */
openfpga::write_xml_pb_type_annotations(fp, fname, openfpga_arch. pb_type_annotations);
fp << "</openfpga_architecture>" << "\n"; fp << "</openfpga_architecture>" << "\n";
/* Write the simulation */ /* 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 << "\""; 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 * A most utilized function to write an XML attribute to file
* This accepts the value as a float * This accepts the value as a float

View File

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

View File

@ -67,6 +67,7 @@ void PbParser::parse() {
/* The last pb is the leaf node. /* The last pb is the leaf node.
* It should NOT be empty and should NOT contain any brackets! * 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(false == pb_tokens.back().empty());
VTR_ASSERT(pb_tokens.back().find(bracket_.x()) == std::string::npos); VTR_ASSERT(pb_tokens.back().find(bracket_.x()) == std::string::npos);
VTR_ASSERT(pb_tokens.back().find(bracket_.y()) == std::string::npos); VTR_ASSERT(pb_tokens.back().find(bracket_.y()) == std::string::npos);

View File

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