vivado: resolve install path from ~/skills_env.md instead of hardcoding D:\Xilinx

The Vivado install root differs per machine (C:\Xilinx here, D:\Xilinx on the
box these skills were written on), so every hardcoded path was already wrong
on this machine.

- new fpga_flash/scripts/vivado_env.py: resolves --vivado-dir > env var >
  VIVADO_ROOT (falling back to VIVADO_PATH) from ~/skills_env.md
- gen_mcs / program_flash / check_flash_csv: --vivado-dir now optional
- fpga_update/gen_update_mcs.py: same precedence for --vivado
- fpga_flash / smod_atsc_dev / vivado-prj-create SKILL.md: document the
  lookup instead of naming a drive letter
- skills_env template: VIVADO_ROOT/VIVADO_PATH are now blanks to fill in,
  so a new machine can't inherit a wrong default

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Myfro9
2026-07-20 07:48:04 -05:00
co-authored by Claude Opus 4.8
parent fbfa060b67
commit 88f96fa5fa
9 changed files with 138 additions and 32 deletions
+8 -8
View File
@@ -52,16 +52,18 @@ python "$USERPROFILE/.claude/skills/fpga_flash/scripts/<script>.py" [参数...]
调用 `check_flash_csv.py`,检查 `xicom_cfgmem_part_table.csv` 中是否已包含 `w25q128bv-spi-x1_x2_x4`:
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/check_flash_csv.py" \
--vivado-dir "D:/Xilinx/Vivado/2018.1"
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/check_flash_csv.py"
```
**返回值含义:**
- 退出码 `0`:器件已存在,直接进入第二步
- 退出码 `2`:已成功添加器件行,需提示用户**重启 Vivado** 后才能识别
- 退出码 `1`:CSV 未找到,询问用户提供正确的 Vivado 安装目录后重试
- 退出码 `1`:CSV 未找到,检查 `~/skills_env.md` 的 `VIVADO_ROOT` 是否指向有效的 Vivado 安装
若 Vivado 不在默认路径 `D:/Xilinx/Vivado/2018.1`,询问用户后替换 `--vivado-dir` 的值。
**Vivado 安装路径不写死在本 skill 里**:三个脚本都通过 `scripts/vivado_env.py`
按 `--vivado-dir` > 环境变量 > `~/skills_env.md` 的 `VIVADO_ROOT`(退化到 `VIVADO_PATH`)
的顺序解析。换机器只改 `~/skills_env.md`,不改 skill。仅在需要临时用另一套 Vivado
时才显式传 `--vivado-dir`。
---
@@ -88,12 +90,11 @@ python "$USERPROFILE/.claude/skills/fpga_flash/scripts/check_flash_csv.py" \
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/gen_mcs.py" \
--vivado-dir "D:/Xilinx/Vivado/2018.1" \
--bit-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_top.bit" \
--mcs-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_smod.mcs"
```
将示例路径替换为用户实际的 Vivado 安装路径、.bit 文件路径、.mcs 输出路径。
将示例路径替换为用户实际的 .bit 文件路径、.mcs 输出路径(Vivado 路径自动解析,见第一步)。
**验证成功的标志:** 输出中包含 `write_cfgmem completed successfully` 且显示 `0 Errors`。
@@ -105,7 +106,6 @@ python "$USERPROFILE/.claude/skills/fpga_flash/scripts/gen_mcs.py" \
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/program_flash.py" \
--vivado-dir "D:/Xilinx/Vivado/2018.1" \
--flash-part "w25q128bv-spi-x1_x2_x4" \
--bit-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_top.bit" \
--mcs-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_smod.mcs" \
@@ -149,7 +149,7 @@ ILA core 的 `Dropping logic core` WARNING 是正常现象(载入 loader/golde
| 现象 | 可能原因 | 解决方法 |
|------|----------|----------|
| `check_flash_csv.py` 退出码 1 | Vivado 不在默认路径 | 询问用户,更换 `--vivado-dir` 参数 |
| `check_flash_csv.py` 退出码 1 | `VIVADO_ROOT` 未配置或指错 | 修正 `~/skills_env.md` 的 `VIVADO_ROOT`;临时可传 `--vivado-dir` 覆盖 |
| Vivado 中找不到 w25q128bv | CSV 已修改但 Vivado 未重启 | 提示用户重启 Vivado 后重新执行 |
| `No hardware target` 错误 | JTAG 未连接或板卡未上电 | 检查连接后重新执行第四步 |
| DONE 灯不亮 | 启动模式跳线错误 | 检查 MODE 引脚电平,确认为 SPI 启动模式 |
+8 -4
View File
@@ -6,7 +6,8 @@ Checks whether 'w25q128bv-spi-x1_x2_x4' is present in Vivado's
xicom_cfgmem_part_table.csv. If not, appends the correct row.
Usage:
python check_flash_csv.py --vivado-dir "D:/Xilinx/Vivado/2018.1"
python check_flash_csv.py # Vivado path from ~/skills_env.md
python check_flash_csv.py --vivado-dir "<install root>" # or override it
Exit codes:
0 = device already present (no changes made)
@@ -17,6 +18,8 @@ import argparse
import os
import sys
from vivado_env import resolve_vivado_dir
DEVICE_NAME = "w25q128bv-spi-x1_x2_x4"
# Fields: NAME, MEM_DEVICE, MEM_TYPE, MEM_DENSITY, DATA_WIDTH,
# MEM_MANUFACTURER, NUM_CFG_FILES, MEM_DEVICE_ALIAS, MEM_FAMILY
@@ -29,13 +32,14 @@ def main():
)
parser.add_argument(
"--vivado-dir",
required=True,
help="Vivado install root, e.g. D:/Xilinx/Vivado/2018.1",
default=None,
help="Vivado install root; defaults to VIVADO_ROOT from ~/skills_env.md",
)
args = parser.parse_args()
csv_path = os.path.join(
args.vivado_dir, "data", "xicom", "xicom_cfgmem_part_table.csv"
resolve_vivado_dir(args.vivado_dir),
"data", "xicom", "xicom_cfgmem_part_table.csv"
)
csv_path = csv_path.replace("\\", "/")
+5 -4
View File
@@ -7,7 +7,6 @@ via -tclargs so no temporary script files are created.
Usage:
python gen_mcs.py \
--vivado-dir "D:/Xilinx/Vivado/2018.1" \
--bit-file "E:/project/RU_golden/RU_golden.runs/impl_1/RU_golden_top.bit" \
--mcs-file "E:/project/RU_golden/RU_golden.runs/impl_1/RU_golden_smod.mcs"
@@ -20,6 +19,8 @@ import os
import subprocess
import sys
from vivado_env import resolve_vivado_dir
def norm(path: str) -> str:
"""Normalize path to forward slashes (Vivado on Windows accepts both)."""
@@ -32,8 +33,8 @@ def main():
)
parser.add_argument(
"--vivado-dir",
required=True,
help="Vivado install root, e.g. D:/Xilinx/Vivado/2018.1",
default=None,
help="Vivado install root; defaults to VIVADO_ROOT from ~/skills_env.md",
)
parser.add_argument(
"--bit-file",
@@ -47,7 +48,7 @@ def main():
)
args = parser.parse_args()
vivado_dir = norm(args.vivado_dir)
vivado_dir = norm(resolve_vivado_dir(args.vivado_dir))
bit_file = norm(args.bit_file)
mcs_file = norm(args.mcs_file)
+5 -4
View File
@@ -7,7 +7,6 @@ via -tclargs so no temporary script files are created.
Usage:
python program_flash.py \
--vivado-dir "D:/Xilinx/Vivado/2018.1" \
--flash-part "w25q128bv-spi-x1_x2_x4" \
--bit-file "E:/project/impl_1/RU_golden_top.bit" \
--mcs-file "E:/project/impl_1/RU_golden_smod.mcs" \
@@ -29,6 +28,8 @@ import os
import subprocess
import sys
from vivado_env import resolve_vivado_dir
def norm(path: str) -> str:
"""Normalize path to forward slashes (Vivado on Windows accepts both)."""
@@ -41,8 +42,8 @@ def main():
)
parser.add_argument(
"--vivado-dir",
required=True,
help="Vivado install root, e.g. D:/Xilinx/Vivado/2018.1",
default=None,
help="Vivado install root; defaults to VIVADO_ROOT from ~/skills_env.md",
)
parser.add_argument(
"--flash-part",
@@ -66,7 +67,7 @@ def main():
)
args = parser.parse_args()
vivado_dir = norm(args.vivado_dir)
vivado_dir = norm(resolve_vivado_dir(args.vivado_dir))
bit_file = norm(args.bit_file)
mcs_file = norm(args.mcs_file)
ltx_file = norm(args.ltx_file) if args.ltx_file else ""
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""Resolve the machine-local Vivado install path.
The install path differs per machine (C:\\Xilinx here, D:\\Xilinx elsewhere), so it
is never hardcoded in a skill. It lives in ~/skills_env.md, which stays out of git.
Precedence: explicit --vivado-dir > OS env var > ~/skills_env.md.
"""
import os
import re
import sys
def env_lookup(key, default=None):
"""Read KEY from the OS environment, else from a `KEY = value` line in
~/skills_env.md. Trailing `# comments` are stripped."""
v = os.environ.get(key)
if v:
return v
path = os.path.join(os.path.expanduser("~"), "skills_env.md")
try:
with open(path, encoding="utf-8") as f:
for line in f:
m = re.match(rf"\s*{re.escape(key)}\s*=\s*(.+?)\s*(?:#.*)?$", line)
if m:
val = m.group(1).strip()
# Placeholders like `<未安装>` mean "not configured on this machine".
if val and not val.startswith("<"):
return val
except OSError:
pass
return default
def resolve_vivado_dir(cli_value=None):
"""Vivado install ROOT (the dir containing bin/vivado.bat)."""
if cli_value:
return cli_value
root = env_lookup("VIVADO_ROOT")
if root:
return root
exe = env_lookup("VIVADO_PATH")
if exe:
# .../<root>/bin/vivado.bat -> <root>
return os.path.dirname(os.path.dirname(exe))
sys.exit(
"Vivado path not configured. Add `VIVADO_ROOT = <install root>` to "
"~/skills_env.md, set it as an env var, or pass --vivado-dir."
)
def resolve_vivado_exe(cli_value=None):
"""Full path to bin/vivado.bat."""
if cli_value:
return cli_value
exe = env_lookup("VIVADO_PATH")
if exe:
return exe
return os.path.join(resolve_vivado_dir(), "bin", "vivado.bat")