Merge pull request #1843 from lnis-uofu/xt_clkmux
Support intermediate drivers in programmable clock network
This commit is contained in:
commit
41cf56e372
|
@ -27,6 +27,9 @@ The entry point of a clock tree must be at a valid connection block.
|
|||
<clock_networks default_segment="<string>" default_tap_switch="<string>" default_driver_switch="<string>">
|
||||
<clock_network name="<string>" global_port="<int>">
|
||||
<spine name="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>">
|
||||
<intermediate_driver x="<int>" y="<int>">
|
||||
<tap from_pin="<string>" to_pin="<string>"/>
|
||||
</intermediate_driver>
|
||||
<switch_point tap="<string>" x="<int>" y="<int>">
|
||||
<internal_driver from_pin="<string>" to_pin="<string>"/>
|
||||
</switch_point>
|
||||
|
@ -179,6 +182,62 @@ where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to
|
|||
|
||||
.. note:: We only support clock spines in horizental and vertical directions. Diagonal clock spine is not supported!
|
||||
|
||||
.. _file_formats_clock_network_intermediate_driver:
|
||||
|
||||
Intermediate Driver
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following syntax are applicable to the XML definition tagged by ``intermediate_driver``
|
||||
Note that a number of intermediate drivers can be defined under each clock spine ``spine``.
|
||||
|
||||
.. option:: x="<int>"
|
||||
|
||||
The coordinate X where the intermediate driver should occur on the spine. Must be a valid coordinate within the range of the current clock spine and the clock spine to be tapped.
|
||||
|
||||
.. option:: y="<int>"
|
||||
|
||||
The coordinate Y where the intermediate driver should occur on the spine. Must be a valid coordinate within the range of the current clock spine and the clock spine to be tapped.
|
||||
|
||||
.. note:: The intermeidate driver is different than the internal driver (see details in :ref:`file_formats_clock_network_switch_point`). Intermediate driver may occur in any mid points of a spine, while internal driver occurs **ONLY** on the switch points between spines.
|
||||
|
||||
Under each intermediate driver, a number of tap points can be specified.
|
||||
For each tap point, outputs of neighbouring programmable blocks are allowed to drive the spine through syntax ``tap``.
|
||||
|
||||
.. option:: from_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.
|
||||
|
||||
.. option:: to_pin="<string>"
|
||||
|
||||
Define the source pin of 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.
|
||||
|
||||
For example,
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<clock_network name="clk_tree_0" global_port="clk[0:1]">
|
||||
<!-- Some clock spines -->
|
||||
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||
<intermediate_driver x="1" y="1">
|
||||
<tap from_pin="clb.O[0:1]" to_pin="clk[0:0]"/>
|
||||
</intermediate_driver>
|
||||
<spine>
|
||||
</clock_network>
|
||||
|
||||
|
||||
where clock spine ``spine0`` will be driven by other programmable blocks at (1, 1), as highlighted in purple in the :numref:`fig_prog_clock_network_example_2x2_perimeter_cb`
|
||||
|
||||
To be specific, 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_switch_point:
|
||||
|
||||
Switch Point Settings
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 72 KiB |
|
@ -1,6 +1,11 @@
|
|||
<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">
|
||||
<intermediate_driver x="1" y="2">
|
||||
<tap from_pin="clb.O[0:0]" to_pin="clk[0:0]"/>
|
||||
<tap from_pin="clb.O[1:1]" to_pin="clk[1:1]"/>
|
||||
<tap from_pin="clb.O[2:3]" to_pin="clk[2:2]"/>
|
||||
</intermediate_driver>
|
||||
<switch_point tap="spine_lvl2_upper" x="2" y="2">
|
||||
<internal_driver from_pin="clb.O[0:3]" to_pin="clk[1:1]"/>
|
||||
</switch_point>
|
||||
|
|
|
@ -270,6 +270,54 @@ vtr::Point<int> ClockNetwork::spine_end_point(
|
|||
return spine_end_points_[spine_id];
|
||||
}
|
||||
|
||||
std::vector<ClockInternalDriverId> ClockNetwork::spine_intermediate_drivers(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
|
||||
VTR_ASSERT(valid_spine_id(spine_id));
|
||||
/* Convert coord to a unique string */
|
||||
std::string coord_str =
|
||||
std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
|
||||
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
|
||||
if (result == spine_intermediate_drivers_[spine_id].end()) {
|
||||
return std::vector<ClockInternalDriverId>();
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
vtr::Point<int> ClockNetwork::spine_intermediate_driver_routing_track_coord(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
|
||||
vtr::Point<int> des_coord(coord.x(), coord.y());
|
||||
Direction des_spine_direction = spine_direction(spine_id);
|
||||
/* des node depends on the type of routing track and direction. But it
|
||||
* should be a starting point at the current SB[x][y] */
|
||||
if (des_spine_direction == Direction::INC &&
|
||||
spine_track_type(spine_id) == CHANX) {
|
||||
des_coord.set_x(coord.x() + 1);
|
||||
}
|
||||
if (des_spine_direction == Direction::INC &&
|
||||
spine_track_type(spine_id) == CHANY) {
|
||||
des_coord.set_y(coord.y() + 1);
|
||||
}
|
||||
return des_coord;
|
||||
}
|
||||
|
||||
std::vector<ClockInternalDriverId>
|
||||
ClockNetwork::spine_intermediate_drivers_by_routing_track(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& track_coord) const {
|
||||
vtr::Point<int> des_coord(track_coord.x(), track_coord.y());
|
||||
Direction des_spine_direction = spine_direction(spine_id);
|
||||
/* des node depends on the type of routing track and direction. But it
|
||||
* should be a starting point at the current SB[x][y] */
|
||||
if (des_spine_direction == Direction::INC &&
|
||||
spine_track_type(spine_id) == CHANX) {
|
||||
des_coord.set_x(track_coord.x() - 1);
|
||||
}
|
||||
if (des_spine_direction == Direction::INC &&
|
||||
spine_track_type(spine_id) == CHANY) {
|
||||
des_coord.set_y(track_coord.y() - 1);
|
||||
}
|
||||
return spine_intermediate_drivers(spine_id, des_coord);
|
||||
}
|
||||
|
||||
ClockLevelId ClockNetwork::spine_level(const ClockSpineId& spine_id) const {
|
||||
VTR_ASSERT(valid_spine_id(spine_id));
|
||||
if (is_dirty_) {
|
||||
|
@ -624,6 +672,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
|
|||
spine_switch_points_.reserve(num_spines);
|
||||
spine_switch_coords_.reserve(num_spines);
|
||||
spine_switch_internal_drivers_.reserve(num_spines);
|
||||
spine_intermediate_drivers_.reserve(num_spines);
|
||||
spine_parents_.reserve(num_spines);
|
||||
spine_children_.reserve(num_spines);
|
||||
spine_parent_trees_.reserve(num_spines);
|
||||
|
@ -716,6 +765,7 @@ ClockSpineId ClockNetwork::create_spine(const std::string& name) {
|
|||
spine_switch_points_.emplace_back();
|
||||
spine_switch_coords_.emplace_back();
|
||||
spine_switch_internal_drivers_.emplace_back();
|
||||
spine_intermediate_drivers_.emplace_back();
|
||||
spine_parents_.emplace_back();
|
||||
spine_children_.emplace_back();
|
||||
spine_parent_trees_.emplace_back();
|
||||
|
@ -817,6 +867,53 @@ ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(
|
|||
return int_driver_id;
|
||||
}
|
||||
|
||||
ClockInternalDriverId ClockNetwork::add_spine_intermediate_driver(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
|
||||
const std::string& int_driver_from_port,
|
||||
const std::string& int_driver_to_port) {
|
||||
VTR_ASSERT(valid_spine_id(spine_id));
|
||||
/* Convert coord to a unique string */
|
||||
std::string coord_str =
|
||||
std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
|
||||
/* Parse ports */
|
||||
PortParser to_pin_parser(int_driver_to_port);
|
||||
/* Find any existing id for the driver port */
|
||||
ClockInternalDriverId int_driver_id_to_add =
|
||||
ClockInternalDriverId(internal_driver_ids_.size());
|
||||
for (ClockInternalDriverId int_driver_id : internal_driver_ids_) {
|
||||
if (internal_driver_from_pins_[int_driver_id] == int_driver_from_port &&
|
||||
internal_driver_to_pins_[int_driver_id] == to_pin_parser.port()) {
|
||||
int_driver_id_to_add = int_driver_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Reaching here, no existing id can be reused, create a new one */
|
||||
if (int_driver_id_to_add ==
|
||||
ClockInternalDriverId(internal_driver_ids_.size())) {
|
||||
internal_driver_ids_.push_back(int_driver_id_to_add);
|
||||
internal_driver_from_pins_.push_back(int_driver_from_port);
|
||||
internal_driver_to_pins_.push_back(to_pin_parser.port());
|
||||
}
|
||||
/* Add it to existing map, avoid duplicated id */
|
||||
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
|
||||
if (result == spine_intermediate_drivers_[spine_id].end()) {
|
||||
spine_intermediate_drivers_[spine_id][coord_str].push_back(
|
||||
int_driver_id_to_add);
|
||||
} else {
|
||||
if (std::find(result->second.begin(), result->second.end(),
|
||||
int_driver_id_to_add) == result->second.end()) {
|
||||
result->second.push_back(int_driver_id_to_add);
|
||||
} else {
|
||||
VTR_LOG_WARN(
|
||||
"Skip intermediate driver (from_port='%s', to_port='%s') at (%s) as it "
|
||||
"is duplicated in the clock architecture description file!\n",
|
||||
int_driver_from_port.c_str(), int_driver_to_port.c_str(),
|
||||
coord_str.c_str());
|
||||
}
|
||||
}
|
||||
return int_driver_id_to_add;
|
||||
}
|
||||
|
||||
ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
|
||||
const BasicPort& from_port,
|
||||
const std::string& to_port) {
|
||||
|
|
|
@ -97,6 +97,27 @@ class ClockNetwork {
|
|||
std::string spine_name(const ClockSpineId& spine_id) const;
|
||||
vtr::Point<int> spine_start_point(const ClockSpineId& spine_id) const;
|
||||
vtr::Point<int> spine_end_point(const ClockSpineId& spine_id) const;
|
||||
/* Find the intermediate drivers by the SB coordinate */
|
||||
std::vector<ClockInternalDriverId> spine_intermediate_drivers(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
|
||||
/* Find the coordinate of routing track which the intermediate driver will
|
||||
* driver. Note that the coordinate may be different than the coordinate of
|
||||
* intermeidate driver. One of the exceptions lies in the CHANX with INC
|
||||
* direction, which starts actually on the routing tracks on the right side of
|
||||
* a SB, resulting in x -> x + 1. Another exception is on the CHANY with INC
|
||||
* direction, which starts actually on the routing tracks on the top side of a
|
||||
* SB, resulting in y - > y + 1. This function is to provide an official
|
||||
* conversion the coordinates. */
|
||||
vtr::Point<int> spine_intermediate_driver_routing_track_coord(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
|
||||
/* Find the intermediate drivers by the routing track starting point. Note
|
||||
* that the routing track starting point may be different from the SB
|
||||
* coordinate. See the exceptions in the
|
||||
* spine_intermediate_driver_track_coord() */
|
||||
std::vector<ClockInternalDriverId>
|
||||
spine_intermediate_drivers_by_routing_track(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& track_coord) const;
|
||||
|
||||
/* Return the level where the spine locates in the multi-layer clock tree
|
||||
* structure */
|
||||
ClockLevelId spine_level(const ClockSpineId& spine_id) const;
|
||||
|
@ -227,6 +248,10 @@ class ClockNetwork {
|
|||
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
|
||||
const std::string& internal_driver_from_port,
|
||||
const std::string& internal_driver_to_port);
|
||||
ClockInternalDriverId add_spine_intermediate_driver(
|
||||
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
|
||||
const std::string& internal_driver_from_port,
|
||||
const std::string& internal_driver_to_port);
|
||||
ClockTapId add_tree_tap(const ClockTreeId& tree_id,
|
||||
const BasicPort& from_port,
|
||||
const std::string& to_port);
|
||||
|
@ -314,6 +339,9 @@ class ClockNetwork {
|
|||
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,
|
||||
std::map<std::string, std::vector<ClockInternalDriverId>>>
|
||||
spine_intermediate_drivers_;
|
||||
vtr::vector<ClockSpineId, ClockSpineId> spine_parents_;
|
||||
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_children_;
|
||||
vtr::vector<ClockSpineId, ClockTreeId> spine_parent_trees_;
|
||||
|
|
|
@ -21,6 +21,15 @@ constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_X = "end_x";
|
|||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_Y = "end_y";
|
||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type";
|
||||
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME =
|
||||
"intermediate_driver";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME = "tap";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X = "x";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y = "y";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN =
|
||||
"from_pin";
|
||||
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN =
|
||||
"to_pin";
|
||||
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";
|
||||
|
|
|
@ -178,6 +178,32 @@ static void read_xml_clock_spine_switch_point_internal_driver(
|
|||
int_driver_to_port_name);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <tap> to an object of ClockNetwork
|
||||
*******************************************************************/
|
||||
static void read_xml_clock_spine_intermediate_driver_tap(
|
||||
pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data,
|
||||
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
|
||||
const vtr::Point<int>& spine_coord) {
|
||||
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_from_port_name =
|
||||
get_attribute(xml_int_driver,
|
||||
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN,
|
||||
loc_data)
|
||||
.as_string();
|
||||
std::string int_driver_to_port_name =
|
||||
get_attribute(xml_int_driver,
|
||||
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
|
||||
loc_data)
|
||||
.as_string();
|
||||
clk_ntwk.add_spine_intermediate_driver(
|
||||
spine_id, spine_coord, int_driver_from_port_name, int_driver_to_port_name);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <switch_point> to an object of ClockNetwork
|
||||
*******************************************************************/
|
||||
|
@ -229,6 +255,41 @@ static void read_xml_clock_spine_switch_point(
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <driver> to an object of ClockNetwork
|
||||
*******************************************************************/
|
||||
static void read_xml_clock_spine_intermediate_driver(
|
||||
pugi::xml_node& xml_driver, const pugiutil::loc_data& loc_data,
|
||||
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id) {
|
||||
if (!clk_ntwk.valid_spine_id(spine_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_driver),
|
||||
"Invalid id of a clock spine!\n");
|
||||
}
|
||||
|
||||
int tap_x =
|
||||
get_attribute(xml_driver, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X,
|
||||
loc_data)
|
||||
.as_int();
|
||||
int tap_y =
|
||||
get_attribute(xml_driver, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y,
|
||||
loc_data)
|
||||
.as_int();
|
||||
|
||||
/* Add internal drivers if possible */
|
||||
for (pugi::xml_node xml_int_driver : xml_driver.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_int_driver.name() ==
|
||||
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME)) {
|
||||
read_xml_clock_spine_intermediate_driver_tap(
|
||||
xml_int_driver, loc_data, clk_ntwk, spine_id,
|
||||
vtr::Point<int>(tap_x, tap_y));
|
||||
} else {
|
||||
bad_tag(xml_int_driver, loc_data, xml_driver,
|
||||
{XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert string to the enumerate of model type
|
||||
*******************************************************************/
|
||||
|
@ -333,9 +394,15 @@ static void read_xml_clock_spine(pugi::xml_node& xml_spine,
|
|||
std::string(XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME)) {
|
||||
read_xml_clock_spine_switch_point(xml_switch_point, loc_data, clk_ntwk,
|
||||
spine_id);
|
||||
} else if (xml_switch_point.name() ==
|
||||
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME)) {
|
||||
read_xml_clock_spine_intermediate_driver(xml_switch_point, loc_data,
|
||||
clk_ntwk, spine_id);
|
||||
|
||||
} else {
|
||||
bad_tag(xml_switch_point, loc_data, xml_spine,
|
||||
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME});
|
||||
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME,
|
||||
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,6 +142,41 @@ static int write_xml_clock_spine_switch_point(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_xml_clock_spine_intermediate_drivers(
|
||||
std::fstream& fp, const ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
|
||||
const vtr::Point<int>& coord) {
|
||||
std::vector<ClockInternalDriverId> int_drivers =
|
||||
clk_ntwk.spine_intermediate_drivers(spine_id, coord);
|
||||
if (int_drivers.empty()) {
|
||||
return 0;
|
||||
}
|
||||
openfpga::write_tab_to_file(fp, 3);
|
||||
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << "";
|
||||
|
||||
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X,
|
||||
coord.x());
|
||||
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y,
|
||||
coord.y());
|
||||
|
||||
for (ClockInternalDriverId int_driver_id : int_drivers) {
|
||||
openfpga::write_tab_to_file(fp, 4);
|
||||
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME;
|
||||
write_xml_attribute(
|
||||
fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN,
|
||||
clk_ntwk.internal_driver_from_pin(int_driver_id).c_str());
|
||||
write_xml_attribute(fp,
|
||||
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
|
||||
clk_ntwk.internal_driver_to_pin(int_driver_id)
|
||||
.to_verilog_string()
|
||||
.c_str());
|
||||
fp << "/>"
|
||||
<< "\n";
|
||||
}
|
||||
fp << "</" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << ">\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_xml_clock_spine(std::fstream& fp, const ClockNetwork& clk_ntwk,
|
||||
const ClockSpineId& spine_id) {
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
|
@ -166,6 +201,10 @@ static int write_xml_clock_spine(std::fstream& fp, const ClockNetwork& clk_ntwk,
|
|||
fp << ">"
|
||||
<< "\n";
|
||||
|
||||
for (const vtr::Point<int>& coord : clk_ntwk.spine_coordinates(spine_id)) {
|
||||
write_xml_clock_spine_intermediate_drivers(fp, clk_ntwk, spine_id, coord);
|
||||
}
|
||||
|
||||
for (const ClockSwitchPointId& switch_point_id :
|
||||
clk_ntwk.spine_switch_points(spine_id)) {
|
||||
write_xml_clock_spine_switch_point(fp, clk_ntwk, spine_id, switch_point_id);
|
||||
|
|
|
@ -736,6 +736,67 @@ static int add_rr_graph_opin2clk_edges(
|
|||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add edges between OPIN of programmable blocks and clock routing tracks
|
||||
* Note that such edges only occur at the intermeidate points of spines
|
||||
* Different from add_rr_graph_opin2clk_edges(), we follow the clock spines
|
||||
*here By expanding on intermediate points, internal drivers will be added
|
||||
*******************************************************************/
|
||||
static int add_rr_graph_opin2clk_intermediate_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 (const vtr::Point<int>& coord :
|
||||
clk_ntwk.spine_coordinates(ispine)) {
|
||||
if (clk_ntwk.spine_intermediate_drivers(ispine, coord).empty()) {
|
||||
continue;
|
||||
}
|
||||
size_t curr_edge_count = edge_count;
|
||||
/* Get the rr node of destination spine */
|
||||
Direction des_spine_direction = clk_ntwk.spine_direction(ispine);
|
||||
ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine);
|
||||
vtr::Point<int> des_coord =
|
||||
clk_ntwk.spine_intermediate_driver_routing_track_coord(ispine,
|
||||
coord);
|
||||
RRNodeId des_node = clk_rr_lookup.find_node(
|
||||
des_coord.x(), des_coord.y(), clk_tree, des_spine_level, ipin,
|
||||
des_spine_direction, verbose);
|
||||
if (!rr_graph_view.valid_node(des_node)) {
|
||||
continue;
|
||||
}
|
||||
/* Walk through each qualified OPIN, build edges */
|
||||
std::vector<ClockInternalDriverId> int_driver_ids =
|
||||
clk_ntwk.spine_intermediate_drivers(ispine, coord);
|
||||
for (RRNodeId src_node : find_clock_opin2track_node(
|
||||
grids, rr_graph_view, layer, coord, clk_ntwk, ipin,
|
||||
int_driver_ids, verbose)) {
|
||||
/* 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 from OPINs as intermediate drivers 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
|
||||
* Walk through the routing tracks in each connection block (driver nodes)
|
||||
|
@ -812,6 +873,9 @@ static void add_rr_graph_clock_edges(
|
|||
add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create,
|
||||
clk_rr_lookup, rr_graph_view, grids, layer,
|
||||
clk_ntwk, verbose);
|
||||
add_rr_graph_opin2clk_intermediate_edges(
|
||||
rr_graph_builder, num_edges_to_create, clk_rr_lookup, rr_graph_view, grids,
|
||||
layer, clk_ntwk, verbose);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -293,6 +293,70 @@ static int route_spine_taps(
|
|||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Recursively route a clock spine on an existing routing resource graph
|
||||
*******************************************************************/
|
||||
static int route_spine_intermediate_drivers(
|
||||
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& curr_spine, const ClockTreePinId& curr_pin,
|
||||
const vtr::Point<int>& des_coord, const bool& verbose) {
|
||||
Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine);
|
||||
ClockLevelId des_spine_level = clk_ntwk.spine_level(curr_spine);
|
||||
RRNodeId des_node = clk_rr_lookup.find_node(
|
||||
des_coord.x(), des_coord.y(), clk_tree, des_spine_level, curr_pin,
|
||||
des_spine_direction, verbose);
|
||||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||
|
||||
/* Internal drivers may appear at the intermediate. 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_intermediate_drivers_by_routing_track(curr_spine, des_coord)
|
||||
.empty() &&
|
||||
tree2clk_pin_map.find(curr_pin) != tree2clk_pin_map.end()) {
|
||||
VTR_LOGV(
|
||||
verbose, "Finding intermediate drivers at (%d, %d) for spine '%s'\n",
|
||||
des_coord.x(), des_coord.y(), clk_ntwk.spine_name(curr_spine).c_str());
|
||||
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(curr_pin)) {
|
||||
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(curr_pin));
|
||||
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||
tree2clk_pin_map.at(curr_pin));
|
||||
use_int_driver++;
|
||||
VTR_LOGV(verbose,
|
||||
"Routed intermediate point of spine '%s' at "
|
||||
"(%lu, %lu) using internal driver\n",
|
||||
clk_ntwk.spine_name(curr_spine).c_str(), des_coord.x(),
|
||||
des_coord.y());
|
||||
}
|
||||
}
|
||||
if (use_int_driver > 1) {
|
||||
VTR_LOG_ERROR(
|
||||
"Found %lu internal drivers for the intermediate point (%lu, %lu) "
|
||||
"for "
|
||||
"spine '%s'!\n Expect only 1!\n",
|
||||
use_int_driver, des_coord.x(), des_coord.y(),
|
||||
clk_ntwk.spine_name(curr_spine).c_str());
|
||||
}
|
||||
return use_int_driver;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Recursively route a clock spine on an existing routing resource graph
|
||||
* The strategy is to route spine one by one
|
||||
|
@ -427,6 +491,15 @@ static int rec_expand_and_route_clock_spine(
|
|||
* The skip condition may cause this. */
|
||||
/* Skip the first stop */
|
||||
if (icoord == spine_coords.size() - 1) {
|
||||
vtr::Point<int> des_coord = spine_coords[icoord];
|
||||
|
||||
int use_int_driver = route_spine_intermediate_drivers(
|
||||
vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets,
|
||||
tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, des_coord,
|
||||
verbose);
|
||||
if (use_int_driver > 1) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Connect only when next stop is used */
|
||||
|
@ -449,6 +522,22 @@ static int rec_expand_and_route_clock_spine(
|
|||
des_spine_direction, verbose);
|
||||
VTR_ASSERT(rr_graph.valid_node(src_node));
|
||||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||
|
||||
/* Internal drivers may appear at the intermediate. 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 */
|
||||
int use_int_driver = route_spine_intermediate_drivers(
|
||||
vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets,
|
||||
tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, des_coord,
|
||||
verbose);
|
||||
if (use_int_driver > 1) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
if (use_int_driver == 1) {
|
||||
continue; /* Used internal driver, early pass. */
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose,
|
||||
"Routed backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, "
|
||||
"y=%lu)...\n",
|
||||
|
|
|
@ -262,6 +262,7 @@ run-task basic_tests/clock_network/homo_1clock_1reset_2layer_on_lut_pb_pin_fixup
|
|||
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 $@
|
||||
run-task basic_tests/clock_network/homo_1clock_1reset_2layer_intermediate_driver $@
|
||||
|
||||
echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific";
|
||||
run-task basic_tests/verific_test $@
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<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:1]">
|
||||
<spine name="clk_spine_lvl0" start_x="1" start_y="1" end_x="2" end_y="1">
|
||||
<intermediate_driver x="1" y="1">
|
||||
<tap from_pin="clb.O[0:7]" to_pin="op_clk[1:1]"/>
|
||||
</intermediate_driver>
|
||||
<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]"/>
|
||||
<all from_pin="op_clk[0:0]" to_pin="clb[0:0].I[0:11]"/>
|
||||
<all from_pin="op_clk[1:1]" 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,35 @@
|
|||
<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">
|
||||
<intermediate_driver x="1" y="1">
|
||||
<tap from_pin="clb.O[0:7]" to_pin="op_reset[0:0]"/>
|
||||
</intermediate_driver>
|
||||
<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,9 @@
|
|||
<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="OPEN"/>
|
||||
<set_io pin="op_clk[0]" net="clk_i"/>
|
||||
<set_io pin="op_clk[1]" net="int_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="int_rst"/>
|
||||
<set_io pin="op_clk[0]" net="clk_i"/>
|
||||
</pin_constraints>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<repack_design_constraints>
|
||||
<!-- Intended to be dummy -->
|
||||
</repack_design_constraints>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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_int_driver_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=32
|
||||
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=
|
||||
openfpga_vpr_constraint_file=${PATH:TASK_DIR}/config/vpr_constraint_clk_cond.xml
|
||||
|
||||
[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/clk_cond/clk_cond.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/rst_cond/rst_cond.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 = clk_cond
|
||||
bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_clk_cond.xml
|
||||
bench0_openfpga_vpr_constraint_file=${PATH:TASK_DIR}/config/vpr_constraint_clk_cond.xml
|
||||
bench0_openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer_int_driver_clk.xml
|
||||
|
||||
bench1_top = rst_cond
|
||||
bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_rst_cond.xml
|
||||
bench1_openfpga_vpr_constraint_file=${PATH:TASK_DIR}/config/vpr_constraint_rst_cond.xml
|
||||
bench1_openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer_int_driver_rst.xml
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,12 @@
|
|||
<vpr_constraints tool_name="vpr">
|
||||
<partition_list>
|
||||
<partition name="q_o_part">
|
||||
<add_atom name_pattern="q_o"/>
|
||||
<add_region x_low="2" y_low="2" x_high="2" y_high="2"/>
|
||||
</partition>
|
||||
<partition name="int_clk_part">
|
||||
<add_atom name_pattern="int_clk*"/>
|
||||
<add_region x_low="1" y_low="1" x_high="1" y_high="1"/>
|
||||
</partition>
|
||||
</partition_list>
|
||||
</vpr_constraints>
|
|
@ -0,0 +1,12 @@
|
|||
<vpr_constraints tool_name="vpr">
|
||||
<partition_list>
|
||||
<partition name="q_o_part">
|
||||
<add_atom name_pattern="q_o"/>
|
||||
<add_region x_low="2" y_low="2" x_high="2" y_high="2"/>
|
||||
</partition>
|
||||
<partition name="int_rst_part">
|
||||
<add_atom name_pattern="int_rst*"/>
|
||||
<add_region x_low="1" y_low="1" x_high="1" y_high="1"/>
|
||||
</partition>
|
||||
</partition_list>
|
||||
</vpr_constraints>
|
Loading…
Reference in New Issue