From d631dfef5c941a058e3caeb011bf3f3b2c9e3498 Mon Sep 17 00:00:00 2001 From: bowei Date: Sat, 29 Aug 2026 04:36:26 +0800 Subject: [PATCH] =?UTF-8?q?sync:=20BOWEI=202026-08-29=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20dpd-mig-flow=20/=20sim-rtl-flow=20=E4=B8=A4=E4=B8=AA=20skill?= =?UTF-8?q?=EF=BC=8C=E5=8E=BB=E7=A1=AC=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dpd-mig-flow、sim-rtl-flow 首次入库 - 两者的 LangGraph 检出路径、SMOD 参考工程路径、N9320B/板卡 IP 改为 引用 ~/skills_env.md(新增 DPD_MIG_FLOW_ROOT / SIM_RTL_FLOW_ROOT / XILINX_SMOD_ROOT / SMOD_ATSC_REF 等条目) - sim-rtl-flow 示例里写死的 /c/Users/Administrator 临时路径改为 $TMPDIR - 撤出上次遗留的误入库 __pycache__/run_fpga_local.cpython-311.pyc - .gitignore 忽略 orca-cli(指向 ~/.agents/skills 的外部链接) --- .gitignore | 1 + dpd-mig-flow/SKILL.md | 236 ++++++++++++++++++ .../run_fpga_local.cpython-311.pyc | Bin 18735 -> 0 bytes sim-rtl-flow/SKILL.md | 7 +- 4 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 dpd-mig-flow/SKILL.md delete mode 100644 fpga-goldenref-flow/scripts/__pycache__/run_fpga_local.cpython-311.pyc diff --git a/.gitignore b/.gitignore index c02de40..838513c 100644 --- a/.gitignore +++ b/.gitignore @@ -369,5 +369,6 @@ __pycache__/ /vercel-react-native-skills/ /vercel-react-view-transitions/ /web-design-guidelines/ +/orca-cli/ /.stfolder/ /.claude/ diff --git a/dpd-mig-flow/SKILL.md b/dpd-mig-flow/SKILL.md new file mode 100644 index 0000000..a98951d --- /dev/null +++ b/dpd-mig-flow/SKILL.md @@ -0,0 +1,236 @@ +--- +name: dpd-mig-flow +description: > + Run the dpd-mig-flow LangGraph workflow (checkout path 见 `~\skills_env.md` 的 + `DPD_MIG_FLOW_ROOT`) — the + pipeline that ports the DPD + CFR functionality (FPGA RTL + i.MX6 app) from the ATSC + reference project (SMOD_ATSC\my_exciter) into **another SMOD project**, then verifies it + on real hardware: survey the reference design, port FPGA and imx6 sides in parallel, + build the bitstream and cross-compile the app (both via the fpga-imx6-flow skill), + debug on the board with the fake-PA distortion model, and gate on two objective + measurements — DPD trains without error and settles to Hold with shoulder ≥ 40 dB, and + the shoulder survives a power cycle. It drives the graph in-process (no langgraph dev) + and hands its 6 interrupts back to this Claude session to execute. + + ALWAYS use this skill whenever the user wants to port, migrate, or transplant DPD/CFR + into another SMOD project, or wants to run/start/drive/resume/continue this workflow — + including phrasings like "移植 DPD", "把 DPD 和 CFR 移到 DAB/DVBT2 工程", "跑 dpd-mig-flow", + "启动 DPD 移植流程", "继续 DPD 移植", "resume the DPD migration", "port DPD to the DVB-T2 + exciter", "DPD 带肩不达标怎么迭代", "验证 DPD 断电保持", even when they don't name the + project path or say the word "skill". Because the target project is never fixed, this + skill always asks the user which Vivado project to port INTO before starting. +--- + +## What this skill does + +Drives the **dpd-mig-flow** graph (10 nodes / 12 flow-edges, 1:1 with +`Notes/dpd-mig-flow.drawio`; plan in `Notes/Task00.md`). Two node classes: + +- **6 interrupt nodes** pause the graph and hand control to **this Claude session**, + which does the real work (read reference RTL/C, copy and rewire code, invoke the + `fpga-imx6-flow` skill to synthesize / cross-compile / debug on the board). +- **2 measurement nodes** run in-process and decide objectively: read DPD state over + HTTP/SSH, measure shoulder with the N9320B, power-cycle the board via the COM relay. + +Persistence is a SqliteSaver file, so `start` / `resume` survive across separate process +calls, and each target project gets its own thread. + +| Item | Value | +|---|---| +| Project root | 见 `~\skills_env.md` 的 `DPD_MIG_FLOW_ROOT` | +| Conda env | `langgraph` (path 见 `~\skills_env.md` 的 `CONDA_LANGGRAPH_PYTHON`) | +| Graph | `app.main_graph:build_graph` (in-process, no langgraph dev) | +| Driver | `\run.py`(`start` / `resume` / `status` 三个子命令) | +| Checkpoint | `\runs\checkpoint.sqlite`(按 `thread_id` 分区) | +| Reference project | 见 `~\skills_env.md` 的 `SMOD_ATSC_REF`,顶层 `...\sources_1\top\smod_top.v` | +| Target project | **每次运行由用户指定**,见 Step 1 | +| Design source | `Notes/dpd-mig-flow.drawio`,方案 `Notes/Task00.md` | +| Self-test | `\smoke_test.py`(mock,68 项检查) | + +``` +PY = +PROJ = +RUN = %PROJ%\run.py +``` + +> **直接用环境里的 python.exe 跑,别用裸 `conda run`**:本机 GBK 控制台下 `conda run` 会用 +> GBK 重新编码子进程的 UTF-8 stdout,**遇到中文 interrupt payload 会崩**。用环境 +> `python.exe`,或 `conda run --no-capture-output`。 + +## ⚠️ 硬件时序铁律 + +**绝不在 USB-Blast 处于连接状态时给板卡上电或断电。** 本工作流的 `check_power_cycle` +节点会真的断电重启,其内部顺序已固定为: + +``` +断开 USB-Blast → 断电 → 等待 → 上电 → 等 app 就绪 +``` + +`power_on()` / `power_off()` 各自还会兜底确认一次 USB-Blast 已断开。断电保持判定不需要 +JTAG,所以默认**不再接回** USB-Blast(需要接回时把 `env_config.json` 的 +`power.reconnect_blast` 置 `true`)。手工介入板卡时同样遵守这条。 + +继电器 COM 号**唯一来源是 `~/vivado_mcp_usb.conf`**(`[power]` / `[usb_blast]`,逐机而异、 +不入库),与 vivado-mcp 的 `power_on`/`USB_Blast_on` 共用同一份配置;文件缺失时调 vivado-mcp +的 **`detect_serial_relays`** 工具自动探测生成。 + +## Step 0 — 确认环境(驱动前必做) + +```powershell +$py = @("$env:USERPROFILE\miniconda3\envs\langgraph\python.exe","$env:USERPROFILE\.conda\envs\langgraph\python.exe") | Where-Object { Test-Path $_ } | Select-Object -First 1 +if (-not $py) { Write-Host "[MISSING] langgraph env" } else { + & $py -c "import langgraph; from langgraph.checkpoint.sqlite import SqliteSaver; from langgraph.types import Command; print('[OK] langgraph + checkpoint-sqlite')" +} +``` + +`[OK]` → 进 Step 1。缺失/导入失败 → 告诉用户先跑 **`/langgraph-vivado-install`**,别硬上。 + +想先确认工作流本身没坏(不碰任何硬件): + +```powershell +& $py "$PROJ\smoke_test.py" # 期望 ALL PASS (68 checks) +``` + +## Step 1 — 问用户:移植到哪个工程?(这一步不能跳过) + +设计图里全程只说"当前 vivado 工程",因为**它本来就不固定**——这条流水线是为"把 ATSC 的 +DPD/CFR 搬到任意 SMOD 工程"设计的。所以目标工程**必须每次运行由用户显式给出**:没有默认值、 +不沿用上次、不从配置文件里读、不替用户猜。`run.py` 会强制校验,缺参数直接非零退出。 + +`XILINX_SMOD_ROOT`(见 `~\skills_env.md`)下的候选通常有 `SMOD_DAB`、`SMOD_DVBT2`、`SMOD_DTMB_CG`、 +`SMOD_DVBS`、`SMOD_SAT`。用 AskUserQuestion 或直接问,把这 7 项凑齐: + +| 参数 | 含义 | 怎么定 | +|---|---|---| +| `--target-vivado` | 目标 Vivado 工程目录 | 用户指定 | +| `--target-xpr` | 目标工程 `.xpr` | 在上面目录里找,找到多个就让用户选 | +| `--target-imx6` | 目标配套 imx6 工程目录 | 通常是工程下的 `imx6` | +| `--standard` | 调制标准 | DAB / DVBT2 / DTMB / DVBS / SAT | +| `--symbol-clk-mhz` | 调制核输出符号采样率时钟 | **决定 DPD/CFR 挂在哪条数据链上**,问用户或从目标顶层读出来核实 | +| `--center-hz` | 频谱测量中心频率 | 决定带肩怎么测 | +| `--ch-bw-hz` | 信道带宽 | 同上 | + +参数多,可以先写成档案文件再点名(**档案名仍须每次显式给出**,不许自动挑最新的): + +```powershell +& $py $RUN start --target-profile "$PROJ\targets\smod_dab.json" +``` + +`start` 会校验目录/`.xpr` 真实存在、目标不是参考工程(防止误改参考工程 `my_exciter`),派生 +`thread_id`(含工程指纹,不同工程绝不共用 checkpoint),并把参数落到 +`runs//launch.json` 留痕。 + +## Step 2 — 启动 + +```powershell +& $py $RUN start ` + --target-vivado "<目标工程目录>" ` + --target-xpr "<目标工程目录>\.xpr" ` + --target-imx6 "<目标工程目录>\imx6" ` + --standard DAB --symbol-clk-mhz 8.192 --center-hz 214e6 --ch-bw-hz 1.536e6 +``` + +输出一行 JSON:`{"status":"waiting","thread_id":...,"interrupts":[{"id":...,"task":...,"value":{...}}]}`。 +**记下 `thread_id`**,后面每次 resume 都要用。 + +想先空跑一遍看流程(不碰仪器/串口/板卡):设 `$env:DPD_MIG_MOCK="1"` 再 start。 + +## Step 3 — 执行 interrupt,然后 resume(主循环) + +每个 interrupt 的 `value` 里带 `action`、`instructions`(这一步的完整任务书)、`target` +(本次运行指定的目标工程,**据此决定往哪个工程写**,别靠记忆)、`expected_resume`(该回填什么)。 + +### ⚠️ 并行阶段会同时抛出 2 个 interrupt + +`study_ref` 之后图分成 FPGA 侧和 imx6 侧两条并行支路,`invoke` 会**同时**返回 2 个 +interrupt(构建阶段同理)。因此 resume **统一用 `{interrupt_id: payload}` 映射**, +单值形式会因为无法指定目标而报错卡死。可以分批恢复:只给一个 id,另一个保持挂起。 + +### resume 的正确姿势:写文件,别贴 JSON + +Windows PowerShell 5.1 会**吞掉**传给原生 exe 的双引号,直接把 JSON 贴到命令行必然变成非法 +JSON。用 `--mapping-file`(最省事,Write 出一个文件即可)或 `--mapping-b64`: + +```powershell +# resume.json 内容形如: +# { "": { "fpga_port_done": true, ... }, +# "": { "imx6_port_done": true, ... } } +& $py $RUN resume --thread-id "" --mapping-file "\resume.json" + +# 随时看卡在哪 +& $py $RUN status --thread-id "" +``` + +### 6 个 interrupt 各自要做什么 + +| action | 你要做的事 | resume 回填 | +|---|---|---| +| `survey_reference`
(#3) | 通读参考工程的 DPD/CFR 用法,产出调研 md + 待移植文件清单。重点:旁路宏 `DPDENABLE`/`CFR_ENABLE`;发射链 `digital_rms_agc → CFR_cfr_conf → dacfr → DPD`;ORx 反馈链 `120M → rx1_dec3_120to40 → orx_dec_hb_40to10 → RAM2 → orx_iq_udp_tx`;SPI3 仲裁 `spi3_agc_arbiter`;DPD 系数存取 `spi_slave_2_DPD_SL.v` | `ref_survey_md`, `ref_file_list` | +| `port_fpga`
(#4) | 复制 DPD/CFR 源码进目标工程并加入 `.xpr`;参考 `smod_top.v` 接进目标顶层;**做速率转换**(参考工程 DPD/CFR 跑 40 MHz,目标符号率不同,必须接在调制核输出的正确符号采样率链上并与后续 204b 接口时序匹配);宏旁路;**ORx AGC + SPI3 仲裁与参考工程完全一致**;**保留 fake-PA**;建独立 DPD 寄存器模块(对标 `reg_map_dpd.v`) | `fpga_port_done`, `fpga_ported_files`, `rate_conv_scheme`, `reg_map_dpd_path`, `bypass_macros`, `fake_pa_kept`, `orx_agc_ported` | +| `port_imx6`
(#5) | 整理并移植 6 项功能:①寄存器控制 ②**DPD 控制状态流程 md(含 mermaid)** ③前面板键盘+液晶 ④SPI3 仲裁 ⑤网页控制+状态显示 ⑥隐藏菜单参数。入口:`bsp/dpd_proc.c`、`bsp/eeprom.c`、`task/lcd_task.c`、`task/uart_user.c`、`adrv9009/adrv9009_config.c`、`web/www*/sys_set.html`。**顺手把 `env_config.json` 的 `board.endpoints` 按实际接口填实** | `imx6_port_done`, `imx6_ported_files`, `dpd_state_md`, `imx6_feature_md`, `imx6_features_ok`(6 项全 true 才放行) | +| `build_fpga`
(#11) | 调 **`fpga-imx6-flow` skill** 综合实现出 bitstream + flash 文件;重点看速率转换到 204b 那段时序有没有违例 | `build_fpga_ok`, `bit_path`(必须真实存在), `flash_path` | +| `build_imx6`
(#6) | 调 **`fpga-imx6-flow` skill** 交叉编译出 app | `build_imx6_ok`, `app_path` | +| `hw_debug`
(#10) | 调 **`fpga-imx6-flow` skill** 下 bit、部署 app、重启;**开 fake-PA**;网页 DPD start 训练;看 ILA/串口;用 N9320B 看 DPD 前后带肩。离开本节点前确保 fake-PA 已开、DPD 已 start、板卡与频谱仪在线——下一个节点会自动读状态+测带肩来判定 | `debug_log`, `fake_pa_on`(必须 true), `dpd_started`(必须 true), `shoulder_before_db`(可选,用于判定改善量) | + +第 2 轮起 `hw_debug` 的 payload 里会带 `previous_failure`:**先看它再动手**。带肩不达标 → +查 DPD 收敛 / ORx AGC / 速率转换;断电后带肩掉了 → 查 DPD 系数 save/load 与 eeprom 持久化。 + +### 两个判定节点(不需要你介入,除非降级) + +- `check_dpd_train`(#15):等训练收敛 → 读 DPD 状态 → 测带肩。四个条件全过才算通过: + 训练无报错、状态为 `Hold`、带肩 ≥ 40 dB、(若已知 DPD 前带肩)确有改善。否则回 `hw_debug`。 +- `check_power_cycle`(#19):测重启前带肩 → 按铁律断电重启 → 等 app 起来 → 复测 → + 变化 ≤ 1.5 dB 且仍 ≥ 40 dB 且状态仍为 Hold 才算通过。否则回 `hw_debug`。 + +**降级裁决**:仪器/板卡够不着或读数矛盾时,节点会抛 `action: "adjudicate"` 的 interrupt, +payload 的 `evidence` 里带着已采到的数据。你据此给结论:`{"pass": true/false, "reason": "..."}`。 +别为了让流程往下走而随手判 true——这两个判据就是整个任务的验收标准。 + +> 测量结果按 `(thread, iteration)` 落盘缓存(`runs//iter/verify_*.json`)。 +> interrupt-resume 会让节点从头重跑,缓存保证**一轮之内绝不会把板子断电两次**。 + +## Step 4 — 结束 + +两个判定都过 → `task_done`,`status` 变 `done`,汇总落 `runs//summary.json` +(含最终带肩、断电前后读数、bit/app 路径、产出的几份 md)。把这些回报给用户。 + +迭代超过 `max_iterations`(默认 10)会优雅报错退出——这是让人介入判断"是移植方案的问题还是 +指标定义的问题",不是让你调大上限硬撑。 + +## 真机运行前的检查清单 + +`DPD_MIG_MOCK` **不设**(或设为 0)就是真机模式。开跑前确认: + +| 项 | 怎么确认 | 缺了怎么办 | +|---|---|---| +| 继电器 COM 号 | `~/vivado_mcp_usb.conf` 有 `[power]` 和 `[usb_blast]` | 调 vivado-mcp 的 `detect_serial_relays` | +| 板卡 DPD 接口 | `env_config.json` 的 `board.endpoints`(或 `ssh_commands`)已按目标工程实际接口填实 | 还是占位模板时 `tools_board` 会**明确报错**,不会对着不存在的接口测出假结论;先完成 `port_imx6` 再来 | +| N9320B | `spectrum.host`(默认取 `~\skills_env.md` 的 `N9320B_HOST`)能 ping 通 | 检查网络/仪器电源 | +| 板卡 | `board.ip`(默认取 `~\skills_env.md` 的 `SMOD_BOARD_IP`)能通 | 先上电 | +| 频谱判据 | `center_hz` / `ch_bw_hz` 是本次目标标准的正确值 | 问用户 | + +带肩定义(DPD 前后、断电前后必须用**完全相同**的仪器设置,否则数值不可比):带内参考取 +信道内 PSD 均值,肩部取 `±(ch_bw/2 + ch_bw × shoulder_offset_ratio)` 处 PSD, +`shoulder_db = 带内 − 肩部`,取上下边带较差者。RBW/VBW/检测器/平均/参考电平/衰减全部由 +`env_config.json` 固定。 + +## 常见问题 + +| 现象 | 原因 / 处理 | +|---|---| +| `缺少必填的目标工程参数` | 按设计如此(每次必须显式指定),把 7 个参数补齐 | +| `目标工程不能是参考工程` | 防误改 `my_exciter` 的保护,检查 `--target-vivado` | +| `目标工程参数与本 thread 已记录的不一致` | 中途改了参数。换工程会自动换 thread;只是想改测量频点/带宽就用 `--tag` 开新 thread,别在半途改判据 | +| `resume 参数不是合法 JSON` 且引号丢了 | PowerShell 吞引号,改用 `--mapping-file` / `--mapping-b64` | +| `未知的 interrupt id` | id 过期了(已被恢复过)。先 `status` 拿当前 id | +| `board 接口仍是占位模板` | `port_imx6` 还没把实际网页/命令行接口填进 `env_config.json` | +| 控制台中文乱码/崩溃 | 别用裸 `conda run`,直接用环境 `python.exe` | +| 改了 `app/*.py` 后行为没变 | 无 dev server 缓存,直接重跑即可;若图结构改到与旧 checkpoint 不兼容,换 `--tag` 或删 `runs/checkpoint.sqlite` | + +## 相关 + +- **`fpga-imx6-flow`** — 综合/交叉编译/下载/上板调试都转交它(本图不嵌套调用另一张图, + 两张图各有 checkpointer 与 interrupt 语义,进程内嵌套会互相污染) +- **`smod_atsc_dev`** — SMOD 平台事实、两条烧写路径的选择、上电时序 +- **`fpga_flash`** / **`fpga_update`** — JTAG 直烧 / 远程升级 mcs +- **`langgraph-vivado-install`** — 创建 `langgraph` conda 环境 diff --git a/fpga-goldenref-flow/scripts/__pycache__/run_fpga_local.cpython-311.pyc b/fpga-goldenref-flow/scripts/__pycache__/run_fpga_local.cpython-311.pyc deleted file mode 100644 index df9663ad909f75cd9aaf926a72a0b3a3d49207f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18735 zcmdUXdvF`andb~J00vJI6iHDOA0vs92#F6_5+zx(rKLp5*2APtQnvL90&zeR6bLXg zpk#7E2lgrzSjR+M$B7YJN)WH(&}TVOwr*pcWAEBtSK_L@yP8o=m076bmG9QH{_B3-gV#W$tla%|!WzE<2Ip5G}@(XW5`VXdZRua$aDiwZ->oS1zUaS464TOn3q={a_i? z?#9KAdUA21RkRs%8J~TsOsp5}!E(_NEFa=T=OxQ2Z_&N$5_hUXbYEgltwKHz-mOwB z!(EkF4q7dGL05|vpf%zu&^2NuXsuWUx>l?PtrJ&+){8Zu4dNQmMzI!D2(A;?o~Lb> zTxhfK8k+n@uGtLBh^Bse`5GpA%naig8Xpd{4oAacFd_wqT8F~Xi^9dIbe;yJiAW?U z3I8+kf^ej#_0hiGL*4!Tf+&S9Ahx-uR|p3p!^2Wwd_)j~7X&#dA;H(?aCDI@vJe{y z3WL$H@lZG@3dfQ6A(}T^A|wR|W8q056hX$2EIc|H8;M4QaVa_&lx5*!C^jMl9OFSr z4#}}#BqsDfc03eAjU&Oq^W)J_Bo>s~gaJ}Ca3LBJ_2(_uBmt%IwD9C!M+Ejhz*Vm z;l*SD6-NW25ROL2+l2mD08Pv`8VwtiqIefM7La1?Qc#{43$_nN(V7UV4Mi?Q2LrKC zG$K3D2@gakV&fArzZjDCx3`fG<0oIiA4aBdoBXXXUcN;*ADl#Io|{CUNx^{V4~gh+ z+6m|f(&2J69L#;Ap{PXT^d4^}$;RvU2lAo5d@mM4foz`$ zV z{pdpkw-??9RX2}JjNt_WgXHVs^@Ae%%kc%7Xgz~@)`2@77v>rB<$lDz$ixuL9iw?B zmM$)lOJ?GXk*Q3Z;wA}Kzp)llJ3Z1|E>!$$cw!;1r8rM6EV9NYiY6nIn>O2-m^+u7 zVd7@de4R7q>0qY0IM>CTou0PD$_jZ$Nl(y2G{)O=@ulzkG9y~And25?{nOUCRqBab z(^T~2%I1E-mJQ+|ooD~K9OT!?6sK)*o3t@*TR|Z3#v0}FxNXqHGJ_`3PX3IoW0`(t z=4m^#d|Jf0fw_;7xr?T!%qN+PEX$k(OJ^d_EKo%YKw@8xz}vM*@Q*NN=U=22&_D0`?^ZF}Ml09|=ezVF4n_V^-0! z`@r#ov@*(f0%Jj8Bp3$oBYCp?DQTo8~$+oZ9r>ES8Hhg87 zhz+&wd7aJh!3Z7}iVRPg&&XS*YCs;u)!erAfRFqh*t?-^i|;_w7i0>3#XivE^JGj> zIb+LqMaDcFjAc0T5*cn3q9Wr6J~bYQh~NuShKr5|BN>wv%vi<<8_!sS@?c;bw}kVL zXDo6I4bC_y*OrMK%Gi4Qy9p=o@fkBXaKEa%7*sdz)i&;>k@JmBDObw1AP1y`=@6<{p}AH-~PcL-ul(zKVSOn>VN#=JKy{K z-CzFkotOUbtG5=f&Xw{4VeyrpEM87yW-s$Fu#*Rtd)8Mu%f)wpxIeRo zmOOmC_X&Sr_n{Mg{YQFx{Ktc~(`>9rERGfgU{P$L#yBh#BSQzN(lef-cg9zdh=8JuK_Yg;>n5p*Xr==bkxit0ClTqM8)#o z9*Rq;qJ!^#-TWGIyphiZMaC2>Qj-c}Cyw$WCt9wW<0Yd7_7(jzjv*4;&nz$cNs7%hq!DH2JFCQnBlgwnOK)zuNW;k(TY}{v-c93{F(AXiF zybC0bKFnNl;6gAr)TBK~I)Y2S0g_-A?C$T4rH-ne&6;QP+^QQF75f3zen7JyAYAPX z``&#Eylcjuw%@G%=%P~b1UXNhQu)&we_G*B6JB?Q)wAmKPqf&dDJ_n_dzf*(*s%L^l6fum^d^nvS3aBT4lnx!) z7t3p~3?Pm;3%%8JZ5hp&Wnx9z=qPC+JxYNKIA}^h)FfIrA_FYhzOghdbAnwk{lD7 zVI_?RVCuHE>SMMw1Osvax}0SwJRy%rLFn89ZYE@^G=4{Hb&;6J8 zrUWAPS5QG$)1D53O}OqBN{(~zyj}_;b*&oH8c{Y_OWmAzp={O6WXk(od?rq222o*(37H#pWNMTql;q3KhLv;4M8|yJS9#E3 z{=mT<^w>V|vY>{EK)4E>2>%@c;BW+kW5(EN7F>xH&0*7+c^c+S@gN?}b3KExS7MHe z-1Sn^%xnT@jGK)^aGJ9-aV||b^Bsp#a%T-8!rHROorVyeV2X3st;T1>%|kGYeYUA1 zhjh592=&l$q#Pu(0*)j!pAQDdbBI+W;%k!#AMmjmXFmmA`oTOUa(iwf6c+syP&tfy zFGZvLGK?R;KJXFgDu$?h_RQKm=+ah5$s#(^Av`DJ0p8Iz76?W3nx!rhY11*E9T^+I zjtD>yD*a%dKwBEm*t?$^42~20!DrED1gS|c$&mucNE$7ZuL&uTlLJ;ieFdo((I;`q z*FX}?C){quc+PWM6yv$zte81)ZBP2By0%?g+x}jM;yj`{k7&*#iLQCq>g2H$r@HDj zSAC*;$z-;;=Xv)P=Vj+}?iqIyf43K$m1KyotSMI~_ocfP=N8quMRRVM>r$NC6mA=3 z_wQ78dYSjVj?M=2`}HiSVU&{*PDeShqRA+aGa2opC%{(*rp*SG#$2rE8Wj-f z!MGVE_7Y@9+7&CBit!RSJnF>8vU^O=1!Cqx@M zo}b!Jga!c$bTBdo{52*6U3e;{<8>`Se!=-+^i!~|H4NM#OwizAK!Di=e8M6SdnsT$d& z2SI!mV)FyP&RF#?nX!!rCW!>eSO!NXBIh$40S-&2kj<~xFP%djqqyW55X>QO^^0}S z*QJKj7jE7^Tc>)vHE;J4!&!DwlC&&1t7e1O22|&I&AA@7uYK2iO+Cbp8yP@mx%pMA zF+;q&er`^8{mlNV{bOP0En(-40ae(m3B>C4?pml^lWI#hrP@+$H#nuTL#^!4DmxH> zg=)_|>Mok`M`-F@hFghdJZ&0grlIE+z)E6=VKD8V=8CoBI47DgOfbL;8gw>iGl0On zM1k&Y!GN(Ca{|;eub^&~aC(-R@y#5FqeYbCTc!^6QQHyN7POG)PywaIsG?s|N55nN z^IHP<$ASaUAA&6b1s(zlJ?U$E9p-2rtCo8t!bE&r#tsk(UmAlhV~GXi^T3x76Nts6 zj1~MEwfJn(S>%#9Q@3t>Rsmk}!HKYbi-`3#)2VJJWS@F?H2WZPiX? z)!v&X3@AI&L6Qd-%2%gMsfW^iYI(C(-kj{5ca>i`cKKL}eXeJwCyBo$3(0L|T;;Qs z$-N3!b>{#g<}78g0_J$BMh&glF!RsgZrVf!4u;Bo7%D}aPh^XSLy=j9ArvEOV)mfe zGWgLOd7iW)m)RaS7nGK9HpEO@;+Aw?!_L)6ens0bV{9v0_(Os!uaKW#CV!k@#w+Bv ziwxy--$;D&I(^(L@mAWLYI(Fv?q(G@AI#9`8txk?3yMC}p_F}`K#40$6f1%zdZtSD$QkG%opZ=pry`yiMs7bB9&$ z4$ZscnWKrWWYfIcOBAhPYLXALNtRkQC$Gh>PR*^m(fO{dJodQK_=MW{gx2_k;yFpq zKv3a_RDMX~hY-N|iQ7AKT5&g|4kixISJb??<@qhCZ_M?n72C9mZGb>6-Kd_>q&1tY z)VIz_YQ=V~Vmp9fJ4q)rd2qg>^2JThZ%VC6A5trtwTkBCq4_fJl?#_I%$`@v)@x-D zhOGNAyHH-GRPRZfLCCK(xAoO;>*4n}rMz1$@7Bt@5y%xDRm;|CW$Q@cZoTksQg}B` z6yEac(|Y)3OeybD%e%DlE(C5bIZ3Pj;$kcg#qosVA5=I|J6(ga>5N1=wDCTckS?2H>?LSeDOaxP-Fb$0h%75X?qT`ONT@@a1r7Z#u4ec50rT ziH8&0er;a~(Hy^Z^Kd^8I?Y0kGEa+g7uxIk~#(@!fPili1 zW{O$rFbJAu#yBvGVy%*3x`sJ`^dduNG_ORIdJwTdCko1gw9oKdiva;C%4Za+`cn0s z^YGr=V0fx+*_w($!4jAc&nbcfOF=;B-vlVi9;0Ly&|~?mYa0Lias*J75l>o2G zdrg(*Tk%~>7SMq^*y{YZf-+BBF1GvN zh$F&fLulUSYn!S9Ul`~dIMIK$IGfHPq;H|cQ>zO(vK}GL#N2#PdWNKW3#szNAaOaO zkWY`#T_oO#sFn5;LY8D;4Wc|*-$j$jye|PUDMulzS;T+FXDt%`O(b((1IU=1J zUDWINyba4gSPUMKE+gSZT=E}563pT<;@##Xn!k=!ZkiJneuv8M(D)q)Ebuj{s zj}(lKbe=Ed3nNep@<+b0Lg^w7R4BhfUh={3I9ABJe5;tzJV!ImQR7|d8fM8lR^G&l z!(uOW-@z;{n(Z-yXJwCqC#6wmFg_cgRKbp5L<^p92PkC7VT+ro*70@u__*nw^4Vi+ zb1lYqEa8(Y)=lV})*w{*~7`DU0-P#IY*jY)P~L}BMl|4HJM{=8zL)yysgrmL!SaG)8JpUWEd>NKLVzRc zdP6;Abu6>3tpCv^T`*Q4*;vW?wo=xVUjMOY>n+b#)zhkZS`!b= zx9$WtuQmIdcw^p-T<@ad(o|~KgWM=mrWTCf$CXOz0)=S4`9q9oqJE+_ijV?Ycl&|_>*9%Ag z{`d>W)$(;(`MSgrDu;H%sN=d+u1n*(5TJ3*sgsJM87F{Iu0!QIG_C^yn%0`GRUEB2 zZ=m|UDz{hTfOGAoX?uR&JhxX}ze`)cOL6SM32T$qcO)f~*==G-(x0&m2p1 zCwCH0sH*uo;cCy#EsCcbXVN_HESuR!6z$gebsJw@n>;k@R$UF$?%sK`OW`|JzEk5n z5m?|WXHTXbD!*0Zw<`SB1-@+7^23X%Np-bPTkV7672mG$?F!#snzC2rcWL}Ch2QlF z@4Di+?0C*K<4V%M+exlC0xG^te9}HV(7ER!H}iXU^+OwsD<(v8QMvjD1paU3s!;<6 z0?Zou&pk_MxV6fy#rk@w1O}977EJ}w0%utB^0Herms$eTELlXMcrmB*oPwJ~ZtaXt z+Yxky)JX_MZ#aplVTE}Fgcn+(Ok^`r+;p|A%#Y=XXc(>)`tqN24apzkk|#khgDR?D zXjdvWr~5wkw%zi!sorgxcU$7bK%Ei+s8ER?Nge)Wg&eD_#gTenz7}r{WJtuHoa9h@FCnGyoHfXoj(cL1tJI;L^(~O-7+Y zy?n9lBW?|`)3#zGOtcV1Km=Y3Va|!R>wKx%7iljR)Gi{n^C}MpBq!P-xRYG+yX^e=>lH(LEUD9 z5azR9|6+#Ex%y8zv0*^p3m`rS9RbD_Dhc}BnXY!THrB!v2iC;ya)-&vU?WQ@0vSvr}CVxY-+53I-<_s_4tCvtK5vyTErU*Bd}B}DTcKR zUan%5@eNr9JFcq5)nUh&bJ_|w!V2uCswvb8H$n@zUCp$$cuy4oouW30mh84!uK_?R z0mF5kX(;E)m#Z&4@lJ4@EOHsjRp!ezeqA|zp)Dp9^5Ko(wD~L(w<7dU&}KIj(%@jT z20jP|nE<`lG0ls$)AnNcNL(AYQ%J1tdVQ%DZOGRkeqD~nxb2>5627*kb<`taJ(dc; z?wK3DE=SzHY>uL(lAB=4If>Ia^yP9MuYNXv*3Xh1Xj<+z*NMJLPI^)pyR2 zL|wn;TM0M@pi26OY>vWS+9^k22QAsrhJDWdm^2YQ40YS8Z(r5xMZSX0UF5`_;qzja zsJl6Bzx)vV;+{GY30w$-!o-DA5=ko2n5X{c!T-nOD>kb(O#BV%JKcG_v+ohOYxH(? zKPh~A^LvX|e)ahab7WgO*_oc-r-~0USU;Oc%=O&0# z#p3sWy7+P$Tb?G);EwEMe5!ePJl5LL*5N~)-~aU8^x}7Zv-r!u)2mzj&aXdx`;9MN zxwiQBYyX~j7W_QRPLA7ZaWH4(G>?+FOp=v_)~$s*X*XV^iYLCwAABhRY2pn`##{ zyO20I&so3Q`)u#*BXfHay(+g;<8~_C&RlHI+(8oCu5s-O*Pe?#I%guW+4ZqpmAqtZbK6PYHjQgjxVBsa9IAbT zX5a924Jaw>bdg=5&+VVtPaF`-X7-RZyry~He#Ld!^_*wMlk{9OU**%@A3Lu)Q_dyM zY-yP1JCr-lobNY0A6Sb{=GVedtkF-hO`?JLC0JKkD(Qn}FWz!CD9(ljSJkZeT<=V8 zlK#Q7Y39jP%`Nvj#l3F9RXrP1U3HqP4twPEQ_oO)%e_HyZ&+{vWCIMVxf+z*xnyQM zO-Q@FNQ`FI;wcdLtIs>(H0iJadCQRn4;qld2hg!^#k1o^1>jy!b<#}i-qG0|$gPvI3g4^py&B((08Rd;G7?t!F_j= zH)wnV0){o*BzCRj{?OmIm#Xld1TEf;3G=&Z>*0FlclEBrE#}{CWeMF@`>>Vyy^GRj zLO-&W9dnpJsyevkn8o~W77K1Nyx&jvF8Fr3x+g@o*7(_ve( zR-&Ui6yJ%G+iw$ci4d}|uCt(t`Eeu(fUE;hfx5NS~Q*UWap@EU{B2);asM%5BoPO$xW^lZvX@4YQ%yb1#GxVc*RYYV{$l8oqg5T18i) zY{_b3?}zU&dw*(>{><&5Kc&P$a-hxlN$Wq$CYztSmM(8A-K+y$=&EM`~I8 zlOW8>0_CkNJmmAFf@iCjm^`U=vq9u9qJou{Eut0WZ21zCCtIpm^kbfEv$1d@%#+G; ylA0%*cygO3)!SIGhddc#8P1iQx@BIYnAgm6e4^`_! - Run the sim-rtl-flow LangGraph workflow at E:\LangGraph_Design\sim-rtl-flow — the + Run the sim-rtl-flow LangGraph workflow (checkout path 见 `~\skills_env.md` 的 + `SIM_RTL_FLOW_ROOT`) — the Simulink-to-RTL-to-hardware design pipeline: read the previous run's design version-tree doc xxx_tree.md to decide what may be reused → Simulink -x principle sim (sim-golden) → HUMAN sign-off on simulation performance → optional -q fixed-point → @@ -228,7 +229,7 @@ regenerated tree has lost last round's attributes. Default, as everywhere here, `/.sim_rtl_flow/`** — that is where `resume`/`record`/`status` will look. ```bash -cat > /c/Users/Administrator/AppData/Local/Temp/claude/input.json <<'EOF' +cat > $TMPDIR/sim_rtl_flow_input.json <<'EOF' { "requirements_path": "Notes/requirements.md", "work_dir": "E:/Xilinx_design/my_project", @@ -257,7 +258,7 @@ EOF ### 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 +"$PY" "$RUN" --thread-id my-design-001 start --input $TMPDIR/sim_rtl_flow_input.json ``` `start` takes `work_dir` from the input JSON and prints where state landed. Verified: