Remove fpga_interchange

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2024-09-30 11:32:41 +02:00 committed by myrtle
parent 1967db170d
commit fcdaf3f86c
135 changed files with 2 additions and 20757 deletions

View File

@ -1,64 +0,0 @@
#!/bin/bash
# Install capnproto libraries
function build_capnp {
curl -O https://capnproto.org/capnproto-c++-0.8.0.tar.gz
tar zxf capnproto-c++-0.8.0.tar.gz
pushd capnproto-c++-0.8.0
./configure
make -j`nproc` check
sudo make install
popd
git clone https://github.com/capnproto/capnproto-java.git
pushd capnproto-java
make -j`nproc`
sudo make install
popd
}
# Install latest Yosys
function build_yosys {
DESTDIR=`pwd`/.yosys
pushd yosys
make -j`nproc`
sudo make install DESTDIR=$DESTDIR
popd
}
function get_dependencies {
# Install python-fpga-interchange libraries
git clone -b ${PYTHON_INTERCHANGE_TAG} https://github.com/SymbiFlow/python-fpga-interchange.git ${PYTHON_INTERCHANGE_PATH}
pushd ${PYTHON_INTERCHANGE_PATH}
git submodule update --init --recursive
python3 -m pip install -r requirements.txt
popd
if [ ${DEVICE} == "LIFCL-17" ] || [ ${DEVICE} == "LIFCL-40" ]; then
# Install prjoxide
curl --proto '=https' -sSf https://sh.rustup.rs | sh -s -- -y
git clone --recursive https://github.com/gatecat/prjoxide.git
pushd prjoxide/libprjoxide
# TODO: use a tag instead of a commit, like python-fpga-interchange
git reset --hard ${PRJOXIDE_REVISION}
PATH=$PATH:$HOME/.cargo/bin cargo install --path prjoxide --all-features
popd
else
# Install RapidWright
git clone https://github.com/Xilinx/RapidWright.git ${RAPIDWRIGHT_PATH}
pushd ${RAPIDWRIGHT_PATH}
./gradlew updateJars --no-watch-fs
make compile
popd
fi
}
function build_nextpnr {
build_capnp
mkdir build
pushd build
cmake .. -DARCH=fpga_interchange -DRAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH} -DPYTHON_INTERCHANGE_PATH=${PYTHON_INTERCHANGE_PATH} -DWERROR=on
make nextpnr-fpga_interchange -j`nproc`
popd
}

View File

@ -1,132 +0,0 @@
name: FPGA interchange CI tests
on: [push, pull_request]
jobs:
Build-yosys:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
- name: Install
run: |
sudo apt-get update
sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig locales libtinfo-dev
- name: ccache
uses: hendrikmuhs/ccache-action@v1
- name: Get yosys
run: |
git clone https://github.com/YosysHQ/yosys.git
cd yosys
echo "YOSYS_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Cache yosys installation
uses: actions/cache@v2
id: cache-yosys
with:
path: .yosys
key: cache-yosys-${{ env.YOSYS_SHA }}
- name: Build yosys
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
source ./.github/ci/build_interchange.sh
build_yosys
if: steps.cache-yosys.outputs.cache-hit != 'true'
Build-nextpnr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
- name: Install
run: |
sudo apt-get update
sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig
- name: ccache
uses: hendrikmuhs/ccache-action@v1
- name: Execute build nextpnr
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
source ./.github/ci/build_interchange.sh
build_nextpnr
Run-Tests:
runs-on: ubuntu-latest
needs: [Build-yosys, Build-nextpnr]
strategy:
# Don't terminate jobs when one fails. This is important when
# debugging CI failures.
fail-fast: false
matrix:
device: [xc7a35t, xc7a100t, xc7a200t, xc7z010, LIFCL-17, LIFCL-40]
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
- name: Install
run: |
sudo apt-get update
sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig
- name: ccache
uses: hendrikmuhs/ccache-action@v1
- name: Get yosys
run: |
git clone https://github.com/YosysHQ/yosys.git
cd yosys
echo "YOSYS_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Cache yosys installation
uses: actions/cache@v2
id: cache-yosys
with:
path: .yosys
key: cache-yosys-${{ env.YOSYS_SHA }}
- name: Build yosys
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
source ./.github/ci/build_interchange.sh
build_yosys
if: steps.cache-yosys.outputs.cache-hit != 'true'
- name: Execute build interchange script
env:
RAPIDWRIGHT_PATH: ${{ github.workspace }}/RapidWright
PYTHON_INTERCHANGE_PATH: ${{ github.workspace }}/python-fpga-interchange
PYTHON_INTERCHANGE_TAG: v0.0.20
PRJOXIDE_REVISION: 318331f8b30c2e2a31cc41d51f104b671e180a8a
DEVICE: ${{ matrix.device }}
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
source ./.github/ci/build_interchange.sh
build_nextpnr && get_dependencies
- name: Run tests
env:
DEVICE: ${{ matrix.device }}
run: |
export PATH="$GITHUB_WORKSPACE/.yosys/usr/local/bin:$PATH"
which yosys
cd build
make all-$DEVICE-tests -j`nproc`

3
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "tests"]
path = tests
url = https://github.com/YosysHQ/nextpnr-tests
[submodule "fpga-interchange-schema"]
path = 3rdparty/fpga-interchange-schema
url = https://github.com/SymbiFlow/fpga-interchange-schema.git
[submodule "himbaechel/uarch/xilinx/meta"]
path = himbaechel/uarch/xilinx/meta
url = https://github.com/gatecat/nextpnr-xilinx-meta

@ -1 +0,0 @@
Subproject commit 6b2973788692be86c4a8b2cff1353e603e5857a3

View File

@ -108,9 +108,9 @@ endif()
set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables")
# List of families to build
set(FAMILIES generic ice40 ecp5 nexus gowin fpga_interchange machxo2 mistral himbaechel)
set(FAMILIES generic ice40 ecp5 nexus gowin machxo2 mistral himbaechel)
set(STABLE_FAMILIES generic ice40 ecp5)
set(EXPERIMENTAL_FAMILIES nexus gowin fpga_interchange machxo2 mistral himbaechel)
set(EXPERIMENTAL_FAMILIES nexus gowin machxo2 mistral himbaechel)
set(ARCH "" CACHE STRING "Architecture family for nextpnr build")
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})

View File

@ -1,78 +0,0 @@
## FPGA interchange nextpnr architecture
This nextpnr architecture is a meta architecture that in theory will implement
any architecture that emits a complete FPGA interchange device database.
### FPGA interchange
The FPGA interchange is a set of file formats intended to describe any modern
island based FPGA. It consists of three primary file formats:
- Device database
- This is a description of a particular FPGA fabric. This description
includes placement locations, placement constraints and a complete
description of the routing fabric.
- This file will also include timing information once added.
- Logical netlist
- This is the output of a synthesis tool. This is equivalent to the
Yosys JSON format, EDIF, or eblif.
- As part of future nextpnr development, a frontend will be added that
takes this format as input.
- Physical netlist
- This is the output of a place and route tool. It can describe a clustered
design, a partially or fully placed design, and a partially or fully
routed design.
### Current development status
This architecture implementation can be compiled in conjunction with a FPGA
interchange device database, and the outputs from
`fpga_interchange.nextpnr_emit`, which is part of the
[python-fpga-interchange](https://github.com/SymbiFlow/python-fpga-interchange/)
library.
The current implementation is missing essential features for place and route.
As these features are added, this implementation will become more useful.
- [ ] Logical netlist macro expansion is not implemented, meaning that any
macro primitives are unplaceable. Common macro primitives examples are
differential IO buffers (IBUFDS) and some LUT RAM (e.g. RAM64X1D).
- [ ] Timing information is missing from the FPGA interchange device
database, so it is also currently missing from the FPGA interchange
architecture. Once timing information is added to the device database
#### Weaknesses of current implementation
Initial development on the following features is started, but needs more
refinement.
- [ ] BEL validity checking is too expensive. The majority of the runtime
is currently in the LUT rotation. Profiling, optimization and
algorithm review is likely required to bring strict legalisation
runtimes into expected levels.
- [ ] The router lookahead is disabled by default. Without the lookahead,
router runtime is terrible. However the current lookahead
implementation is slow to compute and memory intensive, hence why it is
disabled by default.
- [ ] Pseudo pips (e.g. pips that consume BELs and or site resources) and
pseudo site pips (e.g. site pips that route through BELs) consume site
wires to indicate that they block some resources. This covers many
validity check cases, but misses some. In particular, when a pseudo
pip / pseudo site pip has an implication on the constraint system (e.g.
LUT on a LUT-RAM BEL), an edge may be allowed incorrectly, resulting
in an illegal design.
### FPGA interchange fabrics
Xilinx 7-series, UltraScale and UltraScale+ fabrics have a
device database generator, via [RapidWright](https://github.com/Xilinx/RapidWright).
A Lattice Nexus device database is being worked on, via
[prjoxide](https://github.com/gatecat/prjoxide).
### FPGA interchange build system
Construction of chipdb's is currently integrated into nextpnr's CMake build
system. See fpga\_interchange/examples/README.md for more details.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,497 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef ARCH_ITERATORS_H
#define ARCH_ITERATORS_H
#include "chipdb.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
NEXTPNR_NAMESPACE_BEGIN
struct BelIterator
{
const ChipInfoPOD *chip;
int cursor_index;
int cursor_tile;
BelIterator operator++()
{
cursor_index++;
while (cursor_tile < chip->tiles.ssize() && cursor_index >= tile_info(chip, cursor_tile).bel_data.ssize()) {
cursor_index = 0;
cursor_tile++;
}
return *this;
}
BelIterator operator++(int)
{
BelIterator prior(*this);
++(*this);
return prior;
}
bool operator!=(const BelIterator &other) const
{
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
}
bool operator==(const BelIterator &other) const
{
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
}
BelId operator*() const
{
BelId ret;
ret.tile = cursor_tile;
ret.index = cursor_index;
return ret;
}
};
struct BelRange
{
BelIterator b, e;
BelIterator begin() const { return b; }
BelIterator end() const { return e; }
};
struct FilteredBelIterator
{
std::function<bool(BelId)> filter;
BelIterator b, e;
FilteredBelIterator operator++()
{
++b;
while (b != e) {
if (filter(*b)) {
break;
}
++b;
}
return *this;
}
bool operator!=(const FilteredBelIterator &other) const
{
NPNR_ASSERT(e == other.e);
return b != other.b;
}
bool operator==(const FilteredBelIterator &other) const
{
NPNR_ASSERT(e == other.e);
return b == other.b;
}
BelId operator*() const
{
BelId bel = *b;
NPNR_ASSERT(filter(bel));
return bel;
}
};
struct FilteredBelRange
{
FilteredBelRange(BelIterator bel_b, BelIterator bel_e, std::function<bool(BelId)> filter)
{
b.filter = filter;
b.b = bel_b;
b.e = bel_e;
if (b.b != b.e && !filter(*b.b)) {
++b;
}
e.b = bel_e;
e.e = bel_e;
if (b != e) {
NPNR_ASSERT(filter(*b.b));
}
}
FilteredBelIterator b, e;
FilteredBelIterator begin() const { return b; }
FilteredBelIterator end() const { return e; }
};
// -----------------------------------------------------------------------
// Iterate over TileWires for a wire (will be more than one if nodal)
struct TileWireIterator
{
const ChipInfoPOD *chip;
WireId baseWire;
int cursor = -1;
void operator++() { cursor++; }
bool operator==(const TileWireIterator &other) const { return cursor == other.cursor; }
bool operator!=(const TileWireIterator &other) const { return cursor != other.cursor; }
// Returns a *denormalised* identifier always pointing to a tile wire rather than a node
WireId operator*() const
{
if (baseWire.tile == -1) {
WireId tw;
const auto &node_wire = chip->nodes[baseWire.index].tile_wires[cursor];
tw.tile = node_wire.tile;
tw.index = node_wire.index;
return tw;
} else {
return baseWire;
}
}
};
struct TileWireRange
{
TileWireIterator b, e;
TileWireIterator begin() const { return b; }
TileWireIterator end() const { return e; }
};
NPNR_ALWAYS_INLINE inline WireId canonical_wire(const ChipInfoPOD *chip_info, int32_t tile, int32_t wire)
{
WireId id;
if (wire >= chip_info->tiles[tile].tile_wire_to_node.ssize()) {
// Cannot be a nodal wire
id.tile = tile;
id.index = wire;
} else {
int32_t node = chip_info->tiles[tile].tile_wire_to_node[wire];
if (node == -1) {
// Not a nodal wire
id.tile = tile;
id.index = wire;
} else {
// Is a nodal wire, set tile to -1
id.tile = -1;
id.index = node;
}
}
return id;
}
// -----------------------------------------------------------------------
struct WireIterator
{
const ChipInfoPOD *chip;
int cursor_index = 0;
int cursor_tile = -1;
WireIterator operator++()
{
// Iterate over nodes first, then tile wires that aren't nodes
do {
cursor_index++;
if (cursor_tile == -1 && cursor_index >= chip->nodes.ssize()) {
cursor_tile = 0;
cursor_index = 0;
}
while (cursor_tile != -1 && cursor_tile < chip->tiles.ssize() &&
cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].wire_data.ssize()) {
cursor_index = 0;
cursor_tile++;
}
} while ((cursor_tile != -1 && cursor_tile < chip->tiles.ssize() &&
cursor_index < chip->tiles[cursor_tile].tile_wire_to_node.ssize() &&
chip->tiles[cursor_tile].tile_wire_to_node[cursor_index] != -1));
return *this;
}
WireIterator operator++(int)
{
WireIterator prior(*this);
++(*this);
return prior;
}
bool operator!=(const WireIterator &other) const
{
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
}
bool operator==(const WireIterator &other) const
{
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
}
WireId operator*() const
{
WireId ret;
ret.tile = cursor_tile;
ret.index = cursor_index;
return ret;
}
};
struct WireRange
{
WireIterator b, e;
WireIterator begin() const { return b; }
WireIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct AllPipIterator
{
const ChipInfoPOD *chip;
int cursor_index;
int cursor_tile;
AllPipIterator operator++()
{
cursor_index++;
while (cursor_tile < chip->tiles.ssize() &&
cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].pip_data.ssize()) {
cursor_index = 0;
cursor_tile++;
}
return *this;
}
AllPipIterator operator++(int)
{
AllPipIterator prior(*this);
++(*this);
return prior;
}
bool operator!=(const AllPipIterator &other) const
{
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
}
bool operator==(const AllPipIterator &other) const
{
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
}
PipId operator*() const
{
PipId ret;
ret.tile = cursor_tile;
ret.index = cursor_index;
return ret;
}
};
struct AllPipRange
{
AllPipIterator b, e;
AllPipIterator begin() const { return b; }
AllPipIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct UphillPipIterator
{
const ChipInfoPOD *chip;
TileWireIterator twi, twi_end;
int cursor = -1;
void operator++()
{
cursor++;
while (true) {
if (!(twi != twi_end))
break;
WireId w = *twi;
auto &tile = chip->tile_types[chip->tiles[w.tile].type];
if (cursor < tile.wire_data[w.index].pips_uphill.ssize())
break;
++twi;
cursor = 0;
}
}
bool operator!=(const UphillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; }
PipId operator*() const
{
PipId ret;
WireId w = *twi;
ret.tile = w.tile;
ret.index = chip->tile_types[chip->tiles[w.tile].type].wire_data[w.index].pips_uphill[cursor];
return ret;
}
};
struct UphillPipRange
{
UphillPipIterator b, e;
UphillPipIterator begin() const { return b; }
UphillPipIterator end() const { return e; }
};
struct DownhillPipIterator
{
const ChipInfoPOD *chip;
TileWireIterator twi, twi_end;
int cursor = -1;
int32_t tile;
int32_t tile_type;
const RelSlice<int32_t> *pips_downhill = nullptr;
void operator++()
{
cursor++;
while (true) {
if (!(twi != twi_end))
break;
if (pips_downhill == nullptr) {
WireId w = *twi;
tile_type = chip->tiles[w.tile].type;
const TileTypeInfoPOD &type = chip->tile_types[tile_type];
tile = w.tile;
pips_downhill = &type.wire_data[w.index].pips_downhill;
}
if (cursor < pips_downhill->ssize())
break;
++twi;
cursor = 0;
pips_downhill = nullptr;
}
}
bool operator!=(const DownhillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; }
PipId operator*() const
{
PipId ret;
ret.tile = tile;
ret.index = (*pips_downhill)[cursor];
return ret;
}
};
struct DownhillPipRange
{
DownhillPipIterator b, e;
DownhillPipIterator begin() const { return b; }
DownhillPipIterator end() const { return e; }
};
struct BelPinIterator
{
const ChipInfoPOD *chip;
TileWireIterator twi, twi_end;
int cursor = -1;
void operator++()
{
cursor++;
while (twi != twi_end) {
WireId w = *twi;
auto &tile = tile_info(chip, w.tile);
if (cursor < tile.wire_data[w.index].bel_pins.ssize())
break;
++twi;
cursor = 0;
}
}
bool operator!=(const BelPinIterator &other) const { return twi != other.twi || cursor != other.cursor; }
BelPin operator*() const
{
BelPin ret;
WireId w = *twi;
ret.bel.tile = w.tile;
ret.bel.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].bel_index;
ret.pin.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].port;
return ret;
}
};
struct BelPinRange
{
BelPinIterator b, e;
BelPinIterator begin() const { return b; }
BelPinIterator end() const { return e; }
};
struct IdStringIterator : std::iterator<std::forward_iterator_tag,
/*T=*/IdString,
/*Distance=*/ptrdiff_t,
/*pointer=*/IdString *,
/*reference=*/IdString>
{
const int32_t *cursor;
void operator++() { cursor += 1; }
bool operator!=(const IdStringIterator &other) const { return cursor != other.cursor; }
bool operator==(const IdStringIterator &other) const { return cursor == other.cursor; }
IdString operator*() const { return IdString(*cursor); }
};
struct IdStringRange
{
IdStringIterator b, e;
IdStringIterator begin() const { return b; }
IdStringIterator end() const { return e; }
};
struct BelBucketIterator
{
IdStringIterator cursor;
void operator++() { ++cursor; }
bool operator!=(const BelBucketIterator &other) const { return cursor != other.cursor; }
bool operator==(const BelBucketIterator &other) const { return cursor == other.cursor; }
BelBucketId operator*() const
{
BelBucketId bucket;
bucket.name = IdString(*cursor);
return bucket;
}
};
struct BelBucketRange
{
BelBucketIterator b, e;
BelBucketIterator begin() const { return b; }
BelBucketIterator end() const { return e; }
};
NEXTPNR_NAMESPACE_END
#endif /* ARCH_ITERATORS_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,356 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "log.h"
#include "nextpnr.h"
#include "util.h"
#include <queue>
NEXTPNR_NAMESPACE_BEGIN
namespace {
bool search_routing_for_placement(Arch *arch, WireId start_wire, CellInfo *cell, IdString cell_pin, bool downhill)
{
std::queue<WireId> visit_queue;
pool<WireId> already_visited;
visit_queue.push(start_wire);
already_visited.insert(start_wire);
int iter = 0;
while (!visit_queue.empty() && iter++ < 1000) {
WireId next = visit_queue.front();
visit_queue.pop();
for (auto bp : arch->getWireBelPins(next)) {
if (!arch->isValidBelForCellType(cell->type, bp.bel))
continue;
if (!arch->checkBelAvail(bp.bel))
continue;
// We need to do a test placement to update the bel pin map
arch->bindBel(bp.bel, cell, STRENGTH_FIXED);
for (IdString bel_pin : arch->getBelPinsForCellPin(cell, cell_pin)) {
if (bel_pin == bp.pin)
return true;
}
// Bel pin doesn't match
arch->unbindBel(bp.bel);
}
auto do_visit = [&](PipId pip) {
WireId dst = downhill ? arch->getPipDstWire(pip) : arch->getPipSrcWire(pip);
if (already_visited.count(dst))
return;
visit_queue.push(dst);
already_visited.insert(dst);
};
if (downhill) {
for (auto pip : arch->getPipsDownhill(next))
do_visit(pip);
} else {
for (auto pip : arch->getPipsUphill(next))
do_visit(pip);
}
}
return false;
}
} // namespace
void Arch::place_iobufs(WireId pad_wire, NetInfo *net,
const dict<CellInfo *, IdString, hash_ptr_ops> &tightly_attached_bels,
pool<CellInfo *, hash_ptr_ops> *placed_cells)
{
Context *ctx = getCtx();
for (auto cell_port : tightly_attached_bels) {
bool downhill = (cell_port.first->ports.at(cell_port.second).type != PORT_OUT);
if (cell_port.first->bel != BelId())
continue;
if (search_routing_for_placement(this, pad_wire, cell_port.first, cell_port.second, downhill)) {
if (ctx->verbose)
log_info("Placed IO cell %s:%s at %s.\n", ctx->nameOf(cell_port.first),
ctx->nameOf(cell_port.first->type), ctx->nameOfBel(cell_port.first->bel));
placed_cells->insert(cell_port.first);
}
}
// Also try, on a best-effort basis, to preplace other cells in the macro based on downstream routing. This is
// needed for the split INBUF+IBUFCTRL arrangement in the UltraScale+, as just placing the INBUF will result in an
// unrouteable site and illegal placement.
std::queue<CellInfo *> place_queue;
for (auto pc : *placed_cells)
place_queue.push(pc);
while (!place_queue.empty()) {
CellInfo *cursor = place_queue.front();
place_queue.pop();
// Ignore cells not part of a macro
if (cursor->macro_parent == IdString())
continue;
for (auto &port : cursor->ports) {
// Only consider routing downstream from outputs for now
if (port.second.net == nullptr)
continue;
NetInfo *ni = port.second.net;
if (port.second.type == PORT_OUT) {
WireId src_wire = ctx->getNetinfoSourceWire(ni);
for (auto &usr : ni->users) {
// Look for unplaced users in the same macro
if (usr.cell->bel != BelId() || usr.cell->macro_parent != cursor->macro_parent)
continue;
// Try and place using dedicated routing
if (search_routing_for_placement(this, src_wire, usr.cell, usr.port, true)) {
// Successful
placed_cells->insert(usr.cell);
place_queue.push(usr.cell);
if (ctx->verbose)
log_info("Placed %s at %s based on dedicated IO macro routing.\n", ctx->nameOf(usr.cell),
ctx->nameOfBel(usr.cell->bel));
}
}
} else {
auto &drv = ni->driver;
// Look for unplaced driver in the same macro
if (drv.cell->bel != BelId() || drv.cell->macro_parent != cursor->macro_parent)
continue;
for (auto bel_pin : ctx->getBelPinsForCellPin(cursor, port.first)) {
// Try and place using dedicated routing
WireId dst_wire = ctx->getBelPinWire(cursor->bel, bel_pin);
if (search_routing_for_placement(this, dst_wire, drv.cell, drv.port, false)) {
// Successful
placed_cells->insert(drv.cell);
place_queue.push(drv.cell);
if (ctx->verbose)
log_info("Placed %s at %s based on dedicated IO macro routing.\n", ctx->nameOf(drv.cell),
ctx->nameOfBel(drv.cell->bel));
}
}
}
}
}
// TODO: for even more complex cases, if any future devices hit them, we probably should do a full validity check of
// all placed cells here, and backtrack and try a different placement if the first one we choose isn't legal overall
}
void Arch::pack_ports()
{
dict<IdString, const TileInstInfoPOD *> tile_type_prototypes;
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
const auto &tile = chip_info->tiles[i];
const auto &tile_type = chip_info->tile_types[tile.type];
IdString tile_type_name(tile_type.name);
tile_type_prototypes.emplace(tile_type_name, &tile);
}
// set(site_types) for package pins
pool<IdString> package_sites;
// Package pin -> (Site type -> BelId)
dict<IdString, std::vector<std::pair<IdString, BelId>>> package_pin_bels;
// Placed cells across all IO
pool<CellInfo *, hash_ptr_ops> all_placed_io;
for (const PackagePinPOD &package_pin : chip_info->packages[package_index].pins) {
IdString pin(package_pin.package_pin);
IdString bel(package_pin.bel);
IdString site(package_pin.site);
package_sites.emplace(site);
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
const auto &tile = chip_info->tiles[i];
pool<uint32_t> package_pin_sites;
for (size_t j = 0; j < tile.sites.size(); ++j) {
auto &site_data = chip_info->sites[tile.sites[j]];
if (site == id(site_data.site_name.get())) {
package_pin_sites.emplace(j);
}
}
const auto &tile_type = chip_info->tile_types[tile.type];
for (size_t j = 0; j < tile_type.bel_data.size(); ++j) {
const BelInfoPOD &bel_data = tile_type.bel_data[j];
if (bel == IdString(bel_data.name) && package_pin_sites.count(bel_data.site)) {
auto &site_data = chip_info->sites[tile.sites[bel_data.site]];
IdString site_type(site_data.site_type);
BelId bel;
bel.tile = i;
bel.index = j;
package_pin_bels[pin].push_back(std::make_pair(site_type, bel));
}
}
}
}
// Determine for each package site type, which site types are possible.
pool<IdString> package_pin_site_types;
dict<IdString, pool<IdString>> possible_package_site_types;
for (const TileInstInfoPOD &tile : chip_info->tiles) {
for (size_t site_index : tile.sites) {
const SiteInstInfoPOD &site = chip_info->sites[site_index];
IdString site_name = getCtx()->id(site.site_name.get());
if (package_sites.count(site_name) == 1) {
possible_package_site_types[site_name].emplace(IdString(site.site_type));
package_pin_site_types.emplace(IdString(site.site_type));
}
}
}
// IO sites are usually pretty weird, so see if we can define some
// constraints between the port cell create by nextpnr and cells that are
// immediately attached to that port cell.
for (auto port_pair : port_cells) {
IdString port_name = port_pair.first;
CellInfo *port_cell = port_pair.second;
dict<CellInfo *, IdString, hash_ptr_ops> tightly_attached_bels;
for (auto port_pair : port_cell->ports) {
const PortInfo &port_info = port_pair.second;
const NetInfo *net = port_info.net;
if (net->driver.cell) {
tightly_attached_bels.emplace(net->driver.cell, net->driver.port);
}
for (const PortRef &port_ref : net->users) {
if (port_ref.cell) {
tightly_attached_bels.emplace(port_ref.cell, port_ref.port);
}
}
}
if (getCtx()->verbose) {
log_info("Tightly attached BELs for port %s\n", port_name.c_str(getCtx()));
for (auto cell_port : tightly_attached_bels) {
log_info(" - %s : %s\n", cell_port.first->name.c_str(getCtx()), cell_port.first->type.c_str(getCtx()));
}
}
NPNR_ASSERT(tightly_attached_bels.erase(port_cell) == 1);
pool<IdString> cell_types_in_io_group;
for (auto cell_port : tightly_attached_bels) {
NPNR_ASSERT(port_cells.find(cell_port.first->name) == port_cells.end());
cell_types_in_io_group.emplace(cell_port.first->type);
}
// Get possible placement locations for tightly coupled BELs with
// port.
pool<IdString> possible_site_types;
for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
IdString tile_type_name(tile_type.name);
for (const BelInfoPOD &bel_info : tile_type.bel_data) {
if (bel_info.category != BEL_CATEGORY_LOGIC) {
break;
}
for (IdString cell_type : cell_types_in_io_group) {
size_t cell_type_index = get_cell_type_index(cell_type);
if (bel_info.category == BEL_CATEGORY_LOGIC && bel_info.pin_map[cell_type_index] != -1) {
auto *tile = tile_type_prototypes.at(tile_type_name);
const SiteInstInfoPOD &site = chip_info->sites[tile->sites[bel_info.site]];
IdString site_type(site.site_type);
if (package_pin_site_types.count(site_type)) {
possible_site_types.emplace(site_type);
}
}
}
}
}
if (possible_site_types.empty()) {
if (getCtx()->verbose)
log_info("Port '%s' has no possible site types, falling back to all types!\n",
port_name.c_str(getCtx()));
possible_site_types = package_pin_site_types;
}
if (getCtx()->verbose) {
log_info("Possible site types for port %s\n", port_name.c_str(getCtx()));
for (IdString site_type : possible_site_types) {
log_info(" - %s\n", site_type.c_str(getCtx()));
}
}
auto iter = port_cell->attrs.find(id("PACKAGE_PIN"));
if (iter == port_cell->attrs.end()) {
iter = port_cell->attrs.find(id("LOC"));
if (iter == port_cell->attrs.end()) {
log_error("Port '%s' is missing PACKAGE_PIN or LOC property\n", port_cell->name.c_str(getCtx()));
}
}
// dict<IdString, dict<IdString, BelId>> package_pin_bels;
IdString package_pin_id = id(iter->second.as_string());
auto pin_iter = package_pin_bels.find(package_pin_id);
if (pin_iter == package_pin_bels.end()) {
log_error("Package pin '%s' not found in part %s\n", package_pin_id.c_str(getCtx()), get_part().c_str());
}
NPNR_ASSERT(pin_iter != package_pin_bels.end());
// Select the first BEL from package_bel_pins that is a legal site
// type.
//
// This is likely the most generic (versus specialized) site type.
BelId package_bel;
for (auto site_type_and_bel : pin_iter->second) {
IdString legal_site_type = site_type_and_bel.first;
BelId bel = site_type_and_bel.second;
if (possible_site_types.count(legal_site_type)) {
// FIXME: Need to handle case where a port can be in multiple
// modes, but only one of the modes works.
package_bel = bel;
break;
}
}
if (package_bel == BelId()) {
log_info("Failed to find BEL for package pin '%s' in any possible site types:\n",
package_pin_id.c_str(getCtx()));
for (IdString site_type : possible_site_types) {
log_info(" - %s\n", site_type.c_str(getCtx()));
}
log_error("Failed to find BEL for package pin '%s'\n", package_pin_id.c_str(getCtx()));
}
if (getCtx()->verbose) {
log_info("Binding port %s to BEL %s\n", port_name.c_str(getCtx()), getCtx()->nameOfBel(package_bel));
}
pool<CellInfo *, hash_ptr_ops> placed_cells;
bindBel(package_bel, port_cell, STRENGTH_FIXED);
placed_cells.emplace(port_cell);
IdStringRange package_bel_pins = getBelPins(package_bel);
IdString pad_pin = get_only_value(package_bel_pins);
WireId pad_wire = getBelPinWire(package_bel, pad_pin);
place_iobufs(pad_wire, ports[port_pair.first].net, tightly_attached_bels, &placed_cells);
for (CellInfo *cell : placed_cells)
all_placed_io.insert(cell);
}
// Check at the end of IO placement, because differential pairs might need P and N sides to both be placed to be
// legal.
for (CellInfo *cell : all_placed_io) {
log_info("%s\n", getCtx()->nameOf(cell));
NPNR_ASSERT(cell->bel != BelId());
if (!isBelLocationValid(cell->bel)) {
explain_bel_status(cell->bel);
log_error("Tightly bound BEL %s was not valid!\n", nameOfBel(cell->bel));
}
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,106 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "log.h"
#include "nextpnr.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
void Arch::place_constraints()
{
std::vector<std::pair<IdString, BelId>> constrained_cells;
for (auto &cell_pair : cells) {
CellInfo *cell = cell_pair.second.get();
auto loc_constr = cell->attrs.find(id("LOC"));
auto bel_constr = cell->attrs.find(id("BEL"));
if (loc_constr == cell->attrs.end() || bel_constr == cell->attrs.end())
continue;
IdString loc_name = id(loc_constr->second.as_string());
IdString bel_name = id(bel_constr->second.as_string());
BelId bel;
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
const auto &tile = chip_info->tiles[i];
bool site_found = false;
for (size_t j = 0; j < tile.sites.size(); ++j) {
auto &site_data = chip_info->sites[tile.sites[j]];
if (loc_name == id(site_data.site_name.get())) {
site_found = true;
break;
}
}
if (!site_found)
continue;
const auto &tile_type = chip_info->tile_types[tile.type];
bool bel_found = false;
for (size_t j = 0; j < tile_type.bel_data.size(); ++j) {
const BelInfoPOD &bel_data = tile_type.bel_data[j];
if (bel_name == IdString(bel_data.name)) {
bel.tile = i;
bel.index = j;
bel_found = true;
break;
}
}
if (bel_found)
break;
else
log_error("No bel found for user constraint \'%s/%s\' for cell \'%s\'\n", loc_name.c_str(getCtx()),
bel_name.c_str(getCtx()), cell->name.c_str(getCtx()));
}
if (!isValidBelForCellType(cell->type, bel))
log_error("Bel \'%s\' is invalid for cell \'%s\' (%s)\n", nameOfBel(bel), cell->name.c_str(getCtx()),
cell->type.c_str(getCtx()));
auto bound_cell = getBoundBelCell(bel);
if (bound_cell)
log_error("Cell \'%s\' cannot be bound to bel \'%s\' "
"since it is already bound to cell \'%s\'\n",
cell->name.c_str(getCtx()), nameOfBel(bel), bound_cell->name.c_str(getCtx()));
bindBel(bel, cell, STRENGTH_USER);
cell->attrs.erase(id("BEL"));
constrained_cells.emplace_back(cell->name, bel);
}
if (constrained_cells.empty())
return;
log_info("Cell placed via user constraints:\n");
for (auto cell_bel : constrained_cells) {
IdString cell_name = cell_bel.first;
BelId bel = cell_bel.second;
if (!isBelLocationValid(bel))
log_error(" - Bel \'%s\' is not valid for cell \'%s\'\n", nameOfBel(bel), cell_name.c_str(getCtx()));
log_info(" - %s placed at %s\n", cell_name.c_str(getCtx()), nameOfBel(cell_bel.second));
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,79 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2020 gatecat <gatecat@ds0.me>
* Copyright (C) 2021 Symbiflow Authors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef NO_PYTHON
#include "arch_pybindings.h"
#include "nextpnr.h"
#include "pybindings.h"
NEXTPNR_NAMESPACE_BEGIN
void arch_wrap_python(py::module &m)
{
using namespace PythonConversion;
py::class_<ArchArgs>(m, "ArchArgs").def_readwrite("chipdb", &ArchArgs::chipdb);
py::class_<BelId>(m, "BelId").def_readwrite("index", &BelId::index);
py::class_<WireId>(m, "WireId").def_readwrite("index", &WireId::index);
py::class_<PipId>(m, "PipId").def_readwrite("index", &PipId::index);
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
auto ctx_cls = py::class_<Context, Arch>(m, "Context")
.def("checksum", &Context::checksum)
.def("pack", &Context::pack)
.def("place", &Context::place)
.def("route", &Context::route);
fn_wrapper_0a_v<Context, decltype(&Context::remove_site_routing), &Context::remove_site_routing>::def_wrap(
ctx_cls, "remove_site_routing");
fn_wrapper_1a_v<Context, decltype(&Context::explain_bel_status), &Context::explain_bel_status,
conv_from_str<BelId>>::def_wrap(ctx_cls, "explain_bel_status");
typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef dict<IdString, IdString> AliasMap;
typedef dict<IdString, HierarchicalCell> HierarchyMap;
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");
readonly_wrapper<BelPin, decltype(&BelPin::pin), &BelPin::pin, conv_to_str<IdString>>::def_wrap(belpin_cls, "pin");
typedef FilteredBelRange BelRangeForBelBucket;
#include "arch_pybindings_shared.h"
WRAP_RANGE(m, BelBucket, conv_to_str<BelBucketId>);
WRAP_RANGE(m, Bel, conv_to_str<BelId>);
WRAP_RANGE(m, Wire, conv_to_str<WireId>);
WRAP_RANGE(m, AllPip, conv_to_str<PipId>);
WRAP_RANGE(m, UphillPip, conv_to_str<PipId>);
WRAP_RANGE(m, DownhillPip, conv_to_str<PipId>);
WRAP_RANGE(m, BelPin, wrap_context<BelPin>);
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
}
NEXTPNR_NAMESPACE_END
#endif // NO_PYTHON

View File

@ -1,110 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2020 gatecat <gatecat@ds0.me>
* Copyright (C) 2021 Symbiflow Authors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef ARCH_PYBINDINGS_H
#define ARCH_PYBINDINGS_H
#ifndef NO_PYTHON
#include "nextpnr.h"
#include "pybindings.h"
NEXTPNR_NAMESPACE_BEGIN
namespace PythonConversion {
template <> struct string_converter<BelId>
{
BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(IdStringList::parse(ctx, name)); }
std::string to_str(Context *ctx, BelId id)
{
if (id == BelId())
throw bad_wrap();
return ctx->getBelName(id).str(ctx);
}
};
template <> struct string_converter<WireId>
{
WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(IdStringList::parse(ctx, name)); }
std::string to_str(Context *ctx, WireId id)
{
if (id == WireId())
throw bad_wrap();
return ctx->getWireName(id).str(ctx);
}
};
template <> struct string_converter<const WireId>
{
WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(IdStringList::parse(ctx, name)); }
std::string to_str(Context *ctx, WireId id)
{
if (id == WireId())
throw bad_wrap();
return ctx->getWireName(id).str(ctx);
}
};
template <> struct string_converter<PipId>
{
PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(IdStringList::parse(ctx, name)); }
std::string to_str(Context *ctx, PipId id)
{
if (id == PipId())
throw bad_wrap();
return ctx->getPipName(id).str(ctx);
}
};
template <> struct string_converter<BelBucketId>
{
BelBucketId from_str(Context *ctx, std::string name) { return ctx->getBelBucketByName(ctx->id(name)); }
std::string to_str(Context *ctx, BelBucketId id)
{
if (id == BelBucketId())
throw bad_wrap();
return ctx->getBelBucketName(id).str(ctx);
}
};
template <> struct string_converter<BelPin>
{
BelPin from_str(Context *ctx, std::string name)
{
NPNR_ASSERT_FALSE("string_converter<BelPin>::from_str not implemented");
}
std::string to_str(Context *ctx, BelPin pin)
{
if (pin.bel == BelId())
throw bad_wrap();
return ctx->getBelName(pin.bel).str(ctx) + "/" + pin.pin.str(ctx);
}
};
} // namespace PythonConversion
NEXTPNR_NAMESPACE_END
#endif
#endif

View File

@ -1,129 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2021 Symbiflow Authors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef FPGA_INTERCHANGE_ARCHDEFS_H
#define FPGA_INTERCHANGE_ARCHDEFS_H
#include <cstdint>
#include "hashlib.h"
#include "luts.h"
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
typedef int delay_t;
// -----------------------------------------------------------------------
struct BelId
{
// Tile that contains this BEL.
int32_t tile = -1;
// Index into tile type BEL array.
// BEL indicies are the same for all tiles of the same type.
int32_t index = -1;
bool operator==(const BelId &other) const { return tile == other.tile && index == other.index; }
bool operator!=(const BelId &other) const { return tile != other.tile || index != other.index; }
bool operator<(const BelId &other) const
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
unsigned int hash() const { return mkhash(tile, index); }
};
struct WireId
{
// Tile that contains this wire.
int32_t tile = -1;
int32_t index = -1;
bool operator==(const WireId &other) const { return tile == other.tile && index == other.index; }
bool operator!=(const WireId &other) const { return tile != other.tile || index != other.index; }
bool operator<(const WireId &other) const
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
unsigned int hash() const { return mkhash(tile, index); }
};
struct PipId
{
int32_t tile = -1;
int32_t index = -1;
bool operator==(const PipId &other) const { return tile == other.tile && index == other.index; }
bool operator!=(const PipId &other) const { return tile != other.tile || index != other.index; }
bool operator<(const PipId &other) const
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
unsigned int hash() const { return mkhash(tile, index); }
};
struct GroupId
{
bool operator==(const GroupId &other) const { return true; }
bool operator!=(const GroupId &other) const { return false; }
unsigned int hash() const { return 0; }
};
struct DecalId
{
bool operator==(const DecalId &other) const { return true; }
bool operator!=(const DecalId &other) const { return false; }
unsigned int hash() const { return 0; }
};
struct BelBucketId
{
IdString name;
bool operator==(const BelBucketId &other) const { return (name == other.name); }
bool operator!=(const BelBucketId &other) const { return (name != other.name); }
bool operator<(const BelBucketId &other) const { return name < other.name; }
unsigned int hash() const { return name.hash(); }
};
typedef IdString ClusterId;
struct SiteExpansionLoop;
struct ArchNetInfo
{
virtual ~ArchNetInfo();
SiteExpansionLoop *loop = nullptr;
};
struct ArchCellInfo
{
int32_t cell_mapping = -1;
dict<IdString, std::vector<IdString>> cell_bel_pins;
dict<IdString, std::vector<IdString>> masked_cell_bel_pins;
pool<IdString> const_ports;
IdString macro_parent = IdString();
LutCell lut_cell;
};
NEXTPNR_NAMESPACE_END
#endif /* FPGA_INTERCHANGE_ARCHDEFS_H */

View File

@ -1,222 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "cell_parameters.h"
#include <limits>
#include "DeviceResources.capnp.h"
#include "context.h"
#include "log.h"
#include "nextpnr_assertions.h"
NEXTPNR_NAMESPACE_BEGIN
CellParameters::CellParameters()
// 1'b0
: verilog_binary_re("([1-9][0-9]*)'b([01]+)$"),
// 8'hF
verilog_hex_re("([1-9][0-9]*)'h([0-9a-fA-F]+)$"),
// 0b10
c_binary_re("0b([01]+)$"),
// 0xF
c_hex_re("0x([0-9a-fA-F]+)$")
{
}
void CellParameters::init(const Context *ctx)
{
for (const CellParameterPOD &cell_parameter : ctx->chip_info->cell_map->cell_parameters) {
IdString cell_type(cell_parameter.cell_type);
IdString parameter(cell_parameter.parameter);
auto result = parameters.emplace(std::make_pair(cell_type, parameter), &cell_parameter);
NPNR_ASSERT(result.second);
}
}
static bool parse_int(const std::string &data, int64_t *result)
{
NPNR_ASSERT(result != nullptr);
try {
*result = boost::lexical_cast<int64_t>(data);
return true;
} catch (boost::bad_lexical_cast &e) {
return false;
}
}
DynamicBitarray<> CellParameters::parse_int_like(const Context *ctx, IdString cell_type, IdString parameter,
const Property &property) const
{
const CellParameterPOD *definition = parameters.at(std::make_pair(cell_type, parameter));
DeviceResources::Device::ParameterFormat format;
format = static_cast<DeviceResources::Device::ParameterFormat>(definition->format);
DynamicBitarray<> result;
switch (format) {
case DeviceResources::Device::ParameterFormat::BOOLEAN:
result.resize(1);
if (property.is_string) {
if (property.as_string() == "TRUE" || property.as_string() == "1") {
result.set(0, true);
} else if (property.as_string() == "FALSE" || property.as_string() == "0") {
result.set(0, false);
} else {
log_error("Property value %s not expected for BOOLEAN type.\n", property.c_str());
}
} else {
if (property.intval == 1) {
result.set(0, true);
} else if (property.intval == 0) {
result.set(0, false);
} else {
log_error("Property value %lu not expected for BOOLEAN type.\n", property.intval);
}
}
return result;
case DeviceResources::Device::ParameterFormat::INTEGER:
if (property.is_string) {
char *endptr;
std::uintmax_t value = strtoumax(property.c_str(), &endptr, /*base=*/10);
if (endptr != (property.c_str() + property.size())) {
log_error("Property value %s not expected for INTEGER type.\n", property.c_str());
}
return DynamicBitarray<>::to_bitarray(value);
} else {
return DynamicBitarray<>::to_bitarray(property.intval);
}
break;
case DeviceResources::Device::ParameterFormat::VERILOG_BINARY:
if (property.is_string) {
std::smatch m;
if (!std::regex_match(property.as_string(), m, verilog_binary_re)) {
log_error("Property value %s not expected for VERILOG_BINARY type.\n", property.c_str());
}
int64_t width;
if (!parse_int(m[1], &width)) {
log_error("Failed to parse width from property value %s of type VERILOG_BINARY.\n", property.c_str());
}
if (width < 0) {
log_error("Expected width to be positive for property value %s\n", property.c_str());
}
return DynamicBitarray<>::parse_binary_bitstring(width, m[2]);
} else {
return DynamicBitarray<>::to_bitarray(property.intval);
}
break;
case DeviceResources::Device::ParameterFormat::VERILOG_HEX:
if (property.is_string) {
std::smatch m;
if (!std::regex_match(property.as_string(), m, verilog_hex_re)) {
log_error("Property value %s not expected for VERILOG_HEX type.\n", property.c_str());
}
int64_t width;
if (!parse_int(m[1], &width)) {
log_error("Failed to parse width from property value %s of type VERILOG_HEX.\n", property.c_str());
}
if (width < 0) {
log_error("Expected width to be positive for property value %s\n", property.c_str());
}
return DynamicBitarray<>::parse_hex_bitstring(width, m[2]);
} else {
return DynamicBitarray<>::to_bitarray(property.intval);
}
break;
case DeviceResources::Device::ParameterFormat::C_BINARY:
if (property.is_string) {
std::smatch m;
if (!std::regex_match(property.as_string(), m, c_binary_re)) {
log_error("Property value %s not expected for C_BINARY type.\n", property.c_str());
}
return DynamicBitarray<>::parse_binary_bitstring(/*width=*/-1, m[1]);
} else {
return DynamicBitarray<>::to_bitarray(property.intval);
}
break;
case DeviceResources::Device::ParameterFormat::C_HEX:
if (property.is_string) {
std::smatch m;
if (!std::regex_match(property.as_string(), m, c_hex_re)) {
log_error("Property value %s not expected for C_HEX type.\n", property.c_str());
}
return DynamicBitarray<>::parse_hex_bitstring(/*width=*/-1, m[1]);
} else {
return DynamicBitarray<>::to_bitarray(property.intval);
}
break;
default:
log_error("Format %d is not int-like\n", definition->format);
}
// Unreachable!
NPNR_ASSERT(false);
}
bool CellParameters::compare_property(const Context *ctx, IdString cell_type, IdString parameter,
const Property &property, IdString value_to_compare) const
{
const CellParameterPOD *definition = parameters.at(std::make_pair(cell_type, parameter));
DeviceResources::Device::ParameterFormat format;
format = static_cast<DeviceResources::Device::ParameterFormat>(definition->format);
switch (format) {
case DeviceResources::Device::ParameterFormat::STRING:
return value_to_compare.c_str(ctx) == property.as_string();
case DeviceResources::Device::ParameterFormat::FLOATING_POINT:
// Note: Comparing floating point is pretty weird
log_warning("Doing direct comparisions on floating points values is pretty weird, double check this. Cell "
"type %s parameter %s\n",
cell_type.c_str(ctx), parameter.c_str(ctx));
return value_to_compare.c_str(ctx) == property.as_string();
case DeviceResources::Device::ParameterFormat::BOOLEAN:
case DeviceResources::Device::ParameterFormat::INTEGER:
case DeviceResources::Device::ParameterFormat::VERILOG_BINARY:
case DeviceResources::Device::ParameterFormat::VERILOG_HEX:
case DeviceResources::Device::ParameterFormat::C_BINARY:
case DeviceResources::Device::ParameterFormat::C_HEX: {
if (property.is_string) {
// Given that string presentations should be equivalent if
// formatted consistently, this should work most and or all of
// the time. If there are important exceptions, revisit this.
return property.as_string() == value_to_compare.c_str(ctx);
} else {
int64_t int_to_compare;
if (!parse_int(value_to_compare.c_str(ctx), &int_to_compare)) {
log_error("Comparision failed, to compare value %s is not int-like\n", value_to_compare.c_str(ctx));
}
return property.intval == int_to_compare;
}
}
}
// Unreachable!
NPNR_ASSERT(false);
}
NEXTPNR_NAMESPACE_END

View File

@ -1,54 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef CELL_PARAMETERS_H
#define CELL_PARAMETERS_H
#include <regex>
#include "chipdb.h"
#include "dynamic_bitarray.h"
#include "nextpnr_namespaces.h"
#include "property.h"
NEXTPNR_NAMESPACE_BEGIN
struct Context;
struct CellParameters
{
CellParameters();
void init(const Context *ctx);
DynamicBitarray<> parse_int_like(const Context *ctx, IdString cell_type, IdString parameter,
const Property &property) const;
bool compare_property(const Context *ctx, IdString cell_type, IdString parameter, const Property &property,
IdString value_to_compare) const;
dict<std::pair<IdString, IdString>, const CellParameterPOD *> parameters;
std::regex verilog_binary_re;
std::regex verilog_hex_re;
std::regex c_binary_re;
std::regex c_hex_re;
};
NEXTPNR_NAMESPACE_END
#endif /* CELL_PARAMETERS_H */

View File

@ -1,547 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef CHIPDB_H
#define CHIPDB_H
#include "archdefs.h"
#include "nextpnr_namespaces.h"
#include "relptr.h"
NEXTPNR_NAMESPACE_BEGIN
/* !!! Everything in this section must be kept in sync !!!
* !!! with fpga_interchange/chip_info.py !!!
*
* When schema changes, bump version number in chip_info.py and
* kExpectedChipInfoVersion
*/
static constexpr int32_t kExpectedChipInfoVersion = 15;
NPNR_PACKED_STRUCT(struct BelConnectedPinsPOD {
int32_t pin1;
int32_t pin2;
});
// Flattened site indexing.
//
// To enable flat BelId.z spaces, every tile and sites within that tile are
// flattened.
//
// This has implications on BelId's, WireId's and PipId's.
// The flattened site space works as follows:
// - Objects that belong to the tile are first. BELs are always part of Sites,
// so no BEL objects are in this category.
// - All site alternative modes are exposed as a "full" site.
// - Each site appends it's BEL's, wires (site wires) and PIP's.
// - Sites add two types of pips. Sites will add pip data first for site
// pips, and then for site pin edges.
// 1. The first type is site pips, which connect site wires to other site
// wires.
// 2. The second type is site pin edges, which connect site wires to tile
// wires (or vise-versa).
NPNR_PACKED_STRUCT(struct BelInfoPOD {
int32_t name; // bel name (in site) constid
int32_t type; // Type name constid
int32_t bel_bucket; // BEL bucket constid.
int32_t num_bel_wires;
RelPtr<int32_t> ports; // port name constid
RelPtr<int32_t> types; // port type (IN/OUT/BIDIR)
RelPtr<int32_t> wires; // connected wire index in tile, or -1 if NA
int16_t site;
int16_t site_variant; // some sites have alternative types
int16_t category;
int8_t synthetic;
int8_t lut_element;
RelPtr<int32_t> pin_map; // Index into CellMapPOD::cell_bel_map
// If this BEL is a site routing BEL with inverting pins, these values
// will be [0, num_bel_wires). If this BEL is either not a site routing
// BEL or this site routing has no inversion capabilities, then these will
// both be -1.
int8_t non_inverting_pin;
int8_t inverting_pin;
int16_t padding;
RelSlice<BelConnectedPinsPOD> connected_pins;
});
enum BELCategory
{
// BEL is a logic element
BEL_CATEGORY_LOGIC = 0,
// BEL is a site routing mux
BEL_CATEGORY_ROUTING = 1,
// BEL is a site port, e.g. boundry between site and routing graph.
BEL_CATEGORY_SITE_PORT = 2
};
NPNR_PACKED_STRUCT(struct BelPortPOD {
int32_t bel_index;
int32_t port;
});
NPNR_PACKED_STRUCT(struct TileWireInfoPOD {
int32_t name; // wire name constid
// Pip index inside tile
RelSlice<int32_t> pips_uphill;
// Pip index inside tile
RelSlice<int32_t> pips_downhill;
// Bel index inside tile
RelSlice<BelPortPOD> bel_pins;
int16_t site; // site index in tile
int16_t site_variant; // site variant index in tile
});
NPNR_PACKED_STRUCT(struct PipInfoPOD {
int32_t src_index, dst_index;
int16_t site; // site index in tile
int16_t site_variant; // site variant index in tile
int16_t bel; // BEL this pip belongs to if site pip.
int16_t extra_data;
RelSlice<int32_t> pseudo_cell_wires;
});
NPNR_PACKED_STRUCT(struct ConstraintTagPOD {
int32_t tag_prefix; // constid
int32_t default_state; // constid
RelSlice<int32_t> states; // constid
});
NPNR_PACKED_STRUCT(struct LutBelPOD {
uint32_t name; // constid
RelSlice<int32_t> pins; // constid
uint32_t low_bit;
uint32_t high_bit;
int32_t out_pin; // constid
});
NPNR_PACKED_STRUCT(struct LutElementPOD {
int32_t width;
RelSlice<LutBelPOD> lut_bels;
});
NPNR_PACKED_STRUCT(struct TileTypeInfoPOD {
int32_t name; // Tile type constid
RelSlice<BelInfoPOD> bel_data;
RelSlice<TileWireInfoPOD> wire_data;
RelSlice<PipInfoPOD> pip_data;
RelSlice<ConstraintTagPOD> tags;
RelSlice<LutElementPOD> lut_elements;
RelSlice<int32_t> site_types; // constid
});
NPNR_PACKED_STRUCT(struct SiteInstInfoPOD {
RelPtr<char> name;
RelPtr<char> site_name;
// Which site type is this site instance?
// constid
int32_t site_type;
});
NPNR_PACKED_STRUCT(struct TileInstInfoPOD {
// Name of this tile.
RelPtr<char> name;
// Index into root.tile_types.
int32_t type;
// This array is root.tile_types[type].site_types.size() long.
// Index into root.sites
RelSlice<int32_t> sites;
// Number of tile wires; excluding any site-internal wires
// which come after general wires and are not stored here
// as they will never be nodal
// -1 if a tile-local wire; node index if nodal wire
RelSlice<int32_t> tile_wire_to_node;
// Index into wire_types
RelSlice<int16_t> tile_wire_to_type;
});
NPNR_PACKED_STRUCT(struct TileWireRefPOD {
int32_t tile;
int32_t index;
});
NPNR_PACKED_STRUCT(struct NodeInfoPOD { RelSlice<TileWireRefPOD> tile_wires; });
NPNR_PACKED_STRUCT(struct CellBelPinPOD {
int32_t cell_pin; // constid
int32_t bel_pin; // constid
});
NPNR_PACKED_STRUCT(struct ParameterPinsPOD {
int32_t key; // constid
int32_t value; // constid
RelSlice<CellBelPinPOD> pins;
});
NPNR_PACKED_STRUCT(struct CellConstraintPOD {
int32_t tag; // Tag index
int32_t constraint_type; // Constraint::ConstraintType
RelSlice<int32_t> states; // State indicies
});
// Cell parameters metadata
NPNR_PACKED_STRUCT(struct CellParameterPOD {
int32_t cell_type; // constid
int32_t parameter; // constid
int32_t format; // ParameterFormat enum
int32_t default_value; // constid
});
NPNR_PACKED_STRUCT(struct CellBelMapPOD {
RelSlice<CellBelPinPOD> common_pins;
RelSlice<ParameterPinsPOD> parameter_pins;
RelSlice<CellConstraintPOD> constraints;
});
NPNR_PACKED_STRUCT(struct LutCellPOD {
int32_t cell; // constid
RelSlice<int32_t> input_pins; // constids
int32_t parameter;
});
NPNR_PACKED_STRUCT(struct CellMapPOD {
// Cell names supported in this arch.
RelSlice<int32_t> cell_names; // constids
// BEL names that are global buffers.
RelSlice<int32_t> global_buffers; // constids
// Name of BelBuckets.
RelSlice<int32_t> cell_bel_buckets; // constids
RelSlice<CellBelMapPOD> cell_bel_map;
RelSlice<LutCellPOD> lut_cells;
RelSlice<CellParameterPOD> cell_parameters;
});
NPNR_PACKED_STRUCT(struct PackagePinPOD {
int32_t package_pin; // constid
int32_t site; // constid
int32_t bel; // constid
});
NPNR_PACKED_STRUCT(struct PackagePOD {
int32_t package; // constid
RelSlice<PackagePinPOD> pins;
});
enum CellPinValue
{
// leave floating
PIN_VALUE_FLOAT = 0,
// connect to ground
PIN_VALUE_GND = 1,
// connect to vcc
PIN_VALUE_VCC = 2,
};
NPNR_PACKED_STRUCT(struct DefaultCellConnPOD {
int32_t pin_name; // constid
int32_t value; // CellPinValue
});
NPNR_PACKED_STRUCT(struct DefaultCellConnsPOD {
int32_t cell_type; // constid
RelSlice<DefaultCellConnPOD> pins;
});
NPNR_PACKED_STRUCT(struct ConstantsPOD {
// Cell type and port for the GND and VCC global source.
int32_t gnd_cell_name; // constid
int32_t gnd_cell_port; // constid
int32_t vcc_cell_name; // constid
int32_t vcc_cell_port; // constid
int32_t gnd_bel_tile;
int32_t gnd_bel_index;
int32_t gnd_bel_pin; // constid
int32_t vcc_bel_tile;
int32_t vcc_bel_index;
int32_t vcc_bel_pin; // constid
// Name to use for the global GND constant net
int32_t gnd_net_name; // constid
// Name to use for the global VCC constant net
int32_t vcc_net_name; // constid
// If a choice is available, which constant net should be used?
// Can be ''/0 if either constant net are equivilent.
int32_t best_constant_net; // constid
// Default cell pin connections
RelSlice<DefaultCellConnsPOD> default_conns;
});
enum WireCategory
{
WIRE_CAT_GENERAL = 0,
WIRE_CAT_SPECIAL = 1,
WIRE_CAT_GLOBAL = 2,
};
NPNR_PACKED_STRUCT(struct WireTypePOD {
int32_t name; // constid
int32_t category; // WireCategory
});
NPNR_PACKED_STRUCT(struct GlobalCellPinPOD {
int32_t name; // constid
int16_t max_hops; // max routing hops to try
int8_t guide_placement;
int8_t force_routing;
});
NPNR_PACKED_STRUCT(struct GlobalCellPOD {
int32_t cell_type;
RelSlice<GlobalCellPinPOD> pins;
});
NPNR_PACKED_STRUCT(struct MacroParameterPOD {
int32_t key; // constid
int32_t value; // constid
});
enum MacroParamRuleType
{
PARAM_MAP_COPY = 0, // copy parameter value
PARAM_MAP_SLICE = 1, // take a slice of bits
PARAM_MAP_TABLE = 2, // lookup strings in table
};
NPNR_PACKED_STRUCT(struct MacroParamMapRulePOD {
// name of parameter on parent primitive
int32_t prim_param; // constid
// name of instance to set parameter on
int32_t inst_name; // constid
// name of parameter on macro expansion instance
int32_t inst_param; // constid
// type of mapping to use to derive new value
int32_t rule_type; // MacroParamRuleType
// for slice mappings, the bits to collect
RelSlice<uint32_t> slice_bits;
// for table mappings, the lookup table to use
RelSlice<MacroParameterPOD> map_table;
});
NPNR_PACKED_STRUCT(struct MacroCellInstPOD {
int32_t name; // instance name constid
int32_t type; // instance type constid
// parameters to set on cell
RelSlice<MacroParameterPOD> parameters;
});
NPNR_PACKED_STRUCT(struct MacroPortInstPOD {
// name of the cell instance the port is on; or 0/'' for top level ports
int32_t instance;
// name of the port
int32_t port;
// direction of the port
int32_t dir;
});
NPNR_PACKED_STRUCT(struct MacroNetPOD {
// name of the net
int32_t name;
// ports on the net
RelSlice<MacroPortInstPOD> ports;
});
NPNR_PACKED_STRUCT(struct MacroPOD {
// macro name
int32_t name;
// cell instances inside macro
RelSlice<MacroCellInstPOD> cell_insts;
// nets inside macro
RelSlice<MacroNetPOD> nets;
});
NPNR_PACKED_STRUCT(struct MacroExpansionPOD {
// primitive name to match
int32_t prim_name;
// macro name to expand to
int32_t macro_name;
// list of parameters to (optionally) match
RelSlice<MacroParameterPOD> param_matches;
// how to derive parameters for expansion instances
RelSlice<MacroParamMapRulePOD> param_rules;
});
NPNR_PACKED_STRUCT(struct ClusterCellPortPOD {
uint32_t cell;
uint32_t port;
});
NPNR_PACKED_STRUCT(struct ChainablePortPOD {
uint32_t cell_source;
uint32_t cell_sink;
uint32_t bel_source;
uint32_t bel_sink;
int16_t avg_x_offset;
int16_t avg_y_offset;
});
NPNR_PACKED_STRUCT(struct ClusterRequiredCellPOD {
uint32_t name;
uint32_t count;
});
NPNR_PACKED_STRUCT(struct ClusterUsedPortPOD { uint32_t name; });
NPNR_PACKED_STRUCT(struct ClusterEdgePOD {
uint32_t dir;
uint32_t cell_pin;
uint32_t other_cell_pin;
uint32_t other_cell_type;
});
NPNR_PACKED_STRUCT(struct ClusterConnectionsPOD {
uint32_t target_idx;
RelSlice<ClusterEdgePOD> edges;
});
NPNR_PACKED_STRUCT(struct ClusterConnectionGraphPOD {
uint32_t idx;
uint32_t cell_type;
RelSlice<ClusterConnectionsPOD> connections;
RelSlice<ClusterUsedPortPOD> used_ports;
});
NPNR_PACKED_STRUCT(struct ClusterPhysicalPlacementEntryPOD { RelSlice<uint32_t> bels; });
NPNR_PACKED_STRUCT(struct ClusterPhysicalPlacementsPOD {
uint32_t site_type;
RelSlice<ClusterPhysicalPlacementEntryPOD> places;
});
NPNR_PACKED_STRUCT(struct ClusterPOD {
uint32_t name;
RelSlice<uint32_t> root_cell_types;
RelSlice<ChainablePortPOD> chainable_ports;
RelSlice<ClusterCellPortPOD> cluster_cells_map;
RelSlice<ClusterRequiredCellPOD> required_cells;
RelSlice<ClusterConnectionGraphPOD> connection_graph;
RelSlice<ClusterPhysicalPlacementsPOD> physical_placements;
uint32_t out_of_site_clusters;
uint32_t disallow_other_cells;
uint32_t from_macro;
});
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
RelPtr<char> name;
RelPtr<char> generator;
int32_t version;
int32_t width, height;
RelSlice<TileTypeInfoPOD> tile_types;
RelSlice<SiteInstInfoPOD> sites;
RelSlice<TileInstInfoPOD> tiles;
RelSlice<NodeInfoPOD> nodes;
RelSlice<PackagePOD> packages;
RelSlice<WireTypePOD> wire_types;
RelSlice<GlobalCellPOD> global_cells;
// Macro related data
RelSlice<MacroPOD> macros;
RelSlice<MacroExpansionPOD> macro_rules;
RelSlice<ClusterPOD> clusters;
// BEL bucket constids.
RelSlice<int32_t> bel_buckets;
RelPtr<CellMapPOD> cell_map;
RelPtr<ConstantsPOD> constants;
// Constid string data.
RelPtr<RelSlice<RelPtr<char>>> constids;
});
/************************ End of chipdb section. ************************/
inline const TileTypeInfoPOD &tile_info(const ChipInfoPOD *chip_info, int32_t tile)
{
return chip_info->tile_types[chip_info->tiles[tile].type];
}
template <typename Id> const TileTypeInfoPOD &loc_info(const ChipInfoPOD *chip_info, Id &id)
{
return chip_info->tile_types[chip_info->tiles[id.tile].type];
}
NPNR_ALWAYS_INLINE inline const BelInfoPOD &bel_info(const ChipInfoPOD *chip_info, BelId bel)
{
NPNR_ASSERT(bel != BelId());
return loc_info(chip_info, bel).bel_data[bel.index];
}
inline const PipInfoPOD &pip_info(const ChipInfoPOD *chip_info, PipId pip)
{
NPNR_ASSERT(pip != PipId());
return loc_info(chip_info, pip).pip_data[pip.index];
}
inline const SiteInstInfoPOD &site_inst_info(const ChipInfoPOD *chip_info, int32_t tile, int32_t site)
{
return chip_info->sites[chip_info->tiles[tile].sites[site]];
}
inline const ClusterPOD &cluster_info(const ChipInfoPOD *chip_info, int32_t cluster)
{
return chip_info->clusters[cluster];
}
enum SyntheticType
{
NOT_SYNTH = 0,
SYNTH_SIGNAL = 1,
SYNTH_GND = 2,
SYNTH_VCC = 3,
};
NEXTPNR_NAMESPACE_END
#endif /* CHIPDB_H */

View File

@ -1,400 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "cost_map.h"
#include "context.h"
#include "log.h"
NEXTPNR_NAMESPACE_BEGIN
///@brief Factor to adjust the penalty calculation for deltas outside the segment bounding box:
// factor < 1.0: penalty has less impact on the final returned delay
// factor > 1.0: penalty has more impact on the final returned delay
static constexpr float PENALTY_FACTOR = 1.f;
///@brief Minimum penalty cost that is added when penalizing a delta outside the segment bounding box.
static constexpr delay_t PENALTY_MIN = 1;
// also known as the L1 norm
static int manhattan_distance(const std::pair<int32_t, int32_t> &a, const std::pair<int32_t, int32_t> &b)
{
return std::abs(b.first - a.first) + std::abs(b.second - a.second);
}
static delay_t penalize(const delay_t &entry, int distance, delay_t penalty)
{
penalty = std::max(penalty, PENALTY_MIN);
return entry + distance * penalty * PENALTY_FACTOR;
}
delay_t CostMap::get_delay(const Context *ctx, WireId src_wire, WireId dst_wire) const
{
TypeWirePair type_pair;
type_pair.src = TypeWireId(ctx, src_wire);
type_pair.dst = TypeWireId(ctx, dst_wire);
int src_tile;
if (src_wire.tile == -1) {
src_tile = ctx->chip_info->nodes[src_wire.index].tile_wires[0].tile;
} else {
src_tile = src_wire.tile;
}
int32_t src_x, src_y;
ctx->get_tile_x_y(src_tile, &src_x, &src_y);
int dst_tile;
if (dst_wire.tile == -1) {
dst_tile = ctx->chip_info->nodes[dst_wire.index].tile_wires[0].tile;
} else {
dst_tile = dst_wire.tile;
}
int32_t dst_x, dst_y;
ctx->get_tile_x_y(dst_tile, &dst_x, &dst_y);
auto iter = cost_map_.find(type_pair);
if (iter == cost_map_.end()) {
auto &src_type = ctx->chip_info->tile_types[type_pair.src.type];
IdString src_tile_type(src_type.name);
IdString src_wire_name(src_type.wire_data[type_pair.src.index].name);
auto &dst_type = ctx->chip_info->tile_types[type_pair.dst.type];
IdString dst_tile_type(dst_type.name);
IdString dst_wire_name(dst_type.wire_data[type_pair.dst.index].name);
#if 0
log_warning("Delay matrix is missing %s/%s -> %s/%s\n",
src_tile_type.c_str(ctx),
src_wire_name.c_str(ctx),
dst_tile_type.c_str(ctx),
dst_wire_name.c_str(ctx));
#endif
return std::numeric_limits<delay_t>::max();
}
const auto &delay_matrix = iter->second;
int32_t off_x = delay_matrix.offset.first + (dst_x - src_x);
int32_t off_y = delay_matrix.offset.second + (dst_y - src_y);
int32_t x_dim = delay_matrix.data.shape()[0];
int32_t y_dim = delay_matrix.data.shape()[1];
NPNR_ASSERT(x_dim > 0);
NPNR_ASSERT(y_dim > 0);
// Bound closest_x/y to [0, dim)
int32_t closest_x = std::min(std::max(off_x, 0), x_dim - 1);
int32_t closest_y = std::min(std::max(off_y, 0), y_dim - 1);
// Get the cost entry from the cost map at the deltas values
auto cost = delay_matrix.data[closest_x][closest_y];
NPNR_ASSERT(cost >= 0);
// Get the base penalty corresponding to the current segment.
auto penalty = delay_matrix.penalty;
// Get the distance between the closest point in the bounding box and the original coordinates.
// Note that if the original coordinates are within the bounding box, the distance will be equal to zero.
auto distance = manhattan_distance(std::make_pair(off_x, off_y), std::make_pair(closest_x, closest_y));
// Return the penalized cost (no penalty is added if the coordinates are within the bounding box).
return penalize(cost, distance, penalty);
}
void CostMap::set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
const dict<std::pair<int32_t, int32_t>, delay_t> &delays)
{
CostMapEntry delay_matrix;
auto &offset = delay_matrix.offset;
offset.first = 0;
offset.second = 0;
int32_t max_x_offset = 0;
int32_t max_y_offset = 0;
for (const auto &delay_pair : delays) {
auto &dx_dy = delay_pair.first;
offset.first = std::max(-dx_dy.first, offset.first);
offset.second = std::max(-dx_dy.second, offset.second);
max_x_offset = std::max(dx_dy.first, max_x_offset);
max_y_offset = std::max(dx_dy.second, max_y_offset);
}
int32_t x_dim = offset.first + max_x_offset + 1;
int32_t y_dim = offset.second + max_y_offset + 1;
delay_matrix.data.resize(boost::extents[x_dim][y_dim]);
// Fill matrix with sentinel of -1 to know where the holes in the matrix
// are.
std::fill_n(delay_matrix.data.data(), delay_matrix.data.num_elements(), -1);
for (const auto &delay_pair : delays) {
auto &dx_dy = delay_pair.first;
int32_t off_x = dx_dy.first + offset.first;
int32_t off_y = dx_dy.second + offset.second;
NPNR_ASSERT(off_x >= 0);
NPNR_ASSERT(off_x < x_dim);
NPNR_ASSERT(off_y >= 0);
NPNR_ASSERT(off_y < y_dim);
delay_matrix.data[off_x][off_y] = delay_pair.second;
}
delay_matrix.penalty = get_penalty(delay_matrix.data);
fill_holes(ctx, wire_pair, delay_matrix.data, delay_matrix.penalty);
{
cost_map_mutex_.lock();
auto result = cost_map_.emplace(wire_pair, delay_matrix);
NPNR_ASSERT(result.second);
cost_map_mutex_.unlock();
}
}
static void assign_min_entry(delay_t *dst, const delay_t &src)
{
if (src >= 0) {
if (*dst < 0) {
*dst = src;
} else if (src < *dst) {
*dst = src;
}
}
}
std::pair<delay_t, int> CostMap::get_nearby_cost_entry(const boost::multi_array<delay_t, 2> &matrix, int cx, int cy,
const BoundingBox &bounds)
{
#ifdef DEBUG_FILL
log_info("Filling %d, %d within (%d, %d, %d, %d)\n", cx, cy, bounds.x0, bounds.y0, bounds.x1, bounds.y1);
#endif
// spiral around (cx, cy) looking for a nearby entry
bool in_bounds = bounds.contains(cx, cy);
if (!in_bounds) {
#ifdef DEBUG_FILL
log_info("Already out of bounds, return!\n");
#endif
return std::make_pair(-1, 0);
}
int n = 0;
delay_t fill(matrix[cx][cy]);
while (in_bounds && (fill < 0)) {
n++;
#ifdef DEBUG_FILL
log_info("At n = %d\n", n);
#endif
in_bounds = false;
delay_t min_entry = -1;
for (int ox = -n; ox <= n; ox++) {
int x = cx + ox;
int oy = n - abs(ox);
int yp = cy + oy;
int yn = cy - oy;
#ifdef DEBUG_FILL
log_info("Testing %d, %d\n", x, yp);
#endif
if (bounds.contains(x, yp)) {
assign_min_entry(&min_entry, matrix[x][yp]);
in_bounds = true;
#ifdef DEBUG_FILL
log_info("matrix[%d, %d] = %d, min_entry = %d\n", x, yp, matrix[x][yp], min_entry);
#endif
}
#ifdef DEBUG_FILL
log_info("Testing %d, %d\n", x, yn);
#endif
if (bounds.contains(x, yn)) {
assign_min_entry(&min_entry, matrix[x][yn]);
in_bounds = true;
#ifdef DEBUG_FILL
log_info("matrix[%d, %d] = %d, min_entry = %d\n", x, yn, matrix[x][yn], min_entry);
#endif
}
}
if (fill < 0 && min_entry >= 0) {
fill = min_entry;
}
}
return std::make_pair(fill, n);
}
void CostMap::fill_holes(const Context *ctx, const TypeWirePair &type_pair, boost::multi_array<delay_t, 2> &matrix,
delay_t delay_penalty)
{
// find missing cost entries and fill them in by copying a nearby cost entry
std::vector<std::tuple<unsigned, unsigned, delay_t>> missing;
bool couldnt_fill = false;
auto shifted_bounds = BoundingBox(0, 0, matrix.shape()[0] - 1, matrix.shape()[1] - 1);
int max_fill = 0;
for (unsigned ix = 0; ix < matrix.shape()[0]; ix++) {
for (unsigned iy = 0; iy < matrix.shape()[1]; iy++) {
delay_t &cost_entry = matrix[ix][iy];
if (cost_entry < 0) {
// maximum search radius
delay_t filler;
int distance;
std::tie(filler, distance) = get_nearby_cost_entry(matrix, ix, iy, shifted_bounds);
if (filler >= 0) {
missing.push_back(std::make_tuple(ix, iy, penalize(filler, distance, delay_penalty)));
max_fill = std::max(max_fill, distance);
} else {
couldnt_fill = true;
}
}
}
if (couldnt_fill) {
// give up trying to fill an empty matrix
break;
}
}
if (!couldnt_fill && max_fill > 0) {
if (ctx->verbose) {
auto &src_type_data = ctx->chip_info->tile_types[type_pair.src.type];
IdString src_type(src_type_data.name);
IdString src_wire(src_type_data.wire_data[type_pair.src.index].name);
auto &dst_type_data = ctx->chip_info->tile_types[type_pair.dst.type];
IdString dst_type(dst_type_data.name);
IdString dst_wire(dst_type_data.wire_data[type_pair.dst.index].name);
#ifdef DEBUG_FILL
log_info("At %s/%s -> %s/%s: max_fill = %d, delay_penalty = %d\n", src_type.c_str(ctx), src_wire.c_str(ctx),
dst_type.c_str(ctx), dst_wire.c_str(ctx), max_fill, delay_penalty);
#endif
}
}
// write back the missing entries
for (auto &xy_entry : missing) {
matrix[std::get<0>(xy_entry)][std::get<1>(xy_entry)] = std::get<2>(xy_entry);
}
if (couldnt_fill) {
auto &src_type_data = ctx->chip_info->tile_types[type_pair.src.type];
IdString src_type(src_type_data.name);
IdString src_wire(src_type_data.wire_data[type_pair.src.index].name);
auto &dst_type_data = ctx->chip_info->tile_types[type_pair.dst.type];
IdString dst_type(dst_type_data.name);
IdString dst_wire(dst_type_data.wire_data[type_pair.dst.index].name);
log_warning("Couldn't fill holes in the cost matrix %s/%s -> %s/%s %d x %d bounding box\n", src_type.c_str(ctx),
src_wire.c_str(ctx), dst_type.c_str(ctx), dst_wire.c_str(ctx), shifted_bounds.x1,
shifted_bounds.y1);
for (unsigned y = 0; y < matrix.shape()[1]; y++) {
for (unsigned x = 0; x < matrix.shape()[0]; x++) {
NPNR_ASSERT(matrix[x][y] >= 0);
}
}
}
}
delay_t CostMap::get_penalty(const boost::multi_array<delay_t, 2> &matrix) const
{
delay_t min_delay = std::numeric_limits<delay_t>::max();
delay_t max_delay = std::numeric_limits<delay_t>::lowest();
std::pair<int32_t, int32_t> min_location(0, 0), max_location(0, 0);
for (unsigned ix = 0; ix < matrix.shape()[0]; ix++) {
for (unsigned iy = 0; iy < matrix.shape()[1]; iy++) {
const delay_t &cost_entry = matrix[ix][iy];
if (cost_entry >= 0) {
if (cost_entry < min_delay) {
min_delay = cost_entry;
min_location = std::make_pair(ix, iy);
}
if (cost_entry > max_delay) {
max_delay = cost_entry;
max_location = std::make_pair(ix, iy);
}
}
}
}
delay_t delay_penalty =
(max_delay - min_delay) / static_cast<float>(std::max(1, manhattan_distance(max_location, min_location)));
return delay_penalty;
}
void CostMap::from_reader(lookahead_storage::CostMap::Reader reader)
{
for (auto cost_entry : reader.getCostMap()) {
TypeWirePair key(cost_entry.getKey());
auto result = cost_map_.emplace(key, CostMapEntry());
NPNR_ASSERT(result.second);
CostMapEntry &entry = result.first->second;
auto data = cost_entry.getData();
auto in_iter = data.begin();
entry.data.resize(boost::extents[cost_entry.getXDim()][cost_entry.getYDim()]);
if (entry.data.num_elements() != data.size()) {
log_error("entry.data.num_elements() %zu != data.size() %u", entry.data.num_elements(), data.size());
}
delay_t *out = entry.data.origin();
for (; in_iter != data.end(); ++in_iter, ++out) {
*out = *in_iter;
}
entry.penalty = cost_entry.getPenalty();
entry.offset.first = cost_entry.getXOffset();
entry.offset.second = cost_entry.getYOffset();
}
}
void CostMap::to_builder(lookahead_storage::CostMap::Builder builder) const
{
auto cost_map = builder.initCostMap(cost_map_.size());
auto entry_iter = cost_map.begin();
auto in = cost_map_.begin();
for (; entry_iter != cost_map.end(); ++entry_iter, ++in) {
NPNR_ASSERT(in != cost_map_.end());
in->first.to_builder(entry_iter->getKey());
const CostMapEntry &entry = in->second;
auto data = entry_iter->initData(entry.data.num_elements());
const delay_t *data_in = entry.data.origin();
for (size_t i = 0; i < entry.data.num_elements(); ++i) {
data.set(i, data_in[i]);
}
entry_iter->setXDim(entry.data.shape()[0]);
entry_iter->setYDim(entry.data.shape()[1]);
entry_iter->setXOffset(entry.offset.first);
entry_iter->setYOffset(entry.offset.second);
entry_iter->setPenalty(entry.penalty);
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,67 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef COST_MAP_H
#define COST_MAP_H
#include <boost/multi_array.hpp>
#include <mutex>
#include "lookahead.capnp.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
#include "type_wire.h"
NEXTPNR_NAMESPACE_BEGIN
struct Context;
class CostMap
{
public:
delay_t get_delay(const Context *ctx, WireId src, WireId dst) const;
void set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
const dict<std::pair<int32_t, int32_t>, delay_t> &delays);
void from_reader(lookahead_storage::CostMap::Reader reader);
void to_builder(lookahead_storage::CostMap::Builder builder) const;
private:
struct CostMapEntry
{
boost::multi_array<delay_t, 2> data;
std::pair<int32_t, int32_t> offset;
delay_t penalty;
};
std::mutex cost_map_mutex_;
dict<TypeWirePair, CostMapEntry> cost_map_;
void fill_holes(const Context *ctx, const TypeWirePair &wire_pair, boost::multi_array<delay_t, 2> &matrix,
delay_t delay_penality);
std::pair<delay_t, int> get_nearby_cost_entry(const boost::multi_array<delay_t, 2> &matrix, int cx, int cy,
const BoundingBox &bounds);
delay_t get_penalty(const boost::multi_array<delay_t, 2> &matrix) const;
};
NEXTPNR_NAMESPACE_END
#endif /* COST_MAP_H */

View File

@ -1,902 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "log.h"
#include "nextpnr.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
namespace {
// All legal routes involved at most 2 sites, the source site and the sink
// site. The source site and sink sites may be the same, but that is not
// dedicated routing, that is intra site routing.
//
// Dedicated routing must leave the sink site, traverse some routing and
// terminate at another site. Routing that "flys" over a site is expressed as
// a psuedo-pip connected the relevant site pin wires, rather than traversing
// the site.
enum WireNodeState
{
IN_SINK_SITE = 0,
IN_ROUTING = 1,
IN_SOURCE_SITE = 2
};
enum ExpansionDirection
{
EXPAND_DOWNHILL = 0,
EXPAND_UPHILL = 1
};
struct WireNode
{
WireId wire;
WireNodeState state;
int depth;
};
} // namespace
// Maximum depth that a dedicate interconnect is considered.
//
// Routing networks with depth <= kMaxDepth is considers a dedicated
// interconnect.
constexpr int kMaxDepth = 6;
static uint32_t get_num_pips(const Context *ctx, WireId wire, ExpansionDirection direction)
{
uint32_t num_pips = 0;
if (direction == EXPAND_DOWNHILL) {
for (PipId pip : ctx->getPipsDownhill(wire)) {
auto &pip_data = pip_info(ctx->chip_info, pip);
if (pip_data.pseudo_cell_wires.size() > 0)
continue;
if (ctx->getPipDstWire(pip) == WireId())
continue;
if (ctx->is_pip_synthetic(pip))
continue;
if (ctx->is_site_port(pip))
continue;
num_pips++;
}
} else {
NPNR_ASSERT(direction == EXPAND_UPHILL);
for (PipId pip : ctx->getPipsUphill(wire)) {
auto &pip_data = pip_info(ctx->chip_info, pip);
if (pip_data.pseudo_cell_wires.size() > 0)
continue;
if (ctx->getPipSrcWire(pip) == WireId())
continue;
if (ctx->is_pip_synthetic(pip))
continue;
if (ctx->is_site_port(pip))
continue;
num_pips++;
}
}
return num_pips;
}
void DedicatedInterconnect::init(const Context *ctx)
{
this->ctx = ctx;
if (ctx->debug) {
log_info("Finding dedicated interconnect!\n");
}
find_dedicated_interconnect();
if (ctx->debug) {
print_dedicated_interconnect();
}
}
bool DedicatedInterconnect::check_routing(BelId src_bel, IdString src_bel_pin, BelId dst_bel, IdString dst_bel_pin,
bool site_only) const
{
std::vector<WireNode> nodes_to_expand;
WireId src_wire = ctx->getBelPinWire(src_bel, src_bel_pin);
const auto &src_wire_data = ctx->wire_info(src_wire);
NPNR_ASSERT(src_wire_data.site != -1);
WireId dst_wire = ctx->getBelPinWire(dst_bel, dst_bel_pin);
if (src_wire == dst_wire) {
return true;
}
const auto &dst_wire_data = ctx->wire_info(dst_wire);
NPNR_ASSERT(dst_wire_data.site != -1);
WireNode wire_node;
wire_node.wire = src_wire;
if (src_wire.tile == dst_wire.tile && src_wire_data.site == dst_wire_data.site)
wire_node.state = IN_SINK_SITE;
else
wire_node.state = IN_SOURCE_SITE;
wire_node.depth = 0;
nodes_to_expand.push_back(wire_node);
while (!nodes_to_expand.empty()) {
WireNode node_to_expand = nodes_to_expand.back();
nodes_to_expand.pop_back();
auto num_pips = get_num_pips(ctx, node_to_expand.wire, EXPAND_DOWNHILL);
// Usually, dedicated interconnects do not have more than one PIPs in the out-of-site
if (node_to_expand.depth > 1 && node_to_expand.state == IN_ROUTING && num_pips > 1) {
if (ctx->verbose)
log_info("Wire %s is on a non-dedicated path (number of pips %d)\n",
ctx->nameOfWire(node_to_expand.wire), num_pips);
continue;
}
for (PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) {
if (ctx->is_pip_synthetic(pip)) {
continue;
}
WireId wire = ctx->getPipDstWire(pip);
if (wire == WireId()) {
continue;
}
if (ctx->debug) {
log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));
}
WireNode next_node;
next_node.wire = wire;
next_node.depth = node_to_expand.depth;
if (node_to_expand.depth > kMaxDepth) {
// Dedicated routing should reach sources by kMaxDepth (with
// tuning).
//
// FIXME: Consider removing kMaxDepth and use kMaxSources?
continue;
}
auto const &wire_data = ctx->wire_info(wire);
bool expand_node = true;
if (ctx->is_site_port(pip)) {
if (site_only) {
// When routing site only, don't allow site ports.
continue;
}
switch (node_to_expand.state) {
case IN_SOURCE_SITE:
NPNR_ASSERT(wire_data.site == -1);
next_node.state = IN_ROUTING;
break;
case IN_ROUTING:
NPNR_ASSERT(wire_data.site != -1);
if (wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) {
// Dedicated routing won't have straight loops,
// general routing looks like that.
#ifdef DEBUG_EXPANSION
log_info(" - Not dedicated site routing because loop!");
#endif
continue;
}
next_node.state = IN_SINK_SITE;
break;
case IN_SINK_SITE:
// Once entering a site, do not leave it again.
// This path is not a legal route!
expand_node = false;
break;
default:
// Unreachable!!!
NPNR_ASSERT(false);
}
} else {
next_node.state = node_to_expand.state;
if (next_node.state == IN_ROUTING)
next_node.depth++;
}
if (expand_node) {
nodes_to_expand.push_back(next_node);
} else {
continue;
}
if (next_node.state == IN_SINK_SITE) {
for (BelPin bel_pin : ctx->getWireBelPins(wire)) {
if (bel_pin.bel == dst_bel && bel_pin.pin == dst_bel_pin) {
if (ctx->debug) {
log_info("Valid dedicated interconnect from %s/%s to %s/%s\n", ctx->nameOfBel(src_bel),
src_bel_pin.c_str(ctx), ctx->nameOfBel(dst_bel), dst_bel_pin.c_str(ctx));
}
return true;
}
}
}
}
}
return false;
}
bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel, const CellInfo *cell, IdString driver_port,
NetInfo *net) const
{
const auto &driver_bel_data = bel_info(ctx->chip_info, driver_bel);
TileTypeBelPin type_bel_pin;
type_bel_pin.tile_type = ctx->chip_info->tiles[driver_bel.tile].type;
type_bel_pin.bel_index = driver_bel.index;
Loc driver_loc = ctx->getBelLocation(driver_bel);
for (IdString driver_bel_pin : ctx->getBelPinsForCellPin(cell, driver_port)) {
type_bel_pin.bel_pin = driver_bel_pin;
auto iter = sources.find(type_bel_pin);
if (iter == sources.end()) {
// This BEL pin doesn't have a dedicate interconnect.
continue;
}
for (const PortRef &port_ref : net->users) {
NPNR_ASSERT(port_ref.cell != nullptr);
if (port_ref.cell->bel == BelId()) {
// FIXME: This should actually return "unknown!" because the
// sink is unplaced. Once the sink is placed, this constraint
// can be evaluated.
if (ctx->debug) {
log_info("BEL %s is not valid because sink cell %s/%s is not placed\n", ctx->nameOfBel(driver_bel),
port_ref.cell->name.c_str(ctx), port_ref.port.c_str(ctx));
}
return false;
}
BelId sink_bel = port_ref.cell->bel;
const auto &sink_bel_data = bel_info(ctx->chip_info, sink_bel);
Loc sink_loc = ctx->getBelLocation(port_ref.cell->bel);
if (sink_bel.tile == driver_bel.tile && sink_bel_data.site == driver_bel_data.site) {
// This might site local routing. See if it can be routed
for (IdString sink_bel_pin : ctx->getBelPinsForCellPin(port_ref.cell, port_ref.port)) {
if (!check_routing(driver_bel, driver_bel_pin, sink_bel, sink_bel_pin, /*site_only=*/true)) {
return false;
}
}
continue;
}
DeltaTileTypeBelPin sink_type_bel_pin;
sink_type_bel_pin.delta_x = sink_loc.x - driver_loc.x;
sink_type_bel_pin.delta_y = sink_loc.y - driver_loc.y;
sink_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[sink_bel.tile].type;
sink_type_bel_pin.type_bel_pin.bel_index = sink_bel.index;
for (IdString sink_bel_pin : ctx->getBelPinsForCellPin(port_ref.cell, port_ref.port)) {
sink_type_bel_pin.type_bel_pin.bel_pin = sink_bel_pin;
// Do fast routing check to see if the pair of driver and sink
// every are valid.
if (iter->second.count(sink_type_bel_pin) == 0) {
if (ctx->debug) {
log_info("BEL %s is not valid because pin %s cannot reach %s/%s\n", ctx->nameOfBel(driver_bel),
driver_bel_pin.c_str(ctx), ctx->nameOfBel(sink_bel), sink_bel_pin.c_str(ctx));
}
return false;
}
// Do detailed routing check to ensure driver can reach sink.
//
// FIXME: This might be too slow, but it handles a case on
// SLICEL.COUT -> SLICEL.CIN has delta_y = {1, 2}, but the
// delta_y=2 case is rare.
if (!check_routing(driver_bel, driver_bel_pin, sink_bel, sink_bel_pin, /*site_only=*/false)) {
if (ctx->debug) {
log_info("BEL %s is not valid because pin %s cannot be reach %s/%s (via detailed check)\n",
ctx->nameOfBel(driver_bel), driver_bel_pin.c_str(ctx), ctx->nameOfBel(sink_bel),
sink_bel_pin.c_str(ctx));
}
return false;
}
}
}
}
return true;
}
bool DedicatedInterconnect::is_sink_on_net_valid(BelId bel, const CellInfo *cell, IdString port_name,
NetInfo *net) const
{
const auto &bel_data = bel_info(ctx->chip_info, bel);
Loc bel_loc = ctx->getBelLocation(bel);
BelId driver_bel = net->driver.cell->bel;
for (IdString bel_pin : ctx->getBelPinsForCellPin(cell, port_name)) {
TileTypeBelPin type_bel_pin;
type_bel_pin.tile_type = ctx->chip_info->tiles[bel.tile].type;
type_bel_pin.bel_index = bel.index;
type_bel_pin.bel_pin = bel_pin;
auto iter = sinks.find(type_bel_pin);
if (iter == sinks.end()) {
// This BEL pin doesn't have a dedicate interconnect.
continue;
}
if (driver_bel == BelId()) {
// FIXME: This should actually return "unknown!" because the
// driver is unplaced. Once the driver is placed, this constraint
// can be evaluated.
if (ctx->debug) {
log_info("BEL %s is not valid because driver cell %s/%s is not placed\n", ctx->nameOfBel(bel),
net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx));
}
return false;
}
const auto &driver_bel_data = bel_info(ctx->chip_info, driver_bel);
if (bel.tile == driver_bel.tile && bel_data.site == driver_bel_data.site) {
// This is a site local routing, even though this is a sink
// with a dedicated interconnect.
continue;
}
Loc driver_loc = ctx->getBelLocation(driver_bel);
DeltaTileTypeBelPin driver_type_bel_pin;
driver_type_bel_pin.delta_x = driver_loc.x - bel_loc.x;
driver_type_bel_pin.delta_y = driver_loc.y - bel_loc.y;
driver_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[driver_bel.tile].type;
driver_type_bel_pin.type_bel_pin.bel_index = driver_bel.index;
driver_type_bel_pin.type_bel_pin.bel_pin =
get_only_value(ctx->getBelPinsForCellPin(net->driver.cell, net->driver.port));
// Do fast routing check to see if the pair of driver and sink
// every are valid.
if (iter->second.count(driver_type_bel_pin) == 0) {
if (ctx->debug) {
log_info("BEL %s is not valid because pin %s cannot be driven by %s/%s\n", ctx->nameOfBel(bel),
bel_pin.c_str(ctx), ctx->nameOfBel(driver_bel),
driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx));
}
return false;
}
// Do detailed routing check to ensure driver can reach sink.
//
// FIXME: This might be too slow, but it handles a case on
// SLICEL.COUT -> SLICEL.CIN has delta_y = {1, 2}, but the
// delta_y=2 case is rare.
if (!check_routing(driver_bel, driver_type_bel_pin.type_bel_pin.bel_pin, bel, bel_pin, /*site_only=*/false)) {
if (ctx->debug) {
log_info("BEL %s is not valid because pin %s cannot be driven by %s/%s (via detailed check)\n",
ctx->nameOfBel(bel), bel_pin.c_str(ctx), ctx->nameOfBel(driver_bel),
driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx));
}
return false;
}
}
return true;
}
bool DedicatedInterconnect::isBelLocationValid(BelId bel, const CellInfo *cell) const
{
NPNR_ASSERT(bel != BelId());
for (const auto &port_pair : cell->ports) {
IdString port_name = port_pair.first;
NetInfo *net = port_pair.second.net;
if (net == nullptr || net->driver.cell == nullptr) {
continue;
}
if (ctx->io_port_types.count(net->driver.cell->type)) {
continue;
}
// Only check sink BELs.
if (net->driver.cell == cell && net->driver.port == port_name) {
if (!is_driver_on_net_valid(bel, cell, port_name, net)) {
return false;
}
} else {
if (!is_sink_on_net_valid(bel, cell, port_name, net)) {
return false;
}
}
}
return true;
}
void DedicatedInterconnect::explain_bel_status(BelId bel, const CellInfo *cell) const
{
NPNR_ASSERT(bel != BelId());
for (const auto &port_pair : cell->ports) {
IdString port_name = port_pair.first;
NetInfo *net = port_pair.second.net;
if (net == nullptr) {
continue;
}
// This net doesn't have a driver, probably not valid?
NPNR_ASSERT(net->driver.cell != nullptr);
if (ctx->io_port_types.count(net->driver.cell->type)) {
continue;
}
// Only check sink BELs.
if (net->driver.cell == cell && net->driver.port == port_name) {
if (!is_driver_on_net_valid(bel, cell, port_name, net)) {
log_info("Driver %s/%s is not valid on net '%s'\n", cell->name.c_str(ctx), port_name.c_str(ctx),
net->name.c_str(ctx));
}
} else {
if (!is_sink_on_net_valid(bel, cell, port_name, net)) {
log_info("Sink %s/%s is not valid on net '%s'\n", cell->name.c_str(ctx), port_name.c_str(ctx),
net->name.c_str(ctx));
}
}
}
}
void DedicatedInterconnect::print_dedicated_interconnect() const
{
log_info("Found %zu sinks with dedicated interconnect\n", sinks.size());
log_info("Found %zu sources with dedicated interconnect\n", sources.size());
std::vector<TileTypeBelPin> sorted_keys;
for (const auto &sink_to_srcs : sinks) {
sorted_keys.push_back(sink_to_srcs.first);
}
for (const auto &src_to_sinks : sources) {
sorted_keys.push_back(src_to_sinks.first);
}
std::sort(sorted_keys.begin(), sorted_keys.end());
for (const auto &key : sorted_keys) {
auto iter = sinks.find(key);
if (iter != sinks.end()) {
auto dst = key;
for (const auto &src_delta : iter->second) {
auto src = src_delta.type_bel_pin;
auto delta_x = src_delta.delta_x;
auto delta_y = src_delta.delta_y;
const TileTypeInfoPOD &src_tile_type = ctx->chip_info->tile_types[src.tile_type];
const BelInfoPOD &src_bel_info = src_tile_type.bel_data[src.bel_index];
IdString src_site_type = IdString(src_tile_type.site_types[src_bel_info.site]);
IdString src_bel_pin = src.bel_pin;
const TileTypeInfoPOD &dst_tile_type = ctx->chip_info->tile_types[dst.tile_type];
const BelInfoPOD &dst_bel_info = dst_tile_type.bel_data[dst.bel_index];
IdString dst_site_type = IdString(dst_tile_type.site_types[dst_bel_info.site]);
IdString dst_bel_pin = dst.bel_pin;
log_info("%s.%s[%d]/%s/%s (%d, %d) -> %s.%s[%d]/%s/%s\n", IdString(src_tile_type.name).c_str(ctx),
src_site_type.c_str(ctx), src_bel_info.site, IdString(src_bel_info.name).c_str(ctx),
src_bel_pin.c_str(ctx), delta_x, delta_y, IdString(dst_tile_type.name).c_str(ctx),
dst_site_type.c_str(ctx), dst_bel_info.site, IdString(dst_bel_info.name).c_str(ctx),
dst_bel_pin.c_str(ctx));
}
} else {
auto src = key;
for (const auto &dst_delta : sources.at(key)) {
auto dst = dst_delta.type_bel_pin;
auto delta_x = dst_delta.delta_x;
auto delta_y = dst_delta.delta_y;
const TileTypeInfoPOD &src_tile_type = ctx->chip_info->tile_types[src.tile_type];
const BelInfoPOD &src_bel_info = src_tile_type.bel_data[src.bel_index];
IdString src_site_type = IdString(src_tile_type.site_types[src_bel_info.site]);
IdString src_bel_pin = src.bel_pin;
const TileTypeInfoPOD &dst_tile_type = ctx->chip_info->tile_types[dst.tile_type];
const BelInfoPOD &dst_bel_info = dst_tile_type.bel_data[dst.bel_index];
IdString dst_site_type = IdString(dst_tile_type.site_types[dst_bel_info.site]);
IdString dst_bel_pin = dst.bel_pin;
log_info("%s.%s[%d]/%s/%s -> %s.%s[%d]/%s/%s (%d, %d)\n", IdString(src_tile_type.name).c_str(ctx),
src_site_type.c_str(ctx), src_bel_info.site, IdString(src_bel_info.name).c_str(ctx),
src_bel_pin.c_str(ctx), IdString(dst_tile_type.name).c_str(ctx), dst_site_type.c_str(ctx),
dst_bel_info.site, IdString(dst_bel_info.name).c_str(ctx), dst_bel_pin.c_str(ctx), delta_x,
delta_y);
}
}
}
}
void DedicatedInterconnect::find_dedicated_interconnect()
{
for (BelId bel : ctx->getBels()) {
const auto &bel_data = bel_info(ctx->chip_info, bel);
if (bel_data.category != BEL_CATEGORY_LOGIC) {
continue;
}
if (bel_data.synthetic) {
continue;
}
for (int i = 0; i < bel_data.num_bel_wires; ++i) {
if (bel_data.types[i] != PORT_IN) {
continue;
}
WireId wire;
wire.tile = bel.tile;
wire.index = bel_data.wires[i];
expand_sink_bel(bel, IdString(bel_data.ports[i]), wire);
}
}
pool<TileTypeBelPin> seen_pins;
for (auto sink_pair : sinks) {
for (auto src : sink_pair.second) {
seen_pins.emplace(src.type_bel_pin);
}
}
for (BelId bel : ctx->getBels()) {
const auto &bel_data = bel_info(ctx->chip_info, bel);
if (bel_data.category != BEL_CATEGORY_LOGIC) {
continue;
}
if (bel_data.synthetic) {
continue;
}
for (int i = 0; i < bel_data.num_bel_wires; ++i) {
if (bel_data.types[i] != PORT_OUT || bel_data.wires[i] == -1) {
continue;
}
IdString bel_pin(bel_data.ports[i]);
TileTypeBelPin type_bel_pin;
type_bel_pin.tile_type = ctx->chip_info->tiles[bel.tile].type;
type_bel_pin.bel_index = bel.index;
type_bel_pin.bel_pin = bel_pin;
// Don't visit src pins already handled in the sink expansion!
if (seen_pins.count(type_bel_pin)) {
continue;
}
WireId wire;
wire.tile = bel.tile;
wire.index = bel_data.wires[i];
expand_source_bel(bel, bel_pin, wire);
}
}
}
void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, WireId sink_wire)
{
NPNR_ASSERT(sink_bel != BelId());
#ifdef DEBUG_EXPANSION
log_info("Expanding from %s/%s\n", ctx->nameOfBel(sink_bel), pin.c_str(ctx));
#endif
std::vector<WireNode> nodes_to_expand;
const auto &sink_wire_data = ctx->wire_info(sink_wire);
NPNR_ASSERT(sink_wire_data.site != -1);
WireNode wire_node;
wire_node.wire = sink_wire;
wire_node.state = IN_SINK_SITE;
wire_node.depth = 0;
nodes_to_expand.push_back(wire_node);
Loc sink_loc = ctx->getBelLocation(sink_bel);
pool<DeltaTileTypeBelPin> srcs;
while (!nodes_to_expand.empty()) {
WireNode node_to_expand = nodes_to_expand.back();
nodes_to_expand.pop_back();
for (PipId pip : ctx->getPipsUphill(node_to_expand.wire)) {
if (ctx->is_pip_synthetic(pip)) {
continue;
}
WireId wire = ctx->getPipSrcWire(pip);
if (wire == WireId()) {
continue;
}
#ifdef DEBUG_EXPANSION
log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));
#endif
WireNode next_node;
next_node.wire = wire;
next_node.depth = node_to_expand.depth;
if (node_to_expand.depth > kMaxDepth) {
// Dedicated routing should reach sources by kMaxDepth (with
// tuning).
//
// FIXME: Consider removing kMaxDepth and use kMaxSources?
#ifdef DEBUG_EXPANSION
log_info(" - Exceeded max depth!\n");
#endif
return;
}
auto const &wire_data = ctx->wire_info(wire);
bool expand_node = true;
if (ctx->is_site_port(pip)) {
switch (node_to_expand.state) {
case IN_SINK_SITE:
NPNR_ASSERT(wire_data.site == -1);
next_node.state = IN_ROUTING;
break;
case IN_ROUTING:
NPNR_ASSERT(wire_data.site != -1);
if (wire.tile == sink_wire.tile && wire_data.site == sink_wire_data.site) {
// Dedicated routing won't have straight loops,
// general routing looks like that.
#ifdef DEBUG_EXPANSION
log_info(" - Not dedicated site routing because loop!");
#endif
return;
}
next_node.state = IN_SOURCE_SITE;
break;
case IN_SOURCE_SITE:
// Once entering a site, do not leave it again.
// This path is not a legal route!
expand_node = false;
break;
default:
// Unreachable!!!
NPNR_ASSERT(false);
}
} else {
next_node.state = node_to_expand.state;
if (next_node.state == IN_ROUTING)
next_node.depth++;
}
if (expand_node) {
nodes_to_expand.push_back(next_node);
} else {
continue;
}
if (next_node.state == IN_SOURCE_SITE) {
for (BelPin bel_pin : ctx->getWireBelPins(wire)) {
BelId src_bel = bel_pin.bel;
auto const &bel_data = bel_info(ctx->chip_info, src_bel);
if (bel_data.category != BEL_CATEGORY_LOGIC) {
continue;
}
if (bel_data.synthetic) {
continue;
}
if (ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_OUT) {
continue;
}
#ifdef DEBUG_EXPANSION
log_info(" - Reached %s/%s\n", ctx->nameOfBel(bel_pin.bel), bel_pin.pin.c_str(ctx));
#endif
Loc src_loc = ctx->getBelLocation(src_bel);
DeltaTileTypeBelPin delta_type_bel_pin;
delta_type_bel_pin.delta_x = src_loc.x - sink_loc.x;
delta_type_bel_pin.delta_y = src_loc.y - sink_loc.y;
delta_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[src_bel.tile].type;
delta_type_bel_pin.type_bel_pin.bel_index = src_bel.index;
delta_type_bel_pin.type_bel_pin.bel_pin = bel_pin.pin;
srcs.emplace(delta_type_bel_pin);
}
}
}
}
TileTypeBelPin type_bel_pin;
type_bel_pin.tile_type = ctx->chip_info->tiles[sink_bel.tile].type;
type_bel_pin.bel_index = sink_bel.index;
type_bel_pin.bel_pin = sink_pin;
auto result = sinks.emplace(type_bel_pin, srcs);
if (!result.second) {
// type_bel_pin was already present! Add any new sources from this
// sink type (if any);
for (auto src : srcs) {
result.first->second.emplace(src);
}
}
}
void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, WireId src_wire)
{
NPNR_ASSERT(src_bel != BelId());
#ifdef DEBUG_EXPANSION
log_info("Expanding from %s/%s\n", ctx->nameOfBel(src_bel), src_pin.c_str(ctx));
#endif
std::vector<WireNode> nodes_to_expand;
const auto &src_wire_data = ctx->wire_info(src_wire);
NPNR_ASSERT(src_wire_data.site != -1);
WireNode wire_node;
wire_node.wire = src_wire;
wire_node.state = IN_SOURCE_SITE;
wire_node.depth = 0;
nodes_to_expand.push_back(wire_node);
Loc src_loc = ctx->getBelLocation(src_bel);
pool<DeltaTileTypeBelPin> dsts;
while (!nodes_to_expand.empty()) {
WireNode node_to_expand = nodes_to_expand.back();
nodes_to_expand.pop_back();
for (PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) {
if (ctx->is_pip_synthetic(pip)) {
continue;
}
WireId wire = ctx->getPipDstWire(pip);
if (wire == WireId()) {
continue;
}
#ifdef DEBUG_EXPANSION
log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));
#endif
WireNode next_node;
next_node.wire = wire;
next_node.depth = node_to_expand.depth;
if (node_to_expand.depth > kMaxDepth) {
// Dedicated routing should reach sources by kMaxDepth (with
// tuning).
//
// FIXME: Consider removing kMaxDepth and use kMaxSources?
#ifdef DEBUG_EXPANSION
log_info(" - Exceeded max depth!\n");
#endif
return;
}
auto const &wire_data = ctx->wire_info(wire);
bool expand_node = true;
if (ctx->is_site_port(pip)) {
switch (node_to_expand.state) {
case IN_SOURCE_SITE:
NPNR_ASSERT(wire_data.site == -1);
next_node.state = IN_ROUTING;
break;
case IN_ROUTING:
NPNR_ASSERT(wire_data.site != -1);
if (wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) {
// Dedicated routing won't have straight loops,
// general routing looks like that.
#ifdef DEBUG_EXPANSION
log_info(" - Not dedicated site routing because loop!");
#endif
return;
}
next_node.state = IN_SINK_SITE;
break;
case IN_SINK_SITE:
// Once entering a site, do not leave it again.
// This path is not a legal route!
expand_node = false;
break;
default:
// Unreachable!!!
NPNR_ASSERT(false);
}
} else {
next_node.state = node_to_expand.state;
if (next_node.state == IN_ROUTING)
next_node.depth++;
}
if (expand_node) {
nodes_to_expand.push_back(next_node);
} else {
continue;
}
if (next_node.state == IN_SINK_SITE) {
for (BelPin bel_pin : ctx->getWireBelPins(wire)) {
BelId sink_bel = bel_pin.bel;
auto const &bel_data = bel_info(ctx->chip_info, sink_bel);
if (bel_data.category != BEL_CATEGORY_LOGIC) {
continue;
}
if (bel_data.synthetic) {
continue;
}
if (ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_IN) {
continue;
}
#ifdef DEBUG_EXPANSION
log_info(" - Reached %s/%s\n", ctx->nameOfBel(bel_pin.bel), bel_pin.pin.c_str(ctx));
#endif
Loc sink_loc = ctx->getBelLocation(sink_bel);
DeltaTileTypeBelPin delta_type_bel_pin;
delta_type_bel_pin.delta_x = sink_loc.x - src_loc.x;
delta_type_bel_pin.delta_y = sink_loc.y - src_loc.y;
delta_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[sink_bel.tile].type;
delta_type_bel_pin.type_bel_pin.bel_index = sink_bel.index;
delta_type_bel_pin.type_bel_pin.bel_pin = bel_pin.pin;
dsts.emplace(delta_type_bel_pin);
}
}
}
}
TileTypeBelPin type_bel_pin;
type_bel_pin.tile_type = ctx->chip_info->tiles[src_bel.tile].type;
type_bel_pin.bel_index = src_bel.index;
type_bel_pin.bel_pin = src_pin;
auto result = sources.emplace(type_bel_pin, dsts);
if (!result.second) {
// type_bel_pin was already present! Add any new sources from this
// sink type (if any);
for (auto dst : dsts) {
result.first->second.emplace(dst);
}
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,124 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef DEDICATED_INTERCONNECT_H
#define DEDICATED_INTERCONNECT_H
#include <boost/functional/hash.hpp>
#include <cstdint>
#include "archdefs.h"
#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
struct TileTypeBelPin
{
int32_t tile_type;
int32_t bel_index;
IdString bel_pin;
bool operator<(const TileTypeBelPin &other) const
{
if (tile_type >= other.tile_type) {
return false;
}
if (bel_index >= other.bel_index) {
return false;
}
return bel_pin < other.bel_pin;
}
bool operator==(const TileTypeBelPin &other) const
{
return tile_type == other.tile_type && bel_index == other.bel_index && bel_pin == other.bel_pin;
}
bool operator!=(const TileTypeBelPin &other) const
{
return tile_type != other.tile_type || bel_index != other.bel_index || bel_pin != other.bel_pin;
}
unsigned int hash() const { return mkhash(mkhash(tile_type, bel_index), bel_pin.hash()); }
};
struct DeltaTileTypeBelPin
{
int32_t delta_x;
int32_t delta_y;
TileTypeBelPin type_bel_pin;
bool operator==(const DeltaTileTypeBelPin &other) const
{
return delta_x == other.delta_x && delta_y == other.delta_y && type_bel_pin == other.type_bel_pin;
}
bool operator!=(const DeltaTileTypeBelPin &other) const
{
return delta_x != other.delta_x || delta_y != other.delta_y || type_bel_pin != other.type_bel_pin;
}
unsigned int hash() const { return mkhash(mkhash(delta_x, delta_y), type_bel_pin.hash()); }
};
struct Context;
// This class models dedicated interconnect present in the given fabric.
//
// Examples of dedicate interconnect:
// - IBUF.O -> ISERDES.I
// - IBUF.O -> IDELAY.I
// - CARRY4.CO[3] -> CARRY4.CIN
//
// Note that CARRY4.CYINIT does not **require** dedicated interconnect, so
// it doesn't qualify.
//
// This class discovers dedicated interconnect by examing the routing graph.
// This discovery make be expensive, and require caching to accelerate
// startup.
struct DedicatedInterconnect
{
const Context *ctx;
dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sinks;
dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sources;
void init(const Context *ctx);
// Is this BEL placed in a location that is valid based on dedicated
// interconnect?
//
// Note: Only BEL pin sinks are checked.
bool isBelLocationValid(BelId bel, const CellInfo *cell) const;
void explain_bel_status(BelId bel, const CellInfo *cell) const;
void find_dedicated_interconnect();
void print_dedicated_interconnect() const;
bool check_routing(BelId src_bel, IdString src_bel_pin, BelId dst_bel, IdString dst_bel_pin, bool site_only) const;
void expand_sink_bel(BelId bel, IdString pin, WireId wire);
void expand_source_bel(BelId bel, IdString pin, WireId wire);
bool is_driver_on_net_valid(BelId driver_bel, const CellInfo *cell, IdString driver_port, NetInfo *net) const;
bool is_sink_on_net_valid(BelId bel, const CellInfo *cell, IdString port_name, NetInfo *net) const;
};
NEXTPNR_NAMESPACE_END
#endif /* DEDICATED_INTERCONNECT_H */

View File

@ -1,76 +0,0 @@
## FPGA interchange instructions
These are instructions on how to get the dependencies, generate the FPGA interchange architecture build system and
run some example designs.
### Installing dependencies
Install java and javac if not already installed:
```
# Or equivalent for your local system.
sudo apt-get install openjdk-10-jdk
```
Install capnproto if not already installed. Version 0.8.0 is required.
As stated in the [official instructions](https://capnproto.org/install.html), the version on the common package managers
might not be up to date with the latest version, hence it is suggested to install
from the archive or, in alternative, directly from the git repository.
Install capnproto-java if not already installed:
```
git clone https://github.com/capnproto/capnproto-java.git
cd capnproto-java
make
sudo make install
```
Install python-fpga-interchange if not already installed:
```
git clone https://github.com/SymbiFlow/python-fpga-interchange.git
cd python-fpga-interchange.git
#
# Note: Recommend checking out a specific release, for example:
#
# git checkout v0.0.5
#
# Release of python-fpga-interchange library does have to match nextpnr
# implementation.
python -m pip install -e .
```
Clone RapidWright, if not already cloned:
```
git clone https://github.com/Xilinx/RapidWright.git
cd RapidWright
make update_jars
```
### Build instructions
Once dependencies are installed/cloned, configure the build system for the FPGA interchange.
From the nextpnr root dir run:
```
mkdir build
cd build
cmake .. --DARCH=fpga_interchange -DRAPIDWRIGHT_PATH=<RapidWright path> -DINTERCHANGE_SCHEMA_PATH=<fpga-interchange-schema path> -DPYTHON_INTERCHANGE_PATH=<python-fpga-interchange path>
```
To build the xc7a35t architecture, run:
```
make chipdb-xc7a35t-bin
```
To build the example designs run:
```
make test-fpga_interchange-wire_arty-dcp
```
The make targets for the example designs follow the same pattern: `test-fpga_interchange-<test_name>-<output>`, where `output` is the name of the intermediate step of the build which can be:
- `json`: synthesis output
- `netlist`: logical netlist
- `phys`: physical netlist
- `dcp`: design checkpoint

View File

@ -1,50 +0,0 @@
function(add_board)
# ~~~
# add_board(
# name <board name>
# device_family <device family>
# device <common device>
# package <package>
# )
# ~~~
#
# Generates a board target containing information on the common device and package
# of the board.
#
# Arguments:
# - name: name of the board. E.g. arty
# - device_family: the name of the family this device belongs to.
# E.g. the xc7a35t device belongs to the xc7 family
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - package: one of the packages available for a given device. E.g. cpg236
#
# Targets generated:
# - board-<name>
set(options)
set(oneValueArgs name device_family device package)
set(multiValueArgs)
cmake_parse_arguments(
add_board
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(name ${add_board_name})
set(device_family ${add_board_device_family})
set(device ${add_board_device})
set(package ${add_board_package})
add_custom_target(board-${name} DEPENDS device-${device})
set_target_properties(
board-${name}
PROPERTIES
DEVICE_FAMILY ${device_family}
DEVICE ${device}
PACKAGE ${package}
)
endfunction()

View File

@ -1,49 +0,0 @@
add_board(
name arty35t
device_family xc7
device xc7a35t
package csg324
)
add_board(
name arty100t
device_family xc7
device xc7a100t
package csg324
)
add_board(
name nexys_video
device_family xc7
device xc7a200t
package sbg484
)
add_board(
name basys3
device_family xc7
device xc7a35t
package cpg236
)
add_board(
name zybo
device_family xc7
device xc7z010
package clg400
)
# This isn't a real board, all the real boards currently available use the LIFCL-40 but the LIFCL-17 speeds up runtime for testing
add_board(
name lifcl17
device_family nexus
device LIFCL-17
package QFN72
)
add_board(
name lifcl40evn
device_family nexus
device LIFCL-40
package CABGA400
)

View File

@ -1,341 +0,0 @@
include(${family}/examples/chipdb_xilinx.cmake)
include(${family}/examples/chipdb_nexus.cmake)
function(create_patched_device_db)
# ~~~
# create_patched_device_db(
# device <common device>
# patch_name <patch_name>
# patch_path <patch_path>
# patch_format <patch_format>
# patch_data <patch_data>
# input_device <input device target>
# output_target <output device target>
# )
# ~~~
#
# Generates a patched device database starting from an input device
#
# If output_target is specified, the variable named as the output_target
# parameter value is set to the generated output_device_file target.
#
# Arguments:
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix.
# - patch_name: name of the patch which determines the target name
# - patch_path: patch_path argument for the fpga_interchange.patch call
# - patch_format: patch_format argument for the fpga_interchange.patch call
# - patch_data: path to the patch_data required for the fpga_interchange.patch call
# - input_device: target for the device that needs to be patched
# - output_target: variable name that will hold the output device target for the parent scope
#
# Targets generated:
# - <patch_name>-<device>-device
set(options)
set(oneValueArgs device patch_name patch_path patch_format patch_data input_device output_target)
set(multiValueArgs)
cmake_parse_arguments(
create_patched_device_db
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${create_patched_device_db_device})
set(patch_name ${create_patched_device_db_patch_name})
set(patch_path ${create_patched_device_db_patch_path})
set(patch_format ${create_patched_device_db_patch_format})
set(patch_data ${create_patched_device_db_patch_data})
set(input_device ${create_patched_device_db_input_device})
set(output_target ${create_patched_device_db_output_target})
get_target_property(input_device_loc ${input_device} LOCATION)
set(output_device_file ${CMAKE_CURRENT_BINARY_DIR}/${device}_${patch_name}.device)
add_custom_command(
OUTPUT ${output_device_file}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.patch
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--schema device
--patch_path ${patch_path}
--patch_format ${patch_format}
${input_device_loc}
${patch_data}
${output_device_file}
DEPENDS
${patch_data}
${input_device}
${input_device_loc}
)
add_custom_target(${patch_name}-${device}-device DEPENDS ${output_device_file})
set_property(TARGET ${patch_name}-${device}-device PROPERTY LOCATION ${output_device_file})
add_custom_target(${patch_name}-${device}-device-yaml
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.convert
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--schema device
--input_format capnp
--output_format yaml
${output_device_file}
${output_device_file}.yaml
DEPENDS ${output_device_file})
if (DEFINED output_target)
set(${output_target} ${patch_name}-${device}-device PARENT_SCOPE)
endif()
endfunction()
function(patch_device_with_prim_lib)
# ~~~
# patch_device_with_prim_lib(
# device <common device>
# yosys_script <yosys script>
# input_device <input device target>
# output_target <output device target>
# )
# ~~~
#
# Patches an input device with a primitive library from Yosys
#
# If output_target is specified, the variable named as the output_target
# parameter value is set to the generated output_device_file target.
#
# Arguments:
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix.
# - yosys_script: yosys script to produce cell library
# - input_device: target for the device that needs to be patched
# - output_target: variable name that will hold the output device target for the parent scope
#
# Targets generated:
# - prims-<device>-device
set(options)
set(oneValueArgs device yosys_script input_device output_target)
set(multiValueArgs)
cmake_parse_arguments(
patch_device_with_prim_lib
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${patch_device_with_prim_lib_device})
set(yosys_script ${patch_device_with_prim_lib_yosys_script})
set(input_device ${patch_device_with_prim_lib_input_device})
set(output_target ${patch_device_with_prim_lib_output_target})
get_target_property(input_device_loc ${input_device} LOCATION)
set(output_device_file ${CMAKE_CURRENT_BINARY_DIR}/${device}_prim_lib.device)
set(output_json_file ${CMAKE_CURRENT_BINARY_DIR}/${device}_prim_lib.json)
add_custom_command(
OUTPUT ${output_json_file}
COMMAND
yosys -p '${yosys_script}\; write_json ${output_json_file}'
)
add_custom_command(
OUTPUT ${output_device_file}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.add_prim_lib
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
${input_device_loc}
${output_json_file}
${output_device_file}
DEPENDS
${input_device}
${input_device_loc}
${output_json_file}
)
add_custom_target(prims-${device}-device DEPENDS ${output_device_file})
set_property(TARGET prims-${device}-device PROPERTY LOCATION ${output_device_file})
if (DEFINED output_target)
set(${output_target} prims-${device}-device PARENT_SCOPE)
endif()
endfunction()
function(generate_chipdb)
# ~~~
# generate_chipdb(
# family <family>
# device <common device>
# part <part>
# device_target <device target>
# device_config <device config>
# test_package <test_package>
# )
# ~~~
#
# Generates a chipdb BBA file, starting from a device database.
#
# The chipdb binary file is directly generated to the
# <nextpnr-root>/build/fpga_interchange/chipdb/ directory.
#
# The package argument is only used to run the architecture check target.
#
# Arguments:
# - family: nextpnr architecture family (e.g. fpga_interchange)
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - part: one among the parts available for a given device
# - device_target: target for the device from which the chipdb is generated
# - device_config: path to the device configYAML file
# This file specifies some nextpnr specific data, such as BEL bucket
# seeds and global BEL names.
# - test_package: package among the ones available for the device. This is used for architecture
# testing only
#
# Targets generated:
# - chipdb-${device}-bba
# - chipdb-${device}-bin
# - device-${device}
#
# The device-${device} target contains properties to get the interchange device as well
# as the binary chipdb
set(options)
set(oneValueArgs family device part device_target device_config test_package)
set(multiValueArgs)
cmake_parse_arguments(
generate_chipdb
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(family ${generate_chipdb_family})
set(device ${generate_chipdb_device})
set(part ${generate_chipdb_part})
set(device_target ${generate_chipdb_device_target})
set(device_config ${generate_chipdb_device_config})
set(test_package ${generate_chipdb_test_package})
get_target_property(device_loc ${device_target} LOCATION)
set(chipdb_bba ${CMAKE_CURRENT_BINARY_DIR}/chipdb.bba)
add_custom_command(
OUTPUT ${chipdb_bba}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.nextpnr_emit
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--output_dir ${CMAKE_CURRENT_BINARY_DIR}
--device_config ${device_config}
--device ${device_loc}
DEPENDS
${device_config}
${device_target}
${device_loc}
)
add_custom_target(chipdb-${device}-bba DEPENDS ${chipdb_bba})
set(chipdb_bin ${chipdb_dir}/chipdb-${device}.bin)
add_custom_command(
OUTPUT ${chipdb_bin}
COMMAND
bbasm -l ${chipdb_bba} ${chipdb_bin}
DEPENDS
chipdb-${device}-bba
${chipdb_bba}
bbasm
)
add_custom_target(chipdb-${device}-bin DEPENDS ${chipdb_bin})
# Setting device target properties
add_custom_target(device-${device})
set_target_properties(
device-${device}
PROPERTIES
DEVICE_LOC ${device_loc}
DEVICE_TARGET ${device_target}
CHIPDB_BIN_LOC ${chipdb_bin}
CHIPDB_BIN_TARGET chipdb-${device}-bin
)
# Generate architecture check target
add_custom_target(
chipdb-${device}-bin-check
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin}
--package ${test_package}
--test
DEPENDS
${chipdb_bin}
chipdb-${device}-bin
)
add_custom_target(
chipdb-${device}-bin-check-verbose
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin}
--package ${test_package}
--test --verbose
DEPENDS
${chipdb_bin}
chipdb-${device}-bin
)
add_custom_target(
chipdb-${device}-bin-check-verbose2
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin}
--package ${test_package}
--test --debug
DEPENDS
${chipdb_bin}
chipdb-${device}-bin
)
add_custom_target(
chipdb-${device}-bin-check-debug
COMMAND gdb --args
$<TARGET_FILE:nextpnr-fpga_interchange>
--chipdb ${chipdb_bin}
--package ${test_package}
--test
DEPENDS
${chipdb_bin}
chipdb-${device}-bin
)
add_custom_target(
chipdb-${device}-bin-check-test-data
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin}
--package ${test_package}
--run ${PROJECT_SOURCE_DIR}/python/check_arch_api.py
DEPENDS
${chipdb_bin}
chipdb-${device}-bin
${test_data_binary}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
add_dependencies(all-${family}-archcheck-tests chipdb-${device}-bin-check-test-data chipdb-${device}-bin-check)
# All tests targets for this device are added to this target
add_custom_target(
all-${device}-tests
DEPENDS
chipdb-${device}-bin-check-test-data
chipdb-${device}-bin-check
)
endfunction()

View File

@ -1,101 +0,0 @@
function(create_prjoxide_device_db)
# ~~~
# create_prjoxide_device_db(
# device <common device>
# output_target <output device target>
# )
# ~~~
#
# Generates a device database from Project Oxide
#
# If output_target is specified, the output_target_name variable
# is set to the generated output_device_file target.
#
# Arguments:
# - device: common device name of a set of parts. E.g. LIFCL-17
# - output_target: variable name that will hold the output device target for the parent scope
#
# Targets generated:
# - prjoxide-<device>-device
set(options)
set(oneValueArgs device output_target)
set(multiValueArgs)
cmake_parse_arguments(
create_prjoxide_device_db
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${create_prjoxide_device_db_device})
set(output_target ${create_prjoxide_device_db_output_target})
set(prjoxide_device_db ${CMAKE_CURRENT_BINARY_DIR}/${device}.device)
add_custom_command(
OUTPUT ${prjoxide_device_db}
COMMAND
${PRJOXIDE_PREFIX}/bin/prjoxide
interchange-export
${device}
${prjoxide_device_db}
DEPENDS
${PRJOXIDE_PREFIX}/bin/prjoxide
)
add_custom_target(prjoxide-${device}-device DEPENDS ${prjoxide_device_db})
set_property(TARGET prjoxide-${device}-device PROPERTY LOCATION ${prjoxide_device_db})
if (DEFINED output_target)
set(${output_target} prjoxide-${device}-device PARENT_SCOPE)
endif()
endfunction()
function(generate_nexus_device_db)
# ~~~
# generate_nexus_device_db(
# device <common device>
# device_target <variable name for device target>
# )
# ~~~
#
# Generates a chipdb BBA file, starting from a Project Oxide device database.
# Patches applied:
# - primitive library from Yosys
#
# Arguments:
# - device: common device name of a set of parts. E.g. LIFCL-17
# - device_target: variable name that will hold the output device target for the parent scope
set(options)
set(oneValueArgs device device_target)
set(multiValueArgs)
cmake_parse_arguments(
generate_nexus_device_db
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${generate_nexus_device_db_device})
set(device_target ${generate_nexus_device_db_device_target})
create_prjoxide_device_db(
device ${device}
output_target prjoxide_device
)
# Add primitive library
patch_device_with_prim_lib(
device ${device}
yosys_script synth_nexus
input_device ${prjoxide_device}
output_target prjoxide_prims_device
)
if(DEFINED device_target)
set(${device_target} ${prjoxide_prims_device} PARENT_SCOPE)
endif()
endfunction()

View File

@ -1,138 +0,0 @@
function(create_rapidwright_device_db)
# ~~~
# create_rapidwright_device_db(
# device <common device>
# part <part>
# output_target <output device target>
# )
# ~~~
#
# Generates a device database from RapidWright
#
# If output_target is specified, the output_target_name variable
# is set to the generated output_device_file target.
#
# Arguments:
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - part: one among the parts available for a given device
# - output_target: variable name that will hold the output device target for the parent scope
#
# Targets generated:
# - rapidwright-<device>-device
set(options)
set(oneValueArgs device part output_target)
set(multiValueArgs)
cmake_parse_arguments(
create_rapidwright_device_db
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${create_rapidwright_device_db_device})
set(part ${create_rapidwright_device_db_part})
set(output_target ${create_rapidwright_device_db_output_target})
set(rapidwright_device_db ${CMAKE_CURRENT_BINARY_DIR}/${part}.device)
add_custom_command(
OUTPUT ${rapidwright_device_db}
COMMAND
RAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH}
${INVOKE_RAPIDWRIGHT} ${JAVA_HEAP_SPACE}
com.xilinx.rapidwright.interchange.DeviceResourcesExample
${part}
DEPENDS
${INVOKE_RAPIDWRIGHT}
)
add_custom_target(rapidwright-${device}-device DEPENDS ${rapidwright_device_db})
set_property(TARGET rapidwright-${device}-device PROPERTY LOCATION ${rapidwright_device_db})
add_custom_target(rapidwright-${device}-device-yaml
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.convert
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--schema device
--input_format capnp
--output_format yaml
${rapidwright_device_db}
${rapidwright_device_db}.yaml
DEPENDS ${rapidwright_device_db})
if (DEFINED output_target)
set(${output_target} rapidwright-${device}-device PARENT_SCOPE)
endif()
endfunction()
function(generate_xc7_device_db)
# ~~~
# generate_xc7_device_db(
# device <common device>
# part <part>
# device_target <variable name for device target>
# )
# ~~~
#
# Generates a chipdb BBA file, starting from a RapidWright device database which is then patched.
# Patches applied:
# - constraints patch
# - luts patch
#
# Arguments:
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - part: one among the parts available for a given device
# - device_target: variable name that will hold the output device target for the parent scope
set(options)
set(oneValueArgs device part device_target)
set(multiValueArgs)
cmake_parse_arguments(
create_rapidwright_device_db
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(device ${create_rapidwright_device_db_device})
set(part ${create_rapidwright_device_db_part})
set(device_target ${create_rapidwright_device_db_device_target})
create_rapidwright_device_db(
device ${device}
part ${part}
output_target rapidwright_device
)
# Generate constraints patch
create_patched_device_db(
device ${device}
patch_name constraints
patch_path constraints
patch_format yaml
patch_data ${PYTHON_INTERCHANGE_PATH}/test_data/series7_constraints.yaml
input_device ${rapidwright_device}
output_target constraints_device
)
# Generate lut constraints patch
create_patched_device_db(
device ${device}
patch_name constraints-luts
patch_path lutDefinitions
patch_format yaml
patch_data ${PYTHON_INTERCHANGE_PATH}/test_data/series7_luts.yaml
input_device ${constraints_device}
output_target constraints_luts_device
)
if(DEFINED device_target)
set(${device_target} ${constraints_luts_device} PARENT_SCOPE)
endif()
endfunction()

View File

@ -1,11 +0,0 @@
# Artix-7 devices
add_subdirectory(xc7a35t)
add_subdirectory(xc7a100t)
add_subdirectory(xc7a200t)
# Zynq-7 devices
add_subdirectory(xc7z010)
# Nexus devices
add_subdirectory(LIFCL-17)
add_subdirectory(LIFCL-40)

View File

@ -1,13 +0,0 @@
generate_nexus_device_db(
device LIFCL-17
device_target lifcl17_target
)
generate_chipdb(
family ${family}
device LIFCL-17
part LIFCL-17-7SG72C
device_target ${lifcl17_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/nexus_device_config.yaml
test_package QFN72
)

View File

@ -1,8 +0,0 @@
pip_test:
- src_wire: R3C3_PLC.PLC/JDI0_SLICEA
dst_wire: R3C3/JF0
bel_pin_test:
- bel: R7C3_PLC.PLC/SLICEA_LUT0
pin: D
wire: R7C3_PLC.PLC/JD0_SLICEA

View File

@ -1,13 +0,0 @@
generate_nexus_device_db(
device LIFCL-40
device_target lifcl40_target
)
generate_chipdb(
family ${family}
device LIFCL-40
part LIFCL-40-9BG400C
device_target ${lifcl40_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/nexus_device_config.yaml
test_package CABGA400
)

View File

@ -1,8 +0,0 @@
pip_test:
- src_wire: R3C3_PLC.PLC/JDI0_SLICEA
dst_wire: R3C3/JF0
bel_pin_test:
- bel: R7C3_PLC.PLC/SLICEA_LUT0
pin: D
wire: R7C3_PLC.PLC/JD0_SLICEA

View File

@ -1,14 +0,0 @@
generate_xc7_device_db(
device xc7a100t
part xc7a100tcsg324-1
device_target xc7a100t_target
)
generate_chipdb(
family ${family}
device xc7a100t
part xc7a100tcsg324-1
device_target ${xc7a100t_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/series7_device_config.yaml
test_package csg324
)

View File

@ -1,36 +0,0 @@
pip_test:
- src_wire: CLBLM_R_X11Y93/CLBLM_L_D3
dst_wire: SLICE_X15Y93.SLICEL/D3
pip_chain_test:
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- TIEOFF_X3Y145.TIEOFF/$GND_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD0GND_HARD0
- INT_R_X3Y145/GND_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- TIEOFF_X3Y145.TIEOFF/$VCC_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD1VCC_HARD1
- INT_R_X3Y145/VCC_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- SLICE_X3Y145.SLICEL/$VCC_SITE_WIRE
- SLICE_X3Y145.SLICEL/CEUSEDVCC_HARD1
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- SLICE_X3Y145.SLICEL/$GND_SITE_WIRE
- SLICE_X3Y145.SLICEL/SRUSEDGND_HARD0
bel_pin_test:
- bel: SLICE_X15Y93.SLICEL/D6LUT
pin: A3
wire: SLICE_X15Y93.SLICEL/D3
- bel: $CONSTANTS_X0Y0.$CONSTANTS/GND
pin: G
wire: $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- bel: $CONSTANTS_X0Y0.$CONSTANTS/VCC
pin: P
wire: $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE

View File

@ -1,14 +0,0 @@
generate_xc7_device_db(
device xc7a200t
part xc7a200tsbg484-1
device_target xc7a200t_target
)
generate_chipdb(
family ${family}
device xc7a200t
part xc7a200tsbg484-1
device_target ${xc7a200t_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/series7_device_config.yaml
test_package sbg484
)

View File

@ -1,36 +0,0 @@
pip_test:
- src_wire: CLBLM_R_X11Y93/CLBLM_L_D3
dst_wire: SLICE_X15Y93.SLICEL/D3
pip_chain_test:
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- TIEOFF_X3Y145.TIEOFF/$GND_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD0GND_HARD0
- INT_R_X3Y145/GND_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- TIEOFF_X3Y145.TIEOFF/$VCC_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD1VCC_HARD1
- INT_R_X3Y145/VCC_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- SLICE_X3Y145.SLICEL/$VCC_SITE_WIRE
- SLICE_X3Y145.SLICEL/CEUSEDVCC_HARD1
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- SLICE_X3Y145.SLICEL/$GND_SITE_WIRE
- SLICE_X3Y145.SLICEL/SRUSEDGND_HARD0
bel_pin_test:
- bel: SLICE_X15Y93.SLICEL/D6LUT
pin: A3
wire: SLICE_X15Y93.SLICEL/D3
- bel: $CONSTANTS_X0Y0.$CONSTANTS/GND
pin: G
wire: $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- bel: $CONSTANTS_X0Y0.$CONSTANTS/VCC
pin: P
wire: $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE

View File

@ -1,14 +0,0 @@
generate_xc7_device_db(
device xc7a35t
part xc7a35tcsg324-1
device_target xc7a35t_target
)
generate_chipdb(
family ${family}
device xc7a35t
part xc7a35tcsg324-1
device_target ${xc7a35t_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/series7_device_config.yaml
test_package csg324
)

View File

@ -1,40 +0,0 @@
pip_test:
- src_wire: CLBLM_R_X11Y93/CLBLM_L_D3
dst_wire: SLICE_X15Y93.SLICEL/D3
pip_chain_test:
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- TIEOFF_X3Y145.TIEOFF/$GND_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD0GND_HARD0
- INT_R_X3Y145/GND_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- TIEOFF_X3Y145.TIEOFF/$VCC_SITE_WIRE
- TIEOFF_X3Y145.TIEOFF/HARD1VCC_HARD1
- INT_R_X3Y145/VCC_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- SLICE_X3Y145.SLICEL/$VCC_SITE_WIRE
- SLICE_X3Y145.SLICEL/CEUSEDVCC_HARD1
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- SLICE_X3Y145.SLICEL/$GND_SITE_WIRE
- SLICE_X3Y145.SLICEL/SRUSEDGND_HARD0
bel_pin_test:
- bel: SLICE_X15Y93.SLICEL/D6LUT
pin: A3
wire: SLICE_X15Y93.SLICEL/D3
- bel: $CONSTANTS_X0Y0.$CONSTANTS/GND
pin: G
wire: $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- bel: $CONSTANTS_X0Y0.$CONSTANTS/VCC
pin: P
wire: $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- bel: SLICE_X1Y19.SLICEL/SRUSEDGND
pin: "0"
wire: SLICE_X1Y19.SLICEL/SRUSEDGND_HARD0
type: PORT_OUT

View File

@ -1,14 +0,0 @@
generate_xc7_device_db(
device xc7z010
part xc7z010clg400-1
device_target xc7z010_target
)
generate_chipdb(
family ${family}
device xc7z010
part xc7z010clg400-1
device_target ${xc7z010_target}
device_config ${PYTHON_INTERCHANGE_PATH}/test_data/series7_device_config.yaml
test_package clg400
)

View File

@ -1,36 +0,0 @@
pip_test:
- src_wire: CLBLM_L_X8Y69/CLBLM_L_D3
dst_wire: SLICE_X11Y69.SLICEL/D3
pip_chain_test:
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- TIEOFF_X9Y69.TIEOFF/$GND_SITE_WIRE
- TIEOFF_X9Y69.TIEOFF/HARD0GND_HARD0
- INT_L_X8Y69/GND_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- TIEOFF_X9Y69.TIEOFF/$VCC_SITE_WIRE
- TIEOFF_X9Y69.TIEOFF/HARD1VCC_HARD1
- INT_L_X8Y69/VCC_WIRE
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE
- $CONSTANTS_X0Y0/$VCC_NODE
- SLICE_X11Y69.SLICEL/$VCC_SITE_WIRE
- SLICE_X11Y69.SLICEL/CEUSEDVCC_HARD1
- wires:
- $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- $CONSTANTS_X0Y0/$GND_NODE
- SLICE_X11Y69.SLICEL/$GND_SITE_WIRE
- SLICE_X11Y69.SLICEL/SRUSEDGND_HARD0
bel_pin_test:
- bel: SLICE_X14Y63.SLICEL/D6LUT
pin: A3
wire: SLICE_X14Y63.SLICEL/D3
- bel: $CONSTANTS_X0Y0.$CONSTANTS/GND
pin: G
wire: $CONSTANTS_X0Y0.$CONSTANTS/$GND_SOURCE
- bel: $CONSTANTS_X0Y0.$CONSTANTS/VCC
pin: P
wire: $CONSTANTS_X0Y0.$CONSTANTS/$VCC_SOURCE

View File

@ -1,180 +0,0 @@
// Inverter support is still a TODO
module INV(input A, output Z);
LUT4 #(.INIT("0x5555")) _TECHMAP_REPLACE_ (.A(A), .B(1'b1), .C(1'b1), .D(1'b1), .Z(Z));
endmodule
module PDPSC16K (...);
parameter DATA_WIDTH_W = "X36";
parameter DATA_WIDTH_R = "X36";
parameter OUTREG = "BYPASSED";
parameter RESETMODE = "SYNC";
parameter GSR = "ENABLED";
parameter ECC = "DISABLED";
parameter INITVAL_00 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_01 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_02 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_03 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_04 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_05 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_06 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_07 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_08 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_09 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_0F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_10 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_11 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_12 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_13 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_14 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_15 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_16 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_17 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_18 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_19 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_1F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_20 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_21 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_22 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_23 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_24 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_25 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_26 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_27 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_28 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_29 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_2F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_30 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_31 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_32 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_33 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_34 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_35 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_36 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_37 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_38 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_39 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter INITVAL_3F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
parameter CSDECODE_W = "000";
parameter CSDECODE_R = "000";
parameter ASYNC_RST_RELEASE = "SYNC";
parameter INIT_DATA = "STATIC";
input [35:0] DI;
input [13:0] ADW;
input [13:0] ADR;
input CLK;
input CER;
input CEW;
input [2:0] CSW;
input [2:0] CSR;
input RST;
output [35:0] DO;
output ONEBITERR;
output TWOBITERR;
// TODO: this should really be a macro or otherwise dealt with more automatically
PDPSC16K_MODE #(
.DATA_WIDTH_W(DATA_WIDTH_W),
.DATA_WIDTH_R(DATA_WIDTH_R),
.OUTREG(OUTREG),
.GSR(GSR),
.ECC(ECC),
.CSDECODE_W(CSDECODE_W),
.CSDECODE_R(CSDECODE_R),
.ASYNC_RST_RELEASE(ASYNC_RST_RELEASE),
.INITVAL_00(INITVAL_00),
.INITVAL_01(INITVAL_01),
.INITVAL_02(INITVAL_02),
.INITVAL_03(INITVAL_03),
.INITVAL_04(INITVAL_04),
.INITVAL_05(INITVAL_05),
.INITVAL_06(INITVAL_06),
.INITVAL_07(INITVAL_07),
.INITVAL_08(INITVAL_08),
.INITVAL_09(INITVAL_09),
.INITVAL_0A(INITVAL_0A),
.INITVAL_0B(INITVAL_0B),
.INITVAL_0C(INITVAL_0C),
.INITVAL_0D(INITVAL_0D),
.INITVAL_0E(INITVAL_0E),
.INITVAL_0F(INITVAL_0F),
.INITVAL_10(INITVAL_10),
.INITVAL_11(INITVAL_11),
.INITVAL_12(INITVAL_12),
.INITVAL_13(INITVAL_13),
.INITVAL_14(INITVAL_14),
.INITVAL_15(INITVAL_15),
.INITVAL_16(INITVAL_16),
.INITVAL_17(INITVAL_17),
.INITVAL_18(INITVAL_18),
.INITVAL_19(INITVAL_19),
.INITVAL_1A(INITVAL_1A),
.INITVAL_1B(INITVAL_1B),
.INITVAL_1C(INITVAL_1C),
.INITVAL_1D(INITVAL_1D),
.INITVAL_1E(INITVAL_1E),
.INITVAL_1F(INITVAL_1F),
.INITVAL_20(INITVAL_20),
.INITVAL_21(INITVAL_21),
.INITVAL_22(INITVAL_22),
.INITVAL_23(INITVAL_23),
.INITVAL_24(INITVAL_24),
.INITVAL_25(INITVAL_25),
.INITVAL_26(INITVAL_26),
.INITVAL_27(INITVAL_27),
.INITVAL_28(INITVAL_28),
.INITVAL_29(INITVAL_29),
.INITVAL_2A(INITVAL_2A),
.INITVAL_2B(INITVAL_2B),
.INITVAL_2C(INITVAL_2C),
.INITVAL_2D(INITVAL_2D),
.INITVAL_2E(INITVAL_2E),
.INITVAL_2F(INITVAL_2F),
.INITVAL_30(INITVAL_30),
.INITVAL_31(INITVAL_31),
.INITVAL_32(INITVAL_32),
.INITVAL_33(INITVAL_33),
.INITVAL_34(INITVAL_34),
.INITVAL_35(INITVAL_35),
.INITVAL_36(INITVAL_36),
.INITVAL_37(INITVAL_37),
.INITVAL_38(INITVAL_38),
.INITVAL_39(INITVAL_39),
.INITVAL_3A(INITVAL_3A),
.INITVAL_3B(INITVAL_3B),
.INITVAL_3C(INITVAL_3C),
.INITVAL_3D(INITVAL_3D),
.INITVAL_3E(INITVAL_3E),
.INITVAL_3F(INITVAL_3F),
.INIT_DATA(INIT_DATA)
) _TECHMAP_REPLACE_ (
.CLK(CLK), .CER(CER), .CEW(CEW), .RST(RST),
.CSW0(CSW[0]), .CSW1(CSW[1]), .CSW2(CSW[2]),
.CSR0(CSR[0]), .CSR1(CSR[1]), .CSR2(CSR[2]),
.DI0(DI[0]), .DI1(DI[1]), .DI2(DI[2]), .DI3(DI[3]), .DI4(DI[4]), .DI5(DI[5]), .DI6(DI[6]), .DI7(DI[7]), .DI8(DI[8]), .DI9(DI[9]), .DI10(DI[10]), .DI11(DI[11]), .DI12(DI[12]), .DI13(DI[13]), .DI14(DI[14]), .DI15(DI[15]), .DI16(DI[16]), .DI17(DI[17]), .DI18(DI[18]), .DI19(DI[19]), .DI20(DI[20]), .DI21(DI[21]), .DI22(DI[22]), .DI23(DI[23]), .DI24(DI[24]), .DI25(DI[25]), .DI26(DI[26]), .DI27(DI[27]), .DI28(DI[28]), .DI29(DI[29]), .DI30(DI[30]), .DI31(DI[31]), .DI32(DI[32]), .DI33(DI[33]), .DI34(DI[34]), .DI35(DI[35]),
.ADW0(ADW[0]), .ADW1(ADW[1]), .ADW2(ADW[2]), .ADW3(ADW[3]), .ADW4(ADW[4]), .ADW5(ADW[5]), .ADW6(ADW[6]), .ADW7(ADW[7]), .ADW8(ADW[8]), .ADW9(ADW[9]), .ADW10(ADW[10]), .ADW11(ADW[11]), .ADW12(ADW[12]), .ADW13(ADW[13]),
.ADR0(ADR[0]), .ADR1(ADR[1]), .ADR2(ADR[2]), .ADR3(ADR[3]), .ADR4(ADR[4]), .ADR5(ADR[5]), .ADR6(ADR[6]), .ADR7(ADR[7]), .ADR8(ADR[8]), .ADR9(ADR[9]), .ADR10(ADR[10]), .ADR11(ADR[11]), .ADR12(ADR[12]), .ADR13(ADR[13]),
.DO0(DO[0]), .DO1(DO[1]), .DO2(DO[2]), .DO3(DO[3]), .DO4(DO[4]), .DO5(DO[5]), .DO6(DO[6]), .DO7(DO[7]), .DO8(DO[8]), .DO9(DO[9]), .DO10(DO[10]), .DO11(DO[11]), .DO12(DO[12]), .DO13(DO[13]), .DO14(DO[14]), .DO15(DO[15]), .DO16(DO[16]), .DO17(DO[17]), .DO18(DO[18]), .DO19(DO[19]), .DO20(DO[20]), .DO21(DO[21]), .DO22(DO[22]), .DO23(DO[23]), .DO24(DO[24]), .DO25(DO[25]), .DO26(DO[26]), .DO27(DO[27]), .DO28(DO[28]), .DO29(DO[29]), .DO30(DO[30]), .DO31(DO[31]), .DO32(DO[32]), .DO33(DO[33]), .DO34(DO[34]), .DO35(DO[35]),
.ONEBITERR(ONEBITERR), .TWOBITERR(TWOBITERR),
);
endmodule

View File

@ -1,11 +0,0 @@
module INV(input I, output O);
LUT1 #(.INIT(2'b01)) _TECHMAP_REPLACE_ (.I0(I), .O(O));
endmodule
module BUF(input I, output O);
LUT1 #(.INIT(2'b10)) _TECHMAP_REPLACE_ (.I0(I), .O(O));
endmodule

View File

@ -1,405 +0,0 @@
function(add_interchange_test)
# ~~~
# add_interchange_test(
# name <name>
# family <family>
# device <common device>
# package <package>
# tcl <tcl>
# xdc <xdc>
# sources <sources list>
# [top <top name>]
# [techmap <techmap file>]
# [output_fasm]
# [device_family <device family>]
# )
#
# Generates targets to run desired tests
#
# Arguments:
# - name: test name. This must be unique and no other tests with the same
# name should exist
# - family: nextpnr architecture family (e.g. fpga_interchange)
# - device_family: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - device: common device name of a set of parts. E.g. xc7a35tcsg324-1 and xc7a35tcpg236-1
# share the same xc7a35t device prefix
# - package: package among the ones available for the device
# - tcl: tcl script used for synthesis
# - xdc: constraints file used in the physical netlist generation step
# - sources: list of HDL sources
# - top (optional): name of the top level module.
# If not provided, "top" is assigned as top level module
# - techmap (optional): techmap file used during synthesis
# - output_fasm (optional): generates a fasm output
# - device_family (optional): this information is used during FASM generation, therfore it is
# required only if the `output_fasm` option is enabled
#
# Targets generated:
# - test-fpga_interchange-<name>-json : synthesis output
# - test-fpga_interchange-<name>-netlist : interchange logical netlist
# - test-fpga_interchange-<name>-phys : interchange physical netlist
# - test-fpga_interchange-<name>-dcp : design checkpoint with RapidWright
set(options skip_dcp output_fasm)
set(oneValueArgs name family device package tcl xdc top techmap device_family)
set(multiValueArgs sources)
cmake_parse_arguments(
add_interchange_test
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(name ${add_interchange_test_name})
set(family ${add_interchange_test_family})
set(device ${add_interchange_test_device})
set(package ${add_interchange_test_package})
set(skip_dcp ${add_interchange_test_skip_dcp})
set(output_fasm ${add_interchange_test_output_fasm})
set(top ${add_interchange_test_top})
set(tcl ${CMAKE_CURRENT_SOURCE_DIR}/${add_interchange_test_tcl})
set(xdc ${CMAKE_CURRENT_SOURCE_DIR}/${add_interchange_test_xdc})
set(techmap ${CMAKE_CURRENT_SOURCE_DIR}/${add_interchange_test_techmap})
set(device_family ${add_interchange_test_device_family})
set(sources)
foreach(source ${add_interchange_test_sources})
list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source})
endforeach()
if (NOT DEFINED top)
# Setting default top value
set(top "top")
endif()
# Synthesis
set(synth_json ${CMAKE_CURRENT_BINARY_DIR}/${name}.json)
set(synth_log ${CMAKE_CURRENT_BINARY_DIR}/${name}.json.log)
add_custom_command(
OUTPUT ${synth_json}
COMMAND ${CMAKE_COMMAND} -E env
SOURCES="${sources}"
OUT_JSON=${synth_json}
TECHMAP=${techmap}
yosys -c ${tcl} -l ${synth_log}
DEPENDS ${sources} ${techmap} ${tcl}
)
add_custom_target(test-${family}-${name}-json DEPENDS ${synth_json})
# Logical Netlist
get_property(device_target TARGET device-${device} PROPERTY DEVICE_TARGET)
get_property(device_loc TARGET device-${device} PROPERTY DEVICE_LOC)
set(netlist ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist)
add_custom_command(
OUTPUT ${netlist}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.yosys_json
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--device ${device_loc}
--top ${top}
${synth_json}
${netlist}
DEPENDS
${synth_json}
${device_target}
${device_loc}
)
add_custom_target(test-${family}-${name}-netlist DEPENDS ${netlist})
# Logical Netlist YAML
set(netlist_yaml ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist.yaml)
add_custom_command(
OUTPUT ${netlist_yaml}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.convert
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--schema logical
--input_format capnp
--output_format yaml
${netlist}
${netlist_yaml}
DEPENDS
${netlist}
)
add_custom_target(test-${family}-${name}-netlist-yaml DEPENDS ${netlist_yaml})
# Physical Netlist
get_property(chipdb_bin_target TARGET device-${device} PROPERTY CHIPDB_BIN_TARGET)
get_property(chipdb_bin_loc TARGET device-${device} PROPERTY CHIPDB_BIN_LOC)
set(phys ${CMAKE_CURRENT_BINARY_DIR}/${name}.phys)
set(phys_log ${CMAKE_CURRENT_BINARY_DIR}/${name}.phys.log)
add_custom_command(
OUTPUT ${phys}
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
--log ${phys_log}
DEPENDS
nextpnr-fpga_interchange
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
set(phys_verbose_log ${CMAKE_CURRENT_BINARY_DIR}/${name}.phys.verbose.log)
add_custom_target(
test-${family}-${name}-phys-verbose
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
--verbose
--log ${phys_verbose_log}
DEPENDS
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
add_custom_target(
test-${family}-${name}-phys-verbose2
COMMAND
nextpnr-fpga_interchange
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
--debug
DEPENDS
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
add_custom_target(
test-${family}-${name}-phys-debug
COMMAND gdb --args
$<TARGET_FILE:nextpnr-fpga_interchange>
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
DEPENDS
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
add_custom_target(
test-${family}-${name}-phys-valgrind
COMMAND
PYTHONMALLOC=malloc valgrind
$<TARGET_FILE:nextpnr-fpga_interchange>
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
DEPENDS
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
if(PROFILER)
add_custom_target(
test-${family}-${name}-phys-profile
COMMAND CPUPROFILE=${name}.prof
$<TARGET_FILE:nextpnr-fpga_interchange>
--chipdb ${chipdb_bin_loc}
--xdc ${xdc}
--netlist ${netlist}
--phys ${phys}
--package ${package}
DEPENDS
${netlist}
${xdc}
${chipdb_bin_target}
${chipdb_bin_loc}
)
endif()
add_custom_target(test-${family}-${name}-phys DEPENDS ${phys})
# Physical Netlist YAML
set(phys_yaml ${CMAKE_CURRENT_BINARY_DIR}/${name}.phys.yaml)
add_custom_command(
OUTPUT ${phys_yaml}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.convert
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--schema physical
--input_format capnp
--output_format yaml
${phys}
${phys_yaml}
DEPENDS
${phys}
)
add_custom_target(test-${family}-${name}-phys-yaml DEPENDS ${phys_yaml})
set(last_target "")
if(skip_dcp)
set(last_target test-${family}-${name}-phys)
else()
set(dcp ${CMAKE_CURRENT_BINARY_DIR}/${name}.dcp)
add_custom_command(
OUTPUT ${dcp}
COMMAND
RAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH}
${INVOKE_RAPIDWRIGHT} ${JAVA_HEAP_SPACE}
com.xilinx.rapidwright.interchange.PhysicalNetlistToDcp
${netlist} ${phys} ${xdc} ${dcp}
DEPENDS
${INVOKE_RAPIDWRIGHT}
${phys}
${netlist}
)
add_custom_target(test-${family}-${name}-dcp DEPENDS ${dcp})
set(last_target test-${family}-${name}-dcp)
endif()
add_dependencies(all-${device}-tests ${last_target})
add_dependencies(all-${family}-tests ${last_target})
if(output_fasm)
if(NOT DEFINED device_family)
message(FATAL_ERROR "If FASM output is enabled, the device family must be provided as well!")
endif()
# Output FASM target
set(fasm ${CMAKE_CURRENT_BINARY_DIR}/${name}.fasm)
add_custom_command(
OUTPUT ${fasm}
COMMAND
${Python3_EXECUTABLE} -mfpga_interchange.fasm_generator
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
--family ${device_family}
${device_loc}
${netlist}
${phys}
${fasm}
DEPENDS
${device_target}
${netlist}
${phys}
)
add_custom_target(test-${family}-${name}-fasm DEPENDS ${fasm} ${last_target})
add_dependencies(all-${device}-tests test-${family}-${name}-fasm)
add_dependencies(all-${family}-tests test-${family}-${name}-fasm)
endif()
endfunction()
function(add_interchange_group_test)
# ~~~
# add_interchange_group_test(
# name <name>
# family <family>
# board_list <boards>
# xdc_list <xdc>
# tcl <tcl>
# sources <sources list>
# [top <top name>]
# [techmap <techmap file>]
# [skip_dcp]
# )
#
# Generates targets to run desired tests over multiple devices.
#
# Arguments:
# - name: base test name. The real test name will be <name>_<board>
# - family: nextpnr architecture family (e.g. fpga_interchange)
# - board_list: list of boards, one for each test
# - tcl: tcl script used for synthesis
# - sources: list of HDL sources
# - top (optional): name of the top level module.
# If not provided, "top" is assigned as top level module
# - techmap (optional): techmap file used during synthesis
#
# This function internally calls add_interchange_test to generate the various tests.
#
# Note: it is assumed that there exists an XDC file for each board, with the following naming
# convention: <board>.xdc
set(options output_fasm skip_dcp)
set(oneValueArgs name family tcl top techmap)
set(multiValueArgs sources board_list)
cmake_parse_arguments(
add_interchange_group_test
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(name ${add_interchange_group_test_name})
set(family ${add_interchange_group_test_family})
set(top ${add_interchange_group_test_top})
set(tcl ${add_interchange_group_test_tcl})
set(techmap ${add_interchange_group_test_techmap})
set(sources ${add_interchange_group_test_sources})
set(output_fasm ${add_interchange_group_test_output_fasm})
set(skip_dcp ${add_interchange_group_test_skip_dcp})
set(output_fasm_arg "")
if(output_fasm)
set(output_fasm_arg "output_fasm")
endif()
set(skip_dcp_arg "")
if(skip_dcp)
set(skip_dcp_arg "skip_dcp")
endif()
if (NOT DEFINED top)
# Setting default top value
set(top "top")
endif()
foreach(board ${add_interchange_group_test_board_list})
get_property(device_family TARGET board-${board} PROPERTY DEVICE_FAMILY)
get_property(device TARGET board-${board} PROPERTY DEVICE)
get_property(package TARGET board-${board} PROPERTY PACKAGE)
add_interchange_test(
name ${name}_${board}
family ${family}
device ${device}
device_family ${device_family}
package ${package}
tcl ${tcl}
xdc ${board}.xdc
sources ${sources}
top ${top}
techmap ${techmap}
${output_fasm_arg}
${skip_dcp_arg}
)
endforeach()
endfunction()

View File

@ -1,10 +0,0 @@
add_subdirectory(wire)
add_subdirectory(const_wire)
add_subdirectory(counter)
add_subdirectory(ram)
add_subdirectory(ff)
add_subdirectory(lut)
add_subdirectory(lut_nexus)
add_subdirectory(lutram)
add_subdirectory(obuftds)
add_subdirectory(ram_nexus)

View File

@ -1,7 +0,0 @@
add_interchange_group_test(
name const_wire
family ${family}
board_list basys3 arty35t arty100t
tcl run.tcl
sources wire.v
)

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN H5 [get_ports o]
set_property PACKAGE_PIN J5 [get_ports o2]
set_property PACKAGE_PIN T9 [get_ports o3]
set_property PACKAGE_PIN T10 [get_ports o4]
set_property IOSTANDARD LVCMOS33 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports o2]
set_property IOSTANDARD LVCMOS33 [get_ports o3]
set_property IOSTANDARD LVCMOS33 [get_ports o4]

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN H5 [get_ports o]
set_property PACKAGE_PIN J5 [get_ports o2]
set_property PACKAGE_PIN T9 [get_ports o3]
set_property PACKAGE_PIN T10 [get_ports o4]
set_property IOSTANDARD LVCMOS33 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports o2]
set_property IOSTANDARD LVCMOS33 [get_ports o3]
set_property IOSTANDARD LVCMOS33 [get_ports o4]

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN U16 [get_ports o]
set_property PACKAGE_PIN E19 [get_ports o2]
set_property PACKAGE_PIN U19 [get_ports o3]
set_property PACKAGE_PIN V19 [get_ports o4]
set_property IOSTANDARD LVCMOS33 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports o2]
set_property IOSTANDARD LVCMOS33 [get_ports o3]
set_property IOSTANDARD LVCMOS33 [get_ports o4]

View File

@ -1,14 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_xilinx -nolutram -nowidelut -nosrl -nocarry -nodsp
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,8 +0,0 @@
module top(output o, output o2, output o3, output o4);
assign o = 1'b0;
assign o2 = 1'b1;
assign o3 = 1'b0;
assign o4 = 1'b1;
endmodule

View File

@ -1,19 +0,0 @@
add_interchange_group_test(
name counter
family ${family}
board_list basys3 arty35t arty100t zybo
tcl run_xilinx.tcl
sources counter.v
techmap ../../remap_xilinx.v
output_fasm
)
add_interchange_group_test(
name counter
family ${family}
board_list lifcl17 lifcl40evn
tcl run_nexus.tcl
sources counter.v
techmap ../../remap_nexus.v
skip_dcp
)

View File

@ -1,14 +0,0 @@
## arty-100t board
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN D9 [get_ports rst]
set_property PACKAGE_PIN H5 [get_ports io_led[4]]
set_property PACKAGE_PIN J5 [get_ports io_led[5]]
set_property PACKAGE_PIN T9 [get_ports io_led[6]]
set_property PACKAGE_PIN T10 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,14 +0,0 @@
## arty-35t board
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN D9 [get_ports rst]
set_property PACKAGE_PIN H5 [get_ports io_led[4]]
set_property PACKAGE_PIN J5 [get_ports io_led[5]]
set_property PACKAGE_PIN T9 [get_ports io_led[6]]
set_property PACKAGE_PIN T10 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,14 +0,0 @@
## basys3 breakout board
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN V17 [get_ports rst]
set_property PACKAGE_PIN U16 [get_ports io_led[4]]
set_property PACKAGE_PIN E19 [get_ports io_led[5]]
set_property PACKAGE_PIN U19 [get_ports io_led[6]]
set_property PACKAGE_PIN V19 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,17 +0,0 @@
module top(input clk, input rst, output [7:4] io_led);
localparam SIZE = 32;
reg [SIZE-1:0] counter = SIZE'b0;
assign io_led = {counter[SIZE-1], counter[25:23]};
always @(posedge clk)
begin
if(rst)
counter <= SIZE'b0;
else
counter <= counter + 1;
end
endmodule

View File

@ -1,14 +0,0 @@
## lifcl17 pins for testing based on breakout board
set_property PACKAGE_PIN 55 [get_ports clk]
set_property PACKAGE_PIN 57 [get_ports rst]
set_property PACKAGE_PIN 56 [get_ports io_led[4]]
set_property PACKAGE_PIN 59 [get_ports io_led[5]]
set_property PACKAGE_PIN 60 [get_ports io_led[6]]
set_property PACKAGE_PIN 61 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,13 +0,0 @@
set_property PACKAGE_PIN L13 [get_ports clk]
set_property PACKAGE_PIN G19 [get_ports rst]
set_property PACKAGE_PIN E17 [get_ports io_led[4]]
set_property PACKAGE_PIN F13 [get_ports io_led[5]]
set_property PACKAGE_PIN G13 [get_ports io_led[6]]
set_property PACKAGE_PIN F14 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,15 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_nexus -nolutram -nowidelut -nobram -noccu2 -nodsp
techmap -max_iter 1 -map $::env(TECHMAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,15 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_xilinx -nolutram -nowidelut -nosrl -nodsp
techmap -map $::env(TECHMAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,14 +0,0 @@
# zybo board
set_property PACKAGE_PIN K17 [get_ports clk]
set_property PACKAGE_PIN K18 [get_ports rst]
set_property PACKAGE_PIN M14 [get_ports io_led[4]]
set_property PACKAGE_PIN M15 [get_ports io_led[5]]
set_property PACKAGE_PIN G14 [get_ports io_led[6]]
set_property PACKAGE_PIN D18 [get_ports io_led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports io_led[7]]

View File

@ -1,8 +0,0 @@
add_interchange_group_test(
name ff
family ${family}
board_list basys3 arty35t arty100t
tcl run.tcl
sources ff.v
output_fasm
)

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN A8 [get_ports d]
set_property PACKAGE_PIN D9 [get_ports r]
set_property PACKAGE_PIN H5 [get_ports q]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports d]
set_property IOSTANDARD LVCMOS33 [get_ports r]
set_property IOSTANDARD LVCMOS33 [get_ports q]

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN A8 [get_ports d]
set_property PACKAGE_PIN D9 [get_ports r]
set_property PACKAGE_PIN H5 [get_ports q]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports d]
set_property IOSTANDARD LVCMOS33 [get_ports r]
set_property IOSTANDARD LVCMOS33 [get_ports q]

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN U16 [get_ports d]
set_property PACKAGE_PIN E19 [get_ports r]
set_property PACKAGE_PIN U19 [get_ports q]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports d]
set_property IOSTANDARD LVCMOS33 [get_ports r]
set_property IOSTANDARD LVCMOS33 [get_ports q]

View File

@ -1,11 +0,0 @@
module top(input clk, input d, input r, output reg q);
always @(posedge clk)
begin
if(r)
q <= 1'b0;
else
q <= d;
end
endmodule

View File

@ -1,14 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_xilinx -nolutram -nowidelut -nosrl -nocarry -nodsp
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,8 +0,0 @@
add_interchange_group_test(
name lut
family ${family}
board_list basys3 arty35t arty100t
tcl run.tcl
sources lut.v
output_fasm
)

View File

@ -1,7 +0,0 @@
set_property PACKAGE_PIN A8 [get_ports i0]
set_property PACKAGE_PIN C11 [get_ports i1]
set_property PACKAGE_PIN H5 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i0]
set_property IOSTANDARD LVCMOS33 [get_ports i1]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,7 +0,0 @@
set_property PACKAGE_PIN A8 [get_ports i0]
set_property PACKAGE_PIN C11 [get_ports i1]
set_property PACKAGE_PIN H5 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i0]
set_property IOSTANDARD LVCMOS33 [get_ports i1]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,7 +0,0 @@
set_property PACKAGE_PIN V17 [get_ports i0]
set_property PACKAGE_PIN V16 [get_ports i1]
set_property PACKAGE_PIN U16 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i0]
set_property IOSTANDARD LVCMOS33 [get_ports i1]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,5 +0,0 @@
module top(input i0, input i1, output o);
assign o = i0 | i1;
endmodule

View File

@ -1,14 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_xilinx -nolutram -nowidelut -nosrl -nocarry -nodsp
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,21 +0,0 @@
add_interchange_test(
name lut_nexus
family ${family}
device LIFCL-17
package QFN72
tcl run.tcl
xdc empty.xdc
sources lut.v
skip_dcp
)
add_interchange_test(
name lut_nexus40
family ${family}
device LIFCL-40
package CABGA400
tcl run.tcl
xdc empty.xdc
sources lut.v
skip_dcp
)

View File

@ -1,7 +0,0 @@
module top;
wire x, y;
(*keep*)
LUT4 lut_0(.A(x), .B(x), .C(x), .D(x), .Z(y));
(*keep*)
LUT4 lut_1(.A(y), .B(y), .C(y), .D(y), .Z(x));
endmodule

View File

@ -1,14 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_nexus -noccu2 -nobram -nolutram -nowidelut
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,8 +0,0 @@
add_interchange_group_test(
name lutram
family ${family}
board_list basys3
tcl run.tcl
sources lutram.v
)

View File

@ -1,41 +0,0 @@
# basys3 100 MHz CLK
set_io clk W5
set_io tx A18
set_io rx B18
#
# in[0:15] correspond with SW0-SW15 on the basys3
set_io sw[0] V17
set_io sw[1] V16
set_io sw[2] W16
set_io sw[3] W17
set_io sw[4] W15
set_io sw[5] V15
set_io sw[6] W14
set_io sw[7] W13
set_io sw[8] V2
set_io sw[9] T3
set_io sw[10] T2
set_io sw[11] R3
set_io sw[12] W2
set_io sw[13] U1
set_io sw[14] T1
set_io sw[15] R2
# out[0:15] correspond with LD0-LD15 on the basys3
set_io led[0] U16
set_io led[1] E19
set_io led[2] U19
set_io led[3] V19
set_io led[4] W18
set_io led[5] U15
set_io led[6] U14
set_io led[7] V14
set_io led[8] V13
set_io led[9] V3
set_io led[10] W3
set_io led[11] U3
set_io led[12] P3
set_io led[13] N3
set_io led[14] P1
set_io led[15] L1

View File

@ -1,80 +0,0 @@
# basys3 100 MHz CLK
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN A18 [get_ports tx]
set_property PACKAGE_PIN B18 [get_ports rx]
#
# in[0:15] correspond with SW0-SW15 on the basys3
set_property PACKAGE_PIN V17 [get_ports sw[0]]
set_property PACKAGE_PIN V16 [get_ports sw[1]]
set_property PACKAGE_PIN W16 [get_ports sw[2]]
set_property PACKAGE_PIN W17 [get_ports sw[3]]
set_property PACKAGE_PIN W15 [get_ports sw[4]]
set_property PACKAGE_PIN V15 [get_ports sw[5]]
set_property PACKAGE_PIN W14 [get_ports sw[6]]
set_property PACKAGE_PIN W13 [get_ports sw[7]]
set_property PACKAGE_PIN V2 [get_ports sw[8]]
set_property PACKAGE_PIN T3 [get_ports sw[9]]
set_property PACKAGE_PIN T2 [get_ports sw[10]]
set_property PACKAGE_PIN R3 [get_ports sw[11]]
set_property PACKAGE_PIN W2 [get_ports sw[12]]
set_property PACKAGE_PIN U1 [get_ports sw[13]]
set_property PACKAGE_PIN T1 [get_ports sw[14]]
set_property PACKAGE_PIN R2 [get_ports sw[15]]
# out[0:15] correspond with LD0-LD15 on the basys3
set_property PACKAGE_PIN U16 [get_ports led[0]]
set_property PACKAGE_PIN E19 [get_ports led[1]]
set_property PACKAGE_PIN U19 [get_ports led[2]]
set_property PACKAGE_PIN V19 [get_ports led[3]]
set_property PACKAGE_PIN W18 [get_ports led[4]]
set_property PACKAGE_PIN U15 [get_ports led[5]]
set_property PACKAGE_PIN U14 [get_ports led[6]]
set_property PACKAGE_PIN V14 [get_ports led[7]]
set_property PACKAGE_PIN V13 [get_ports led[8]]
set_property PACKAGE_PIN V3 [get_ports led[9]]
set_property PACKAGE_PIN W3 [get_ports led[10]]
set_property PACKAGE_PIN U3 [get_ports led[11]]
set_property PACKAGE_PIN P3 [get_ports led[12]]
set_property PACKAGE_PIN N3 [get_ports led[13]]
set_property PACKAGE_PIN P1 [get_ports led[14]]
set_property PACKAGE_PIN L1 [get_ports led[15]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports tx]
set_property IOSTANDARD LVCMOS33 [get_ports rx]
#
set_property IOSTANDARD LVCMOS33 [get_ports sw[0]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[1]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[2]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[3]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[4]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[5]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[6]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[7]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[8]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[9]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[10]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[11]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[12]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[13]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[14]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[15]]
set_property IOSTANDARD LVCMOS33 [get_ports led[0]]
set_property IOSTANDARD LVCMOS33 [get_ports led[1]]
set_property IOSTANDARD LVCMOS33 [get_ports led[2]]
set_property IOSTANDARD LVCMOS33 [get_ports led[3]]
set_property IOSTANDARD LVCMOS33 [get_ports led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports led[8]]
set_property IOSTANDARD LVCMOS33 [get_ports led[9]]
set_property IOSTANDARD LVCMOS33 [get_ports led[10]]
set_property IOSTANDARD LVCMOS33 [get_ports led[11]]
set_property IOSTANDARD LVCMOS33 [get_ports led[12]]
set_property IOSTANDARD LVCMOS33 [get_ports led[13]]
set_property IOSTANDARD LVCMOS33 [get_ports led[14]]
set_property IOSTANDARD LVCMOS33 [get_ports led[15]]

View File

@ -1,24 +0,0 @@
module top (
input wire clk,
input wire rx,
output wire tx,
input wire [15:0] sw,
output wire [15:0] led
);
RAM128X1D #(
.INIT(128'hFFEEDDCCBBAA99887766554433221100)
) ram_i (
.WCLK(clk),
.A(sw[6:0]),
.DPRA(sw[13:7]),
.WE(sw[14]),
.D(sw[15]),
.SPO(led[0]),
.DPO(led[1]),
);
assign led[15:2] = 14'b0;
assign tx = rx;
endmodule

View File

@ -1,17 +0,0 @@
yosys -import
foreach src $::env(SOURCES) {
read_verilog $src
}
synth_xilinx -flatten -nolutram -nowidelut -nosrl -nocarry -nodsp
techmap -map $::env(TECHMAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,7 +0,0 @@
add_interchange_group_test(
name obuftds
family ${family}
board_list basys3
tcl run.tcl
sources obuftds.v
)

View File

@ -1,9 +0,0 @@
set_property PACKAGE_PIN V2 [get_ports sw[8] ]
set_property PACKAGE_PIN T3 [get_ports sw[9] ]
set_property PACKAGE_PIN T2 [get_ports sw[10]]
set_property PACKAGE_PIN R3 [get_ports sw[11]]
set_property PACKAGE_PIN U19 [get_ports diff_p[0]]
set_property PACKAGE_PIN V19 [get_ports diff_n[0]]
set_property PACKAGE_PIN V13 [get_ports diff_p[1]]
set_property PACKAGE_PIN V14 [get_ports diff_n[1]]

View File

@ -1,37 +0,0 @@
module top(
input wire [11:8] sw,
output wire [1:0] diff_p,
output wire [1:0] diff_n
);
wire [1:0] buf_i;
wire [1:0] buf_t;
OBUFTDS # (
.IOSTANDARD("DIFF_SSTL135"),
.SLEW("FAST")
) obuftds_0 (
.I(buf_i[0]),
.T(buf_t[0]),
.O(diff_p[0]),
.OB(diff_n[0])
);
OBUFTDS # (
.IOSTANDARD("DIFF_SSTL135"),
.SLEW("FAST")
) obuftds_1 (
.I(buf_i[1]),
.T(buf_t[1]),
.O(diff_p[1]),
.OB(diff_n[1])
);
assign buf_i[0] = sw[ 8];
assign buf_t[0] = sw[ 9];
assign buf_i[1] = sw[10];
assign buf_t[1] = sw[11];
endmodule

View File

@ -1,14 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_xilinx -nolutram -nowidelut -nosrl -nocarry -nodsp
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,8 +0,0 @@
add_interchange_group_test(
name ram
family ${family}
board_list basys3
tcl run.tcl
sources ram.v
)

View File

@ -1,41 +0,0 @@
# basys3 100 MHz CLK
set_io clk W5
set_io tx A18
set_io rx B18
#
# in[0:15] correspond with SW0-SW15 on the basys3
set_io sw[0] V17
set_io sw[1] V16
set_io sw[2] W16
set_io sw[3] W17
set_io sw[4] W15
set_io sw[5] V15
set_io sw[6] W14
set_io sw[7] W13
set_io sw[8] V2
set_io sw[9] T3
set_io sw[10] T2
set_io sw[11] R3
set_io sw[12] W2
set_io sw[13] U1
set_io sw[14] T1
set_io sw[15] R2
# out[0:15] correspond with LD0-LD15 on the basys3
set_io led[0] U16
set_io led[1] E19
set_io led[2] U19
set_io led[3] V19
set_io led[4] W18
set_io led[5] U15
set_io led[6] U14
set_io led[7] V14
set_io led[8] V13
set_io led[9] V3
set_io led[10] W3
set_io led[11] U3
set_io led[12] P3
set_io led[13] N3
set_io led[14] P1
set_io led[15] L1

View File

@ -1,80 +0,0 @@
# basys3 100 MHz CLK
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN A18 [get_ports tx]
set_property PACKAGE_PIN B18 [get_ports rx]
#
# in[0:15] correspond with SW0-SW15 on the basys3
set_property PACKAGE_PIN V17 [get_ports sw[0]]
set_property PACKAGE_PIN V16 [get_ports sw[1]]
set_property PACKAGE_PIN W16 [get_ports sw[2]]
set_property PACKAGE_PIN W17 [get_ports sw[3]]
set_property PACKAGE_PIN W15 [get_ports sw[4]]
set_property PACKAGE_PIN V15 [get_ports sw[5]]
set_property PACKAGE_PIN W14 [get_ports sw[6]]
set_property PACKAGE_PIN W13 [get_ports sw[7]]
set_property PACKAGE_PIN V2 [get_ports sw[8]]
set_property PACKAGE_PIN T3 [get_ports sw[9]]
set_property PACKAGE_PIN T2 [get_ports sw[10]]
set_property PACKAGE_PIN R3 [get_ports sw[11]]
set_property PACKAGE_PIN W2 [get_ports sw[12]]
set_property PACKAGE_PIN U1 [get_ports sw[13]]
set_property PACKAGE_PIN T1 [get_ports sw[14]]
set_property PACKAGE_PIN R2 [get_ports sw[15]]
# out[0:15] correspond with LD0-LD15 on the basys3
set_property PACKAGE_PIN U16 [get_ports led[0]]
set_property PACKAGE_PIN E19 [get_ports led[1]]
set_property PACKAGE_PIN U19 [get_ports led[2]]
set_property PACKAGE_PIN V19 [get_ports led[3]]
set_property PACKAGE_PIN W18 [get_ports led[4]]
set_property PACKAGE_PIN U15 [get_ports led[5]]
set_property PACKAGE_PIN U14 [get_ports led[6]]
set_property PACKAGE_PIN V14 [get_ports led[7]]
set_property PACKAGE_PIN V13 [get_ports led[8]]
set_property PACKAGE_PIN V3 [get_ports led[9]]
set_property PACKAGE_PIN W3 [get_ports led[10]]
set_property PACKAGE_PIN U3 [get_ports led[11]]
set_property PACKAGE_PIN P3 [get_ports led[12]]
set_property PACKAGE_PIN N3 [get_ports led[13]]
set_property PACKAGE_PIN P1 [get_ports led[14]]
set_property PACKAGE_PIN L1 [get_ports led[15]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports tx]
set_property IOSTANDARD LVCMOS33 [get_ports rx]
#
set_property IOSTANDARD LVCMOS33 [get_ports sw[0]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[1]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[2]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[3]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[4]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[5]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[6]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[7]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[8]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[9]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[10]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[11]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[12]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[13]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[14]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[15]]
set_property IOSTANDARD LVCMOS33 [get_ports led[0]]
set_property IOSTANDARD LVCMOS33 [get_ports led[1]]
set_property IOSTANDARD LVCMOS33 [get_ports led[2]]
set_property IOSTANDARD LVCMOS33 [get_ports led[3]]
set_property IOSTANDARD LVCMOS33 [get_ports led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports led[8]]
set_property IOSTANDARD LVCMOS33 [get_ports led[9]]
set_property IOSTANDARD LVCMOS33 [get_ports led[10]]
set_property IOSTANDARD LVCMOS33 [get_ports led[11]]
set_property IOSTANDARD LVCMOS33 [get_ports led[12]]
set_property IOSTANDARD LVCMOS33 [get_ports led[13]]
set_property IOSTANDARD LVCMOS33 [get_ports led[14]]
set_property IOSTANDARD LVCMOS33 [get_ports led[15]]

View File

@ -1,134 +0,0 @@
module ram0(
// Write port
input wrclk,
input [15:0] di,
input wren,
input [9:0] wraddr,
// Read port
input rdclk,
input rden,
input [9:0] rdaddr,
output reg [15:0] do);
(* ram_style = "block" *) reg [15:0] ram[0:1023];
initial begin
ram[0] = 16'b00000000_00000001;
ram[1] = 16'b10101010_10101010;
ram[2] = 16'b01010101_01010101;
ram[3] = 16'b11111111_11111111;
ram[4] = 16'b11110000_11110000;
ram[5] = 16'b00001111_00001111;
ram[6] = 16'b11001100_11001100;
ram[7] = 16'b00110011_00110011;
ram[8] = 16'b00000000_00000010;
ram[9] = 16'b00000000_00000100;
end
always @ (posedge wrclk) begin
if(wren == 1) begin
ram[wraddr] <= di;
end
end
always @ (posedge rdclk) begin
if(rden == 1) begin
do <= ram[rdaddr];
end
end
endmodule
module top (
input wire clk,
input wire rx,
output wire tx,
input wire [15:0] sw,
output wire [15:0] led
);
wire rden;
reg wren;
wire [9:0] rdaddr;
wire [9:0] wraddr;
wire [15:0] di;
wire [15:0] do;
ram0 ram(
.wrclk(clk),
.di(di),
.wren(wren),
.wraddr(wraddr),
.rdclk(clk),
.rden(rden),
.rdaddr(rdaddr),
.do(do)
);
reg [9:0] address_reg;
reg [15:0] data_reg;
reg [15:0] out_reg;
assign rdaddr = address_reg;
assign wraddr = address_reg;
// display_mode == 00 -> ram[address_reg]
// display_mode == 01 -> address_reg
// display_mode == 10 -> data_reg
wire [1:0] display_mode;
// input_mode == 00 -> in[9:0] -> address_reg
// input_mode == 01 -> in[7:0] -> data_reg[7:0]
// input_mode == 10 -> in[7:0] -> data_reg[15:8]
// input_mode == 11 -> data_reg -> ram[address_reg]
wire [1:0] input_mode;
// WE == 0 -> address_reg and data_reg unchanged.
// WE == 1 -> address_reg or data_reg is updated because on input_mode.
wire we;
assign display_mode[0] = sw[14];
assign display_mode[1] = sw[15];
assign input_mode[0] = sw[12];
assign input_mode[1] = sw[13];
assign we = sw[11];
assign led = out_reg;
assign di = data_reg;
assign rden = 1;
initial begin
address_reg = 10'b0;
data_reg = 16'b0;
out_reg = 16'b0;
end
always @ (posedge clk) begin
if(display_mode == 0) begin
out_reg <= do;
end else if(display_mode == 1) begin
out_reg <= address_reg;
end else if(display_mode == 2) begin
out_reg <= data_reg;
end
if(we == 1) begin
if(input_mode == 0) begin
address_reg <= sw[9:0];
wren <= 0;
end else if(input_mode == 1) begin
data_reg[7:0] <= sw[7:0];
wren <= 0;
end else if(input_mode == 2) begin
data_reg[15:8] <= sw[7:0];
wren <= 0;
end else if(input_mode == 3) begin
wren <= 1;
end
end
end
// Uart loopback
assign tx = rx;
endmodule

View File

@ -1,17 +0,0 @@
yosys -import
foreach src $::env(SOURCES) {
read_verilog $src
}
synth_xilinx -flatten -nolutram -nowidelut -nosrl -nocarry -nodsp
techmap -map $::env(TECHMAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,10 +0,0 @@
add_interchange_group_test(
name ram_nexus
family ${family}
board_list lifcl40evn
tcl run_nexus.tcl
sources ram_nexus.v
techmap ../../remap_nexus.v
skip_dcp
)

View File

@ -1,57 +0,0 @@
set_property PACKAGE_PIN L13 [get_ports clk]
set_property PACKAGE_PIN E17 [get_ports led[0]]
set_property PACKAGE_PIN F13 [get_ports led[1]]
set_property PACKAGE_PIN G13 [get_ports led[2]]
set_property PACKAGE_PIN F14 [get_ports led[3]]
set_property PACKAGE_PIN L16 [get_ports led[4]]
set_property PACKAGE_PIN L15 [get_ports led[5]]
set_property PACKAGE_PIN L20 [get_ports led[6]]
set_property PACKAGE_PIN L19 [get_ports led[7]]
set_property PACKAGE_PIN R17 [get_ports led[8]]
set_property PACKAGE_PIN R18 [get_ports led[9]]
set_property PACKAGE_PIN U20 [get_ports led[10]]
set_property PACKAGE_PIN T20 [get_ports led[11]]
set_property PACKAGE_PIN W20 [get_ports led[12]]
set_property PACKAGE_PIN V20 [get_ports led[13]]
set_property PACKAGE_PIN G14 [get_ports pb0]
set_property PACKAGE_PIN G15 [get_ports pb1]
set_property PACKAGE_PIN N14 [get_ports sw[0]]
set_property PACKAGE_PIN M14 [get_ports sw[1]]
set_property PACKAGE_PIN M16 [get_ports sw[2]]
set_property PACKAGE_PIN M15 [get_ports sw[3]]
set_property PACKAGE_PIN N15 [get_ports sw[4]]
set_property PACKAGE_PIN N16 [get_ports sw[5]]
set_property PACKAGE_PIN M17 [get_ports sw[6]]
set_property PACKAGE_PIN M18 [get_ports sw[7]]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports led[0]]
set_property IOSTANDARD LVCMOS33 [get_ports led[1]]
set_property IOSTANDARD LVCMOS33 [get_ports led[2]]
set_property IOSTANDARD LVCMOS33 [get_ports led[3]]
set_property IOSTANDARD LVCMOS33 [get_ports led[4]]
set_property IOSTANDARD LVCMOS33 [get_ports led[5]]
set_property IOSTANDARD LVCMOS33 [get_ports led[6]]
set_property IOSTANDARD LVCMOS33 [get_ports led[7]]
set_property IOSTANDARD LVCMOS33 [get_ports led[8]]
set_property IOSTANDARD LVCMOS33 [get_ports led[9]]
set_property IOSTANDARD LVCMOS33 [get_ports led[10]]
set_property IOSTANDARD LVCMOS33 [get_ports led[11]]
set_property IOSTANDARD LVCMOS33 [get_ports led[12]]
set_property IOSTANDARD LVCMOS33 [get_ports led[13]]
set_property IOSTANDARD LVCMOS33 [get_ports pb0]
set_property IOSTANDARD LVCMOS33 [get_ports pb1]
set_property IOSTANDARD LVCMOS33 [get_ports sw[0]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[1]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[2]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[3]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[4]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[5]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[6]]
set_property IOSTANDARD LVCMOS33 [get_ports sw[7]]

View File

@ -1,123 +0,0 @@
module ram0(
// Write port
input wrclk,
input [7:0] di,
input wren,
input [5:0] wraddr,
// Read port
input rdclk,
input rden,
input [5:0] rdaddr,
output reg [7:0] do);
(* syn_ramstyle = "block_ram" *) reg [7:0] ram[0:63];
initial begin
ram[0] = 8'b00000001;
ram[1] = 8'b10101010;
ram[2] = 8'b01010101;
ram[3] = 8'b11111111;
ram[4] = 8'b11110000;
ram[5] = 8'b00001111;
ram[6] = 8'b11001100;
ram[7] = 8'b00110011;
ram[8] = 8'b00000010;
ram[9] = 8'b00000100;
end
always @ (posedge wrclk) begin
if(wren == 1) begin
ram[wraddr] <= di;
end
end
always @ (posedge rdclk) begin
if(rden == 1) begin
do <= ram[rdaddr];
end
end
endmodule
module top (
input wire clk,
input wire pb0,
input wire pb1,
input wire [7:0] sw,
output wire [13:0] led
);
wire bufclk;
DCC gbuf_i(.CLKI(clk), .CLKO(bufclk));
wire rden;
reg wren;
wire [5:0] rdaddr;
wire [5:0] wraddr;
wire [7:0] di;
wire [7:0] do;
ram0 ram(
.wrclk(bufclk),
.di(di),
.wren(wren),
.wraddr(wraddr),
.rdclk(bufclk),
.rden(rden),
.rdaddr(rdaddr),
.do(do)
);
reg [5:0] address_reg;
reg [7:0] data_reg;
reg [7:0] out_reg;
assign rdaddr = address_reg;
assign wraddr = address_reg;
// input_mode == 00 -> in[3:0] -> address_reg
// input_mode == 01 -> in[3:0] -> data_reg[3:0]
// input_mode == 10 -> in[3:0] -> data_reg[7:4]
// input_mode == 11 -> data_reg -> ram[address_reg]
wire [1:0] input_mode;
// WE == 0 -> address_reg and data_reg unchanged.
// WE == 1 -> address_reg or data_reg is updated because on input_mode.
wire we;
assign input_mode[0] = ~sw[6];
assign input_mode[1] = ~sw[7];
assign we = ~pb0;
assign led = ~{address_reg, out_reg};
assign di = data_reg;
assign rden = 1;
initial begin
wren = 1'b0;
address_reg = 10'b0;
data_reg = 16'b0;
out_reg = 16'b0;
end
always @ (posedge bufclk) begin
out_reg <= do;
if(we == 1) begin
if(input_mode == 0) begin
address_reg <= ~sw[5:0];
wren <= 0;
end else if(input_mode == 1) begin
data_reg[3:0] <= ~sw[3:0];
wren <= 0;
end else if(input_mode == 2) begin
data_reg[7:4] <= ~sw[3:0];
wren <= 0;
end else if(input_mode == 3) begin
wren <= 1;
end
end
end
endmodule

View File

@ -1,15 +0,0 @@
yosys -import
read_verilog $::env(SOURCES)
synth_nexus -nolutram -nowidelut -noccu2 -nodsp
techmap -max_iter 1 -map $::env(TECHMAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
write_json $::env(OUT_JSON)

View File

@ -1,17 +0,0 @@
add_interchange_group_test(
name wire
family ${family}
board_list basys3 arty35t zybo arty100t nexys_video
tcl run.tcl
sources wire.v
output_fasm
)
add_interchange_group_test(
name wire
family ${family}
board_list lifcl40evn
tcl run_nexus.tcl
sources wire.v
skip_dcp
)

View File

@ -1,5 +0,0 @@
set_property PACKAGE_PIN A8 [get_ports i]
set_property PACKAGE_PIN H5 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,5 +0,0 @@
set_property PACKAGE_PIN A8 [get_ports i]
set_property PACKAGE_PIN H5 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,5 +0,0 @@
set_property PACKAGE_PIN V17 [get_ports i]
set_property PACKAGE_PIN U16 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i]
set_property IOSTANDARD LVCMOS33 [get_ports o]

View File

@ -1,5 +0,0 @@
set_property PACKAGE_PIN G19 [get_ports i]
set_property PACKAGE_PIN E17 [get_ports o]
set_property IOSTANDARD LVCMOS33 [get_ports i]
set_property IOSTANDARD LVCMOS33 [get_ports o]

Some files were not shown because too many files have changed in this diff Show More