From 675a59ecb8fa523fa0209c6e633207aaeb09731a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 20 Jun 2020 18:25:17 -0600 Subject: [PATCH] Move fpga_bitstream to the libopenfpga library and add XML reader --- libopenfpga/CMakeLists.txt | 1 + libopenfpga/libfpgabitstream/CMakeLists.txt | 35 ++++ .../src}/arch_bitstream_writer.cpp | 92 +++++---- .../src}/arch_bitstream_writer.h | 3 +- .../src}/bitstream_manager.cpp | 37 +++- .../libfpgabitstream/src}/bitstream_manager.h | 25 ++- .../src}/bitstream_manager_fwd.h | 0 .../src}/bitstream_manager_utils.cpp | 0 .../src}/bitstream_manager_utils.h | 0 .../src/read_xml_arch_bitstream.cpp | 181 ++++++++++++++++++ .../src/read_xml_arch_bitstream.h | 21 ++ .../test/test_arch_bitstream.cpp | 33 ++++ .../libopenfpgautil/src/openfpga_digest.cpp | 16 ++ .../libopenfpgautil/src/openfpga_digest.h | 3 + .../src}/openfpga_reserved_words.h | 5 + openfpga/CMakeLists.txt | 1 + openfpga/src/base/openfpga_bitstream.cpp | 3 +- openfpga/src/base/openfpga_naming.cpp | 6 +- .../fpga_bitstream/build_device_bitstream.cpp | 1 + .../fpga_bitstream/build_grid_bitstream.cpp | 36 +++- .../src/fpga_bitstream/build_grid_bitstream.h | 2 + .../build_routing_bitstream.cpp | 25 ++- 22 files changed, 455 insertions(+), 71 deletions(-) create mode 100644 libopenfpga/libfpgabitstream/CMakeLists.txt rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/arch_bitstream_writer.cpp (70%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/arch_bitstream_writer.h (87%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/bitstream_manager.cpp (87%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/bitstream_manager.h (90%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/bitstream_manager_fwd.h (100%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/bitstream_manager_utils.cpp (100%) rename {openfpga/src/fpga_bitstream => libopenfpga/libfpgabitstream/src}/bitstream_manager_utils.h (100%) create mode 100644 libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp create mode 100644 libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.h create mode 100644 libopenfpga/libfpgabitstream/test/test_arch_bitstream.cpp rename {openfpga/src/base => libopenfpga/libopenfpgautil/src}/openfpga_reserved_words.h (93%) diff --git a/libopenfpga/CMakeLists.txt b/libopenfpga/CMakeLists.txt index ec3299198..92d25522a 100644 --- a/libopenfpga/CMakeLists.txt +++ b/libopenfpga/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory(libopenfpgashell) add_subdirectory(libarchopenfpga) add_subdirectory(libopenfpgautil) add_subdirectory(libfabrickey) +add_subdirectory(libfpgabitstream) diff --git a/libopenfpga/libfpgabitstream/CMakeLists.txt b/libopenfpga/libfpgabitstream/CMakeLists.txt new file mode 100644 index 000000000..ce1a37d31 --- /dev/null +++ b/libopenfpga/libfpgabitstream/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.9) + +project("libfpgabitstream") + +file(GLOB_RECURSE EXEC_SOURCES test/*.cpp) +file(GLOB_RECURSE LIB_SOURCES src/*.cpp) +file(GLOB_RECURSE LIB_HEADERS src/*.h) +files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) + +#Remove test executable from library +list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES}) + +#Create the library +add_library(libfpgabitstream STATIC + ${LIB_HEADERS} + ${LIB_SOURCES}) +target_include_directories(libfpgabitstream PUBLIC ${LIB_INCLUDE_DIRS}) +set_target_properties(libfpgabitstream PROPERTIES PREFIX "") #Avoid extra 'lib' prefix + +#Specify link-time dependancies +target_link_libraries(libfpgabitstream + libopenfpgautil + libarchopenfpga + libvtrutil + libpugixml + libpugiutil) + +#Create the test executable +foreach(testsourcefile ${EXEC_SOURCES}) + # Use a simple string replace, to cut off .cpp. + get_filename_component(testname ${testsourcefile} NAME_WE) + add_executable(${testname} ${testsourcefile}) + # Make sure the library is linked to each test executable + target_link_libraries(${testname} libfpgabitstream) +endforeach(testsourcefile ${EXEC_SOURCES}) diff --git a/openfpga/src/fpga_bitstream/arch_bitstream_writer.cpp b/libopenfpga/libfpgabitstream/src/arch_bitstream_writer.cpp similarity index 70% rename from openfpga/src/fpga_bitstream/arch_bitstream_writer.cpp rename to libopenfpga/libfpgabitstream/src/arch_bitstream_writer.cpp index 6b3afdf4b..ebb0a3129 100644 --- a/openfpga/src/fpga_bitstream/arch_bitstream_writer.cpp +++ b/libopenfpga/libfpgabitstream/src/arch_bitstream_writer.cpp @@ -14,7 +14,7 @@ /* Headers from openfpgautil library */ #include "openfpga_digest.h" -#include "openfpga_naming.h" +#include "openfpga_reserved_words.h" #include "bitstream_manager_utils.h" #include "arch_bitstream_writer.h" @@ -51,70 +51,86 @@ void write_bitstream_xml_file_head(std::fstream& fp) { *******************************************************************/ static void rec_write_block_bitstream_to_xml_file(std::fstream& fp, - const AtomContext& atom_ctx, const BitstreamManager& bitstream_manager, - const ConfigBlockId& block) { + const ConfigBlockId& block, + const size_t& hierarchy_level) { valid_file_stream(fp); + /* Write the bits of this block */ + write_tab_to_file(fp, hierarchy_level); + fp << "" << std::endl; + /* Dive to child blocks if this block has any */ for (const ConfigBlockId& child_block : bitstream_manager.block_children(block)) { - rec_write_block_bitstream_to_xml_file(fp, atom_ctx, bitstream_manager, child_block); + rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, child_block, hierarchy_level + 1); } if (0 == bitstream_manager.block_bits(block).size()) { + write_tab_to_file(fp, hierarchy_level); + fp << "" <" << std::endl; - std::vector block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, block); /* Output hierarchy of this parent*/ - fp << "\t" << std::endl; + write_tab_to_file(fp, hierarchy_level + 1); + fp << "" << std::endl; size_t hierarchy_counter = 0; for (const ConfigBlockId& temp_block : block_hierarchy) { - fp << "\t\t" << std::endl; hierarchy_counter++; } - fp << "\t" << std::endl; + write_tab_to_file(fp, hierarchy_level + 1); + fp << "" << std::endl; /* Output input/output nets if there are any */ if (false == bitstream_manager.block_input_net_ids(block).empty()) { - fp << "\t\n"; - fp << "\t\t"; - for (const AtomNetId& net : bitstream_manager.block_input_net_ids(block)) { - if (false == atom_ctx.nlist.valid_net_id(net)) { - fp << "\tunmapped"; - } else { - VTR_ASSERT_SAFE(true == atom_ctx.nlist.valid_net_id(net)); - fp << "\t" << atom_ctx.nlist.net_name(net); - } + write_tab_to_file(fp, hierarchy_level + 1); + fp << "\n"; + size_t path_counter = 0; + for (const std::string& net : bitstream_manager.block_input_net_ids(block)) { + write_tab_to_file(fp, hierarchy_level + 2); + fp << ""; + + path_counter++; } fp << "\n"; - fp << "\t\n"; + write_tab_to_file(fp, hierarchy_level + 1); + fp << "\n"; } if (false == bitstream_manager.block_output_net_ids(block).empty()) { - fp << "\t\n"; - fp << "\t\t"; - for (const AtomNetId& net : bitstream_manager.block_output_net_ids(block)) { - if (false == atom_ctx.nlist.valid_net_id(net)) { - fp << "\tunmapped"; - } else { - VTR_ASSERT_SAFE(true == atom_ctx.nlist.valid_net_id(net)); - fp << "\t" << atom_ctx.nlist.net_name(net); - } + write_tab_to_file(fp, hierarchy_level + 1); + fp << "\n"; + size_t path_counter = 0; + for (const std::string& net : bitstream_manager.block_output_net_ids(block)) { + write_tab_to_file(fp, hierarchy_level + 2); + fp << ""; + + path_counter++; } fp << "\n"; - fp << "\t\n"; + write_tab_to_file(fp, hierarchy_level + 1); + fp << "\n"; } /* Output child bits under this block */ size_t bit_counter = 0; - fp << "\t" << std::endl; for (const ConfigBitId& child_bit : bitstream_manager.block_bits(block)) { - fp << "\t\t" << std::endl; bit_counter++; } - fp << "\t" << std::endl; + write_tab_to_file(fp, hierarchy_level + 1); + fp << "" << std::endl; + write_tab_to_file(fp, hierarchy_level); fp << "" < top_block = find_bitstream_manager_top_blocks(bitstream_manager); /* Make sure we have only 1 top block and its name matches the top module */ @@ -175,7 +193,7 @@ void write_arch_independent_bitstream_to_xml_file(const BitstreamManager& bitstr VTR_ASSERT(0 == top_block_name.compare(bitstream_manager.block_name(top_block[0]))); /* Write bitstream, block by block, in a recursive way */ - rec_write_block_bitstream_to_xml_file(fp, atom_ctx, bitstream_manager, top_block[0]); + rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, top_block[0], 0); /* Close file handler */ fp.close(); diff --git a/openfpga/src/fpga_bitstream/arch_bitstream_writer.h b/libopenfpga/libfpgabitstream/src/arch_bitstream_writer.h similarity index 87% rename from openfpga/src/fpga_bitstream/arch_bitstream_writer.h rename to libopenfpga/libfpgabitstream/src/arch_bitstream_writer.h index 69ee1f5a2..91f9e271d 100644 --- a/openfpga/src/fpga_bitstream/arch_bitstream_writer.h +++ b/libopenfpga/libfpgabitstream/src/arch_bitstream_writer.h @@ -5,7 +5,6 @@ * Include header files that are required by function declaration *******************************************************************/ #include -#include "vpr_context.h" #include "bitstream_manager.h" /******************************************************************** @@ -16,7 +15,7 @@ namespace openfpga { void write_arch_independent_bitstream_to_xml_file(const BitstreamManager& bitstream_manager, - const AtomContext& clustering_ctx, + const std::string& top_block_name, const std::string& fname); } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/bitstream_manager.cpp b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp similarity index 87% rename from openfpga/src/fpga_bitstream/bitstream_manager.cpp rename to libopenfpga/libfpgabitstream/src/bitstream_manager.cpp index 15946c292..66b4d1f23 100644 --- a/openfpga/src/fpga_bitstream/bitstream_manager.cpp +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp @@ -115,14 +115,14 @@ int BitstreamManager::block_path_id(const ConfigBlockId& block_id) const { return block_path_ids_[block_id]; } -std::vector BitstreamManager::block_input_net_ids(const ConfigBlockId& block_id) const { +std::vector BitstreamManager::block_input_net_ids(const ConfigBlockId& block_id) const { /* Ensure the input ids are valid */ VTR_ASSERT(true == valid_block_id(block_id)); return block_input_net_ids_[block_id]; } -std::vector BitstreamManager::block_output_net_ids(const ConfigBlockId& block_id) const { +std::vector BitstreamManager::block_output_net_ids(const ConfigBlockId& block_id) const { /* Ensure the input ids are valid */ VTR_ASSERT(true == valid_block_id(block_id)); @@ -143,11 +143,22 @@ ConfigBitId BitstreamManager::add_bit(const bool& bit_value) { return bit; } -ConfigBlockId BitstreamManager::add_block(const std::string& block_name) { +void BitstreamManager::reserve_blocks(const size_t& num_blocks) { + block_ids_.reserve(num_blocks); + block_names_.reserve(num_blocks); + block_bit_ids_.reserve(num_blocks); + block_path_ids_.reserve(num_blocks); + block_input_net_ids_.reserve(num_blocks); + block_output_net_ids_.reserve(num_blocks); + parent_block_ids_.reserve(num_blocks); + child_block_ids_.reserve(num_blocks); +} + +ConfigBlockId BitstreamManager::create_block() { ConfigBlockId block = ConfigBlockId(block_ids_.size()); /* Add a new bit, and allocate associated data structures */ block_ids_.push_back(block); - block_names_.push_back(block_name); + block_names_.emplace_back(); block_bit_ids_.emplace_back(); block_path_ids_.push_back(-2); block_input_net_ids_.emplace_back(); @@ -158,6 +169,20 @@ ConfigBlockId BitstreamManager::add_block(const std::string& block_name) { return block; } +ConfigBlockId BitstreamManager::add_block(const std::string& block_name) { + ConfigBlockId block = create_block(); + set_block_name(block, block_name); + + return block; +} + +void BitstreamManager::set_block_name(const ConfigBlockId& block_id, + const std::string& block_name) { + /* Ensure the input ids are valid */ + VTR_ASSERT(true == valid_block_id(block_id)); + block_names_[block_id] = block_name; +} + void BitstreamManager::add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block) { /* Ensure the input ids are valid */ VTR_ASSERT(true == valid_block_id(parent_block)); @@ -199,7 +224,7 @@ void BitstreamManager::add_path_id_to_block(const ConfigBlockId& block, const in } void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block, - const AtomNetId& input_net_id) { + const std::string& input_net_id) { /* Ensure the input ids are valid */ VTR_ASSERT(true == valid_block_id(block)); @@ -208,7 +233,7 @@ void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block, } void BitstreamManager::add_output_net_id_to_block(const ConfigBlockId& block, - const AtomNetId& output_net_id) { + const std::string& output_net_id) { /* Ensure the input ids are valid */ VTR_ASSERT(true == valid_block_id(block)); diff --git a/openfpga/src/fpga_bitstream/bitstream_manager.h b/libopenfpga/libfpgabitstream/src/bitstream_manager.h similarity index 90% rename from openfpga/src/fpga_bitstream/bitstream_manager.h rename to libopenfpga/libfpgabitstream/src/bitstream_manager.h index 0621a214e..71bd63b43 100644 --- a/openfpga/src/fpga_bitstream/bitstream_manager.h +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.h @@ -38,9 +38,6 @@ #include #include "vtr_vector.h" -/* Header files from vpr library */ -#include "atom_netlist_fwd.h" - #include "bitstream_manager_fwd.h" /* begin namespace openfpga */ @@ -89,18 +86,28 @@ class BitstreamManager { int block_path_id(const ConfigBlockId& block_id) const; /* Find input net ids of a block */ - std::vector block_input_net_ids(const ConfigBlockId& block_id) const; + std::vector block_input_net_ids(const ConfigBlockId& block_id) const; /* Find input net ids of a block */ - std::vector block_output_net_ids(const ConfigBlockId& block_id) const; + std::vector block_output_net_ids(const ConfigBlockId& block_id) const; public: /* Public Mutators */ /* Add a new configuration bit to the bitstream manager */ ConfigBitId add_bit(const bool& bit_value); + /* Reserve memory for a number of clocks */ + void reserve_blocks(const size_t& num_blocks); + + /* Create a new block of configuration bits */ + ConfigBlockId create_block(); + /* Add a new block of configuration bits to the bitstream manager */ ConfigBlockId add_block(const std::string& block_name); + /* Set a name for a block */ + void set_block_name(const ConfigBlockId& block_id, + const std::string& block_name); + /* Set a block as a child block of another */ void add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block); @@ -111,10 +118,10 @@ class BitstreamManager { void add_path_id_to_block(const ConfigBlockId& block, const int& path_id); /* Add an input net id to a block */ - void add_input_net_id_to_block(const ConfigBlockId& block, const AtomNetId& input_net_id); + void add_input_net_id_to_block(const ConfigBlockId& block, const std::string& input_net_id); /* Add an output net id to a block */ - void add_output_net_id_to_block(const ConfigBlockId& block, const AtomNetId& output_net_id); + void add_output_net_id_to_block(const ConfigBlockId& block, const std::string& output_net_id); /* Add share configuration bits to a configuration bit */ void add_shared_config_bit_values(const ConfigBitId& bit, const std::vector& shared_config_bits); @@ -161,8 +168,8 @@ class BitstreamManager { * -Bitstream manager will NOT check if the id is good for bitstream builders * It just store the results */ - vtr::vector> block_input_net_ids_; - vtr::vector> block_output_net_ids_; + vtr::vector> block_input_net_ids_; + vtr::vector> block_output_net_ids_; /* Unique id of a bit in the Bitstream */ vtr::vector bit_ids_; diff --git a/openfpga/src/fpga_bitstream/bitstream_manager_fwd.h b/libopenfpga/libfpgabitstream/src/bitstream_manager_fwd.h similarity index 100% rename from openfpga/src/fpga_bitstream/bitstream_manager_fwd.h rename to libopenfpga/libfpgabitstream/src/bitstream_manager_fwd.h diff --git a/openfpga/src/fpga_bitstream/bitstream_manager_utils.cpp b/libopenfpga/libfpgabitstream/src/bitstream_manager_utils.cpp similarity index 100% rename from openfpga/src/fpga_bitstream/bitstream_manager_utils.cpp rename to libopenfpga/libfpgabitstream/src/bitstream_manager_utils.cpp diff --git a/openfpga/src/fpga_bitstream/bitstream_manager_utils.h b/libopenfpga/libfpgabitstream/src/bitstream_manager_utils.h similarity index 100% rename from openfpga/src/fpga_bitstream/bitstream_manager_utils.h rename to libopenfpga/libfpgabitstream/src/bitstream_manager_utils.h diff --git a/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp new file mode 100644 index 000000000..e7bcb726c --- /dev/null +++ b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp @@ -0,0 +1,181 @@ +/******************************************************************** + * 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, "name", loc_data).as_string(); + VTR_ASSERT((size_t)id < input_nets.size()); + input_nets[id] = net_name; + } + + for (const std::string& input_net : input_nets) { + bitstream_manager.add_input_net_id_to_block(curr_block, input_net); + } + } + + /* 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, "name", loc_data).as_string(); + VTR_ASSERT((size_t)id < output_nets.size()); + output_nets[id] = net_name; + } + + for (const std::string& output_net : output_nets) { + bitstream_manager.add_output_net_id_to_block(curr_block, output_net); + } + } + + /* 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).as_int(); + if (-2 < path_id) { + bitstream_manager.add_path_id_to_block(curr_block, path_id); + } + + /* Find the child paths/nets */ + 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(); + ConfigBitId bit = bitstream_manager.add_bit(1 == bit_value); + /* Link the bit to parent block */ + bitstream_manager.add_bit_to_block(curr_block, bit); + } + } + + /* 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_bitstream_block, 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 */ + diff --git a/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.h b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.h new file mode 100644 index 000000000..0f24c802b --- /dev/null +++ b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.h @@ -0,0 +1,21 @@ +#ifndef READ_XML_ARCH_BITSTREAM_H +#define READ_XML_ARCH_BITSTREAM_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "pugixml_util.hpp" +#include "pugixml.hpp" +#include "bitstream_manager.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ +/* begin namespace openfpga */ +namespace openfpga { + +BitstreamManager read_xml_architecture_bitstream(const char* fname); + +} /* end namespace openfpga */ + +#endif diff --git a/libopenfpga/libfpgabitstream/test/test_arch_bitstream.cpp b/libopenfpga/libfpgabitstream/test/test_arch_bitstream.cpp new file mode 100644 index 000000000..05915c1ed --- /dev/null +++ b/libopenfpga/libfpgabitstream/test/test_arch_bitstream.cpp @@ -0,0 +1,33 @@ +/******************************************************************** + * Unit test functions to validate the correctness of + * 1. parser of data structures + * 2. writer of data structures + *******************************************************************/ +/* Headers from vtrutils */ +#include "vtr_assert.h" +#include "vtr_log.h" + +/* Headers from fabric key */ +#include "read_xml_arch_bitstream.h" +#include "arch_bitstream_writer.h" + +int main(int argc, const char** argv) { + /* Ensure we have only one or two argument */ + VTR_ASSERT((2 == argc) || (3 == argc)); + + /* Parse the bitstream from an XML file */ + openfpga::BitstreamManager test_bitstream = openfpga::read_xml_architecture_bitstream(argv[1]); + VTR_LOG("Read the bitstream from an XML file: %s.\n", + argv[1]); + + /* Output the circuit library to an XML file + * This is optional only used when there is a second argument + */ + if (3 <= argc) { + openfpga::write_arch_independent_bitstream_to_xml_file(test_bitstream, std::string("fpga_top"), argv[2]); + VTR_LOG("Echo the bitstream to an XML file: %s.\n", + argv[2]); + } +} + + diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp index 00cbbe1e3..edb0bd5cc 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp @@ -251,4 +251,20 @@ bool write_space_to_file(std::fstream& fp, return true; } +/******************************************************************** + * Write a number of tab to a file + ********************************************************************/ +bool write_tab_to_file(std::fstream& fp, + const size_t& num_tab) { + if (false == valid_file_stream(fp)) { + return false; + } + + for (size_t i = 0; i < num_tab; ++i) { + fp << "\t"; + } + + return true; +} + } /* namespace openfpga ends */ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.h b/libopenfpga/libopenfpgautil/src/openfpga_digest.h index a28b2c4d0..c1a80ce99 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.h @@ -28,6 +28,9 @@ void create_directory(const std::string& dir_path, const bool& recursive = true) bool write_space_to_file(std::fstream& fp, const size_t& num_space); +bool write_tab_to_file(std::fstream& fp, + const size_t& num_tab); + } /* namespace openfpga ends */ #endif diff --git a/openfpga/src/base/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h similarity index 93% rename from openfpga/src/base/openfpga_reserved_words.h rename to libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h index a9b31f64e..e6b89a10b 100644 --- a/openfpga/src/base/openfpga_reserved_words.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h @@ -10,6 +10,11 @@ /* begin namespace openfpga */ namespace openfpga { +/* Top-level module name */ +constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top"; + +constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out"; + /* IO PORT */ /* Prefix of global input, output and inout ports of FPGA fabric */ constexpr char* GIO_INOUT_PREFIX = "gfpga_pad_"; diff --git a/openfpga/CMakeLists.txt b/openfpga/CMakeLists.txt index 7578630af..609602e1a 100644 --- a/openfpga/CMakeLists.txt +++ b/openfpga/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(libopenfpga libopenfpgashell libopenfpgautil libfabrickey + libfpgabitstream libini libvtrutil libvpr8) diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp index 1a6345040..ea5b0abff 100644 --- a/openfpga/src/base/openfpga_bitstream.cpp +++ b/openfpga/src/base/openfpga_bitstream.cpp @@ -10,6 +10,7 @@ /* Headers from openfpgautil library */ #include "openfpga_digest.h" +#include "openfpga_reserved_words.h" #include "build_device_bitstream.h" #include "arch_bitstream_writer.h" @@ -43,7 +44,7 @@ int fpga_bitstream(OpenfpgaContext& openfpga_ctx, create_directory(src_dir_path); write_arch_independent_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(), - g_vpr_ctx.atom(), + std::string(FPGA_TOP_MODULE_NAME), cmd_context.option_value(cmd, opt_file)); } diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index 44eb2c8cd..38f20f0ee 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -705,7 +705,7 @@ std::string generate_configuration_chain_tail_name() { * TODO: This could be replaced as a constexpr string *********************************************************************/ std::string generate_configurable_memory_data_out_name() { - return std::string("mem_out"); + return std::string(CONFIGURABLE_MEMORY_DATA_OUT_NAME); } /********************************************************************* @@ -1409,7 +1409,7 @@ std::string generate_fpga_global_io_port_name(const std::string& prefix, * We give a fixed name here, because it is independent from benchmark file ********************************************************************/ std::string generate_fpga_top_module_name() { - return std::string("fpga_top"); + return std::string(FPGA_TOP_MODULE_NAME); } /********************************************************************* @@ -1418,7 +1418,7 @@ std::string generate_fpga_top_module_name() { * We give a fixed name here, because it is independent from benchmark file ********************************************************************/ std::string generate_fpga_top_netlist_name(const std::string& postfix) { - return std::string("fpga_top" + postfix); + return std::string(FPGA_TOP_MODULE_NAME + postfix); } /********************************************************************* diff --git a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp index a6e0a6bf3..6d13dfe6f 100644 --- a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp @@ -60,6 +60,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx, openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(), vpr_ctx.device().grid, + vpr_ctx.atom(), openfpga_ctx.vpr_device_annotation(), openfpga_ctx.vpr_clustering_annotation(), openfpga_ctx.vpr_placement_annotation(), diff --git a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp index fd09e3581..c3de6cbfe 100644 --- a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp @@ -128,6 +128,7 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, const PhysicalPb& physical_pb, t_pb_graph_pin* des_pb_graph_pin, @@ -221,9 +222,17 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag /* Record path ids, input and output nets */ bitstream_manager.add_path_id_to_block(mux_mem_block, mux_input_pin_id); for (const AtomNetId& input_net : input_nets) { - bitstream_manager.add_input_net_id_to_block(mux_mem_block, input_net); + if (true == atom_ctx.nlist.valid_net_id(input_net)) { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_net)); + } else { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped")); + } + } + if (true == atom_ctx.nlist.valid_net_id(output_net)) { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_net)); + } else { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped")); } - bitstream_manager.add_output_net_id_to_block(mux_mem_block, output_net); break; } @@ -245,6 +254,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, t_pb_graph_node* physical_pb_graph_node, const PhysicalPb& physical_pb, @@ -256,7 +266,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) { build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, physical_pb, &(physical_pb_graph_node->input_pins[iport][ipin]), physical_mode); @@ -268,7 +278,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) { build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, physical_pb, &(physical_pb_graph_node->output_pins[iport][ipin]), physical_mode); @@ -280,7 +290,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) { build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, physical_pb, &(physical_pb_graph_node->clock_pins[iport][ipin]), physical_mode); @@ -305,6 +315,7 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, t_pb_graph_node* physical_pb_graph_node, const PhysicalPb& physical_pb, @@ -327,7 +338,7 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager, */ build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, physical_pb_graph_node, physical_pb, CIRCUIT_PB_PORT_OUTPUT, physical_mode); @@ -346,13 +357,13 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager, /* For each child_pb_graph_node input pins*/ build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, child_pb_graph_node, physical_pb, CIRCUIT_PB_PORT_INPUT, physical_mode); /* For clock pins, we should do the same work */ build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block, module_manager, circuit_lib, mux_lib, - device_annotation, + atom_ctx, device_annotation, child_pb_graph_node, physical_pb, CIRCUIT_PB_PORT_CLOCK, physical_mode); } @@ -478,6 +489,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, const e_side& border_side, const PhysicalPb& physical_pb, @@ -508,6 +520,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager, /* Go recursively */ rec_build_physical_block_bitstream(bitstream_manager, pb_configurable_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, border_side, physical_pb, child_pb, @@ -552,6 +565,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager, /* Generate the bitstream for the interconnection in this physical block */ build_physical_block_interc_bitstream(bitstream_manager, pb_configurable_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, physical_pb_graph_node, physical_pb, physical_mode); @@ -569,6 +583,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, const VprClusteringAnnotation& cluster_annotation, const VprPlacementAnnotation& place_annotation, @@ -603,6 +618,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager, /* Recursively traverse the pb_graph and generate bitstream */ rec_build_physical_block_bitstream(bitstream_manager, grid_configurable_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, border_side, PhysicalPb(), PhysicalPbId::INVALID(), lb_type->pb_graph_head, z); @@ -617,6 +633,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager, /* Recursively traverse the pb_graph and generate bitstream */ rec_build_physical_block_bitstream(bitstream_manager, grid_configurable_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, border_side, phy_pb, top_pb_id, pb_graph_head, z); } @@ -637,6 +654,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, const DeviceGrid& grids, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, const VprClusteringAnnotation& cluster_annotation, const VprPlacementAnnotation& place_annotation, @@ -662,6 +680,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager, vtr::Point grid_coord(ix, iy); build_physical_block_bitstream(bitstream_manager, top_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, cluster_annotation, place_annotation, grids, grid_coord, NUM_SIDES); @@ -709,6 +728,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager, } build_physical_block_bitstream(bitstream_manager, top_block, module_manager, circuit_lib, mux_lib, + atom_ctx, device_annotation, cluster_annotation, place_annotation, grids, io_coordinate, io_side); diff --git a/openfpga/src/fpga_bitstream/build_grid_bitstream.h b/openfpga/src/fpga_bitstream/build_grid_bitstream.h index 6f192a9b7..be2425c5a 100644 --- a/openfpga/src/fpga_bitstream/build_grid_bitstream.h +++ b/openfpga/src/fpga_bitstream/build_grid_bitstream.h @@ -5,6 +5,7 @@ * Include header files that are required by function declaration *******************************************************************/ #include +#include "vpr_context.h" #include "device_grid.h" #include "bitstream_manager.h" #include "module_manager.h" @@ -27,6 +28,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, const DeviceGrid& grids, + const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation, const VprClusteringAnnotation& cluster_annotation, const VprPlacementAnnotation& place_annotation, diff --git a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp index b396385a0..457b1d004 100644 --- a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp @@ -107,10 +107,18 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager, bitstream_manager.add_path_id_to_block(mux_mem_block, path_id); for (const ClusterNetId& input_net : input_nets) { AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net); - bitstream_manager.add_input_net_id_to_block(mux_mem_block, input_atom_net); + if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_atom_net)); + } else { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped")); + } } AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net); - bitstream_manager.add_output_net_id_to_block(mux_mem_block, output_atom_net); + if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net)); + } else { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped")); + } } /******************************************************************** @@ -290,13 +298,20 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager, bitstream_manager.add_path_id_to_block(mux_mem_block, path_id); for (const ClusterNetId& input_net : input_nets) { AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net); - bitstream_manager.add_input_net_id_to_block(mux_mem_block, input_atom_net); + if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_atom_net)); + } else { + bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped")); + } } AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net); - bitstream_manager.add_output_net_id_to_block(mux_mem_block, output_atom_net); + if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net)); + } else { + bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped")); + } } - /******************************************************************** * This function generates bitstream for an interconnection, * i.e., a routing multiplexer, in a Connection Block