206 lines
7.7 KiB
C++
206 lines
7.7 KiB
C++
/********************************************************************
|
|
* This file includes the top-level function of this library
|
|
* which reads an XML of a fabric key 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 libarchfpga */
|
|
#include "arch_error.h"
|
|
#include "openfpga_reserved_words.h"
|
|
#include "read_xml_arch_bitstream.h"
|
|
#include "read_xml_util.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/********************************************************************
|
|
* Parse XML codes of a <bitstream_block> to an object of BitstreamManager
|
|
* This function goes recursively until we reach the leaf node
|
|
*******************************************************************/
|
|
static void rec_read_xml_bitstream_block(pugi::xml_node& xml_bitstream_block,
|
|
const pugiutil::loc_data& loc_data,
|
|
BitstreamManager& bitstream_manager,
|
|
const ConfigBlockId& parent_block) {
|
|
/* Find the name of this bitstream block */
|
|
const std::string& block_name =
|
|
get_attribute(xml_bitstream_block, "name", loc_data).as_string();
|
|
|
|
/* Create the bitstream block */
|
|
ConfigBlockId curr_block = bitstream_manager.add_block(block_name);
|
|
|
|
/* Add it to parent block */
|
|
bitstream_manager.add_child_block(parent_block, curr_block);
|
|
|
|
/* Parse input nets if defined */
|
|
pugi::xml_node xml_input_nets = get_single_child(
|
|
xml_bitstream_block, "input_nets", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
|
if (xml_input_nets) {
|
|
std::vector<std::string> input_nets;
|
|
size_t num_input_nets = count_children(xml_input_nets, "path", loc_data,
|
|
pugiutil::ReqOpt::OPTIONAL);
|
|
input_nets.resize(num_input_nets);
|
|
|
|
/* Find the child paths/nets */
|
|
for (pugi::xml_node xml_input_net : xml_input_nets.children()) {
|
|
/* We only care child bitstream blocks here */
|
|
if (xml_input_net.name() != std::string("path")) {
|
|
bad_tag(xml_input_net, loc_data, xml_input_nets, {"path"});
|
|
}
|
|
const int& id = get_attribute(xml_input_net, "id", loc_data).as_int();
|
|
const std::string& net_name =
|
|
get_attribute(xml_input_net, "net_name", loc_data).as_string();
|
|
VTR_ASSERT((size_t)id < input_nets.size());
|
|
input_nets[id] = net_name;
|
|
}
|
|
|
|
std::string input_nets_str;
|
|
bool need_splitter = false;
|
|
for (const std::string& input_net : input_nets) {
|
|
if (true == need_splitter) {
|
|
input_nets_str += std::string(" ");
|
|
}
|
|
input_nets_str += input_net;
|
|
need_splitter = true;
|
|
}
|
|
bitstream_manager.add_input_net_id_to_block(curr_block, input_nets_str);
|
|
}
|
|
|
|
/* Parse output nets if defined */
|
|
pugi::xml_node xml_output_nets = get_single_child(
|
|
xml_bitstream_block, "output_nets", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
|
if (xml_output_nets) {
|
|
std::vector<std::string> output_nets;
|
|
size_t num_output_nets = count_children(xml_output_nets, "path", loc_data,
|
|
pugiutil::ReqOpt::OPTIONAL);
|
|
output_nets.resize(num_output_nets);
|
|
|
|
/* Find the child paths/nets */
|
|
for (pugi::xml_node xml_output_net : xml_output_nets.children()) {
|
|
/* We only care child bitstream blocks here */
|
|
if (xml_output_net.name() != std::string("path")) {
|
|
bad_tag(xml_output_net, loc_data, xml_output_nets, {"path"});
|
|
}
|
|
const int& id = get_attribute(xml_output_net, "id", loc_data).as_int();
|
|
const std::string& net_name =
|
|
get_attribute(xml_output_net, "net_name", loc_data).as_string();
|
|
VTR_ASSERT((size_t)id < output_nets.size());
|
|
output_nets[id] = net_name;
|
|
}
|
|
|
|
std::string output_nets_str;
|
|
bool need_splitter = false;
|
|
for (const std::string& output_net : output_nets) {
|
|
if (true == need_splitter) {
|
|
output_nets_str += std::string(" ");
|
|
}
|
|
output_nets_str += output_net;
|
|
need_splitter = true;
|
|
}
|
|
bitstream_manager.add_output_net_id_to_block(curr_block, output_nets_str);
|
|
}
|
|
|
|
/* Parse configuration bits */
|
|
pugi::xml_node xml_bitstream = get_single_child(
|
|
xml_bitstream_block, "bitstream", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
|
if (xml_bitstream) {
|
|
/* Parse path_id: -2 is an invalid value defined in the bitstream manager
|
|
* internally */
|
|
const int& path_id = get_attribute(xml_bitstream, "path_id", loc_data,
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
.as_int(-2);
|
|
if (-2 < path_id) {
|
|
bitstream_manager.add_path_id_to_block(curr_block, path_id);
|
|
}
|
|
|
|
/* Find the child paths/nets */
|
|
std::vector<bool> block_bits;
|
|
for (pugi::xml_node xml_bit : xml_bitstream.children()) {
|
|
/* We only care child bitstream blocks here */
|
|
if (xml_bit.name() != std::string("bit")) {
|
|
bad_tag(xml_bit, loc_data, xml_bitstream, {"bit"});
|
|
}
|
|
const int& bit_value = get_attribute(xml_bit, "value", loc_data).as_int();
|
|
block_bits.push_back(1 == bit_value);
|
|
}
|
|
/* Link the bit to parent block */
|
|
bitstream_manager.add_block_bits(curr_block, block_bits);
|
|
}
|
|
|
|
/* Go recursively: find all the child blocks and parse */
|
|
for (pugi::xml_node xml_child : xml_bitstream_block.children()) {
|
|
/* We only care child bitstream blocks here */
|
|
if (xml_child.name() == std::string("bitstream_block")) {
|
|
rec_read_xml_bitstream_block(xml_child, loc_data, bitstream_manager,
|
|
curr_block);
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Parse XML codes about <bitstream> to an object of Bitstream
|
|
*******************************************************************/
|
|
BitstreamManager read_xml_architecture_bitstream(const char* fname) {
|
|
vtr::ScopedStartFinishTimer timer("Read Architecture Bitstream file");
|
|
|
|
BitstreamManager bitstream_manager;
|
|
|
|
/* Parse the file */
|
|
pugi::xml_document doc;
|
|
pugiutil::loc_data loc_data;
|
|
|
|
try {
|
|
loc_data = pugiutil::load_xml(doc, fname);
|
|
|
|
/* Count the child <bitstream_block> */
|
|
|
|
pugi::xml_node xml_root =
|
|
get_single_child(doc, "bitstream_block", loc_data);
|
|
|
|
/* Find the name of the top block*/
|
|
const std::string& top_block_name =
|
|
get_attribute(xml_root, "name", loc_data).as_string();
|
|
|
|
if (top_block_name != std::string(FPGA_TOP_MODULE_NAME)) {
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_root),
|
|
"Top-level block must be named as '%s'!\n",
|
|
FPGA_TOP_MODULE_NAME);
|
|
}
|
|
|
|
/* Create the top-level block */
|
|
ConfigBlockId top_block = bitstream_manager.add_block(top_block_name);
|
|
|
|
size_t num_blks = count_children(xml_root, "bitstream_block", loc_data,
|
|
pugiutil::ReqOpt::OPTIONAL);
|
|
|
|
/* Reserve bitstream blocks in the data base */
|
|
bitstream_manager.reserve_blocks(num_blks);
|
|
|
|
/* Iterate over the children under this node,
|
|
* each child should be named after circuit_model
|
|
*/
|
|
for (pugi::xml_node xml_blk : xml_root.children()) {
|
|
/* Error out if the XML child has an invalid name! */
|
|
if (xml_blk.name() != std::string("bitstream_block")) {
|
|
bad_tag(xml_blk, loc_data, xml_root, {"bitstream_block"});
|
|
}
|
|
rec_read_xml_bitstream_block(xml_blk, loc_data, bitstream_manager,
|
|
top_block);
|
|
}
|
|
} catch (pugiutil::XmlError& e) {
|
|
archfpga_throw(fname, e.line(), "%s", e.what());
|
|
}
|
|
|
|
return bitstream_manager;
|
|
}
|
|
|
|
} /* end namespace openfpga */
|