OpenFPGA/libs/libbusgroup/src/read_xml_bus_group.cpp

141 lines
4.9 KiB
C++

/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of bus group file 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"
#include "vtr_time.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "bus_group_xml_constants.h"
#include "read_xml_bus_group.h"
#include "read_xml_util.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* Parse XML codes of a <pin> to an object of BusGroup
*******************************************************************/
static void read_xml_pin(pugi::xml_node& xml_pin,
const pugiutil::loc_data& loc_data,
BusGroup& bus_group, const BusGroupId& bus_id) {
if (false == bus_group.valid_bus_id(bus_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin),
"Invalid id of a bus group!\n");
}
int pin_index =
get_attribute(xml_pin, XML_PIN_INDEX_ATTRIBUTE_NAME, loc_data).as_int();
std::string pin_name =
get_attribute(xml_pin, XML_PIN_NAME_ATTRIBUTE_NAME, loc_data).as_string();
/* Before update storage, check if the pin index is in the range */
BasicPort pin_port(bus_group.bus_port(bus_id).get_name(), pin_index,
pin_index);
if (!bus_group.bus_port(bus_id).contained(pin_port)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin),
"Pin index is out of range of the bus port width!\n");
}
BusPinId pin_id = bus_group.create_pin(bus_id, pin_index);
bus_group.set_pin_name(pin_id, pin_name);
}
/********************************************************************
* Parse XML codes of a <bus> to an object of BusGroup
*******************************************************************/
static void read_xml_bus(pugi::xml_node& xml_bus,
const pugiutil::loc_data& loc_data,
BusGroup& bus_group) {
openfpga::PortParser port_parser(
get_attribute(xml_bus, XML_BUS_PORT_ATTRIBUTE_NAME, loc_data).as_string());
/* Create a new bus in the storage */
BusGroupId bus_id = bus_group.create_bus(port_parser.port());
if (false == bus_group.valid_bus_id(bus_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bus),
"Fail to create a bus group!\n");
}
/* Ensure the bus port is valid */
if (!bus_group.bus_port(bus_id).is_valid()) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bus),
"Bus port is invalid, check LSB and MSB!\n");
}
/* Find big endian */
bus_group.set_bus_big_endian(
bus_id, get_attribute(xml_bus, XML_BUS_BIG_ENDIAN_ATTRIBUTE_NAME, loc_data,
pugiutil::OPTIONAL)
.as_bool(true));
for (pugi::xml_node xml_pin : xml_bus.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_pin.name() != std::string(XML_PIN_NODE_NAME)) {
bad_tag(xml_pin, loc_data, xml_bus, {XML_PIN_NODE_NAME});
}
read_xml_pin(xml_pin, loc_data, bus_group, bus_id);
}
}
/********************************************************************
* Parse XML codes about <bus_group> to an object of BusGroup
*******************************************************************/
BusGroup read_xml_bus_group(const char* fname) {
vtr::ScopedStartFinishTimer timer("Read Bus Group");
BusGroup bus_group;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, fname);
pugi::xml_node xml_root =
get_single_child(doc, XML_BUS_GROUP_NODE_NAME, loc_data);
size_t num_buses =
std::distance(xml_root.children().begin(), xml_root.children().end());
/* Count the total number of pins */
size_t num_pins = 0;
for (pugi::xml_node xml_bus : xml_root.children()) {
num_pins +=
std::distance(xml_bus.children().begin(), xml_bus.children().end());
}
/* Reserve memory space for the buses */
bus_group.reserve_buses(num_buses);
/* Reserve memory space for the pins */
bus_group.reserve_pins(num_pins);
for (pugi::xml_node xml_bus : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_bus.name() != std::string(XML_BUS_NODE_NAME)) {
bad_tag(xml_bus, loc_data, xml_root, {XML_BUS_NODE_NAME});
}
read_xml_bus(xml_bus, loc_data, bus_group);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(fname, e.line(), "%s", e.what());
}
return bus_group;
}
} // End of namespace openfpga