Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ce9b15a
feat(dlc10): pure-Rust driver + SPI flash programming
claude May 10, 2026
d08b049
fix(dlc10): use real 22956-byte Cypress FX2 firmware (was placeholder)
May 12, 2026
80470ab
feat(dlc10): debug subcommand + verbose sram for DONE=LOW diagnosis
claude May 12, 2026
32020d2
fix(dlc10): RTI parking in Type-1 read + INIT_B poll after JPROGRAM
claude May 12, 2026
9452ad1
fix(dlc10): mirror openFPGALoader dumpRegister — per-word Update-DR
claude May 12, 2026
f75cc3c
refactor(tri): centralize FPGA + hooks in Rust, remove Python/shell l…
claude May 12, 2026
25a44de
fix(fpga): SPI flash JEDEC=FF FF FF on QMTech XC7A100T — bit-reverse …
claude May 12, 2026
1a54b7b
feat(fpga): openXC7 build path for QMTech-specific proxy bitstream
claude May 12, 2026
422bd94
fix(tri): nextpnr-himbaechel xilinx uses -o xdc=/-o fasm= not --xdc/-…
gHashTag May 12, 2026
7764be1
feat(fpga): openXC7 chipdb setup helper for nextpnr-himbaechel
May 12, 2026
d6bc04c
feat(fpga): docker vivado build path for QMTech proxy
claude May 12, 2026
471bc01
fix(fpga): correct himbaechel device name to xc7a100tfgg676-1
gHashTag May 12, 2026
56490e4
docs(fpga): openXC7 native FGG676 status — chipdb OK, config-pin rout…
claude May 12, 2026
e22a603
fix(dlc10): SPI capture uses Migen JTAG2SPI framing (marker + BE leng…
claude May 12, 2026
a90d29d
feat(fpga): docker vivado 2025.2 image prep for FGG676 proxy
claude May 12, 2026
ad0cbc0
docs(fpga): docker-vivado FGG676 status — image build in progress
claude May 12, 2026
d83ef1e
feat(fpga): deploy CI-built spiOverJtag_xc7a100tfgg676.bit proxy bits…
claude May 12, 2026
3557848
feat(dlc10): fix bring-up, read_cfg_reg, and STARTUPCLK — DONE=HIGH a…
claude May 12, 2026
cd0a79e
feat(dlc10): port spi_put_v2 — JEDEC 20 BA 17 reads end-to-end
claude May 13, 2026
c3345fb
feat(dlc10): SPI flash write/verify works end-to-end — 3-month blocke…
claude May 13, 2026
95c45ab
feat(dlc10): default per-byte bitswap of bitstream payload for Master…
claude May 13, 2026
4b3ca9b
fix(ci): L1 traceability accepts Refs/Updates/Resolves as valid issue…
gHashTag May 14, 2026
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
40 changes: 22 additions & 18 deletions .claude/hooks/check-l1-traceability.sh
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
#!/bin/bash
# L1 Traceability Check - Ensures commits reference issues
# L1: "No code merged without `Closes #N`"

#!/usr/bin/env bash
# L1 TRACEABILITY gate — thin forwarder to the Rust implementation.
#
# Real logic lives in `cli/tri` (`tri hooks l1-check`). This file exists
# only so that pre-existing harness wiring that exec's the .sh path keeps
# working. Do not add logic here — edit `cli/tri/src/hooks.rs` instead.
set -euo pipefail

# Get last commit message
COMMIT_MSG=$(git log -1 --pretty=%B HEAD)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

# Check for issue reference pattern
if ! echo "$COMMIT_MSG" | grep -qE "Closes #|Fixes #|Resolves #|Reference #"; then
for p in \
"$REPO_ROOT/target/release/tri" \
"$REPO_ROOT/target/debug/tri" \
; do
if [[ -x "$p" ]]; then
exec "$p" hooks l1-check
fi
done

# Fallback if the Rust binary is not yet built (e.g. fresh clone).
COMMIT_MSG=$(git log -1 --pretty=%B HEAD)
if ! echo "$COMMIT_MSG" | grep -qE "(Closes|Fixes|Resolves|Reference) #[0-9]+"; then
echo "L1 VIOLATION: Commit missing issue reference"
echo "Commit message: $COMMIT_MSG"
echo "Required pattern: Closes #N, Fixes #N, etc."
echo "Required pattern: Closes #N | Fixes #N | Resolves #N | Reference #N"
exit 1
fi

# Check for issue number after pattern
ISSUE_NUM=$(echo "$COMMIT_MSG" | grep -oE "#[0-9]+" | head -1)
if [ -z "$ISSUE_NUM" ]; then
echo "L1 VIOLATION: No issue number found"
exit 1
fi

echo "L1 PASSED: Issue #$ISSUE_NUM referenced"
exit 0
echo "L1 PASSED: Issue $ISSUE_NUM referenced"
9 changes: 7 additions & 2 deletions .github/workflows/l1-traceability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ jobs:
FULL_MSG=$(git log -1 --format="%B" "$hash")
SHORT_MSG=$(git log -1 --format="%h %s" "$hash")

# Check for "Closes #N" or "Close #N" or "Fixes #N" or "Fix #N" in full message
if ! echo "$FULL_MSG" | grep -qiE "(Closes?|Fixes?)\s*#[0-9]+"; then
# Check for issue reference in full message.
# Accept any standard GitHub linking keyword:
# Close(s)/Fix(es)/Resolve(s) — closes the issue on merge
# Refs/Ref — references an issue (work in progress on same epic)
# Updates/Update — progress update on an existing issue
# Also accept "#N" anywhere on a line that contains one of these verbs.
if ! echo "$FULL_MSG" | grep -qiE "(Closes?|Fixes?|Resolves?|Refs?|Updates?)\s*#[0-9]+"; then
FAILED=1
FAILED_COMMITS="$FAILED_COMMITS ❌ $SHORT_MSG"$'\n'
else
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ bootstrap/.trinity/
!.trinity/current_task/notebook_meta.json
.trinity/current_task/session_log.jsonl
.trinity/gate_bypasses.log

# Vivado Docker build secrets (token + installer)
docker/wi_authentication_key
docker/FPGAs_AdaptiveSoCs_Unified_SDI_*.bin
docker/Xilinx_Unified_*.bin
64 changes: 36 additions & 28 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["bootstrap", "bindings/javascript", "cli/tri", "cli/trios-bridge", "cli/flash-spi"]
members = ["bootstrap", "bindings/javascript", "cli/tri", "cli/trios-bridge", "cli/flash-spi", "cli/dlc10"]
exclude = ["bindings/python", "tools/converter", "gen"]

[workspace.package]
Expand Down
94 changes: 94 additions & 0 deletions MIGRATION_AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# MIGRATION_AUDIT.md

Audit of `.py` and `.sh` files in the t27 repository for migration to Rust /
centralization in the `tri` CLI, per issue #592.

**Scope:** every `.py`/`.sh` file outside `target/`, `node_modules/`,
`contrib/solana/node_modules/`, `contrib/portable-claude-setup/`,
`research/trinity-pellis-paper/`, and `.git/`.

**Classes:**

- **A — Infra critical path:** pre-commit / push hooks, CI gates, scripts
invoked from `.githooks/` or `.github/workflows/`. Must be rewritten in
Rust and exposed via `tri hooks <name>`.
- **B — FPGA tooling duplicates:** Python implementations of cable/flash
programming whose behaviour now lives in `cli/dlc10` (Rust, silicon-
verified). Delete.
- **C — Research / examples / contrib backend:** standalone scripts not on
any commit / push / CI critical path. Keep as-is for this migration.
- **D — Bootstrap stubs:** `bootstrap/t27c.py`,
`bootstrap/src/memory/ace_step_wrapper.py`. The real `t27c` is the
Rust binary built from `bootstrap/`. Stubs are unused at the critical
path; keep for this migration, address separately.

## Decisions for this PR (#593, Closes #592)

| Path | Class | Decision | Rationale |
|------|-------|----------|-----------|
| `tools/dlc10_jtag.py` | B | **Delete** | Behaviour reimplemented in `cli/dlc10` lib (silicon-verified: IDCODE `0x13631093`, SRAM blink, SPI flash). |
| `tools/tri_fpga/__init__.py` | B | **Delete** | Same as above; package empty. |
| `tools/tri_fpga/cli.py` | B | **Delete** | Same as above; replaced by `tri fpga ...`. |
| `.claude/hooks/check-l1-traceability.sh` | A | **Rewrite + keep stub** | Wrapped via `tri hooks l1-check`; the `.sh` becomes a one-line forwarder so any existing harness wiring keeps working. |
| `.claude/hooks/session-gate.sh` | A | Keep | Calls into `cargo run`; not on commit/push path, harness-only. Out of scope for this PR. |
| `.claude/hooks/stop-hook-guard.sh` | A | Keep | Session-stop accounting only; not on commit/push gate. |
| `.claude/hooks/inject-notebook-context.sh` | A | Keep | NotebookLM telemetry, not a gate. |
| `.githooks/pre-commit` | A | Keep | Already delegates to `scripts/tri check-now` (Rust `t27c`). Out of scope. |
| `.githooks/pre-push` | A | Keep | NotebookLM gate, no Rust replacement available yet. |
| `.githooks/post-merge` | A | Keep | NotebookLM sync; non-blocking. |
| `scripts/tri` | A | Keep | Already a 17-line forwarder to the Rust `t27c` binary. |
| `scripts/ci/now-sync-gate-diff.sh` | A | Keep | CI-only diff check against GitHub event env; thin glue. |
| `scripts/ci/phi-loop-last-failure.sh` | A | Keep | Diagnostic only, off the merge gate. |
| `scripts/aggregate-experience.sh` | A | Keep | Triggered by `brain-seal-refresh.yml` workflow; not commit-gate. |
| `.claude/skills/tri/scripts/*.sh` | A | Keep | Skill-internal helpers, not invoked from any gate. |
| `scripts/fpga/build.sh`, `scripts/fpga/flash.sh` | C | Keep | Vivado wrappers — orthogonal to the DLC10 USB driver. |
| `examples/fpga/qmtech_minimal/build.sh` | C | Keep | Example; not on critical path. |
| `bootstrap/t27c.py`, `bootstrap/src/memory/ace_step_wrapper.py` | D | Keep | Out of scope; handled separately. |
| `contrib/backend/**/*.py` | C | Keep | NotebookLM / music-generator backends; not on commit gate. |
| `clara-bridge/**/*.py` | C | Keep | Research bridge. |
| `benchmarks/**/*.py`, `research/**/*.py`, `scripts/ultra_engine_v*.py`, `scripts/pysr_*.py`, `scripts/pslq_*.py`, `scripts/trinity-pellis-pipeline/**/*.py`, `external/kaggle/**/*.py`, `docs/clara/examples/*.py` | C | Keep | Research / examples; orthogonal. |
| `bindings/python/**/*.py` | C | Keep | Python bindings to golden-float crate. |
| `conformance/kepler_newton_tests.py` | C | Keep | Conformance helper not on gate. |
| `test_notebooklm.py`, `test_notebooklm_venv.sh` | C | Keep | Manual smoke tests at repo root. |
| `scripts/tri-*.py`, `scripts/audit_discovery.py`, `scripts/check_first_party_doc_language.py`, `scripts/verify_*.py`, `scripts/lee_*.py`, `scripts/compare_*.py`, `scripts/fix_*.py`, `scripts/overnight_research_agent.py`, `scripts/print_pellis_seal_decimal.py`, `scripts/unified_search_all.py`, `scripts/wrapup/*.py` | C | Keep | Standalone helpers; none referenced from `.githooks/` or commit-path workflows. |
| `scripts/install-*.sh`, `scripts/setup-git-hooks.sh`, `scripts/auto-*.sh`, `scripts/check-conflicts.sh`, `scripts/bulk-create-notebooks.sh`, `scripts/generate_episodes.sh`, `scripts/git_commands_tasks_1_4.sh`, `scripts/mcp-wrapper.sh`, `scripts/phi-loop-stack.sh`, `scripts/run_v51_multiple.sh`, `scripts/test-agent-bridge.sh`, `scripts/verify-notebooklm.sh`, `scripts/verify-ssot-integration.sh` | C | Keep | One-shot setup / human-invoked utilities; not gated. |

## New `tri` subcommands added by this PR

| Command | Behaviour |
|---------|-----------|
| `tri fpga idcode` | Read DLC10 JTAG IDCODE (was `tools/dlc10_jtag.py idcode` / `dlc10 idcode`). |
| `tri fpga sram <bit> [--verbose]` | Program FPGA SRAM (volatile). |
| `tri fpga program <bit> [--no-verify]` | Program SPI flash (persistent). |
| `tri fpga flash-id` | Read SPI flash JEDEC ID. |
| `tri fpga status` | Raw CFG_OUT status. |
| `tri fpga debug [--no-jstart]` | Decode 7-series CFG registers. |
| `tri hooks l1-check` | Pure-Rust port of `.claude/hooks/check-l1-traceability.sh` (commit-message issue-reference gate). |
| `tri hooks now-gate` | Verifies `docs/NOW.md` "Last updated" is today's date (UTC). |
| `tri hooks pre-commit` | Runs the migrated gates in sequence (currently `now-gate` + `l1-check`). |

## Crate restructuring

- `cli/dlc10` is now a **lib crate** (`lib.rs` already exposed all primitives;
the `[lib]` target is now consumed by both `cli/flash-spi` and `cli/tri`).
The `dlc10` binary stays as a thin diagnostic wrapper.
- `cli/flash-spi` continues to ship a `flash-spi` binary that re-exports the
same logic; for new work users are pointed at `tri fpga program`.
- `cli/tri` gains a `fpga` subcommand backed by `dlc10::Dlc10` directly
(no shell-out, no Python).

## What was NOT changed and why

- `scripts/tri` (the Bash forwarder to `t27c`): already a 17-line thin
wrapper around a Rust binary. Rewriting it to Rust would be circular
(Rust binary launching a Rust binary). Constitution allows it under
L7-UNITY since it never implements logic.
- `.githooks/pre-commit` and `pre-push`: still call `scripts/tri check-now`
and a NotebookLM ID guard. These remain Bash because they're glue and
the Rust replacement for the NotebookLM client is out of scope.
- `bootstrap/t27c.py`: scaffolding stub; deletion would force a
bootstrap-tooling change that is orthogonal to this issue.

---

**Issue:** #592 — Closes #592 in the corresponding commit.
20 changes: 20 additions & 0 deletions cli/dlc10/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "dlc10"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Pure-Rust driver for Xilinx Platform Cable USB II (DLC10/DLC9), supports JTAG + SPI flash via 7-series proxy"

[lib]
path = "src/lib.rs"

[[bin]]
name = "dlc10"
path = "src/bin/dlc10.rs"

[dependencies]
rusb = "0.9"
anyhow = "1"
clap = { version = "4", features = ["derive", "env"] }
thiserror = "1"
hex = "0.4"
66 changes: 66 additions & 0 deletions cli/dlc10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# dlc10 — pure-Rust driver for the Xilinx DLC10/DLC9

Replaces the legacy Python `tools/dlc10_jtag.py` with a Rust crate providing:

- USB enumeration + Cypress FX2 firmware load (Intel-HEX `xusb_xp2.hex`)
- Low-level JTAG primitives (`shift_ir`, `shift_dr`, `cycle_tck`, …)
- `read_idcode`, `read_status`, `program_sram` (correct UG470 §6 sequence)
- `program_flash`: loads a JTAG-to-SPI bridge bitstream into SRAM, then
drives the on-board SPI flash (M25P/N25Q-class) via `USER1`

## Critical fixes vs the prior Python attempt

1. **SRAM `JPROGRAM` was missing.** The old flow `JSHUTDOWN → CFG_IN →
JSTART` left `DONE = LOW`. The correct UG470 §6 sequence is now
implemented:
```
JPROGRAM cycle_tck(64)
JSHUTDOWN cycle_tck(12)
CFG_IN <bitstream> cycle_tck(1)
JSTART cycle_tck(24)
BYPASS → CFG_OUT → STATUS
```
2. **`chunk_bits = 16379`** for `_do_shift` — explicitly **not** a multiple
of 4. The DLC10 firmware silently corrupts payloads with multiple-of-4
bit counts unless padded.
3. **USB endpoints**: `EP_OUT = 0x02`, `EP_IN = 0x86`, vendor-request
`0xB0`, FX2 firmware-load request `0xA0`, FX2 CPUCS register `0xE600`.

## CLI

```text
dlc10 idcode # read and print IDCODE
dlc10 sram <file.bit> # SRAM program (volatile)
dlc10 flash <file.bit> [--verify] # SPI flash program (permanent)
dlc10 flash-id # JEDEC ID via JTAG-to-SPI bridge
dlc10 status # CFG_OUT STATUS register
```

## Embedded blobs

- `fpga/tools/xusb_xp2.hex` — Cypress FX2 firmware for the DLC10 cable.
**The file currently committed is a placeholder EOF record.** Copy the
real 22 956-byte HEX (from a working Vivado / xc3sprog install) onto the
build host before producing a release binary. Build will succeed with
the placeholder, but `Dlc10::open()` will fail to bring up the cable.

- `fpga/tools/bscan_spi_xc7a100t.bit` — JTAG-to-SPI bridge bitstream for
the XC7A100T, **404 986 bytes**, SHA-256
`6e8cef49958fbab96a217c209782be67f4943ff80ae9c81e51425da41fc975e0`.
Sourced from
<https://github.com/quartiq/bscan_spi_bitstreams>, **MIT-licensed**:

> Copyright © Robert Jördens et al.
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files…

See the upstream repo for the full MIT notice; we redistribute the
bitstream unmodified.

## Tests

```sh
cargo test -p dlc10 # unit tests (no hardware needed)
cargo test -p dlc10 -- --ignored # hardware integration (DLC10 + Wukong)
cargo clippy -p dlc10 -- -D warnings
```
Loading
Loading