gowin-program-verify — programmer_cli wrapper with UserCode 検証 + auto retry

STEP: 1596 / Date: 2026-08-30 / Status: ✅ E2E 動作確認完了 (Tang Nano 9K + STEP 1591 bitstream で 1 attempt PASS)

STEP 1586 で発見された programming transient (programmer_cli 100% 完了報告 + Status non-error なのに FPGA に data 到達せず) を fs↔programmed UserCode diff で 一発検知 + auto retry する wrapper。 STEP 1590 で 「User code mismatch」 warning が critical signal であることが 実証され、 本 STEP で それを code 化。 Phase C 全 project の README を wrapper 経由に 統一。

使い方

scripts/gowin-program-verify.sh -f impl/pnr/<project>.fs

Options

FlagDefault説明
-f FSFILE(required).fs bitstream path
-c INDEX1cable-index
-d DEVICEGW1NR-9C--device value (Tang Nano 9K default)
-r RETRIES3max retry on mismatch
--flashoffembFlash Program (irreversible); default = SRAM (reversible)
--programmer PATHGowin V1.9.12.02_SP2programmer_cli.exe path override

動作 flow

  1. fs file の //UserCode: header を 事前抽出 (例: 0x0000E28C)
  2. programmer_cli --device ... --cable-index ... --run 2 --fsFile FSFILE 実行
  3. 出力から User Code is: 0xNNNNNNNN + Status Code is: 0xNNNNNNNN + Cost 抽出
  4. "User code mismatch" warning 有無 検出
  5. fs UserCode ↔ programmed User Code diff verify
  6. 一致 → ✅ SUCCESS exit 0 / 不一致 → auto retry (default 最大 3 回) / 全 retry 失敗 → ❌ exit 1

E2E 実測 (STEP 1591 reprogram、 2026-08-30)

scripts/gowin-program-verify.sh -f hardware/phase-c/14-nano9k-inductive-coil-loopback/impl/pnr/inductive_coil_loopback.fs

═══════════════════════════════════════════════════════════════
  Gowin program-verify
  fs file:        .../inductive_coil_loopback.fs
  fs UserCode:    0x0000E28C
  device:         GW1NR-9C
  cable-index:    1
  run mode:       2 (SRAM Program (reversible))
  max retries:    3
═══════════════════════════════════════════════════════════════

  attempt 1 result:
    programmed User Code:  0x0000E28C
    Status Code:           0x0003F020
    Cost 3.02 second(s)
  ✅ MATCH — configuration OK (fs=0x0000E28C == prog=0x0000E28C)

═══════════════════════════════════════════════════════════════
  ✅ SUCCESS after 1 attempt(s)
═══════════════════════════════════════════════════════════════

Error paths (実測 verify 済)

$ scripts/gowin-program-verify.sh
ERROR: -f FSFILE is required
$ echo $?
2

$ scripts/gowin-program-verify.sh -f /nonexistent.fs
ERROR: file not found: /nonexistent.fs

$ scripts/gowin-program-verify.sh -f /tmp/fake.fs   # 不正 fs
ERROR: could not extract UserCode from fs header: /tmp/fake.fs
  (expected line like: //UserCode: 0xNNNNNNNN)

Exit codes

Code意味
0program 成功 + UserCode 一致 verify OK
1configuration 失敗 (retry 後も mismatch or 通信 error)
2usage error (args 不正 / fs 不在 / UserCode header 抽出失敗)

なぜ必要か

STEP 1586 で発生した incident: Rev 1 (counter reset-comparison pattern) の bitstream を Program → progress bar 100% + "Finished. Cost 4.89 second(s)" = 見た目 成功 → LED 点滅せず。 唯一の critical signal は 「User Code is: 0x00000000」 (fs 側は valid checksum のはずが 0 = configuration 失敗) と 「User code mismatch」 warning。 私 (Claude) は これを cosmetic 判断 (「set_option -user_code 未指定 だから」) してしまい、 「STEP 1574 generator の bug」 と 誤診断。

STEP 1590 で hardware 不要 diagnostic (byte-for-byte 同一 source rebuild → LUT/FF/CLS 完全一致 + fs UserCode 0x0000B4BF valid) で 「code は 正しい」 と 特定、 STEP 1590 silicon retest で 「program → UserCode 一致 + LED 点滅」 で 完全裏付け = 単なる一時的 programming failure だった と 確定。

Wrapper 使用で 「気付かない失敗」 を fs↔programmed UserCode diff で 一発検知 できる。 mismatch なら 自動 retry で 大半の transient は 2 回目以内で 通る。

Phase C 全 project の 統一 (2026-08-30 完了)

以下の README を wrapper 経由に update:

05-11 の 過去 spike project (xor-nand / uart-i2c-scaffold / bme280-phase2 / osco-drift / ring-puf-spike / dfumt8-alu) は 生 programmer_cli 参照を そのまま残す (rewrite せず、 top-level README で wrapper 推奨を明示) — legacy 保存の 保守方針。 新規 spike は 必ず wrapper 経由。

Honest scope

Files