diff --git a/dev/pylint_check.py b/dev/pylint_check.py index 6e0987a7f84..96e78a2393d 100755 --- a/dev/pylint_check.py +++ b/dev/pylint_check.py @@ -60,6 +60,7 @@ repo_path / "doc/_exts/rrgraphdomain/__init__.py", repo_path / "doc/_exts/sdcdomain/__init__.py", repo_path / "doc/_exts/archdomain/__init__.py", + repo_path / "doc/_exts/constraintsdomain/__init__.py", repo_path / "vpr/scripts/compare_timing_reports.py", repo_path / "vpr/scripts/profile/util.py", repo_path / "vpr/scripts/profile/parse_and_plot_detailed.py", diff --git a/doc/_exts/constraintsdomain/__init__.py b/doc/_exts/constraintsdomain/__init__.py new file mode 100644 index 00000000000..2c78b148045 --- /dev/null +++ b/doc/_exts/constraintsdomain/__init__.py @@ -0,0 +1,27 @@ +from sphinxcontrib.domaintools import custom_domain +from sphinx.util.docfields import * + + +def setup(app): + app.add_domain( + custom_domain( + "VPRConstraintsDomain", + name="vpr_constraints", + label="Place and Route Constraints", + elements=dict( + tag=dict( + objname="Attribute", + indextemplate="pair: %s; Tag Attribute", + fields=[ + GroupedField( + "required_parameter", label="Required Attributes", names=["req_param"] + ), + GroupedField( + "optional_parameter", label="Optional Attributes", names=["opt_param"] + ), + Field("required", label="Tag Required", names=["required"]), + ], + ), + ), + ) + ) diff --git a/doc/src/arch/reference.rst b/doc/src/arch/reference.rst index 404802511e9..8a0510c2772 100644 --- a/doc/src/arch/reference.rst +++ b/doc/src/arch/reference.rst @@ -1955,7 +1955,7 @@ Wire Segments The content within the ```` tag consists of a group of ```` tags. The ```` tag and its contents are described below. -.. arch:tag:: content +.. arch:tag:: content :opt_param axis: @@ -1975,6 +1975,10 @@ The ```` tag and its contents are described below. .. note:: ``longline`` is only supported on with ``bidir`` routing + :opt_param res_type: + Specifies whether the segment belongs to the general or a clock routing network. If this tag is not specified, the resource type for + the segment is considered to be GENERAL (i.e. regular routing). + :req_param freq: The supply of routing tracks composed of this type of segment. VPR automatically determines the percentage of tracks for each segment type by taking the frequency for the type specified and dividing with the sum of all frequencies. @@ -2092,6 +2096,7 @@ Specifing a Clock Architecture The element ```` contains three sub-elements that collectively describe the clock architecture: the wiring parameters ````, the clock distribution ````, and the clock connectivity ````. + .. note:: The clock network architecture defined in this structure is assigned the fixed default name ``"clock_network"``. When the user wants to specify a net to be routed through the defined clock architecture using a :ref:`global routing constraints file `, the network name attribute in the constraint tag must be set to ``"clock_network"``. .. _clock_arch_example: diff --git a/doc/src/conf.py b/doc/src/conf.py index 99458f6e3f4..fe2fc79f5b1 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -45,6 +45,7 @@ "sphinx_markdown_tables", "sdcdomain", "archdomain", + "constraintsdomain", "rrgraphdomain", "myst_parser", "sphinx.ext.autodoc", diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index 9647dcfe496..af611dad5c4 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -360,11 +360,11 @@ Use the options below to override this default naming behaviour. .. option:: --read_vpr_constraints - Reads the :ref:`floorplanning constraints ` that packing and placement must respect from the specified XML file. + Reads the :ref:`VPR constraints ` that the flow must respect from the specified XML file. .. option:: --write_vpr_constraints - Writes out new :ref:`floorplanning constraints ` based on current placement to the specified XML file. + Writes out new :ref:`floorplanning constraints ` based on the current placement to the specified XML file. .. option:: --read_router_lookahead diff --git a/doc/src/vpr/global_routing_constraints.rst b/doc/src/vpr/global_routing_constraints.rst new file mode 100644 index 00000000000..2024524b85d --- /dev/null +++ b/doc/src/vpr/global_routing_constraints.rst @@ -0,0 +1,108 @@ +Global Routing Constraints +========================== +.. _global_routing_constraints: + +VPR allows users to designate specific nets in the input netlist as global and define the routing model for the global nets by utilizing a VPR constraints XML file. These routing constraints for global nets are specified inside the VPR constraints file in XML format, as described in the following section. + +A Global Routing Constraints File Example +------------------------------------------ + +.. code-block:: xml + :caption: An example of a global routing constraints file in XML format. + :linenos: + + + + + + + + +Global Routing Constraints File Format +--------------------------------------- +.. _global_routing_constraints_file_format: + +.. vpr_constraints:tag:: content + + Content inside this tag contains a group of ```` tags that specify the global nets and their assigned routing methods. + +.. vpr_constraints:tag:: + + :req_param name: The name of the net to be assigned as global. Regular expressions are also accepted. + :req_param route_model: The route model for the specified net. + + * ``ideal``: The net is not routed. There would be no delay for the global net. + + * ``route``: The net is routed similarly to other nets using generic routing resources. + + * ``dedicated_network``: The net will be routed through a dedicated clock network. + + :req_param network_name: The name of the clock network through which the net is routed. This parameter is required when ``route_model="dedicated_network"``. + + +Dedicated Clock Networks +-------------------------- + +Users can define a clock architecture in two ways. First, through the architecture description outlined in section :ref:`Clocks `. By using the ```` tag, users can establish a single clock architecture with the fixed default name "clock_network". When routing a net through the dedicated network described with this tag, the network name must be set to ``"clock_network"``. + +Alternatively, users can define a custom clock network architecture by inputting a custom resource routing graph. In this approach, users can specify various clock routing networks, such as a global clock network and multiple regional clock networks. There are three main considerations for defining a clock network through a custom RR graph definition, as described in the following sections. + +Virtual Sinks Definition for Clock Networks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +For VPR to route global nets within defined clock networks, there needs to be a virtual sink node defined in the RR graph per each clock network. This virtual sink, which is of the type ``"SINK"``, must have incoming edges from all drive points of the clock network. The two-stage router used for global net routing will initially route to the virtual sink (which serves as the entry point of the clock network) in the first stage and then from the entry point to the actual sink of the net in the second stage. + +To indicate that a node represents a clock network virtual sink, users can utilize the ``"clk_res_type"`` attribute on a node setting it to ``"VIRTUAL_SINK"``. + +Distinguishing Between Clock Networks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Given the support for multiple clock networks, VPR needs a way to distinguish between different virtual sinks belonging to various clock networks. This is achieved through the optional ``"name"`` attribute for the rr_node, accepting a string used as the clock network name. Therefore, when the ``"clk_res_type"`` is set to ``"VIRTUAL_SINK"``, the attribute ``"name"`` becomes a requried parameter to enable VPR to determine which clock network the virtual sink belongs to. + +When specifying the network_name in a global routing constraints file for routing a global net through a desired clock network, as described in the :ref:`above ` section, the name defined as an attribute in the virtual sink of the clock network should be used to reference that clock network. + +Segment Definition for Clock Networks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The node types ``"CHANX"`` and ``"CHANY"`` can construct the clock routing architecture, similar to a generic routing network. However, to identify nodes that are part of a clock network, one can define unique segments for clock networks. To indicate that a segment defined is a clock network resource, users can use the optional attribute ``res_type="GCLK"``. Therefore, nodes with a segment ID of this defined segment are considered to be part of a clock network. + +While VPR currently does not leverage this distinction of clock network resources, it is recommended to use the ``res_type="GCLK"`` attribute, as this preparation ensures compatibility for future support. + + +Example of RR Graph Definition for Clock Networks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Below are snapshots of a sample RR graph that illustrate how to define a clock network. This example demonstrates the definition of a virtual sink node, a clock network segment, and a CHANY node that is part of the clock network. + +For the node with ``id="12746"``, the ``res_type="VIRTUAL_SINK"`` attribute marks it as the virtual sink node of a clock network named ``"global_network"``, as specified by the ``name`` attribute. + +For the segment with ``id="1"``, the ``res_type="GCLK"`` attribute indicates that this segment is a clock network resource. + +The ``"CHANY"`` node with the ``id="12746"`` has ``segment_id="1"``, which means this resource belongs to the clock network. + +.. code-block:: xml + :caption: Example snippets from an RR graph describing part of a clock network. + :linenos: + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/src/vpr/index.rst b/doc/src/vpr/index.rst index 763ac3459be..61d60030bdb 100644 --- a/doc/src/vpr/index.rst +++ b/doc/src/vpr/index.rst @@ -55,7 +55,7 @@ The purpose of VPR is to make the packing, placement, and routing stages of the graphics timing_constraints - placement_constraints + vpr_constraints sdc_commands file_formats diff --git a/doc/src/vpr/placement_constraints.rst b/doc/src/vpr/placement_constraints.rst index f2cb8cfcab1..cbc0642ec48 100644 --- a/doc/src/vpr/placement_constraints.rst +++ b/doc/src/vpr/placement_constraints.rst @@ -1,39 +1,40 @@ -VPR Placement Constraints -========================= -.. _vpr_constraints_file: +Placement Constraints +====================== +.. _placement_constraints: + VPR supports running flows with placement constraints. Placement constraints are set on primitives to lock them down to specified regions on the FPGA chip. For example, a user may use placement constraints to lock down pins to specific locations on the chip. Also, groups of primitives may be locked down to regions on the chip in CAD flows that use floorplanning or modular design, or to hand-place a timing critical piece. The placement constraints should be specified by the user using an XML constraints file format, as described in the section below. When VPR is run with placement constraints, both the packing and placement flows are performed in such a way that the constraints are respected. The packing stage does not pack any primitives together that have conflicting floorplan constraints. The placement stage considers the floorplan constraints when choosing a location for each clustered block during initial placement, and does not move any block outside of its constraint boundaries during place moves. -A Constraints File Example --------------------------- +A Placement Constraints File Example +------------------------------------ .. code-block:: xml :caption: An example of a placement constraints file in XML format. :linenos: - - - - - - - - - - - - - - + + + + + + + + + + + + + + .. _end: -Constraints File Format ------------------------ +Placement Constraints File Format +--------------------------------- VPR has a specific XML format which must be used when creating a placement constraints file. The purpose of this constraints file is to specify @@ -42,9 +43,7 @@ VPR has a specific XML format which must be used when creating a placement const The file is passed as an input to VPR when running with placement constraints. When the file is read in, its information is used during the packing and placement stages of VPR. The hierarchy of the file is set up as follows. -.. note:: Use the VPR option :vpr:option:`--read_vpr_constraints` to specify the VPR placement constraints file that is to be loaded. - -The top level tag is the ```` tag. This tag contains one ```` tag. The ```` tag can be made up of an unbounded number of ```` tags. The ```` tags contains all of the detailed information of the placement constraints, and is described in detail below. +The top level tag is the ```` tag. This tag can contain one ```` tag. The ```` tag can be made up of an unbounded number of ```` tags. The ```` tags contains all of the detailed information of the placement constraints, and is described in detail below. Partitions, Atoms, and Regions ------------------------------ diff --git a/doc/src/vpr/vpr_constraints.rst b/doc/src/vpr/vpr_constraints.rst new file mode 100644 index 00000000000..a56fecf358b --- /dev/null +++ b/doc/src/vpr/vpr_constraints.rst @@ -0,0 +1,32 @@ +VPR Constraints +========================= +.. _vpr_constraints: + +VPR allows users to run the flow with placement constraints that enable primitives to be locked down to a specific region on the chip and global routing constraints that facilitate the routing of global nets through clock networks. + +Users can specify these constraints through a constraints file in XML format, as shown in the format below. + +.. code-block:: xml + :caption: The overall format of a VPR constraints file + :linenos: + + + + + + + + + + +.. note:: Use the VPR option :option:`vpr --read_vpr_constraints` to specify the VPR constraints file that is to be loaded. + +The top-level tag is the ```` tag. This tag can contain ```` and ```` tags. The ```` tag contains information related to placement constraints, while ```` contains information about global routing constraints. The details for each of these constraints are given in the respective sections :ref:`Placement Constraints ` and :ref:`Global Route Constraints `. + +.. toctree:: + :maxdepth: 2 + + placement_constraints + global_routing_constraints + + diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index f71a942ec60..ec42adfe4d3 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1509,6 +1509,22 @@ enum e_parallel_axis { Y_AXIS, BOTH_AXIS }; + +/** + * @brief An attribute of a segment that defines the general category of the wire segment type. + * + * @details + * - `GCLK`: A segment type that is part of the global routing network for clocks. + * - `GENERAL`: Describes a segment type that is part of the regular routing network. + */ +enum class SegResType { + GCLK = 0, + GENERAL = 1, + NUM_RES_TYPES +}; + +constexpr std::array(SegResType::NUM_RES_TYPES)> RES_TYPE_STRING = {{"GCLK", "GENERAL"}}; //String versions of segment resource types + enum e_switch_block_type { SUBSET, WILTON, @@ -1561,6 +1577,14 @@ enum e_Fc_type { * the segment's index in the unified segment_inf vector. This is * * useful when building the rr_graph for different Y & X channels * * in terms of track distribution and segment type. * + * res_type: Determines the routing network to which the segment belongs. * + * Possible values are: + * - GENERAL: The segment is part of the general routing * + * resources. * + * - GCLK: The segment is part of the global routing network. * + * For backward compatibility, this attribute is optional. If not * + * specified, the resource type for the segment is considered to * + * be GENERAL. * * meta: Table storing extra arbitrary metadata attributes. */ struct t_segment_inf { std::string name; @@ -1579,6 +1603,7 @@ struct t_segment_inf { std::vector cb; std::vector sb; int seg_index; + enum SegResType res_type = SegResType::GENERAL; //float Cmetal_per_m; /* Wire capacitance (per meter) */ }; @@ -2014,6 +2039,7 @@ struct t_arch { std::string gnd_net = "$__gnd_net"; std::string vcc_net = "$__vcc_net"; + std::string default_clock_network_name = "clock_network"; // Luts std::vector lut_cells; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index f4581a48bf7..dc98b5f3cc7 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -3724,6 +3724,18 @@ static void ProcessSegments(pugi::xml_node Parent, y_axis_seg_found = true; } + /*Get segment resource type*/ + tmp = get_attribute(Node, "res_type", loc_data, ReqOpt::OPTIONAL).as_string(nullptr); + + if (tmp) { + auto it = std::find(RES_TYPE_STRING.begin(), RES_TYPE_STRING.end(), tmp); + if (it != RES_TYPE_STRING.end()) { + Segs[i].res_type = static_cast(std::distance(RES_TYPE_STRING.begin(), it)); + } else { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), "Unsopported segment res_type: %s\n", tmp); + } + } + /* Get Power info */ /* * (*Segs)[i].Cmetal_per_m = get_attribute(Node, "Cmetal_per_m", false, diff --git a/libs/librrgraph/src/base/check_rr_graph.cpp b/libs/librrgraph/src/base/check_rr_graph.cpp index 104e069af65..ec452383f70 100644 --- a/libs/librrgraph/src/base/check_rr_graph.cpp +++ b/libs/librrgraph/src/base/check_rr_graph.cpp @@ -53,7 +53,6 @@ void check_rr_graph(const RRGraphView& rr_graph, const DeviceGrid& grid, const t_chan_width& chan_width, const t_graph_type graph_type, - const int virtual_clock_network_root_idx, bool is_flat) { e_route_type route_type = DETAILED; if (graph_type == GRAPH_GLOBAL) { @@ -76,7 +75,7 @@ void check_rr_graph(const RRGraphView& rr_graph, } // Virtual clock network sink is special, ignore. - if (virtual_clock_network_root_idx == int(inode)) { + if (rr_graph.is_virtual_clock_network_root(rr_node)) { continue; } diff --git a/libs/librrgraph/src/base/check_rr_graph.h b/libs/librrgraph/src/base/check_rr_graph.h index 46e5a80486c..ee137e8a956 100644 --- a/libs/librrgraph/src/base/check_rr_graph.h +++ b/libs/librrgraph/src/base/check_rr_graph.h @@ -11,7 +11,6 @@ void check_rr_graph(const RRGraphView& rr_graph, const DeviceGrid& grid, const t_chan_width& chan_width, const t_graph_type graph_type, - const int virtual_clock_network_root_idx, bool is_flat); void check_rr_node(const RRGraphView& rr_graph, diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index b58748e70fe..2ad5cfba50b 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -114,6 +114,11 @@ class RRGraphBuilder { inline void set_node_type(RRNodeId id, t_rr_type type) { node_storage_.set_node_type(id, type); } + + /** @brief Set the node name with a given valid id */ + inline void set_node_name(RRNodeId id, std::string name) { + node_storage_.set_node_name(id, name); + } /** * @brief Add an existing rr_node in the node storage to the node look-up * @@ -219,6 +224,11 @@ class RRGraphBuilder { node_storage_.set_node_direction(id, new_direction); } + /** @brief Set the node id for clock network virtual sink */ + inline void set_virtual_clock_network_root_idx(RRNodeId virtual_clock_network_root_idx) { + node_storage_.set_virtual_clock_network_root_idx(virtual_clock_network_root_idx); + } + /** @brief Reserve the lists of edges to be memory efficient. * This function is mainly used to reserve memory space inside RRGraph, * when adding a large number of edges in order to avoid memory fragements */ diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index b2cdefb9649..a7c8ce471c8 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -1,6 +1,8 @@ #include #include "arch_types.h" #include "rr_graph_storage.h" +#include "vtr_expr_eval.h" +#include "vtr_error.h" #include @@ -718,6 +720,9 @@ void t_rr_graph_storage::set_node_type(RRNodeId id, t_rr_type new_type) { node_storage_[id].type_ = new_type; } +void t_rr_graph_storage::set_node_name(RRNodeId id, std::string new_name) { + node_name_.insert(std::make_pair(id, new_name)); +} void t_rr_graph_storage::set_node_coordinates(RRNodeId id, short x1, short y1, short x2, short y2) { auto& node = node_storage_[id]; if (x1 < x2) { @@ -774,6 +779,20 @@ void t_rr_graph_storage::add_node_side(RRNodeId id, e_side new_side) { node_storage_[id].dir_side_.sides = static_cast(side_bits.to_ulong()); } +void t_rr_graph_storage::set_virtual_clock_network_root_idx(RRNodeId virtual_clock_network_root_idx) { + // Retrieve the name string for the specified RRNodeId. + auto clock_network_name_str = node_name(virtual_clock_network_root_idx); + + // If the name is available, associate it with the given node id for the clock network virtual sink. + if(clock_network_name_str) { + virtual_clock_network_root_idx_.insert(std::make_pair(*(clock_network_name_str.value()), virtual_clock_network_root_idx)); + } + else { + // If no name is available, throw a VtrError indicating the absence of the attribute name for the virtual sink node. + throw vtr::VtrError(vtr::string_fmt("Attribute name is not specified for virtual sink node '%u'\n", size_t(virtual_clock_network_root_idx)), __FILE__, __LINE__); + } +} + int t_rr_graph_view::node_ptc_num(RRNodeId id) const { return node_ptc_[id].ptc_.pin_num; } @@ -797,10 +816,12 @@ t_rr_graph_view t_rr_graph_storage::view() const { vtr::make_const_array_view_id(node_first_edge_), vtr::make_const_array_view_id(node_fan_in_), vtr::make_const_array_view_id(node_layer_), + node_name_, vtr::make_const_array_view_id(node_ptc_twist_incr_), vtr::make_const_array_view_id(edge_src_node_), vtr::make_const_array_view_id(edge_dest_node_), - vtr::make_const_array_view_id(edge_switch_)); + vtr::make_const_array_view_id(edge_switch_), + virtual_clock_network_root_idx_); } // Given `order`, a vector mapping each RRNodeId to a new one (old -> new), diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index 25c37ad1d4d..d3f695df87e 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -15,6 +15,8 @@ #include "vtr_memory.h" #include "vtr_strong_id_range.h" #include "vtr_array_view.h" +#include +#include /* Main structure describing one routing resource node. Everything in * * this structure should describe the graph -- information needed only * @@ -101,50 +103,49 @@ struct t_rr_node_ptc_data { class t_rr_graph_view; -// RR node and edge storage class. -// -// Description: -// -// This class stores the detailed routing graph. Each node within the graph is -// identified by a RRNodeId. Each edge within the graph is identified by a -// RREdgeId. -// -// Each node contains data about the node itself, for example look at the -// comment t_rr_node_data. Each node also has a set of RREdgeId's that all have -// RRNodeId as the source node. -// -// Each edge is defined by the source node, destination node, and the switch -// index that connects the source to the destination node. -// -// NOTE: The switch index represents either an index into arch_switch_inf -// **or** rr_switch_inf. During rr graph construction, the switch index is -// always is an index into arch_switch_inf. Once the graph is completed, the -// RR graph construction code coverts all arch_switch_inf indicies -// into rr_switch_inf indicies via the remap_rr_node_switch_indices method. -// -// Usage notes and assumptions: -// -// This class broadly speak is used by two types of code: -// - Code that writes to the rr graph -// - Code that reads from the rr graph -// -// Within VPR, there are two locations that the rr graph is expected to be -// modified, either: -// - During the building of the rr graph in rr_graph.cpp -// - During the reading of a static rr graph from a file in rr_graph_reader -// / rr_graph_uxsdcxx_serializer. -// -// It is expected and assume that once the graph is completed, the graph is -// fixed until the entire graph is cleared. This object enforces this -// assumption with state flags. In particular RR graph edges are assumed -// to be write only during construction of the RR graph, and read only -// otherwise. See the description of the "Edge methods" for details. -// -// Broadly speaking there are two sets of methods. Methods for reading and -// writing RR nodes, and methods for reading and writing RR edges. The node -// methods can be found underneath the header "Node methods" and the edge -// methods can be found underneath the header "Edge methods". -// +/** + * @file + * @brief RR node and edge storage class. + * + * @details + * This class stores the detailed routing graph. Each node within the graph is + * identified by a RRNodeId. Each edge within the graph is identified by a + * RREdgeId. + * + * Each node contains data about the node itself; refer to the comment for t_rr_node_data. + * Each node also has a set of RREdgeId's, all with RRNodeId as the source node. + * + * Each edge is defined by the source node, destination node, and the switch + * index that connects the source to the destination node. + * + * NOTE: The switch index represents either an index into arch_switch_inf + * **or** rr_switch_inf. During rr graph construction, the switch index is + * always an index into arch_switch_inf. Once the graph is completed, the + * RR graph construction code converts all arch_switch_inf indices + * into rr_switch_inf indices via the remap_rr_node_switch_indices method. + * + * @par Usage notes and assumptions: + * This class is broadly used by two types of code: + * - Code that writes to the rr graph + * - Code that reads from the rr graph + * + * Within VPR, there are two locations where the rr graph is expected to be + * modified: + * - During the building of the rr graph in rr_graph.cpp + * - During the reading of a static rr graph from a file in rr_graph_reader + * / rr_graph_uxsdcxx_serializer. + * + * It is expected and assumed that once the graph is completed, the graph is + * fixed until the entire graph is cleared. This object enforces this + * assumption with state flags. In particular, RR graph edges are assumed + * to be write-only during the construction of the RR graph and read-only + * otherwise. See the description of the "Edge methods" for details. + * + * Broadly speaking, there are two sets of methods: methods for reading and + * writing RR nodes, and methods for reading and writing RR edges. The node + * methods can be found underneath the header "Node methods," and the edge + * methods can be found underneath the header "Edge methods." + */ class t_rr_graph_storage { public: t_rr_graph_storage() { @@ -234,6 +235,23 @@ class t_rr_graph_storage { short node_layer(RRNodeId id) const{ return node_layer_[id]; } + + /** + * @brief Retrieve the name assigned to a given node ID. + * + * If no name is assigned, an empty optional is returned. + * + * @param id The id of the node. + * @return An optional pointer to the string representing the name if found, + * otherwise an empty optional. + */ + std::optional node_name(RRNodeId id) const{ + auto it = node_name_.find(id); + if (it != node_name_.end()) { + return &it->second; // Return the value if key is found + } + return std::nullopt; // Return an empty optional if key is not found + } /** @brief Find the twist number that RR node uses to change ptc number across the same track. * By default this number is zero, meaning that ptc number across the same track should be the same. @@ -247,6 +265,51 @@ class t_rr_graph_storage { return node_ptc_twist_incr_[id]; } + /** + * @brief Returns the node ID of the virtual sink for the specified clock network name. + * + * If the clock network name is not found, the function returns INVALID RRNodeId. + * + * @param clock_network_name The name of the clock network. + * @return The node ID of the virtual sink associated with the provided clock network name, + * or INVALID RRNodeID if the clock network name is not found. + */ + RRNodeId virtual_clock_network_root_idx(const char* clock_network_name) const { + // Convert the input char* to a C++ string + std::string clock_network_name_str(clock_network_name); + + // Check if the clock network name exists in the list of virtual sink entries + auto it = virtual_clock_network_root_idx_.find(clock_network_name); + + if (it != virtual_clock_network_root_idx_.end()) { + // Return the node ID for the virtual sink of the given clock network name + return it->second; + } + + // Return INVALID RRNodeID if the clock network name is not found + return RRNodeId::INVALID(); + } + + /** + * @brief Checks if the specified RRNode ID is a virtual sink for a clock network. + * + * A virtual sink/root is a node with the type SINK to which all clock network drive points are + * connected in the routing graph. + * When the two-stage router routes a net through a clock network, it first routes to the virtual sink + * in the first stage and then proceeds from there to the destination in the second stage. + * + * @param id The ID of an RRNode. + * @return True if the node with the given ID is a virtual sink for a clock network, false otherwise. + */ + bool is_virtual_clock_network_root(RRNodeId id) const{ + for (const auto& pair : virtual_clock_network_root_idx_) { + if (pair.second == id) { + return true; + } + } + return false; + } + /** @brief This prefetechs hot RR node data required for optimization. * * Note: This is optional, but may lower time spent on memory stalls in @@ -472,6 +535,8 @@ class t_rr_graph_storage { node_first_edge_.clear(); node_fan_in_.clear(); node_layer_.clear(); + node_name_.clear(); + virtual_clock_network_root_idx_.clear(); node_ptc_twist_incr_.clear(); edge_src_node_.clear(); edge_dest_node_.clear(); @@ -538,6 +603,7 @@ class t_rr_graph_storage { void set_node_class_num(RRNodeId id, int); //Same as set_ptc_num() by checks type() is consistent void set_node_type(RRNodeId id, t_rr_type new_type); + void set_node_name(RRNodeId id, std::string new_name); void set_node_coordinates(RRNodeId id, short x1, short y1, short x2, short y2); void set_node_layer(RRNodeId id, short layer); void set_node_ptc_twist_incr(RRNodeId id, short twist); @@ -552,6 +618,13 @@ class t_rr_graph_storage { */ void add_node_side(RRNodeId, e_side new_side); + /** + * @brief Set the node ID of the virtual sink for the clock network. + * + * @param virtual_clock_network_root_idx The node ID of the virtual sink for the clock network. + */ + void set_virtual_clock_network_root_idx(RRNodeId virtual_clock_network_root_idx); + /**************** * Edge methods * ****************/ @@ -675,7 +748,14 @@ class t_rr_graph_storage { return node_storage[id].dir_side_.direction; } - /* Find if the given node appears on a specific side */ + /** + * @brief Find if the given node appears on a specific side. + * + * @param node_storage Array view containing data for the nodes. + * @param id The RRNodeId to check for. + * @param side The specific side to check for the node. + * @return true if the node appears on the specified side, false otherwise. + */ static inline bool is_node_on_specific_side( vtr::array_view_id node_storage, const RRNodeId& id, @@ -731,7 +811,7 @@ class t_rr_graph_storage { */ vtr::vector> node_storage_; - /**@brief + /** @brief * The PTC data is cold data, and is generally not used during the inner * loop of either the placer or router. */ @@ -755,6 +835,26 @@ class t_rr_graph_storage { */ vtr::vector node_layer_; + /** + * @brief Stores the assigned names for the RRNode IDs. + * + * We use a hash table for efficiency because most RRNodes do not have names. + * An RRNode can be given a name (e.g., example_name) by reading in an rr-graph + * in which the optional attribute is set. + * Currently, the only use case for names is with global clock networks, where + * the name specifies the clock network to which an RRNode belongs. + */ + std::unordered_map node_name_; + + /** + * @brief A map that uses the name for each clock network as the key and stores + * the rr_node index for the virtual sink that connects to all the nodes that + * are clock network entry points. + * + * This map is particularly useful for two-stage clock routing. + */ + std::unordered_map virtual_clock_network_root_idx_; + /** @brief *Twist Increment number is defined for CHANX/CHANY nodes; it is useful for layout of tileable FPGAs used by openFPGA. *It gives us a new track index in each tile a longer wire crosses, which enables us to make long wires with a repeated single-tile pattern that "twists" the wires as they cross the tile. @@ -816,14 +916,17 @@ class t_rr_graph_storage { bool partitioned_; }; -// t_rr_graph_view is a read-only version of t_rr_graph_storage that only -// uses pointers and sizes to rr graph data. -// -// t_rr_graph_view enables efficient access to RR graph storage without owning -// the underlying storage. -// -// Because t_rr_graph_view only uses pointers and sizes, it is suitable for -// use with purely mmap'd data. +/** + * @brief t_rr_graph_view is a read-only version of t_rr_graph_storage that only + * uses pointers and sizes to RR graph data. + * + * @details + * t_rr_graph_view enables efficient access to RR graph storage without owning + * the underlying storage. + * + * Because t_rr_graph_view only uses pointers and sizes, it is suitable for + * use with purely mmap'd data. + */ class t_rr_graph_view { public: t_rr_graph_view(); @@ -833,19 +936,23 @@ class t_rr_graph_view { const vtr::array_view_id node_first_edge, const vtr::array_view_id node_fan_in, const vtr::array_view_id node_layer, + const std::unordered_map& node_name, const vtr::array_view_id node_ptc_twist_incr, const vtr::array_view_id edge_src_node, const vtr::array_view_id edge_dest_node, - const vtr::array_view_id edge_switch) + const vtr::array_view_id edge_switch, + const std::unordered_map& virtual_clock_network_root_idx) : node_storage_(node_storage) , node_ptc_(node_ptc) , node_first_edge_(node_first_edge) , node_fan_in_(node_fan_in) , node_layer_(node_layer) + , node_name_(node_name) , node_ptc_twist_incr_(node_ptc_twist_incr) , edge_src_node_(edge_src_node) , edge_dest_node_(edge_dest_node) - , edge_switch_(edge_switch) {} + , edge_switch_(edge_switch) + , virtual_clock_network_root_idx_(virtual_clock_network_root_idx) {} /**************** * Node methods * @@ -894,17 +1001,49 @@ class t_rr_graph_view { int node_track_num(RRNodeId id) const; //Same as ptc_num() but checks that type() is consistent int node_class_num(RRNodeId id) const; //Same as ptc_num() but checks that type() is consistent - /* Retrieve fan_in for RRNodeId. */ + /** + * @brief Retrieve the fan-in for a given RRNodeId. + * + * @param id The RRNodeId for which to retrieve the fan-in. + * @return The fan-in value. + */ t_edge_size fan_in(RRNodeId id) const { return node_fan_in_[id]; } - /* Retrieve layer(die) number that RRNodeId is located at */ + /** + * @brief Retrieve the layer (die) number where the given RRNodeId is located. + * + * @param id The RRNodeId for which to retrieve the layer number. + * @return The layer number (die) where the RRNodeId is located. + */ short node_layer(RRNodeId id) const{ return node_layer_[id]; } - /* Retrieve twist number (if available) that RRNodeId used for its ptc number */ + /** + * @brief Retrieve the name assigned to a given node ID. + * + * If no name is assigned, an empty optional is returned. + * + * @param id The id of the node. + * @return An optional pointer to the string representing the name if found, + * otherwise an empty optional. + */ + std::optional node_name(RRNodeId id) const{ + auto it = node_name_.find(id); + if (it != node_name_.end()) { + return &it->second; // Return the value if key is found + } + return std::nullopt; // Return an empty optional if key is not found + } + + /** + * @brief Retrieve the twist number (if available) that the given RRNodeId used for its PTC number. + * + * @param id The RRNodeId for which to retrieve the twist number. + * @return The twist number used for the PTC number, or a default value if not available. + */ short node_ptc_twist_incr(RRNodeId id) const{ //check if ptc twist increment allocated if(node_ptc_twist_incr_.empty()){ @@ -913,29 +1052,101 @@ class t_rr_graph_view { return node_ptc_twist_incr_[id]; } - // This prefetechs hot RR node data required for optimization. - // - // Note: This is optional, but may lower time spent on memory stalls in - // some circumstances. + /** + * @brief Prefetches hot RR node data required for optimization. + * + * @details + * This is optional but may lower time spent on memory stalls in some circumstances. + * + * @param id The RRNodeId for which to prefetch hot node data. + */ inline void prefetch_node(RRNodeId id) const { VTR_PREFETCH(&node_storage_[id], 0, 0); } + /** + * @brief Returns the node ID of the virtual sink for the specified clock network name. + * + * If the clock network name is not found, the function returns INVALID RRNodeId. + * + * @param clock_network_name The name of the clock network. + * @return The node ID of the virtual sink associated with the provided clock network name, + * or INVALID RRNodeID if the clock network name is not found. + */ + RRNodeId virtual_clock_network_root_idx(const char* clock_network_name) const { + // Convert the input char* to a C++ string + std::string clock_network_name_str(clock_network_name); + + // Check if the clock network name exists in the list of virtual sink entries + auto it = virtual_clock_network_root_idx_.find(clock_network_name_str); + + if (it != virtual_clock_network_root_idx_.end()) { + // Return the node ID for the virtual sink of the given clock network name + return it->second; + } + + // Return INVALID RRNodeID if the clock network name is not found + return RRNodeId::INVALID(); + } + + + /** + * @brief Checks if the specified RRNode ID is a virtual sink for a clock network. + * + * A virtual sink is a node with the type SINK to which all clock network drive points are + * connected in the routing graph. + * When the two-stage router routes a net through a clock network, it first routes to the virtual sink + * in the first stage and then proceeds from there to the destination in the second stage. + * + * @param id The ID of an RRNode. + * @return True if the node with the given ID is a virtual sink for a clock network, false otherwise. + */ + bool is_virtual_clock_network_root(RRNodeId id) const { + for (const auto& pair : virtual_clock_network_root_idx_) { + if (pair.second == id) { + return true; + } + } + return false; + } + /* Edge accessors */ - // Returns a range of RREdgeId's belonging to RRNodeId id. - // - // If this range is empty, then RRNodeId id has no edges. + /** + * @brief Returns a range of RREdgeId's belonging to RRNodeId id. + * + * @details + * If this range is empty, then RRNodeId id has no edges. + * + * @param id The RRNodeId for which to retrieve the edge range. + * @return A range of RREdgeId's belonging to the specified RRNodeId. + */ vtr::StrongIdRange edge_range(RRNodeId id) const { return vtr::StrongIdRange(first_edge(id), last_edge(id)); } - // Get the destination node for the specified edge. + /** + * @brief Get the destination node for the specified edge. + * + * @details + * This function retrieves the RRNodeId representing the destination node for the specified edge. + * + * @param edge The RREdgeId for which to retrieve the destination node. + * @return The RRNodeId representing the destination node for the specified edge. + */ RRNodeId edge_sink_node(RREdgeId edge) const { return edge_dest_node_[edge]; } - // Get the switch used for the specified edge. + /** + * @brief Get the switch used for the specified edge. + * + * @details + * This function retrieves the switch used for the specified edge. + * + * @param edge The RREdgeId for which to retrieve the switch. + * @return The switch index used for the specified edge. + */ short edge_switch(RREdgeId edge) const { return edge_switch_[edge]; } @@ -954,10 +1165,13 @@ class t_rr_graph_view { vtr::array_view_id node_first_edge_; vtr::array_view_id node_fan_in_; vtr::array_view_id node_layer_; + const std::unordered_map& node_name_; vtr::array_view_id node_ptc_twist_incr_; vtr::array_view_id edge_src_node_; vtr::array_view_id edge_dest_node_; vtr::array_view_id edge_switch_; + const std::unordered_map& virtual_clock_network_root_idx_; + }; #endif /* _RR_GRAPH_STORAGE_ */ diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 1df732484f5..af5035099b5 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -93,6 +93,19 @@ class RRGraphView { return node_storage_.node_type(node); } + /** + * @brief Retrieve the name assigned to a given node ID. + * + * If no name is assigned, an empty optional is returned. + * + * @param id The id of the node. + * @return An optional pointer to the string representing the name if found, + * otherwise an empty optional. + */ + std::optional node_name(RRNodeId node) const { + return node_storage_.node_name(node); + } + /** @brief Get the type string of a routing resource node. This function is inlined for runtime optimization. */ inline const char* node_type_string(RRNodeId node) const { return node_storage_.node_type_string(node); @@ -315,6 +328,21 @@ class RRGraphView { inline const char* node_side_string(RRNodeId node) const { return node_storage_.node_side_string(node); } + + /** @brief Get the node id of the clock network virtual sink */ + inline RRNodeId virtual_clock_network_root_idx(const char* clock_network_name) const { + return node_storage_.virtual_clock_network_root_idx(clock_network_name); + } + + /** + * @brief Checks if the specified RRNode ID is a virtual sink for a clock network. + * @param id The ID of an RRNode. + * @return True if the node with the given ID is a virtual sink for a clock network, false otherwise. + */ + inline bool is_virtual_clock_network_root(RRNodeId id) const { + return node_storage_.is_virtual_clock_network_root(id); + } + /** @brief Get the switch id that represents the iedge'th outgoing edge from a specific node * TODO: We may need to revisit this API and think about higher level APIs, like ``switch_delay()`` **/ diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h index 5099e2309e8..e276ba29f1a 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 + * Cmdline: /home/talaeikh/uxsdcxx/uxsdcxx.py /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 9c14a0ddd3c6bc1e690ca6abf467bae6 */ #include @@ -247,8 +247,8 @@ constexpr const char *atok_lookup_t_segment_timing[] = {"C_per_meter", "R_per_me enum class gtok_t_segment {TIMING}; constexpr const char *gtok_lookup_t_segment[] = {"timing"}; -enum class atok_t_segment {ID, NAME}; -constexpr const char *atok_lookup_t_segment[] = {"id", "name"}; +enum class atok_t_segment {ID, NAME, RES_TYPE}; +constexpr const char *atok_lookup_t_segment[] = {"id", "name", "res_type"}; enum class gtok_t_segments {SEGMENT}; constexpr const char *gtok_lookup_t_segments[] = {"segment"}; @@ -294,8 +294,8 @@ enum class gtok_t_metadata {META}; constexpr const char *gtok_lookup_t_metadata[] = {"meta"}; enum class gtok_t_node {LOC, TIMING, SEGMENT, METADATA}; constexpr const char *gtok_lookup_t_node[] = {"loc", "timing", "segment", "metadata"}; -enum class atok_t_node {CAPACITY, DIRECTION, ID, TYPE}; -constexpr const char *atok_lookup_t_node[] = {"capacity", "direction", "id", "type"}; +enum class atok_t_node {CAPACITY, CLK_RES_TYPE, DIRECTION, ID, NAME, TYPE}; +constexpr const char *atok_lookup_t_node[] = {"capacity", "clk_res_type", "direction", "id", "name", "type"}; enum class gtok_t_rr_nodes {NODE}; constexpr const char *gtok_lookup_t_rr_nodes[] = {"node"}; @@ -792,6 +792,14 @@ inline atok_t_segment lex_attr_t_segment(const char *in, const std::function.").c_str()); @@ -1339,6 +1347,9 @@ inline atok_t_node lex_attr_t_node(const char *in, const std::function.").c_str()); @@ -1575,9 +1599,11 @@ template /* Lookup tables for enums. */ constexpr const char *lookup_switch_type[] = {"UXSD_INVALID", "mux", "tristate", "pass_gate", "short", "buffer"}; +constexpr const char *lookup_segment_res_type[] = {"UXSD_INVALID", "GENERAL", "GCLK"}; constexpr const char *lookup_pin_type[] = {"UXSD_INVALID", "OPEN", "OUTPUT", "INPUT"}; constexpr const char *lookup_node_type[] = {"UXSD_INVALID", "CHANX", "CHANY", "SOURCE", "SINK", "OPIN", "IPIN"}; constexpr const char *lookup_node_direction[] = {"UXSD_INVALID", "INC_DIR", "DEC_DIR", "BI_DIR"}; +constexpr const char *lookup_node_clk_res_type[] = {"UXSD_INVALID", "VIRTUAL_SINK"}; constexpr const char *lookup_loc_side[] = {"UXSD_INVALID", "LEFT", "RIGHT", "TOP", "BOTTOM", "RIGHT_LEFT", "RIGHT_BOTTOM", "RIGHT_BOTTOM_LEFT", "TOP_RIGHT", "TOP_BOTTOM", "TOP_LEFT", "TOP_RIGHT_BOTTOM", "TOP_RIGHT_LEFT", "TOP_BOTTOM_LEFT", "TOP_RIGHT_BOTTOM_LEFT", "BOTTOM_LEFT"}; /* Lexers(string->token functions) for enums. */ @@ -1661,6 +1687,47 @@ inline enum_switch_type lex_enum_switch_type(const char *in, bool throw_on_inval return enum_switch_type::UXSD_INVALID; } +inline enum_segment_res_type lex_enum_segment_res_type(const char *in, bool throw_on_invalid, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 4: + switch(*((triehash_uu32*)&in[0])){ + case onechar('G', 0, 32) | onechar('C', 8, 32) | onechar('L', 16, 32) | onechar('K', 24, 32): + return enum_segment_res_type::GCLK; + break; + default: break; + } + break; + case 7: + switch(*((triehash_uu32*)&in[0])){ + case onechar('G', 0, 32) | onechar('E', 8, 32) | onechar('N', 16, 32) | onechar('E', 24, 32): + switch(in[4]){ + case onechar('R', 0, 8): + switch(in[5]){ + case onechar('A', 0, 8): + switch(in[6]){ + case onechar('L', 0, 8): + return enum_segment_res_type::GENERAL; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + if(throw_on_invalid) + noreturn_report(report_error, ("Found unrecognized enum value " + std::string(in) + " of enum_segment_res_type.").c_str()); + return enum_segment_res_type::UXSD_INVALID; +} + inline enum_pin_type lex_enum_pin_type(const char *in, bool throw_on_invalid, const std::function * report_error){ unsigned int len = strlen(in); switch(len){ @@ -1837,6 +1904,29 @@ inline enum_node_direction lex_enum_node_direction(const char *in, bool throw_on return enum_node_direction::UXSD_INVALID; } +inline enum_node_clk_res_type lex_enum_node_clk_res_type(const char *in, bool throw_on_invalid, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 12: + switch(*((triehash_uu64*)&in[0])){ + case onechar('V', 0, 64) | onechar('I', 8, 64) | onechar('R', 16, 64) | onechar('T', 24, 64) | onechar('U', 32, 64) | onechar('A', 40, 64) | onechar('L', 48, 64) | onechar('_', 56, 64): + switch(*((triehash_uu32*)&in[8])){ + case onechar('S', 0, 32) | onechar('I', 8, 32) | onechar('N', 16, 32) | onechar('K', 24, 32): + return enum_node_clk_res_type::VIRTUAL_SINK; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + if(throw_on_invalid) + noreturn_report(report_error, ("Found unrecognized enum value " + std::string(in) + " of enum_node_clk_res_type.").c_str()); + return enum_node_clk_res_type::UXSD_INVALID; +} + inline enum_loc_side lex_enum_loc_side(const char *in, bool throw_on_invalid, const std::function * report_error){ unsigned int len = strlen(in); switch(len){ @@ -2235,7 +2325,7 @@ inline void load_switch_required_attributes(const pugi::xml_node &root, int * id } inline void load_segment_required_attributes(const pugi::xml_node &root, int * id, const std::function * report_error){ - std::bitset<2> astate = 0; + std::bitset<3> astate = 0; for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ atok_t_segment in = lex_attr_t_segment(attr.name(), report_error); if(astate[(int)in] == 0) astate[(int)in] = 1; @@ -2247,10 +2337,13 @@ inline void load_segment_required_attributes(const pugi::xml_node &root, int * i case atok_t_segment::NAME: /* Attribute name set after element init */ break; + case atok_t_segment::RES_TYPE: + /* Attribute res_type set after element init */ + break; default: break; /* Not possible. */ } } - std::bitset<2> test_astate = astate | std::bitset<2>(0b00); + std::bitset<3> test_astate = astate | std::bitset<3>(0b100); if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_segment, report_error); } @@ -2422,7 +2515,7 @@ inline void load_node_segment_required_attributes(const pugi::xml_node &root, in } inline void load_node_required_attributes(const pugi::xml_node &root, unsigned int * capacity, unsigned int * id, enum_node_type * type, const std::function * report_error){ - std::bitset<4> astate = 0; + std::bitset<6> astate = 0; for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ atok_t_node in = lex_attr_t_node(attr.name(), report_error); if(astate[(int)in] == 0) astate[(int)in] = 1; @@ -2431,19 +2524,25 @@ inline void load_node_required_attributes(const pugi::xml_node &root, unsigned i case atok_t_node::CAPACITY: *capacity = load_unsigned_int(attr.value(), report_error); break; + case atok_t_node::CLK_RES_TYPE: + /* Attribute clk_res_type set after element init */ + break; case atok_t_node::DIRECTION: /* Attribute direction set after element init */ break; case atok_t_node::ID: *id = load_unsigned_int(attr.value(), report_error); break; + case atok_t_node::NAME: + /* Attribute name set after element init */ + break; case atok_t_node::TYPE: *type = lex_enum_node_type(attr.value(), true, report_error); break; default: break; /* Not possible. */ } } - std::bitset<4> test_astate = astate | std::bitset<4>(0b0010); + std::bitset<6> test_astate = astate | std::bitset<6>(0b010110); if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_node, report_error); } @@ -2840,6 +2939,9 @@ inline void load_segment(const pugi::xml_node &root, T &out, Context &context, c case atok_t_segment::NAME: out.set_segment_name(attr.value(), context); break; + case atok_t_segment::RES_TYPE: + out.set_segment_res_type(lex_enum_segment_res_type(attr.value(), true, report_error), context); + break; default: break; /* Not possible. */ } } @@ -3448,12 +3550,18 @@ inline void load_node(const pugi::xml_node &root, T &out, Context &context, cons case atok_t_node::CAPACITY: /* Attribute capacity is already set */ break; + case atok_t_node::CLK_RES_TYPE: + out.set_node_clk_res_type(lex_enum_node_clk_res_type(attr.value(), true, report_error), context); + break; case atok_t_node::DIRECTION: out.set_node_direction(lex_enum_node_direction(attr.value(), true, report_error), context); break; case atok_t_node::ID: /* Attribute id is already set */ break; + case atok_t_node::NAME: + out.set_node_name(attr.value(), context); + break; case atok_t_node::TYPE: /* Attribute type is already set */ break; @@ -3899,6 +4007,8 @@ inline void write_segments(T &in, std::ostream &os, Context &context){ os << ""; write_segment(in, os, child_context); os << "\n"; @@ -4070,9 +4180,13 @@ inline void write_rr_nodes(T &in, std::ostream &os, Context &context){ auto child_context = in.get_rr_nodes_node(i, context); os << ""; write_node(in, os, child_context); diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h index c523a6d7f42..1669549db45 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 + * Cmdline: /home/talaeikh/uxsdcxx/uxsdcap.py /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 9c14a0ddd3c6bc1e690ca6abf467bae6 */ #include @@ -154,6 +154,33 @@ inline ucap::SwitchType conv_to_enum_switch_type(enum_switch_type e) { } } +inline enum_segment_res_type conv_enum_segment_res_type(ucap::SegmentResType e, const std::function * report_error) { + switch(e) { + case ucap::SegmentResType::UXSD_INVALID: + return enum_segment_res_type::UXSD_INVALID; + case ucap::SegmentResType::GENERAL: + return enum_segment_res_type::GENERAL; + case ucap::SegmentResType::GCLK: + return enum_segment_res_type::GCLK; + default: + (*report_error)("Unknown enum_segment_res_type"); + throw std::runtime_error("Unreachable!"); + } +} + +inline ucap::SegmentResType conv_to_enum_segment_res_type(enum_segment_res_type e) { + switch(e) { + case enum_segment_res_type::UXSD_INVALID: + return ucap::SegmentResType::UXSD_INVALID; + case enum_segment_res_type::GENERAL: + return ucap::SegmentResType::GENERAL; + case enum_segment_res_type::GCLK: + return ucap::SegmentResType::GCLK; + default: + throw std::runtime_error("Unknown enum_segment_res_type"); + } +} + inline enum_pin_type conv_enum_pin_type(ucap::PinType e, const std::function * report_error) { switch(e) { case ucap::PinType::UXSD_INVALID: @@ -259,6 +286,29 @@ inline ucap::NodeDirection conv_to_enum_node_direction(enum_node_direction e) { } } +inline enum_node_clk_res_type conv_enum_node_clk_res_type(ucap::NodeClkResType e, const std::function * report_error) { + switch(e) { + case ucap::NodeClkResType::UXSD_INVALID: + return enum_node_clk_res_type::UXSD_INVALID; + case ucap::NodeClkResType::VIRTUAL_SINK: + return enum_node_clk_res_type::VIRTUAL_SINK; + default: + (*report_error)("Unknown enum_node_clk_res_type"); + throw std::runtime_error("Unreachable!"); + } +} + +inline ucap::NodeClkResType conv_to_enum_node_clk_res_type(enum_node_clk_res_type e) { + switch(e) { + case enum_node_clk_res_type::UXSD_INVALID: + return ucap::NodeClkResType::UXSD_INVALID; + case enum_node_clk_res_type::VIRTUAL_SINK: + return ucap::NodeClkResType::VIRTUAL_SINK; + default: + throw std::runtime_error("Unknown enum_node_clk_res_type"); + } +} + inline enum_loc_side conv_enum_loc_side(ucap::LocSide e, const std::function * report_error) { switch(e) { case ucap::LocSide::UXSD_INVALID: @@ -552,6 +602,7 @@ inline void load_segment_capnp_type(const ucap::Segment::Reader &root, T &out, C (void)stack; out.set_segment_name(root.getName().cStr(), context); + out.set_segment_res_type(conv_enum_segment_res_type(root.getResType(), report_error), context); stack->push_back(std::make_pair("getTiming", 0)); if (root.hasTiming()) { auto child_el = root.getTiming(); @@ -774,7 +825,9 @@ inline void load_node_capnp_type(const ucap::Node::Reader &root, T &out, Context (void)report_error; (void)stack; + out.set_node_clk_res_type(conv_enum_node_clk_res_type(root.getClkResType(), report_error), context); out.set_node_direction(conv_enum_node_direction(root.getDirection(), report_error), context); + out.set_node_name(root.getName().cStr(), context); stack->push_back(std::make_pair("getLoc", 0)); if (root.hasLoc()) { auto child_el = root.getLoc(); @@ -1049,6 +1102,8 @@ inline void write_segments_capnp_type(T &in, ucap::Segments::Builder &root, Cont auto child_context = in.get_segments_segment(i, context); segments_segment.setId(in.get_segment_id(child_context)); segments_segment.setName(in.get_segment_name(child_context)); + if((bool)in.get_segment_res_type(child_context)) + segments_segment.setResType(conv_to_enum_segment_res_type(in.get_segment_res_type(child_context))); write_segment_capnp_type(in, segments_segment, child_context); } } @@ -1200,9 +1255,13 @@ inline void write_rr_nodes_capnp_type(T &in, ucap::RrNodes::Builder &root, Conte auto rr_nodes_node = rr_nodes_nodes[i]; auto child_context = in.get_rr_nodes_node(i, context); rr_nodes_node.setCapacity(in.get_node_capacity(child_context)); + if((bool)in.get_node_clk_res_type(child_context)) + rr_nodes_node.setClkResType(conv_to_enum_node_clk_res_type(in.get_node_clk_res_type(child_context))); if((bool)in.get_node_direction(child_context)) rr_nodes_node.setDirection(conv_to_enum_node_direction(in.get_node_direction(child_context))); rr_nodes_node.setId(in.get_node_id(child_context)); + if((bool)in.get_node_name(child_context)) + rr_nodes_node.setName(in.get_node_name(child_context)); rr_nodes_node.setType(conv_to_enum_node_type(in.get_node_type(child_context))); write_node_capnp_type(in, rr_nodes_node, child_context); } diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h index 1fa575acf1a..4edff09238b 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 + * Cmdline: /home/talaeikh/uxsdcxx/uxsdcxx.py /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 9c14a0ddd3c6bc1e690ca6abf467bae6 */ #include @@ -23,12 +23,16 @@ namespace uxsd { enum class enum_switch_type {UXSD_INVALID = 0, MUX, TRISTATE, PASS_GATE, SHORT, BUFFER}; +enum class enum_segment_res_type {UXSD_INVALID = 0, GENERAL, GCLK}; + enum class enum_pin_type {UXSD_INVALID = 0, OPEN, OUTPUT, INPUT}; enum class enum_node_type {UXSD_INVALID = 0, CHANX, CHANY, SOURCE, SINK, OPIN, IPIN}; enum class enum_node_direction {UXSD_INVALID = 0, INC_DIR, DEC_DIR, BI_DIR}; +enum class enum_node_clk_res_type {UXSD_INVALID = 0, VIRTUAL_SINK}; + enum class enum_loc_side {UXSD_INVALID = 0, LEFT, RIGHT, TOP, BOTTOM, RIGHT_LEFT, RIGHT_BOTTOM, RIGHT_BOTTOM_LEFT, TOP_RIGHT, TOP_BOTTOM, TOP_LEFT, TOP_RIGHT_BOTTOM, TOP_RIGHT_LEFT, TOP_BOTTOM_LEFT, TOP_RIGHT_BOTTOM_LEFT, BOTTOM_LEFT}; /* Base class for the schema. */ @@ -136,8 +140,8 @@ class RrGraphBase { * * * - * - * + * + * * * */ @@ -188,7 +192,7 @@ class RrGraphBase { /** Generated for complex type "switch": * * - * + * * * * @@ -214,7 +218,7 @@ class RrGraphBase { /** Generated for complex type "switches": * * - * + * * * */ @@ -238,15 +242,18 @@ class RrGraphBase { /** Generated for complex type "segment": * * - * + * * * * + * * */ virtual inline int get_segment_id(typename ContextTypes::SegmentReadContext &ctx) = 0; virtual inline const char * get_segment_name(typename ContextTypes::SegmentReadContext &ctx) = 0; virtual inline void set_segment_name(const char * name, typename ContextTypes::SegmentWriteContext &ctx) = 0; + virtual inline enum_segment_res_type get_segment_res_type(typename ContextTypes::SegmentReadContext &ctx) = 0; + virtual inline void set_segment_res_type(enum_segment_res_type res_type, typename ContextTypes::SegmentWriteContext &ctx) = 0; virtual inline typename ContextTypes::SegmentTimingWriteContext init_segment_timing(typename ContextTypes::SegmentWriteContext &ctx) = 0; virtual inline void finish_segment_timing(typename ContextTypes::SegmentTimingWriteContext &ctx) = 0; virtual inline typename ContextTypes::SegmentTimingReadContext get_segment_timing(typename ContextTypes::SegmentReadContext &ctx) = 0; @@ -255,7 +262,7 @@ class RrGraphBase { /** Generated for complex type "segments": * * - * + * * * */ @@ -281,7 +288,7 @@ class RrGraphBase { /** Generated for complex type "pin_class": * * - * + * * * * @@ -296,7 +303,7 @@ class RrGraphBase { /** Generated for complex type "block_type": * * - * + * * * * @@ -318,7 +325,7 @@ class RrGraphBase { /** Generated for complex type "block_types": * * - * + * * * */ @@ -330,7 +337,7 @@ class RrGraphBase { /** Generated for complex type "grid_loc": * - * + * * * * @@ -349,7 +356,7 @@ class RrGraphBase { /** Generated for complex type "grid_locs": * * - * + * * * */ @@ -361,7 +368,7 @@ class RrGraphBase { /** Generated for complex type "node_loc": * - * + * * * * @@ -416,7 +423,7 @@ class RrGraphBase { /** Generated for complex type "metadata": * * - * + * * * */ @@ -430,20 +437,26 @@ class RrGraphBase { * * * - * - * - * + * + * + * * * * + * * + * * * */ virtual inline unsigned int get_node_capacity(typename ContextTypes::NodeReadContext &ctx) = 0; + virtual inline enum_node_clk_res_type get_node_clk_res_type(typename ContextTypes::NodeReadContext &ctx) = 0; + virtual inline void set_node_clk_res_type(enum_node_clk_res_type clk_res_type, typename ContextTypes::NodeWriteContext &ctx) = 0; virtual inline enum_node_direction get_node_direction(typename ContextTypes::NodeReadContext &ctx) = 0; virtual inline void set_node_direction(enum_node_direction direction, typename ContextTypes::NodeWriteContext &ctx) = 0; virtual inline unsigned int get_node_id(typename ContextTypes::NodeReadContext &ctx) = 0; + virtual inline const char * get_node_name(typename ContextTypes::NodeReadContext &ctx) = 0; + virtual inline void set_node_name(const char * name, typename ContextTypes::NodeWriteContext &ctx) = 0; virtual inline enum_node_type get_node_type(typename ContextTypes::NodeReadContext &ctx) = 0; virtual inline typename ContextTypes::NodeLocWriteContext init_node_loc(typename ContextTypes::NodeWriteContext &ctx, int ptc, int xhigh, int xlow, int yhigh, int ylow) = 0; virtual inline void finish_node_loc(typename ContextTypes::NodeLocWriteContext &ctx) = 0; @@ -477,7 +490,7 @@ class RrGraphBase { /** Generated for complex type "edge": * * - * + * * * * diff --git a/libs/librrgraph/src/io/rr_graph.xsd b/libs/librrgraph/src/io/rr_graph.xsd index 6b6650e100c..b990c488682 100644 --- a/libs/librrgraph/src/io/rr_graph.xsd +++ b/libs/librrgraph/src/io/rr_graph.xsd @@ -143,12 +143,20 @@ + + + + + + + + @@ -287,7 +301,9 @@ + + diff --git a/libs/librrgraph/src/io/rr_graph_reader.cpp b/libs/librrgraph/src/io/rr_graph_reader.cpp index a62f41d84d9..ec574080dba 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.cpp +++ b/libs/librrgraph/src/io/rr_graph_reader.cpp @@ -50,7 +50,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, const t_arch* arch, t_chan_width* chan_width, const enum e_base_cost_type base_cost_type, - const int virtual_clock_network_root_idx, int* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, @@ -86,7 +85,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, &rr_graph_builder->rr_switch(), rr_indexed_data, rr_rc_data, - virtual_clock_network_root_idx, arch_switch_inf, rr_graph->rr_segments(), physical_tile_types, diff --git a/libs/librrgraph/src/io/rr_graph_reader.h b/libs/librrgraph/src/io/rr_graph_reader.h index 0e7234cbe7e..8549b712bdf 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.h +++ b/libs/librrgraph/src/io/rr_graph_reader.h @@ -25,7 +25,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, const t_arch* arch, t_chan_width* chan_width, const enum e_base_cost_type base_cost_type, - const int virtual_clock_network_root_idx, int* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 736ea358a81..53d365b24e6 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "rr_graph_uxsdcxx_interface.h" @@ -286,7 +287,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { vtr::vector* rr_switch_inf, vtr::vector* rr_indexed_data, std::vector* rr_rc_data, - const int virtual_clock_network_root_idx, const std::vector& arch_switch_inf, const vtr::vector& segment_inf, const std::vector& physical_tile_types, @@ -305,7 +305,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { , rr_indexed_data_(rr_indexed_data) , read_rr_graph_filename_(read_rr_graph_filename) , rr_rc_data_(rr_rc_data) - , virtual_clock_network_root_idx_(virtual_clock_network_root_idx) , graph_type_(graph_type) , base_cost_type_(base_cost_type) , do_check_rr_graph_(do_check_rr_graph) @@ -916,8 +915,18 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { return id; } - inline void finish_rr_nodes_node(int& /*inode*/) final { + inline void finish_rr_nodes_node(int& inode) final { + auto node = (*rr_nodes_)[inode]; + RRNodeId node_id = node.id(); + + // At this point, all attributes for the node are loaded. Check whether the current node is included in the temporary list of + // clock network virtual sinks. If it is, permanently add it to the unordered map in rr_graph_storage, using the attribute + // name as the key. + if (clock_net_virtual_sinks.find(inode) != clock_net_virtual_sinks.end()) { + rr_graph_builder_->set_virtual_clock_network_root_idx(node_id); + } } + inline size_t num_rr_nodes_node(void*& /*ctx*/) final { return rr_nodes_->size(); @@ -939,6 +948,14 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { return to_uxsd_node_type(rr_graph.node_type(node.id())); } + inline const char* get_node_name(const t_rr_node& node) final { + const auto& rr_graph = (*rr_graph_); + auto node_name = rr_graph.node_name(node.id()); + if(node_name) + return node_name.value()->c_str(); + return nullptr; + } + inline void set_node_direction(uxsd::enum_node_direction direction, int& inode) final { const auto& rr_graph = (*rr_graph_); auto node = (*rr_nodes_)[inode]; @@ -963,6 +980,40 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { } } + inline void set_node_name(const char * name, int& inode) final { + if(name[0] != '\0') + { + // Do not store the attribute name if the string is empty + auto node = (*rr_nodes_)[inode]; + RRNodeId node_id = node.id(); + std::string name_str(name); + rr_graph_builder_->set_node_name(node_id, name_str); + } + + } + // Currently, this function only processes cases where clk_res_type=VIRTUAL_SINK + // It temporarily stores the node ID of the virtual sink in a temporary set. Eventually, + //the node ID will be stored in an unordered map within rr_graph_storage, using the attribute "name" + // as the key. Since, at this point in the code, the "name" attribute might not have been processed yet, + //the final storage will occur in the finish_rr_nodes_node function. + inline void set_node_clk_res_type(uxsd::enum_node_clk_res_type clk_res_type, int& inode) final { + if(clk_res_type == uxsd::enum_node_clk_res_type::VIRTUAL_SINK) + { + clock_net_virtual_sinks.insert(inode); + } + } + inline uxsd::enum_node_clk_res_type get_node_clk_res_type(const t_rr_node& node) final { + // Currently only VIRTUAL_SINK is supported as the clk_res_type + // If the node id doesn't match the node id of the clock virtual sink + // the function returns UXSD_INVALID + const auto& rr_graph = (*rr_graph_); + RRNodeId node_id = node.id(); + if (rr_graph.is_virtual_clock_network_root(node_id)) { + return uxsd::enum_node_clk_res_type::VIRTUAL_SINK; + } + return uxsd::enum_node_clk_res_type::UXSD_INVALID; + } + inline void* init_rr_graph_rr_nodes(void*& /*ctx*/) final { rr_nodes_->clear(); seg_index_.resize(CHANX_COST_INDEX_START + segment_inf_x_.size() + segment_inf_y_.size(), -1); @@ -1303,6 +1354,19 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { segment->name.c_str(), name); } } + inline uxsd::enum_segment_res_type get_segment_res_type(const t_segment_inf*& segment) final { + return to_uxsd_segment_res_type(segment->res_type); + } + inline void set_segment_res_type(uxsd::enum_segment_res_type seg_res_type, const t_segment_inf*& segment) final { + if (segment->res_type != from_uxsd_segment_res_type(seg_res_type)) { + const auto arch_index = static_cast(segment->res_type); + const auto rrgraph_index = static_cast(from_uxsd_segment_res_type(seg_res_type)); + + report_error( + "Architecture file does not match RR graph's segment res_type: arch uses %s, RR graph uses %s", + RES_TYPE_STRING[arch_index], RES_TYPE_STRING[rrgraph_index]); + } + } /** Generated for complex type "segments": * @@ -1762,7 +1826,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { grid_, *chan_width_, graph_type_, - virtual_clock_network_root_idx_, is_flat_); } } @@ -1903,6 +1966,30 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { } } + uxsd::enum_segment_res_type to_uxsd_segment_res_type(SegResType segment_res_type) { + switch (segment_res_type) { + case SegResType::GCLK: + return uxsd::enum_segment_res_type::GCLK; + case SegResType::GENERAL: + return uxsd::enum_segment_res_type::GENERAL; + default: + report_error( + "Invalid segment_res_type %d", segment_res_type); + } + } + + SegResType from_uxsd_segment_res_type(uxsd::enum_segment_res_type segment_res_type) { + switch (segment_res_type) { + case uxsd::enum_segment_res_type::GCLK: + return SegResType::GCLK; + case uxsd::enum_segment_res_type::GENERAL: + return SegResType::GENERAL; + default: + report_error( + "Invalid node segment_res_type %d", segment_res_type); + } + } + t_rr_type from_uxsd_node_type(uxsd::enum_node_type type) { switch (type) { case uxsd::enum_node_type::CHANX: @@ -2046,6 +2133,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { // Temporary storage vtr::vector seg_index_; std::string temp_string_; + std::unordered_set clock_net_virtual_sinks; // Temporary set storing the ID of nodes that have clk_res_type=virtual_sink // Constant mapping which is frequently used std::array side_map_; @@ -2062,7 +2150,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { t_rr_node_indices* rr_node_indices_; std::string* read_rr_graph_filename_; std::vector* rr_rc_data_; - const int virtual_clock_network_root_idx_; // Constant data for loads and writes. const t_graph_type graph_type_; diff --git a/libs/librrgraph/src/io/rr_graph_writer.cpp b/libs/librrgraph/src/io/rr_graph_writer.cpp index 6df594d49f1..d254ae9edb7 100644 --- a/libs/librrgraph/src/io/rr_graph_writer.cpp +++ b/libs/librrgraph/src/io/rr_graph_writer.cpp @@ -37,7 +37,6 @@ void write_rr_graph(RRGraphBuilder* rr_graph_builder, const t_arch* arch, t_chan_width* chan_width, const char* file_name, - const int virtual_clock_network_root_idx, bool echo_enabled, const char* echo_file_name, bool is_flat) { @@ -60,7 +59,6 @@ void write_rr_graph(RRGraphBuilder* rr_graph_builder, &rr_graph_builder->rr_switch(), rr_indexed_data, rr_rc_data, - virtual_clock_network_root_idx, arch_switch_inf, rr_graph_view->rr_segments(), physical_tile_types, diff --git a/libs/librrgraph/src/io/rr_graph_writer.h b/libs/librrgraph/src/io/rr_graph_writer.h index 467d65bb7ea..b84fe3e9f6e 100644 --- a/libs/librrgraph/src/io/rr_graph_writer.h +++ b/libs/librrgraph/src/io/rr_graph_writer.h @@ -23,7 +23,6 @@ void write_rr_graph(RRGraphBuilder* rr_graph_builder, const t_arch* arch, t_chan_width* chan_width, const char* file_name, - const int virtual_clock_network_root_idx, bool echo_enabled, const char* echo_file_name, bool is_flat); diff --git a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp index bba305feef1..b8ae564a385 100644 --- a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp +++ b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp @@ -2,11 +2,11 @@ # https://github.com/duck2/uxsdcxx # Modify only if your build process doesn't involve regenerating this file. # -# Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 +# Cmdline: /home/talaeikh/uxsdcxx/uxsdcap.py /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# Input file: /home/talaeikh/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# md5sum of input file: 9c14a0ddd3c6bc1e690ca6abf467bae6 -@0xf7009c96d0510b05; +@0xa136dd28cdc8783b; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("ucap"); @@ -19,6 +19,12 @@ enum SwitchType { buffer @5; } +enum SegmentResType { + uxsdInvalid @0; + general @1; + gclk @2; +} + enum PinType { uxsdInvalid @0; open @1; @@ -43,6 +49,11 @@ enum NodeDirection { biDir @3; } +enum NodeClkResType { + uxsdInvalid @0; + virtualSink @1; +} + enum LocSide { uxsdInvalid @0; left @1; @@ -119,7 +130,8 @@ struct SegmentTiming { struct Segment { id @0 :Int32; name @1 :Text; - timing @2 :SegmentTiming; + resType @2 :SegmentResType; + timing @3 :SegmentTiming; } struct Segments { @@ -192,13 +204,15 @@ struct Metadata { struct Node { capacity @0 :UInt32; - direction @1 :NodeDirection; - id @2 :UInt32; - type @3 :NodeType; - loc @4 :NodeLoc; - timing @5 :NodeTiming; - segment @6 :NodeSegment; - metadata @7 :Metadata; + clkResType @1 :NodeClkResType; + direction @2 :NodeDirection; + id @3 :UInt32; + name @4 :Text; + type @5 :NodeType; + loc @6 :NodeLoc; + timing @7 :NodeTiming; + segment @8 :NodeSegment; + metadata @9 :Metadata; } struct RrNodes { diff --git a/utils/fasm/test/test_fasm.cpp b/utils/fasm/test/test_fasm.cpp index ef55f4604f5..b700211825f 100644 --- a/utils/fasm/test/test_fasm.cpp +++ b/utils/fasm/test/test_fasm.cpp @@ -293,7 +293,6 @@ TEST_CASE("fasm_integration_test", "[fasm]") { device_ctx.arch, &device_ctx.chan_width, kRrGraphFile, - device_ctx.virtual_clock_network_root_idx, echo_enabled, echo_file_name, is_flat); diff --git a/vpr/src/base/constraints_load.cpp b/vpr/src/base/constraints_load.cpp index 158c6850980..0d170eebfca 100644 --- a/vpr/src/base/constraints_load.cpp +++ b/vpr/src/base/constraints_load.cpp @@ -1,6 +1,6 @@ #include "constraints_load.h" -void echo_constraints(char* filename, const VprConstraints& constraints) { +void echo_constraints(char* filename, const UserPlaceConstraints& constraints) { FILE* fp; fp = vtr::fopen(filename, "w"); @@ -8,7 +8,7 @@ void echo_constraints(char* filename, const VprConstraints& constraints) { fprintf(fp, "Constraints\n"); fprintf(fp, "--------------------------------------------------------------\n"); fprintf(fp, "\n"); - print_constraints(fp, constraints); + print_placement_constraints(fp, constraints); fclose(fp); } diff --git a/vpr/src/base/constraints_load.h b/vpr/src/base/constraints_load.h index d9fa93c7d49..783be088a32 100644 --- a/vpr/src/base/constraints_load.h +++ b/vpr/src/base/constraints_load.h @@ -4,10 +4,10 @@ #include "region.h" #include "partition.h" #include "partition_region.h" -#include "vpr_constraints.h" +#include "user_place_constraints.h" #include "vtr_vector.h" ///@brief Used to print vpr's floorplanning constraints to an echo file "vpr_constraints.echo" -void echo_constraints(char* filename, const VprConstraints& constraints); +void echo_constraints(char* filename, const UserPlaceConstraints& constraints); #endif diff --git a/vpr/src/base/gen/vpr_constraints_uxsdcxx.h b/vpr/src/base/gen/vpr_constraints_uxsdcxx.h index 3248c338281..d896dd6bdf5 100644 --- a/vpr/src/base/gen/vpr_constraints_uxsdcxx.h +++ b/vpr/src/base/gen/vpr_constraints_uxsdcxx.h @@ -4,13 +4,14 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx.py vpr_constraints.xsd - * Input file: /home/khalid88/Documents/uxsdcxx/vpr_constraints.xsd - * md5sum of input file: 6b6011a6e6446347b234da82e517422e + * Cmdline: /home/kimia/uxsdcxx/uxsdcxx.py ../vpr_constraints.xsd + * Input file: /home/kimia/vtr-verilog-to-routing/vpr/src/base/vpr_constraints.xsd + * md5sum of input file: f2b3721db9b14ccdf0787c9c99e00a78 */ #include + #include #include #include @@ -25,8 +26,6 @@ #include "pugixml.hpp" #include "vpr_constraints_uxsdcxx_interface.h" -#include "region.h" - /* All uxsdcxx functions and structs live in this namespace. */ namespace uxsd { @@ -34,827 +33,1106 @@ namespace uxsd { * Internal function for getting line and column number from file based on * byte offset. */ -inline void get_line_number(const char* filename, std::ptrdiff_t offset, int* line, int* col); +inline void get_line_number(const char *filename, std::ptrdiff_t offset, int * line, int * col); -[[noreturn]] inline void noreturn_report(const std::function* report_error, const char* msg) { +[[noreturn]] inline void noreturn_report(const std::function * report_error, const char *msg) { (*report_error)(msg); throw std::runtime_error("Unreachable!"); } /* Declarations for internal load functions for the complex types. */ -template -inline void load_add_atom(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug); -template -inline void load_add_region(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug); -inline void load_add_region_required_attributes(const pugi::xml_node& root, int* x_high, int* x_low, int* y_high, int* y_low, const std::function* report_error); -template -inline void load_partition(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug); -template -inline void load_partition_list(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug); -template -inline void load_vpr_constraints(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug); +template +inline void load_add_atom(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +template +inline void load_add_region(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +inline void load_add_region_required_attributes(const pugi::xml_node &root, int * x_high, int * x_low, int * y_high, int * y_low, const std::function * report_error); +template +inline void load_partition(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +template +inline void load_partition_list(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +template +inline void load_set_global_signal(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +inline void load_set_global_signal_required_attributes(const pugi::xml_node &root, enum_route_model_type * route_model, const std::function * report_error); +template +inline void load_global_route_constraints(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); +template +inline void load_vpr_constraints(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug); /* Declarations for internal write functions for the complex types. */ -template -inline void write_partition(T& in, std::ostream& os, const void* data, void* iter); -template -inline void write_partition_list(T& in, std::ostream& os, const void* data, void* iter); -template -inline void write_vpr_constraints(T& in, std::ostream& os, const void* data, void* iter); +template +inline void write_partition(T &in, std::ostream &os, const void *data, void *iter); +template +inline void write_partition_list(T &in, std::ostream &os, const void *data, void *iter); +template +inline void write_global_route_constraints(T &in, std::ostream &os, const void *data, void *iter); +template +inline void write_vpr_constraints(T &in, std::ostream &os, const void *data, void *iter); /* Load function for the root element. */ -template -inline void load_vpr_constraints_xml(T& out, Context& context, const char* filename, std::istream& is) { - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load(is); - if (!result) { - int line, col; - get_line_number(filename, result.offset, &line, &col); - std::stringstream msg; - msg << "Unable to load XML file '" << filename << "', "; - msg << result.description() << " (line: " << line; - msg << " col: " << col << ")"; - out.error_encountered(filename, line, msg.str().c_str()); - } - ptrdiff_t offset_debug = 0; - std::function report_error = [filename, &out, &offset_debug](const char* message) { - int line, col; - get_line_number(filename, offset_debug, &line, &col); - out.error_encountered(filename, line, message); - // If error_encountered didn't throw, throw now to unwind. - throw std::runtime_error(message); - }; - out.start_load(&report_error); - - for (pugi::xml_node node = doc.first_child(); node; node = node.next_sibling()) { - if (std::strcmp(node.name(), "vpr_constraints") == 0) { - /* If errno is set up to this point, it messes with strtol errno checking. */ - errno = 0; - load_vpr_constraints(node, out, context, &report_error, &offset_debug); - } else { - offset_debug = node.offset_debug(); - report_error(("Invalid root-level element " + std::string(node.name())).c_str()); - } - } - out.finish_load(); +template +inline void load_vpr_constraints_xml(T &out, Context &context, const char * filename, std::istream &is){ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load(is); + if(!result) { + int line, col; + get_line_number(filename, result.offset, &line, &col); + std::stringstream msg; + msg << "Unable to load XML file '" << filename << "', "; + msg << result.description() << " (line: " << line; + msg << " col: " << col << ")"; out.error_encountered(filename, line, msg.str().c_str()); + } + ptrdiff_t offset_debug = 0; + std::function report_error = [filename, &out, &offset_debug](const char * message) { + int line, col; + get_line_number(filename, offset_debug, &line, &col); + out.error_encountered(filename, line, message); + // If error_encountered didn't throw, throw now to unwind. + throw std::runtime_error(message); + }; + out.start_load(&report_error); + + for(pugi::xml_node node= doc.first_child(); node; node = node.next_sibling()){ + if(std::strcmp(node.name(), "vpr_constraints") == 0){ + /* If errno is set up to this point, it messes with strtol errno checking. */ + errno = 0; + load_vpr_constraints(node, out, context, &report_error, &offset_debug); + } else { + offset_debug = node.offset_debug(); + report_error(("Invalid root-level element " + std::string(node.name())).c_str()); + } + } + out.finish_load(); } /* Write function for the root element. */ -template -inline void write_vpr_constraints_xml(T& in, Context& context, std::ostream& os) { - in.start_write(); - os << "\n"; - write_vpr_constraints(in, os, context); - os << "\n"; - in.finish_write(); +template +inline void write_vpr_constraints_xml(T &in, Context &context, std::ostream &os){ + in.start_write(); + os << "\n"; + write_vpr_constraints(in, os, context); + os << "\n"; + in.finish_write(); } + typedef const uint32_t __attribute__((aligned(1))) triehash_uu32; typedef const uint64_t __attribute__((aligned(1))) triehash_uu64; static_assert(alignof(triehash_uu32) == 1, "Unaligned 32-bit access not found."); static_assert(alignof(triehash_uu64) == 1, "Unaligned 64-bit access not found."); #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define onechar(c, s, l) (((uint64_t)(c)) << (s)) +#define onechar(c, s, l) (((uint64_t)(c)) << (s)) #else -# define onechar(c, s, l) (((uint64_t)(c)) << (l - 8 - s)) +#define onechar(c, s, l) (((uint64_t)(c)) << (l-8-s)) #endif /* Tokens for attribute and node names. */ -enum class atok_t_add_atom { NAME_PATTERN }; -constexpr const char* atok_lookup_t_add_atom[] = {"name_pattern"}; - -enum class atok_t_add_region { SUBTILE, - X_HIGH, - X_LOW, - Y_HIGH, - Y_LOW }; -constexpr const char* atok_lookup_t_add_region[] = {"subtile", "x_high", "x_low", "y_high", "y_low"}; - -enum class gtok_t_partition { ADD_ATOM, - ADD_REGION }; -constexpr const char* gtok_lookup_t_partition[] = {"add_atom", "add_region"}; -enum class atok_t_partition { NAME }; -constexpr const char* atok_lookup_t_partition[] = {"name"}; - -enum class gtok_t_partition_list { PARTITION }; -constexpr const char* gtok_lookup_t_partition_list[] = {"partition"}; -enum class gtok_t_vpr_constraints { PARTITION_LIST }; -constexpr const char* gtok_lookup_t_vpr_constraints[] = {"partition_list"}; -enum class atok_t_vpr_constraints { TOOL_NAME }; -constexpr const char* atok_lookup_t_vpr_constraints[] = {"tool_name"}; +enum class atok_t_add_atom {NAME_PATTERN}; +constexpr const char *atok_lookup_t_add_atom[] = {"name_pattern"}; + + +enum class atok_t_add_region {SUBTILE, X_HIGH, X_LOW, Y_HIGH, Y_LOW}; +constexpr const char *atok_lookup_t_add_region[] = {"subtile", "x_high", "x_low", "y_high", "y_low"}; + +enum class gtok_t_partition {ADD_ATOM, ADD_REGION}; +constexpr const char *gtok_lookup_t_partition[] = {"add_atom", "add_region"}; +enum class atok_t_partition {NAME}; +constexpr const char *atok_lookup_t_partition[] = {"name"}; + +enum class gtok_t_partition_list {PARTITION}; +constexpr const char *gtok_lookup_t_partition_list[] = {"partition"}; + +enum class atok_t_set_global_signal {NAME, NETWORK_NAME, ROUTE_MODEL}; +constexpr const char *atok_lookup_t_set_global_signal[] = {"name", "network_name", "route_model"}; + +enum class gtok_t_global_route_constraints {SET_GLOBAL_SIGNAL}; +constexpr const char *gtok_lookup_t_global_route_constraints[] = {"set_global_signal"}; +enum class gtok_t_vpr_constraints {PARTITION_LIST, GLOBAL_ROUTE_CONSTRAINTS}; +constexpr const char *gtok_lookup_t_vpr_constraints[] = {"partition_list", "global_route_constraints"}; +enum class atok_t_vpr_constraints {TOOL_NAME}; +constexpr const char *atok_lookup_t_vpr_constraints[] = {"tool_name"}; + /* Internal lexers. These convert the PugiXML node names to input tokens. */ -inline atok_t_add_atom lex_attr_t_add_atom(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 12: - switch (*((triehash_uu64*)&in[0])) { - case onechar('n', 0, 64) | onechar('a', 8, 64) | onechar('m', 16, 64) | onechar('e', 24, 64) | onechar('_', 32, 64) | onechar('p', 40, 64) | onechar('a', 48, 64) | onechar('t', 56, 64): - switch (*((triehash_uu32*)&in[8])) { - case onechar('t', 0, 32) | onechar('e', 8, 32) | onechar('r', 16, 32) | onechar('n', 24, 32): - return atok_t_add_atom::NAME_PATTERN; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); +inline atok_t_add_atom lex_attr_t_add_atom(const char *in, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 12: + switch(*((triehash_uu64*)&in[0])){ + case onechar('n', 0, 64) | onechar('a', 8, 64) | onechar('m', 16, 64) | onechar('e', 24, 64) | onechar('_', 32, 64) | onechar('p', 40, 64) | onechar('a', 48, 64) | onechar('t', 56, 64): + switch(*((triehash_uu32*)&in[8])){ + case onechar('t', 0, 32) | onechar('e', 8, 32) | onechar('r', 16, 32) | onechar('n', 24, 32): + return atok_t_add_atom::NAME_PATTERN; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); } -inline atok_t_add_region lex_attr_t_add_region(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 5: - switch (*((triehash_uu32*)&in[0])) { - case onechar('x', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('o', 24, 32): - switch (in[4]) { - case onechar('w', 0, 8): - return atok_t_add_region::X_LOW; - break; - default: - break; - } - break; - case onechar('y', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('o', 24, 32): - switch (in[4]) { - case onechar('w', 0, 8): - return atok_t_add_region::Y_LOW; - break; - default: - break; - } - break; - default: - break; - } - break; - case 6: - switch (*((triehash_uu32*)&in[0])) { - case onechar('x', 0, 32) | onechar('_', 8, 32) | onechar('h', 16, 32) | onechar('i', 24, 32): - switch (in[4]) { - case onechar('g', 0, 8): - switch (in[5]) { - case onechar('h', 0, 8): - return atok_t_add_region::X_HIGH; - break; - default: - break; - } - break; - default: - break; - } - break; - case onechar('y', 0, 32) | onechar('_', 8, 32) | onechar('h', 16, 32) | onechar('i', 24, 32): - switch (in[4]) { - case onechar('g', 0, 8): - switch (in[5]) { - case onechar('h', 0, 8): - return atok_t_add_region::Y_HIGH; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - case 7: - switch (*((triehash_uu32*)&in[0])) { - case onechar('s', 0, 32) | onechar('u', 8, 32) | onechar('b', 16, 32) | onechar('t', 24, 32): - switch (in[4]) { - case onechar('i', 0, 8): - switch (in[5]) { - case onechar('l', 0, 8): - switch (in[6]) { - case onechar('e', 0, 8): - return atok_t_add_region::SUBTILE; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); +inline atok_t_add_region lex_attr_t_add_region(const char *in, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 5: + switch(*((triehash_uu32*)&in[0])){ + case onechar('x', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('o', 24, 32): + switch(in[4]){ + case onechar('w', 0, 8): + return atok_t_add_region::X_LOW; + break; + default: break; + } + break; + case onechar('y', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('o', 24, 32): + switch(in[4]){ + case onechar('w', 0, 8): + return atok_t_add_region::Y_LOW; + break; + default: break; + } + break; + default: break; + } + break; + case 6: + switch(*((triehash_uu32*)&in[0])){ + case onechar('x', 0, 32) | onechar('_', 8, 32) | onechar('h', 16, 32) | onechar('i', 24, 32): + switch(in[4]){ + case onechar('g', 0, 8): + switch(in[5]){ + case onechar('h', 0, 8): + return atok_t_add_region::X_HIGH; + break; + default: break; + } + break; + default: break; + } + break; + case onechar('y', 0, 32) | onechar('_', 8, 32) | onechar('h', 16, 32) | onechar('i', 24, 32): + switch(in[4]){ + case onechar('g', 0, 8): + switch(in[5]){ + case onechar('h', 0, 8): + return atok_t_add_region::Y_HIGH; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + case 7: + switch(*((triehash_uu32*)&in[0])){ + case onechar('s', 0, 32) | onechar('u', 8, 32) | onechar('b', 16, 32) | onechar('t', 24, 32): + switch(in[4]){ + case onechar('i', 0, 8): + switch(in[5]){ + case onechar('l', 0, 8): + switch(in[6]){ + case onechar('e', 0, 8): + return atok_t_add_region::SUBTILE; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); } -inline gtok_t_partition lex_node_t_partition(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 8: - switch (*((triehash_uu64*)&in[0])) { - case onechar('a', 0, 64) | onechar('d', 8, 64) | onechar('d', 16, 64) | onechar('_', 24, 64) | onechar('a', 32, 64) | onechar('t', 40, 64) | onechar('o', 48, 64) | onechar('m', 56, 64): - return gtok_t_partition::ADD_ATOM; - break; - default: - break; - } - break; - case 10: - switch (*((triehash_uu64*)&in[0])) { - case onechar('a', 0, 64) | onechar('d', 8, 64) | onechar('d', 16, 64) | onechar('_', 24, 64) | onechar('r', 32, 64) | onechar('e', 40, 64) | onechar('g', 48, 64) | onechar('i', 56, 64): - switch (in[8]) { - case onechar('o', 0, 8): - switch (in[9]) { - case onechar('n', 0, 8): - return gtok_t_partition::ADD_REGION; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); +inline gtok_t_partition lex_node_t_partition(const char *in, const std::function *report_error){ + unsigned int len = strlen(in); + switch(len){ + case 8: + switch(*((triehash_uu64*)&in[0])){ + case onechar('a', 0, 64) | onechar('d', 8, 64) | onechar('d', 16, 64) | onechar('_', 24, 64) | onechar('a', 32, 64) | onechar('t', 40, 64) | onechar('o', 48, 64) | onechar('m', 56, 64): + return gtok_t_partition::ADD_ATOM; + break; + default: break; + } + break; + case 10: + switch(*((triehash_uu64*)&in[0])){ + case onechar('a', 0, 64) | onechar('d', 8, 64) | onechar('d', 16, 64) | onechar('_', 24, 64) | onechar('r', 32, 64) | onechar('e', 40, 64) | onechar('g', 48, 64) | onechar('i', 56, 64): + switch(in[8]){ + case onechar('o', 0, 8): + switch(in[9]){ + case onechar('n', 0, 8): + return gtok_t_partition::ADD_REGION; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); } -inline atok_t_partition lex_attr_t_partition(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 4: - switch (*((triehash_uu32*)&in[0])) { - case onechar('n', 0, 32) | onechar('a', 8, 32) | onechar('m', 16, 32) | onechar('e', 24, 32): - return atok_t_partition::NAME; - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); +inline atok_t_partition lex_attr_t_partition(const char *in, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 4: + switch(*((triehash_uu32*)&in[0])){ + case onechar('n', 0, 32) | onechar('a', 8, 32) | onechar('m', 16, 32) | onechar('e', 24, 32): + return atok_t_partition::NAME; + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); } -inline gtok_t_partition_list lex_node_t_partition_list(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 9: - switch (*((triehash_uu64*)&in[0])) { - case onechar('p', 0, 64) | onechar('a', 8, 64) | onechar('r', 16, 64) | onechar('t', 24, 64) | onechar('i', 32, 64) | onechar('t', 40, 64) | onechar('i', 48, 64) | onechar('o', 56, 64): - switch (in[8]) { - case onechar('n', 0, 8): - return gtok_t_partition_list::PARTITION; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); +inline gtok_t_partition_list lex_node_t_partition_list(const char *in, const std::function *report_error){ + unsigned int len = strlen(in); + switch(len){ + case 9: + switch(*((triehash_uu64*)&in[0])){ + case onechar('p', 0, 64) | onechar('a', 8, 64) | onechar('r', 16, 64) | onechar('t', 24, 64) | onechar('i', 32, 64) | onechar('t', 40, 64) | onechar('i', 48, 64) | onechar('o', 56, 64): + switch(in[8]){ + case onechar('n', 0, 8): + return gtok_t_partition_list::PARTITION; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); } -inline gtok_t_vpr_constraints lex_node_t_vpr_constraints(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 14: - switch (*((triehash_uu64*)&in[0])) { - case onechar('p', 0, 64) | onechar('a', 8, 64) | onechar('r', 16, 64) | onechar('t', 24, 64) | onechar('i', 32, 64) | onechar('t', 40, 64) | onechar('i', 48, 64) | onechar('o', 56, 64): - switch (*((triehash_uu32*)&in[8])) { - case onechar('n', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('i', 24, 32): - switch (in[12]) { - case onechar('s', 0, 8): - switch (in[13]) { - case onechar('t', 0, 8): - return gtok_t_vpr_constraints::PARTITION_LIST; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); +inline atok_t_set_global_signal lex_attr_t_set_global_signal(const char *in, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 4: + switch(*((triehash_uu32*)&in[0])){ + case onechar('n', 0, 32) | onechar('a', 8, 32) | onechar('m', 16, 32) | onechar('e', 24, 32): + return atok_t_set_global_signal::NAME; + break; + default: break; + } + break; + case 11: + switch(*((triehash_uu64*)&in[0])){ + case onechar('r', 0, 64) | onechar('o', 8, 64) | onechar('u', 16, 64) | onechar('t', 24, 64) | onechar('e', 32, 64) | onechar('_', 40, 64) | onechar('m', 48, 64) | onechar('o', 56, 64): + switch(in[8]){ + case onechar('d', 0, 8): + switch(in[9]){ + case onechar('e', 0, 8): + switch(in[10]){ + case onechar('l', 0, 8): + return atok_t_set_global_signal::ROUTE_MODEL; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + case 12: + switch(*((triehash_uu64*)&in[0])){ + case onechar('n', 0, 64) | onechar('e', 8, 64) | onechar('t', 16, 64) | onechar('w', 24, 64) | onechar('o', 32, 64) | onechar('r', 40, 64) | onechar('k', 48, 64) | onechar('_', 56, 64): + switch(*((triehash_uu32*)&in[8])){ + case onechar('n', 0, 32) | onechar('a', 8, 32) | onechar('m', 16, 32) | onechar('e', 24, 32): + return atok_t_set_global_signal::NETWORK_NAME; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); } -inline atok_t_vpr_constraints lex_attr_t_vpr_constraints(const char* in, const std::function* report_error) { - unsigned int len = strlen(in); - switch (len) { - case 9: - switch (*((triehash_uu64*)&in[0])) { - case onechar('t', 0, 64) | onechar('o', 8, 64) | onechar('o', 16, 64) | onechar('l', 24, 64) | onechar('_', 32, 64) | onechar('n', 40, 64) | onechar('a', 48, 64) | onechar('m', 56, 64): - switch (in[8]) { - case onechar('e', 0, 8): - return atok_t_vpr_constraints::TOOL_NAME; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); + +inline gtok_t_global_route_constraints lex_node_t_global_route_constraints(const char *in, const std::function *report_error){ + unsigned int len = strlen(in); + switch(len){ + case 17: + switch(*((triehash_uu64*)&in[0])){ + case onechar('s', 0, 64) | onechar('e', 8, 64) | onechar('t', 16, 64) | onechar('_', 24, 64) | onechar('g', 32, 64) | onechar('l', 40, 64) | onechar('o', 48, 64) | onechar('b', 56, 64): + switch(*((triehash_uu64*)&in[8])){ + case onechar('a', 0, 64) | onechar('l', 8, 64) | onechar('_', 16, 64) | onechar('s', 24, 64) | onechar('i', 32, 64) | onechar('g', 40, 64) | onechar('n', 48, 64) | onechar('a', 56, 64): + switch(in[16]){ + case onechar('l', 0, 8): + return gtok_t_global_route_constraints::SET_GLOBAL_SIGNAL; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); +} + +inline gtok_t_vpr_constraints lex_node_t_vpr_constraints(const char *in, const std::function *report_error){ + unsigned int len = strlen(in); + switch(len){ + case 14: + switch(*((triehash_uu64*)&in[0])){ + case onechar('p', 0, 64) | onechar('a', 8, 64) | onechar('r', 16, 64) | onechar('t', 24, 64) | onechar('i', 32, 64) | onechar('t', 40, 64) | onechar('i', 48, 64) | onechar('o', 56, 64): + switch(*((triehash_uu32*)&in[8])){ + case onechar('n', 0, 32) | onechar('_', 8, 32) | onechar('l', 16, 32) | onechar('i', 24, 32): + switch(in[12]){ + case onechar('s', 0, 8): + switch(in[13]){ + case onechar('t', 0, 8): + return gtok_t_vpr_constraints::PARTITION_LIST; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + case 24: + switch(*((triehash_uu64*)&in[0])){ + case onechar('g', 0, 64) | onechar('l', 8, 64) | onechar('o', 16, 64) | onechar('b', 24, 64) | onechar('a', 32, 64) | onechar('l', 40, 64) | onechar('_', 48, 64) | onechar('r', 56, 64): + switch(*((triehash_uu64*)&in[8])){ + case onechar('o', 0, 64) | onechar('u', 8, 64) | onechar('t', 16, 64) | onechar('e', 24, 64) | onechar('_', 32, 64) | onechar('c', 40, 64) | onechar('o', 48, 64) | onechar('n', 56, 64): + switch(*((triehash_uu64*)&in[16])){ + case onechar('s', 0, 64) | onechar('t', 8, 64) | onechar('r', 16, 64) | onechar('a', 24, 64) | onechar('i', 32, 64) | onechar('n', 40, 64) | onechar('t', 48, 64) | onechar('s', 56, 64): + return gtok_t_vpr_constraints::GLOBAL_ROUTE_CONSTRAINTS; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized child " + std::string(in) + " of .").c_str()); +} +inline atok_t_vpr_constraints lex_attr_t_vpr_constraints(const char *in, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 9: + switch(*((triehash_uu64*)&in[0])){ + case onechar('t', 0, 64) | onechar('o', 8, 64) | onechar('o', 16, 64) | onechar('l', 24, 64) | onechar('_', 32, 64) | onechar('n', 40, 64) | onechar('a', 48, 64) | onechar('m', 56, 64): + switch(in[8]){ + case onechar('e', 0, 8): + return atok_t_vpr_constraints::TOOL_NAME; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + noreturn_report(report_error, ("Found unrecognized attribute " + std::string(in) + " of .").c_str()); } /** * Internal error function for xs:choice and xs:sequence validators. */ -[[noreturn]] inline void dfa_error(const char* wrong, const int* states, const char* const* lookup, int len, const std::function* report_error); +[[noreturn]] inline void dfa_error(const char *wrong, const int *states, const char * const *lookup, int len, const std::function * report_error); /** * Internal error function for xs:all validators. */ template -[[noreturn]] inline void all_error(std::bitset gstate, const char* const* lookup, const std::function* report_error); +[[noreturn]] inline void all_error(std::bitset gstate, const char * const *lookup, const std::function * report_error); /** * Internal error function for attribute validators. */ template -[[noreturn]] inline void attr_error(std::bitset astate, const char* const* lookup, const std::function* report_error); +[[noreturn]] inline void attr_error(std::bitset astate, const char * const *lookup, const std::function * report_error); + + +/* Lookup tables for enums. */ +constexpr const char *lookup_route_model_type[] = {"UXSD_INVALID", "ideal", "route", "dedicated_network"}; + +/* Lexers(string->token functions) for enums. */ +inline enum_route_model_type lex_enum_route_model_type(const char *in, bool throw_on_invalid, const std::function * report_error){ + unsigned int len = strlen(in); + switch(len){ + case 5: + switch(*((triehash_uu32*)&in[0])){ + case onechar('i', 0, 32) | onechar('d', 8, 32) | onechar('e', 16, 32) | onechar('a', 24, 32): + switch(in[4]){ + case onechar('l', 0, 8): + return enum_route_model_type::IDEAL; + break; + default: break; + } + break; + case onechar('r', 0, 32) | onechar('o', 8, 32) | onechar('u', 16, 32) | onechar('t', 24, 32): + switch(in[4]){ + case onechar('e', 0, 8): + return enum_route_model_type::ROUTE; + break; + default: break; + } + break; + default: break; + } + break; + case 17: + switch(*((triehash_uu64*)&in[0])){ + case onechar('d', 0, 64) | onechar('e', 8, 64) | onechar('d', 16, 64) | onechar('i', 24, 64) | onechar('c', 32, 64) | onechar('a', 40, 64) | onechar('t', 48, 64) | onechar('e', 56, 64): + switch(*((triehash_uu64*)&in[8])){ + case onechar('d', 0, 64) | onechar('_', 8, 64) | onechar('n', 16, 64) | onechar('e', 24, 64) | onechar('t', 32, 64) | onechar('w', 40, 64) | onechar('o', 48, 64) | onechar('r', 56, 64): + switch(in[16]){ + case onechar('k', 0, 8): + return enum_route_model_type::DEDICATED_NETWORK; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + if(throw_on_invalid) + noreturn_report(report_error, ("Found unrecognized enum value " + std::string(in) + " of enum_route_model_type.").c_str()); + return enum_route_model_type::UXSD_INVALID; +} + /* Internal loading functions, which validate and load a PugiXML DOM tree into memory. */ -inline int load_int(const char* in, const std::function* report_error) { - int out; - // global variable, must set to 0 before using it to avoid changed by other errors - errno = 0; - out = std::strtol(in, NULL, 10); - if (errno != 0) - noreturn_report(report_error, ("Invalid value `" + std::string(in) + "` when loading into a int.").c_str()); - return out; +inline int load_int(const char *in, const std::function * report_error){ + int out; + out = std::strtol(in, NULL, 10); + if(errno != 0) + noreturn_report(report_error, ("Invalid value `" + std::string(in) + "` when loading into a int.").c_str()); + return out; +} +inline void load_add_region_required_attributes(const pugi::xml_node &root, int * x_high, int * x_low, int * y_high, int * y_low, const std::function * report_error){ + std::bitset<5> astate = 0; + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_add_region in = lex_attr_t_add_region(attr.name(), report_error); + if(astate[(int)in] == 0) astate[(int)in] = 1; + else noreturn_report(report_error, ("Duplicate attribute " + std::string(attr.name()) + " in .").c_str()); + switch(in){ + case atok_t_add_region::SUBTILE: + /* Attribute subtile set after element init */ + break; + case atok_t_add_region::X_HIGH: + *x_high = load_int(attr.value(), report_error); + break; + case atok_t_add_region::X_LOW: + *x_low = load_int(attr.value(), report_error); + break; + case atok_t_add_region::Y_HIGH: + *y_high = load_int(attr.value(), report_error); + break; + case atok_t_add_region::Y_LOW: + *y_low = load_int(attr.value(), report_error); + break; + default: break; /* Not possible. */ + } + } + std::bitset<5> test_astate = astate | std::bitset<5>(0b00001); + if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_add_region, report_error); } -inline void load_add_region_required_attributes(const pugi::xml_node& root, int* x_high, int* x_low, int* y_high, int* y_low, const std::function* report_error) { - std::bitset<5> astate = 0; - for (pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()) { - atok_t_add_region in = lex_attr_t_add_region(attr.name(), report_error); - if (astate[(int)in] == 0) - astate[(int)in] = 1; - else - noreturn_report(report_error, ("Duplicate attribute " + std::string(attr.name()) + " in .").c_str()); - switch (in) { - case atok_t_add_region::SUBTILE: - /* Attribute subtile set after element init */ - break; - case atok_t_add_region::X_HIGH: - *x_high = load_int(attr.value(), report_error); - break; - case atok_t_add_region::X_LOW: - *x_low = load_int(attr.value(), report_error); - break; - case atok_t_add_region::Y_HIGH: - *y_high = load_int(attr.value(), report_error); - break; - case atok_t_add_region::Y_LOW: - *y_low = load_int(attr.value(), report_error); - break; - default: - break; /* Not possible. */ - } - } - std::bitset<5> test_astate = astate | std::bitset<5>(0b00001); - if (!test_astate.all()) attr_error(test_astate, atok_lookup_t_add_region, report_error); + +inline void load_set_global_signal_required_attributes(const pugi::xml_node &root, enum_route_model_type * route_model, const std::function * report_error){ + std::bitset<3> astate = 0; + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_set_global_signal in = lex_attr_t_set_global_signal(attr.name(), report_error); + if(astate[(int)in] == 0) astate[(int)in] = 1; + else noreturn_report(report_error, ("Duplicate attribute " + std::string(attr.name()) + " in .").c_str()); + switch(in){ + case atok_t_set_global_signal::NAME: + /* Attribute name set after element init */ + break; + case atok_t_set_global_signal::NETWORK_NAME: + /* Attribute network_name set after element init */ + break; + case atok_t_set_global_signal::ROUTE_MODEL: + *route_model = lex_enum_route_model_type(attr.value(), true, report_error); + break; + default: break; /* Not possible. */ + } + } + std::bitset<3> test_astate = astate | std::bitset<3>(0b010); + if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_set_global_signal, report_error); } template -inline void load_add_atom(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug) { - (void)root; - (void)out; - (void)context; - (void)report_error; - // Update current file offset in case an error is encountered. - *offset_debug = root.offset_debug(); - - for (pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()) { - atok_t_add_atom in = lex_attr_t_add_atom(attr.name(), report_error); - switch (in) { - case atok_t_add_atom::NAME_PATTERN: - out.set_add_atom_name_pattern(attr.value(), context); - break; - default: - break; /* Not possible. */ - } - } - - if (root.first_child().type() == pugi::node_element) - noreturn_report(report_error, "Unexpected child element in ."); +inline void load_add_atom(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_add_atom in = lex_attr_t_add_atom(attr.name(), report_error); + switch(in){ + case atok_t_add_atom::NAME_PATTERN: + out.set_add_atom_name_pattern(attr.value(), context); + break; + default: break; /* Not possible. */ + } + } + + if(root.first_child().type() == pugi::node_element) + noreturn_report(report_error, "Unexpected child element in ."); + } template -inline void load_add_region(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug) { - (void)root; - (void)out; - (void)context; - (void)report_error; - // Update current file offset in case an error is encountered. - *offset_debug = root.offset_debug(); - - for (pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()) { - atok_t_add_region in = lex_attr_t_add_region(attr.name(), report_error); - switch (in) { - case atok_t_add_region::SUBTILE: - out.set_add_region_subtile(load_int(attr.value(), report_error), context); - break; - case atok_t_add_region::X_HIGH: - /* Attribute x_high is already set */ - break; - case atok_t_add_region::X_LOW: - /* Attribute x_low is already set */ - break; - case atok_t_add_region::Y_HIGH: - /* Attribute y_high is already set */ - break; - case atok_t_add_region::Y_LOW: - /* Attribute y_low is already set */ - break; - default: - break; /* Not possible. */ - } - } - - if (root.first_child().type() == pugi::node_element) - noreturn_report(report_error, "Unexpected child element in ."); +inline void load_add_region(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_add_region in = lex_attr_t_add_region(attr.name(), report_error); + switch(in){ + case atok_t_add_region::SUBTILE: + out.set_add_region_subtile(load_int(attr.value(), report_error), context); + break; + case atok_t_add_region::X_HIGH: + /* Attribute x_high is already set */ + break; + case atok_t_add_region::X_LOW: + /* Attribute x_low is already set */ + break; + case atok_t_add_region::Y_HIGH: + /* Attribute y_high is already set */ + break; + case atok_t_add_region::Y_LOW: + /* Attribute y_low is already set */ + break; + default: break; /* Not possible. */ + } + } + + if(root.first_child().type() == pugi::node_element) + noreturn_report(report_error, "Unexpected child element in ."); + } constexpr int NUM_T_PARTITION_STATES = 2; constexpr const int NUM_T_PARTITION_INPUTS = 2; constexpr int gstate_t_partition[NUM_T_PARTITION_STATES][NUM_T_PARTITION_INPUTS] = { - {0, 0}, - {0, 0}, + {0, 0}, + {0, 0}, }; template -inline void load_partition(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug) { - (void)root; - (void)out; - (void)context; - (void)report_error; - // Update current file offset in case an error is encountered. - *offset_debug = root.offset_debug(); - - for (pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()) { - atok_t_partition in = lex_attr_t_partition(attr.name(), report_error); - switch (in) { - case atok_t_partition::NAME: - out.set_partition_name(attr.value(), context); - break; - default: - break; /* Not possible. */ - } - } - - // Preallocate arrays by counting child nodes (if any) - size_t add_atom_count = 0; - size_t add_region_count = 0; - { - int next, state = 1; - for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { - *offset_debug = node.offset_debug(); - gtok_t_partition in = lex_node_t_partition(node.name(), report_error); - next = gstate_t_partition[state][(int)in]; - if (next == -1) - dfa_error(gtok_lookup_t_partition[(int)in], gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); - state = next; - switch (in) { - case gtok_t_partition::ADD_ATOM: - add_atom_count += 1; - break; - case gtok_t_partition::ADD_REGION: - add_region_count += 1; - break; - default: - break; /* Not possible. */ - } - } - - out.preallocate_partition_add_atom(context, add_atom_count); - out.preallocate_partition_add_region(context, add_region_count); - } - int next, state = 1; - for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { - *offset_debug = node.offset_debug(); - gtok_t_partition in = lex_node_t_partition(node.name(), report_error); - next = gstate_t_partition[state][(int)in]; - if (next == -1) - dfa_error(gtok_lookup_t_partition[(int)in], gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); - state = next; - switch (in) { - case gtok_t_partition::ADD_ATOM: { - auto child_context = out.add_partition_add_atom(context); - load_add_atom(node, out, child_context, report_error, offset_debug); - out.finish_partition_add_atom(child_context); - } break; - case gtok_t_partition::ADD_REGION: { - int add_region_x_high; - memset(&add_region_x_high, 0, sizeof(add_region_x_high)); - int add_region_x_low; - memset(&add_region_x_low, 0, sizeof(add_region_x_low)); - int add_region_y_high; - memset(&add_region_y_high, 0, sizeof(add_region_y_high)); - int add_region_y_low; - memset(&add_region_y_low, 0, sizeof(add_region_y_low)); - load_add_region_required_attributes(node, &add_region_x_high, &add_region_x_low, &add_region_y_high, &add_region_y_low, report_error); - auto child_context = out.add_partition_add_region(context, add_region_x_high, add_region_x_low, add_region_y_high, add_region_y_low); - load_add_region(node, out, child_context, report_error, offset_debug); - out.finish_partition_add_region(child_context); - } break; - default: - break; /* Not possible. */ - } - } - if (state != 0) dfa_error("end of input", gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); +inline void load_partition(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_partition in = lex_attr_t_partition(attr.name(), report_error); + switch(in){ + case atok_t_partition::NAME: + out.set_partition_name(attr.value(), context); + break; + default: break; /* Not possible. */ + } + } + + // Preallocate arrays by counting child nodes (if any) + size_t add_atom_count = 0; + size_t add_region_count = 0; + { + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { + *offset_debug = node.offset_debug(); + gtok_t_partition in = lex_node_t_partition(node.name(), report_error); + next = gstate_t_partition[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_partition[(int)in], gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); + state = next; + switch(in) { + case gtok_t_partition::ADD_ATOM: + add_atom_count += 1; + break; + case gtok_t_partition::ADD_REGION: + add_region_count += 1; + break; + default: break; /* Not possible. */ + } + } + + out.preallocate_partition_add_atom(context, add_atom_count); + out.preallocate_partition_add_region(context, add_region_count); + } + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()){ + *offset_debug = node.offset_debug(); + gtok_t_partition in = lex_node_t_partition(node.name(), report_error); + next = gstate_t_partition[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_partition[(int)in], gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); + state = next; + switch(in){ + case gtok_t_partition::ADD_ATOM: + { + auto child_context = out.add_partition_add_atom(context); + load_add_atom(node, out, child_context, report_error, offset_debug); + out.finish_partition_add_atom(child_context); + } + break; + case gtok_t_partition::ADD_REGION: + { + int add_region_x_high; + memset(&add_region_x_high, 0, sizeof(add_region_x_high)); + int add_region_x_low; + memset(&add_region_x_low, 0, sizeof(add_region_x_low)); + int add_region_y_high; + memset(&add_region_y_high, 0, sizeof(add_region_y_high)); + int add_region_y_low; + memset(&add_region_y_low, 0, sizeof(add_region_y_low)); + load_add_region_required_attributes(node, &add_region_x_high, &add_region_x_low, &add_region_y_high, &add_region_y_low, report_error); + auto child_context = out.add_partition_add_region(context, add_region_x_high, add_region_x_low, add_region_y_high, add_region_y_low); + load_add_region(node, out, child_context, report_error, offset_debug); + out.finish_partition_add_region(child_context); + } + break; + default: break; /* Not possible. */ + } + } + if(state != 0) dfa_error("end of input", gstate_t_partition[state], gtok_lookup_t_partition, 2, report_error); + } constexpr int NUM_T_PARTITION_LIST_STATES = 2; constexpr const int NUM_T_PARTITION_LIST_INPUTS = 1; constexpr int gstate_t_partition_list[NUM_T_PARTITION_LIST_STATES][NUM_T_PARTITION_LIST_INPUTS] = { - {0}, - {0}, + {0}, + {0}, +}; +template +inline void load_partition_list(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + if(root.first_attribute()) + noreturn_report(report_error, "Unexpected attribute in ."); + + // Preallocate arrays by counting child nodes (if any) + size_t partition_count = 0; + { + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { + *offset_debug = node.offset_debug(); + gtok_t_partition_list in = lex_node_t_partition_list(node.name(), report_error); + next = gstate_t_partition_list[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_partition_list[(int)in], gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); + state = next; + switch(in) { + case gtok_t_partition_list::PARTITION: + partition_count += 1; + break; + default: break; /* Not possible. */ + } + } + + out.preallocate_partition_list_partition(context, partition_count); + } + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()){ + *offset_debug = node.offset_debug(); + gtok_t_partition_list in = lex_node_t_partition_list(node.name(), report_error); + next = gstate_t_partition_list[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_partition_list[(int)in], gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); + state = next; + switch(in){ + case gtok_t_partition_list::PARTITION: + { + auto child_context = out.add_partition_list_partition(context); + load_partition(node, out, child_context, report_error, offset_debug); + out.finish_partition_list_partition(child_context); + } + break; + default: break; /* Not possible. */ + } + } + if(state != 0) dfa_error("end of input", gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); + +} + +template +inline void load_set_global_signal(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_set_global_signal in = lex_attr_t_set_global_signal(attr.name(), report_error); + switch(in){ + case atok_t_set_global_signal::NAME: + out.set_set_global_signal_name(attr.value(), context); + break; + case atok_t_set_global_signal::NETWORK_NAME: + out.set_set_global_signal_network_name(attr.value(), context); + break; + case atok_t_set_global_signal::ROUTE_MODEL: + /* Attribute route_model is already set */ + break; + default: break; /* Not possible. */ + } + } + + if(root.first_child().type() == pugi::node_element) + noreturn_report(report_error, "Unexpected child element in ."); + +} + +constexpr int NUM_T_GLOBAL_ROUTE_CONSTRAINTS_STATES = 2; +constexpr const int NUM_T_GLOBAL_ROUTE_CONSTRAINTS_INPUTS = 1; +constexpr int gstate_t_global_route_constraints[NUM_T_GLOBAL_ROUTE_CONSTRAINTS_STATES][NUM_T_GLOBAL_ROUTE_CONSTRAINTS_INPUTS] = { + {0}, + {0}, }; template -inline void load_partition_list(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug) { - (void)root; - (void)out; - (void)context; - (void)report_error; - // Update current file offset in case an error is encountered. - *offset_debug = root.offset_debug(); - - if (root.first_attribute()) - noreturn_report(report_error, "Unexpected attribute in ."); - - // Preallocate arrays by counting child nodes (if any) - size_t partition_count = 0; - { - int next, state = 1; - for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { - *offset_debug = node.offset_debug(); - gtok_t_partition_list in = lex_node_t_partition_list(node.name(), report_error); - next = gstate_t_partition_list[state][(int)in]; - if (next == -1) - dfa_error(gtok_lookup_t_partition_list[(int)in], gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); - state = next; - switch (in) { - case gtok_t_partition_list::PARTITION: - partition_count += 1; - break; - default: - break; /* Not possible. */ - } - } - - out.preallocate_partition_list_partition(context, partition_count); - } - int next, state = 1; - for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { - *offset_debug = node.offset_debug(); - gtok_t_partition_list in = lex_node_t_partition_list(node.name(), report_error); - next = gstate_t_partition_list[state][(int)in]; - if (next == -1) - dfa_error(gtok_lookup_t_partition_list[(int)in], gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); - state = next; - switch (in) { - case gtok_t_partition_list::PARTITION: { - auto child_context = out.add_partition_list_partition(context); - load_partition(node, out, child_context, report_error, offset_debug); - out.finish_partition_list_partition(child_context); - } break; - default: - break; /* Not possible. */ - } - } - if (state != 0) dfa_error("end of input", gstate_t_partition_list[state], gtok_lookup_t_partition_list, 1, report_error); +inline void load_global_route_constraints(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + if(root.first_attribute()) + noreturn_report(report_error, "Unexpected attribute in ."); + + // Preallocate arrays by counting child nodes (if any) + size_t set_global_signal_count = 0; + { + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { + *offset_debug = node.offset_debug(); + gtok_t_global_route_constraints in = lex_node_t_global_route_constraints(node.name(), report_error); + next = gstate_t_global_route_constraints[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_global_route_constraints[(int)in], gstate_t_global_route_constraints[state], gtok_lookup_t_global_route_constraints, 1, report_error); + state = next; + switch(in) { + case gtok_t_global_route_constraints::SET_GLOBAL_SIGNAL: + set_global_signal_count += 1; + break; + default: break; /* Not possible. */ + } + } + + out.preallocate_global_route_constraints_set_global_signal(context, set_global_signal_count); + } + int next, state=1; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()){ + *offset_debug = node.offset_debug(); + gtok_t_global_route_constraints in = lex_node_t_global_route_constraints(node.name(), report_error); + next = gstate_t_global_route_constraints[state][(int)in]; + if(next == -1) + dfa_error(gtok_lookup_t_global_route_constraints[(int)in], gstate_t_global_route_constraints[state], gtok_lookup_t_global_route_constraints, 1, report_error); + state = next; + switch(in){ + case gtok_t_global_route_constraints::SET_GLOBAL_SIGNAL: + { + enum_route_model_type set_global_signal_route_model; + memset(&set_global_signal_route_model, 0, sizeof(set_global_signal_route_model)); + load_set_global_signal_required_attributes(node, &set_global_signal_route_model, report_error); + auto child_context = out.add_global_route_constraints_set_global_signal(context, set_global_signal_route_model); + load_set_global_signal(node, out, child_context, report_error, offset_debug); + out.finish_global_route_constraints_set_global_signal(child_context); + } + break; + default: break; /* Not possible. */ + } + } + if(state != 0) dfa_error("end of input", gstate_t_global_route_constraints[state], gtok_lookup_t_global_route_constraints, 1, report_error); + } template -inline void load_vpr_constraints(const pugi::xml_node& root, T& out, Context& context, const std::function* report_error, ptrdiff_t* offset_debug) { - (void)root; - (void)out; - (void)context; - (void)report_error; - // Update current file offset in case an error is encountered. - *offset_debug = root.offset_debug(); - - for (pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()) { - atok_t_vpr_constraints in = lex_attr_t_vpr_constraints(attr.name(), report_error); - switch (in) { - case atok_t_vpr_constraints::TOOL_NAME: - out.set_vpr_constraints_tool_name(attr.value(), context); - break; - default: - break; /* Not possible. */ - } - } - - std::bitset<1> gstate = 0; - for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling()) { - *offset_debug = node.offset_debug(); - gtok_t_vpr_constraints in = lex_node_t_vpr_constraints(node.name(), report_error); - if (gstate[(int)in] == 0) - gstate[(int)in] = 1; - else - noreturn_report(report_error, ("Duplicate element " + std::string(node.name()) + " in .").c_str()); - switch (in) { - case gtok_t_vpr_constraints::PARTITION_LIST: { - auto child_context = out.init_vpr_constraints_partition_list(context); - load_partition_list(node, out, child_context, report_error, offset_debug); - out.finish_vpr_constraints_partition_list(child_context); - } break; - default: - break; /* Not possible. */ - } - } - std::bitset<1> test_gstate = gstate | std::bitset<1>(0b0); - if (!test_gstate.all()) all_error(test_gstate, gtok_lookup_t_vpr_constraints, report_error); +inline void load_vpr_constraints(const pugi::xml_node &root, T &out, Context &context, const std::function *report_error, ptrdiff_t *offset_debug){ + (void)root; + (void)out; + (void)context; + (void)report_error; + // Update current file offset in case an error is encountered. + *offset_debug = root.offset_debug(); + + for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ + atok_t_vpr_constraints in = lex_attr_t_vpr_constraints(attr.name(), report_error); + switch(in){ + case atok_t_vpr_constraints::TOOL_NAME: + out.set_vpr_constraints_tool_name(attr.value(), context); + break; + default: break; /* Not possible. */ + } + } + + std::bitset<2> gstate = 0; + for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling()){ + *offset_debug = node.offset_debug(); + gtok_t_vpr_constraints in = lex_node_t_vpr_constraints(node.name(), report_error); + if(gstate[(int)in] == 0) gstate[(int)in] = 1; + else noreturn_report(report_error, ("Duplicate element " + std::string(node.name()) + " in .").c_str()); + switch(in){ + case gtok_t_vpr_constraints::PARTITION_LIST: + { + auto child_context = out.init_vpr_constraints_partition_list(context); + load_partition_list(node, out, child_context, report_error, offset_debug); + out.finish_vpr_constraints_partition_list(child_context); + } + break; + case gtok_t_vpr_constraints::GLOBAL_ROUTE_CONSTRAINTS: + { + auto child_context = out.init_vpr_constraints_global_route_constraints(context); + load_global_route_constraints(node, out, child_context, report_error, offset_debug); + out.finish_vpr_constraints_global_route_constraints(child_context); + } + break; + default: break; /* Not possible. */ + } + } + std::bitset<2> test_gstate = gstate | std::bitset<2>(0b11); + if(!test_gstate.all()) all_error(test_gstate, gtok_lookup_t_vpr_constraints, report_error); + } + /* Internal writing functions, which uxsdcxx uses to write out a class. */ template -inline void write_partition(T& in, std::ostream& os, Context& context) { - (void)in; - (void)os; - (void)context; - { - for (size_t i = 0, n = in.num_partition_add_atom(context); i < n; i++) { - auto child_context = in.get_partition_add_atom(i, context); - os << "\n"; - } - } - { - for (size_t i = 0, n = in.num_partition_add_region(context); i < n; i++) { - auto child_context = in.get_partition_add_region(i, context); - os << "\n"; - } - } +inline void write_partition(T &in, std::ostream &os, Context &context){ + (void)in; + (void)os; + (void)context; + { + for(size_t i=0, n=in.num_partition_add_atom(context); i\n"; + } + } + { + for(size_t i=0, n=in.num_partition_add_region(context); i\n"; + } + } } template -inline void write_partition_list(T& in, std::ostream& os, Context& context) { - (void)in; - (void)os; - (void)context; - { - for (size_t i = 0, n = in.num_partition_list_partition(context); i < n; i++) { - auto child_context = in.get_partition_list_partition(i, context); - os << ""; - write_partition(in, os, child_context); - os << "\n"; - } - } +inline void write_partition_list(T &in, std::ostream &os, Context &context){ + (void)in; + (void)os; + (void)context; + { + for(size_t i=0, n=in.num_partition_list_partition(context); i"; + write_partition(in, os, child_context); + os << "\n"; + } + } } template -inline void write_vpr_constraints(T& in, std::ostream& os, Context& context) { - (void)in; - (void)os; - (void)context; - { - auto child_context = in.get_vpr_constraints_partition_list(context); - os << "\n"; - write_partition_list(in, os, child_context); - os << "\n"; - } +inline void write_global_route_constraints(T &in, std::ostream &os, Context &context){ + (void)in; + (void)os; + (void)context; + { + for(size_t i=0, n=in.num_global_route_constraints_set_global_signal(context); i\n"; + } + } } -inline void dfa_error(const char* wrong, const int* states, const char* const* lookup, int len, const std::function* report_error) { - std::vector expected; - for (int i = 0; i < len; i++) { - if (states[i] != -1) expected.push_back(lookup[i]); - } +template +inline void write_vpr_constraints(T &in, std::ostream &os, Context &context){ + (void)in; + (void)os; + (void)context; + { + if(in.has_vpr_constraints_partition_list(context)){ + auto child_context = in.get_vpr_constraints_partition_list(context); + os << "\n"; + write_partition_list(in, os, child_context); + os << "\n"; + } + } + { + if(in.has_vpr_constraints_global_route_constraints(context)){ + auto child_context = in.get_vpr_constraints_global_route_constraints(context); + os << "\n"; + write_global_route_constraints(in, os, child_context); + os << "\n"; + } + } +} - std::string expected_or = expected[0]; - for (unsigned int i = 1; i < expected.size(); i++) - expected_or += std::string(" or ") + expected[i]; +inline void dfa_error(const char *wrong, const int *states, const char * const *lookup, int len, const std::function * report_error){ + std::vector expected; + for(int i=0; i -inline void all_error(std::bitset gstate, const char* const* lookup, const std::function* report_error) { - std::vector missing; - for (unsigned int i = 0; i < N; i++) { - if (gstate[i] == 0) missing.push_back(lookup[i]); - } +inline void all_error(std::bitset gstate, const char * const *lookup, const std::function * report_error){ + std::vector missing; + for(unsigned int i=0; i -inline void attr_error(std::bitset astate, const char* const* lookup, const std::function* report_error) { - std::vector missing; - for (unsigned int i = 0; i < N; i++) { - if (astate[i] == 0) missing.push_back(lookup[i]); - } +inline void attr_error(std::bitset astate, const char * const *lookup, const std::function * report_error){ + std::vector missing; + for(unsigned int i=0; i f(fopen(filename, "rb"), fclose); - - if (!f) { - throw std::runtime_error(std::string("Failed to open file") + filename); - } - - int current_line = 1; - std::ptrdiff_t offset = 0; - std::ptrdiff_t last_line_offset = 0; - std::ptrdiff_t current_line_offset = 0; - - char buffer[1024]; - std::size_t size; - - while ((size = fread(buffer, 1, sizeof(buffer), f.get())) > 0) { - for (std::size_t i = 0; i < size; ++i) { - if (buffer[i] == '\n') { - current_line += 1; - last_line_offset = current_line_offset; - current_line_offset = offset + i; - - if (target_offset < current_line_offset) { - if (target_offset < last_line_offset) { - throw std::runtime_error("Assertion violation"); - } - - *line = current_line - 1; - *col = target_offset - last_line_offset; - return; - } - } - } - - offset += size; - } - - *line = current_line; - *col = target_offset - current_line_offset; +inline void get_line_number(const char *filename, std::ptrdiff_t target_offset, int * line, int * col) { + std::unique_ptr f(fopen(filename, "rb"), fclose); + + if (!f) { + throw std::runtime_error(std::string("Failed to open file") + filename); + } + + int current_line = 1; + std::ptrdiff_t offset = 0; + std::ptrdiff_t last_line_offset = 0; + std::ptrdiff_t current_line_offset = 0; + + char buffer[1024]; + std::size_t size; + + while ((size = fread(buffer, 1, sizeof(buffer), f.get())) > 0) { + for (std::size_t i = 0; i < size; ++i) { + if (buffer[i] == '\n') { + current_line += 1; + last_line_offset = current_line_offset; + current_line_offset = offset + i; + + if(target_offset < current_line_offset) { + if(target_offset < last_line_offset) { + throw std::runtime_error("Assertion violation"); + } + + *line = current_line - 1; + *col = target_offset - last_line_offset; + return; + } + } + } + + offset += size; + } + + *line = current_line; + *col = target_offset - current_line_offset; } + } /* namespace uxsd */ diff --git a/vpr/src/base/gen/vpr_constraints_uxsdcxx_interface.h b/vpr/src/base/gen/vpr_constraints_uxsdcxx_interface.h index 8939778861e..64c20239e6e 100644 --- a/vpr/src/base/gen/vpr_constraints_uxsdcxx_interface.h +++ b/vpr/src/base/gen/vpr_constraints_uxsdcxx_interface.h @@ -4,13 +4,14 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx.py vpr_constraints.xsd - * Input file: /home/khalid88/Documents/uxsdcxx/vpr_constraints.xsd - * md5sum of input file: 6b6011a6e6446347b234da82e517422e + * Cmdline: /home/kimia/uxsdcxx/uxsdcxx.py ../vpr_constraints.xsd + * Input file: /home/kimia/vtr-verilog-to-routing/vpr/src/base/vpr_constraints.xsd + * md5sum of input file: f2b3721db9b14ccdf0787c9c99e00a78 */ #include + /* All uxsdcxx functions and structs live in this namespace. */ #include @@ -18,104 +19,143 @@ namespace uxsd { +/* Enum tokens generated from XSD enumerations. */ + +enum class enum_route_model_type {UXSD_INVALID = 0, IDEAL, ROUTE, DEDICATED_NETWORK}; + /* Base class for the schema. */ struct DefaultVprConstraintsContextTypes { - using AddAtomReadContext = void*; - using AddRegionReadContext = void*; - using PartitionReadContext = void*; - using PartitionListReadContext = void*; - using VprConstraintsReadContext = void*; - using AddAtomWriteContext = void*; - using AddRegionWriteContext = void*; - using PartitionWriteContext = void*; - using PartitionListWriteContext = void*; - using VprConstraintsWriteContext = void*; +using AddAtomReadContext = void *; + using AddRegionReadContext = void *; + using PartitionReadContext = void *; + using PartitionListReadContext = void *; + using SetGlobalSignalReadContext = void *; + using GlobalRouteConstraintsReadContext = void *; + using VprConstraintsReadContext = void *; +using AddAtomWriteContext = void *; + using AddRegionWriteContext = void *; + using PartitionWriteContext = void *; + using PartitionListWriteContext = void *; + using SetGlobalSignalWriteContext = void *; + using GlobalRouteConstraintsWriteContext = void *; + using VprConstraintsWriteContext = void *; }; -template +template class VprConstraintsBase { - public: - virtual ~VprConstraintsBase() {} - virtual void start_load(const std::function* report_error) = 0; - virtual void finish_load() = 0; - virtual void start_write() = 0; - virtual void finish_write() = 0; - virtual void error_encountered(const char* file, int line, const char* message) = 0; - /** Generated for complex type "add_atom": - * - * - * - */ - virtual inline const char* get_add_atom_name_pattern(typename ContextTypes::AddAtomReadContext& ctx) = 0; - virtual inline void set_add_atom_name_pattern(const char* name_pattern, typename ContextTypes::AddAtomWriteContext& ctx) = 0; - - /** Generated for complex type "add_region": - * - * - * - * - * - * - * - */ - virtual inline int get_add_region_layer_num(typename ContextTypes::AddRegionReadContext& ctx) = 0; - virtual inline int get_add_region_subtile(typename ContextTypes::AddRegionReadContext& ctx) = 0; - virtual inline void set_add_region_subtile(int subtile, typename ContextTypes::AddRegionWriteContext& ctx) = 0; - virtual inline int get_add_region_x_high(typename ContextTypes::AddRegionReadContext& ctx) = 0; - virtual inline int get_add_region_x_low(typename ContextTypes::AddRegionReadContext& ctx) = 0; - virtual inline int get_add_region_y_high(typename ContextTypes::AddRegionReadContext& ctx) = 0; - virtual inline int get_add_region_y_low(typename ContextTypes::AddRegionReadContext& ctx) = 0; - - /** Generated for complex type "partition": - * - * - * - * - * - * - * - * - * - */ - virtual inline const char* get_partition_name(typename ContextTypes::PartitionReadContext& ctx) = 0; - virtual inline void set_partition_name(const char* name, typename ContextTypes::PartitionWriteContext& ctx) = 0; - virtual inline void preallocate_partition_add_atom(typename ContextTypes::PartitionWriteContext& ctx, size_t size) = 0; - virtual inline typename ContextTypes::AddAtomWriteContext add_partition_add_atom(typename ContextTypes::PartitionWriteContext& ctx) = 0; - virtual inline void finish_partition_add_atom(typename ContextTypes::AddAtomWriteContext& ctx) = 0; - virtual inline size_t num_partition_add_atom(typename ContextTypes::PartitionReadContext& ctx) = 0; - virtual inline typename ContextTypes::AddAtomReadContext get_partition_add_atom(int n, typename ContextTypes::PartitionReadContext& ctx) = 0; - virtual inline void preallocate_partition_add_region(typename ContextTypes::PartitionWriteContext& ctx, size_t size) = 0; - virtual inline typename ContextTypes::AddRegionWriteContext add_partition_add_region(typename ContextTypes::PartitionWriteContext& ctx, int x_high, int x_low, int y_high, int y_low) = 0; - virtual inline void finish_partition_add_region(typename ContextTypes::AddRegionWriteContext& ctx) = 0; - virtual inline size_t num_partition_add_region(typename ContextTypes::PartitionReadContext& ctx) = 0; - virtual inline typename ContextTypes::AddRegionReadContext get_partition_add_region(int n, typename ContextTypes::PartitionReadContext& ctx) = 0; - - /** Generated for complex type "partition_list": - * - * - * - * - * - */ - virtual inline void preallocate_partition_list_partition(typename ContextTypes::PartitionListWriteContext& ctx, size_t size) = 0; - virtual inline typename ContextTypes::PartitionWriteContext add_partition_list_partition(typename ContextTypes::PartitionListWriteContext& ctx) = 0; - virtual inline void finish_partition_list_partition(typename ContextTypes::PartitionWriteContext& ctx) = 0; - virtual inline size_t num_partition_list_partition(typename ContextTypes::PartitionListReadContext& ctx) = 0; - virtual inline typename ContextTypes::PartitionReadContext get_partition_list_partition(int n, typename ContextTypes::PartitionListReadContext& ctx) = 0; - - /** Generated for complex type "vpr_constraints": - * - * - * - * - * - * - */ - virtual inline const char* get_vpr_constraints_tool_name(typename ContextTypes::VprConstraintsReadContext& ctx) = 0; - virtual inline void set_vpr_constraints_tool_name(const char* tool_name, typename ContextTypes::VprConstraintsWriteContext& ctx) = 0; - virtual inline typename ContextTypes::PartitionListWriteContext init_vpr_constraints_partition_list(typename ContextTypes::VprConstraintsWriteContext& ctx) = 0; - virtual inline void finish_vpr_constraints_partition_list(typename ContextTypes::PartitionListWriteContext& ctx) = 0; - virtual inline typename ContextTypes::PartitionListReadContext get_vpr_constraints_partition_list(typename ContextTypes::VprConstraintsReadContext& ctx) = 0; +public: + virtual ~VprConstraintsBase() {} + virtual void start_load(const std::function *report_error) = 0; + virtual void finish_load() = 0; + virtual void start_write() = 0; + virtual void finish_write() = 0; + virtual void error_encountered(const char * file, int line, const char *message) = 0; + /** Generated for complex type "add_atom": + * + * + * + */ + virtual inline const char * get_add_atom_name_pattern(typename ContextTypes::AddAtomReadContext &ctx) = 0; + virtual inline void set_add_atom_name_pattern(const char * name_pattern, typename ContextTypes::AddAtomWriteContext &ctx) = 0; + + /** Generated for complex type "add_region": + * + * + * + * + * + * + * + */ + virtual inline int get_add_region_subtile(typename ContextTypes::AddRegionReadContext &ctx) = 0; + virtual inline void set_add_region_subtile(int subtile, typename ContextTypes::AddRegionWriteContext &ctx) = 0; + virtual inline int get_add_region_x_high(typename ContextTypes::AddRegionReadContext &ctx) = 0; + virtual inline int get_add_region_x_low(typename ContextTypes::AddRegionReadContext &ctx) = 0; + virtual inline int get_add_region_y_high(typename ContextTypes::AddRegionReadContext &ctx) = 0; + virtual inline int get_add_region_y_low(typename ContextTypes::AddRegionReadContext &ctx) = 0; + + /** Generated for complex type "partition": + * + * + * + * + * + * + * + * + * + */ + virtual inline const char * get_partition_name(typename ContextTypes::PartitionReadContext &ctx) = 0; + virtual inline void set_partition_name(const char * name, typename ContextTypes::PartitionWriteContext &ctx) = 0; + virtual inline void preallocate_partition_add_atom(typename ContextTypes::PartitionWriteContext &ctx, size_t size) = 0; + virtual inline typename ContextTypes::AddAtomWriteContext add_partition_add_atom(typename ContextTypes::PartitionWriteContext &ctx) = 0; + virtual inline void finish_partition_add_atom(typename ContextTypes::AddAtomWriteContext &ctx) = 0; + virtual inline size_t num_partition_add_atom(typename ContextTypes::PartitionReadContext &ctx) = 0; + virtual inline typename ContextTypes::AddAtomReadContext get_partition_add_atom(int n, typename ContextTypes::PartitionReadContext &ctx) = 0; + virtual inline void preallocate_partition_add_region(typename ContextTypes::PartitionWriteContext &ctx, size_t size) = 0; + virtual inline typename ContextTypes::AddRegionWriteContext add_partition_add_region(typename ContextTypes::PartitionWriteContext &ctx, int x_high, int x_low, int y_high, int y_low) = 0; + virtual inline void finish_partition_add_region(typename ContextTypes::AddRegionWriteContext &ctx) = 0; + virtual inline size_t num_partition_add_region(typename ContextTypes::PartitionReadContext &ctx) = 0; + virtual inline typename ContextTypes::AddRegionReadContext get_partition_add_region(int n, typename ContextTypes::PartitionReadContext &ctx) = 0; + + /** Generated for complex type "partition_list": + * + * + * + * + * + */ + virtual inline void preallocate_partition_list_partition(typename ContextTypes::PartitionListWriteContext &ctx, size_t size) = 0; + virtual inline typename ContextTypes::PartitionWriteContext add_partition_list_partition(typename ContextTypes::PartitionListWriteContext &ctx) = 0; + virtual inline void finish_partition_list_partition(typename ContextTypes::PartitionWriteContext &ctx) = 0; + virtual inline size_t num_partition_list_partition(typename ContextTypes::PartitionListReadContext &ctx) = 0; + virtual inline typename ContextTypes::PartitionReadContext get_partition_list_partition(int n, typename ContextTypes::PartitionListReadContext &ctx) = 0; + + /** Generated for complex type "set_global_signal": + * + * + * + * + * + */ + virtual inline const char * get_set_global_signal_name(typename ContextTypes::SetGlobalSignalReadContext &ctx) = 0; + virtual inline void set_set_global_signal_name(const char * name, typename ContextTypes::SetGlobalSignalWriteContext &ctx) = 0; + virtual inline const char * get_set_global_signal_network_name(typename ContextTypes::SetGlobalSignalReadContext &ctx) = 0; + virtual inline void set_set_global_signal_network_name(const char * network_name, typename ContextTypes::SetGlobalSignalWriteContext &ctx) = 0; + virtual inline enum_route_model_type get_set_global_signal_route_model(typename ContextTypes::SetGlobalSignalReadContext &ctx) = 0; + + /** Generated for complex type "global_route_constraints": + * + * + * + * + * + */ + virtual inline void preallocate_global_route_constraints_set_global_signal(typename ContextTypes::GlobalRouteConstraintsWriteContext &ctx, size_t size) = 0; + virtual inline typename ContextTypes::SetGlobalSignalWriteContext add_global_route_constraints_set_global_signal(typename ContextTypes::GlobalRouteConstraintsWriteContext &ctx, enum_route_model_type route_model) = 0; + virtual inline void finish_global_route_constraints_set_global_signal(typename ContextTypes::SetGlobalSignalWriteContext &ctx) = 0; + virtual inline size_t num_global_route_constraints_set_global_signal(typename ContextTypes::GlobalRouteConstraintsReadContext &ctx) = 0; + virtual inline typename ContextTypes::SetGlobalSignalReadContext get_global_route_constraints_set_global_signal(int n, typename ContextTypes::GlobalRouteConstraintsReadContext &ctx) = 0; + + /** Generated for complex type "vpr_constraints": + * + * + * + * + * + * + * + */ + virtual inline const char * get_vpr_constraints_tool_name(typename ContextTypes::VprConstraintsReadContext &ctx) = 0; + virtual inline void set_vpr_constraints_tool_name(const char * tool_name, typename ContextTypes::VprConstraintsWriteContext &ctx) = 0; + virtual inline typename ContextTypes::PartitionListWriteContext init_vpr_constraints_partition_list(typename ContextTypes::VprConstraintsWriteContext &ctx) = 0; + virtual inline void finish_vpr_constraints_partition_list(typename ContextTypes::PartitionListWriteContext &ctx) = 0; + virtual inline typename ContextTypes::PartitionListReadContext get_vpr_constraints_partition_list(typename ContextTypes::VprConstraintsReadContext &ctx) = 0; + virtual inline bool has_vpr_constraints_partition_list(typename ContextTypes::VprConstraintsReadContext &ctx) = 0; + virtual inline typename ContextTypes::GlobalRouteConstraintsWriteContext init_vpr_constraints_global_route_constraints(typename ContextTypes::VprConstraintsWriteContext &ctx) = 0; + virtual inline void finish_vpr_constraints_global_route_constraints(typename ContextTypes::GlobalRouteConstraintsWriteContext &ctx) = 0; + virtual inline typename ContextTypes::GlobalRouteConstraintsReadContext get_vpr_constraints_global_route_constraints(typename ContextTypes::VprConstraintsReadContext &ctx) = 0; + virtual inline bool has_vpr_constraints_global_route_constraints(typename ContextTypes::VprConstraintsReadContext &ctx) = 0; }; } /* namespace uxsd */ diff --git a/vpr/src/base/user_place_constraints.cpp b/vpr/src/base/user_place_constraints.cpp new file mode 100644 index 00000000000..b8a6f3bd999 --- /dev/null +++ b/vpr/src/base/user_place_constraints.cpp @@ -0,0 +1,89 @@ +#include "user_place_constraints.h" + +void UserPlaceConstraints::add_constrained_atom(AtomBlockId blk_id, PartitionId part_id) { + auto got = constrained_atoms.find(blk_id); + + /** + * Each atom can only be in one partition. If the atom is not found in constrained_atoms, it + * will be added with its partition id. + * If the atom is already in constrained_atoms, the partition id will be updated. + */ + if (got == constrained_atoms.end()) { + constrained_atoms.insert({blk_id, part_id}); + } else { + got->second = part_id; + } +} + +PartitionId UserPlaceConstraints::get_atom_partition(AtomBlockId blk_id) const { + auto got = constrained_atoms.find(blk_id); + + if (got == constrained_atoms.end()) { + return PartitionId::INVALID(); ///< atom is not in a partition, i.e. unconstrained + } else { + return got->second; + } +} + +void UserPlaceConstraints::add_partition(const Partition& part) { + partitions.push_back(part); +} + +const Partition& UserPlaceConstraints::get_partition(PartitionId part_id) const { + return partitions[part_id]; +} + +Partition& UserPlaceConstraints::get_mutable_partition(PartitionId part_id) { + return partitions[part_id]; +} + +std::vector UserPlaceConstraints::get_part_atoms(PartitionId part_id) const { + std::vector part_atoms; + + for (const auto& it : constrained_atoms) { + if (it.second == part_id) { + part_atoms.push_back(it.first); + } + } + + return part_atoms; +} + +int UserPlaceConstraints::get_num_partitions() const { + return partitions.size(); +} + +const PartitionRegion& UserPlaceConstraints::get_partition_pr(PartitionId part_id) const { + return partitions[part_id].get_part_region(); +} + +PartitionRegion& UserPlaceConstraints::get_mutable_partition_pr(PartitionId part_id) { + return partitions[part_id].get_mutable_part_region(); +} + +void print_placement_constraints(FILE* fp, const UserPlaceConstraints& constraints) { + std::vector atoms; + + int num_parts = constraints.get_num_partitions(); + + fprintf(fp, "\n Number of partitions is %d \n", num_parts); + + for (int i = 0; i < num_parts; i++) { + PartitionId part_id(i); + + const Partition& temp_part = constraints.get_partition(part_id); + + fprintf(fp, "\npartition_id: %zu\n", size_t(part_id)); + print_partition(fp, temp_part); + + atoms = constraints.get_part_atoms(part_id); + + int atoms_size = atoms.size(); + + fprintf(fp, "\tAtom vector size is %d\n", atoms_size); + fprintf(fp, "\tIds of atoms in partition: \n"); + for (auto atom_id : atoms) { + fprintf(fp, "\t#%zu\n", size_t(atom_id)); + } + } +} diff --git a/vpr/src/base/user_place_constraints.h b/vpr/src/base/user_place_constraints.h new file mode 100644 index 00000000000..b7bcf69f38a --- /dev/null +++ b/vpr/src/base/user_place_constraints.h @@ -0,0 +1,117 @@ +#ifndef USER_PLACE_CONSTRAINTS_H +#define USER_PLACE_CONSTRAINTS_H + +#include "vtr_vector.h" +#include "partition.h" +#include "partition_region.h" + +/** + * + * @brief This file defines the UserPlaceConstraints class used to store and read out data related to user-specified + * block and region constraints for the packing and placement stages. + * + * Overview + * ======== + * This class contains functions that read in and store information related to floorplan constraints from a constraints XML file. + * The XML file provides a partition list, with the names of the partitions, and each atom in the partition. + * It also specifies which regions the partitions should be placed in. Atoms cannot be placed in more than one partition. + * If an atom is assigned to more than one partition, the last partition is was assigned to will be the partition it is placed in. + * + * Related Classes + * =============== + * The following definitions are useful to understanding this class: + * + * Partition: a grouping of atoms that are constrained to a portion of an FPGA + * See vpr/src/base/partition.h for more detail + * + * Region: the x and y bounds of a rectangular region, optionally including a subtile value, + * that atoms in a partition are constrained to + * See vpr/src/base/region.h for more detail + * + * PartitionRegion: the union of regions that a partition can be placed in + * See vpr/src/base/partition_region.h for more detail + * + * + */ + +class UserPlaceConstraints { + public: + /** + * @brief Store the id of a constrained atom with the id of the partition it belongs to + * + * @param blk_id The atom being stored + * @param part_id The partition the atom is being constrained to + */ + void add_constrained_atom(AtomBlockId blk_id, PartitionId part_id); + + /** + * @brief Return id of the partition the atom belongs to + * + * If an atom is not in a partition (unconstrained), PartitionId::INVALID() is returned. + * + * @param blk_id The atom for which the partition id is needed + */ + PartitionId get_atom_partition(AtomBlockId blk_id) const; + /** + * @brief Store a partition + * + * @param part The partition being stored + */ + void add_partition(const Partition& part); + + /** + * @brief Return a partition + * + * @param part_id The id of the partition that is wanted + */ + const Partition& get_partition(PartitionId part_id) const; + + /** + * @brief Returns a mutable partition + * + * @param part_id The id of the partition that is wanted + */ + Partition& get_mutable_partition(PartitionId part_id); + + /** + * @brief Return all the atoms that belong to a partition + * + * @param part_id The id of the partition whose atoms are needed + */ + std::vector get_part_atoms(PartitionId part_id) const; + + /** + * @brief Returns the number of partitions in the object + */ + int get_num_partitions() const; + + /** + * @brief Returns the PartitionRegion belonging to the specified Partition + * + * @param part_id The id of the partition whose PartitionRegion is needed + */ + const PartitionRegion& get_partition_pr(PartitionId part_id) const; + + /** + * @brief Returns the mutable PartitionRegion belonging to the specified Partition + * + * @param part_id The id of the partition whose PartitionRegion is needed + */ + PartitionRegion& get_mutable_partition_pr(PartitionId part_id); + + private: + /** + * Store all constrained atoms + */ + std::unordered_map constrained_atoms; + + /** + * Store all partitions + */ + vtr::vector partitions; +}; + +///@brief used to print floorplanning constraints data from a VprConstraints object +void print_placement_constraints(FILE* fp, const UserPlaceConstraints& constraints); + +#endif /* USER_PLACE_CONSTRAINTS_H */ diff --git a/vpr/src/base/user_route_constraints.cpp b/vpr/src/base/user_route_constraints.cpp new file mode 100644 index 00000000000..52888811714 --- /dev/null +++ b/vpr/src/base/user_route_constraints.cpp @@ -0,0 +1,84 @@ +#include "user_route_constraints.h" + + +void UserRouteConstraints::add_route_constraint(std::string net_name, RoutingScheme route_scheme) { + route_constraints_.insert({net_name, route_scheme}); +} + + +const std::pair UserRouteConstraints::get_route_constraint_by_idx(std::size_t idx) const { + RoutingScheme route_scheme; + + // throw an error if the index is out of range + if ((route_constraints_.size() == 0) || (idx > route_constraints_.size() - 1)) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "in get_route_constraint_by_idx: index %u is out of range. The unordered map for route constraints has a size of %u\n", + idx, route_constraints_.size()); + } + + auto it = route_constraints_.begin(); + std::advance(it, idx); + return *it; +} + +bool UserRouteConstraints::has_routing_constraint(std::string net_name) const { + + // Check if there's an exact match for the net name + auto const& rc_itr = route_constraints_.find(net_name); + if (rc_itr != route_constraints_.end()) { + return true; + } + + // Check for wildcard matches + for (const auto& route_constraint : route_constraints_) { + if (std::regex_match(net_name, std::regex(route_constraint.first))) { + return true; + } + } + + // Return false if no match is found + return false; +} + +const RoutingScheme UserRouteConstraints::get_route_scheme_by_net_name(std::string net_name) const{ + + if(has_routing_constraint(net_name) == false) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "in get_route_scheme_by_net_name: no routing constraints exist for net name %s \n", + net_name.c_str()); + } + + RoutingScheme route_scheme; + auto const& rs_itr = route_constraints_.find(net_name); + if (rs_itr == route_constraints_.end()) { + // Check for wildcard matches + for (auto constraint : route_constraints_) { + if (std::regex_match(net_name, std::regex(constraint.first))) { + route_scheme = constraint.second; + break; + } + } + } else { + route_scheme = rs_itr->second; + } + return route_scheme; + +} + + +e_clock_modeling UserRouteConstraints::get_route_model_by_net_name(std::string net_name) const{ + RoutingScheme route_scheme = get_route_scheme_by_net_name(net_name); + return route_scheme.route_model(); +} + + +const std::string UserRouteConstraints::get_routing_network_name_by_net_name(std::string net_name) const{ + RoutingScheme route_scheme = get_route_scheme_by_net_name(net_name); + return route_scheme.network_name(); +} + + +int UserRouteConstraints::get_num_route_constraints(void) const { + return route_constraints_.size(); +} \ No newline at end of file diff --git a/vpr/src/base/user_route_constraints.h b/vpr/src/base/user_route_constraints.h new file mode 100644 index 00000000000..57d6a3d2455 --- /dev/null +++ b/vpr/src/base/user_route_constraints.h @@ -0,0 +1,158 @@ +#ifndef USER_ROUTE_CONSTRAINTS_H +#define USER_ROUTE_CONSTRAINTS_H + +#include "clock_modeling.h" +#include "vpr_error.h" +#include +#include + +/** + * @brief This class specifies a routing scheme for a global net. + * + * Global nets, such as clocks, may require special + * handling. Clocks are marked as global by default in VPR, but other nets can be specified + * as global in a user routing constraints file. + * + * The variable `route_model_` can decide between different routing schemes: + * - "ideal": The net is not routed. + * - "route": The net is routed through the general routing fabric. + * - "dedicated_network": The net is routed through a dedicated global clock network using + * the two-stage router. In the first stage the net source is routed + * to the clock network root and in the second stage the net is routed + * from the clock network root to the sinks + * In the third case, the variable `network_name_` specifies the name of the clock network + * through which the net should be routed. + */ +class RoutingScheme { +private: + std::string network_name_ = "INVALID"; // Name of the clock network (if applicable) + e_clock_modeling route_model_ = e_clock_modeling::ROUTED_CLOCK; + +public: + // Constructors + RoutingScheme() = default; + RoutingScheme(const std::string network_name, const e_clock_modeling route_model) + : network_name_(network_name), route_model_(route_model) {} + + // Getters + std::string network_name() const { + return network_name_; + } + + e_clock_modeling route_model() const { + return route_model_; + } + + // Setters + void set_network_name(const std::string& network_name) { + network_name_ = network_name; + } + + void set_route_model(e_clock_modeling route_model) { + route_model_ = route_model; + } + + // Reset network_name_ and route_model_ to their default values + void reset() { + network_name_ = "INVALID"; + route_model_ = e_clock_modeling::ROUTED_CLOCK; + } +}; + + +/** + * @brief This class is used to store information related to global route constraints from a constraints XML file. + * + * In the XML file, you can specify a list of global route constraints where you can specify the name of the net + * you want to be treated as global. Then, you can define the routing scheme, including the routing method and the + * name of the global network you want the net to be routed through (if applicable). + * + * This class contains an unordered map that stores the name of the global net as the key and the routing scheme + * for that net as the value. The name can also be a wildcard. + */ +class UserRouteConstraints { + public: + /** + * @brief Add a global route constraint for a specific net with its corresponding routing scheme. + * + * @param net_name The name of the net to which the route constraint applies. + * @param route_scheme The routing scheme specifying how the net should be routed. + */ + void add_route_constraint(std::string net_name, RoutingScheme route_scheme); + + /** + * @brief Get a global route constraint by its index. + * + * The index refers to the position of the key-value entry in the unordered map that stores + * the route constraints. This function has a linear complexity, and calling it in an outer + * loop may result in performance issues. Currently, it is primarily used in auto-generated + * constraint writer code that loops over the number of constraints and fetches them by index. + * + * @param index The index of the key-value entry in the unordered map. + * @return A pair containing the net name and its corresponding routing scheme. + */ + const std::pair get_route_constraint_by_idx(std::size_t idx) const; + + /** + * @brief Check if a routing constraint has been specified for a specific net. + * + * The net name can include wildcard / regex patterns. The function first searches for an exact match of the net name in the route_constraints collection. + * If no exact match is found, the method iterates through the entries in the collection, + * attempting to match the net name using wildcard or regex patterns. + * + * @param net_name The name of the net to check for a routing constraint. + * @return True if a routing constraint has been specified for the net, false otherwise. + */ + bool has_routing_constraint(std::string net_name) const; + + /** + * @brief Get the routing scheme for a specific net by its name. + * + * The net name may include wildcard patterns, which will be supported. + * + * @param net_name The name of the net for which to retrieve the routing scheme. + * @return The routing scheme associated with the specified net. + */ + const RoutingScheme get_route_scheme_by_net_name(std::string net_name) const; + + /** + * @brief Get the routing model for a specific net by its name. + * + * This function retrieves the routing scheme associated with a specific net and + * then obtains the routing method from the retrieved routing scheme. + * + * @param net_name The name of the net for which to retrieve the routing method. + * @return The routing method associated with the specified net. + * + * Note: This is a convenience method that just extracts part of the routing scheme. + * + */ + e_clock_modeling get_route_model_by_net_name(std::string net_name) const; + + /** + * @brief Get the name of the routing network for a specific net by its name. + * + * If the net's routing scheme is "dedicated_network", this function will return + * the name of the dedicated global clock network specified in the routing scheme. + * Otherwise, the function will return the default value "INVALID" since the network name + * is meaningful only when the routing method is "dedicated_network". + * + * @param net_name The name of the net for which to retrieve the name of the routing network. + * @return The name of the routing network associated with the specified net. + */ + const std::string get_routing_network_name_by_net_name(std::string net_name) const; + + /** + * @brief Get the total number of user-specified global route constraints. + */ + int get_num_route_constraints(void) const; + + + + private: + /** + * store all route constraints + */ + std::unordered_map route_constraints_; +}; +#endif /* USER_ROUTE_CONSTRAINTS_H */ \ No newline at end of file diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 41bd8e6e672..e23e98083cf 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -354,10 +354,16 @@ void vpr_init_with_options(const t_options* options, t_vpr_setup* vpr_setup, t_a } } - //Initialize vpr floorplanning constraints + //Initialize vpr floorplanning and routing constraints auto& filename_opts = vpr_setup->FileNameOpts; if (!filename_opts.read_vpr_constraints_file.empty()) { load_vpr_constraints_file(filename_opts.read_vpr_constraints_file.c_str()); + + // Check if there are route constraints specified, and if the clock modeling setting is explicitly specified + // If both conditions are met, issue a warning that the route constraints will override the clock modeling setting. + if (g_vpr_ctx.routing().constraints.get_num_route_constraints() && options->clock_modeling.provenance() == argparse::Provenance::SPECIFIED) { + VTR_LOG_WARN("Route constraint(s) detected and will override clock modeling setting.\n"); + } } fflush(stdout); @@ -387,7 +393,6 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) { return false; //Unimplementable } } - // For the time being, we decided to create the flat graph after placement is done. Thus, the is_flat parameter for this function //, since it is called before routing, should be false. vpr_create_device(vpr_setup, arch, false); @@ -805,6 +810,10 @@ RouteStatus vpr_route_flow(const Netlist<>& net_list, //Assume successful route_status = RouteStatus(true, -1); } else { //Do or load + + // set the net_is_ignored flag for nets that that have route_model set to ideal in route constraints + apply_route_constraints(g_vpr_ctx.routing().constraints); + int chan_width = router_opts.fixed_channel_width; NetPinsMatrix net_delay; diff --git a/vpr/src/base/vpr_constraints.cpp b/vpr/src/base/vpr_constraints.cpp index c44fc490ab3..9ae678c94e0 100644 --- a/vpr/src/base/vpr_constraints.cpp +++ b/vpr/src/base/vpr_constraints.cpp @@ -1,90 +1,18 @@ #include "vpr_constraints.h" -#include "partition.h" -void VprConstraints::add_constrained_atom(AtomBlockId blk_id, PartitionId part_id) { - auto got = constrained_atoms.find(blk_id); - /** - * Each atom can only be in one partition. If the atom is not found in constrained_atoms, it - * will be added with its partition id. - * If the atom is already in constrained_atoms, the partition id will be updated. - */ - if (got == constrained_atoms.end()) { - constrained_atoms.insert({blk_id, part_id}); - } else { - got->second = part_id; - } +UserPlaceConstraints& VprConstraints::mutable_place_constraints() { + return placement_constraints_; } -PartitionId VprConstraints::get_atom_partition(AtomBlockId blk_id) const { - auto got = constrained_atoms.find(blk_id); - - if (got == constrained_atoms.end()) { - return PartitionId::INVALID(); ///< atom is not in a partition, i.e. unconstrained - } else { - return got->second; - } -} - -void VprConstraints::add_partition(const Partition& part) { - partitions.push_back(part); -} - -const Partition& VprConstraints::get_partition(PartitionId part_id) const { - return partitions[part_id]; -} - -Partition& VprConstraints::get_mutable_partition(PartitionId part_id) { - return partitions[part_id]; -} - -std::vector VprConstraints::get_part_atoms(PartitionId part_id) const { - std::vector part_atoms; - - for (const auto& it : constrained_atoms) { - if (it.second == part_id) { - part_atoms.push_back(it.first); - } - } - - return part_atoms; +UserRouteConstraints& VprConstraints::mutable_route_constraints() { + return route_constraints_; } -int VprConstraints::get_num_partitions() const { - return partitions.size(); +const UserPlaceConstraints& VprConstraints::place_constraints() const { + return placement_constraints_; } -const PartitionRegion& VprConstraints::get_partition_pr(PartitionId part_id) const { - return partitions[part_id].get_part_region(); -} - -PartitionRegion& VprConstraints::get_mutable_partition_pr(PartitionId part_id) { - return partitions[part_id].get_mutable_part_region(); -} - -void print_constraints(FILE* fp, const VprConstraints& constraints) { - std::vector atoms; - - int num_parts = constraints.get_num_partitions(); - - fprintf(fp, "\n Number of partitions is %d \n", num_parts); - - for (int i = 0; i < num_parts; i++) { - PartitionId part_id(i); - - const Partition& temp_part = constraints.get_partition(part_id); - - fprintf(fp, "\npartition_id: %zu\n", size_t(part_id)); - print_partition(fp, temp_part); - - atoms = constraints.get_part_atoms(part_id); - - int atoms_size = atoms.size(); - - fprintf(fp, "\tAtom vector size is %d\n", atoms_size); - fprintf(fp, "\tIds of atoms in partition: \n"); - for (auto atom_id : atoms) { - fprintf(fp, "\t#%zu\n", size_t(atom_id)); - } - } +const UserRouteConstraints& VprConstraints::route_constraints() const { + return route_constraints_; } diff --git a/vpr/src/base/vpr_constraints.h b/vpr/src/base/vpr_constraints.h index 9dd09f47b82..0d5f8049a52 100644 --- a/vpr/src/base/vpr_constraints.h +++ b/vpr/src/base/vpr_constraints.h @@ -1,119 +1,57 @@ #ifndef VPR_CONSTRAINTS_H #define VPR_CONSTRAINTS_H -#include "vtr_vector.h" -#include "vpr_utils.h" -#include "partition.h" -#include "partition_region.h" +#include "user_place_constraints.h" +#include "user_route_constraints.h" + /** - * @file - * @brief This file defines the VprConstraints class used to store and read out data related to user-specified - * block and region constraints for the packing and placement stages. + * @brief This file defines the VprConstraints class, which encapsulates user-specified placement and routing constraints + * * * Overview * ======== - * This class contains functions that read in and store information from a constraints XML file. - * The XML file provides a partition list, with the names of the partitions, and each atom in the partition. - * It also specifies which regions the partitions should be placed in. Atoms cannot be placed in more than one partition. - * If an atom is assigned to more than one partition, the last partition is was assigned to will be the partition it is placed in. + * The VprConstraints class is used to load and manage user-specified constraints from an XML file. + * It includes instances of the UserRouteConstraints and UserPlaceConstraints classes, which hold routing and placement + * constraints, respectively. * * Related Classes * =============== - * The following definitions are useful to understanding this class: - * - * Partition: a grouping of atoms that are constrained to a portion of an FPGA - * See vpr/src/base/partition.h for more detail - * - * Region: the x and y bounds of a rectangular region, optionally including a subtile value, - * that atoms in a partition are constrained to - * See vpr/src/base/region.h for more detail - * - * PartitionRegion: the union of regions that a partition can be placed in - * See vpr/src/base/partition_region.h for more detail - * + * + * UserRouteConstraints: Stores routing constraints for global nets, specifying routing method and routing network name. + * See vpr/src/base/user_route_constraints.h for more detail. * + * UserPlaceConstraints: Stores block and region constraints for packing and placement stages. + * See vpr/src/base/user_place_constraints.h for more detail. */ - class VprConstraints { public: - /** - * @brief Store the id of a constrained atom with the id of the partition it belongs to - * - * @param blk_id The atom being stored - * @param part_id The partition the atom is being constrained to - */ - void add_constrained_atom(AtomBlockId blk_id, PartitionId part_id); - - /** - * @brief Return id of the partition the atom belongs to - * - * If an atom is not in a partition (unconstrained), PartitionId::INVALID() is returned. - * - * @param blk_id The atom for which the partition id is needed - */ - PartitionId get_atom_partition(AtomBlockId blk_id) const; /** - * @brief Store a partition - * - * @param part The partition being stored + * @brief Get a mutable reference to the UserPlaceConstraints instance. */ - void add_partition(const Partition& part); + UserPlaceConstraints& mutable_place_constraints(); /** - * @brief Return a partition - * - * @param part_id The id of the partition that is wanted + * @brief Get a mutable reference to the UserRouteConstraints instance. */ - const Partition& get_partition(PartitionId part_id) const; + UserRouteConstraints& mutable_route_constraints(); /** - * @brief Returns a mutable partition - * - * @param part_id The id of the partition that is wanted + * @brief Get a const reference to the UserPlaceConstraints instance. */ - Partition& get_mutable_partition(PartitionId part_id); + const UserPlaceConstraints& place_constraints() const; /** - * @brief Return all the atoms that belong to a partition - * - * @param part_id The id of the partition whose atoms are needed + * @brief Get a const reference to the UserRouteConstraints instance. */ - std::vector get_part_atoms(PartitionId part_id) const; - - /** - * @brief Returns the number of partitions in the object - */ - int get_num_partitions() const; - - /** - * @brief Returns the PartitionRegion belonging to the specified Partition - * - * @param part_id The id of the partition whose PartitionRegion is needed - */ - const PartitionRegion& get_partition_pr(PartitionId part_id) const; - - /** - * @brief Returns the mutable PartitionRegion belonging to the specified Partition - * - * @param part_id The id of the partition whose PartitionRegion is needed - */ - PartitionRegion& get_mutable_partition_pr(PartitionId part_id); + const UserRouteConstraints& route_constraints() const; private: - /** - * Store all constrained atoms - */ - std::unordered_map constrained_atoms; + + UserRouteConstraints route_constraints_; + UserPlaceConstraints placement_constraints_; - /** - * Store all partitions - */ - vtr::vector partitions; }; -///@brief used to print floorplanning constraints data from a VprConstraints object -void print_constraints(FILE* fp, const VprConstraints& constraints); - #endif /* VPR_CONSTRAINTS_H */ diff --git a/vpr/src/base/vpr_constraints.xsd b/vpr/src/base/vpr_constraints.xsd index 406e2abcda4..704d084f381 100644 --- a/vpr/src/base/vpr_constraints.xsd +++ b/vpr/src/base/vpr_constraints.xsd @@ -59,14 +59,42 @@ + + + + + + + + + + + + + + + + + + + + + + - + + diff --git a/vpr/src/base/vpr_constraints_reader.cpp b/vpr/src/base/vpr_constraints_reader.cpp index c1d3f33389b..9bb8dccf9bd 100644 --- a/vpr/src/base/vpr_constraints_reader.cpp +++ b/vpr/src/base/vpr_constraints_reader.cpp @@ -12,7 +12,7 @@ #include "vpr_constraints_reader.h" void load_vpr_constraints_file(const char* read_vpr_constraints_name) { - vtr::ScopedStartFinishTimer timer("Loading VPR constraints file"); + vtr::ScopedStartFinishTimer timer("Reading VPR constraints from " + std::string(read_vpr_constraints_name)); VprConstraintsSerializer reader; @@ -33,8 +33,11 @@ void load_vpr_constraints_file(const char* read_vpr_constraints_name) { //Update the floorplanning constraints in the floorplanning constraints context auto& floorplanning_ctx = g_vpr_ctx.mutable_floorplanning(); - floorplanning_ctx.constraints = reader.constraints_; + floorplanning_ctx.constraints = reader.constraints_.place_constraints(); + auto& routing_ctx = g_vpr_ctx.mutable_routing(); + routing_ctx.constraints = reader.constraints_.route_constraints(); + const auto& ctx_constraints = floorplanning_ctx.constraints; if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_VPR_CONSTRAINTS)) { diff --git a/vpr/src/base/vpr_constraints_reader.h b/vpr/src/base/vpr_constraints_reader.h index 95fcc988607..9740825836d 100644 --- a/vpr/src/base/vpr_constraints_reader.h +++ b/vpr/src/base/vpr_constraints_reader.h @@ -1,5 +1,5 @@ /* Defines the function used to load a vpr constraints file written in XML format into vpr - * The functions loads up the VprConstraints, Partition, Region, and PartitionRegion data structures + * The functions loads up the data structures related to placement and routing constraints * according to the data provided in the XML file*/ #ifndef VPR_CONSTRAINTS_READER_H_ diff --git a/vpr/src/base/vpr_constraints_serializer.h b/vpr/src/base/vpr_constraints_serializer.h index 902d3977a80..9ab4c3bd96f 100644 --- a/vpr/src/base/vpr_constraints_serializer.h +++ b/vpr/src/base/vpr_constraints_serializer.h @@ -8,13 +8,15 @@ #include "echo_files.h" #include "constraints_load.h" #include "vtr_log.h" +#include "vtr_error.h" #include "globals.h" //for the g_vpr_ctx +#include "clock_modeling.h" #include "vpr_constraints_uxsdcxx_interface.h" /** * @file - * @brief The reading of vpr floorplanning constraints is now done via uxsdcxx and the 'vpr_constraints.xsd' file. + * @brief The reading of vpr constraints is now done via uxsdcxx and the 'vpr_constraints.xsd' file. * The interface between the generated code and VPR is provided by VprConstraintsBase, which is in the * file 'vpr/src/base/gen/vpr_constraints_uxsdcxx_interface.h'. * This file implements the virtual functions from VprConstraintsBase. @@ -69,11 +71,15 @@ struct VprConstraintsContextTypes : public uxsd::DefaultVprConstraintsContextTyp using AddRegionReadContext = Region; using PartitionReadContext = partition_info; using PartitionListReadContext = void*; + using SetGlobalSignalReadContext = std::pair; + using GlobalRouteConstraintsReadContext = void*; using VprConstraintsReadContext = void*; using AddAtomWriteContext = void*; using AddRegionWriteContext = void*; using PartitionWriteContext = void*; using PartitionListWriteContext = void*; + using SetGlobalSignalWriteContext = void*; + using GlobalRouteConstraintsWriteContext = void*; using VprConstraintsWriteContext = void*; }; @@ -104,6 +110,18 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase * @@ -223,7 +241,7 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase atoms = constraints_.get_part_atoms(partid); + Partition part = constraints_.place_constraints().get_partition(partid); + std::vector atoms = constraints_.place_constraints().get_part_atoms(partid); partition_info part_info; part_info.part = part; @@ -305,10 +323,116 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase + * + * + * + * + */ + + e_clock_modeling from_uxsd_route_model(uxsd::enum_route_model_type route_model) { + switch (route_model) { + case uxsd::enum_route_model_type::DEDICATED_NETWORK: + return e_clock_modeling::DEDICATED_NETWORK; + case uxsd::enum_route_model_type::ROUTE: + return e_clock_modeling::ROUTED_CLOCK; + case uxsd::enum_route_model_type::IDEAL: + return e_clock_modeling::IDEAL_CLOCK; + default: + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Invalid route model %d", route_model); + } + } + + uxsd::enum_route_model_type to_uxsd_route_model(e_clock_modeling route_model) { + switch (route_model) { + case e_clock_modeling::DEDICATED_NETWORK: + return uxsd::enum_route_model_type::DEDICATED_NETWORK; + case e_clock_modeling::ROUTED_CLOCK: + return uxsd::enum_route_model_type::ROUTE; + case e_clock_modeling::IDEAL_CLOCK: + return uxsd::enum_route_model_type::IDEAL; + default: + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Invalid route model %d", route_model); + } + } + + virtual inline const char* get_set_global_signal_name(std::pair& rc) final { + temp_name_string_ = rc.first; + return temp_name_string_.c_str(); + } + virtual inline void set_set_global_signal_name(const char* name, void*& /*ctx*/) final { + std::string net_name = std::string(name); + loaded_route_constraint.first = net_name; + return; + } + virtual inline uxsd::enum_route_model_type get_set_global_signal_route_model(std::pair& rc) final { + return to_uxsd_route_model(rc.second.route_model()); + } + virtual inline void set_set_global_signal_route_model(uxsd::enum_route_model_type route_model, void*& /*ctx*/) final { + loaded_route_constraint.second.set_route_model(from_uxsd_route_model(route_model)); + } + virtual inline const char* get_set_global_signal_network_name(std::pair& rc) final { + temp_name_string_ = rc.second.network_name(); + return temp_name_string_.c_str(); + } + virtual inline void set_set_global_signal_network_name(const char* network_name, void*& /*ctx*/) final { + loaded_route_constraint.second.set_network_name(std::string(network_name)); + } + + /** Generated for complex type "global_route_constraints": + * + * + * + * + * + */ + virtual inline void preallocate_global_route_constraints_set_global_signal(void*& /*ctx*/, size_t /*size*/) final {} + virtual inline void* add_global_route_constraints_set_global_signal(void*& ctx, uxsd::enum_route_model_type route_model) final { + reset_loaded_route_constrints(); + set_set_global_signal_route_model(route_model, ctx); + return nullptr; + } + virtual inline void finish_global_route_constraints_set_global_signal(void*& /*ctx*/) final { + if(loaded_route_constraint.second.route_model() == e_clock_modeling::DEDICATED_NETWORK + && loaded_route_constraint.second.network_name() == "INVALID"){ + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Invalid routing constraint for net \"%s\". The network name has to be specified when routing model is set to \"dedicated_network\".\n", loaded_route_constraint.first.c_str()); + } + constraints_.mutable_route_constraints().add_route_constraint(loaded_route_constraint.first, loaded_route_constraint.second); + } + virtual inline size_t num_global_route_constraints_set_global_signal(void*& /*ctx*/) final { + return constraints_.route_constraints().get_num_route_constraints(); + } + virtual inline std::pair get_global_route_constraints_set_global_signal(int n, void*& /*ctx*/) final { + return constraints_.route_constraints().get_route_constraint_by_idx((std::size_t)n); + } + + virtual inline void* init_vpr_constraints_global_route_constraints(void*& /*ctx*/) final { + return nullptr; + } + + virtual inline void finish_vpr_constraints_global_route_constraints(void*& /*ctx*/) final {} + + virtual inline void* get_vpr_constraints_global_route_constraints(void*& /*ctx*/) final { + return nullptr; + } + + virtual inline bool has_vpr_constraints_global_route_constraints(void*& /*ctx*/){ + if(constraints_.route_constraints().get_num_route_constraints() > 0) + return true; + else + return false; + } + + /** Generated for complex type "vpr_constraints": * - * + * * + * * * * @@ -335,12 +459,19 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase 0) + return true; + else + return false; + } virtual void finish_load() final { } //temp data for writes std::string temp_atom_string_; std::string temp_part_string_; + std::string temp_name_string_; /* * Temp data for loads and writes. @@ -355,6 +486,7 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase loaded_route_constraint; //temp string used when a method must return a const char* std::string temp_ = "vpr"; diff --git a/vpr/src/base/vpr_constraints_writer.cpp b/vpr/src/base/vpr_constraints_writer.cpp index 073b02dc1f3..b1e50917ae1 100644 --- a/vpr/src/base/vpr_constraints_writer.cpp +++ b/vpr/src/base/vpr_constraints_writer.cpp @@ -78,12 +78,12 @@ void setup_vpr_floorplan_constraints_one_loc(VprConstraints& constraints, int ex pr.add_to_part_region(reg); part.set_part_region(pr); - constraints.add_partition(part); + constraints.mutable_place_constraints().add_partition(part); std::unordered_set* atoms = cluster_to_atoms(blk_id); for (auto atom_id : *atoms) { - constraints.add_constrained_atom(atom_id, partid); + constraints.mutable_place_constraints().add_constrained_atom(atom_id, partid); } part_id++; } @@ -202,10 +202,10 @@ void setup_vpr_floorplan_constraints_cutpoints(VprConstraints& constraints, int const auto reg_coord = region.first.get_region_rect(); create_partition(part, part_name, {reg_coord.xmin, reg_coord.ymin, reg_coord.xmax, reg_coord.ymax, reg_coord.layer_num}); - constraints.add_partition(part); + constraints.mutable_place_constraints().add_partition(part); for (auto blk_id : region.second) { - constraints.add_constrained_atom(blk_id, partid); + constraints.mutable_place_constraints().add_constrained_atom(blk_id, partid); } num_partitions++; diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index b4a145ab13f..201157609fd 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -235,14 +235,6 @@ struct DeviceContext : public Context { std::vector> clock_networks; std::vector> clock_connections; - /** - * @brief rr_node idx that connects to the input of all clock network wires - * - * Useful for two stage clock routing - * XXX: currently only one place to source the clock networks so only storing - * a single value - */ - int virtual_clock_network_root_idx; /** * @brief switch_fanin_remap is only used for printing out switch fanin stats * (the -switch_stats option) @@ -493,6 +485,11 @@ struct RoutingContext : public Context { vtr::Cache>, RouterLookahead> cached_router_lookahead_; + + /** + * @brief User specified routing constraints + */ + UserRouteConstraints constraints; }; /** @@ -510,7 +507,7 @@ struct FloorplanningContext : public Context { * * The constraints are input into vpr and do not change. */ - VprConstraints constraints; + UserPlaceConstraints constraints; /** * @brief Constraints for each cluster diff --git a/vpr/src/draw/draw_floorplanning.cpp b/vpr/src/draw/draw_floorplanning.cpp index 8cb32442774..d3e0ca520e7 100644 --- a/vpr/src/draw/draw_floorplanning.cpp +++ b/vpr/src/draw/draw_floorplanning.cpp @@ -6,7 +6,7 @@ #include "globals.h" #include "atom_netlist.h" #include "draw_floorplanning.h" -#include "vpr_constraints.h" +#include "user_place_constraints.h" #include "draw_color.h" #include "draw.h" #include "draw_rr.h" diff --git a/vpr/src/pack/output_clustering.cpp b/vpr/src/pack/output_clustering.cpp index 084898322b9..cee87ad51a1 100644 --- a/vpr/src/pack/output_clustering.cpp +++ b/vpr/src/pack/output_clustering.cpp @@ -661,7 +661,7 @@ void write_packing_results_to_xml(const bool& global_clocks, const std::string& architecture_id, const char* out_fname) { vtr::vector*> intra_lb_routing_placeholder; - std::unordered_set is_clock = alloc_and_load_is_clock(global_clocks); + std::unordered_set is_clock = alloc_and_load_is_clock(); output_clustering(intra_lb_routing_placeholder, global_clocks, diff --git a/vpr/src/pack/pack.cpp b/vpr/src/pack/pack.cpp index 041d48eb879..c151a1eea02 100644 --- a/vpr/src/pack/pack.cpp +++ b/vpr/src/pack/pack.cpp @@ -56,7 +56,7 @@ bool try_pack(t_packer_opts* packer_opts, helper_ctx.num_models = count_models(user_models); helper_ctx.num_models += count_models(library_models); - is_clock = alloc_and_load_is_clock(packer_opts->global_clocks); + is_clock = alloc_and_load_is_clock(); is_global.insert(is_clock.begin(), is_clock.end()); size_t num_p_inputs = 0; @@ -299,10 +299,9 @@ float get_arch_switch_info(short switch_index, int switch_fanin, float& Tdel_swi return Tdel_switch + R_switch * Cout_switch; } -std::unordered_set alloc_and_load_is_clock(bool global_clocks) { +std::unordered_set alloc_and_load_is_clock() { /* Looks through all the atom blocks to find and mark all the clocks, by setting * the corresponding entry by adding the clock to is_clock. - * global_clocks is used * only for an error check. */ int num_clocks = 0; @@ -321,15 +320,6 @@ std::unordered_set alloc_and_load_is_clock(bool global_clocks) { } } - /* If we have multiple clocks and we're supposed to declare them global, * - * print a warning message, since it looks like this circuit may have * - * locally generated clocks. */ - - if (num_clocks > 1 && global_clocks) { - VTR_LOG_WARN( - "All %d clocks will be treated as global.\n", num_clocks); - } - return (is_clock); } diff --git a/vpr/src/pack/pack.h b/vpr/src/pack/pack.h index df99104512b..9f811b78f52 100644 --- a/vpr/src/pack/pack.h +++ b/vpr/src/pack/pack.h @@ -15,6 +15,6 @@ bool try_pack(t_packer_opts* packer_opts, float get_arch_switch_info(short switch_index, int switch_fanin, float& Tdel_switch, float& R_switch, float& Cout_switch); -std::unordered_set alloc_and_load_is_clock(bool global_clocks); +std::unordered_set alloc_and_load_is_clock(); #endif diff --git a/vpr/src/route/clock_connection_builders.cpp b/vpr/src/route/clock_connection_builders.cpp index e24bdbe8ea0..d7c41cae408 100644 --- a/vpr/src/route/clock_connection_builders.cpp +++ b/vpr/src/route/clock_connection_builders.cpp @@ -53,14 +53,12 @@ void RoutingToClockConnection::create_switches(const ClockRRGraphBuilder& clock_ std::mt19937 rand_generator; rand_generator.seed(seed); - auto& device_ctx = g_vpr_ctx.device(); + auto& device_ctx = g_vpr_ctx.mutable_device(); + auto& rr_graph_builder = device_ctx.rr_graph_builder; const auto& node_lookup = device_ctx.rr_graph.node_lookup(); RRNodeId virtual_clock_network_root_idx = create_virtual_clock_network_sink_node(switch_location.layer, switch_location.x, switch_location.y); - { - auto& mut_device_ctx = g_vpr_ctx.mutable_device(); - mut_device_ctx.virtual_clock_network_root_idx = size_t(virtual_clock_network_root_idx); - } + rr_graph_builder.set_virtual_clock_network_root_idx(virtual_clock_network_root_idx); // rr_node indices for x and y channel routing wires and clock wires to connect to auto x_wire_indices = node_lookup.find_channel_nodes(switch_location.layer, switch_location.x, switch_location.y, CHANX); @@ -97,6 +95,7 @@ RRNodeId RoutingToClockConnection::create_virtual_clock_network_sink_node(int la auto& rr_graph_builder = device_ctx.rr_graph_builder; auto& node_lookup = device_ctx.rr_graph_builder.node_lookup(); auto& rr_rc_data = device_ctx.rr_rc_data; + auto& arch = device_ctx.arch; rr_graph_builder.emplace_back(); RRNodeId node_index = RRNodeId(rr_graph.num_nodes() - 1); @@ -110,6 +109,7 @@ RRNodeId RoutingToClockConnection::create_virtual_clock_network_sink_node(int la int ptc = max_ptc + 1; rr_graph_builder.set_node_type(node_index, SINK); + rr_graph_builder.set_node_name(node_index, arch->default_clock_network_name); rr_graph_builder.set_node_class_num(node_index, ptc); rr_graph_builder.set_node_coordinates(node_index, x, y, x, y); rr_graph_builder.set_node_layer(node_index, layer); diff --git a/vpr/src/route/clock_network_builders.cpp b/vpr/src/route/clock_network_builders.cpp index d27c2c5e362..40e581a02de 100644 --- a/vpr/src/route/clock_network_builders.cpp +++ b/vpr/src/route/clock_network_builders.cpp @@ -35,6 +35,7 @@ void populate_segment_values(int seg_index, segment_inf[seg_index].arch_opin_switch = -1; segment_inf[seg_index].frac_cb = -1; segment_inf[seg_index].frac_sb = -1; + segment_inf[seg_index].res_type = SegResType::GCLK; } /* diff --git a/vpr/src/route/route_net.tpp b/vpr/src/route/route_net.tpp index 593c6940d3a..45cff71dd37 100644 --- a/vpr/src/route/route_net.tpp +++ b/vpr/src/route/route_net.tpp @@ -145,27 +145,56 @@ inline NetResultFlags route_net(ConnectionRouter& router, // Pre-route to clock source for clock nets (marked as global nets) if (net_list.net_is_global(net_id) && router_opts.two_stage_clock_routing) { - //VTR_ASSERT(router_opts.clock_modeling == DEDICATED_NETWORK); - RRNodeId sink_node(device_ctx.virtual_clock_network_root_idx); - - enable_router_debug(router_opts, net_id, sink_node, itry, &router); - - VTR_LOGV_DEBUG(f_router_debug, "Pre-routing global net %zu\n", size_t(net_id)); - - // Set to the max timing criticality which should intern minimize clock insertion - // delay by selecting a direct route from the clock source to the virtual sink - cost_params.criticality = router_opts.max_criticality; - - return pre_route_to_clock_root(router, - net_id, - net_list, - sink_node, - cost_params, - router_opts.high_fanout_threshold, - tree, - spatial_route_tree_lookup, - router_stats, - is_flat); + auto& route_constraints = route_ctx.constraints; + std::string net_name = net_list.net_name(net_id); + + // If there is no routing constraint for the current global net + // and the clock modelling is set to dedicated network or + //there is a routing constraint for the current net setting routing model + // to the dedicated network run the first stage router. + if((!route_constraints.has_routing_constraint(net_name) && router_opts.clock_modeling == e_clock_modeling::DEDICATED_NETWORK) + || route_constraints.get_route_model_by_net_name(net_name) == e_clock_modeling::DEDICATED_NETWORK){ + + std::string clock_network_name = ""; + + // If a user-specified routing constratins exists for the curret net get the clock network name + // from the constraints file, otherwise use the default clock network name + if(route_constraints.has_routing_constraint(net_name)){ + clock_network_name = route_constraints.get_routing_network_name_by_net_name(net_name); + } + else { + auto& arch = device_ctx.arch; + clock_network_name = arch->default_clock_network_name; + } + + RRNodeId sink_node = rr_graph.virtual_clock_network_root_idx(clock_network_name.c_str()); + + enable_router_debug(router_opts, net_id, sink_node, itry, &router); + + VTR_LOGV_DEBUG(f_router_debug, "Pre-routing global net %zu\n", size_t(net_id)); + + // Set to the max timing criticality which should intern minimize clock insertion + // delay by selecting a direct route from the clock source to the virtual sink + cost_params.criticality = router_opts.max_criticality; + + if (sink_node == RRNodeId::INVALID()){ + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Cannot route net \"%s\" through given clock network. Unknown clock network name \"%s\"", net_name.c_str(), clock_network_name.c_str()); + } + + flags = pre_route_to_clock_root(router, + net_id, + net_list, + sink_node, + cost_params, + router_opts.high_fanout_threshold, + tree, + spatial_route_tree_lookup, + router_stats, + is_flat); + + if (flags.success == false) + return flags; + } } if (budgeting_inf.if_set()) { @@ -273,6 +302,7 @@ inline NetResultFlags pre_route_to_clock_root(ConnectionRouter& router, auto& m_route_ctx = g_vpr_ctx.mutable_routing(); NetResultFlags out; + out.was_rerouted = true; bool high_fanout = is_high_fanout(net_list.net_sinks(net_id).size(), high_fanout_threshold); diff --git a/vpr/src/route/route_tree.cpp b/vpr/src/route/route_tree.cpp index a12cab81d3c..daf21bd1eb8 100644 --- a/vpr/src/route/route_tree.cpp +++ b/vpr/src/route/route_tree.cpp @@ -479,8 +479,11 @@ void RouteTree::print(void) const { /** Add the most recently finished wire segment to the routing tree, and * update the Tdel, etc. numbers for the rest of the routing tree. hptr * is the heap pointer of the SINK that was reached, and target_net_pin_index - * is the net pin index corresponding to the SINK that was reached. This routine - * returns a tuple: RouteTreeNode of the branch it adds to the route tree and + * is the net pin index corresponding to the SINK that was reached. Usually target_net_pin_index + * is a non-negative integer indicating the netlist connection being routed, but it can be OPEN (-1) + * to indicate this is a routing path to a virtual sink which we use when routing to the source of + * dedicated clock networks. + * This routine returns a tuple: RouteTreeNode of the branch it adds to the route tree and * RouteTreeNode of the SINK it adds to the routing. */ std::tuple, vtr::optional> RouteTree::update_from_heap(t_heap* hptr, int target_net_pin_index, SpatialRouteTreeLookup* spatial_rt_lookup, bool is_flat) { @@ -501,7 +504,7 @@ RouteTree::update_from_heap(t_heap* hptr, int target_net_pin_index, SpatialRoute update_route_tree_spatial_lookup_recur(*start_of_new_subtree_rt_node, *spatial_rt_lookup); } - if (_net_id.is_valid()) /* We don't have this lookup if the tree isn't associated with a net */ + if (_net_id.is_valid() && target_net_pin_index != OPEN) /* We don't have this lookup if the tree isn't associated with a net */ _is_isink_reached.set(target_net_pin_index, true); return {*start_of_new_subtree_rt_node, *sink_rt_node}; diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 1ba31ca9dd1..af3dbc472a3 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -699,7 +699,6 @@ void create_rr_graph(const t_graph_type graph_type, device_ctx.arch, &mutable_device_ctx.chan_width, router_opts.base_cost_type, - device_ctx.virtual_clock_network_root_idx, &det_routing_arch->wire_to_rr_ipin_switch, &det_routing_arch->wire_to_arch_ipin_switch_between_dice, det_routing_arch->read_rr_graph_filename.c_str(), @@ -786,7 +785,6 @@ void create_rr_graph(const t_graph_type graph_type, device_ctx.arch, &mutable_device_ctx.chan_width, det_routing_arch->write_rr_graph_filename.c_str(), - device_ctx.virtual_clock_network_root_idx, echo_enabled, echo_file_name, is_flat); @@ -1344,9 +1342,10 @@ static void build_rr_graph(const t_graph_type graph_type, is_flat); // Verify no incremental node allocation. - /* AA: Note that in the case of dedicated networks, we are currently underestimating the additional node count due to the clock networks. - * Thus, this below error is logged; it's not actually an error, the node estimation needs to get fixed for dedicated clock networks. */ - if (rr_graph.num_nodes() > expected_node_count) { + // AA: Note that in the case of dedicated networks, we are currently underestimating the additional node count due to the clock networks. + /* For now, the node count comparison is being skipped in the presence of clock networks. + * TODO: The node estimation needs to be fixed for dedicated clock networks. */ + if (rr_graph.num_nodes() > expected_node_count && clock_modeling != DEDICATED_NETWORK) { VTR_LOG_ERROR("Expected no more than %zu nodes, have %zu nodes\n", expected_node_count, rr_graph.num_nodes()); } @@ -1415,7 +1414,6 @@ static void build_rr_graph(const t_graph_type graph_type, grid, device_ctx.chan_width, graph_type, - device_ctx.virtual_clock_network_root_idx, is_flat); /* Free all temp structs */ @@ -1486,8 +1484,6 @@ static void build_intra_cluster_rr_graph(const t_graph_type graph_type, is_flat, load_rr_graph); - /* AA: Note that in the case of dedicated networks, we are currently underestimating the additional node count due to the clock networks. - * Thus this below error is logged; it's not actually an error, the node estimation needs to get fixed for dedicated clock networks. */ if (rr_graph.num_nodes() > expected_node_count) { VTR_LOG_ERROR("Expected no more than %zu nodes, have %zu nodes\n", expected_node_count, rr_graph.num_nodes()); @@ -1510,7 +1506,6 @@ static void build_intra_cluster_rr_graph(const t_graph_type graph_type, grid, device_ctx.chan_width, graph_type, - device_ctx.virtual_clock_network_root_idx, is_flat); } diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 7db14d2ae84..aaa1a6016b9 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -16,6 +16,7 @@ #include "vpr_utils.h" #include "cluster_placement.h" #include "device_grid.h" +#include "user_route_constraints.h" #include "re_cluster_util.h" /* This module contains subroutines that are used in several unrelated parts * @@ -2508,6 +2509,32 @@ void add_pb_child_to_list(std::list& pb_list, const t_pb* parent_pb } } +void apply_route_constraints(const UserRouteConstraints& route_constraints) { + ClusteringContext& mutable_cluster_ctx = g_vpr_ctx.mutable_clustering(); + + // Iterate through all the nets + for (auto net_id : mutable_cluster_ctx.clb_nlist.nets()) { + // Get the name of the current net + std::string net_name = mutable_cluster_ctx.clb_nlist.net_name(net_id); + + // Check if a routing constraint is specified for the current net + if (route_constraints.has_routing_constraint(net_name)) { + // Mark the net as 'global' if there is a routing constraint for this net + // as the routing constraints are used to set the net as global + // and specify the routing model for it + mutable_cluster_ctx.clb_nlist.set_net_is_global(net_id, true); + + // Mark the net as 'ignored' if the route model is 'ideal' + if (route_constraints.get_route_model_by_net_name(net_name) == e_clock_modeling::IDEAL_CLOCK) { + mutable_cluster_ctx.clb_nlist.set_net_is_ignored(net_id, true); + } else { + // Set the 'ignored' flag to false otherwise + mutable_cluster_ctx.clb_nlist.set_net_is_ignored(net_id, false); + } + } + } +} + float get_min_cross_layer_delay() { const auto& rr_graph = g_vpr_ctx.device().rr_graph; float min_delay = std::numeric_limits::max(); diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index 17cf04e3fb2..edd148d6974 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -13,6 +13,7 @@ #include "arch_util.h" #include "physical_types_util.h" #include "rr_graph_utils.h" +#include "vpr_constraints.h" class DeviceGrid; @@ -310,6 +311,16 @@ t_arch_switch_inf create_internal_arch_sw(float delay); void add_pb_child_to_list(std::list& pb_list, const t_pb* parent_pb); +/** + * @brief Apply user-defined route constraints to set the 'net_is_ignored_' and 'net_is_global_' flags. + * + * The 'net_is_global_' flag is used to identify global nets, which can be either clock signals or specified as global by user constraints. + * The 'net_is_ignored_' flag ensures that the router will ignore routing for the net. + * + * @param route_constraints User-defined route constraints to guide the application of constraints. + */ +void apply_route_constraints(const UserRouteConstraints& constraint); + /** * @brief Iterate over all inter-layer switch types and return the minimum delay of it. * useful four router lookahead to to have some estimate of the cost of crossing a layer diff --git a/vpr/test/test_vpr.cpp b/vpr/test/test_vpr.cpp index b715679f530..4945c56c001 100644 --- a/vpr/test/test_vpr.cpp +++ b/vpr/test/test_vpr.cpp @@ -165,7 +165,6 @@ TEST_CASE("read_rr_graph_metadata", "[vpr]") { device_ctx.arch, &mutable_device_ctx.chan_width, kRrGraphFile, - device_ctx.virtual_clock_network_root_idx, echo_enabled, echo_file_name, false); diff --git a/vpr/test/test_vpr_constraints.cpp b/vpr/test/test_vpr_constraints.cpp index f0fb486d76a..fbe219f672f 100644 --- a/vpr/test/test_vpr_constraints.cpp +++ b/vpr/test/test_vpr_constraints.cpp @@ -4,14 +4,14 @@ #include "vpr_api.h" #include "globals.h" -#include "vpr_constraints.h" +#include "user_place_constraints.h" #include "partition.h" #include "region.h" #include "place_constraints.h" /** * This file contains unit tests that check the functionality of all classes related to vpr constraints. These classes include - * VprConstraints, Region, PartitionRegions, and Partition. + * UserPlaceConstraints, Region, PartitionRegions, and Partition. */ //Test Region class accessors and mutators @@ -93,8 +93,8 @@ TEST_CASE("Partition", "[vpr]") { REQUIRE(pr_reg_coord.ymax == 8); } -//Test VprConstraints class accessors and mutators -TEST_CASE("VprConstraints", "[vpr]") { +//Test UserPlaceConstraints class accessors and mutators +TEST_CASE("UserPlaceConstraints", "[vpr]") { PartitionId part_id(0); PartitionId part_id_2(1); AtomBlockId atom_id(6); @@ -102,7 +102,7 @@ TEST_CASE("VprConstraints", "[vpr]") { AtomBlockId atom_id_3(8); AtomBlockId atom_id_4(9); - VprConstraints vprcon; + UserPlaceConstraints vprcon; vprcon.add_constrained_atom(atom_id, part_id); vprcon.add_constrained_atom(atom_id_2, part_id); diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/config.txt new file mode 100644 index 00000000000..e9b34d127a2 --- /dev/null +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/config.txt @@ -0,0 +1,36 @@ +############################################## +# Configuration file for running experiments +############################################## + +# Path to directory of circuits to use +circuits_dir=benchmarks/ + +# Path to directory of architectures to use +archs_dir=arch/ + +# Add circuits to list to sweep +circuit_list_add=verilog/multiclock_output_and_latch.v +circuit_list_add=verilog/and_latch.v + +# Add architectures to list to sweep +arch_list_add=timing/k6_frac_N10_frac_chain_mem32K_htree0_40nm.xml +arch_list_add=timing/k6_frac_N10_frac_chain_mem32K_htree0_routedCLK_40nm.xml +arch_list_add=timing/k6_frac_N10_frac_chain_mem32K_htree0short_40nm.xml + +# Parse info and how to parse +parse_file=vpr_clock_modeling.txt + +# How to parse QoR info +qor_parse_file=qor_standard.txt + +# Pass requirements +# A pass requirement to check that the number of routed nets +# are equal can change if the circuit is synthesized +# differently. At that point a new golden results file must +# be created and checked to see that using the route option +# increases the number of routed nets. +pass_requirements_file=pass_requirements_clock_modeling.txt + +# Script parameters +# Since the used benchmarks in this test are small, a small target_utilization has been set to that the created grid is large enough for the clock network to get built properly +script_params_list_add= --target_utilization 0.01 --two_stage_clock_routing -read_vpr_constraints tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml --clock_modeling dedicated_network diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/golden_results.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/golden_results.txt new file mode 100644 index 00000000000..d3982a6196f --- /dev/null +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/config/golden_results.txt @@ -0,0 +1,7 @@ +arch circuit script_params vtr_flow_elapsed_time vtr_max_mem_stage vtr_max_mem error odin_synth_time max_odin_mem parmys_synth_time max_parmys_mem abc_depth abc_synth_time abc_cec_time abc_sec_time max_abc_mem ace_time max_ace_mem num_clb num_io num_memories num_mult vpr_status vpr_revision vpr_build_info vpr_compiler vpr_compiled hostname rundir max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_mem pack_time placed_wirelength_est total_swap accepted_swap rejected_swap aborted_swap place_mem place_time place_quench_time placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est placed_geomean_nonvirtual_intradomain_critical_path_delay_est place_delay_matrix_lookup_time place_quench_timing_analysis_time place_quench_sta_time place_total_timing_analysis_time place_total_sta_time min_chan_width routed_wirelength min_chan_width_route_success_iteration logic_block_area_total logic_block_area_used min_chan_width_routing_area_total min_chan_width_routing_area_per_tile min_chan_width_route_time min_chan_width_total_timing_analysis_time min_chan_width_total_sta_time crit_path_num_rr_graph_nodes crit_path_num_rr_graph_edges crit_path_collapsed_nodes crit_path_routed_wirelength crit_path_route_success_iteration crit_path_total_nets_routed crit_path_total_connections_routed crit_path_total_heap_pushes crit_path_total_heap_pops critical_path_delay geomean_nonvirtual_intradomain_critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS crit_path_routing_area_total crit_path_routing_area_per_tile router_lookahead_computation_time crit_path_route_time crit_path_create_rr_graph_time crit_path_create_intra_cluster_rr_graph_time crit_path_tile_lookahead_computation_time crit_path_router_lookahead_computation_time crit_path_total_timing_analysis_time crit_path_total_sta_time num_global_nets num_routed_nets +timing/k6_frac_N10_frac_chain_mem32K_htree0_40nm.xml verilog/multiclock_output_and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 4.80 vpr 62.41 MiB -1 -1 0.15 16964 1 0.23 -1 -1 31908 -1 -1 2 6 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63912 6 1 16 17 2 10 9 17 17 289 -1 auto 23.9 MiB 0.02 67 27 9 18 0 62.4 MiB 0.00 0.00 1.66771 -4.34981 -1.66771 0.805 0.93 6.292e-05 5.3006e-05 0.00038211 0.000333692 20 141 4 1.34605e+07 107788 411619. 1424.29 0.56 0.00244758 0.00222679 24098 82050 -1 132 2 10 10 10345 2735 2.73969 0.805 -5.54288 -2.73969 -0.842296 -0.421627 535376. 1852.51 0.16 0.28 0.12 -1 -1 0.16 0.00169603 0.00160376 1 9 +timing/k6_frac_N10_frac_chain_mem32K_htree0_40nm.xml verilog/and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 3.27 vpr 62.22 MiB -1 -1 0.17 16808 1 0.23 -1 -1 29760 -1 -1 1 3 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63712 3 1 5 6 1 4 5 13 13 169 -1 auto 23.5 MiB 0.01 26 12 4 8 0 62.2 MiB 0.00 0.00 0.684768 -1.31529 -0.684768 0.684768 0.50 2.4726e-05 1.8709e-05 0.000144623 0.000117099 20 52 1 6.63067e+06 53894 227243. 1344.63 0.31 0.0012983 0.00120858 13251 44387 -1 54 1 4 4 4093 1283 1.57879 1.57879 -1.64658 -1.57879 -0.385237 -0.385237 294987. 1745.49 0.08 0.16 0.07 -1 -1 0.08 0.00115216 0.00111231 0 4 +timing/k6_frac_N10_frac_chain_mem32K_htree0_routedCLK_40nm.xml verilog/multiclock_output_and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 4.85 vpr 62.34 MiB -1 -1 0.17 17132 1 0.23 -1 -1 32004 -1 -1 2 6 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63832 6 1 16 17 2 10 9 17 17 289 -1 auto 23.8 MiB 0.02 86 27 10 16 1 62.3 MiB 0.00 0.00 1.73508 -4.45965 -1.73508 0.805 0.94 6.3063e-05 5.3154e-05 0.000382365 0.000334342 20 156 3 1.34605e+07 107788 424167. 1467.71 0.57 0.00232866 0.0021239 24098 84646 -1 143 1 9 9 10051 2608 2.60696 0.805 -5.45498 -2.60696 -0.46436 -0.232734 547923. 1895.93 0.16 0.29 0.12 -1 -1 0.16 0.00170576 0.00163038 1 9 +timing/k6_frac_N10_frac_chain_mem32K_htree0_routedCLK_40nm.xml verilog/and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 3.23 vpr 62.38 MiB -1 -1 0.17 17164 1 0.23 -1 -1 29612 -1 -1 1 3 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63872 3 1 5 6 1 4 5 13 13 169 -1 auto 23.9 MiB 0.01 26 12 4 8 0 62.4 MiB 0.00 0.00 0.698051 -1.3327 -0.698051 0.698051 0.51 2.4972e-05 1.869e-05 0.000139687 0.000111725 20 52 1 6.63067e+06 53894 235789. 1395.20 0.32 0.00137232 0.0012738 13251 46155 -1 54 1 4 4 4037 1263 1.58964 1.58964 -1.65632 -1.58964 -0.386343 -0.386343 303533. 1796.05 0.08 0.12 0.04 -1 -1 0.08 0.00117266 0.00113601 0 4 +timing/k6_frac_N10_frac_chain_mem32K_htree0short_40nm.xml verilog/multiclock_output_and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 4.90 vpr 62.34 MiB -1 -1 0.16 17264 1 0.23 -1 -1 31964 -1 -1 2 6 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63832 6 1 16 17 2 10 9 17 17 289 -1 auto 23.8 MiB 0.02 67 27 9 18 0 62.3 MiB 0.01 0.00 1.66771 -4.34981 -1.66771 0.805 0.97 6.398e-05 5.3905e-05 0.000660909 0.000612393 20 619 3 1.34605e+07 107788 408865. 1414.76 0.59 0.00267306 0.00246585 24098 82150 -1 610 2 10 10 12597 4156 3.681 0.805 -7.42729 -3.681 -2.7249 -1.36293 532630. 1843.01 0.16 0.29 0.12 -1 -1 0.16 0.00169111 0.00160117 1 9 +timing/k6_frac_N10_frac_chain_mem32K_htree0short_40nm.xml verilog/and_latch.v common_--target_utilization_0.01_--two_stage_clock_routing_-read_vpr_constraints_tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml_--clock_modeling_dedicated_network 3.27 vpr 62.18 MiB -1 -1 0.16 16892 1 0.23 -1 -1 29700 -1 -1 1 3 0 0 success v8.0.0-10229-g9de163162 release VTR_ASSERT_LEVEL=2 GNU 9.4.0 on Linux-4.15.0-197-generic x86_64 2024-06-03T20:58:32 betzgrp-wintermute.eecg.utoronto.ca /home/talaeikh/vtr-verilog-to-routing/vtr_flow/tasks/regression_tests 63672 3 1 5 6 1 4 5 13 13 169 -1 auto 23.6 MiB 0.01 26 12 4 8 0 62.2 MiB 0.00 0.00 0.684768 -1.31529 -0.684768 0.684768 0.50 2.4929e-05 1.8673e-05 0.000144104 0.000115519 20 183 1 6.63067e+06 53894 225153. 1332.26 0.31 0.00152207 0.00139859 13251 44463 -1 185 1 4 4 1139 237 2.19802 2.19802 -2.19802 -2.19802 -1.00447 -1.00447 292904. 1733.16 0.08 0.15 0.07 -1 -1 0.08 0.00115607 0.00111789 0 4 diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml new file mode 100644 index 00000000000..878f0b0120d --- /dev/null +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_routing_constraints/multi_clock_routing_constraints.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt index c159711565f..322e7de030d 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt @@ -84,3 +84,4 @@ regression_tests/vtr_reg_strong/strong_timing_fail regression_tests/vtr_reg_strong/strong_timing_no_fail regression_tests/vtr_reg_strong/strong_noc regression_tests/vtr_reg_strong/strong_flat_router +regression_tests/vtr_reg_strong/strong_routing_constraints \ No newline at end of file