Files
skills-win/sim-rtl-flow/SKILL.md
T
boweiandClaude Opus 5 e07cfaa6d1 sync: WIN-BOWEI 2026-08-10 fpga_flash 增 Zynq BOOT.bin/QSPI 脚本,rtl-ip-replace 与 sim-rtl-flow 更新
- fpga_flash: 新增 build_zynq_boot.py / program_zynq_qspi.py(bootgen + program_flash,
  含备份、SHA-256/容量/marker 守卫);vivado_env.py 增 resolve_sdk_dir(SDK_ROOT/SDK_PATH);
  SKILL.md 补 Zynq 烧写流程,示例去掉写死的 D:\Xilinx\SDK\2018.1,改由 skills_env.md 解析。
- rtl-ip-replace: gen_ip.tcl / namespace_ip.py 更新。
- sim-rtl-flow: SKILL.md 与 run_sim_rtl_flow.py 更新。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:50:44 +08:00

404 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: sim-rtl-flow
description: >
Run the sim-rtl-flow LangGraph workflow at E:\LangGraph_Design\sim-rtl-flow — the
Simulink-to-RTL-to-hardware design pipeline: read the previous run's design history
doc sim-rtl-flow-<date>.md to decide what may be reused → Simulink -x principle sim
(sim-golden) → HUMAN sign-off on simulation performance → optional -q fixed-point →
parallel functional partition + RTL/SoC interface spec → HUMAN sign-off on the
partition (skippable when history says the partition is unchanged) → per-module
-E.slx nativization and Xilinx-IP replacement (parallel Send fanout, modules the
history proved good are skipped) → Vivado build + timing → hardware-in-the-loop via
fpga-imx6-flow or zynq-imx6-flow → write a fresh sim-rtl-flow-<date>.md summarising
every -x / -q / -E version. It drives the compiled graph in-process (no langgraph dev
server) and hands every subagent task back to THIS Claude session — and every human
checkpoint to the USER — through a record/replay ledger stored in the design project
being worked on.
ALWAYS use this skill whenever the user wants to run, start, drive, resume or continue
the sim-rtl-flow workflow / Simulink→RTL design flow, or says things like "启动
sim-rtl-flow", "跑 sim-rtl-flow", "运行仿真到RTL的设计流程", "执行 sim-rtl-flow 设计任务",
"继续 sim-rtl-flow", "run the sim to rtl flow", "resume the sim-rtl-flow run", even if
they don't name the project path. Also use it when the user asks to record a subagent
result, to approve or reject one of the two human checkpoints, or to rehearse the graph
with the scripted backend.
---
## What this skill does
Drives the **sim-rtl-flow** graph (25 top-level nodes + a 5-node per-module subgraph,
1:1 with `Notes/PR01-1.md`, `Notes/PR01-2.md` and `Notes/PR01_sim_rtl_flow.drawio`).
The graph contains **no** agent logic — it talks to the outside world through two
protocols: `SubagentBackend` (design work) and `ReviewGate` (the two mandatory human
sign-offs). This skill plugs a **record/replay** implementation into both: the graph
runs in-process until it needs an answer that isn't recorded yet, then stops and prints
the request. **You are the subagent; the USER is the reviewer.** You do the work,
`record` the answer, and `resume` — the driver replays the ledger, deterministically
walks back to where it stopped, and asks for the next thing.
| Item | Value |
|---|---|
| Project root | 见 `~\skills_env.md` 的 `SIM_RTL_FLOW_ROOT`(driver 自动读取,也可 `--project` 覆盖) |
| Conda env | `langgraph` (path 见 `~\skills_env.md` 的 `CONDA_LANGGRAPH_PYTHON`;装环境用 `/langgraph-vivado-install`) |
| Graph | `sim_rtl_flow.graph:build_workflow` (in-process, no `langgraph dev`) |
| Driver | `%USERPROFILE%\.claude\skills\sim-rtl-flow\scripts\run_sim_rtl_flow.py` |
| **Run state** | **`<work_dir>\.sim_rtl_flow\runs\<thread-id>\`** — inside the *design project*, never in the workflow repo |
| Max attempts | 10 per gate (default) |
There is **no LangGraph checkpointer** in the driver, on purpose: graph nodes have no
side effects of their own (all side effects live in the subagents, which are replayed),
so re-invoking from scratch is cheaper and immune to partial-superstep resume semantics.
`ledger.json` *is* the persistence.
**Drive the driver with the Bash tool (Git Bash), not PowerShell** — PowerShell 5.1
mangles the double quotes inside `--result '{...}'` payloads. Every command below was
run this way and verified.
```bash
PY="<CONDA_LANGGRAPH_PYTHON — see ~\skills_env.md>"
RUN="$USERPROFILE/.claude/skills/sim-rtl-flow/scripts/run_sim_rtl_flow.py"
export PYTHONIOENCODING=utf-8
```
The driver resolves the workflow checkout from `SIM_RTL_FLOW_ROOT` in
`~\skills_env.md`, so no path is baked into this skill.
## 📄 The design history doc `sim-rtl-flow-<date>.md`
Every run **reads** the newest history doc and **writes** a new one. That doc is the
only mechanism stopping the flow from re-doing — and thereby re-breaking — design work
that a previous run already validated.
| | |
|---|---|
| Location | `<work_dir>/<history_dir>/`, where `history_dir` defaults to the folder holding `requirements_path` (usually `Notes`) |
| Name | `sim-rtl-flow-<YYYYMMDD-HH>.md` — date **and hour**, zero-padded, so name order == time order |
| Read | `start` freezes the newest matching file into `input.json` as `history_path`; the `history_review#1` task interprets it |
| Written | the `design_summary#1` task, at the end of **every** run — completed *and* failed |
`history_review` returns its verdict in `metadata`, and that verdict is what lets the
graph skip work:
| metadata field | effect if `false` / listed |
|---|---|
| `redo_fixed_point` | `false` → the `-q` stage is skipped entirely |
| `redo_partition` + `partition_review_required` | both `false` → the **`functional_partition` human checkpoint is skipped** |
| `reuse_modules` | listed module → its `native:M` + `ip_replace:M` are skipped; result recorded as `stage: history_reuse` |
| `redo_modules` | listed module always re-runs, even if also in `reuse_modules` |
**Every default is "redo".** Omit a field and the stage runs. Fail the
`history_review` gate (`gate_passed: false`) and *nothing* is skipped. Recording a skip
you did not verify means a later gate — Vivado, HIL, sim-golden — validates a design
nobody checked this run.
Four things force everything back to redo, regardless of the history doc:
1. `simulink_x` running a second time (a rejected `sim_performance`, or a retry) —
sim-golden may have moved, so the history describes a *different* `-x`;
2. `partition#n` returning `metadata.partition_changed: true` — the human checkpoint
comes back even if history said to skip it;
3. any module named by Vivado or HIL rework — the reuse pool is consumed after the
first module round and never applies to a rework round;
4. the user having already answered `functional_partition` once — a rejection can never
be swallowed by a later "history says skip it".
When you write the summary, `artifacts[0]` must be the real path you wrote. If the
summary cannot be written after `--max-attempts`, the run is reported **failed** even
if the design itself passed — because the next run would silently lose its basis for
skipping anything.
## ⚠️ The two human checkpoints are the user's decision, not yours
The graph stops at two points that **an agent may not decide**:
| checkpoint | where | what the user confirms |
|---|---|---|
| `sim_performance` | after step 1 | the `-x` sim meets the requirement and may be frozen as **sim-golden** |
| `functional_partition` | after step 3 | the pure-sim / RTL / SoC split and the RTL↔SoC interface doc — **skipped** only when the history doc says the partition is unchanged (see above) |
When one comes up the driver prints a `!!!` banner. **Relay the question and its context
to the user verbatim, then wait.** Do not approve on your own judgement, do not infer
approval from "the numbers look fine", and do not use `--all-ok` (the driver refuses it
for review keys anyway). A rejection **must** carry the user's reason.
```bash
"$PY" "$RUN" --work-dir <proj> --thread-id <id> record --key review:sim_performance#1 --approve
"$PY" "$RUN" --work-dir <proj> --thread-id <id> record --key review:sim_performance#1 \
--reject --notes "带外抑制不足 6dB"
```
Rejecting `sim_performance` re-runs step 1; rejecting `functional_partition` re-runs the
whole partition + interface superstep.
## Non-negotiable design rules the graph enforces
From `Notes/PR01.md` and `Notes/PR01-2.md`; the graph routes on these.
1. **sim-golden is the only acceptance criterion.** `-q`, the partition, and every `-E`
version must match the `-x` sim. If it doesn't, record `gate_passed: false` — never
record a pass you didn't verify.
2. **One `-E.slx` per RTL submodule**, saved separately (`<project>_A-E.slx`, …). Do not
nativize all submodules in one Simulink model.
3. **Never hand-edit MATLAB-generated RTL.** If IP replacement, Vivado timing, or HIL
needs a change there, return `change_scope: "simulink_module"` + `affected_modules`.
The graph then forces `modify_e:* → sync_sim:*` before any RTL is regenerated.
4. **Editing a `-E` model obliges you to sync the `-x`/`-q` model.** `modify_e:*` edits
only the `-E`; the follow-up `sync_sim:*` uses **`simulink-rtl-redev`** to carry the
same change into the simulation model and re-verify against sim-golden. The
derivation script does *not* translate native-core edits into the m implementation,
so changing one side alone means the RTL moved while the simulation still validates
the old behaviour. If they don't align, the graph goes back to `modify_e:*` — it will
**not** let you regenerate RTL.
5. **Timing fixes change the RTL, not the constraints.** Prefer adding pipeline/delay
stages. Only touch timing constraints when the constraint itself is plainly wrong,
and say why in `notes`.
6. **HIL is strictly read-only.** `hil:*` arrives with `allow_code_changes=false`. Run
`fpga-imx6-flow` / `zynq-imx6-flow` for *diagnosis only*; the moment a code change is
needed, stop that sub-flow and report it back here — the fix happens in the
sim-rtl-flow main graph, then re-enters Vivado and HIL.
7. **Skipping a step needs written evidence, and every run leaves some.** The only
grounds for not executing a stage are a history doc that records it as verified and
unaffected. Every run ends by writing the next `sim-rtl-flow-<date>.md`; anything you
could not verify goes in as *not verified*, so the next run redoes it.
## Run (agent path)
### 1. Write the workflow input
`work_dir` is the design project. **All run state goes under
`<work_dir>/.sim_rtl_flow/`** — that is where `resume`/`record`/`status` will look.
```bash
cat > /c/Users/Administrator/AppData/Local/Temp/claude/input.json <<'EOF'
{
"requirements_path": "Notes/requirements.md",
"work_dir": "E:/Xilinx_design/my_project",
"project_name": "demo",
"device_family": "fpga-imx6",
"fixed_point_required": true,
"rtl_modules": ["A", "B", "C"],
"soc_modules": ["control"]
}
EOF
```
| field | meaning |
|---|---|
| `requirements_path` | user's requirement `.md`, relative to `work_dir` |
| `work_dir` | the design project — **absolute path**; also where run state is written |
| `project_name` | artifact prefix — `<name>-x.slx`, `<name>_A-E.slx`, `<name>.bit` |
| `device_family` | `fpga-imx6` → HIL via `fpga-imx6-flow`; `zynq-imx6` → `zynq-imx6-flow`. Anything else raises at `initialize`. |
| `fixed_point_required` | `false` skips the `-q` stage |
| `rtl_modules` | submodule names; each gets its own parallel `native → ip_replace` chain. Non-empty. |
| `soc_modules` | MCU/SoC-side modules (interface-spec input) |
| `history_dir` | optional — folder holding `sim-rtl-flow-<date>.md`; defaults to the folder of `requirements_path` |
| `history_path` | optional — pin one history doc. Omit and `start` fills in the newest it finds; set `""` to declare "no history, do everything". |
### 2. Start — exits 10 with a handoff
```bash
"$PY" "$RUN" --thread-id my-design-001 start --input /c/Users/Administrator/AppData/Local/Temp/claude/input.json
```
`start` takes `work_dir` from the input JSON and prints where state landed. Verified:
```
work dir : E:\Xilinx_design\my_project
run dir : E:\Xilinx_design\my_project\.sim_rtl_flow\runs\my-design-001
========================================================================
HANDOFF — 1 subagent task(s), 0 human review(s)
========================================================================
--- key: simulink_x#1
role : simulink-principle-agent
permission : WRITE ALLOWED
prompt : 根据需求文档创建或修订 Simulink -x 原理仿真;...
```
Exit codes: **10** = handoff pending, **0** = completed, **1** = `failed`, **2** = crash.
### 3. Answer, then resume
Every later command needs to find the run, so pass `--work-dir` (or `cd` into it):
```bash
W="--work-dir E:/Xilinx_design/my_project --thread-id my-design-001"
"$PY" "$RUN" $W record --key simulink_x#1 \
--result '{"gate_passed": true, "artifacts": ["demo-x.slx"], "notes": "EVM -38dB"}'
"$PY" "$RUN" $W resume
```
Loop until `WORKFLOW FINISHED — status: completed`. When several keys are pending,
record **each**, then `resume` once. `record --all-ok` fast-forwards pending *subagent*
keys with a default success — rehearsal only, and it refuses review keys.
### 4. What you get handed
| key | what you actually do | which skill to use |
|---|---|---|
| `history_review#n` | read `sim-rtl-flow-<date>.md` + the requirement doc, decide what may be reused; verdict in `metadata` (**first task of every run that has a history doc**) | inline — read the files, don't guess |
| `simulink_x#n` | build/revise the `-x` sim, document the performance envelope | MATLAB MCP + `model-based-design-core:building-simulink-models`, `simulating-simulink-models` |
| `review:sim_performance#n` | **ask the user** to sign off on sim-golden | — (relay to user) |
| `fixed_point#n` | `-q` fixed-point, compare to `-x` | same MATLAB skills |
| `partition#n` | pure-sim / RTL / SoC split, must not degrade sim-golden | same |
| `interfaces#n` | RTL↔SoC interface doc — register-config or data-stream only | write the doc under `work_dir` |
| `review:functional_partition#n` | **ask the user** to sign off on the split + interfaces | — (relay to user) |
| `module_plan#n` | split the RTL side into A/B/C…, give order + dependencies (**first pass only**) | inline |
| `native:<M>#n` | nativize M into HDL-capable blocks, save `<project>_M-E.slx`, generate RTL | `simulink_rtl_dev` |
| `ip_replace:<M>#n` | swap in Xilinx IP, cycle-true compare vs MATLAB RTL | `rtl-ip-replace` |
| `modify_e:module#n` / `modify_e:vivado#n` / `modify_e:hil#n` | edit **only** the named `-E.slx` (cycle-true / timing / HIL driven) | `simulink_rtl_dev` |
| `sync_sim:<source>#n` | carry that `-E` change into the matching `-x`/`-q` model and re-verify alignment | **`simulink-rtl-redev`** |
| `vivado#n` | build the Vivado project, synth+impl+bitstream, check all timing | `vivado-prj-create`, `vivado-mcp` |
| `hil:fpga-imx6-flow#n` / `hil:zynq-imx6-flow#n` | HIL debug, **read-only** | `fpga-imx6-flow` / `zynq-imx6-flow` |
| `timing_rework#n` | fix non-Simulink RTL / SoC / project timing | inline |
| `hil_rework#n` | apply the code change HIL asked for | inline |
| `design_summary#n` | write `<history_dir>/sim-rtl-flow-<YYYYMMDD-HH>.md` (path handed to you in `context.target_path`) covering every `-x`/`-q`/`-E` version, the partition, per-module status, Vivado/HIL verdicts, what was reused and what is still open; return the real path in `artifacts` (**last task of every run, success or failure**) | inline |
`#n` is the n-th time that key has been requested this run — retries and rework produce
`#2`, `#3`, …
### 5. Answer JSON
`"$PY" "$RUN" schema` prints both templates. All fields optional except `approved`.
```json
subagent: {"success": true, "gate_passed": true, "artifacts": [], "notes": "",
"timing_met": true, "hil_passed": true, "needs_code_change": false,
"change_scope": "none", "affected_modules": [], "metadata": {}}
review: {"approved": true, "notes": "", "metadata": {}}
```
| field | who reads it |
|---|---|
| `success` + `gate_passed` | every design node — `false` → retry, then `failed` after 10 attempts |
| `artifacts` | `simulink_x`'s first artifact **becomes sim-golden**; `vivado`'s go to HIL as the bitstream |
| `timing_met` | `vivado` only |
| `hil_passed` | `hil:*` only |
| `needs_code_change` + `change_scope` + `affected_modules` | `vivado` and `hil:*` — the rework router |
Routing on `change_scope`:
- `simulink_module` → **`modify_e:*`** (edit the `-E.slx`) → **`sync_sim:*`** (carry it
into `-x`/`-q`, re-verify) → only the affected modules re-run `native → ip_replace` →
Vivado → HIL.
- `non_simulink_rtl` / `soc` / `hardware` → `timing_rework` (from Vivado) or `hil_rework`
(from HIL) → Vivado.
- The driver **rejects** `needs_code_change: true` with `change_scope: "none"`.
A failing `ip_replace:<M>` (cycle-true mismatch) enters the same chain on its own:
`evaluate_modules → modify_e:module → sync_sim:module → native:<M>`. A failing
`native:<M>` does **not** — the `-E` isn't sound yet, so it just re-runs nativization.
### 6. Parallel batches (verified)
| stage | keys handed over at once |
|---|---|
| after `-x` / `-q` | `interfaces#1` **and** `partition#1` |
| module fanout | one `native:<M>#1` per module (3 for `["A","B","C"]`) — **minus any module reused from history** |
| next module stage | one `ip_replace:<M>#1` per module |
`history_review#1` and `design_summary#1` are always single-task batches, at the very
start and the very end of the run.
Work batched tasks in any order; record all, then `resume`.
## Rehearsal without touching hardware
```bash
"$PY" "$RUN" dry-run --input examples/happy_path.json
```
Runs the whole graph against `ScriptedBackend` + auto-approving `ScriptedReviewGate` —
no handoffs, no side effects. Verified: `status: completed`, 13 subagent calls listed
with their skill and write permission, plus both review checkpoints. To rehearse a
branch, add `outcomes` (task → list of results) and/or `reviews` (checkpoint → list of
decisions) to the input JSON; `start`/`resume` strip both.
```json
"outcomes": {"hil:fpga-imx6-flow": [
{"success": true, "hil_passed": false, "needs_code_change": true,
"change_scope": "simulink_module", "affected_modules": ["A"]},
{"success": true, "hil_passed": true}]},
"reviews": {"sim_performance": [{"approved": false, "notes": "EVM 未达标"}]}
```
## Other commands
```bash
"$PY" "$RUN" $W status # ledger + pending + final status
"$PY" "$RUN" schema # both answer templates
"$PY" "$RUN" mermaid # graph as Mermaid (see gotcha)
"$PY" -m unittest discover -s tests # project's own 16 tests — all pass
```
Global flags go **before** the subcommand: `--project`, `--work-dir`, `--thread-id`,
`--recursion-limit` (200), `--max-attempts` (10).
## Gotchas
- **`resume`/`record`/`status` need `--work-dir`** (or a `cd` into the design project).
Only `start` can infer it, from the input JSON. Without it the driver looks in the cwd
and reports `no input.json in …`.
- **The driver refuses a `work_dir` inside the sim-rtl-flow repo.** Run state belongs to
the design project (PR01-2). `examples/happy_path.json` therefore carries a placeholder
`E:/Xilinx_design/your_project` — fine for `dry-run`, but replace it before `start`.
- **`mermaid` output is still partly misleading.** The forward and rework edges now
render (path maps were added), but `plan_modules`' `Send` fanout is a dynamic edge
Mermaid can't show. Use `Notes/Result00.md` for the authoritative picture.
- **`--max-attempts` must precede the subcommand** and stay the *same value* across
`start` and every `resume` — it is runtime context, not persisted state.
- **The skill names the graph hands you are real and exact** — `simulink_rtl_dev`
(**underscores**, not dashes), `rtl-ip-replace`, `simulink-rtl-redev`. All three are
installed. Invoke the named one rather than improvising with MATLAB MCP directly: they
carry the project's own gates (`audit_hdl_blocks.m`, cycle-true compare, `check_sync.py`).
- **`sync_sim:*` is not optional bookkeeping.** It is the step that keeps the `-x`/`-q`
model telling the truth about the `-E` you just changed. Recording it as passed without
actually re-simulating means every later gate — Vivado, HIL, sim-golden — is validating
a model that no longer matches the RTL.
- **`simulink_x`'s first artifact silently becomes sim-golden.** Record `artifacts: []`
and the graph substitutes `<project_name>-x.slx`. Always record the real filename.
- **`module_plan` runs only on the first pass.** Rework rounds reuse the plan, so you
will not be asked to re-partition the module list mid-run.
- **Re-recording a key requires editing `ledger.json` by hand.** `record` only accepts
currently-pending keys; anything already in the ledger is replayed forever. To redo a
step, delete its entry *and everything after it*, then `resume`.
- **Runs created before the PR01-2 change live in the old location**
(`<SIM_RTL_FLOW_ROOT>\runs\<id>\`) and their ledgers have no `review:*` or
`module_plan` keys, so they cannot be resumed under the current graph. Start a fresh
thread instead.
- **`work_dir` is passed straight through to every subagent request.** Forward slashes
are fine on Windows; a relative `"."` resolves against wherever the driver was
launched — always use an absolute path.
- **`start` wipes the ledger** unless `--keep-ledger`. Use a fresh `--thread-id` per run.
- **`start` freezes `history_path` into `input.json`.** It must not be re-scanned on
every `resume`: the run itself writes a *newer* `sim-rtl-flow-<date>.md` at the end,
and a re-scan would make a later replay reference a different history doc than the
one already recorded in the ledger. Pinning it also makes `resume` after
`WORKFLOW FINISHED` a no-op instead of a spurious new handoff.
- **A reused module produces no `native:`/`ip_replace:` keys at all.** If you expected
three modules and only got one task, check the `modules_reused_from_history` event —
that is the graph honouring your own `history_review` verdict, not a lost module.
- **`design_summary` is the deliverable, not a formality.** Record it only after the
file really exists on disk with real content; `artifacts[0]` must be its path.
- **The summary can fail an otherwise-good run.** `status: failed` with
`运行已结束但历史设计说明文件 … 未能生成` means the design work passed but the history
doc did not get written — fix that and re-run the summary, don't ignore it.
## Troubleshooting
| symptom | cause / fix |
|---|---|
| `sim_rtl_flow package not found under …\src` | `SIM_RTL_FLOW_ROOT` in `~\skills_env.md` is wrong/missing; fix it or pass `--project <检出目录>` |
| `sim-rtl-flow 工作流仓库路径未配置` | add `SIM_RTL_FLOW_ROOT = <检出目录>` to `~\skills_env.md` |
| `no input.json in …\.sim_rtl_flow\runs\<id>` | missing/incorrect `--work-dir`, or `start` was never run |
| `nothing pending — run 'start' or 'resume' first` | the previous invoke completed or crashed; check `status` |
| `--key X is not pending; pending = [...]` | typo, or already recorded (see the re-record gotcha) |
| `--all-ok 不能用于人工审核断点` | working as intended — the user must decide; use `--approve` / `--reject` |
| `驳回必须写明理由:请提供 notes` | add `--notes "<user's reason>"` |
| `unknown review fields: ['gate_passed']` | you sent a subagent result to a `review:*` key; use `--approve`/`--reject` |
| `needs_code_change=true requires an explicit change_scope` | add `change_scope` |
| `MissingReviewGateError` | only if the graph is driven without a review gate — the driver always supplies one |
| `device_family must be 'fpga-imx6' or 'zynq-imx6'` | raised in `initialize`; exit 2 |
| exit 2 + `recursion_limit` | a rework loop isn't converging — raise `--recursion-limit`, or stop recording `needs_code_change` for the same module |
| mojibake in the Chinese prompts | `export PYTHONIOENCODING=utf-8` |