Merge pull request #1734 from lnis-uofu/xt_clkntwk2
Programmable Clock Network v2.0
This commit is contained in:
commit
5531d416cc
|
@ -79,6 +79,7 @@ For subtile port merge support (see an illustrative example in :numref:`fig_subt
|
||||||
|
|
||||||
.. note:: When defined, the given port of all the subtiles of a tile will be merged into one port. For example, a tile consists of 8 subtile ``A`` and 6 subtile ``B`` and all the subtiles have a port ``clk``, in the FPGA fabric, all the ``clk`` of the subtiles ``A`` and ``B`` will be wired to a common port ``clk`` at tile level.
|
.. note:: When defined, the given port of all the subtiles of a tile will be merged into one port. For example, a tile consists of 8 subtile ``A`` and 6 subtile ``B`` and all the subtiles have a port ``clk``, in the FPGA fabric, all the ``clk`` of the subtiles ``A`` and ``B`` will be wired to a common port ``clk`` at tile level.
|
||||||
|
|
||||||
|
.. note:: Note that when a dedicated clock network is defined, the size of the global port will follow the ``global_port`` defined in the clock network description file (See details in :ref:`file_formats_clock_network`)
|
||||||
|
|
||||||
.. note:: When merged, the port will have a default side of ``TOP`` and index of ``0`` on all the attributes, such as width, height etc.
|
.. note:: When merged, the port will have a default side of ``TOP`` and index of ``0`` on all the attributes, such as width, height etc.
|
||||||
|
|
||||||
|
@ -99,6 +100,8 @@ For global port support:
|
||||||
|
|
||||||
- ``clock_arch_tree_name="<string>"`` defines the name of the programmable clock network, which the global port will drive. The name of the programmable clock network must be a valid name (See details in :ref:`file_formats_clock_network`)
|
- ``clock_arch_tree_name="<string>"`` defines the name of the programmable clock network, which the global port will drive. The name of the programmable clock network must be a valid name (See details in :ref:`file_formats_clock_network`)
|
||||||
|
|
||||||
|
.. note:: ``clock_arch_tree_name`` is applicable to clock, reset and set signals.
|
||||||
|
|
||||||
- ``is_reset="<bool>"`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches.
|
- ``is_reset="<bool>"`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches.
|
||||||
|
|
||||||
- ``is_set="<bool>"`` define if the global port is a set port at the top-level FPGA fabric. An operating set port will be driven by proper signals in testbenches.
|
- ``is_set="<bool>"`` define if the global port is a set port at the top-level FPGA fabric. An operating set port will be driven by proper signals in testbenches.
|
||||||
|
|
|
@ -22,17 +22,29 @@ Using the clock network description language, users can define multiple clock ne
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
<clock_networks default_segment="<string>" default_switch="<string>">
|
<clock_networks default_segment="<string>" default_tap_switch="<string>" default_driver_switch="<string>">
|
||||||
<clock_network name="<string>" width="<int>">
|
<clock_network name="<string>" global_port="<int>">
|
||||||
<spine name="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>">
|
<spine name="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>">
|
||||||
<switch_point tap="<string>" x="<int>" y="<int>"/>
|
<switch_point tap="<string>" x="<int>" y="<int>">
|
||||||
|
<internal_driver tile_pin="<string>"/>
|
||||||
|
</switch_point>
|
||||||
</spine>
|
</spine>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="<string>"/>
|
<all from_pin="<string>" to_pin="<string>"/>
|
||||||
|
<region from_pin="<string>" to_pin="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>" repeat_x="<int>" repeat_y="<int>"/>
|
||||||
|
<single from_pin="<string>" to_pin="<string>" x="<int>" y="<int>"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
||||||
|
.. _fig_prog_clock_network_example_2x2:
|
||||||
|
|
||||||
|
.. figure:: figures/prog_clock_network_example_2x2.png
|
||||||
|
:width: 100%
|
||||||
|
:alt: An example of programmable clock network considering a 2x2 FPGA fabric
|
||||||
|
|
||||||
|
An example of programmable clock network considering a 2x2 FPGA fabric
|
||||||
|
|
||||||
General Settings
|
General Settings
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -40,7 +52,7 @@ The following syntax are applicable to the XML definition under the root node ``
|
||||||
|
|
||||||
.. option:: default_segment="<string>"
|
.. option:: default_segment="<string>"
|
||||||
|
|
||||||
Define the default routing segment to be used when building the routing tracks for the clock network. Must be a valid routing segment defined in the VPR architecture file. For example,
|
Define the default routing segment to be used when building the routing tracks for the clock network. The routing segments are used to build the spines of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing segment defined in the VPR architecture file. For example,
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
|
@ -56,23 +68,30 @@ where the segment is defined in the VPR architecture file:
|
||||||
|
|
||||||
.. note:: Currently, clock network requires only length-1 wire segment to be used!
|
.. note:: Currently, clock network requires only length-1 wire segment to be used!
|
||||||
|
|
||||||
.. option:: default_switch="<string>"
|
.. option:: default_tap_switch="<string>"
|
||||||
|
|
||||||
Define the default routing switch to be used when interconnects the routing tracks in the clock network. Must be a valid routing switch defined in the VPR architecture file. For example,
|
Define the default routing switch to be used when interconnects the routing tracks to the input pins of programmable blocks in the clock network. The tap switches are used to build the taps of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. See the example in the ``default_driver_switch``.
|
||||||
|
|
||||||
|
.. option:: default_driver_switch="<string>"
|
||||||
|
|
||||||
|
.. note:: For internal drivers, suggest to use the same driver switch for the output pins of a programmable block as defined in VPR architecture.
|
||||||
|
|
||||||
|
Define the default routing switch to be used when interconnects the routing tracks in the clock network. The driver switches are used to build the switch points of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. For example,
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
default_switch="clk_mux"
|
default_tap_switch="cb_mux" default_driver_switch="sb_clk_mux"
|
||||||
|
|
||||||
where the switch is defined in the VPR architecture file:
|
where the switch is defined in the VPR architecture file:
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
<switchlist>
|
<switchlist>
|
||||||
<switch type="mux" name="clk_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
|
<switch type="mux" name="cb_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
|
||||||
|
<switch type="mux" name="sb_clk_mux" R="55" Cin=".7e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
|
||||||
</switchlist>
|
</switchlist>
|
||||||
|
|
||||||
.. note:: Currently, clock network only supports one type of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology.
|
.. note:: Currently, clock network only supports the default types of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology.
|
||||||
|
|
||||||
Clock Network Settings
|
Clock Network Settings
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -94,13 +113,18 @@ where the clock network is used to drive the global clock pin ``clk0`` in OpenFP
|
||||||
|
|
||||||
<tile_annotations>
|
<tile_annotations>
|
||||||
<global_port name="clk0" is_clock="true" clock_arch_tree_name="clk_tree_0" default_val="0">
|
<global_port name="clk0" is_clock="true" clock_arch_tree_name="clk_tree_0" default_val="0">
|
||||||
<tile name="clb" port="clk[0:1]"
|
<tile name="clb" port="clk[0:0]"/>
|
||||||
</global_port>
|
</global_port>
|
||||||
</tile_annotations>
|
</tile_annotations>
|
||||||
|
|
||||||
.. option:: width="<int>"
|
.. option:: global_port="<string>"
|
||||||
|
|
||||||
The maximum number of clock pins that a clock network can drive.
|
.. note:: When programmable clock network is specified for a global port in OpenFPGA architecure description file, the width of clock tree will be the final size of the global port.
|
||||||
|
|
||||||
|
Define the source port of the clock network. For example, ``clk[0:7]``. Note that the global port name should match
|
||||||
|
|
||||||
|
- the ``from_pin`` when defining the tap points (See details in :ref:`file_formats_clock_network_clock_tap_point`).
|
||||||
|
- the ``name`` of global port definition in OpenFPGA architecture description file
|
||||||
|
|
||||||
.. _file_formats_clock_network_clock_spine:
|
.. _file_formats_clock_network_clock_spine:
|
||||||
|
|
||||||
|
@ -136,7 +160,7 @@ For example,
|
||||||
|
|
||||||
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1"/>
|
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1"/>
|
||||||
|
|
||||||
where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1)
|
where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1), as highlighted in orange in the :numref:`fig_prog_clock_network_example_2x2`
|
||||||
|
|
||||||
.. note:: We only support clock spines in horizental and vertical directions. Diagonal clock spine is not supported!
|
.. note:: We only support clock spines in horizental and vertical directions. Diagonal clock spine is not supported!
|
||||||
|
|
||||||
|
@ -168,30 +192,101 @@ For example,
|
||||||
<switch_point tap="spine1" x="1" y="1"/>
|
<switch_point tap="spine1" x="1" y="1"/>
|
||||||
<spine>
|
<spine>
|
||||||
|
|
||||||
where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1).
|
where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1), as highlighted in blue in the :numref:`fig_prog_clock_network_example_2x2`
|
||||||
|
|
||||||
|
For each switch point, outputs of neighbouring programmable blocks are allowed to drive the spine at next level, through syntax ``internal_driver``.
|
||||||
|
|
||||||
|
.. option:: tile_pin="<string>"
|
||||||
|
|
||||||
|
Define the pin of a programmable block as an internal driver to a clock network. The pin must be a valid pin defined in the VPR architecture description file.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="spine1" x="1" y="1">
|
||||||
|
<internal_driver tile_pin="clb.O[0:1]"/>
|
||||||
|
</switch_point>
|
||||||
|
<spine>
|
||||||
|
|
||||||
|
where the clock routing can be driven at (x=1,y=1) by the output pins ``O[0:3]`` of tile ``clb`` in a VPR architecture description file:
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<tile name="clb">
|
||||||
|
<sub_tile name="clb">
|
||||||
|
<output name="O" num_pins="8"/>
|
||||||
|
</sub_tile>
|
||||||
|
</tile>
|
||||||
|
|
||||||
|
|
||||||
.. _file_formats_clock_network_tap_point:
|
.. _file_formats_clock_network_tap_point:
|
||||||
|
|
||||||
Tap Point Settings
|
Tap Point Settings
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following syntax are applicable to the XML definition tagged by ``tap``.
|
The following syntax are applicable to the XML definition tagged by ``all``, ``region`` and ``single``.
|
||||||
Note that a number of tap points can be defined under the node ``taps``.
|
Note that a number of tap points can be defined under the node ``taps``.
|
||||||
|
|
||||||
.. option:: tile_pin="<string>"
|
.. option:: from_pin="<string>"
|
||||||
|
|
||||||
Define the pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file.
|
Define the source pin of a programmable block to be tapped by a clock network. The pin must be a valid pin of the global ports defined in the tile_annotation part of OpenFPGA architecture description file.
|
||||||
|
|
||||||
|
.. option:: to_pin="<string>"
|
||||||
|
|
||||||
|
Define the destination pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file.
|
||||||
|
|
||||||
.. note:: Only the leaf clock spine (not switch points to drive other clock spine) can tap pins of programmable blocks.
|
.. note:: Only the leaf clock spine (not switch points to drive other clock spine) can tap pins of programmable blocks.
|
||||||
|
|
||||||
|
.. note:: Each coordinate must be a valid integer within the device height and width that are defined in VPR architecture!!!
|
||||||
|
|
||||||
|
.. warning:: The following syntax are only applicable to ``single`` tap mode.
|
||||||
|
|
||||||
|
.. option:: x="<int>"
|
||||||
|
|
||||||
|
Define the x coordinate of the tap point, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: y="<int>"
|
||||||
|
|
||||||
|
Define the y coordinate of the tap point, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. warning:: The following syntax are only applicable to ``region`` tap mode.
|
||||||
|
|
||||||
|
.. option:: start_x="<int>"
|
||||||
|
|
||||||
|
Define the starting x coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: start_y="<int>"
|
||||||
|
|
||||||
|
Define the starting y coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: end_x="<int>"
|
||||||
|
|
||||||
|
Define the ending x coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: end_y="<int>"
|
||||||
|
|
||||||
|
Define the ending y coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: repeat_x="<int>"
|
||||||
|
|
||||||
|
Define the repeating factor on x coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
|
.. option:: repeat_y="<int>"
|
||||||
|
|
||||||
|
Define the repeating factor on y coordinate of the tap region, which is applied to the destination pin ``to_pin``
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
<clock_network name="clk_tree_0" width="1">
|
<clock_network name="clk_tree_0" width="2">
|
||||||
<!-- Some clock spines -->
|
<!-- Some clock spines -->
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="clb.clk"/>
|
<all from_pin="clk[0:0]" to_pin="clb.clk[0:0]"/>
|
||||||
|
<region from_pin="clk[1:1]" to_pin="clb.clk[1:1]" start_x="1" start_y="1" end_x="4" end_y="4" repeat_x="2" repeat_y="2"/>
|
||||||
|
<single from_pin="clk[1:1]" to_pin="clb.clk[1:1]" x="2" y="2"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
|
|
||||||
|
@ -201,7 +296,8 @@ where all the clock spines of the clock network ``clk_tree_0`` tap the clock pin
|
||||||
|
|
||||||
<tile name="clb">
|
<tile name="clb">
|
||||||
<sub_tile name="clb">
|
<sub_tile name="clb">
|
||||||
<clock name="clk" num_pins="1"/>
|
<clock name="clk" num_pins="2"/>
|
||||||
</sub_tile>
|
</sub_tile>
|
||||||
</tile>
|
</tile>
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
|
@ -130,8 +130,17 @@ Clock signals will be auto-detected and routed based on pin constraints which ar
|
||||||
|
|
||||||
.. option:: --pin_constraints_file <string> or -pcf <string>
|
.. option:: --pin_constraints_file <string> or -pcf <string>
|
||||||
|
|
||||||
Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml``
|
Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml``. Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`.
|
||||||
Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`.
|
|
||||||
|
.. note:: If there is a global net, e.g., ``clk`` or ``reset``, which will be driven by an internal resource, it should also be defined in the PCF file.
|
||||||
|
|
||||||
|
.. option:: --disable_unused_trees
|
||||||
|
|
||||||
|
Disable entire clock trees when they are not used by any clock nets. Useful to reduce clock power
|
||||||
|
|
||||||
|
.. option:: --disable_unused_spines
|
||||||
|
|
||||||
|
Disable part of the clock tree which are used by clock nets. Useful to reduce clock power
|
||||||
|
|
||||||
.. option:: --verbose
|
.. option:: --verbose
|
||||||
|
|
||||||
|
|
|
@ -89,14 +89,6 @@ static void read_xml_tile_global_port_annotation(
|
||||||
get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
||||||
.as_bool(false));
|
.as_bool(false));
|
||||||
|
|
||||||
/* Get clock tree attributes if this is a clock */
|
|
||||||
if (tile_annotation.global_port_is_clock(tile_global_port_id)) {
|
|
||||||
tile_annotation.set_global_port_clock_arch_tree_name(
|
|
||||||
tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name",
|
|
||||||
loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
||||||
.as_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get is_set attributes */
|
/* Get is_set attributes */
|
||||||
tile_annotation.set_global_port_is_set(
|
tile_annotation.set_global_port_is_set(
|
||||||
tile_global_port_id,
|
tile_global_port_id,
|
||||||
|
@ -109,6 +101,16 @@ static void read_xml_tile_global_port_annotation(
|
||||||
get_attribute(xml_tile, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
get_attribute(xml_tile, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
||||||
.as_bool(false));
|
.as_bool(false));
|
||||||
|
|
||||||
|
/* Get clock tree attributes if this is a clock, reset or set */
|
||||||
|
if (tile_annotation.global_port_is_clock(tile_global_port_id) ||
|
||||||
|
tile_annotation.global_port_is_reset(tile_global_port_id) ||
|
||||||
|
tile_annotation.global_port_is_set(tile_global_port_id)) {
|
||||||
|
tile_annotation.set_global_port_clock_arch_tree_name(
|
||||||
|
tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name",
|
||||||
|
loc_data, pugiutil::ReqOpt::OPTIONAL)
|
||||||
|
.as_string());
|
||||||
|
}
|
||||||
|
|
||||||
/* Get default_value attributes */
|
/* Get default_value attributes */
|
||||||
tile_annotation.set_global_port_default_value(
|
tile_annotation.set_global_port_default_value(
|
||||||
tile_global_port_id,
|
tile_global_port_id,
|
||||||
|
|
|
@ -96,6 +96,11 @@ size_t TileAnnotation::global_port_default_value(
|
||||||
return global_port_default_values_[global_port_id];
|
return global_port_default_values_[global_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TileAnnotation::global_port_thru_dedicated_network(
|
||||||
|
const TileGlobalPortId& global_port_id) const {
|
||||||
|
return !global_port_clock_arch_tree_name(global_port_id).empty();
|
||||||
|
}
|
||||||
|
|
||||||
std::string TileAnnotation::global_port_clock_arch_tree_name(
|
std::string TileAnnotation::global_port_clock_arch_tree_name(
|
||||||
const TileGlobalPortId& global_port_id) const {
|
const TileGlobalPortId& global_port_id) const {
|
||||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
|
|
@ -54,6 +54,8 @@ class TileAnnotation {
|
||||||
bool global_port_is_clock(const TileGlobalPortId& global_port_id) const;
|
bool global_port_is_clock(const TileGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_set(const TileGlobalPortId& global_port_id) const;
|
bool global_port_is_set(const TileGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_reset(const TileGlobalPortId& global_port_id) const;
|
bool global_port_is_reset(const TileGlobalPortId& global_port_id) const;
|
||||||
|
bool global_port_thru_dedicated_network(
|
||||||
|
const TileGlobalPortId& global_port_id) const;
|
||||||
std::string global_port_clock_arch_tree_name(
|
std::string global_port_clock_arch_tree_name(
|
||||||
const TileGlobalPortId& global_port_id) const;
|
const TileGlobalPortId& global_port_id) const;
|
||||||
size_t global_port_default_value(
|
size_t global_port_default_value(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<clock_networks default_segment="seg_len1" default_switch="fast_switch">
|
<clock_networks default_segment="seg_len1" default_tap_switch="fast_switch" default_driver_switch="slow_switch">
|
||||||
<clock_network name="example_network" width="8">
|
<clock_network name="example_network" global_port="clk[0:7]">
|
||||||
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
|
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
|
||||||
<switch_point tap="spine_lvl2_upper" x="2" y="2"/>
|
<switch_point tap="spine_lvl2_upper" x="2" y="2"/>
|
||||||
<switch_point tap="spine_lvl2_lower" x="2" y="2"/>
|
<switch_point tap="spine_lvl2_lower" x="2" y="2"/>
|
||||||
|
@ -17,10 +17,10 @@
|
||||||
<spine name="rib_lvl1_lower_left" start_x="2" start_y="1" end_x="1" end_y="1"/>
|
<spine name="rib_lvl1_lower_left" start_x="2" start_y="1" end_x="1" end_y="1"/>
|
||||||
<spine name="rib_lvl1_lower_right" start_x="2" start_y="1" end_x="3" end_y="1"/>
|
<spine name="rib_lvl1_lower_right" start_x="2" start_y="1" end_x="3" end_y="1"/>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="io[0:23].clk[0:7]"/>
|
<all from_pin="clk[0:0]" to_pin="io[0:23].clk[0:7]"/>
|
||||||
<tap tile_pin="clb[0:0].clk[0:7]"/>
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:7]"/>
|
||||||
<tap tile_pin="dsp[0:0].clk[0:7]"/>
|
<all from_pin="clk[0:0]" to_pin="dsp[0:0].clk[0:7]"/>
|
||||||
<tap tile_pin="bram[0:0].clk[0:7]"/>
|
<all from_pin="clk[0:0]" to_pin="bram[0:0].clk[0:7]"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<clock_networks default_segment="seg_len1" default_tap_switch="fast_switch" default_driver_switch="slow_switch">
|
||||||
|
<clock_network name="example_network" global_port="clk[0:7]">
|
||||||
|
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
|
||||||
|
<switch_point tap="spine_lvl2_upper" x="2" y="2">
|
||||||
|
<internal_driver tile_pin="clb.O[0:3]"/>
|
||||||
|
</switch_point>
|
||||||
|
<switch_point tap="spine_lvl2_lower" x="2" y="2">
|
||||||
|
<internal_driver tile_pin="clb.O[0:3]"/>
|
||||||
|
</switch_point>
|
||||||
|
</spine>
|
||||||
|
<spine name="spine_lvl2_upper" start_x="2" start_y="2" end_x="2" end_y="3">
|
||||||
|
<switch_point tap="rib_lvl1_upper_left" x="2" y="3"/>
|
||||||
|
<switch_point tap="rib_lvl1_upper_right" x="2" y="3"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="spine_lvl2_lower" start_x="2" start_y="2" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rib_lvl1_lower_left" x="2" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_lower_right" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rib_lvl1_upper_left" start_x="2" start_y="3" end_x="1" end_y="3"/>
|
||||||
|
<spine name="rib_lvl1_upper_right" start_x="2" start_y="3" end_x="3" end_y="3"/>
|
||||||
|
<spine name="rib_lvl1_lower_left" start_x="2" start_y="1" end_x="1" end_y="1"/>
|
||||||
|
<spine name="rib_lvl1_lower_right" start_x="2" start_y="1" end_x="3" end_y="1"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="clk[0:0]" to_pin="io[0:23].clk[0:0]"/>
|
||||||
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[1:1]"/>
|
||||||
|
<all from_pin="clk[0:0]" to_pin="dsp[0:0].clk[2:2]"/>
|
||||||
|
<single from_pin="clk[0:0]" to_pin="bram[0:0].clk[3:7]" x="1" y="1"/>
|
||||||
|
<region from_pin="clk[0:0]" to_pin="bram[0:0].clk[3:7]" start_x="1" end_x="10" repeat_x="2" start_y="8" end_y="20" repeat_y="8"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -18,7 +18,10 @@ namespace openfpga { // Begin namespace openfpga
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
ClockNetwork::ClockNetwork() {
|
ClockNetwork::ClockNetwork() {
|
||||||
default_segment_id_ = RRSegmentId::INVALID();
|
default_segment_id_ = RRSegmentId::INVALID();
|
||||||
default_switch_id_ = RRSwitchId::INVALID();
|
default_tap_switch_id_ = RRSwitchId::INVALID();
|
||||||
|
default_driver_switch_id_ = RRSwitchId::INVALID();
|
||||||
|
/* Set a default invalid bounding box */
|
||||||
|
empty_tap_bb_ = vtr::Rect<size_t>(1, 0, 1, 0);
|
||||||
is_dirty_ = true;
|
is_dirty_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +34,12 @@ ClockNetwork::clock_tree_range ClockNetwork::trees() const {
|
||||||
return vtr::make_range(tree_ids_.begin(), tree_ids_.end());
|
return vtr::make_range(tree_ids_.begin(), tree_ids_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClockNetwork::clock_internal_driver_range ClockNetwork::internal_drivers()
|
||||||
|
const {
|
||||||
|
return vtr::make_range(internal_driver_ids_.begin(),
|
||||||
|
internal_driver_ids_.end());
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ClockLevelId> ClockNetwork::levels(
|
std::vector<ClockLevelId> ClockNetwork::levels(
|
||||||
const ClockTreeId& tree_id) const {
|
const ClockTreeId& tree_id) const {
|
||||||
std::vector<ClockLevelId> ret;
|
std::vector<ClockLevelId> ret;
|
||||||
|
@ -172,11 +181,20 @@ RRSegmentId ClockNetwork::default_segment() const {
|
||||||
return default_segment_id_;
|
return default_segment_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ClockNetwork::default_switch_name() const {
|
std::string ClockNetwork::default_tap_switch_name() const {
|
||||||
return default_switch_name_;
|
return default_tap_switch_name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
RRSwitchId ClockNetwork::default_switch() const { return default_switch_id_; }
|
std::string ClockNetwork::default_driver_switch_name() const {
|
||||||
|
return default_driver_switch_name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
RRSwitchId ClockNetwork::default_tap_switch() const {
|
||||||
|
return default_tap_switch_id_;
|
||||||
|
}
|
||||||
|
RRSwitchId ClockNetwork::default_driver_switch() const {
|
||||||
|
return default_driver_switch_id_;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const {
|
std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const {
|
||||||
VTR_ASSERT(valid_tree_id(tree_id));
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
|
@ -199,9 +217,14 @@ size_t ClockNetwork::max_tree_depth() const {
|
||||||
return max_size;
|
return max_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasicPort ClockNetwork::tree_global_port(const ClockTreeId& tree_id) const {
|
||||||
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
|
return tree_global_ports_[tree_id];
|
||||||
|
}
|
||||||
|
|
||||||
size_t ClockNetwork::tree_width(const ClockTreeId& tree_id) const {
|
size_t ClockNetwork::tree_width(const ClockTreeId& tree_id) const {
|
||||||
VTR_ASSERT(valid_tree_id(tree_id));
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
return tree_widths_[tree_id];
|
return tree_global_ports_[tree_id].get_width();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ClockNetwork::tree_depth(const ClockTreeId& tree_id) const {
|
size_t ClockNetwork::tree_depth(const ClockTreeId& tree_id) const {
|
||||||
|
@ -315,17 +338,157 @@ vtr::Point<int> ClockNetwork::spine_switch_point(
|
||||||
return spine_switch_coords_[spine_id][size_t(switch_point_id)];
|
return spine_switch_coords_[spine_id][size_t(switch_point_id)];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ClockNetwork::tree_taps(
|
std::vector<ClockSwitchPointId>
|
||||||
|
ClockNetwork::find_spine_switch_points_with_coord(
|
||||||
|
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
|
||||||
|
VTR_ASSERT(valid_spine_id(spine_id));
|
||||||
|
std::vector<ClockSwitchPointId> ret;
|
||||||
|
for (size_t i = 0; i < spine_switch_points_[spine_id].size(); ++i) {
|
||||||
|
if (spine_switch_coords_[spine_id][i] == coord) {
|
||||||
|
ret.push_back(ClockSwitchPointId(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ClockInternalDriverId>
|
||||||
|
ClockNetwork::spine_switch_point_internal_drivers(
|
||||||
|
const ClockSpineId& spine_id,
|
||||||
|
const ClockSwitchPointId& switch_point_id) const {
|
||||||
|
VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id));
|
||||||
|
return spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ClockNetwork::internal_driver_port(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const {
|
||||||
|
VTR_ASSERT(valid_internal_driver_id(int_driver_id));
|
||||||
|
return internal_driver_ports_[int_driver_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ClockTapId> ClockNetwork::tree_taps(
|
||||||
const ClockTreeId& tree_id) const {
|
const ClockTreeId& tree_id) const {
|
||||||
VTR_ASSERT(valid_tree_id(tree_id));
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
return tree_taps_[tree_id];
|
return tree_taps_[tree_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ClockNetwork::tree_flatten_taps(
|
BasicPort ClockNetwork::tap_from_port(const ClockTapId& tap_id) const {
|
||||||
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const {
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
return tap_from_ports_[tap_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ClockNetwork::tap_to_port(const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
return tap_to_ports_[tap_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockNetwork::e_tap_type ClockNetwork::tap_type(
|
||||||
|
const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
/* If not a region, it is a default type covering all the coordinates*/
|
||||||
|
if (tap_bbs_[tap_id] == empty_tap_bb_) {
|
||||||
|
return ClockNetwork::e_tap_type::ALL;
|
||||||
|
}
|
||||||
|
/* Now check if this a single point */
|
||||||
|
if (tap_bbs_[tap_id].height() == 0 && tap_bbs_[tap_id].width() == 0) {
|
||||||
|
return ClockNetwork::e_tap_type::SINGLE;
|
||||||
|
}
|
||||||
|
return ClockNetwork::e_tap_type::REGION;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClockNetwork::tap_x(const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE);
|
||||||
|
return tap_bbs_[tap_id].xmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClockNetwork::tap_y(const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE);
|
||||||
|
return tap_bbs_[tap_id].ymin();
|
||||||
|
}
|
||||||
|
|
||||||
|
vtr::Rect<size_t> ClockNetwork::tap_bounding_box(
|
||||||
|
const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
|
||||||
|
return tap_bbs_[tap_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClockNetwork::tap_step_x(const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
|
||||||
|
return tap_bb_steps_[tap_id].x();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClockNetwork::tap_step_y(const ClockTapId& tap_id) const {
|
||||||
|
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
|
||||||
|
return tap_bb_steps_[tap_id].y();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::valid_tap_coord_in_bb(
|
||||||
|
const ClockTapId& tap_id, const vtr::Point<size_t>& tap_coord) const {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
if (tap_type(tap_id) == ClockNetwork::e_tap_type::ALL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE &&
|
||||||
|
tap_bbs_[tap_id].coincident(tap_coord)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION &&
|
||||||
|
tap_bbs_[tap_id].coincident(tap_coord)) {
|
||||||
|
/* Check if steps are considered, coords still matches */
|
||||||
|
bool x_in_bb = false;
|
||||||
|
for (size_t ix = tap_bbs_[tap_id].xmin(); ix <= tap_bbs_[tap_id].xmax();
|
||||||
|
ix = ix + tap_bb_steps_[tap_id].x()) {
|
||||||
|
if (tap_coord.x() == ix) {
|
||||||
|
x_in_bb = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Early exit */
|
||||||
|
if (!x_in_bb) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool y_in_bb = false;
|
||||||
|
for (size_t iy = tap_bbs_[tap_id].ymin(); iy <= tap_bbs_[tap_id].ymax();
|
||||||
|
iy = iy + tap_bb_steps_[tap_id].y()) {
|
||||||
|
if (tap_coord.y() == iy) {
|
||||||
|
y_in_bb = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y_in_bb && x_in_bb) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ClockNetwork::tree_flatten_tap_to_ports(
|
||||||
|
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id,
|
||||||
|
const vtr::Point<size_t>& tap_coord) const {
|
||||||
VTR_ASSERT(valid_tree_id(tree_id));
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
std::vector<std::string> flatten_taps;
|
std::vector<std::string> flatten_taps;
|
||||||
for (const std::string& tap_name : tree_taps_[tree_id]) {
|
for (ClockTapId tap_id : tree_taps_[tree_id]) {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
/* Filter out unmatched from ports. Expect [clk_pin_id:clk_pin_id] */
|
||||||
|
BasicPort from_port = tap_from_ports_[tap_id];
|
||||||
|
if (!from_port.is_valid()) {
|
||||||
|
VTR_LOG_ERROR("Invalid from port name '%s' whose index is not valid\n",
|
||||||
|
from_port.to_verilog_string().c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (from_port.get_width() != 1) {
|
||||||
|
VTR_LOG_ERROR("Invalid from port name '%s' whose width is not 1\n",
|
||||||
|
from_port.to_verilog_string().c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (from_port.get_lsb() != size_t(clk_pin_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Filter out unmatched coordinates */
|
||||||
|
if (!valid_tap_coord_in_bb(tap_id, tap_coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string tap_name = tap_to_ports_[tap_id];
|
||||||
StringToken tokenizer(tap_name);
|
StringToken tokenizer(tap_name);
|
||||||
std::vector<std::string> pin_tokens = tokenizer.split(".");
|
std::vector<std::string> pin_tokens = tokenizer.split(".");
|
||||||
if (pin_tokens.size() != 2) {
|
if (pin_tokens.size() != 2) {
|
||||||
|
@ -363,6 +526,43 @@ std::vector<std::string> ClockNetwork::tree_flatten_taps(
|
||||||
return flatten_taps;
|
return flatten_taps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ClockNetwork::flatten_internal_driver_port(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const {
|
||||||
|
std::vector<std::string> flatten_taps;
|
||||||
|
std::string tap_name = internal_driver_port(int_driver_id);
|
||||||
|
StringToken tokenizer(tap_name);
|
||||||
|
std::vector<std::string> pin_tokens = tokenizer.split(".");
|
||||||
|
if (pin_tokens.size() != 2) {
|
||||||
|
VTR_LOG_ERROR("Invalid pin name '%s'. Expect <tile>.<port>\n",
|
||||||
|
tap_name.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
PortParser tile_parser(pin_tokens[0]);
|
||||||
|
BasicPort tile_info = tile_parser.port();
|
||||||
|
PortParser pin_parser(pin_tokens[1]);
|
||||||
|
BasicPort pin_info = pin_parser.port();
|
||||||
|
if (!tile_info.is_valid()) {
|
||||||
|
VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n",
|
||||||
|
tap_name.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!pin_info.is_valid()) {
|
||||||
|
VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n",
|
||||||
|
tap_name.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (size_t& tile_idx : tile_info.pins()) {
|
||||||
|
std::string flatten_tile_str =
|
||||||
|
tile_info.get_name() + "[" + std::to_string(tile_idx) + "]";
|
||||||
|
for (size_t& pin_idx : pin_info.pins()) {
|
||||||
|
std::string flatten_pin_str =
|
||||||
|
pin_info.get_name() + "[" + std::to_string(pin_idx) + "]";
|
||||||
|
flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flatten_taps;
|
||||||
|
}
|
||||||
|
|
||||||
ClockTreeId ClockNetwork::find_tree(const std::string& name) const {
|
ClockTreeId ClockNetwork::find_tree(const std::string& name) const {
|
||||||
auto result = tree_name2id_map_.find(name);
|
auto result = tree_name2id_map_.find(name);
|
||||||
if (result == tree_name2id_map_.end()) {
|
if (result == tree_name2id_map_.end()) {
|
||||||
|
@ -400,6 +600,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
|
||||||
spine_track_types_.reserve(num_spines);
|
spine_track_types_.reserve(num_spines);
|
||||||
spine_switch_points_.reserve(num_spines);
|
spine_switch_points_.reserve(num_spines);
|
||||||
spine_switch_coords_.reserve(num_spines);
|
spine_switch_coords_.reserve(num_spines);
|
||||||
|
spine_switch_internal_drivers_.reserve(num_spines);
|
||||||
spine_parents_.reserve(num_spines);
|
spine_parents_.reserve(num_spines);
|
||||||
spine_children_.reserve(num_spines);
|
spine_children_.reserve(num_spines);
|
||||||
spine_parent_trees_.reserve(num_spines);
|
spine_parent_trees_.reserve(num_spines);
|
||||||
|
@ -408,7 +609,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
|
||||||
void ClockNetwork::reserve_trees(const size_t& num_trees) {
|
void ClockNetwork::reserve_trees(const size_t& num_trees) {
|
||||||
tree_ids_.reserve(num_trees);
|
tree_ids_.reserve(num_trees);
|
||||||
tree_names_.reserve(num_trees);
|
tree_names_.reserve(num_trees);
|
||||||
tree_widths_.reserve(num_trees);
|
tree_global_ports_.reserve(num_trees);
|
||||||
tree_top_spines_.reserve(num_trees);
|
tree_top_spines_.reserve(num_trees);
|
||||||
tree_taps_.reserve(num_trees);
|
tree_taps_.reserve(num_trees);
|
||||||
}
|
}
|
||||||
|
@ -417,25 +618,40 @@ void ClockNetwork::set_default_segment(const RRSegmentId& seg_id) {
|
||||||
default_segment_id_ = seg_id;
|
default_segment_id_ = seg_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockNetwork::set_default_switch(const RRSwitchId& switch_id) {
|
void ClockNetwork::set_default_tap_switch(const RRSwitchId& switch_id) {
|
||||||
default_switch_id_ = switch_id;
|
default_tap_switch_id_ = switch_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockNetwork::set_default_driver_switch(const RRSwitchId& switch_id) {
|
||||||
|
default_driver_switch_id_ = switch_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockNetwork::set_default_segment_name(const std::string& name) {
|
void ClockNetwork::set_default_segment_name(const std::string& name) {
|
||||||
default_segment_name_ = name;
|
default_segment_name_ = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockNetwork::set_default_switch_name(const std::string& name) {
|
void ClockNetwork::set_default_tap_switch_name(const std::string& name) {
|
||||||
default_switch_name_ = name;
|
default_tap_switch_name_ = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClockTreeId ClockNetwork::create_tree(const std::string& name, size_t width) {
|
void ClockNetwork::set_default_driver_switch_name(const std::string& name) {
|
||||||
|
default_driver_switch_name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockTreeId ClockNetwork::create_tree(const std::string& name,
|
||||||
|
const BasicPort& global_port) {
|
||||||
|
/* Sanity checks */
|
||||||
|
if (!global_port.is_valid()) {
|
||||||
|
VTR_LOG_ERROR("Invalid global port '%s' for clock tree name '%s'\n",
|
||||||
|
global_port.to_verilog_string().c_str(), name.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
/* Create a new id */
|
/* Create a new id */
|
||||||
ClockTreeId tree_id = ClockTreeId(tree_ids_.size());
|
ClockTreeId tree_id = ClockTreeId(tree_ids_.size());
|
||||||
|
|
||||||
tree_ids_.push_back(tree_id);
|
tree_ids_.push_back(tree_id);
|
||||||
tree_names_.push_back(name);
|
tree_names_.push_back(name);
|
||||||
tree_widths_.push_back(width);
|
tree_global_ports_.push_back(global_port);
|
||||||
tree_depths_.emplace_back();
|
tree_depths_.emplace_back();
|
||||||
tree_taps_.emplace_back();
|
tree_taps_.emplace_back();
|
||||||
tree_top_spines_.emplace_back();
|
tree_top_spines_.emplace_back();
|
||||||
|
@ -476,6 +692,7 @@ ClockSpineId ClockNetwork::create_spine(const std::string& name) {
|
||||||
spine_track_types_.emplace_back(NUM_RR_TYPES);
|
spine_track_types_.emplace_back(NUM_RR_TYPES);
|
||||||
spine_switch_points_.emplace_back();
|
spine_switch_points_.emplace_back();
|
||||||
spine_switch_coords_.emplace_back();
|
spine_switch_coords_.emplace_back();
|
||||||
|
spine_switch_internal_drivers_.emplace_back();
|
||||||
spine_parents_.emplace_back();
|
spine_parents_.emplace_back();
|
||||||
spine_children_.emplace_back();
|
spine_children_.emplace_back();
|
||||||
spine_parent_trees_.emplace_back();
|
spine_parent_trees_.emplace_back();
|
||||||
|
@ -526,13 +743,14 @@ void ClockNetwork::set_spine_track_type(const ClockSpineId& spine_id,
|
||||||
spine_track_types_[spine_id] = type;
|
spine_track_types_[spine_id] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id,
|
ClockSwitchPointId ClockNetwork::add_spine_switch_point(
|
||||||
const ClockSpineId& drive_spine_id,
|
const ClockSpineId& spine_id, const ClockSpineId& drive_spine_id,
|
||||||
const vtr::Point<int>& coord) {
|
const vtr::Point<int>& coord) {
|
||||||
VTR_ASSERT(valid_spine_id(spine_id));
|
VTR_ASSERT(valid_spine_id(spine_id));
|
||||||
VTR_ASSERT(valid_spine_id(drive_spine_id));
|
VTR_ASSERT(valid_spine_id(drive_spine_id));
|
||||||
spine_switch_points_[spine_id].push_back(drive_spine_id);
|
spine_switch_points_[spine_id].push_back(drive_spine_id);
|
||||||
spine_switch_coords_[spine_id].push_back(coord);
|
spine_switch_coords_[spine_id].push_back(coord);
|
||||||
|
spine_switch_internal_drivers_[spine_id].emplace_back();
|
||||||
/* Do not allow any spine has different parents */
|
/* Do not allow any spine has different parents */
|
||||||
if (spine_parents_[drive_spine_id]) {
|
if (spine_parents_[drive_spine_id]) {
|
||||||
VTR_LOG_ERROR(
|
VTR_LOG_ERROR(
|
||||||
|
@ -545,12 +763,91 @@ void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id,
|
||||||
}
|
}
|
||||||
spine_parents_[drive_spine_id] = spine_id;
|
spine_parents_[drive_spine_id] = spine_id;
|
||||||
spine_children_[spine_id].push_back(drive_spine_id);
|
spine_children_[spine_id].push_back(drive_spine_id);
|
||||||
|
return ClockSwitchPointId(spine_switch_points_[spine_id].size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
|
ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(
|
||||||
const std::string& pin_name) {
|
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
|
||||||
|
const std::string& int_driver_port) {
|
||||||
|
VTR_ASSERT(valid_spine_id(spine_id));
|
||||||
|
VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id));
|
||||||
|
/* Find any existing id for the driver port */
|
||||||
|
for (ClockInternalDriverId int_driver_id : internal_driver_ids_) {
|
||||||
|
if (internal_driver_ports_[int_driver_id] == int_driver_port) {
|
||||||
|
spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)]
|
||||||
|
.push_back(int_driver_id);
|
||||||
|
return int_driver_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Reaching here, no existing id can be reused, create a new one */
|
||||||
|
ClockInternalDriverId int_driver_id =
|
||||||
|
ClockInternalDriverId(internal_driver_ids_.size());
|
||||||
|
internal_driver_ids_.push_back(int_driver_id);
|
||||||
|
internal_driver_ports_.push_back(int_driver_port);
|
||||||
|
spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(
|
||||||
|
int_driver_id);
|
||||||
|
return int_driver_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
|
||||||
|
const BasicPort& from_port,
|
||||||
|
const std::string& to_port) {
|
||||||
VTR_ASSERT(valid_tree_id(tree_id));
|
VTR_ASSERT(valid_tree_id(tree_id));
|
||||||
tree_taps_[tree_id].push_back(pin_name);
|
/* TODO: Consider find existing tap template and avoid duplication in storage
|
||||||
|
*/
|
||||||
|
ClockTapId tap_id = ClockTapId(tap_ids_.size());
|
||||||
|
tap_ids_.push_back(tap_id);
|
||||||
|
tap_from_ports_.push_back(from_port);
|
||||||
|
tap_to_ports_.push_back(to_port);
|
||||||
|
tap_bbs_.emplace_back(empty_tap_bb_);
|
||||||
|
tap_bb_steps_.emplace_back(vtr::Point<size_t>(0, 0));
|
||||||
|
tree_taps_[tree_id].push_back(tap_id);
|
||||||
|
return tap_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::set_tap_bounding_box(const ClockTapId& tap_id,
|
||||||
|
const vtr::Rect<size_t>& bb) {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
/* Check the bounding box, ensure it must be valid */
|
||||||
|
if (bb.xmax() < bb.xmin() || bb.ymax() < bb.ymin()) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Invalid bounding box (xlow=%lu, ylow=%lu) -> (xhigh=%lu, yhigh=%lu)! "
|
||||||
|
"Must follow: xlow <= xhigh, ylow <= yhigh!\n",
|
||||||
|
bb.xmin(), bb.ymin(), bb.xmax(), bb.ymax());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tap_bbs_[tap_id] = bb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::set_tap_step_x(const ClockTapId& tap_id,
|
||||||
|
const size_t& step) {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
/* Must be a valid step >= 1 */
|
||||||
|
if (step == 0) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Invalid x-direction step (=%lu) for any bounding box! Expect an integer "
|
||||||
|
">= 1!\n",
|
||||||
|
step);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tap_bb_steps_[tap_id].set_x(step);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::set_tap_step_y(const ClockTapId& tap_id,
|
||||||
|
const size_t& step) {
|
||||||
|
VTR_ASSERT(valid_tap_id(tap_id));
|
||||||
|
/* Must be a valid step >= 1 */
|
||||||
|
if (step == 0) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Invalid y-direction step (=%lu) for any bounding box! Expect an integer "
|
||||||
|
">= 1!\n",
|
||||||
|
step);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tap_bb_steps_[tap_id].set_y(step);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClockNetwork::link() {
|
bool ClockNetwork::link() {
|
||||||
|
@ -562,6 +859,25 @@ bool ClockNetwork::link() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::validate_tree_taps() const {
|
||||||
|
for (ClockTreeId tree_id : trees()) {
|
||||||
|
for (ClockTapId tap_id : tree_taps(tree_id)) {
|
||||||
|
/* The from pin name should match the global port */
|
||||||
|
if (!tree_global_port(tree_id).mergeable(tap_from_port(tap_id)) ||
|
||||||
|
!tree_global_port(tree_id).contained(tap_from_port(tap_id))) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Tap point from_port '%s' is not part of the global port '%s' of "
|
||||||
|
"tree '%s'\n",
|
||||||
|
tap_from_port(tap_id).to_verilog_string().c_str(),
|
||||||
|
tree_global_port(tree_id).to_verilog_string().c_str(),
|
||||||
|
tree_name(tree_id).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClockNetwork::validate_tree() const {
|
bool ClockNetwork::validate_tree() const {
|
||||||
for (ClockTreeId tree_id : trees()) {
|
for (ClockTreeId tree_id : trees()) {
|
||||||
for (ClockSpineId spine_id : spines(tree_id)) {
|
for (ClockSpineId spine_id : spines(tree_id)) {
|
||||||
|
@ -622,7 +938,8 @@ bool ClockNetwork::validate_tree() const {
|
||||||
|
|
||||||
bool ClockNetwork::validate() const {
|
bool ClockNetwork::validate() const {
|
||||||
is_dirty_ = true;
|
is_dirty_ = true;
|
||||||
if (default_segment_id_ && default_switch_id_ && validate_tree()) {
|
if (default_segment_id_ && default_tap_switch_id_ &&
|
||||||
|
default_driver_switch_id_ && validate_tree() && validate_tree_taps()) {
|
||||||
is_dirty_ = false;
|
is_dirty_ = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -698,6 +1015,16 @@ bool ClockNetwork::valid_tree_id(const ClockTreeId& tree_id) const {
|
||||||
(tree_id == tree_ids_[tree_id]);
|
(tree_id == tree_ids_[tree_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::valid_internal_driver_id(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const {
|
||||||
|
return (size_t(int_driver_id) < internal_driver_ids_.size()) &&
|
||||||
|
(int_driver_id == internal_driver_ids_[int_driver_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClockNetwork::valid_tap_id(const ClockTapId& tap_id) const {
|
||||||
|
return (size_t(tap_id) < tap_ids_.size()) && (tap_id == tap_ids_[tap_id]);
|
||||||
|
}
|
||||||
|
|
||||||
bool ClockNetwork::valid_level_id(const ClockTreeId& tree_id,
|
bool ClockNetwork::valid_level_id(const ClockTreeId& tree_id,
|
||||||
const ClockLevelId& lvl_id) const {
|
const ClockLevelId& lvl_id) const {
|
||||||
return valid_tree_id(tree_id) && (size_t(lvl_id) < tree_depth(tree_id));
|
return valid_tree_id(tree_id) && (size_t(lvl_id) < tree_depth(tree_id));
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
/* Headers from openfpgautil library */
|
/* Headers from openfpgautil library */
|
||||||
#include "clock_network_fwd.h"
|
#include "clock_network_fwd.h"
|
||||||
|
#include "openfpga_port.h"
|
||||||
#include "rr_graph_fwd.h"
|
#include "rr_graph_fwd.h"
|
||||||
#include "rr_node_types.h"
|
#include "rr_node_types.h"
|
||||||
|
|
||||||
|
@ -42,6 +43,14 @@ class ClockNetwork {
|
||||||
clock_tree_iterator;
|
clock_tree_iterator;
|
||||||
/* Create range */
|
/* Create range */
|
||||||
typedef vtr::Range<clock_tree_iterator> clock_tree_range;
|
typedef vtr::Range<clock_tree_iterator> clock_tree_range;
|
||||||
|
typedef vtr::vector<ClockInternalDriverId,
|
||||||
|
ClockInternalDriverId>::const_iterator
|
||||||
|
clock_internal_driver_iterator;
|
||||||
|
/* Create range */
|
||||||
|
typedef vtr::Range<clock_internal_driver_iterator>
|
||||||
|
clock_internal_driver_range;
|
||||||
|
/* Type of tap points */
|
||||||
|
enum class e_tap_type : unsigned char { ALL = 0, SINGLE, REGION, NUM_TYPES };
|
||||||
|
|
||||||
public: /* Constructors */
|
public: /* Constructors */
|
||||||
ClockNetwork();
|
ClockNetwork();
|
||||||
|
@ -49,6 +58,7 @@ class ClockNetwork {
|
||||||
public: /* Accessors: aggregates */
|
public: /* Accessors: aggregates */
|
||||||
size_t num_trees() const;
|
size_t num_trees() const;
|
||||||
clock_tree_range trees() const;
|
clock_tree_range trees() const;
|
||||||
|
clock_internal_driver_range internal_drivers() const;
|
||||||
/* Return the range of clock levels */
|
/* Return the range of clock levels */
|
||||||
std::vector<ClockLevelId> levels(const ClockTreeId& tree_id) const;
|
std::vector<ClockLevelId> levels(const ClockTreeId& tree_id) const;
|
||||||
/* Return a list of spine id under a clock tree */
|
/* Return a list of spine id under a clock tree */
|
||||||
|
@ -73,9 +83,12 @@ class ClockNetwork {
|
||||||
* information from RRGraph */
|
* information from RRGraph */
|
||||||
RRSegmentId default_segment() const;
|
RRSegmentId default_segment() const;
|
||||||
std::string default_segment_name() const;
|
std::string default_segment_name() const;
|
||||||
RRSwitchId default_switch() const;
|
RRSwitchId default_tap_switch() const;
|
||||||
std::string default_switch_name() const;
|
std::string default_tap_switch_name() const;
|
||||||
|
RRSwitchId default_driver_switch() const;
|
||||||
|
std::string default_driver_switch_name() const;
|
||||||
std::string tree_name(const ClockTreeId& tree_id) const;
|
std::string tree_name(const ClockTreeId& tree_id) const;
|
||||||
|
BasicPort tree_global_port(const ClockTreeId& tree_id) const;
|
||||||
size_t tree_width(const ClockTreeId& tree_id) const;
|
size_t tree_width(const ClockTreeId& tree_id) const;
|
||||||
size_t tree_depth(const ClockTreeId& tree_id) const;
|
size_t tree_depth(const ClockTreeId& tree_id) const;
|
||||||
size_t max_tree_width() const;
|
size_t max_tree_width() const;
|
||||||
|
@ -114,15 +127,48 @@ class ClockNetwork {
|
||||||
vtr::Point<int> spine_switch_point(
|
vtr::Point<int> spine_switch_point(
|
||||||
const ClockSpineId& spine_id,
|
const ClockSpineId& spine_id,
|
||||||
const ClockSwitchPointId& switch_point_id) const;
|
const ClockSwitchPointId& switch_point_id) const;
|
||||||
|
|
||||||
|
/* Find all the switching points at a given coordinate */
|
||||||
|
std::vector<ClockSwitchPointId> find_spine_switch_points_with_coord(
|
||||||
|
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
|
||||||
|
|
||||||
|
std::vector<ClockInternalDriverId> spine_switch_point_internal_drivers(
|
||||||
|
const ClockSpineId& spine_id,
|
||||||
|
const ClockSwitchPointId& switch_point_id) const;
|
||||||
|
std::string internal_driver_port(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const;
|
||||||
|
std::vector<std::string> flatten_internal_driver_port(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const;
|
||||||
|
|
||||||
/* Return the original list of tap pins that is in storage; useful for parsers
|
/* Return the original list of tap pins that is in storage; useful for parsers
|
||||||
*/
|
*/
|
||||||
std::vector<std::string> tree_taps(const ClockTreeId& tree_id) const;
|
std::vector<ClockTapId> tree_taps(const ClockTreeId& tree_id) const;
|
||||||
|
/* Return the source ports for a given tap */
|
||||||
|
BasicPort tap_from_port(const ClockTapId& tap_id) const;
|
||||||
|
/* Return the destination ports for a given tap */
|
||||||
|
std::string tap_to_port(const ClockTapId& tap_id) const;
|
||||||
|
/* Find the type of tap point:
|
||||||
|
* all -> all coordinates in efpga are required to tap
|
||||||
|
* single -> only 1 coordinate is required to tap
|
||||||
|
* region -> coordinates in a region required to tap. Steps in region may be
|
||||||
|
* required
|
||||||
|
*/
|
||||||
|
e_tap_type tap_type(const ClockTapId& tap_id) const;
|
||||||
|
/* Require the type of single */
|
||||||
|
size_t tap_x(const ClockTapId& tap_id) const;
|
||||||
|
size_t tap_y(const ClockTapId& tap_id) const;
|
||||||
|
/* Require the type of region */
|
||||||
|
vtr::Rect<size_t> tap_bounding_box(const ClockTapId& tap_id) const;
|
||||||
|
/* Steps are only available when type is region */
|
||||||
|
size_t tap_step_x(const ClockTapId& tap_id) const;
|
||||||
|
size_t tap_step_y(const ClockTapId& tap_id) const;
|
||||||
/* Return the list of flatten tap pins. For example: clb[0:1].clk[2:2] is
|
/* Return the list of flatten tap pins. For example: clb[0:1].clk[2:2] is
|
||||||
* flatten to { clb[0].clk[2], clb[1].clk[2] } Useful to build clock routing
|
* flatten to { clb[0].clk[2], clb[1].clk[2] } Useful to build clock routing
|
||||||
* resource graph Note that the clk_pin_id limits only 1 clock to be accessed
|
* resource graph Note that the clk_pin_id limits only 1 clock to be accessed
|
||||||
*/
|
*/
|
||||||
std::vector<std::string> tree_flatten_taps(
|
std::vector<std::string> tree_flatten_tap_to_ports(
|
||||||
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const;
|
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id,
|
||||||
|
const vtr::Point<size_t>& tap_coord) const;
|
||||||
/* Find a spine with a given name, if not found, return an valid id, otherwise
|
/* Find a spine with a given name, if not found, return an valid id, otherwise
|
||||||
* return an invalid one */
|
* return an invalid one */
|
||||||
ClockSpineId find_spine(const std::string& name) const;
|
ClockSpineId find_spine(const std::string& name) const;
|
||||||
|
@ -145,12 +191,15 @@ class ClockNetwork {
|
||||||
/* Reserve a number of trees to be memory efficent */
|
/* Reserve a number of trees to be memory efficent */
|
||||||
void reserve_trees(const size_t& num_trees);
|
void reserve_trees(const size_t& num_trees);
|
||||||
void set_default_segment(const RRSegmentId& seg_id);
|
void set_default_segment(const RRSegmentId& seg_id);
|
||||||
void set_default_switch(const RRSwitchId& switch_id);
|
void set_default_tap_switch(const RRSwitchId& switch_id);
|
||||||
|
void set_default_driver_switch(const RRSwitchId& switch_id);
|
||||||
void set_default_segment_name(const std::string& name);
|
void set_default_segment_name(const std::string& name);
|
||||||
void set_default_switch_name(const std::string& name);
|
void set_default_tap_switch_name(const std::string& name);
|
||||||
|
void set_default_driver_switch_name(const std::string& name);
|
||||||
/* Create a new tree, by default the tree can accomodate only 1 clock signal;
|
/* Create a new tree, by default the tree can accomodate only 1 clock signal;
|
||||||
* use width to adjust the size */
|
* use width to adjust the size */
|
||||||
ClockTreeId create_tree(const std::string& name, size_t width = 1);
|
ClockTreeId create_tree(const std::string& name,
|
||||||
|
const BasicPort& global_port);
|
||||||
/* Create a new spine, if the spine is already created, return an invalid id
|
/* Create a new spine, if the spine is already created, return an invalid id
|
||||||
*/
|
*/
|
||||||
ClockSpineId create_spine(const std::string& name);
|
ClockSpineId create_spine(const std::string& name);
|
||||||
|
@ -168,10 +217,19 @@ class ClockNetwork {
|
||||||
void set_spine_direction(const ClockSpineId& spine_id, const Direction& dir);
|
void set_spine_direction(const ClockSpineId& spine_id, const Direction& dir);
|
||||||
void set_spine_track_type(const ClockSpineId& spine_id,
|
void set_spine_track_type(const ClockSpineId& spine_id,
|
||||||
const t_rr_type& type);
|
const t_rr_type& type);
|
||||||
void add_spine_switch_point(const ClockSpineId& spine_id,
|
ClockSwitchPointId add_spine_switch_point(const ClockSpineId& spine_id,
|
||||||
const ClockSpineId& drive_spine_id,
|
const ClockSpineId& drive_spine_id,
|
||||||
const vtr::Point<int>& coord);
|
const vtr::Point<int>& coord);
|
||||||
void add_tree_tap(const ClockTreeId& tree_id, const std::string& pin_name);
|
ClockInternalDriverId add_spine_switch_point_internal_driver(
|
||||||
|
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
|
||||||
|
const std::string& internal_driver_port);
|
||||||
|
ClockTapId add_tree_tap(const ClockTreeId& tree_id,
|
||||||
|
const BasicPort& from_port,
|
||||||
|
const std::string& to_port);
|
||||||
|
bool set_tap_bounding_box(const ClockTapId& tap_id,
|
||||||
|
const vtr::Rect<size_t>& bb);
|
||||||
|
bool set_tap_step_x(const ClockTapId& tap_id, const size_t& step);
|
||||||
|
bool set_tap_step_y(const ClockTapId& tap_id, const size_t& step);
|
||||||
/* Build internal links between clock tree, spines etc. This is also an
|
/* Build internal links between clock tree, spines etc. This is also an
|
||||||
* validator to verify the correctness of the clock network. Must run before
|
* validator to verify the correctness of the clock network. Must run before
|
||||||
* using the data! */
|
* using the data! */
|
||||||
|
@ -208,7 +266,16 @@ class ClockNetwork {
|
||||||
private: /* Public invalidators/validators */
|
private: /* Public invalidators/validators */
|
||||||
/* Ensure tree data is clean. All the spines are valid, and switch points are
|
/* Ensure tree data is clean. All the spines are valid, and switch points are
|
||||||
* valid */
|
* valid */
|
||||||
|
bool validate_tree_taps() const;
|
||||||
bool validate_tree() const;
|
bool validate_tree() const;
|
||||||
|
/* Show if the internal driver id is a valid for data queries */
|
||||||
|
bool valid_internal_driver_id(
|
||||||
|
const ClockInternalDriverId& int_driver_id) const;
|
||||||
|
/* Show if the tap id is a valid for data queries */
|
||||||
|
bool valid_tap_id(const ClockTapId& tap_id) const;
|
||||||
|
/* Check if a given coordinate matches the requirements for a tap point */
|
||||||
|
bool valid_tap_coord_in_bb(const ClockTapId& tap_id,
|
||||||
|
const vtr::Point<size_t>& tap_coord) const;
|
||||||
|
|
||||||
private: /* Private mutators */
|
private: /* Private mutators */
|
||||||
/* Build internal links between spines under a given tree */
|
/* Build internal links between spines under a given tree */
|
||||||
|
@ -226,10 +293,10 @@ class ClockNetwork {
|
||||||
/* Basic information of each tree */
|
/* Basic information of each tree */
|
||||||
vtr::vector<ClockTreeId, ClockTreeId> tree_ids_;
|
vtr::vector<ClockTreeId, ClockTreeId> tree_ids_;
|
||||||
vtr::vector<ClockTreeId, std::string> tree_names_;
|
vtr::vector<ClockTreeId, std::string> tree_names_;
|
||||||
vtr::vector<ClockTreeId, size_t> tree_widths_;
|
vtr::vector<ClockTreeId, BasicPort> tree_global_ports_;
|
||||||
vtr::vector<ClockTreeId, size_t> tree_depths_;
|
vtr::vector<ClockTreeId, size_t> tree_depths_;
|
||||||
vtr::vector<ClockTreeId, std::vector<ClockSpineId>> tree_top_spines_;
|
vtr::vector<ClockTreeId, std::vector<ClockSpineId>> tree_top_spines_;
|
||||||
vtr::vector<ClockTreeId, std::vector<std::string>> tree_taps_;
|
vtr::vector<ClockTreeId, std::vector<ClockTapId>> tree_taps_;
|
||||||
|
|
||||||
/* Basic information of each spine */
|
/* Basic information of each spine */
|
||||||
vtr::vector<ClockSpineId, ClockSpineId> spine_ids_;
|
vtr::vector<ClockSpineId, ClockSpineId> spine_ids_;
|
||||||
|
@ -241,22 +308,43 @@ class ClockNetwork {
|
||||||
vtr::vector<ClockSpineId, t_rr_type> spine_track_types_;
|
vtr::vector<ClockSpineId, t_rr_type> spine_track_types_;
|
||||||
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_switch_points_;
|
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_switch_points_;
|
||||||
vtr::vector<ClockSpineId, std::vector<vtr::Point<int>>> spine_switch_coords_;
|
vtr::vector<ClockSpineId, std::vector<vtr::Point<int>>> spine_switch_coords_;
|
||||||
|
vtr::vector<ClockSpineId, std::vector<std::vector<ClockInternalDriverId>>>
|
||||||
|
spine_switch_internal_drivers_;
|
||||||
vtr::vector<ClockSpineId, ClockSpineId> spine_parents_;
|
vtr::vector<ClockSpineId, ClockSpineId> spine_parents_;
|
||||||
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_children_;
|
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_children_;
|
||||||
vtr::vector<ClockSpineId, ClockTreeId> spine_parent_trees_;
|
vtr::vector<ClockSpineId, ClockTreeId> spine_parent_trees_;
|
||||||
|
|
||||||
|
/* Basic Information about internal drivers */
|
||||||
|
vtr::vector<ClockInternalDriverId, ClockInternalDriverId>
|
||||||
|
internal_driver_ids_;
|
||||||
|
vtr::vector<ClockInternalDriverId, std::string> internal_driver_ports_;
|
||||||
|
/* Basic information about tap */
|
||||||
|
vtr::vector<ClockTapId, ClockTapId> tap_ids_;
|
||||||
|
vtr::vector<ClockTapId, BasicPort> tap_from_ports_;
|
||||||
|
vtr::vector<ClockTapId, std::string> tap_to_ports_;
|
||||||
|
vtr::vector<ClockTapId, vtr::Rect<size_t>>
|
||||||
|
tap_bbs_; /* Bounding box for tap points, (xlow, ylow) -> (xhigh, yhigh) */
|
||||||
|
vtr::vector<ClockTapId, vtr::Point<size_t>>
|
||||||
|
tap_bb_steps_; /* x() -> x-direction step, y() -> y-direction step */
|
||||||
|
|
||||||
/* Default routing resource */
|
/* Default routing resource */
|
||||||
std::string default_segment_name_; /* The routing segment representing the
|
std::string default_segment_name_; /* The routing segment representing the
|
||||||
clock wires */
|
clock wires */
|
||||||
RRSegmentId default_segment_id_;
|
RRSegmentId default_segment_id_;
|
||||||
std::string
|
std::string default_tap_switch_name_; /* The routing switch interconnecting
|
||||||
default_switch_name_; /* The routing switch interconnecting clock wire */
|
clock wire */
|
||||||
RRSwitchId default_switch_id_;
|
RRSwitchId default_tap_switch_id_;
|
||||||
|
std::string default_driver_switch_name_; /* The routing switch interconnecting
|
||||||
|
clock wire */
|
||||||
|
RRSwitchId default_driver_switch_id_;
|
||||||
|
|
||||||
/* Fast lookup */
|
/* Fast lookup */
|
||||||
std::map<std::string, ClockTreeId> tree_name2id_map_;
|
std::map<std::string, ClockTreeId> tree_name2id_map_;
|
||||||
std::map<std::string, ClockSpineId> spine_name2id_map_;
|
std::map<std::string, ClockSpineId> spine_name2id_map_;
|
||||||
|
|
||||||
|
/* Constants */
|
||||||
|
vtr::Rect<size_t> empty_tap_bb_;
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
mutable bool is_dirty_;
|
mutable bool is_dirty_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,12 +19,16 @@ struct clock_tree_id_tag;
|
||||||
struct clock_tree_pin_id_tag;
|
struct clock_tree_pin_id_tag;
|
||||||
struct clock_spine_id_tag;
|
struct clock_spine_id_tag;
|
||||||
struct clock_switch_point_id_tag;
|
struct clock_switch_point_id_tag;
|
||||||
|
struct clock_internal_driver_id_tag;
|
||||||
|
struct clock_tap_id_tag;
|
||||||
|
|
||||||
typedef vtr::StrongId<clock_level_id_tag> ClockLevelId;
|
typedef vtr::StrongId<clock_level_id_tag> ClockLevelId;
|
||||||
typedef vtr::StrongId<clock_tree_id_tag> ClockTreeId;
|
typedef vtr::StrongId<clock_tree_id_tag> ClockTreeId;
|
||||||
typedef vtr::StrongId<clock_tree_pin_id_tag> ClockTreePinId;
|
typedef vtr::StrongId<clock_tree_pin_id_tag> ClockTreePinId;
|
||||||
typedef vtr::StrongId<clock_spine_id_tag> ClockSpineId;
|
typedef vtr::StrongId<clock_spine_id_tag> ClockSpineId;
|
||||||
typedef vtr::StrongId<clock_switch_point_id_tag> ClockSwitchPointId;
|
typedef vtr::StrongId<clock_switch_point_id_tag> ClockSwitchPointId;
|
||||||
|
typedef vtr::StrongId<clock_internal_driver_id_tag> ClockInternalDriverId;
|
||||||
|
typedef vtr::StrongId<clock_tap_id_tag> ClockTapId;
|
||||||
|
|
||||||
/* Short declaration of class */
|
/* Short declaration of class */
|
||||||
class ClockNetwork;
|
class ClockNetwork;
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
constexpr const char* XML_CLOCK_NETWORK_ROOT_NAME = "clock_networks";
|
constexpr const char* XML_CLOCK_NETWORK_ROOT_NAME = "clock_networks";
|
||||||
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT =
|
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT =
|
||||||
"default_segment";
|
"default_segment";
|
||||||
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH =
|
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH =
|
||||||
"default_switch";
|
"default_tap_switch";
|
||||||
|
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH =
|
||||||
|
"default_driver_switch";
|
||||||
constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network";
|
constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network";
|
||||||
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name";
|
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name";
|
||||||
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_WIDTH = "width";
|
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT = "global_port";
|
||||||
constexpr const char* XML_CLOCK_SPINE_NODE_NAME = "spine";
|
constexpr const char* XML_CLOCK_SPINE_NODE_NAME = "spine";
|
||||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_NAME = "name";
|
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_NAME = "name";
|
||||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_X = "start_x";
|
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_X = "start_x";
|
||||||
|
@ -20,11 +22,26 @@ constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_Y = "end_y";
|
||||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type";
|
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type";
|
||||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction";
|
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction";
|
||||||
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME = "switch_point";
|
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME = "switch_point";
|
||||||
|
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME =
|
||||||
|
"internal_driver";
|
||||||
|
constexpr const char*
|
||||||
|
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN = "tile_pin";
|
||||||
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP = "tap";
|
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP = "tap";
|
||||||
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X = "x";
|
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X = "x";
|
||||||
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y = "y";
|
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y = "y";
|
||||||
constexpr const char* XML_CLOCK_TREE_TAPS_NODE_NAME = "taps";
|
constexpr const char* XML_CLOCK_TREE_TAPS_NODE_NAME = "taps";
|
||||||
constexpr const char* XML_CLOCK_TREE_TAP_NODE_NAME = "tap";
|
constexpr const char* XML_CLOCK_TREE_TAP_ALL_NODE_NAME = "all";
|
||||||
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN = "tile_pin";
|
constexpr const char* XML_CLOCK_TREE_TAP_REGION_NODE_NAME = "region";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME = "single";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN = "from_pin";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN = "to_pin";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_X = "x";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_Y = "y";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX = "start_x";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY = "start_y";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX = "end_x";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY = "end_y";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX = "repeat_x";
|
||||||
|
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY = "repeat_y";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,21 +25,107 @@
|
||||||
namespace openfpga { // Begin namespace openfpga
|
namespace openfpga { // Begin namespace openfpga
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Parse XML codes of a <tap> to an object of ClockNetwork
|
* Parse XML codes of a <all> to an object of ClockNetwork
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static void read_xml_clock_tree_tap(pugi::xml_node& xml_tap,
|
static void read_xml_clock_tree_tap_type_all(pugi::xml_node& xml_tap,
|
||||||
const pugiutil::loc_data& loc_data,
|
const pugiutil::loc_data& loc_data,
|
||||||
ClockNetwork& clk_ntwk,
|
ClockNetwork& clk_ntwk,
|
||||||
const ClockTreeId& tree_id) {
|
const ClockTreeId& tree_id) {
|
||||||
if (!clk_ntwk.valid_tree_id(tree_id)) {
|
if (!clk_ntwk.valid_tree_id(tree_id)) {
|
||||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
|
||||||
"Invalid id of a clock tree!\n");
|
"Invalid id of a clock tree!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tile_pin_name =
|
std::string from_pin_name =
|
||||||
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN, loc_data)
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
|
||||||
.as_string();
|
.as_string();
|
||||||
clk_ntwk.add_tree_tap(tree_id, tile_pin_name);
|
std::string to_pin_name =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
PortParser from_port_parser(from_pin_name);
|
||||||
|
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Parse XML codes of a <single> to an object of ClockNetwork
|
||||||
|
*******************************************************************/
|
||||||
|
static void read_xml_clock_tree_tap_type_single(
|
||||||
|
pugi::xml_node& xml_tap, const pugiutil::loc_data& loc_data,
|
||||||
|
ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) {
|
||||||
|
if (!clk_ntwk.valid_tree_id(tree_id)) {
|
||||||
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
|
||||||
|
"Invalid id of a clock tree!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string from_pin_name =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
std::string to_pin_name =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
PortParser from_port_parser(from_pin_name);
|
||||||
|
ClockTapId tap_id =
|
||||||
|
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
|
||||||
|
|
||||||
|
/* Single tap only require a coordinate */
|
||||||
|
size_t tap_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X,
|
||||||
|
loc_data, pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
size_t tap_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y,
|
||||||
|
loc_data, pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
clk_ntwk.set_tap_bounding_box(tap_id,
|
||||||
|
vtr::Rect<size_t>(tap_x, tap_y, tap_x, tap_y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Parse XML codes of a <region> to an object of ClockNetwork
|
||||||
|
*******************************************************************/
|
||||||
|
static void read_xml_clock_tree_tap_type_region(
|
||||||
|
pugi::xml_node& xml_tap, const pugiutil::loc_data& loc_data,
|
||||||
|
ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) {
|
||||||
|
if (!clk_ntwk.valid_tree_id(tree_id)) {
|
||||||
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
|
||||||
|
"Invalid id of a clock tree!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string from_pin_name =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
std::string to_pin_name =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
PortParser from_port_parser(from_pin_name);
|
||||||
|
ClockTapId tap_id =
|
||||||
|
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
|
||||||
|
|
||||||
|
/* Region require a bounding box */
|
||||||
|
size_t tap_start_x =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, loc_data,
|
||||||
|
pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
size_t tap_start_y =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data,
|
||||||
|
pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
size_t tap_end_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX,
|
||||||
|
loc_data, pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
size_t tap_end_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY,
|
||||||
|
loc_data, pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_int();
|
||||||
|
clk_ntwk.set_tap_bounding_box(
|
||||||
|
tap_id, vtr::Rect<size_t>(tap_start_x, tap_start_y, tap_end_x, tap_end_y));
|
||||||
|
|
||||||
|
/* Default step is all 1 */
|
||||||
|
size_t tap_step_x =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX, loc_data)
|
||||||
|
.as_int(1);
|
||||||
|
size_t tap_step_y =
|
||||||
|
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY, loc_data)
|
||||||
|
.as_int(1);
|
||||||
|
clk_ntwk.set_tap_step_x(tap_id, tap_step_x);
|
||||||
|
clk_ntwk.set_tap_step_y(tap_id, tap_step_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps,
|
static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps,
|
||||||
|
@ -48,14 +134,44 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps,
|
||||||
const ClockTreeId& tree_id) {
|
const ClockTreeId& tree_id) {
|
||||||
for (pugi::xml_node xml_tap : xml_taps.children()) {
|
for (pugi::xml_node xml_tap : xml_taps.children()) {
|
||||||
/* Error out if the XML child has an invalid name! */
|
/* Error out if the XML child has an invalid name! */
|
||||||
if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_NODE_NAME)) {
|
if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_ALL_NODE_NAME)) {
|
||||||
read_xml_clock_tree_tap(xml_tap, loc_data, clk_ntwk, tree_id);
|
read_xml_clock_tree_tap_type_all(xml_tap, loc_data, clk_ntwk, tree_id);
|
||||||
|
} else if (xml_tap.name() ==
|
||||||
|
std::string(XML_CLOCK_TREE_TAP_REGION_NODE_NAME)) {
|
||||||
|
read_xml_clock_tree_tap_type_region(xml_tap, loc_data, clk_ntwk, tree_id);
|
||||||
|
} else if (xml_tap.name() ==
|
||||||
|
std::string(XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME)) {
|
||||||
|
read_xml_clock_tree_tap_type_single(xml_tap, loc_data, clk_ntwk, tree_id);
|
||||||
} else {
|
} else {
|
||||||
bad_tag(xml_taps, loc_data, xml_tap, {XML_CLOCK_TREE_TAP_NODE_NAME});
|
bad_tag(
|
||||||
|
xml_taps, loc_data, xml_tap,
|
||||||
|
{XML_CLOCK_TREE_TAP_ALL_NODE_NAME, XML_CLOCK_TREE_TAP_REGION_NODE_NAME,
|
||||||
|
XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Parse XML codes of a <switch_point> to an object of ClockNetwork
|
||||||
|
*******************************************************************/
|
||||||
|
static void read_xml_clock_spine_switch_point_internal_driver(
|
||||||
|
pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data,
|
||||||
|
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
|
||||||
|
const ClockSwitchPointId& switch_point_id) {
|
||||||
|
if (!clk_ntwk.valid_spine_id(spine_id)) {
|
||||||
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_int_driver),
|
||||||
|
"Invalid id of a clock spine!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string int_driver_port_name =
|
||||||
|
get_attribute(
|
||||||
|
xml_int_driver,
|
||||||
|
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, loc_data)
|
||||||
|
.as_string();
|
||||||
|
clk_ntwk.add_spine_switch_point_internal_driver(spine_id, switch_point_id,
|
||||||
|
int_driver_port_name);
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Parse XML codes of a <switch_point> to an object of ClockNetwork
|
* Parse XML codes of a <switch_point> to an object of ClockNetwork
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
@ -90,8 +206,21 @@ static void read_xml_clock_spine_switch_point(
|
||||||
XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data)
|
XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data)
|
||||||
.as_int();
|
.as_int();
|
||||||
|
|
||||||
clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id,
|
ClockSwitchPointId switch_point_id = clk_ntwk.add_spine_switch_point(
|
||||||
vtr::Point<int>(tap_x, tap_y));
|
spine_id, tap_spine_id, vtr::Point<int>(tap_x, tap_y));
|
||||||
|
|
||||||
|
/* Add internal drivers if possible */
|
||||||
|
for (pugi::xml_node xml_int_driver : xml_switch_point.children()) {
|
||||||
|
/* Error out if the XML child has an invalid name! */
|
||||||
|
if (xml_int_driver.name() ==
|
||||||
|
std::string(XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME)) {
|
||||||
|
read_xml_clock_spine_switch_point_internal_driver(
|
||||||
|
xml_int_driver, loc_data, clk_ntwk, spine_id, switch_point_id);
|
||||||
|
} else {
|
||||||
|
bad_tag(xml_int_driver, loc_data, xml_switch_point,
|
||||||
|
{XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -212,14 +341,18 @@ static void read_xml_clock_tree(pugi::xml_node& xml_clk_tree,
|
||||||
const pugiutil::loc_data& loc_data,
|
const pugiutil::loc_data& loc_data,
|
||||||
ClockNetwork& clk_ntwk) {
|
ClockNetwork& clk_ntwk) {
|
||||||
std::string clk_tree_name =
|
std::string clk_tree_name =
|
||||||
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data)
|
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data,
|
||||||
|
pugiutil::ReqOpt::REQUIRED)
|
||||||
|
.as_string();
|
||||||
|
std::string clk_global_port_str =
|
||||||
|
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, loc_data,
|
||||||
|
pugiutil::ReqOpt::REQUIRED)
|
||||||
.as_string();
|
.as_string();
|
||||||
int clk_tree_width =
|
|
||||||
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_WIDTH, loc_data)
|
|
||||||
.as_int();
|
|
||||||
|
|
||||||
/* Create a new tree in the storage */
|
/* Create a new tree in the storage */
|
||||||
ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, clk_tree_width);
|
PortParser gport_parser(clk_global_port_str);
|
||||||
|
ClockTreeId tree_id =
|
||||||
|
clk_ntwk.create_tree(clk_tree_name, gport_parser.port());
|
||||||
|
|
||||||
if (false == clk_ntwk.valid_tree_id(tree_id)) {
|
if (false == clk_ntwk.valid_tree_id(tree_id)) {
|
||||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree),
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree),
|
||||||
|
@ -263,11 +396,17 @@ ClockNetwork read_xml_clock_network(const char* fname) {
|
||||||
.as_string();
|
.as_string();
|
||||||
clk_ntwk.set_default_segment_name(default_segment_name);
|
clk_ntwk.set_default_segment_name(default_segment_name);
|
||||||
|
|
||||||
std::string default_switch_name =
|
std::string default_tap_switch_name =
|
||||||
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH,
|
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH,
|
||||||
loc_data)
|
loc_data)
|
||||||
.as_string();
|
.as_string();
|
||||||
clk_ntwk.set_default_switch_name(default_switch_name);
|
clk_ntwk.set_default_tap_switch_name(default_tap_switch_name);
|
||||||
|
|
||||||
|
std::string default_driver_switch_name =
|
||||||
|
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH,
|
||||||
|
loc_data)
|
||||||
|
.as_string();
|
||||||
|
clk_ntwk.set_default_driver_switch_name(default_driver_switch_name);
|
||||||
|
|
||||||
size_t num_trees =
|
size_t num_trees =
|
||||||
std::distance(xml_root.children().begin(), xml_root.children().end());
|
std::distance(xml_root.children().begin(), xml_root.children().end());
|
||||||
|
|
|
@ -28,14 +28,66 @@ static int write_xml_clock_tree_taps(std::fstream& fp,
|
||||||
const ClockTreeId& tree_id) {
|
const ClockTreeId& tree_id) {
|
||||||
openfpga::write_tab_to_file(fp, 3);
|
openfpga::write_tab_to_file(fp, 3);
|
||||||
fp << "<" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n";
|
fp << "<" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n";
|
||||||
for (const std::string& tile_pin_name : clk_ntwk.tree_taps(tree_id)) {
|
/* Depends on the type */
|
||||||
openfpga::write_tab_to_file(fp, 4);
|
for (ClockTapId tap_id : clk_ntwk.tree_taps(tree_id)) {
|
||||||
fp << "<" << XML_CLOCK_TREE_TAP_NODE_NAME << "";
|
switch (clk_ntwk.tap_type(tap_id)) {
|
||||||
|
case ClockNetwork::e_tap_type::ALL: {
|
||||||
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN,
|
openfpga::write_tab_to_file(fp, 4);
|
||||||
tile_pin_name.c_str());
|
fp << "<" << XML_CLOCK_TREE_TAP_ALL_NODE_NAME << "";
|
||||||
fp << "/>"
|
write_xml_attribute(
|
||||||
<< "\n";
|
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
|
||||||
|
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
|
||||||
|
clk_ntwk.tap_to_port(tap_id).c_str());
|
||||||
|
fp << "/>"
|
||||||
|
<< "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ClockNetwork::e_tap_type::SINGLE: {
|
||||||
|
openfpga::write_tab_to_file(fp, 4);
|
||||||
|
fp << "<" << XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME << "";
|
||||||
|
write_xml_attribute(
|
||||||
|
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
|
||||||
|
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
|
||||||
|
clk_ntwk.tap_to_port(tap_id).c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_X,
|
||||||
|
clk_ntwk.tap_x(tap_id));
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y,
|
||||||
|
clk_ntwk.tap_y(tap_id));
|
||||||
|
fp << "/>"
|
||||||
|
<< "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ClockNetwork::e_tap_type::REGION: {
|
||||||
|
openfpga::write_tab_to_file(fp, 4);
|
||||||
|
fp << "<" << XML_CLOCK_TREE_TAP_REGION_NODE_NAME << "";
|
||||||
|
write_xml_attribute(
|
||||||
|
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
|
||||||
|
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
|
||||||
|
clk_ntwk.tap_to_port(tap_id).c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX,
|
||||||
|
clk_ntwk.tap_bounding_box(tap_id).xmin());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY,
|
||||||
|
clk_ntwk.tap_bounding_box(tap_id).ymin());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX,
|
||||||
|
clk_ntwk.tap_bounding_box(tap_id).xmax());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY,
|
||||||
|
clk_ntwk.tap_bounding_box(tap_id).ymax());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX,
|
||||||
|
clk_ntwk.tap_step_x(tap_id));
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY,
|
||||||
|
clk_ntwk.tap_step_y(tap_id));
|
||||||
|
fp << "/>"
|
||||||
|
<< "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
VTR_LOG_ERROR("Invalid type of tap point!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openfpga::write_tab_to_file(fp, 3);
|
openfpga::write_tab_to_file(fp, 3);
|
||||||
|
@ -60,8 +112,27 @@ static int write_xml_clock_spine_switch_point(
|
||||||
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X, coord.x());
|
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X, coord.x());
|
||||||
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, coord.y());
|
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, coord.y());
|
||||||
|
|
||||||
fp << "/>"
|
/* Optional: internal drivers */
|
||||||
<< "\n";
|
if (clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id)
|
||||||
|
.empty()) {
|
||||||
|
fp << "/>"
|
||||||
|
<< "\n";
|
||||||
|
} else {
|
||||||
|
fp << ">"
|
||||||
|
<< "\n";
|
||||||
|
for (ClockInternalDriverId int_driver_id :
|
||||||
|
clk_ntwk.spine_switch_point_internal_drivers(spine_id,
|
||||||
|
switch_point_id)) {
|
||||||
|
openfpga::write_tab_to_file(fp, 4);
|
||||||
|
fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME;
|
||||||
|
write_xml_attribute(
|
||||||
|
fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN,
|
||||||
|
clk_ntwk.internal_driver_port(int_driver_id).c_str());
|
||||||
|
fp << "/>"
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
fp << "</" << XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME << ">\n";
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +197,9 @@ static int write_xml_clock_tree(std::fstream& fp, const ClockNetwork& clk_ntwk,
|
||||||
|
|
||||||
write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_NAME,
|
write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_NAME,
|
||||||
clk_ntwk.tree_name(tree_id).c_str());
|
clk_ntwk.tree_name(tree_id).c_str());
|
||||||
write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_WIDTH,
|
write_xml_attribute(
|
||||||
clk_ntwk.tree_width(tree_id));
|
fp, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT,
|
||||||
|
clk_ntwk.tree_global_port(tree_id).to_verilog_string().c_str());
|
||||||
fp << ">"
|
fp << ">"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
|
@ -168,8 +240,10 @@ int write_xml_clock_network(const char* fname, const ClockNetwork& clk_ntwk) {
|
||||||
fp << "<" << XML_CLOCK_NETWORK_ROOT_NAME;
|
fp << "<" << XML_CLOCK_NETWORK_ROOT_NAME;
|
||||||
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT,
|
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT,
|
||||||
clk_ntwk.default_segment_name().c_str());
|
clk_ntwk.default_segment_name().c_str());
|
||||||
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH,
|
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH,
|
||||||
clk_ntwk.default_switch_name().c_str());
|
clk_ntwk.default_tap_switch_name().c_str());
|
||||||
|
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH,
|
||||||
|
clk_ntwk.default_driver_switch_name().c_str());
|
||||||
fp << ">"
|
fp << ">"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,10 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk,
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Unable to find the default segement '%s' in VPR architecture "
|
||||||
|
"description!\n",
|
||||||
|
default_segment_name.c_str());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,19 +33,46 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk,
|
||||||
* Link all the switches that are defined in a routing resource graph to a given
|
* Link all the switches that are defined in a routing resource graph to a given
|
||||||
*clock network
|
*clock network
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk,
|
static int link_clock_network_tap_rr_switches(ClockNetwork& clk_ntwk,
|
||||||
const RRGraphView& rr_graph) {
|
const RRGraphView& rr_graph) {
|
||||||
/* default switch id */
|
/* default tap switch id */
|
||||||
std::string default_switch_name = clk_ntwk.default_switch_name();
|
std::string default_tap_switch_name = clk_ntwk.default_tap_switch_name();
|
||||||
for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches();
|
for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches();
|
||||||
++rr_switch_id) {
|
++rr_switch_id) {
|
||||||
if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) ==
|
if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) ==
|
||||||
default_switch_name) {
|
default_tap_switch_name) {
|
||||||
clk_ntwk.set_default_switch(RRSwitchId(rr_switch_id));
|
clk_ntwk.set_default_tap_switch(RRSwitchId(rr_switch_id));
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Unable to find the default tap switch '%s' in VPR architecture "
|
||||||
|
"description!\n",
|
||||||
|
default_tap_switch_name.c_str());
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Link all the switches that are defined in a routing resource graph to a given
|
||||||
|
*clock network
|
||||||
|
*******************************************************************/
|
||||||
|
static int link_clock_network_driver_rr_switches(ClockNetwork& clk_ntwk,
|
||||||
|
const RRGraphView& rr_graph) {
|
||||||
|
/* default driver switch id */
|
||||||
|
std::string default_driver_switch_name =
|
||||||
|
clk_ntwk.default_driver_switch_name();
|
||||||
|
for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches();
|
||||||
|
++rr_switch_id) {
|
||||||
|
if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) ==
|
||||||
|
default_driver_switch_name) {
|
||||||
|
clk_ntwk.set_default_driver_switch(RRSwitchId(rr_switch_id));
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Unable to find the default driver switch '%s' in VPR architecture "
|
||||||
|
"description!\n",
|
||||||
|
default_driver_switch_name.c_str());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +84,11 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
|
||||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
status = link_clock_network_rr_switches(clk_ntwk, rr_graph);
|
status = link_clock_network_tap_rr_switches(clk_ntwk, rr_graph);
|
||||||
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = link_clock_network_driver_rr_switches(clk_ntwk, rr_graph);
|
||||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -62,4 +96,39 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check for each global ports in tile annotation
|
||||||
|
* If a clock tree is required for a global port, the global port name define
|
||||||
|
* in the tile annotation should match the one in clock clock
|
||||||
|
*/
|
||||||
|
int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk,
|
||||||
|
const TileAnnotation& tile_annotation) {
|
||||||
|
for (const TileGlobalPortId& gport_id : tile_annotation.global_ports()) {
|
||||||
|
if (!tile_annotation.global_port_thru_dedicated_network(gport_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string gport_name = tile_annotation.global_port_name(gport_id);
|
||||||
|
std::string clk_tree_name =
|
||||||
|
tile_annotation.global_port_clock_arch_tree_name(gport_id);
|
||||||
|
ClockTreeId clk_tree_id = clk_ntwk.find_tree(clk_tree_name);
|
||||||
|
if (!clk_ntwk.valid_tree_id(clk_tree_id)) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Invalid clock tree name '%s' defined for global port '%s' in tile "
|
||||||
|
"annotation! Must be a valid name defined in the clock network "
|
||||||
|
"description!\n",
|
||||||
|
clk_tree_name.c_str(), gport_name.c_str());
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
if (clk_ntwk.tree_global_port(clk_tree_id).get_name() != gport_name) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Global port '%s' of clock tree name '%s' must match the name of "
|
||||||
|
"assoicated global port '%s' in tile annotation! Must be a valid name "
|
||||||
|
"defined in the clock network description!\n",
|
||||||
|
clk_ntwk.tree_global_port(clk_tree_id).to_verilog_string().c_str(),
|
||||||
|
clk_tree_name.c_str(), gport_name.c_str());
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace openfpga
|
} // End of namespace openfpga
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
#include "clock_network.h"
|
#include "clock_network.h"
|
||||||
#include "rr_graph_view.h"
|
#include "rr_graph_view.h"
|
||||||
|
#include "tile_annotation.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -16,6 +17,9 @@ namespace openfpga { // Begin namespace openfpga
|
||||||
int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
|
int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
|
||||||
const RRGraphView& rr_graph);
|
const RRGraphView& rr_graph);
|
||||||
|
|
||||||
|
int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk,
|
||||||
|
const TileAnnotation& tile_annotation);
|
||||||
|
|
||||||
} // End of namespace openfpga
|
} // End of namespace openfpga
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,6 +22,10 @@ int main(int argc, const char** argv) {
|
||||||
|
|
||||||
/* Validate before write out */
|
/* Validate before write out */
|
||||||
if (!clk_ntwk.link()) {
|
if (!clk_ntwk.link()) {
|
||||||
|
VTR_LOG_ERROR("Invalid clock network when linking.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!clk_ntwk.validate()) {
|
||||||
VTR_LOG_ERROR("Invalid clock network.\n");
|
VTR_LOG_ERROR("Invalid clock network.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,7 @@ static void try_find_and_add_clock_track2ipin_node(
|
||||||
t_physical_tile_type_ptr grid_type = grids.get_physical_type(
|
t_physical_tile_type_ptr grid_type = grids.get_physical_type(
|
||||||
t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer));
|
t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer));
|
||||||
for (std::string tap_pin_name :
|
for (std::string tap_pin_name :
|
||||||
clk_ntwk.tree_flatten_taps(clk_tree, clk_pin)) {
|
clk_ntwk.tree_flatten_tap_to_ports(clk_tree, clk_pin, grid_coord)) {
|
||||||
/* tap pin name could be 'io[5:5].a2f[0]' */
|
/* tap pin name could be 'io[5:5].a2f[0]' */
|
||||||
int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name);
|
int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name);
|
||||||
if (grid_pin_idx == grid_type->num_pins) {
|
if (grid_pin_idx == grid_type->num_pins) {
|
||||||
|
@ -525,8 +525,8 @@ static void add_rr_graph_block_clock_edges(
|
||||||
chan_coord, itree, ilvl, ClockTreePinId(ipin), node_dir)) {
|
chan_coord, itree, ilvl, ClockTreePinId(ipin), node_dir)) {
|
||||||
/* Create edges */
|
/* Create edges */
|
||||||
VTR_ASSERT(rr_graph_view.valid_node(des_node));
|
VTR_ASSERT(rr_graph_view.valid_node(des_node));
|
||||||
rr_graph_builder.create_edge(src_node, des_node,
|
rr_graph_builder.create_edge(
|
||||||
clk_ntwk.default_switch(), false);
|
src_node, des_node, clk_ntwk.default_driver_switch(), false);
|
||||||
edge_count++;
|
edge_count++;
|
||||||
}
|
}
|
||||||
VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n",
|
VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n",
|
||||||
|
@ -541,11 +541,11 @@ static void add_rr_graph_block_clock_edges(
|
||||||
itree, ClockTreePinId(ipin))) {
|
itree, ClockTreePinId(ipin))) {
|
||||||
/* Create edges */
|
/* Create edges */
|
||||||
VTR_ASSERT(rr_graph_view.valid_node(des_node));
|
VTR_ASSERT(rr_graph_view.valid_node(des_node));
|
||||||
rr_graph_builder.create_edge(src_node, des_node,
|
rr_graph_builder.create_edge(
|
||||||
clk_ntwk.default_switch(), false);
|
src_node, des_node, clk_ntwk.default_tap_switch(), false);
|
||||||
edge_count++;
|
edge_count++;
|
||||||
}
|
}
|
||||||
VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n",
|
VTR_LOGV(verbose, "\tWill add %lu edges to IPINs\n",
|
||||||
edge_count - curr_edge_count);
|
edge_count - curr_edge_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,6 +557,154 @@ static void add_rr_graph_block_clock_edges(
|
||||||
num_edges_to_create += edge_count;
|
num_edges_to_create += edge_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Try to find an OPIN of a grid which satisfy the requirement of clock pins
|
||||||
|
* that has been defined in clock network. If the OPIN does exist in a
|
||||||
|
* routing resource graph, add it to the node list
|
||||||
|
*******************************************************************/
|
||||||
|
static void try_find_and_add_clock_opin2track_node(
|
||||||
|
std::vector<RRNodeId>& opin_nodes, const DeviceGrid& grids,
|
||||||
|
const RRGraphView& rr_graph_view, const size_t& layer,
|
||||||
|
const vtr::Point<int>& grid_coord, const e_side& pin_side,
|
||||||
|
const ClockNetwork& clk_ntwk, const ClockInternalDriverId& int_driver_id) {
|
||||||
|
t_physical_tile_type_ptr grid_type = grids.get_physical_type(
|
||||||
|
t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer));
|
||||||
|
for (std::string tap_pin_name :
|
||||||
|
clk_ntwk.flatten_internal_driver_port(int_driver_id)) {
|
||||||
|
/* tap pin name could be 'io[5:5].a2f[0]' */
|
||||||
|
int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name);
|
||||||
|
if (grid_pin_idx == grid_type->num_pins) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RRNodeId opin_node = rr_graph_view.node_lookup().find_node(
|
||||||
|
layer, grid_coord.x(), grid_coord.y(), OPIN, grid_pin_idx, pin_side);
|
||||||
|
if (rr_graph_view.valid_node(opin_node)) {
|
||||||
|
opin_nodes.push_back(opin_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Find the source OPIN nodes as internal drivers for a clock node
|
||||||
|
* For example
|
||||||
|
* clk0_lvl1_chany[1][1]
|
||||||
|
* ^
|
||||||
|
* |
|
||||||
|
* internal_driver OPIN[0] -->-------+
|
||||||
|
* ^
|
||||||
|
* |
|
||||||
|
* internal_driver OPIN[1]
|
||||||
|
*
|
||||||
|
* Coordinate system:
|
||||||
|
*
|
||||||
|
* +----------+----------+------------+
|
||||||
|
* | Grid | CBy | Grid |
|
||||||
|
* | [x][y+1] | [x][y+1] | [x+1][y+1] |
|
||||||
|
* +----------+----------+------------+
|
||||||
|
* | CBx | SB | CBx |
|
||||||
|
* | [x][y] | [x][y] | [x+1][y] |
|
||||||
|
* +----------+----------+------------+
|
||||||
|
* | Grid | CBy | Grid |
|
||||||
|
* | [x][y] | [x][y] | [x+1][y] |
|
||||||
|
* +----------+----------+------------+
|
||||||
|
*******************************************************************/
|
||||||
|
static std::vector<RRNodeId> find_clock_opin2track_node(
|
||||||
|
const DeviceGrid& grids, const RRGraphView& rr_graph_view,
|
||||||
|
const size_t& layer, const vtr::Point<int>& sb_coord,
|
||||||
|
const ClockNetwork& clk_ntwk,
|
||||||
|
const std::vector<ClockInternalDriverId>& int_driver_ids) {
|
||||||
|
std::vector<RRNodeId> opin_nodes;
|
||||||
|
/* Find opins from
|
||||||
|
* - Grid[x][y+1] on right and bottom sides
|
||||||
|
* - Grid[x+1][y+1] on left and bottom sides
|
||||||
|
* - Grid[x][y] on right and top sides
|
||||||
|
* - Grid[x+1][y] on left and top sides
|
||||||
|
*/
|
||||||
|
std::array<vtr::Point<int>, 4> grid_coords;
|
||||||
|
std::array<std::array<e_side, 2>, 4> grid_sides;
|
||||||
|
grid_coords[0] = vtr::Point<int>(sb_coord.x(), sb_coord.y() + 1);
|
||||||
|
grid_sides[0] = {RIGHT, BOTTOM};
|
||||||
|
grid_coords[1] = vtr::Point<int>(sb_coord.x() + 1, sb_coord.y() + 1);
|
||||||
|
grid_sides[1] = {LEFT, BOTTOM};
|
||||||
|
grid_coords[2] = vtr::Point<int>(sb_coord.x(), sb_coord.y());
|
||||||
|
grid_sides[2] = {RIGHT, TOP};
|
||||||
|
grid_coords[3] = vtr::Point<int>(sb_coord.x() + 1, sb_coord.y());
|
||||||
|
grid_sides[3] = {LEFT, TOP};
|
||||||
|
for (size_t igrid = 0; igrid < 4; igrid++) {
|
||||||
|
vtr::Point<int> grid_coord = grid_coords[igrid];
|
||||||
|
for (e_side grid_side : grid_sides[igrid]) {
|
||||||
|
for (ClockInternalDriverId int_driver_id : int_driver_ids) {
|
||||||
|
try_find_and_add_clock_opin2track_node(opin_nodes, grids, rr_graph_view,
|
||||||
|
layer, grid_coord, grid_side,
|
||||||
|
clk_ntwk, int_driver_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opin_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add edges between OPIN of programmable blocks and clock routing tracks
|
||||||
|
* Note that such edges only occur at the switching points of spines
|
||||||
|
* Different from add_rr_graph_block_clock_edges(), we follow the clock spines
|
||||||
|
*here By expanding on switching points, internal drivers will be added
|
||||||
|
*******************************************************************/
|
||||||
|
static int add_rr_graph_opin2clk_edges(
|
||||||
|
RRGraphBuilder& rr_graph_builder, size_t& num_edges_to_create,
|
||||||
|
const RRClockSpatialLookup& clk_rr_lookup, const RRGraphView& rr_graph_view,
|
||||||
|
const DeviceGrid& grids, const size_t& layer, const ClockNetwork& clk_ntwk,
|
||||||
|
const bool& verbose) {
|
||||||
|
size_t edge_count = 0;
|
||||||
|
for (ClockTreeId clk_tree : clk_ntwk.trees()) {
|
||||||
|
for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) {
|
||||||
|
VTR_LOGV(verbose, "Finding internal drivers on spine '%s'...\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
for (auto ipin : clk_ntwk.pins(clk_tree)) {
|
||||||
|
for (ClockSwitchPointId switch_point_id :
|
||||||
|
clk_ntwk.spine_switch_points(ispine)) {
|
||||||
|
if (clk_ntwk
|
||||||
|
.spine_switch_point_internal_drivers(ispine, switch_point_id)
|
||||||
|
.empty()) {
|
||||||
|
continue; /* We only focus on switching points containing internal
|
||||||
|
drivers */
|
||||||
|
}
|
||||||
|
size_t curr_edge_count = edge_count;
|
||||||
|
/* Get the rr node of destination spine */
|
||||||
|
ClockSpineId des_spine =
|
||||||
|
clk_ntwk.spine_switch_point_tap(ispine, switch_point_id);
|
||||||
|
vtr::Point<int> des_coord = clk_ntwk.spine_start_point(des_spine);
|
||||||
|
Direction des_spine_direction = clk_ntwk.spine_direction(des_spine);
|
||||||
|
ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine);
|
||||||
|
RRNodeId des_node =
|
||||||
|
clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree,
|
||||||
|
des_spine_level, ipin, des_spine_direction);
|
||||||
|
/* Walk through each qualified OPIN, build edges */
|
||||||
|
vtr::Point<int> src_coord =
|
||||||
|
clk_ntwk.spine_switch_point(ispine, switch_point_id);
|
||||||
|
std::vector<ClockInternalDriverId> int_driver_ids =
|
||||||
|
clk_ntwk.spine_switch_point_internal_drivers(ispine,
|
||||||
|
switch_point_id);
|
||||||
|
for (RRNodeId src_node : find_clock_opin2track_node(
|
||||||
|
grids, rr_graph_view, layer, src_coord, clk_ntwk,
|
||||||
|
int_driver_ids)) {
|
||||||
|
/* Create edges */
|
||||||
|
VTR_ASSERT(rr_graph_view.valid_node(des_node));
|
||||||
|
rr_graph_builder.create_edge(
|
||||||
|
src_node, des_node, clk_ntwk.default_driver_switch(), false);
|
||||||
|
edge_count++;
|
||||||
|
}
|
||||||
|
VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n",
|
||||||
|
edge_count - curr_edge_count, des_coord.x(), des_coord.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Allocate edges */
|
||||||
|
rr_graph_builder.build_edges(true);
|
||||||
|
num_edges_to_create += edge_count;
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Add edges to interconnect clock nodes
|
* Add edges to interconnect clock nodes
|
||||||
* Walk through the routing tracks in each connection block (driver nodes)
|
* Walk through the routing tracks in each connection block (driver nodes)
|
||||||
|
@ -614,6 +762,10 @@ static void add_rr_graph_clock_edges(
|
||||||
clk_ntwk, chany_coord, CHANY, verbose);
|
clk_ntwk, chany_coord, CHANY, verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Add edges between OPIN (internal driver) and clock routing tracks */
|
||||||
|
add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create,
|
||||||
|
clk_rr_lookup, rr_graph_view, grids, layer,
|
||||||
|
clk_ntwk, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -638,14 +790,6 @@ int append_clock_rr_graph(DeviceContext& vpr_device_ctx,
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Report any clock structure we do not support yet! */
|
|
||||||
if (clk_ntwk.num_trees() > 1) {
|
|
||||||
VTR_LOG(
|
|
||||||
"Currently only support 1 clock tree in programmable clock "
|
|
||||||
"architecture\nPlease update your clock architecture definition\n");
|
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Estimate the number of nodes and pre-allocate */
|
/* Estimate the number of nodes and pre-allocate */
|
||||||
size_t orig_num_nodes = vpr_device_ctx.rr_graph.num_nodes();
|
size_t orig_num_nodes = vpr_device_ctx.rr_graph.num_nodes();
|
||||||
size_t num_clock_nodes = estimate_clock_rr_graph_num_nodes(
|
size_t num_clock_nodes = estimate_clock_rr_graph_num_nodes(
|
||||||
|
|
|
@ -8,10 +8,55 @@
|
||||||
#include "old_traceback.h"
|
#include "old_traceback.h"
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
#include "vtr_log.h"
|
#include "vtr_log.h"
|
||||||
|
#include "vtr_time.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Create a mapping between each rr_node and its mapped nets
|
||||||
|
* - Only applicable to global nets for dedicated clock routing purpose
|
||||||
|
* - Note that this function is different than annotate_vpr_rr_nodes()
|
||||||
|
* Please do not annotate global nets in vpr_routing_annotation!
|
||||||
|
*******************************************************************/
|
||||||
|
vtr::vector<RRNodeId, ClusterNetId> annotate_rr_node_global_net(
|
||||||
|
const DeviceContext& device_ctx, const ClusteredNetlist& cluster_nlist,
|
||||||
|
const PlacementContext& placement_ctx, const bool& verbose) {
|
||||||
|
vtr::vector<RRNodeId, ClusterNetId> rr_node_nets;
|
||||||
|
|
||||||
|
size_t counter = 0;
|
||||||
|
vtr::ScopedStartFinishTimer timer("Annotating rr_node with global nets");
|
||||||
|
|
||||||
|
const auto& rr_graph = device_ctx.rr_graph;
|
||||||
|
|
||||||
|
rr_node_nets.resize(rr_graph.num_nodes(), ClusterNetId::INVALID());
|
||||||
|
|
||||||
|
size_t layer = 0;
|
||||||
|
|
||||||
|
for (ClusterNetId net_id : cluster_nlist.nets()) {
|
||||||
|
if (!cluster_nlist.net_is_ignored(net_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Walk through all the sinks */
|
||||||
|
for (ClusterPinId pin_id : cluster_nlist.net_pins(net_id)) {
|
||||||
|
ClusterBlockId block_id = cluster_nlist.pin_block(pin_id);
|
||||||
|
t_block_loc blk_loc = get_block_loc(block_id, false);
|
||||||
|
int phy_pin = placement_ctx.physical_pins[pin_id];
|
||||||
|
std::vector<RRNodeId> curr_rr_nodes =
|
||||||
|
rr_graph.node_lookup().find_nodes_at_all_sides(
|
||||||
|
layer, blk_loc.loc.x, blk_loc.loc.y, IPIN, phy_pin);
|
||||||
|
for (RRNodeId curr_rr_node : curr_rr_nodes) {
|
||||||
|
rr_node_nets[curr_rr_node] = net_id;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTR_LOGV(verbose, "Done with %d nodes mapping\n", counter);
|
||||||
|
|
||||||
|
return rr_node_nets;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Create a mapping between each rr_node and its mapped nets
|
* Create a mapping between each rr_node and its mapped nets
|
||||||
* based on VPR routing results
|
* based on VPR routing results
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
|
vtr::vector<RRNodeId, ClusterNetId> annotate_rr_node_global_net(
|
||||||
|
const DeviceContext& device_ctx, const ClusteredNetlist& cluster_nlist,
|
||||||
|
const PlacementContext& placement_ctx, const bool& verbose);
|
||||||
|
|
||||||
void annotate_vpr_rr_node_nets(const DeviceContext& device_ctx,
|
void annotate_vpr_rr_node_nets(const DeviceContext& device_ctx,
|
||||||
const ClusteringContext& clustering_ctx,
|
const ClusteringContext& clustering_ctx,
|
||||||
const RoutingContext& routing_ctx,
|
const RoutingContext& routing_ctx,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include "route_clock_rr_graph.h"
|
#include "route_clock_rr_graph.h"
|
||||||
|
|
||||||
#include "command_exit_codes.h"
|
#include "command_exit_codes.h"
|
||||||
#include "openfpga_atom_netlist_utils.h"
|
#include "openfpga_annotate_routing.h"
|
||||||
|
#include "openfpga_clustered_netlist_utils.h"
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
#include "vtr_geometry.h"
|
#include "vtr_geometry.h"
|
||||||
#include "vtr_log.h"
|
#include "vtr_log.h"
|
||||||
|
@ -21,27 +22,30 @@ namespace openfpga {
|
||||||
static int build_clock_tree_net_map(
|
static int build_clock_tree_net_map(
|
||||||
std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||||
const ClusteredNetlist& cluster_nlist, const PinConstraints& pin_constraints,
|
const ClusteredNetlist& cluster_nlist, const PinConstraints& pin_constraints,
|
||||||
const std::vector<std::string>& clk_names, const ClockNetwork& clk_ntwk,
|
const std::vector<ClusterNetId>& gnets, const ClockNetwork& clk_ntwk,
|
||||||
const ClockTreeId clk_tree, const bool& verbose) {
|
const ClockTreeId clk_tree, const bool& verbose) {
|
||||||
|
BasicPort tree_gport = clk_ntwk.tree_global_port(clk_tree);
|
||||||
/* Find the pin id for each clock name, error out if there is any mismatch */
|
/* Find the pin id for each clock name, error out if there is any mismatch */
|
||||||
if (clk_names.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) {
|
if (clk_ntwk.num_trees() == 1 && gnets.size() == 1 &&
|
||||||
|
clk_ntwk.tree_width(clk_tree) == 1) {
|
||||||
/* Find cluster net id */
|
/* Find cluster net id */
|
||||||
ClusterNetId clk_net = cluster_nlist.find_net(clk_names[0]);
|
if (!cluster_nlist.valid_net_id(gnets[0])) {
|
||||||
if (!cluster_nlist.valid_net_id(clk_net)) {
|
VTR_LOG_ERROR("Invalid clock name '%s'! Cannot be found from netlists!\n",
|
||||||
VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n",
|
cluster_nlist.net_name(gnets[0]).c_str());
|
||||||
clk_names[0].c_str());
|
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
tree2clk_pin_map[ClockTreePinId(0)] = clk_net;
|
tree2clk_pin_map[ClockTreePinId(0)] = gnets[0];
|
||||||
} else {
|
} else {
|
||||||
for (std::string clk_name : clk_names) {
|
for (ClusterNetId gnet : gnets) {
|
||||||
/* Find the pin information that the net should be mapped to */
|
/* Find the pin information that the net should be mapped to */
|
||||||
BasicPort tree_pin = pin_constraints.net_pin(clk_name);
|
std::string gnet_name = cluster_nlist.net_name(gnet);
|
||||||
|
/* The pin should match be global port name of the tree */
|
||||||
|
BasicPort tree_pin = pin_constraints.net_pin(gnet_name);
|
||||||
if (!tree_pin.is_valid()) {
|
if (!tree_pin.is_valid()) {
|
||||||
VTR_LOG_ERROR(
|
VTR_LOG_ERROR(
|
||||||
"Invalid tree pin for clock '%s'! Clock name may not be valid "
|
"Global net '%s' is not mapped to a valid pin '%s' in pin "
|
||||||
"(mismatched with netlists)!\n",
|
"constraints!\n",
|
||||||
clk_name.c_str());
|
gnet_name.c_str(), tree_pin.to_verilog_string().c_str());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
if (tree_pin.get_width() != 1) {
|
if (tree_pin.get_width() != 1) {
|
||||||
|
@ -49,25 +53,28 @@ static int build_clock_tree_net_map(
|
||||||
"Invalid tree pin %s[%lu:%lu] for clock '%s'! Clock pin must have "
|
"Invalid tree pin %s[%lu:%lu] for clock '%s'! Clock pin must have "
|
||||||
"only a width of 1!\n",
|
"only a width of 1!\n",
|
||||||
tree_pin.get_name().c_str(), tree_pin.get_lsb(), tree_pin.get_msb(),
|
tree_pin.get_name().c_str(), tree_pin.get_lsb(), tree_pin.get_msb(),
|
||||||
clk_name.c_str());
|
gnet_name.c_str());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
if (tree_pin.get_lsb() >= clk_ntwk.tree_width(clk_tree)) {
|
if (tree_gport.get_name() != tree_pin.get_name()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tree_gport.contained(tree_pin)) {
|
||||||
VTR_LOG_ERROR(
|
VTR_LOG_ERROR(
|
||||||
"Invalid tree pin %s[%lu] is out of range of clock tree size '%lu'\n",
|
"Invalid pin constraint port '%s' which is out of range of the "
|
||||||
tree_pin.get_name().c_str(), tree_pin.get_lsb(),
|
"global port '%s' of clock tree '%s'\n",
|
||||||
clk_ntwk.tree_width(clk_tree));
|
tree_pin.to_verilog_string().c_str(),
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
tree_gport.to_verilog_string().c_str(),
|
||||||
}
|
clk_ntwk.tree_name(clk_tree).c_str());
|
||||||
/* Find cluster net id */
|
|
||||||
ClusterNetId clk_net = cluster_nlist.find_net(clk_name);
|
|
||||||
if (!cluster_nlist.valid_net_id(clk_net)) {
|
|
||||||
VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n",
|
|
||||||
clk_name.c_str());
|
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
/* TODO: Check the tree_pin.get_name(), see if matches the tree from ports
|
||||||
|
*/
|
||||||
/* Register the pin mapping */
|
/* Register the pin mapping */
|
||||||
tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = clk_net;
|
tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = gnet;
|
||||||
|
VTR_LOGV(verbose, "Mapped net '%s' to pin '%s' of clock tree '%s'.\n",
|
||||||
|
gnet_name.c_str(), tree_pin.to_verilog_string().c_str(),
|
||||||
|
clk_ntwk.tree_name(clk_tree).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +84,343 @@ static int build_clock_tree_net_map(
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Route a switching points between spines
|
||||||
|
* - connect between two routing tracks (left or right turns)
|
||||||
|
* - connect internal driver to routing track
|
||||||
|
*******************************************************************/
|
||||||
|
static int route_clock_spine_switch_point(
|
||||||
|
VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph,
|
||||||
|
const RRClockSpatialLookup& clk_rr_lookup,
|
||||||
|
const vtr::vector<RRNodeId, ClusterNetId>& rr_node_gnets,
|
||||||
|
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||||
|
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
||||||
|
const ClockSpineId& ispine, const ClockTreePinId& ipin,
|
||||||
|
const ClockSwitchPointId& switch_point_id, const bool& verbose) {
|
||||||
|
VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
vtr::Point<int> src_coord =
|
||||||
|
clk_ntwk.spine_switch_point(ispine, switch_point_id);
|
||||||
|
ClockSpineId des_spine =
|
||||||
|
clk_ntwk.spine_switch_point_tap(ispine, switch_point_id);
|
||||||
|
vtr::Point<int> des_coord = clk_ntwk.spine_start_point(des_spine);
|
||||||
|
Direction src_spine_direction = clk_ntwk.spine_direction(ispine);
|
||||||
|
Direction des_spine_direction = clk_ntwk.spine_direction(des_spine);
|
||||||
|
ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine);
|
||||||
|
ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine);
|
||||||
|
RRNodeId src_node =
|
||||||
|
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
||||||
|
src_spine_level, ipin, src_spine_direction);
|
||||||
|
RRNodeId des_node =
|
||||||
|
clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree,
|
||||||
|
des_spine_level, ipin, des_spine_direction);
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(src_node));
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||||
|
/* Internal drivers may appear at the switch point. Check if there are
|
||||||
|
* any defined and related rr_node found as incoming edges. If the
|
||||||
|
* global net is mapped to the internal driver, use it as the previous
|
||||||
|
* node */
|
||||||
|
size_t use_int_driver = 0;
|
||||||
|
if (!clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id)
|
||||||
|
.empty() &&
|
||||||
|
tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) {
|
||||||
|
for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) {
|
||||||
|
RRNodeId opin_node = rr_graph.edge_src_node(cand_edge);
|
||||||
|
if (OPIN != rr_graph.node_type(opin_node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* This is the opin node we need, use it as the internal driver */
|
||||||
|
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
||||||
|
opin_node);
|
||||||
|
vpr_routing_annotation.set_rr_node_net(opin_node,
|
||||||
|
tree2clk_pin_map.at(ipin));
|
||||||
|
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||||
|
tree2clk_pin_map.at(ipin));
|
||||||
|
use_int_driver++;
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Routed switch points of spine '%s' at the switching point "
|
||||||
|
"(%lu, %lu) using internal driver\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str(), src_coord.x(),
|
||||||
|
src_coord.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (use_int_driver > 1) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Found %lu internal drivers for the switching point (%lu, %lu) for "
|
||||||
|
"spine '%s'!\n Expect only 1!\n",
|
||||||
|
use_int_driver, src_coord.x(), src_coord.y(),
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
if (use_int_driver == 1) {
|
||||||
|
return CMD_EXEC_SUCCESS; /* Used internal driver, early pass */
|
||||||
|
}
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Routed switch points of spine '%s' from (x=%lu, y=%lu) to spine "
|
||||||
|
"'%s' at (x=%lu, y=%lu)\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y(),
|
||||||
|
clk_ntwk.spine_name(des_spine).c_str(), des_coord.x(),
|
||||||
|
des_coord.y());
|
||||||
|
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node);
|
||||||
|
/* It could happen that there is no net mapped some clock pin, skip the
|
||||||
|
* net mapping */
|
||||||
|
if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) {
|
||||||
|
vpr_routing_annotation.set_rr_node_net(src_node, tree2clk_pin_map.at(ipin));
|
||||||
|
vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Route a spine to its tap points
|
||||||
|
* - Only connect to tap points which are mapped by a global net
|
||||||
|
*******************************************************************/
|
||||||
|
static int route_spine_taps(
|
||||||
|
VprRoutingAnnotation& vpr_routing_annotation, bool& spine_usage,
|
||||||
|
const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup,
|
||||||
|
const vtr::vector<RRNodeId, ClusterNetId>& rr_node_gnets,
|
||||||
|
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||||
|
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
||||||
|
const ClockSpineId& ispine, const ClockTreePinId& ipin, const bool& verbose) {
|
||||||
|
std::vector<vtr::Point<int>> spine_coords =
|
||||||
|
clk_ntwk.spine_coordinates(ispine);
|
||||||
|
size_t spine_tap_cnt = 0;
|
||||||
|
/* Route the spine-to-IPIN connections (only for the last level) */
|
||||||
|
if (clk_ntwk.is_last_level(ispine)) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Routing clock taps of spine '%s' for pin '%d' of tree '%s'...\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str(), size_t(ipin),
|
||||||
|
clk_ntwk.tree_name(clk_tree).c_str());
|
||||||
|
/* Connect to any fan-out node which is IPIN */
|
||||||
|
for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) {
|
||||||
|
vtr::Point<int> src_coord = spine_coords[icoord];
|
||||||
|
Direction src_spine_direction = clk_ntwk.spine_direction(ispine);
|
||||||
|
ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine);
|
||||||
|
RRNodeId src_node =
|
||||||
|
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
||||||
|
src_spine_level, ipin, src_spine_direction);
|
||||||
|
for (RREdgeId edge : rr_graph.edge_range(src_node)) {
|
||||||
|
RRNodeId des_node = rr_graph.edge_sink_node(edge);
|
||||||
|
if (rr_graph.node_type(des_node) == IPIN) {
|
||||||
|
VTR_LOGV(verbose, "Trying to route to IPIN '%s'\n",
|
||||||
|
rr_graph.node_coordinate_to_string(des_node).c_str());
|
||||||
|
/* Check if the IPIN is mapped, if not, do not connect */
|
||||||
|
/* if the IPIN is mapped, only connect when net mapping is
|
||||||
|
* expected */
|
||||||
|
if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Skip routing clock tap of spine '%s' as the tree is "
|
||||||
|
"not used\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!rr_node_gnets[des_node]) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Skip routing clock tap of spine '%s' as the IPIN is "
|
||||||
|
"not mapped\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rr_node_gnets[des_node] != tree2clk_pin_map.at(ipin)) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Skip routing clock tap of spine '%s' as the net "
|
||||||
|
"mapping does not match clock net\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(src_node));
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||||
|
VTR_LOGV(verbose, "Routed clock tap of spine '%s'\n",
|
||||||
|
clk_ntwk.spine_name(ispine).c_str());
|
||||||
|
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
||||||
|
src_node);
|
||||||
|
vpr_routing_annotation.set_rr_node_net(src_node,
|
||||||
|
tree2clk_pin_map.at(ipin));
|
||||||
|
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||||
|
tree2clk_pin_map.at(ipin));
|
||||||
|
/* Increment upon any required tap */
|
||||||
|
spine_tap_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spine_tap_cnt) {
|
||||||
|
spine_usage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Recursively route a clock spine on an existing routing resource graph
|
||||||
|
* The strategy is to route spine one by one
|
||||||
|
* - route the spine from the ending point to starting point (straight line)
|
||||||
|
* - for each stops on the staight line, route the spine-to-spine switching
|
||||||
|
points
|
||||||
|
* - for each switching point (des_spine_top|bottom), go recursively
|
||||||
|
* - If the downstream spine at any switching point is not used, disconnect
|
||||||
|
* - If any stop on the spine (straght line) is not used, disconnect
|
||||||
|
* - route the spine-to-IPIN connections (only for the last level)
|
||||||
|
*
|
||||||
|
* des_spine_top[0...N]
|
||||||
|
* ^ ^ ^ ^
|
||||||
|
* | | | |
|
||||||
|
* spine_start ---->+---->+---->+---->+->spine_end
|
||||||
|
* | | | |
|
||||||
|
* v v v v
|
||||||
|
* des_spine_bottom[0...N]
|
||||||
|
*
|
||||||
|
* <-------------------------------------------- direction to walk through
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* On each stop, we expand the spine to switch points and tap points
|
||||||
|
* - If the previous stop is used (connection to des_spines are required), then
|
||||||
|
the current stop should be connected to the previous stop
|
||||||
|
* - If previous stop is not used, while the des_spines are required to
|
||||||
|
connect, then the current stop should be connected to the previous stop
|
||||||
|
* - Only when previous stops and des_spines are not used, the current stop
|
||||||
|
will be NOT connected to the previous stop
|
||||||
|
*
|
||||||
|
* des_spine_top[i]
|
||||||
|
* ^
|
||||||
|
* |
|
||||||
|
* spine_curr_stop ---->+->spine_prev_stop
|
||||||
|
* |
|
||||||
|
* v
|
||||||
|
* des_spine_bottom[i]
|
||||||
|
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
static int rec_expand_and_route_clock_spine(
|
||||||
|
VprRoutingAnnotation& vpr_routing_annotation, bool& spine_usage,
|
||||||
|
const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup,
|
||||||
|
const vtr::vector<RRNodeId, ClusterNetId>& rr_node_gnets,
|
||||||
|
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||||
|
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
||||||
|
const ClockSpineId& curr_spine, const ClockTreePinId& curr_pin,
|
||||||
|
const bool& disable_unused_spines, const bool& verbose) {
|
||||||
|
int status = CMD_EXEC_SUCCESS;
|
||||||
|
bool curr_spine_usage = false;
|
||||||
|
bool curr_tap_usage = false;
|
||||||
|
/* For last level, we just connect tap points */
|
||||||
|
status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph,
|
||||||
|
clk_rr_lookup, rr_node_gnets, tree2clk_pin_map,
|
||||||
|
clk_ntwk, clk_tree, curr_spine, curr_pin, verbose);
|
||||||
|
if (CMD_EXEC_SUCCESS != status) {
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
if (curr_tap_usage) {
|
||||||
|
curr_spine_usage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vtr::Point<int>> spine_coords =
|
||||||
|
clk_ntwk.spine_coordinates(curr_spine);
|
||||||
|
/* We expand from the the ending point to starting point on the straight line.
|
||||||
|
* As such, it is easy to turn off spines by any stop.
|
||||||
|
* The spine should go in a straight line, connect all the stops on the line
|
||||||
|
*/
|
||||||
|
bool prev_stop_usage = false;
|
||||||
|
std::reverse(spine_coords.begin(), spine_coords.end());
|
||||||
|
for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) {
|
||||||
|
vtr::Point<int> switch_point_coord = spine_coords[icoord];
|
||||||
|
bool curr_stop_usage = false;
|
||||||
|
if (icoord == 0) {
|
||||||
|
prev_stop_usage = true; /* The first stop is always used */
|
||||||
|
}
|
||||||
|
/* Expand on the switching point here */
|
||||||
|
for (ClockSwitchPointId switch_point_id :
|
||||||
|
clk_ntwk.find_spine_switch_points_with_coord(curr_spine,
|
||||||
|
switch_point_coord)) {
|
||||||
|
ClockSpineId des_spine =
|
||||||
|
clk_ntwk.spine_switch_point_tap(curr_spine, switch_point_id);
|
||||||
|
/* Go recursively for the destination spine */
|
||||||
|
bool curr_branch_usage = false;
|
||||||
|
status = rec_expand_and_route_clock_spine(
|
||||||
|
vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup,
|
||||||
|
rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine,
|
||||||
|
curr_pin, disable_unused_spines, verbose);
|
||||||
|
if (CMD_EXEC_SUCCESS != status) {
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
/* Connect only when the destination spine is used */
|
||||||
|
if (disable_unused_spines && !curr_branch_usage) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Disconnect switching from spine '%s' to spine '%s' as "
|
||||||
|
"downstream is not used\n",
|
||||||
|
clk_ntwk.spine_name(curr_spine).c_str(),
|
||||||
|
clk_ntwk.spine_name(des_spine).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
curr_stop_usage = true;
|
||||||
|
/* Now connect to next spine, internal drivers may join */
|
||||||
|
status = route_clock_spine_switch_point(
|
||||||
|
vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets,
|
||||||
|
tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin,
|
||||||
|
switch_point_id, verbose);
|
||||||
|
if (CMD_EXEC_SUCCESS != status) {
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (disable_unused_spines && !curr_stop_usage && !prev_stop_usage) {
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Disconnect backbone of spine '%s' at (x=%lu, y=%lu) as "
|
||||||
|
"downstream is not used\n",
|
||||||
|
clk_ntwk.spine_name(curr_spine).c_str(), switch_point_coord.x(),
|
||||||
|
switch_point_coord.y());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip the first stop */
|
||||||
|
if (icoord == spine_coords.size() - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Connect only when next stop is used */
|
||||||
|
vtr::Point<int> src_coord = spine_coords[icoord + 1];
|
||||||
|
vtr::Point<int> des_coord = spine_coords[icoord];
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"(icoord=%lu) Expanding on backbone of spine '%s' from (x=%lu, "
|
||||||
|
"y=%lu) to (x=%lu, y=%lu)...\n",
|
||||||
|
icoord, clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(),
|
||||||
|
src_coord.y(), des_coord.x(), des_coord.y());
|
||||||
|
Direction src_spine_direction = clk_ntwk.spine_direction(curr_spine);
|
||||||
|
Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine);
|
||||||
|
ClockLevelId src_spine_level = clk_ntwk.spine_level(curr_spine);
|
||||||
|
ClockLevelId des_spine_level = clk_ntwk.spine_level(curr_spine);
|
||||||
|
RRNodeId src_node =
|
||||||
|
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
||||||
|
src_spine_level, curr_pin, src_spine_direction);
|
||||||
|
RRNodeId des_node =
|
||||||
|
clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree,
|
||||||
|
des_spine_level, curr_pin, des_spine_direction);
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(src_node));
|
||||||
|
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||||
|
VTR_LOGV(verbose,
|
||||||
|
"Routed backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, "
|
||||||
|
"y=%lu)...\n",
|
||||||
|
clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(),
|
||||||
|
src_coord.y(), des_coord.x(), des_coord.y());
|
||||||
|
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node);
|
||||||
|
/* It could happen that there is no net mapped some clock pin, skip the
|
||||||
|
* net mapping */
|
||||||
|
if (tree2clk_pin_map.find(curr_pin) != tree2clk_pin_map.end()) {
|
||||||
|
vpr_routing_annotation.set_rr_node_net(src_node,
|
||||||
|
tree2clk_pin_map.at(curr_pin));
|
||||||
|
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||||
|
tree2clk_pin_map.at(curr_pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_stop_usage = true;
|
||||||
|
curr_spine_usage = true;
|
||||||
|
}
|
||||||
|
/* Update status */
|
||||||
|
spine_usage = curr_spine_usage;
|
||||||
|
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Route a clock tree on an existing routing resource graph
|
* Route a clock tree on an existing routing resource graph
|
||||||
* The strategy is to route spine one by one
|
* The strategy is to route spine one by one
|
||||||
|
@ -87,99 +431,35 @@ static int build_clock_tree_net_map(
|
||||||
static int route_clock_tree_rr_graph(
|
static int route_clock_tree_rr_graph(
|
||||||
VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph,
|
VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph,
|
||||||
const RRClockSpatialLookup& clk_rr_lookup,
|
const RRClockSpatialLookup& clk_rr_lookup,
|
||||||
|
const vtr::vector<RRNodeId, ClusterNetId>& rr_node_gnets,
|
||||||
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||||
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
||||||
|
const bool& disable_unused_trees, const bool& disable_unused_spines,
|
||||||
const bool& verbose) {
|
const bool& verbose) {
|
||||||
for (auto ispine : clk_ntwk.spines(clk_tree)) {
|
for (auto ipin : clk_ntwk.pins(clk_tree)) {
|
||||||
VTR_LOGV(verbose, "Routing spine '%s'...\n",
|
/* Do not route unused clock spines */
|
||||||
clk_ntwk.spine_name(ispine).c_str());
|
if (disable_unused_trees &&
|
||||||
for (auto ipin : clk_ntwk.pins(clk_tree)) {
|
tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) {
|
||||||
/* Route the spine from starting point to ending point */
|
VTR_LOGV(verbose, "Skip routing unused tree '%s' pin '%lu'...\n",
|
||||||
std::vector<vtr::Point<int>> spine_coords =
|
clk_ntwk.tree_name(clk_tree).c_str(), size_t(ipin));
|
||||||
clk_ntwk.spine_coordinates(ispine);
|
continue;
|
||||||
VTR_LOGV(verbose, "Routing backbone of spine '%s'...\n",
|
}
|
||||||
clk_ntwk.spine_name(ispine).c_str());
|
/* Start with the top-level spines. Recursively walk through coordinates and
|
||||||
for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) {
|
* expand on switch points */
|
||||||
vtr::Point<int> src_coord = spine_coords[icoord];
|
bool tree_usage = false;
|
||||||
vtr::Point<int> des_coord = spine_coords[icoord + 1];
|
for (auto top_spine : clk_ntwk.tree_top_spines(clk_tree)) {
|
||||||
Direction src_spine_direction = clk_ntwk.spine_direction(ispine);
|
int status = rec_expand_and_route_clock_spine(
|
||||||
Direction des_spine_direction = clk_ntwk.spine_direction(ispine);
|
vpr_routing_annotation, tree_usage, rr_graph, clk_rr_lookup,
|
||||||
ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine);
|
rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin,
|
||||||
ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine);
|
disable_unused_spines, verbose);
|
||||||
RRNodeId src_node =
|
if (CMD_EXEC_SUCCESS != status) {
|
||||||
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
src_spine_level, ipin, src_spine_direction);
|
|
||||||
RRNodeId des_node =
|
|
||||||
clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree,
|
|
||||||
des_spine_level, ipin, des_spine_direction);
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(src_node));
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
|
||||||
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
|
||||||
src_node);
|
|
||||||
}
|
|
||||||
/* Route the spine-to-spine switching points */
|
|
||||||
VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n",
|
|
||||||
clk_ntwk.spine_name(ispine).c_str());
|
|
||||||
for (ClockSwitchPointId switch_point_id :
|
|
||||||
clk_ntwk.spine_switch_points(ispine)) {
|
|
||||||
vtr::Point<int> src_coord =
|
|
||||||
clk_ntwk.spine_switch_point(ispine, switch_point_id);
|
|
||||||
ClockSpineId des_spine =
|
|
||||||
clk_ntwk.spine_switch_point_tap(ispine, switch_point_id);
|
|
||||||
vtr::Point<int> des_coord = clk_ntwk.spine_start_point(des_spine);
|
|
||||||
Direction src_spine_direction = clk_ntwk.spine_direction(ispine);
|
|
||||||
Direction des_spine_direction = clk_ntwk.spine_direction(des_spine);
|
|
||||||
ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine);
|
|
||||||
ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine);
|
|
||||||
RRNodeId src_node =
|
|
||||||
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
|
||||||
src_spine_level, ipin, src_spine_direction);
|
|
||||||
RRNodeId des_node =
|
|
||||||
clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree,
|
|
||||||
des_spine_level, ipin, des_spine_direction);
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(src_node));
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
|
||||||
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
|
||||||
src_node);
|
|
||||||
/* It could happen that there is no net mapped some clock pin, skip the
|
|
||||||
* net mapping */
|
|
||||||
if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) {
|
|
||||||
vpr_routing_annotation.set_rr_node_net(src_node,
|
|
||||||
tree2clk_pin_map.at(ipin));
|
|
||||||
vpr_routing_annotation.set_rr_node_net(des_node,
|
|
||||||
tree2clk_pin_map.at(ipin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Route the spine-to-IPIN connections (only for the last level) */
|
|
||||||
if (clk_ntwk.is_last_level(ispine)) {
|
|
||||||
VTR_LOGV(verbose, "Routing clock taps of spine '%s'...\n",
|
|
||||||
clk_ntwk.spine_name(ispine).c_str());
|
|
||||||
/* Connect to any fan-out node which is IPIN */
|
|
||||||
for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) {
|
|
||||||
vtr::Point<int> src_coord = spine_coords[icoord];
|
|
||||||
Direction src_spine_direction = clk_ntwk.spine_direction(ispine);
|
|
||||||
ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine);
|
|
||||||
RRNodeId src_node =
|
|
||||||
clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree,
|
|
||||||
src_spine_level, ipin, src_spine_direction);
|
|
||||||
for (RREdgeId edge : rr_graph.edge_range(src_node)) {
|
|
||||||
RRNodeId des_node = rr_graph.edge_sink_node(edge);
|
|
||||||
if (rr_graph.node_type(des_node) == IPIN) {
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(src_node));
|
|
||||||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
|
||||||
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
|
||||||
src_node);
|
|
||||||
if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) {
|
|
||||||
vpr_routing_annotation.set_rr_node_net(
|
|
||||||
src_node, tree2clk_pin_map.at(ipin));
|
|
||||||
vpr_routing_annotation.set_rr_node_net(
|
|
||||||
des_node, tree2clk_pin_map.at(ipin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!tree_usage) {
|
||||||
|
VTR_LOGV(verbose, "Detect unused tree '%s' pin '%lu'...\n",
|
||||||
|
clk_ntwk.tree_name(clk_tree).c_str(), size_t(ipin));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -190,15 +470,13 @@ static int route_clock_tree_rr_graph(
|
||||||
* - configure the routing annotation w.r.t. the clock node connections
|
* - configure the routing annotation w.r.t. the clock node connections
|
||||||
* - quick check to ensure routing is valid
|
* - quick check to ensure routing is valid
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
int route_clock_rr_graph(
|
||||||
const DeviceContext& vpr_device_ctx,
|
VprRoutingAnnotation& vpr_routing_annotation,
|
||||||
const AtomContext& atom_ctx,
|
const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist,
|
||||||
const ClusteredNetlist& cluster_nlist,
|
const PlacementContext& vpr_place_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk,
|
||||||
const RRClockSpatialLookup& clk_rr_lookup,
|
const PinConstraints& pin_constraints, const bool& disable_unused_trees,
|
||||||
const ClockNetwork& clk_ntwk,
|
const bool& disable_unused_spines, const bool& verbose) {
|
||||||
const PinConstraints& pin_constraints,
|
|
||||||
const bool& verbose) {
|
|
||||||
vtr::ScopedStartFinishTimer timer(
|
vtr::ScopedStartFinishTimer timer(
|
||||||
"Route programmable clock network based on routing resource graph");
|
"Route programmable clock network based on routing resource graph");
|
||||||
|
|
||||||
|
@ -210,41 +488,40 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Report any clock structure we do not support yet! */
|
/* If there are multiple global signals from the netlist, require pin
|
||||||
if (clk_ntwk.num_trees() > 1) {
|
|
||||||
VTR_LOG(
|
|
||||||
"Currently only support 1 clock tree in programmable clock "
|
|
||||||
"architecture\nPlease update your clock architecture definition\n");
|
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are multiple clock signals from the netlist, require pin
|
|
||||||
* constraints */
|
* constraints */
|
||||||
std::vector<std::string> clock_net_names =
|
std::vector<ClusterNetId> gnets =
|
||||||
find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
|
find_clustered_netlist_global_nets(cluster_nlist);
|
||||||
if (clock_net_names.empty()) {
|
if (gnets.empty()) {
|
||||||
VTR_LOG(
|
VTR_LOG(
|
||||||
"Skip due to 0 clocks found from netlist\nDouble check your HDL design "
|
"Skip due to 0 global nets found from netlist\nDouble check your HDL "
|
||||||
|
"design "
|
||||||
"if this is unexpected\n");
|
"if this is unexpected\n");
|
||||||
return CMD_EXEC_SUCCESS;
|
return CMD_EXEC_SUCCESS;
|
||||||
}
|
}
|
||||||
if (clock_net_names.size() > 1 && pin_constraints.empty()) {
|
if (gnets.size() > 1 && pin_constraints.empty()) {
|
||||||
VTR_LOG(
|
VTR_LOG(
|
||||||
"There is %lu clock nets (more than 1). Require pin constraints to be "
|
"There is %lu global nets (more than 1). Require pin constraints to be "
|
||||||
"specified\n",
|
"specified\n",
|
||||||
clock_net_names.size());
|
gnets.size());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build rr_node-to-net mapping for global nets */
|
||||||
|
vtr::vector<RRNodeId, ClusterNetId> rr_node_gnets =
|
||||||
|
annotate_rr_node_global_net(vpr_device_ctx, cluster_nlist, vpr_place_ctx,
|
||||||
|
verbose);
|
||||||
|
|
||||||
/* Route spines one by one */
|
/* Route spines one by one */
|
||||||
for (auto itree : clk_ntwk.trees()) {
|
for (auto itree : clk_ntwk.trees()) {
|
||||||
VTR_LOGV(verbose, "Build clock name to clock tree '%s' pin mapping...\n",
|
VTR_LOGV(verbose,
|
||||||
|
"Build global net name to clock tree '%s' pin mapping...\n",
|
||||||
clk_ntwk.tree_name(itree).c_str());
|
clk_ntwk.tree_name(itree).c_str());
|
||||||
std::map<ClockTreePinId, ClusterNetId> tree2clk_pin_map;
|
std::map<ClockTreePinId, ClusterNetId> tree2clk_pin_map;
|
||||||
int status = CMD_EXEC_SUCCESS;
|
int status = CMD_EXEC_SUCCESS;
|
||||||
status =
|
status =
|
||||||
build_clock_tree_net_map(tree2clk_pin_map, cluster_nlist, pin_constraints,
|
build_clock_tree_net_map(tree2clk_pin_map, cluster_nlist, pin_constraints,
|
||||||
clock_net_names, clk_ntwk, itree, verbose);
|
gnets, clk_ntwk, itree, verbose);
|
||||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -253,7 +530,8 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
||||||
clk_ntwk.tree_name(itree).c_str());
|
clk_ntwk.tree_name(itree).c_str());
|
||||||
status = route_clock_tree_rr_graph(
|
status = route_clock_tree_rr_graph(
|
||||||
vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup,
|
vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup,
|
||||||
tree2clk_pin_map, clk_ntwk, itree, verbose);
|
rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees,
|
||||||
|
disable_unused_spines, verbose);
|
||||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "pin_constraints.h"
|
#include "pin_constraints.h"
|
||||||
#include "rr_clock_spatial_lookup.h"
|
#include "rr_clock_spatial_lookup.h"
|
||||||
#include "vpr_context.h"
|
#include "vpr_context.h"
|
||||||
#include "vpr_netlist_annotation.h"
|
|
||||||
#include "vpr_routing_annotation.h"
|
#include "vpr_routing_annotation.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -18,15 +17,13 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
int route_clock_rr_graph(
|
||||||
const DeviceContext& vpr_device_ctx,
|
VprRoutingAnnotation& vpr_routing_annotation,
|
||||||
const AtomContext& atom_ctx,
|
const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist,
|
||||||
const ClusteredNetlist& cluster_nlist,
|
const PlacementContext& vpr_place_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk,
|
||||||
const RRClockSpatialLookup& clk_rr_lookup,
|
const PinConstraints& pin_constraints, const bool& disable_unused_trees,
|
||||||
const ClockNetwork& clk_ntwk,
|
const bool& disable_unused_spines, const bool& verbose);
|
||||||
const PinConstraints& pin_constraints,
|
|
||||||
const bool& verbose);
|
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,9 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd,
|
||||||
|
|
||||||
/* add an option '--pin_constraints_file in short '-pcf' */
|
/* add an option '--pin_constraints_file in short '-pcf' */
|
||||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||||
|
CommandOptionId opt_disable_unused_trees = cmd.option("disable_unused_trees");
|
||||||
|
CommandOptionId opt_disable_unused_spines =
|
||||||
|
cmd.option("disable_unused_spines");
|
||||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
CommandOptionId opt_verbose = cmd.option("verbose");
|
||||||
|
|
||||||
/* If pin constraints are enabled by command options, read the file */
|
/* If pin constraints are enabled by command options, read the file */
|
||||||
|
@ -230,9 +233,10 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd,
|
||||||
|
|
||||||
return route_clock_rr_graph(
|
return route_clock_rr_graph(
|
||||||
openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(),
|
openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(),
|
||||||
g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist,
|
g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(),
|
||||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(),
|
openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints,
|
||||||
openfpga_ctx.clock_arch(), pin_constraints,
|
cmd_context.option_enable(cmd, opt_disable_unused_trees),
|
||||||
|
cmd_context.option_enable(cmd, opt_disable_unused_spines),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,9 +236,23 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd,
|
||||||
openfpga_context.mutable_clock_arch() =
|
openfpga_context.mutable_clock_arch() =
|
||||||
read_xml_clock_network(arch_file_name.c_str());
|
read_xml_clock_network(arch_file_name.c_str());
|
||||||
/* Build internal links */
|
/* Build internal links */
|
||||||
openfpga_context.mutable_clock_arch().link();
|
if (!openfpga_context.mutable_clock_arch().link()) {
|
||||||
link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(),
|
VTR_LOG_ERROR("Link clock network failed!");
|
||||||
g_vpr_ctx.device().rr_graph);
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
if (CMD_EXEC_SUCCESS !=
|
||||||
|
link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(),
|
||||||
|
g_vpr_ctx.device().rr_graph)) {
|
||||||
|
VTR_LOG_ERROR("Link clock network to routing architecture failed!");
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
if (CMD_EXEC_SUCCESS != check_clock_network_tile_annotation(
|
||||||
|
openfpga_context.clock_arch(),
|
||||||
|
openfpga_context.arch().tile_annotations)) {
|
||||||
|
VTR_LOG_ERROR(
|
||||||
|
"Check clock network consistency with tile annotation failed!");
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
/* Ensure clean data */
|
/* Ensure clean data */
|
||||||
openfpga_context.clock_arch().validate();
|
openfpga_context.clock_arch().validate();
|
||||||
if (!openfpga_context.clock_arch().is_valid()) {
|
if (!openfpga_context.clock_arch().is_valid()) {
|
||||||
|
|
|
@ -710,6 +710,12 @@ ShellCommandId add_route_clock_rr_graph_command_template(
|
||||||
shell_cmd.set_option_short_name(opt_file, "pcf");
|
shell_cmd.set_option_short_name(opt_file, "pcf");
|
||||||
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
|
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
|
||||||
|
|
||||||
|
shell_cmd.add_option("disable_unused_trees", false,
|
||||||
|
"Disable entire clock trees when they are not used by "
|
||||||
|
"any clock nets. Useful to reduce clock power");
|
||||||
|
shell_cmd.add_option("disable_unused_spines", false,
|
||||||
|
"Disable part of the clock tree which are used by clock "
|
||||||
|
"nets. Useful to reduce clock power");
|
||||||
/* Add an option '--verbose' */
|
/* Add an option '--verbose' */
|
||||||
shell_cmd.add_option("verbose", false, "Show verbose outputs");
|
shell_cmd.add_option("verbose", false, "Show verbose outputs");
|
||||||
|
|
||||||
|
|
|
@ -1242,11 +1242,11 @@ static int build_top_module_global_net_from_clock_arch_tree(
|
||||||
if (clk_ntwk.tree_width(clk_tree) !=
|
if (clk_ntwk.tree_width(clk_tree) !=
|
||||||
module_manager.module_port(top_module, top_module_port).get_width()) {
|
module_manager.module_port(top_module, top_module_port).get_width()) {
|
||||||
VTR_LOG(
|
VTR_LOG(
|
||||||
"Clock tree '%s' does not have the same width '%lu' as the port '%'s of "
|
"Clock tree '%s' does not have the same width '%lu' as the port '%s' of "
|
||||||
"FPGA top module",
|
"FPGA top module",
|
||||||
clk_tree_name.c_str(), clk_ntwk.tree_width(clk_tree),
|
clk_tree_name.c_str(), clk_ntwk.tree_width(clk_tree),
|
||||||
module_manager.module_port(top_module, top_module_port)
|
module_manager.module_port(top_module, top_module_port)
|
||||||
.get_name()
|
.to_verilog_string()
|
||||||
.c_str());
|
.c_str());
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1323,12 +1323,21 @@ int add_top_module_global_ports_from_grid_modules(
|
||||||
BasicPort global_port_to_add;
|
BasicPort global_port_to_add;
|
||||||
global_port_to_add.set_name(
|
global_port_to_add.set_name(
|
||||||
tile_annotation.global_port_name(tile_global_port));
|
tile_annotation.global_port_name(tile_global_port));
|
||||||
size_t max_port_size = 0;
|
/* Dedicated network has their own sizes of port */
|
||||||
for (const BasicPort& tile_port :
|
if (tile_annotation.global_port_thru_dedicated_network(
|
||||||
tile_annotation.global_port_tile_ports(tile_global_port)) {
|
tile_global_port)) {
|
||||||
max_port_size = std::max(tile_port.get_width(), max_port_size);
|
std::string clk_tree_name =
|
||||||
|
tile_annotation.global_port_clock_arch_tree_name(tile_global_port);
|
||||||
|
ClockTreeId clk_tree = clk_ntwk.find_tree(clk_tree_name);
|
||||||
|
global_port_to_add.set_width(clk_ntwk.tree_width(clk_tree));
|
||||||
|
} else {
|
||||||
|
size_t max_port_size = 0;
|
||||||
|
for (const BasicPort& tile_port :
|
||||||
|
tile_annotation.global_port_tile_ports(tile_global_port)) {
|
||||||
|
max_port_size = std::max(tile_port.get_width(), max_port_size);
|
||||||
|
}
|
||||||
|
global_port_to_add.set_width(max_port_size);
|
||||||
}
|
}
|
||||||
global_port_to_add.set_width(max_port_size);
|
|
||||||
global_ports_to_add.push_back(global_port_to_add);
|
global_ports_to_add.push_back(global_port_to_add);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1352,8 +1361,7 @@ int add_top_module_global_ports_from_grid_modules(
|
||||||
* - If the net will be directly wired to tiles, the net will drive an input
|
* - If the net will be directly wired to tiles, the net will drive an input
|
||||||
* of a tile
|
* of a tile
|
||||||
*/
|
*/
|
||||||
if (!tile_annotation.global_port_clock_arch_tree_name(tile_global_port)
|
if (tile_annotation.global_port_thru_dedicated_network(tile_global_port)) {
|
||||||
.empty()) {
|
|
||||||
status = build_top_module_global_net_from_clock_arch_tree(
|
status = build_top_module_global_net_from_clock_arch_tree(
|
||||||
module_manager, top_module, top_module_port, rr_graph, device_rr_gsb,
|
module_manager, top_module, top_module_port, rr_graph, device_rr_gsb,
|
||||||
cb_instance_ids, clk_ntwk,
|
cb_instance_ids, clk_ntwk,
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/***************************************************************************************
|
||||||
|
* This file includes most utilized functions that are used to acquire data from
|
||||||
|
* VPR clustered netlist (post-packing netlist)
|
||||||
|
***************************************************************************************/
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
#include "vtr_time.h"
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "openfpga_clustered_netlist_utils.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* Find the names of all the atom blocks that drive clock nets
|
||||||
|
* This function will find if the block has been renamed due to contain
|
||||||
|
*sensitive characters that violates the Verilog syntax
|
||||||
|
***************************************************************************************/
|
||||||
|
std::vector<ClusterNetId> find_clustered_netlist_global_nets(
|
||||||
|
const ClusteredNetlist& clb_nlist) {
|
||||||
|
std::vector<ClusterNetId> gnets;
|
||||||
|
|
||||||
|
for (ClusterNetId net_id : clb_nlist.nets()) {
|
||||||
|
if (clb_nlist.net_is_ignored(net_id)) {
|
||||||
|
gnets.push_back(net_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gnets;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef OPENFPGA_CLUSTERED_NETLIST_UTILS_H
|
||||||
|
#define OPENFPGA_CLUSTERED_NETLIST_UTILS_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "clustered_netlist.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
std::vector<ClusterNetId> find_clustered_netlist_global_nets(
|
||||||
|
const ClusteredNetlist& clb_nlist);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -174,7 +174,7 @@
|
||||||
</routing_segment>
|
</routing_segment>
|
||||||
<tile_annotations>
|
<tile_annotations>
|
||||||
<global_port name="clk" is_clock="true" clock_arch_tree_name="clk_tree_2lvl" default_val="0">
|
<global_port name="clk" is_clock="true" clock_arch_tree_name="clk_tree_2lvl" default_val="0">
|
||||||
<tile name="clb" port="clk[0:1]"/>
|
<tile name="clb" port="clk[0:0]"/>
|
||||||
</global_port>
|
</global_port>
|
||||||
</tile_annotations>
|
</tile_annotations>
|
||||||
<pb_type_annotations>
|
<pb_type_annotations>
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- Architecture annotation for OpenFPGA framework
|
||||||
|
This annotation supports the k6_N10_40nm.xml
|
||||||
|
- General purpose logic block
|
||||||
|
- K = 6, N = 10, I = 40
|
||||||
|
- Single mode
|
||||||
|
- Routing architecture
|
||||||
|
- L = 4, fc_in = 0.15, fc_out = 0.1
|
||||||
|
-->
|
||||||
|
<openfpga_architecture>
|
||||||
|
<technology_library>
|
||||||
|
<device_library>
|
||||||
|
<device_model name="logic" type="transistor">
|
||||||
|
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
|
||||||
|
<design vdd="0.9" pn_ratio="2"/>
|
||||||
|
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
|
||||||
|
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
|
||||||
|
</device_model>
|
||||||
|
<device_model name="io" type="transistor">
|
||||||
|
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
|
||||||
|
<design vdd="2.5" pn_ratio="3"/>
|
||||||
|
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
|
||||||
|
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
|
||||||
|
</device_model>
|
||||||
|
</device_library>
|
||||||
|
<variation_library>
|
||||||
|
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
|
||||||
|
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
|
||||||
|
</variation_library>
|
||||||
|
</technology_library>
|
||||||
|
<circuit_library>
|
||||||
|
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1" is_default="true">
|
||||||
|
<design_technology type="cmos" topology="inverter" size="1"/>
|
||||||
|
<device_technology device_model_name="logic"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<delay_matrix type="rise" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
<delay_matrix type="fall" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="inv_buf" name="buf4" prefix="buf4" is_default="false">
|
||||||
|
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
|
||||||
|
<device_technology device_model_name="logic"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<delay_matrix type="rise" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
<delay_matrix type="fall" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="false">
|
||||||
|
<design_technology type="cmos" topology="buffer" size="1" num_level="3" f_per_stage="4"/>
|
||||||
|
<device_technology device_model_name="logic"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<delay_matrix type="rise" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
<delay_matrix type="fall" in_port="in" out_port="out">
|
||||||
|
10e-12
|
||||||
|
</delay_matrix>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="gate" name="OR2" prefix="OR2" is_default="true">
|
||||||
|
<design_technology type="cmos" topology="OR"/>
|
||||||
|
<device_technology device_model_name="logic"/>
|
||||||
|
<input_buffer exist="false"/>
|
||||||
|
<output_buffer exist="false"/>
|
||||||
|
<port type="input" prefix="a" size="1"/>
|
||||||
|
<port type="input" prefix="b" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<delay_matrix type="rise" in_port="a b" out_port="out">
|
||||||
|
10e-12 5e-12
|
||||||
|
</delay_matrix>
|
||||||
|
<delay_matrix type="fall" in_port="a b" out_port="out">
|
||||||
|
10e-12 5e-12
|
||||||
|
</delay_matrix>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="true">
|
||||||
|
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
|
||||||
|
<device_technology device_model_name="logic"/>
|
||||||
|
<input_buffer exist="false"/>
|
||||||
|
<output_buffer exist="false"/>
|
||||||
|
<port type="input" prefix="in" lib_name="A" size="1"/>
|
||||||
|
<port type="input" prefix="sel" lib_name="S" size="1"/>
|
||||||
|
<port type="input" prefix="selb" lib_name="SI" size="1"/>
|
||||||
|
<port type="output" prefix="out" lib_name="Y" size="1"/>
|
||||||
|
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
|
||||||
|
10e-12 5e-12 5e-12
|
||||||
|
</delay_matrix>
|
||||||
|
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
|
||||||
|
10e-12 5e-12 5e-12
|
||||||
|
</delay_matrix>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="false"/>
|
||||||
|
<output_buffer exist="false"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/>
|
||||||
|
<!-- model_type could be T, res_val and cap_val DON'T CARE -->
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="false"/>
|
||||||
|
<output_buffer exist="false"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<wire_param model_type="pi" R="0" C="0" num_level="1"/>
|
||||||
|
<!-- model_type could be T, res_val cap_val should be defined -->
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="mux" name="mux_2level" prefix="mux_2level" dump_structural_verilog="true">
|
||||||
|
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<pass_gate_logic circuit_model_name="TGATE"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<port type="sram" prefix="sram" size="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="mux" name="mux_2level_tapbuf" prefix="mux_2level_tapbuf" dump_structural_verilog="true">
|
||||||
|
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
|
||||||
|
<pass_gate_logic circuit_model_name="TGATE"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<port type="sram" prefix="sram" size="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="mux" name="mux_1level_tapbuf" prefix="mux_1level_tapbuf" is_default="true" dump_structural_verilog="true">
|
||||||
|
<design_technology type="cmos" structure="one_level" add_const_input="true" const_input_val="1"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
|
||||||
|
<pass_gate_logic circuit_model_name="TGATE"/>
|
||||||
|
<port type="input" prefix="in" size="1"/>
|
||||||
|
<port type="output" prefix="out" size="1"/>
|
||||||
|
<port type="sram" prefix="sram" size="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
|
||||||
|
<circuit_model type="ff" name="MULTI_MODE_DFFRQ" prefix="MULTI_MODE_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<port type="input" prefix="D" size="1"/>
|
||||||
|
<port type="input" prefix="R" lib_name="RST" size="1" default_val="0"/>
|
||||||
|
<port type="output" prefix="Q" size="1"/>
|
||||||
|
<port type="clock" prefix="C" lib_name="CK" size="1" default_val="0"/>
|
||||||
|
<port type="sram" prefix="mode" size="1" mode_select="true" circuit_model_name="DFFR" default_val="0"/>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="lut" name="frac_lut4" prefix="frac_lut4" dump_structural_verilog="true">
|
||||||
|
<design_technology type="cmos" fracturable_lut="true"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
|
||||||
|
<lut_intermediate_buffer exist="true" circuit_model_name="buf4" location_map="-1-"/>
|
||||||
|
<pass_gate_logic circuit_model_name="TGATE"/>
|
||||||
|
<port type="input" prefix="in" size="4" tri_state_map="---1" circuit_model_name="OR2"/>
|
||||||
|
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
|
||||||
|
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
|
||||||
|
<port type="sram" prefix="sram" size="16"/>
|
||||||
|
<port type="sram" prefix="mode" size="1" mode_select="true" circuit_model_name="DFFR" default_val="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
|
||||||
|
<circuit_model type="ccff" name="DFFR" prefix="DFFR" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<port type="input" prefix="pReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
|
||||||
|
<port type="input" prefix="D" size="1"/>
|
||||||
|
<port type="output" prefix="Q" size="1"/>
|
||||||
|
<port type="output" prefix="QN" size="1"/>
|
||||||
|
<port type="clock" prefix="prog_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
|
||||||
|
</circuit_model>
|
||||||
|
<circuit_model type="iopad" name="GPIO" prefix="GPIO" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/gpio.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<port type="inout" prefix="PAD" size="1" is_global="true" is_io="true" is_data_io="true"/>
|
||||||
|
<port type="sram" prefix="DIR" size="1" mode_select="true" circuit_model_name="DFFR" default_val="1"/>
|
||||||
|
<port type="input" prefix="outpad" lib_name="A" size="1"/>
|
||||||
|
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
</circuit_library>
|
||||||
|
<configuration_protocol>
|
||||||
|
<organization type="scan_chain" circuit_model_name="DFFR"/>
|
||||||
|
</configuration_protocol>
|
||||||
|
<connection_block>
|
||||||
|
<switch name="ipin_cblock" circuit_model_name="mux_2level_tapbuf"/>
|
||||||
|
</connection_block>
|
||||||
|
<switch_block>
|
||||||
|
<switch name="0" circuit_model_name="mux_2level_tapbuf"/>
|
||||||
|
</switch_block>
|
||||||
|
<routing_segment>
|
||||||
|
<segment name="L1" circuit_model_name="chan_segment"/>
|
||||||
|
<segment name="L4" circuit_model_name="chan_segment"/>
|
||||||
|
</routing_segment>
|
||||||
|
<tile_annotations>
|
||||||
|
<global_port name="op_clk" clock_arch_tree_name="clk_tree_2lvl" is_clock="true" default_val="0">
|
||||||
|
<tile name="clb" port="clk"/>
|
||||||
|
</global_port>
|
||||||
|
<global_port name="op_reset" clock_arch_tree_name="rst_tree_2lvl" is_reset="true" default_val="0">
|
||||||
|
<tile name="clb" port="reset"/>
|
||||||
|
</global_port>
|
||||||
|
</tile_annotations>
|
||||||
|
<pb_type_annotations>
|
||||||
|
<!-- physical pb_type binding in complex block IO -->
|
||||||
|
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
|
||||||
|
<pb_type name="io[physical].iopad" circuit_model_name="GPIO" mode_bits="1"/>
|
||||||
|
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
|
||||||
|
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
|
||||||
|
<!-- End physical pb_type binding in complex block IO -->
|
||||||
|
<!-- physical pb_type binding in complex block CLB -->
|
||||||
|
<!-- physical mode will be the default mode if not specified -->
|
||||||
|
<pb_type name="clb">
|
||||||
|
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
|
||||||
|
<interconnect name="crossbar" circuit_model_name="mux_2level"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle" physical_mode_name="physical"/>
|
||||||
|
<pb_type name="clb.fle[physical].fabric.frac_logic.frac_lut4" circuit_model_name="frac_lut4" mode_bits="0"/>
|
||||||
|
<pb_type name="clb.fle[physical].fabric.ff" circuit_model_name="MULTI_MODE_DFFRQ" mode_bits="0"/>
|
||||||
|
<!-- Binding operating pb_type to physical pb_type -->
|
||||||
|
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1" physical_pb_type_index_factor="0.5">
|
||||||
|
<!-- Binding the lut3 to the first 3 inputs of fracturable lut4 -->
|
||||||
|
<port name="in" physical_mode_port="in[0:2]"/>
|
||||||
|
<port name="out" physical_mode_port="lut3_out[0:0]" physical_mode_pin_rotate_offset="1"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff[latch].latch" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0">
|
||||||
|
<port name="clk" physical_mode_port="C"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff[dff].dff" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0"/>
|
||||||
|
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff[dffr].dffr" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0"/>
|
||||||
|
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff[dffrn].dffrn" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="1">
|
||||||
|
<port name="RN" physical_mode_port="R"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle[n1_lut4].ble4.lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="0">
|
||||||
|
<!-- Binding the lut4 to the first 4 inputs of fracturable lut4 -->
|
||||||
|
<port name="in" physical_mode_port="in[0:3]"/>
|
||||||
|
<port name="out" physical_mode_port="lut4_out"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle[n1_lut4].ble4.ff[latch].latch" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0">
|
||||||
|
<port name="clk" physical_mode_port="C"/>
|
||||||
|
</pb_type>
|
||||||
|
<pb_type name="clb.fle[n1_lut4].ble4.ff[dff].dff" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
|
||||||
|
<pb_type name="clb.fle[n1_lut4].ble4.ff[dffr].dffr" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="0" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
|
||||||
|
<pb_type name="clb.fle[n1_lut4].ble4.ff[dffrn].dffrn" physical_pb_type_name="clb.fle[physical].fabric.ff" mode_bits="1" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0">
|
||||||
|
<port name="RN" physical_mode_port="R"/>
|
||||||
|
</pb_type>
|
||||||
|
<!-- End physical pb_type binding in complex block IO -->
|
||||||
|
</pb_type_annotations>
|
||||||
|
</openfpga_architecture>
|
|
@ -197,6 +197,7 @@
|
||||||
<switch name="0" circuit_model_name="mux_2level_tapbuf"/>
|
<switch name="0" circuit_model_name="mux_2level_tapbuf"/>
|
||||||
</switch_block>
|
</switch_block>
|
||||||
<routing_segment>
|
<routing_segment>
|
||||||
|
<segment name="L1" circuit_model_name="chan_segment"/>
|
||||||
<segment name="L4" circuit_model_name="chan_segment"/>
|
<segment name="L4" circuit_model_name="chan_segment"/>
|
||||||
</routing_segment>
|
</routing_segment>
|
||||||
<tile_annotations>
|
<tile_annotations>
|
||||||
|
|
|
@ -22,7 +22,7 @@ append_clock_rr_graph
|
||||||
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
|
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
|
||||||
|
|
||||||
# Route clock based on clock network definition
|
# Route clock based on clock network definition
|
||||||
route_clock_rr_graph
|
route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS}
|
||||||
|
|
||||||
# Check and correct any naming conflicts in the BLIF netlist
|
# Check and correct any naming conflicts in the BLIF netlist
|
||||||
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
# Run VPR for the 'and' design
|
||||||
|
#--write_rr_graph example_rr_graph.xml
|
||||||
|
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} \
|
||||||
|
--clock_modeling ideal \
|
||||||
|
--device ${OPENFPGA_VPR_DEVICE_LAYOUT} \
|
||||||
|
--route_chan_width ${OPENFPGA_VPR_ROUTE_CHAN_WIDTH}
|
||||||
|
|
||||||
|
# Read OpenFPGA architecture definition
|
||||||
|
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
|
||||||
|
|
||||||
|
# Read OpenFPGA simulation settings
|
||||||
|
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
|
||||||
|
|
||||||
|
# Read OpenFPGA clock architecture
|
||||||
|
read_openfpga_clock_arch -f ${OPENFPGA_CLOCK_ARCH_FILE}
|
||||||
|
|
||||||
|
# Append clock network to vpr's routing resource graph
|
||||||
|
append_clock_rr_graph
|
||||||
|
|
||||||
|
# Annotate the OpenFPGA architecture to VPR data base
|
||||||
|
# to debug use --verbose options
|
||||||
|
link_openfpga_arch --sort_gsb_chan_node_in_edges
|
||||||
|
|
||||||
|
# Route clock based on clock network definition
|
||||||
|
route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
||||||
|
|
||||||
|
# Check and correct any naming conflicts in the BLIF netlist
|
||||||
|
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
||||||
|
|
||||||
|
# Apply fix-up to Look-Up Table truth tables based on packing results
|
||||||
|
lut_truth_table_fixup
|
||||||
|
|
||||||
|
# Build the module graph
|
||||||
|
# - Enabled compression on routing architecture modules
|
||||||
|
# - Enable pin duplication on grid modules
|
||||||
|
build_fabric --compress_routing #--verbose
|
||||||
|
|
||||||
|
# Write the fabric hierarchy of module graph to a file
|
||||||
|
# This is used by hierarchical PnR flows
|
||||||
|
write_fabric_hierarchy --file ./fabric_hierarchy.txt
|
||||||
|
|
||||||
|
# Repack the netlist to physical pbs
|
||||||
|
# This must be done before bitstream generator and testbench generation
|
||||||
|
# Strongly recommend it is done after all the fix-up have been applied
|
||||||
|
repack --design_constraints ${OPENFPGA_REPACK_CONSTRAINTS_FILE} #--verbose
|
||||||
|
|
||||||
|
# Build the bitstream
|
||||||
|
# - Output the fabric-independent bitstream to a file
|
||||||
|
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
|
||||||
|
|
||||||
|
# Build fabric-dependent bitstream
|
||||||
|
build_fabric_bitstream --verbose
|
||||||
|
|
||||||
|
# Write fabric-dependent bitstream
|
||||||
|
write_fabric_bitstream --file fabric_bitstream.bit --format plain_text
|
||||||
|
|
||||||
|
# Write the Verilog netlist for FPGA fabric
|
||||||
|
# - Enable the use of explicit port mapping in Verilog netlist
|
||||||
|
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
|
||||||
|
|
||||||
|
# Write the Verilog testbench for FPGA fabric
|
||||||
|
# - We suggest the use of same output directory as fabric Verilog netlists
|
||||||
|
# - Must specify the reference benchmark file if you want to output any testbenches
|
||||||
|
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
|
||||||
|
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
|
||||||
|
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
|
||||||
|
write_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --include_signal_init --bitstream fabric_bitstream.bit --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
||||||
|
write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
||||||
|
write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
||||||
|
|
||||||
|
# Finish and exit OpenFPGA
|
||||||
|
exit
|
||||||
|
|
||||||
|
# Note :
|
||||||
|
# To run verification at the end of the flow maintain source in ./SRC directory
|
|
@ -22,7 +22,7 @@ append_clock_rr_graph
|
||||||
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
|
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
|
||||||
|
|
||||||
# Route clock based on clock network definition
|
# Route clock based on clock network definition
|
||||||
route_clock_rr_graph --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE}
|
||||||
|
|
||||||
# Check and correct any naming conflicts in the BLIF netlist
|
# Check and correct any naming conflicts in the BLIF netlist
|
||||||
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
||||||
|
|
|
@ -232,6 +232,12 @@ echo -e "Testing programmable clock architecture";
|
||||||
run-task basic_tests/clock_network/homo_1clock_2layer $@
|
run-task basic_tests/clock_network/homo_1clock_2layer $@
|
||||||
run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@
|
run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@
|
||||||
run-task basic_tests/clock_network/homo_2clock_2layer $@
|
run-task basic_tests/clock_network/homo_2clock_2layer $@
|
||||||
|
run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused $@
|
||||||
|
run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree $@
|
||||||
|
run-task basic_tests/clock_network/homo_1clock_1reset_2layer $@
|
||||||
|
run-task basic_tests/clock_network/homo_1clock_1reset_2layer_syntax $@
|
||||||
|
run-task basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines $@
|
||||||
|
run-task basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver $@
|
||||||
|
|
||||||
echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific";
|
echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific";
|
||||||
run-task basic_tests/verific_test $@
|
run-task basic_tests/verific_test $@
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="op_clk[0:0]">
|
||||||
|
<spine name="clk_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
<clock_network name="rst_tree_2lvl" global_port="op_reset[0:0]">
|
||||||
|
<spine name="rst_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="reset"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="resetb" default_value="1"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<!-- Intended to be dummy -->
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = false
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 3*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=40
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml
|
||||||
|
openfpga_verilog_testbench_port_mapping=--explicit_port_mapping
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||||
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
# Yosys script parameters
|
||||||
|
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v
|
||||||
|
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||||
|
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
|
||||||
|
|
||||||
|
bench0_top = counter
|
||||||
|
bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||||
|
bench0_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
bench1_top = counter
|
||||||
|
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml
|
||||||
|
bench1_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,32 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="op_clk[0:0]">
|
||||||
|
<spine name="clk_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
<clock_network name="rst_tree_2lvl" global_port="op_reset[0:0]">
|
||||||
|
<spine name="rst_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="reset"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="resetb" default_value="1"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<!-- Intended to be dummy -->
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = false
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 3*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=40
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml
|
||||||
|
openfpga_verilog_testbench_port_mapping=--explicit_port_mapping
|
||||||
|
openfpga_route_clock_options=--disable_unused_spines
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||||
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
# Yosys script parameters
|
||||||
|
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v
|
||||||
|
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||||
|
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
|
||||||
|
|
||||||
|
bench0_top = counter
|
||||||
|
bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||||
|
bench0_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
bench1_top = counter
|
||||||
|
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml
|
||||||
|
bench1_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,40 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="op_clk[0:0]">
|
||||||
|
<spine name="clk_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_upper" x="1" y="1">
|
||||||
|
<internal_driver tile_pin="clb.O[0:7]"/>
|
||||||
|
</switch_point>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_lower" x="1" y="1">
|
||||||
|
<internal_driver tile_pin="clb.O[0:7]"/>
|
||||||
|
</switch_point>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_upper" x="2" y="1">
|
||||||
|
<internal_driver tile_pin="clb.O[0:7]"/>
|
||||||
|
</switch_point>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_lower" x="2" y="1">
|
||||||
|
<internal_driver tile_pin="clb.O[0:7]"/>
|
||||||
|
</switch_point>
|
||||||
|
</spine>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
<clock_network name="rst_tree_2lvl" global_port="op_reset[0:0]">
|
||||||
|
<spine name="rst_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="reset"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="resetb" default_value="1"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<!-- Intended to be dummy -->
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = false
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 3*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=40
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer_int_driver.xml
|
||||||
|
openfpga_verilog_testbench_port_mapping=--explicit_port_mapping
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||||
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
# Yosys script parameters
|
||||||
|
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v
|
||||||
|
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||||
|
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
|
||||||
|
|
||||||
|
bench0_top = counter
|
||||||
|
bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||||
|
bench0_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
bench1_top = counter
|
||||||
|
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml
|
||||||
|
bench1_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,36 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="op_clk[0:0]">
|
||||||
|
<spine name="clk_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="clk_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="clk_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<region from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]" start_x="1" start_y="1" end_x="2" end_y="1" repeat_x="1" repeat_y="1"/>
|
||||||
|
<single from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]" x="1" y="2"/>
|
||||||
|
<single from_pin="op_clk[0:0]" to_pin="clb[0:0].clk[0:0]" x="2" y="2"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
<clock_network name="rst_tree_2lvl" global_port="op_reset[0:0]">
|
||||||
|
<spine name="rst_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rst_rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rst_rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<region from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]" start_x="1" start_y="1" end_x="2" end_y="1" repeat_x="1" repeat_y="1"/>
|
||||||
|
<single from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]" x="1" y="2"/>
|
||||||
|
<single from_pin="op_reset[0:0]" to_pin="clb[0:0].reset[0:0]" x="2" y="2"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="reset"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="resetb" default_value="1"/>
|
||||||
|
<set_io pin="op_clk[0]" net="clk"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<!-- Intended to be dummy -->
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = false
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 3*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=40
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml
|
||||||
|
openfpga_verilog_testbench_port_mapping=--explicit_port_mapping
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||||
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
# Yosys script parameters
|
||||||
|
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v
|
||||||
|
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||||
|
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
|
||||||
|
|
||||||
|
bench0_top = counter
|
||||||
|
bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||||
|
bench0_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
bench1_top = counter
|
||||||
|
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml
|
||||||
|
bench1_openfpga_verilog_testbench_port_mapping=
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -1,5 +1,5 @@
|
||||||
<clock_networks default_segment="L1" default_switch="ipin_cblock">
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
<clock_network name="clk_tree_2lvl" width="1">
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:0]">
|
||||||
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="clb[0:0].clk[0:0]"/>
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
|
@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2
|
||||||
openfpga_vpr_route_chan_width=24
|
openfpga_vpr_route_chan_width=24
|
||||||
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/dummy_repack_constraints.xml
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/dummy_repack_constraints.xml
|
||||||
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/dummy_pin_constraints.xml
|
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/dummy_pin_constraints.xml
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
[ARCHITECTURES]
|
[ARCHITECTURES]
|
||||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<clock_networks default_segment="L1" default_switch="ipin_cblock">
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
<clock_network name="clk_tree_2lvl" width="1">
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:0]">
|
||||||
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="clb[0:0].clk[0:0]"/>
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
|
@ -22,6 +22,7 @@ openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_2layer.xml
|
||||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||||
openfpga_vpr_device_layout=2x2
|
openfpga_vpr_device_layout=2x2
|
||||||
openfpga_vpr_route_chan_width=24
|
openfpga_vpr_route_chan_width=24
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
[ARCHITECTURES]
|
[ARCHITECTURES]
|
||||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<clock_networks default_segment="L1" default_switch="ipin_cblock">
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
<clock_network name="clk_tree_2lvl" width="2">
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:1]">
|
||||||
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
@ -11,8 +11,8 @@
|
||||||
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="clb[0:0].clk[0:0]"/>
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
<tap tile_pin="clb[0:0].clk[1:1]"/>
|
<all from_pin="clk[1:1]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<repack_design_constraints>
|
<repack_design_constraints>
|
||||||
<pin_constraint pb_type="clb" pin="clk[0:0]" net="clk"/>
|
<pin_constraint pb_type="clb" pin="clk[0:0]" net="clk"/>
|
||||||
<pin_constraint pb_type="clb" pin="clk[1:1]" net="OPEN"/>
|
|
||||||
</repack_design_constraints>
|
</repack_design_constraints>
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2
|
||||||
openfpga_vpr_route_chan_width=24
|
openfpga_vpr_route_chan_width=24
|
||||||
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml
|
||||||
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml
|
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml
|
||||||
|
openfpga_route_clock_options=
|
||||||
|
|
||||||
[ARCHITECTURES]
|
[ARCHITECTURES]
|
||||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:1]">
|
||||||
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
<all from_pin="clk[1:1]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<set_io pin="clk[0]" net="clk"/>
|
||||||
|
<set_io pin="clk[1]" net="OPEN"/>
|
||||||
|
</pin_constraints>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<pin_constraint pb_type="clb" pin="clk[0:0]" net="clk"/>
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = true
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 20*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_2clk_2layer.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=24
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml
|
||||||
|
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml
|
||||||
|
openfpga_route_clock_options=--disable_unused_trees --disable_unused_spines
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench0_top = and2_latch
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,18 @@
|
||||||
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:1]">
|
||||||
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw1_upper" x="2" y="1"/>
|
||||||
|
<switch_point tap="rib_lvl1_sw1_lower" x="2" y="1"/>
|
||||||
|
</spine>
|
||||||
|
<spine name="rib_lvl1_sw0_upper" start_x="1" start_y="2" end_x="1" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw0_lower" start_x="1" start_y="1" end_x="1" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
|
<taps>
|
||||||
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
<all from_pin="clk[1:1]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
|
</taps>
|
||||||
|
</clock_network>
|
||||||
|
</clock_networks>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<set_io pin="clk[0]" net="clk"/>
|
||||||
|
<set_io pin="clk[1]" net="OPEN"/>
|
||||||
|
</pin_constraints>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<repack_design_constraints>
|
||||||
|
<pin_constraint pb_type="clb" pin="clk[0:0]" net="clk"/>
|
||||||
|
</repack_design_constraints>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = true
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 20*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml
|
||||||
|
openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_2clk_2layer.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||||
|
openfpga_vpr_device_layout=2x2
|
||||||
|
openfpga_vpr_route_chan_width=24
|
||||||
|
openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml
|
||||||
|
openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml
|
||||||
|
openfpga_route_clock_options=--disable_unused_trees
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench0_top = and2_latch
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -1,5 +1,5 @@
|
||||||
<clock_networks default_segment="L1" default_switch="ipin_cblock">
|
<clock_networks default_segment="L1" default_tap_switch="ipin_cblock" default_driver_switch="0">
|
||||||
<clock_network name="clk_tree_2lvl" width="1">
|
<clock_network name="clk_tree_2lvl" global_port="clk[0:0]">
|
||||||
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
<spine name="spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||||
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_upper" x="1" y="1"/>
|
||||||
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
<switch_point tap="rib_lvl1_sw0_lower" x="1" y="1"/>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_upper" start_x="2" start_y="2" end_x="2" end_y="2" type="CHANY" direction="INC_DIRECTION"/>
|
||||||
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
<spine name="rib_lvl1_sw1_lower" start_x="2" start_y="1" end_x="2" end_y="1" type="CHANY" direction="DEC_DIRECTION"/>
|
||||||
<taps>
|
<taps>
|
||||||
<tap tile_pin="clb[0:0].clk[0:0]"/>
|
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
|
||||||
</taps>
|
</taps>
|
||||||
</clock_network>
|
</clock_network>
|
||||||
</clock_networks>
|
</clock_networks>
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
</equivalent_sites>
|
</equivalent_sites>
|
||||||
<input name="I" num_pins="10" equivalent="full"/>
|
<input name="I" num_pins="10" equivalent="full"/>
|
||||||
<output name="O" num_pins="4" equivalent="none"/>
|
<output name="O" num_pins="4" equivalent="none"/>
|
||||||
<clock name="clk" num_pins="2"/>
|
<clock name="clk" num_pins="1"/>
|
||||||
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
|
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
|
||||||
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
|
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
|
||||||
</fc>
|
</fc>
|
||||||
|
@ -250,7 +250,7 @@
|
||||||
<pb_type name="clb">
|
<pb_type name="clb">
|
||||||
<input name="I" num_pins="10" equivalent="full"/>
|
<input name="I" num_pins="10" equivalent="full"/>
|
||||||
<output name="O" num_pins="4" equivalent="none"/>
|
<output name="O" num_pins="4" equivalent="none"/>
|
||||||
<clock name="clk" num_pins="2"/>
|
<clock name="clk" num_pins="1"/>
|
||||||
<!-- Describe basic logic element.
|
<!-- Describe basic logic element.
|
||||||
Each basic logic element has a 4-LUT that can be optionally registered
|
Each basic logic element has a 4-LUT that can be optionally registered
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -107,7 +107,12 @@
|
||||||
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
|
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
|
||||||
<fc_override port_name="reset" fc_type="frac" fc_val="0"/>
|
<fc_override port_name="reset" fc_type="frac" fc_val="0"/>
|
||||||
</fc>
|
</fc>
|
||||||
<pinlocations pattern="spread"/>
|
<pinlocations pattern="custom">
|
||||||
|
<loc side="left"/>
|
||||||
|
<loc side="top"/>
|
||||||
|
<loc side="right">clb.reset clb.clk clb.O[4:7] clb.I[6:11]</loc>
|
||||||
|
<loc side="bottom">clb.O[0:3] clb.I[0:5]</loc>
|
||||||
|
</pinlocations>
|
||||||
</sub_tile>
|
</sub_tile>
|
||||||
</tile>
|
</tile>
|
||||||
</tiles>
|
</tiles>
|
||||||
|
@ -194,6 +199,11 @@
|
||||||
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
|
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
|
||||||
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
|
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
|
||||||
<!-- GIVE a specific name for the segment! OpenFPGA appreciate that! -->
|
<!-- GIVE a specific name for the segment! OpenFPGA appreciate that! -->
|
||||||
|
<segment name="L1" freq="0.000000" length="1" type="unidir" Rmetal="101" Cmetal="22.5e-15">
|
||||||
|
<mux name="0"/>
|
||||||
|
<sb type="pattern">1 1</sb>
|
||||||
|
<cb type="pattern">1</cb>
|
||||||
|
</segment>
|
||||||
<segment name="L4" freq="1.000000" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
|
<segment name="L4" freq="1.000000" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
|
||||||
<mux name="0"/>
|
<mux name="0"/>
|
||||||
<sb type="pattern">1 1 1 1 1</sb>
|
<sb type="pattern">1 1 1 1 1</sb>
|
||||||
|
|
Loading…
Reference in New Issue