Skip to content

XDC placement constraints support for interchange #2021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
46af2d1
Initial FPGA Interchange rr_graph builder
mtdudek Nov 22, 2021
8dec6b0
RR_graph building for fpga interchange
mtdudek Nov 25, 2021
b3bc567
Small bug fixes
mtdudek Dec 20, 2021
eab6266
Fixes in rr graph generation
mtdudek Dec 20, 2021
7fc76c6
Fix unit test as testarch has 2 lut bels
mtdudek Dec 23, 2021
17298bc
Get Xilinx 7 series to work
mtdudek Dec 27, 2021
ceaf604
Reducing rr_node and rr_edge count in fpga_interchange node translati…
mtdudek Dec 31, 2021
96a2520
Add support for constant networks
mtdudek Jan 24, 2022
eb17d62
Format code
mtdudek Jan 25, 2022
6135e8f
Squashed 'libs/EXTERNAL/libinterchange/' changes from 53e3feda4..54f6…
mtdudek Jan 27, 2022
4153d2b
Misc fixes and comments
mtdudek Jan 27, 2022
5bc078d
Move common code to fpga_interchange_arch_utils
mtdudek Jan 28, 2022
94d2164
vpr: interchange: rr graph: use only routing segments
acomodi Dec 23, 2021
09c771c
interchange: rr graph: adapt to use new RR graph library
acomodi Mar 15, 2022
9264618
interchange: rr graph: cleaning code and adding comments
acomodi Mar 17, 2022
59a0c7e
interchange: arch: add alternative sites types
mtdudek Feb 4, 2022
b7745fd
interchange: fix alternative sites
mtdudek Feb 10, 2022
f2ae4e5
run make format
acomodi May 2, 2022
604a105
Added xdc_constraints.cpp
kboronski-ant Apr 6, 2022
5a89005
WIP XDC constraints
kboronski-ant Apr 8, 2022
2242ce9
XDC: improve TCL handling, associate physical pin names with grid loc…
kboronski-ant Apr 19, 2022
885153d
Refactor XDC handling, add comments, separate wrappers for tcl stuff …
kboronski-ant Apr 20, 2022
15a9d7e
USe atom block names when getting ports
kboronski-ant Apr 20, 2022
2f1d44e
WIP set_propertty IOSTANDARD, a bit of refactoring
kboronski-ant Apr 21, 2022
f28745b
Further cleanup/refactor
kboronski-ant Apr 21, 2022
09a9c6a
Fixed set_property IOSTANDARD no-return
kboronski-ant Apr 22, 2022
61ed2c2
Moved TCL C++ abstraction into libtclcpp
kboronski-ant Apr 22, 2022
e9013da
Use vpr_throw for reporting XDC errors
kboronski-ant Apr 22, 2022
0379c1d
Remove _argv0 global
kboronski-ant Apr 22, 2022
bb44f69
libtclcpp: TCL List wrapper. get_ports: return list of ports. set_pro…
kboronski-ant Apr 25, 2022
eb5d914
Indented switch/case
kboronski-ant Apr 25, 2022
d2f0b92
make format, added trait requirements for some functions in libtclcpp
kboronski-ant Apr 27, 2022
7e3299a
Added tk-dev dependency
kboronski-ant Apr 27, 2022
38ce761
throwaway: enable vtr_reg_strong test run
kboronski-ant Apr 27, 2022
6662ede
Added tk-dev to install_apt_packages.sh
kboronski-ant Apr 27, 2022
81519eb
Allow parsing multiple XDC files
kboronski-ant Apr 27, 2022
f3bf2be
libtclcpp: Added TclDynList
kboronski-ant Apr 27, 2022
9bee76d
Cleanup
kboronski-ant May 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/scripts/install_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ sudo apt install -y \
libxml++2.6-dev \
libreadline-dev \
tcl-dev \
tk-dev \
libffi-dev \
perl \
texinfo \
Expand Down
22 changes: 11 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ jobs:

Run-tests:
# Prevents from running on forks where no custom runners are available
if: ${{ github.repository_owner == 'verilog-to-routing' }}
#if: ${{ github.repository_owner == 'verilog-to-routing' }}

container: ubuntu:bionic

runs-on: [self-hosted, Linux, X64]
runs-on: ubuntu-18.04

strategy:
fail-fast: false
matrix:
include:
- {test: "vtr_reg_nightly_test1", cores: "8", options: "", cmake: "" }
- {test: "vtr_reg_nightly_test2", cores: "16", options: "", cmake: "" }
- {test: "vtr_reg_nightly_test3", cores: "16", options: "", cmake: "" }
- {test: "vtr_reg_nightly_test4", cores: "16", options: "", cmake: "" }
#- {test: "vtr_reg_nightly_test1", cores: "8", options: "", cmake: "" }
#- {test: "vtr_reg_nightly_test2", cores: "16", options: "", cmake: "" }
#- {test: "vtr_reg_nightly_test3", cores: "16", options: "", cmake: "" }
#- {test: "vtr_reg_nightly_test4", cores: "16", options: "", cmake: "" }
- {test: "vtr_reg_strong", cores: "16", options: "", cmake: "-DVTR_ASSERT_LEVEL=3" }
- {test: "vtr_reg_strong", cores: "16", options: "-skip_qor", cmake: "-DVTR_ASSERT_LEVEL=3 -DVTR_ENABLE_SANITIZE=ON"}
- {test: "vtr_reg_yosys", cores: "16", options: "", cmake: "-DWITH_YOSYS=ON" }
- {test: "vtr_reg_yosys_odin", cores: "16", options: "", cmake: "-DODIN_USE_YOSYS=ON" }
- {test: "odin_tech_strong", cores: "16", options: "", cmake: "-DODIN_USE_YOSYS=ON" }
- {test: "odin_reg_strong", cores: "16", options: "", cmake: "" }
#- {test: "vtr_reg_strong", cores: "16", options: "-skip_qor", cmake: "-DVTR_ASSERT_LEVEL=3 -DVTR_ENABLE_SANITIZE=ON"}
#- {test: "vtr_reg_yosys", cores: "16", options: "", cmake: "-DWITH_YOSYS=ON" }
#- {test: "vtr_reg_yosys_odin", cores: "16", options: "", cmake: "-DODIN_USE_YOSYS=ON" }
#- {test: "odin_tech_strong", cores: "16", options: "", cmake: "-DODIN_USE_YOSYS=ON" }
#- {test: "odin_reg_strong", cores: "16", options: "", cmake: "" }

env:
DEBIAN_FRONTEND: "noninteractive"
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/libs/libvtrutil")
list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/libs/libpugiutil")
list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/libs/liblog")
list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/libs/librtlnumber")
list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/libs/libtclcpp")
list(APPEND DIRS_TO_FORMAT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/ODIN_II")

include(AutoClangFormat)
Expand Down
1 change: 1 addition & 0 deletions install_apt_packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ sudo apt-get install -y \
sudo apt-get install -y \
clang \
tcl-dev \
tk-dev \
libreadline-dev

# Required to build the documentation
Expand Down
1 change: 1 addition & 0 deletions libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ if(${VTR_ENABLE_CAPNPROTO})
add_subdirectory(libvtrcapnproto)
endif()
add_subdirectory(librrgraph)
add_subdirectory(libtclcpp)
17 changes: 6 additions & 11 deletions libs/EXTERNAL/libinterchange/interchange/DeviceResources.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ annotation wireRef(*) :WireRef;
using WireIdx = UInt32;

struct WireTypeRef {
type @0 :Ref.ReferenceType = parent;
type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "wireTypes";
depth @2 :Int32 = 1;
}
annotation wireTypeRef(*) :WireTypeRef;
using WireTypeIdx = UInt32;
Expand All @@ -81,19 +80,15 @@ using TileTypeSiteTypeIdx = UInt32;
using TileTypeSubTileIdx = UInt16;

struct PIPTimingRef {
type @0 :Ref.ReferenceType = parent;
field @1 :Text = "pipTimingList";
depth @2 :Int32 = 1;

type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "pipTimings";
}
annotation pipTimingRef(*) :PIPTimingRef;
using PipTimingIdx = UInt32;

struct NodeTimingRef {
type @0 :Ref.ReferenceType = parent;
field @1 :Text = "nodeTimingList";
depth @2 :Int32 = 1;

type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "nodeTimings";
}
annotation nodeTimingRef(*) :NodeTimingRef;
using NodeTimingIdx = UInt32;
Expand Down Expand Up @@ -632,7 +627,7 @@ struct Device {
}

struct PinDelay {
pin @0 : BELPinIdx $belPinRef();
pin @0 : BELPinIdx;
union {
noClock @1 : Void;
clockEdge @2 : ClockEdge;
Expand Down
185 changes: 185 additions & 0 deletions libs/libarchfpga/src/fpga_interchange_arch_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#include "fpga_interchange_arch_utils.h"

/****************** Utility functions ******************/

/**
* @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two
* speed_models (slow and fast).
*
* Timing data can be found on PIPs, nodes, site pins and bel pins.
* This function retrieves the timing value based on the wanted speed model and the wanted corner.
*
* Corner model is considered valid if at least one configuration is set.
* In that case this value shall be returned.
*
* More information on the FPGA Interchange timing model can be found here:
* - https://github.com/chipsalliance/fpga-interchange-schema/blob/main/interchange/DeviceResources.capnp
*/

float get_corner_value(DeviceResources::Device::CornerModel::Reader model, const char* speed_model, const char* value) {
bool slow_model = std::string(speed_model) == std::string("slow");
bool fast_model = std::string(speed_model) == std::string("fast");

bool min_corner = std::string(value) == std::string("min");
bool typ_corner = std::string(value) == std::string("typ");
bool max_corner = std::string(value) == std::string("max");

if (!slow_model && !fast_model) {
archfpga_throw("", __LINE__, "Wrong speed model `%s`. Expected `slow` or `fast`\n", speed_model);
}

if (!min_corner && !typ_corner && !max_corner) {
archfpga_throw("", __LINE__, "Wrong corner model `%s`. Expected `min`, `typ` or `max`\n", value);
}

bool has_fast = model.getFast().hasFast();
bool has_slow = model.getSlow().hasSlow();

if ((slow_model || (fast_model && !has_fast)) && has_slow) {
auto half = model.getSlow().getSlow();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__, "Invalid speed model %s. No value found!\n", speed_model);
}
}
} else if ((fast_model || slow_model) && has_fast) {
auto half = model.getFast().getFast();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__, "Invalid speed model %s. No value found!\n", speed_model);
}
}
}
return 0.;
}

char* int_to_string(char* buff, int value) {
if (value < 10) {
return &(*buff = '0' + value) + 1;
} else {
return &(*int_to_string(buff, value / 10) = '0' + value % 10) + 1;
}
}

void pip_types(std::set<std::tuple<int, bool>>& seen,
DeviceResources::Device::Reader ar_) {
for (const auto& tile : ar_.getTileTypeList()) {
for (const auto& pip : tile.getPips()) {
/*
* FIXME
* right now we allow for pseudo pips even tho we don't check if they are avaiable
* if (pip.isPseudoCells())
* continue;
*/
seen.emplace(pip.getTiming(), pip.getBuffered21());
if (!pip.getDirectional()) {
seen.emplace(pip.getTiming(), pip.getBuffered20());
}
}
}
}

void fill_switch(t_arch_switch_inf* switch_,
float R,
float Cin,
float Cout,
float Cinternal,
float Tdel,
float mux_trans_size,
float buf_size,
char* name,
SwitchType type) {
switch_->R = R;
switch_->Cin = Cin;
switch_->Cout = Cout;
switch_->Cinternal = Cinternal;
switch_->set_Tdel(t_arch_switch_inf::UNDEFINED_FANIN, Tdel);
switch_->mux_trans_size = mux_trans_size;
switch_->buf_size = buf_size;
switch_->name = name;
switch_->set_type(type);
}

void process_cell_bel_mappings(DeviceResources::Device::Reader ar_,
std::unordered_map<uint32_t, std::set<t_bel_cell_mapping>>& bel_cell_mappings_,
std::function<std::string(size_t)> str) {
auto primLib = ar_.getPrimLibs();
auto portList = primLib.getPortList();

for (auto cell_mapping : ar_.getCellBelMap()) {
size_t cell_name = cell_mapping.getCell();

int found_valid_prim = false;
for (auto primitive : primLib.getCellDecls()) {
if (cell_name != primitive.getName()) continue;
if (str(primitive.getLib()) != std::string("primitives")) continue;

bool has_inout = false;
for (auto port_idx : primitive.getPorts()) {
auto port = portList[port_idx];

if (port.getDir() == INOUT) {
has_inout = true;
break;
}
}

if (!has_inout) {
found_valid_prim = true;
break;
}
}

if (!found_valid_prim)
continue;

for (auto common_pins : cell_mapping.getCommonPins()) {
std::vector<std::pair<size_t, size_t>> pins;

for (auto pin_map : common_pins.getPins())
pins.emplace_back(pin_map.getCellPin(), pin_map.getBelPin());

for (auto site_type_entry : common_pins.getSiteTypes()) {
size_t site_type = site_type_entry.getSiteType();

for (auto bel : site_type_entry.getBels()) {
t_bel_cell_mapping mapping;

mapping.cell = cell_name;
mapping.site = site_type;
mapping.pins = pins;

std::set<t_bel_cell_mapping> maps{mapping};
auto res = bel_cell_mappings_.emplace(bel, maps);
if (!res.second) {
res.first->second.insert(mapping);
}
}
}
}
}
}
98 changes: 98 additions & 0 deletions libs/libarchfpga/src/fpga_interchange_arch_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#ifndef FPGAINTERCHANGE_ARCH_UTILS_FILE_H
#define FPGAINTERCHANGE_ARCH_UTILS_FILE_H

#include "arch_types.h"
#include "arch_util.h"
#include "arch_error.h"
#include "vtr_error.h"
#include "vtr_util.h"

#include "DeviceResources.capnp.h"
#include "LogicalNetlist.capnp.h"
#include "capnp/serialize.h"
#include "capnp/serialize-packed.h"
#include <fcntl.h>
#include <unistd.h>
#include <set>
#include <string>

#ifdef __cplusplus
extern "C" {
#endif

// Necessary to reduce code verbosity when getting the pin directions
static const auto INPUT = LogicalNetlist::Netlist::Direction::INPUT;
static const auto OUTPUT = LogicalNetlist::Netlist::Direction::OUTPUT;
static const auto INOUT = LogicalNetlist::Netlist::Direction::INOUT;

struct t_bel_cell_mapping {
size_t cell;
size_t site;
std::vector<std::pair<size_t, size_t>> pins;

bool operator<(const t_bel_cell_mapping& other) const {
return cell < other.cell || (cell == other.cell && site < other.site);
}
};

/****************** Utility functions ******************/

/**
* @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two
* speed_models (slow and fast).
*
* Timing data can be found on PIPs, nodes, site pins and bel pins.
* This function retrieves the timing value based on the wanted speed model and the wanted corner.
*
* Corner model is considered valid if at least one configuration is set.
* In that case this value shall be returned.
*
* More information on the FPGA Interchange timing model can be found here:
* - https://github.com/chipsalliance/fpga-interchange-schema/blob/main/interchange/DeviceResources.capnp
*/

float get_corner_value(DeviceResources::Device::CornerModel::Reader model, const char* speed_model, const char* value);

char* int_to_string(char* buff, int value);

void pip_types(std::set<std::tuple<int, bool>>& seen,
DeviceResources::Device::Reader ar_);

void process_cell_bel_mappings(DeviceResources::Device::Reader ar_,
std::unordered_map<uint32_t, std::set<t_bel_cell_mapping>>& bel_cell_mappings_,
std::function<std::string(size_t)> str);

#ifdef __cplusplus
}
#endif
template<typename T>
void fill_switch(T* switch_,
float R,
float Cin,
float Cout,
float Cinternal,
float Tdel,
float mux_trans_size,
float buf_size,
char* name,
SwitchType type);

void fill_switch(t_arch_switch_inf* switch_,
float R,
float Cin,
float Cout,
float Cinternal,
float Tdel,
float mux_trans_size,
float buf_size,
char* name,
SwitchType type);

template<typename T1, typename T2>
void process_switches_array(DeviceResources::Device::Reader ar_,
std::set<std::tuple<int, bool>>& seen,
T1 switch_array,
std::vector<std::tuple<std::tuple<int, bool>, int>>& pips_models_);

#include "fpga_interchange_arch_utils.impl.h"
#endif
Loading