From 7bc843b74a3a3f4f6a0097c8d3a60e9e5d60529b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Feb 2023 13:23:09 -0800 Subject: [PATCH] [lib] developing xml parser for clk arch --- .../src/io/clock_network_xml_constants.h | 21 ++ .../src/io/read_xml_clock_network.cpp | 182 ++++++++++++++++++ .../src/io/read_xml_clock_network.h | 21 ++ 3 files changed, 224 insertions(+) create mode 100644 libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h create mode 100644 libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp create mode 100644 libs/libclkarchopenfpga/src/io/read_xml_clock_network.h diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h new file mode 100644 index 000000000..8d96330b4 --- /dev/null +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -0,0 +1,21 @@ +#ifndef CLOCK_NETWORK_XML_CONSTANTS_H +#define CLOCK_NETWORK_XML_CONSTANTS_H + +/* Constants required by XML parser */ + +constexpr const char* XML_CLOCK_NETWORK_ROOT_NAME = "clock_networks"; +constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network"; +constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name"; +constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_WIDTH = "width"; +constexpr const char* XML_CLOCK_SPINE_NODE_NAME = "spine"; +constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_NAME = "name"; +constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_X = "start_x"; +constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_Y = "start_y"; +constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_X = "end_x"; +constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_Y = "end_y"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME = "switch_point"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP = "tap"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X = "x"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y = "y"; + +#endif diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp new file mode 100644 index 000000000..5f349f39e --- /dev/null +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -0,0 +1,182 @@ +/******************************************************************** + * This file includes the top-level function of this library + * which reads an XML of clock network file 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 libopenfpga util library */ +#include "openfpga_port_parser.h" + +/* Headers from libarchfpga */ +#include "arch_error.h" +#include "clock_network_xml_constants.h" +#include "read_xml_clock_network.h" +#include "read_xml_util.h" + +namespace openfpga { // Begin namespace openfpga + +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_spine_switch_point(pugi::xml_node& xml_switch_point, + const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk, const ClockSpineId& spine_id) { + if (!clk_ntwk.valid_spine_id(spine_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch_point), + "Invalid id of a clock spine!\n"); + } + + std::string tap_spine_name = + get_attribute(xml_switch_point, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP, loc_data).as_string(); + + /* Try to find an existing spine, if not, create one */ + ClockSpineId tap_spine_id = clk_ntwk.find_spine(tap_spine_name); + if (!tap_spine_id) { + tap_spine_id = clk_ntwk.create_spine(tap_spine_name); + } + + if (false == clk_ntwk.valid_spine_id(tap_spine_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch_point), + "Fail to create a clock spine!\n"); + } + + int tap_x = + get_attribute(xml_switch_point, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X, loc_data).as_int(); + int tap_y = + get_attribute(xml_switch_point, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data).as_int(); + + clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id, vtr::Point(tap_x, tap_y)); +} + +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_spine(pugi::xml_node& xml_spine, + const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) { + if (!clk_ntwk.valid_tree_id(tree_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_spine), + "Invalid id of a clock tree!\n"); + } + + std::string clk_spine_name = + get_attribute(xml_spine, XML_CLOCK_SPINE_ATTRIBUTE_NAME, loc_data).as_string(); + + /* Try to find an existing spine, if not, create one */ + ClockSpineId spine_id = clk_ntwk.find_spine(clk_spine_name); + if (!spine_id) { + spine_id = clk_ntwk.create_spine(clk_spine_name); + } + + if (false == clk_ntwk.valid_spine_id(spine_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_spine), + "Fail to create a clock spine!\n"); + } + + clk_ntwk.set_spine_parent_tree(spine_id, tree_id); + + int start_x = + get_attribute(xml_spine, XML_CLOCK_SPINE_ATTRIBUTE_START_X, loc_data).as_int(); + int start_y = + get_attribute(xml_spine, XML_CLOCK_SPINE_ATTRIBUTE_START_Y, loc_data).as_int(); + clk_ntwk.set_spine_start_point(spine_id, vtr::Point(start_x, start_y)); + + int end_x = + get_attribute(xml_spine, XML_CLOCK_SPINE_ATTRIBUTE_END_X, loc_data).as_int(); + int end_y = + get_attribute(xml_spine, XML_CLOCK_SPINE_ATTRIBUTE_END_Y, loc_data).as_int(); + clk_ntwk.set_spine_end_point(spine_id, vtr::Point(end_x, end_y)); + + for (pugi::xml_node xml_switch_point : xml_spine.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_switch_point.name() != std::string(XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME)) { + bad_tag(xml_switch_point, loc_data, xml_spine, {XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME}); + } + read_xml_clock_spine_switch_point(xml_switch_point, loc_data, clk_ntwk, spine_id); + } +} + +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_tree(pugi::xml_node& xml_clk_tree, + const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk) { + std::string clk_tree_name = + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data).as_string(); + int clk_tree_width = + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_WIDTH, loc_data).as_int(); + + /* Create a new tree in the storage */ + ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, clk_tree_width); + + if (false == clk_ntwk.valid_tree_id(tree_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree), + "Fail to create a clock tree!\n"); + } + + for (pugi::xml_node xml_spine : xml_clk_tree.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_spine.name() != std::string(XML_CLOCK_SPINE_NODE_NAME)) { + bad_tag(xml_spine, loc_data, xml_clk_tree, {XML_CLOCK_SPINE_NODE_NAME}); + } + read_xml_clock_spine(xml_spine, loc_data, clk_ntwk, tree_id); + } +} + +/******************************************************************** + * Parse XML codes about to an object of ClockNetwork + *******************************************************************/ +ClockNetwork read_xml_clock_network(const char* fname) { + vtr::ScopedStartFinishTimer timer("Read clock network"); + + ClockNetwork clk_ntwk; + + /* 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_CLOCK_NETWORK_ROOT_NAME, loc_data); + + size_t num_trees = + std::distance(xml_root.children().begin(), xml_root.children().end()); + + /* Count the total number of spines */ + size_t num_spines = 0; + for (pugi::xml_node xml_tree : xml_root.children()) { + num_spines += + std::distance(xml_tree.children().begin(), xml_tree.children().end()); + } + + /* Reserve memory space */ + clk_ntwk.reserve_trees(num_trees); + clk_ntwk.reserve_spines(num_spines); + + for (pugi::xml_node xml_tree : xml_root.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_tree.name() != std::string(XML_CLOCK_NETWORK_NODE_NAME)) { + bad_tag(xml_tree, loc_data, xml_root, {XML_CLOCK_NETWORK_NODE_NAME}); + } + read_xml_clock_tree(xml_tree, loc_data, clk_ntwk); + } + } catch (pugiutil::XmlError& e) { + archfpga_throw(fname, e.line(), "%s", e.what()); + } + + return clk_ntwk; +} + +} // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.h b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.h new file mode 100644 index 000000000..29e2f8f06 --- /dev/null +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.h @@ -0,0 +1,21 @@ +#ifndef READ_XML_CLOCK_NETWORK_H +#define READ_XML_CLOCK_NETWORK_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "clock_network.h" +#include "pugixml.hpp" +#include "pugixml_util.hpp" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +namespace openfpga { // Begin namespace openfpga + +ClockNetwork read_xml_clock_network(const char* fname); + +} // End of namespace openfpga + +#endif