Remove fpga_interchange
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
1967db170d
commit
fcdaf3f86c
64
.github/ci/build_interchange.sh
vendored
64
.github/ci/build_interchange.sh
vendored
@ -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
|
|
||||||
}
|
|
132
.github/workflows/interchange_ci.yml.disable
vendored
132
.github/workflows/interchange_ci.yml.disable
vendored
@ -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
3
.gitmodules
vendored
@ -1,9 +1,6 @@
|
|||||||
[submodule "tests"]
|
[submodule "tests"]
|
||||||
path = tests
|
path = tests
|
||||||
url = https://github.com/YosysHQ/nextpnr-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"]
|
[submodule "himbaechel/uarch/xilinx/meta"]
|
||||||
path = himbaechel/uarch/xilinx/meta
|
path = himbaechel/uarch/xilinx/meta
|
||||||
url = https://github.com/gatecat/nextpnr-xilinx-meta
|
url = https://github.com/gatecat/nextpnr-xilinx-meta
|
||||||
|
1
3rdparty/fpga-interchange-schema
vendored
1
3rdparty/fpga-interchange-schema
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 6b2973788692be86c4a8b2cff1353e603e5857a3
|
|
@ -108,9 +108,9 @@ endif()
|
|||||||
set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables")
|
set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables")
|
||||||
|
|
||||||
# List of families to build
|
# 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(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(ARCH "" CACHE STRING "Architecture family for nextpnr build")
|
||||||
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})
|
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})
|
||||||
|
@ -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
@ -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
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
||||||
)
|
|
@ -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()
|
|
||||||
|
|
@ -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()
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -1,7 +0,0 @@
|
|||||||
add_interchange_group_test(
|
|
||||||
name const_wire
|
|
||||||
family ${family}
|
|
||||||
board_list basys3 arty35t arty100t
|
|
||||||
tcl run.tcl
|
|
||||||
sources wire.v
|
|
||||||
)
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
||||||
)
|
|
@ -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]]
|
|
@ -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]]
|
|
@ -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]]
|
|
@ -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
|
|
@ -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]]
|
|
@ -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]]
|
|
@ -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)
|
|
@ -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)
|
|
@ -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]]
|
|
@ -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
|
|
||||||
)
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
||||||
)
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
|
@ -1,5 +0,0 @@
|
|||||||
module top(input i0, input i1, output o);
|
|
||||||
|
|
||||||
assign o = i0 | i1;
|
|
||||||
|
|
||||||
endmodule
|
|
@ -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)
|
|
@ -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
|
|
||||||
)
|
|
@ -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
|
|
@ -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)
|
|
@ -1,8 +0,0 @@
|
|||||||
add_interchange_group_test(
|
|
||||||
name lutram
|
|
||||||
family ${family}
|
|
||||||
board_list basys3
|
|
||||||
tcl run.tcl
|
|
||||||
sources lutram.v
|
|
||||||
)
|
|
||||||
|
|
@ -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
|
|
@ -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]]
|
|
@ -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
|
|
@ -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)
|
|
@ -1,7 +0,0 @@
|
|||||||
add_interchange_group_test(
|
|
||||||
name obuftds
|
|
||||||
family ${family}
|
|
||||||
board_list basys3
|
|
||||||
tcl run.tcl
|
|
||||||
sources obuftds.v
|
|
||||||
)
|
|
@ -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]]
|
|
@ -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
|
|
||||||
|
|
@ -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)
|
|
@ -1,8 +0,0 @@
|
|||||||
add_interchange_group_test(
|
|
||||||
name ram
|
|
||||||
family ${family}
|
|
||||||
board_list basys3
|
|
||||||
tcl run.tcl
|
|
||||||
sources ram.v
|
|
||||||
)
|
|
||||||
|
|
@ -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
|
|
@ -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]]
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
||||||
)
|
|
||||||
|
|
@ -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]]
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
||||||
)
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
|
@ -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
Loading…
Reference in New Issue
Block a user