add CLAUDE.md with project guide
Durable project context (architecture, roadmap, key decisions, external references, commit conventions) so any Claude Code session on any machine has the same baseline understanding. Machine-local facts stay out of the repo, in ~/.claude/. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
155
CLAUDE.md
Normal file
155
CLAUDE.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# Project guide for Claude Code
|
||||||
|
|
||||||
|
This file is loaded automatically when working on `bs_explorer` in any
|
||||||
|
Claude Code session, on any machine where the repo is cloned. Keep
|
||||||
|
machine-specific or user-specific facts out of here — they belong in
|
||||||
|
`~/.claude/` memory, not in the repo.
|
||||||
|
|
||||||
|
Project status, decisions, and roadmap below are durable: update them
|
||||||
|
when reality changes, not for every transient task.
|
||||||
|
|
||||||
|
## What this project is
|
||||||
|
|
||||||
|
`bs_explorer` is an application layer on top of Viveris's
|
||||||
|
[jtag-boundary-scanner](https://github.com/viveris/jtag-boundary-scanner)
|
||||||
|
library (LGPL). End goal: program SPI configuration memories attached
|
||||||
|
to FPGAs (Xilinx KU15P first, then others) over JTAG, from a CLI tool
|
||||||
|
running on a host with an FTDI probe.
|
||||||
|
|
||||||
|
The Viveris library itself lives unchanged in `modules/`. Everything
|
||||||
|
new is in `bs/` (the REPL) and future modules (`fpga/`, `bscan_spi/`,
|
||||||
|
`spi_flash/`) sitting alongside the Viveris ones.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
bs/ Application (readline REPL, no business logic)
|
||||||
|
modules/ — Viveris's library (LGPL, unchanged) —
|
||||||
|
├── jtag_core/ TAP state machine, IR/DR shifts
|
||||||
|
├── bsdl_parser/ .bsd loader
|
||||||
|
├── bus_over_jtag/ SPI/I²C/MDIO/parallel mem bit-bang over EXTEST
|
||||||
|
├── drivers/ FTDI, J-Link, Linux GPIO, LPT
|
||||||
|
├── script/ Script engine (40+ commands, the real UI)
|
||||||
|
├── config/ Built-in config.script
|
||||||
|
├── os_interface/ Portable fs/network wrappers
|
||||||
|
└── natsort/ Natural pin-name sorting
|
||||||
|
bsdl_files/ BSDL files for target FPGAs
|
||||||
|
scripts/ Example scripts
|
||||||
|
libs/libftd2xx/ Vendored FTDI SDK
|
||||||
|
```
|
||||||
|
|
||||||
|
User interacts with the project through the script engine commands
|
||||||
|
(`jtag_*`, `set`, `if`, …), exposed via the REPL or piped script files.
|
||||||
|
Adding a feature usually means adding a new script command in
|
||||||
|
`modules/script/script.c` and the supporting C in a new module.
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
| Phase | Module | Status | Summary |
|
||||||
|
|-------|--------|--------|---------|
|
||||||
|
| 1 | `bs/` cleanup, REPL polish, README | **done** (commit `7cb3627`) | Fix format-strings, delete dead code, tab-completion, banner |
|
||||||
|
| 2 | `fpga/` | planned | Per-target descriptor (IDCODE, BSDL, IR codes, proxy path, quirks). Compile-time registry. |
|
||||||
|
| 2.5 | `bscan_spi/` | planned | Load BSCAN proxy bitstream via `CFG_IN`, expose fast `bscan_spi_xfer()` via `USER1`. Required for realistic flashing speeds. |
|
||||||
|
| 3 | `spi_flash/` | planned | Chip database (JEDEC ID → page/sector/cmd set). Generic `read/erase/program/verify` over either backend. |
|
||||||
|
| 4 | script commands | planned | `flash_detect`, `flash_read/write/erase/verify`. |
|
||||||
|
|
||||||
|
Move forward phase by phase: validate one with the user before starting
|
||||||
|
the next. Don't break the validated path
|
||||||
|
`jtag_open_probe → jtag_autoinit → jtag_set_mode 0 EXTEST` while
|
||||||
|
refactoring.
|
||||||
|
|
||||||
|
## Key technical decisions
|
||||||
|
|
||||||
|
### Flashing path: BSCAN proxy, not EXTEST
|
||||||
|
|
||||||
|
The Viveris library has `bus_over_jtag/spi_over_jtag.c` which bit-bangs
|
||||||
|
SPI on FPGA pins placed in EXTEST. **This is not usable for actual
|
||||||
|
flashing.** Each SPI bit costs 2 full boundary-scan-register shifts
|
||||||
|
through JTAG, plus USB latency on the FTDI side. Order of magnitude:
|
||||||
|
~30 bytes/s effective, i.e. **weeks** to flash a 128 MB part. Useful
|
||||||
|
only for one-shot operations (read JEDEC ID, check wiring).
|
||||||
|
|
||||||
|
Real flashing path: load a small "BSCAN proxy" bitstream into the FPGA
|
||||||
|
fabric via standard JTAG configuration (`CFG_IN`). The proxy uses a
|
||||||
|
`BSCANE2` primitive to bridge the JTAG `USER1` instruction's DR shift
|
||||||
|
to the physical SPI pins, running at fabric speed (CCLK driven
|
||||||
|
internally — the `STARTUPE3` problem disappears). Realistic throughput
|
||||||
|
50–200 KB/s, so ~10–40 min for 128 MB. This is what Vivado, OpenOCD's
|
||||||
|
`jtagspi` driver, and `xc3sprog` all do.
|
||||||
|
|
||||||
|
### Per-FPGA descriptor
|
||||||
|
|
||||||
|
`fpga_target` struct (Phase 2) holds the per-target facts that can't be
|
||||||
|
derived from the BSDL alone:
|
||||||
|
- `idcode` + `idcode_mask` — match the device on the chain
|
||||||
|
- `bsdl_filename` — BSDL to auto-load
|
||||||
|
- `cfg_in_ir_code`, `user1_ir_code`, `jprogram_ir_code` — Xilinx-specific
|
||||||
|
private IR opcodes (read from BSDL when available)
|
||||||
|
- `proxy_bitstream_path` — path to the BSCAN proxy `.bit` for this part
|
||||||
|
- `quirks` — flags for known caveats (e.g. CCLK via STARTUPE3)
|
||||||
|
|
||||||
|
Registry is a compile-time array. Adding a part = one entry + its
|
||||||
|
`.bsd` in `bsdl_files/` + its proxy `.bit` in `bscan_proxies/`.
|
||||||
|
|
||||||
|
### Xilinx caveats
|
||||||
|
|
||||||
|
On 7-Series / UltraScale / UltraScale+, `CCLK` is not a regular I/O
|
||||||
|
pin — it goes through the `STARTUPE3` primitive. Cannot be driven
|
||||||
|
directly in EXTEST. Non-issue once we use the BSCAN proxy (CCLK is
|
||||||
|
driven by the fabric clock inside the proxy).
|
||||||
|
|
||||||
|
The FPGA must be in a configurable state before loading the proxy.
|
||||||
|
Issue `JPROGRAM` first to reset, then `CFG_IN` + shift the bitstream,
|
||||||
|
then `JSTART` and check `DONE`.
|
||||||
|
|
||||||
|
## External references
|
||||||
|
|
||||||
|
- **BSCAN proxy bitstreams**: `quartiq/bscan_spi_bitstreams` (BSD-2).
|
||||||
|
Pre-built `.bit` for most Xilinx parts; Migen sources to rebuild any
|
||||||
|
part that's missing (needs Vivado).
|
||||||
|
- **Reference host-side implementation**: `openocd/src/flash/nor/jtagspi.c`.
|
||||||
|
Defines the proxy protocol (header with bit count + CS state, then
|
||||||
|
payload). Don't reinvent — match what OpenOCD does so we share the
|
||||||
|
same bitstreams.
|
||||||
|
- **Viveris library docs**: `modules/jtag_core/` headers are well
|
||||||
|
commented. `modules/config/config.script` documents every runtime
|
||||||
|
variable.
|
||||||
|
|
||||||
|
## Build & test
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir build && cd build && cmake .. && make
|
||||||
|
./bs/bs # interactive REPL
|
||||||
|
```
|
||||||
|
|
||||||
|
No automated tests yet. Smoke test = banner appears, `exit` works.
|
||||||
|
After changes touching `jtag_core`, `drivers/ftdi_jtag`, or the
|
||||||
|
`autoinit` flow, manual hardware test required: probe + KU15P board
|
||||||
|
should scan and load `xcku15p_ffve1517.bsd`.
|
||||||
|
|
||||||
|
The FTDI driver compiles with int-to-pointer-cast warnings (Viveris's
|
||||||
|
code on 64-bit Linux). Don't fix in this repo — that's upstream.
|
||||||
|
|
||||||
|
## Commit conventions
|
||||||
|
|
||||||
|
- Messages in English, lowercase first word, imperative or short
|
||||||
|
descriptive (match existing style: "phase 1: cleanup, REPL polish,
|
||||||
|
README", "translate README to English").
|
||||||
|
- Title ≤ ~70 chars. Body wrapped ~80 chars, with bullets for what
|
||||||
|
changed. Mention the why for non-obvious choices.
|
||||||
|
- Sign-off block:
|
||||||
|
```
|
||||||
|
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||||||
|
```
|
||||||
|
- One logical change per commit. Don't bundle README + bugfix +
|
||||||
|
refactor.
|
||||||
|
|
||||||
|
## What does NOT belong here
|
||||||
|
|
||||||
|
- User preferences (tone, language used in chat, "always do X first")
|
||||||
|
→ `~/.claude/`
|
||||||
|
- Machine-local facts (which probes are physically attached, paths
|
||||||
|
outside the repo, validated-on-this-machine notes) → `~/.claude/`
|
||||||
|
- Transient task state, in-progress decisions → conversation, not file
|
||||||
|
- Generated artifacts (`build/`, downloaded proxy `.bit` if we choose
|
||||||
|
not to vendor) → `.gitignore`
|
||||||
Reference in New Issue
Block a user