Yosys read_json 报错 Unexpected EOF:JSON 网表被截断的解析失败排查
更新时间:2026-11-11。长尾速查篇,属于 EDA 报错排查系列,汇总入口见 开源 EDA 报错排查导航。
write_json导出的网表经过传输、脚本拼接或手工编辑后,再用read_json读回,Yosys 只丢下一句ERROR: Unexpected EOF in JSON file.就中止。报错没有行号、没有字段名,排查该从哪里下手?本文用一份被故意截断的网表把这条 Yosys read_json 报错跑透。
首屏答案:Unexpected EOF 的意思是解析器读到文件尾时,JSON 的括号或引号仍未闭合——文件本身不完整,而不是 Yosys 不认识某个字段。本例中完整网表 counter.json 为 3401 字节,坏文件只保留了前 400 字节,read_json 在解析期直接失败、退出码 1,设计根本没有进入 Yosys 内存。修复不需要改 RTL:换回完整文件后 read_json counter.json; stat 正常列出 2 个单元,退出码 0。拿到这类报错先做文件完整性自检,再考虑重新导出。
这张漏斗对应本文的排查顺序:先确认报错发生在解析期而非综合期,再核对文件字节数与末尾结构,最后才追溯文件是在哪一步被截断的。跳过文件完整性检查、直接怀疑 Yosys 版本或 JSON 字段兼容性,是这类报错最常见的弯路。
本文要回答的问题
- 一份被截断的 Yosys JSON 网表交给
read_json,完整报错原文是什么,退出码是多少? Unexpected EOF in JSON file.具体指什么,为什么报错不给行号?- 解析失败后设计处于什么状态,会不会有半截网表残留在 Yosys 内存里?
- 不进 Yosys 怎样自检 JSON 完整性,修复后复跑要看到哪些证据才算闭环?
一、完整报错原文
实验设计是一个 4 位计数器,综合脚本 export.ys 先 read_verilog、再 synth -top counter -run coarse,最后 write_json counter.json 导出网表。复现坏文件的方式刻意简单:把合法网表的前 400 字节切出来,模拟传输中断或写了一半的场景。
yosys -s export.ys
head -c 400 counter.json > counter_truncated.json
yosys -p "read_json counter_truncated.json"read_json 启动 JSON 前端后立即失败,完整输出原样摘录如下:
-- Running command `read_json counter_truncated.json' --
1. Executing JSON frontend.
ERROR: Unexpected EOF in JSON file.
exit code: 1注意报错前的那一行 Executing JSON frontend.:它说明失败点在前端解析阶段,Yosys 还没来得及构建任何 RTLIL 对象。报错文案只有一句话、不带行号列号,这是 EOF 类错误的固有特征——解析器不是在某个字节处遇到了非法字符,而是在期待后续 token 时发现输入流已经结束,没有具体位置可报。
二、工具与版本
本次全部实验在 Docker 镜像 geek-eda:0.2 内完成,容器底层是 Debian bookworm,Yosys 版本为 0.33(git sha1 2584903a06),与运行日志头部记录一致。宿主机只负责启动容器和挂载目录,不参与综合。
版本信息要先固定,因为 JSON 前端的诊断措辞随版本演进。本文的报错原文、退出码和 stat 输出只对 0.33 这个构建负责;换到其他大版本时,应保留当次完整输出再对照,不能凭本文原文反推。另外,read_json 是纯解析命令,现象与工程是否带 testbench、是否执行过技术映射无关,任何阶段产出的 JSON 网表只要不完整都会踩到同一条报错。
三、根本原因:解析器要求结构闭合,EOF 意味着输入提前终结
JSON 是一种要求严格嵌套闭合的格式:每个 { 要有对应的 },每个 [ 要有对应的 ],字符串引号必须成对出现。Yosys 的 JSON 前端从文件头顺序读取 token,一边解析一边构建模块、端口、单元等 RTLIL 对象。完整文件以最外层的 } 收尾,解析器据此确认文档结束;截断文件在 400 字节处戛然而止,解析器仍处在某个未闭合的对象内部,下一个读取动作直接撞上文件尾,于是抛出 Unexpected EOF。
图中红色是故障支路,蓝色是解析动作,灰色是闭合判定,橙色之后的绿色支路只属于完整文件。这条机制决定了一个重要事实:解析失败是全有或全无的。JSON 前端不会保留半个模块,报错后当前设计里没有任何来自该文件的对象,不存在「半截网表混进后续综合」的情况,但脚本如果只看产出文件、不判退出码,就可能拿着空设计继续往下跑。
现实中制造截断的常见场景有三类:跨机器拷贝时网络中断或传输工具未刷盘;脚本把 write_json 的输出和日志重定向到同一个文件、写入相互覆盖;手工编辑网表时误删了结尾的括号或引号。三类场景的终点完全相同——结构不闭合,解析期 EOF。
四、排查清单:先验文件完整性,再追截断环节
图中蓝色是信息收集动作,灰色是判定点,红色支路通向截断根因,绿色支路才需要考虑字段兼容这类更少见的问题。对照这张图,落地清单如下:
- 先比字节数:导出端记下
wc -c counter.json的结果,读入端再数一次;本例 3401 字节对 400 字节,差异一眼可见。跨机器传输的文件都应做这一步。 - 用独立解析器验语法:不依赖 Yosys,直接跑
python3 -m json.tool counter_truncated.json,标准库解析器会给出Expecting value或Unterminated之类的明确结论,证实问题在文件本身。 - 查看文件末尾:
tail -c 80 counter.json看结尾是否停在匹配的最外层}上;停在半个字符串或半行中间,截断即可确认。 - 追溯写入环节:确认
write_json的输出文件没有被tee、日志重定向或二次写入污染;JSON 后端应独占输出文件,不要把进度信息拼进同一个文件。 - 不要手工截断网表:调试时想看 JSON 结构,用编辑器折叠或
python3 -m json.tool | head分页查看,不要切文件本身;write_json的产物保持原样交给read_json。 - 脚本判退出码:在
.ys流水线或 shell 脚本里,read_json失败必须让整条流程中止,避免空设计流入下游命令。
失败路径的终端记录如下,注意 JSON 前端只执行了一步就中止:
五、修复代码与复跑确认
修复不涉及任何 RTL 改动:弃用截断文件,取回完整的 counter.json,把同一个 read_json 命令指向它,并接上 stat 验证设计确实完成了加载。
# 坏路径:截断文件结构不闭合,解析期失败
yosys -p "read_json counter_truncated.json"
# 修复路径:完整网表读入后立即统计,确认对象入内存
yosys -p "read_json counter.json; stat"复跑输出显示设计被完整还原:2 个单元,分别是 1 个 $alu 和 1 个 $sdff,与计数器「加法加寄存器」的结构吻合,脚本正常结束:
$ yosys -p "read_json counter.json; stat"
Number of processes: 0
Number of cells: 2
$alu 1
$sdff 1
End of script. Logfile hash: e3b39b3862, CPU: user 0.00s system 0.00s, MEM: 7.88 MB peak
exit code: 0修复路径的终端记录如下,与失败段形成退出码 1 对 0 的闭环对照:
判定修复成立看两个证据。其一,退出码为 0 且 stat 有真实单元输出,证明 JSON 已完整解析、对象进入内存;其二,整个过程没有借助任何命令行选项绕过检查,可见性完全来自文件本身恢复完整。如果完整文件仍然报 EOF,说明截断发生在导出环节,应重新执行 write_json 并立即在本机做一次 read_json 往返验证——往返检查的完整做法见 Yosys JSON 网表回读:write_json 与 read_json 往返检查。
实验环境
- 机器/系统:macOS 宿主机启动 Docker 容器,容器内为 Debian bookworm
- 工具版本:Yosys 0.33(git sha1 2584903a060),镜像
geek-eda:0.2 - 日期:2026-11-11
- 完整命令:在实验目录执行
bash run.sh,脚本先用yosys -s export.ys导出 3401 字节的counter.json,再head -c 400制造截断文件并运行read_json(退出码 1),最后对完整文件运行read_json counter.json; stat(退出码 0),逐条打印退出码。
代码获取
完整源码与复现脚本位于公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-yosys-read-json-parse-error,含 counter.v、export.ys 与 run.sh。本地装有 Docker 并取得 geek-eda:0.2 镜像后,在该目录执行 bash run.sh 即可原样复现「导出网表、截断报错、完整文件复跑通过」三步运行。
这一篇在知识体系里的位置
本篇属于 开源 EDA 报错排查导航 的 Yosys 网表交换分支,回答「read_json 为什么连解析都过不去」。同簇的 Yosys JSON 网表回读:write_json 与 read_json 往返检查 处理文件合法前提下的字段保留与回读校验,与本文构成「先保证文件完整、再核对字段内容」的前后置关系;全系列入口见 EDA 报错排查系列。
总结
Yosys read_json 报错 Unexpected EOF in JSON file. 的本质是文件不完整:JSON 前端顺序读取 token 时在括号或引号闭合之前撞上文件尾,解析期直接失败、退出码 1,且不会有半截设计进入内存。本例中 3401 字节的合法网表被截断到 400 字节后稳定复现该报错;排查先用字节数对比、python3 -m json.tool 独立校验和末尾结构检查确认截断,再追溯传输中断、输出重定向或手工编辑环节。修复只需换回完整文件,read_json counter.json; stat 复跑列出 1 个 $alu 与 1 个 $sdff 共 2 个单元、退出码 0;让 JSON 后端独占输出文件、脚本严格判退出码,即可避免同类问题再次流入下游。