/******************************************************************** * This file includes the top-level function of this library * which reads an XML of a fabric key to the associated * data structures *******************************************************************/ #include /* 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 "read_xml_util.h" #include "openfpga_reserved_words.h" #include "read_xml_arch_bitstream.h" /* begin namespace openfpga */ namespace openfpga { /******************************************************************** * Parse XML codes of a 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 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 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 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 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 */ 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 */