Skip to content
This repository was archived by the owner on Mar 11, 2026. It is now read-only.

Commit 2ecd51e

Browse files
committed
Add Nexus support.
1 parent ed1cceb commit 2ecd51e

9 files changed

Lines changed: 190 additions & 6 deletions

File tree

.github/workflows/package.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ jobs:
1212
submodules: recursive
1313
- name: Set up Python
1414
uses: actions/setup-python@v2
15+
- name: Set up Rust
16+
uses: actions-rs/toolchain@v1
17+
with:
18+
profile: minimal
19+
toolchain: nightly
1520
- name: Install dependencies
1621
run: |
1722
python -m pip install --upgrade pip setuptools setuptools_scm wheel

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "prjtrellis-src"]
88
path = prjtrellis-src
99
url = https://github.com/YosysHQ/prjtrellis
10+
[submodule "prjoxide-src"]
11+
path = prjoxide-src
12+
url = https://github.com/gatecat/prjoxide.git

build.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ cmake -B libtrellis-build -S prjtrellis-src/libtrellis \
7575
-DCMAKE_INSTALL_PREFIX=$(pwd)/libtrellis-prefix
7676
make -C libtrellis-build install
7777

78+
cargo build --target-dir prjoxide-build \
79+
--manifest-path prjoxide-src/libprjoxide/prjoxide/Cargo.toml \
80+
--target wasm32-wasi \
81+
--release
82+
83+
cargo install --target-dir prjoxide-build \
84+
--path prjoxide-src/libprjoxide/prjoxide \
85+
--root prjoxide-prefix
86+
7887
cmake -B nextpnr-bba-build -S nextpnr-src/bba
7988
cmake --build nextpnr-bba-build
8089

@@ -90,7 +99,8 @@ cmake -B nextpnr-build -S nextpnr-src \
9099
-DBUILD_PYTHON=OFF \
91100
-DEXTERNAL_CHIPDB=ON \
92101
-DEXTERNAL_CHIPDB_ROOT=/share \
93-
-DARCH="ice40;ecp5" \
102+
-DARCH="ice40;ecp5;nexus" \
94103
-DICESTORM_INSTALL_PREFIX=$(pwd)/icestorm-prefix \
95-
-DTRELLIS_INSTALL_PREFIX=$(pwd)/libtrellis-prefix
104+
-DTRELLIS_INSTALL_PREFIX=$(pwd)/libtrellis-prefix \
105+
-DOXIDE_INSTALL_PREFIX=$(pwd)/prjoxide-prefix
96106
cmake --build nextpnr-build

package-pypi-ecp5.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ PYTHON=${PYTHON:-python}
44

55
mkdir -p pypi-ecp5/yowasp_nextpnr_ecp5/bin/
66
cp prjtrellis-build/ecppll.wasm \
7-
prjtrellis-build/ecpbram.wasm \
8-
prjtrellis-build/ecpmulti.wasm \
9-
prjtrellis-build/ecppack.wasm \
10-
prjtrellis-build/ecpunpack.wasm \
7+
prjtrellis-build/ecpbram.wasm \
8+
prjtrellis-build/ecpmulti.wasm \
9+
prjtrellis-build/ecppack.wasm \
10+
prjtrellis-build/ecpunpack.wasm \
1111
nextpnr-build/nextpnr-ecp5.wasm \
1212
pypi-ecp5/yowasp_nextpnr_ecp5/
1313
mkdir -p pypi-ecp5/yowasp_nextpnr_ecp5/share/ecp5

package-pypi-nexus.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh -ex
2+
3+
PYTHON=${PYTHON:-python}
4+
5+
mkdir -p pypi-nexus/yowasp_nextpnr_nexus/bin/
6+
cp prjoxide-build/wasm32-wasi/release/prjoxide.wasm \
7+
nextpnr-build/nextpnr-nexus.wasm \
8+
pypi-nexus/yowasp_nextpnr_nexus/
9+
mkdir -p pypi-nexus/yowasp_nextpnr_nexus/share/nexus
10+
cp nextpnr-build/nexus/chipdb/*.bin \
11+
pypi-nexus/yowasp_nextpnr_nexus/share/nexus
12+
13+
cd pypi-nexus
14+
rm -rf build && ${PYTHON} setup.py bdist_wheel
15+
sha256sum dist/*.whl

prjoxide-src

Submodule prjoxide-src added at 67d3854

pypi-nexus/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__pycache__/
2+
/*.egg-info
3+
/.eggs
4+
/build
5+
/dist
6+
7+
/yowasp_*/share

pypi-nexus/setup.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import os
2+
from setuptools import setup, find_packages
3+
from setuptools_scm.git import parse as parse_git
4+
5+
6+
def version():
7+
upstream_git = parse_git("../nextpnr-src")
8+
if upstream_git.exact:
9+
nextpnr_version = upstream_git.format_with("{tag}")
10+
else:
11+
nextpnr_version = upstream_git.format_with("{tag}.post{distance}")
12+
13+
package_git = parse_git("..")
14+
if not package_git.dirty:
15+
package_version = package_git.format_with(".dev{distance}")
16+
else:
17+
package_version = package_git.format_with(".dev{distance}+dirty")
18+
19+
return nextpnr_version + package_version
20+
21+
22+
def long_description():
23+
with open("../README.md") as f:
24+
return f.read()
25+
26+
27+
setup_info = dict(
28+
name="yowasp-nextpnr-nexus",
29+
version=version(),
30+
install_requires=[
31+
"importlib_resources; python_version<'3.9'",
32+
"appdirs~=1.4",
33+
"wasmtime>=0.20,<0.28"
34+
],
35+
packages=["yowasp_nextpnr_nexus"],
36+
package_data={
37+
"yowasp_nextpnr_nexus": [
38+
"*.wasm",
39+
"share/nexus/chipdb-*.bin",
40+
],
41+
},
42+
entry_points={
43+
"console_scripts": [
44+
"yowasp-prjoxide = yowasp_nextpnr_nexus:_run_prjoxide_argv",
45+
"yowasp-nextpnr-nexus = yowasp_nextpnr_nexus:_run_nextpnr_nexus_argv",
46+
],
47+
},
48+
)
49+
50+
51+
setup(
52+
author="whitequark",
53+
author_email="whitequark@whitequark.org",
54+
description="nextpnr-nexus FPGA place and route tool",
55+
long_description=long_description(),
56+
long_description_content_type="text/markdown",
57+
license="ISC", # same as Yosys
58+
python_requires="~=3.5",
59+
setup_requires=["setuptools_scm", "wheel"],
60+
**setup_info,
61+
project_urls={
62+
"Homepage": "https://yowasp.github.io/",
63+
"Source Code": "https://github.com/YoWASP/nextpnr",
64+
"Bug Tracker": "https://github.com/YoWASP/nextpnr/issues",
65+
},
66+
classifiers=[
67+
"License :: OSI Approved :: ISC License (ISCL)",
68+
],
69+
)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import os
2+
import sys
3+
import wasmtime
4+
import pathlib
5+
import hashlib
6+
import appdirs
7+
try:
8+
from importlib import resources as importlib_resources
9+
try:
10+
importlib_resources.files # py3.9+ stdlib
11+
except AttributeError:
12+
import importlib_resources # py3.8- shim
13+
except ImportError:
14+
import importlib_resources # py3.6- shim
15+
16+
17+
def _run_wasm_app(wasm_filename, argv):
18+
module_binary = importlib_resources.read_binary(__package__, wasm_filename)
19+
module_digest = hashlib.sha1(module_binary).digest()
20+
21+
wasi_cfg = wasmtime.WasiConfig()
22+
wasi_cfg.argv = argv
23+
wasi_cfg.preopen_dir(str(importlib_resources.files(__package__) / "share"), "/share")
24+
wasi_cfg.preopen_dir("/", "/")
25+
wasi_cfg.preopen_dir(".", ".")
26+
wasi_cfg.inherit_stdin()
27+
wasi_cfg.inherit_stdout()
28+
wasi_cfg.inherit_stderr()
29+
30+
engine = wasmtime.Engine()
31+
cache_path = pathlib.Path(os.getenv("YOWASP_CACHE_DIR", appdirs.user_cache_dir("yowasp")))
32+
cache_path.mkdir(parents=True, exist_ok=True)
33+
cache_filename = (cache_path / "{}-cache".format(wasm_filename))
34+
digest_filename = (cache_path / "{}-digest".format(wasm_filename))
35+
try:
36+
with digest_filename.open("rb") as digest_file:
37+
if digest_file.read() != module_digest:
38+
raise Exception("cache miss")
39+
with cache_filename.open("rb") as cache_file:
40+
module = wasmtime.Module.deserialize(engine, cache_file.read())
41+
except:
42+
print("Preparing to run {}. This might take a while...".format(argv[0]), file=sys.stderr)
43+
module = wasmtime.Module(engine, module_binary)
44+
with cache_filename.open("wb") as cache_file:
45+
cache_file.write(module.serialize())
46+
with digest_filename.open("wb") as digest_file:
47+
digest_file.write(module_digest)
48+
49+
store = wasmtime.Store(engine)
50+
linker = wasmtime.Linker(store)
51+
wasi = linker.define_wasi(wasmtime.WasiInstance(store,
52+
"wasi_snapshot_preview1", wasi_cfg))
53+
app = linker.instantiate(module)
54+
try:
55+
app.exports["_start"]()
56+
return 0
57+
except wasmtime.ExitTrap as trap:
58+
return trap.code
59+
60+
61+
def run_prjoxide(argv):
62+
return _run_wasm_app("prjoxide.wasm", ["yowasp-prjoxide", *argv])
63+
64+
65+
def _run_prjoxide_argv():
66+
sys.exit(run_prjoxide(sys.argv[1:]))
67+
68+
69+
def run_nextpnr_nexus(argv):
70+
return _run_wasm_app("nextpnr-nexus.wasm", ["yowasp-nextpnr-nexus", *argv])
71+
72+
73+
def _run_nextpnr_nexus_argv():
74+
sys.exit(run_nextpnr_nexus(sys.argv[1:]))

0 commit comments

Comments
 (0)