Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Release

on:
push:
tags:
- "*.*.*"

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Verify tag matches Rust package version
env:
TAG_NAME: ${{ github.ref_name }}
run: |
package_version="$(python3 - <<'PY'
import tomllib
with open("tool/Cargo.toml", "rb") as manifest:
print(tomllib.load(manifest)["package"]["version"])
PY
)"
test "$TAG_NAME" = "$package_version" || {
echo "Tag $TAG_NAME does not match Rust package version $package_version" >&2
exit 1
}

- uses: DeterminateSystems/nix-installer-action@v22

- name: Allow Gowin FHS sandbox
run: |
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true
sudo sysctl -w kernel.unprivileged_userns_clone=1 || true

- name: Build FPGA bitstream
run: nix develop --command make build

- name: Package release bitstream
env:
TAG_NAME: ${{ github.ref_name }}
run: |
cp impl/pnr/spi_flash.fs spi_flash.fs
cp impl/pnr/spi_flash.fs "norbert-${TAG_NAME}-tangprimer25k.fs"
sha256sum spi_flash.fs "norbert-${TAG_NAME}-tangprimer25k.fs" > SHA256SUMS
cat > release-notes.md <<EOF
## Programming the Tang Primer 25K

Download \`spi_flash.fs\` (or the versioned copy) and program it with [openFPGALoader](https://github.com/trabucayre/openFPGALoader):

\`\`\`sh
# Volatile: runs immediately, lost on power-off
openFPGALoader -b tangprimer25k spi_flash.fs

# Persistent: boots automatically after power-on
openFPGALoader -b tangprimer25k -f spi_flash.fs
\`\`\`

You can also open the [NORbert Web UI](https://arthurheymans.github.io/NORbert/), choose **Bitstream**, select the downloaded \`.fs\` file, and program SRAM or flash through WebUSB. Chromium and an HTTPS/localhost page are required.

The release tag and Rust package version are both \`${TAG_NAME}\`.
EOF

- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.ref_name }}
run: |
gh release create "$TAG_NAME" \
--title "NORbert $TAG_NAME" \
--notes-file release-notes.md \
spi_flash.fs \
"norbert-${TAG_NAME}-tangprimer25k.fs" \
SHA256SUMS
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ NORbert exposes the SPI flash interface on the **PMOD J5** connector of the Tang

*Note: D3 and `#HOLD#` share the physical IO3 pin. Asserting `#HOLD` drives it low to silence a real flash on a shared bus. Consult `tangprimer25k.cst` for exact pin assignments.*

## Releases

Tagged releases publish a Gowin `.fs` bitstream for the Tang Primer 25K. Download
`spi_flash.fs` from the [latest release](https://github.com/ArthurHeymans/NORbert/releases/latest)
and load it with openFPGALoader:

```sh
# Volatile: runs immediately, lost on power-off
openFPGALoader -b tangprimer25k spi_flash.fs

# Persistent: boots automatically after power-on
openFPGALoader -b tangprimer25k -f spi_flash.fs
```

Release tags exactly match the Rust package version (for example, tag `0.1.0`
uses `version = "0.1.0"` in `tool/Cargo.toml`). The release workflow rejects a
mismatch.

## Building

### Prerequisites
Expand Down Expand Up @@ -131,8 +149,28 @@ Open <http://localhost:8081> and choose either **Connect FT245 (WebUSB)** or
**Connect UART (Web Serial)**. The UI uses the compiled-in rflasher database to
search for and configure the emulated chip, and provides emulation control,
verified SDRAM uploads and downloads, target-flash `#HOLD`, decoded live SPI
activity monitoring, and full TOCTOU trap configuration. Browser device APIs
are unavailable when opening `web/index.html` directly as a `file://` URL.
activity monitoring, and full TOCTOU trap configuration.

The **Bitstream** tab can program a release or locally built Gowin `.fs` file
straight into volatile SRAM or persistent configuration flash. This is a Rust/
WebAssembly port of the FT2232H MPSSE/JTAG and Gowin GW5A paths used by
openFPGALoader, built on the existing `ftdi-nusb`, `nusb`, and WebUSB support.
Disconnect an active FT245 connection and close native JTAG tools before
programming because they also claim FT2232H interface A. On Linux, unbind the
`ftdi_sio` driver from interface A if Chromium reports that it cannot claim the
interface. On Windows, interface A must use the WinUSB driver (for example,
configured with Zadig); leave interface B on its normal driver.

Flash programming requires a readable JEDEC SFDP Basic Flash Parameter Table
and checks the write and sector-erase range against the reported capacity
(and the programmer's 24-bit address limit) before changing protection or
issuing an erase. Chips without supported SFDP data are rejected rather than
assuming a capacity. Incomplete `.fs` configuration data is rejected before
opening the JTAG adapter.

Browser device APIs are unavailable when opening `web/index.html` directly as
a `file://` URL. WebUSB requires Chromium and a secure context (HTTPS or
localhost).

## Usage

Expand Down
2 changes: 1 addition & 1 deletion tool/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "spi-flash-tool"
version = "0.2.0"
version = "0.1.0"
edition = "2024"
description = "Tool for loading data into the Tang Primer 25K SPI Flash Emulator (UART + FT245)"

Expand Down
Loading