
1. 从一段反相器代码说起为什么仿真总是跑不顺Verilog 反相器几乎是每个数字电路入门者的第一段代码逻辑简单到只有一行assign Y ~A;但真正让新手卡住的从来不是这行代码而是从写代码到看到波形的整条链路。我见过太多人把inv.v敲进编辑器后面对仿真器一脸茫然工作目录怎么切、库怎么建、testbench 怎么挂、波形为什么是红线、$stop之后为什么没反应。这些问题单独看都不难凑在一起就变成了代码没错但就是跑不通。这篇内容聚焦 Verilog 反相器从代码到仿真的完整闭环面向数字电路入门和 EDA 环境搭建场景。除了给出可复制的反相器与 testbench 代码我还会给出一份仿真器配置骨架settings.json / config.toml 风格并说明如何用 TaoToken 的统一 Key 和 API 通道把环境配置、脚本生成、报错排查这几步串起来让你一次跑通设计与仿真。适合刚接触 Verilog、正在搭 EDA 环境、或者被仿真器配置折腾过的同学。反相器本身是组合逻辑没有时钟、没有状态输出永远等于输入的取反。正因为简单它特别适合用来验证工具链是否通了——如果反相器都跑不出波形那问题一定在环境或流程而不是设计。所以我会把重点放在可跟做的步骤和排障上而不是重复语法。2. TaoToken 前置统一 Key 与 API 通道准备在动手写配置之前先把 TaoToken 这一侧准备好。它的作用是给你一个统一的 Key 和 API 入口把模型对话、代码生成、配置骨架输出这些动作收敛到一个通道里避免你在多个工具之间来回切换 Key。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个地址不加 UTM 参数。你需要做的第一件事是拿到 API Key。进入控制台创建 Key路径在 console 页面https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建时建议按用途命名比如verilog-sim方便后面区分。Key 生成后只显示一次复制到本地安全位置不要写进会提交到公开仓库的文件里。拿到 Key 之后如果你只是想先验证模型能不能正常对话、帮你补全 testbench可以直接用模型对话页面https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。如果你打算长期做 Verilog 编码、写脚本、跑 Agent 辅助排障那更适合用 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入细节和参数说明统一看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite Key 管理在 api-keys 页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。注意Key 属于凭证任何情况下都不要贴到公开的 issue、论坛或截图里。本地用环境变量承载是最省事的做法。环境变量可以这样设置Linux/macOS 下写进 shell 配置export TAOTOKEN_API_KEY你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/apiWindows PowerShell 下$env:TAOTOKEN_API_KEY你的Key $env:TAOTOKEN_BASE_URLhttps://taotoken.net/api这一步做完后面无论是让模型帮你生成仿真器配置还是排查报错都能直接复用这个通道不用每次重新找 Key。3. 可复制配置反相器代码、testbench 与仿真器骨架先把设计本体写出来。新建inv.v内容如下。注意timescale决定了时间单位和精度1ns/10ps表示一个时间单位是 1ns精度 10ps后面 testbench 里的#10就是 10ns。// inv.v // 反相器设计 timescale 1ns/10ps module inv(A, Y); input A; // 输入端口 output Y; // 输出端口 assign Y ~A; // 输入输出关系取反 endmodule如果要扩展成 8 位反相器只需要在端口声明上加位宽逻辑一行都不用改module inv8(A, Y); input [7:0] A; output [7:0] Y; assign Y ~A; endmodule接着写 testbench。测试台没有外部端口所以模块名后面不跟括号。reg用来驱动输入wire用来观察输出实例化时用命名端口连接更清晰。// testbench of inv timescale 1ns/10ps module inv_tb; reg aa; // 驱动输入 wire yy; // 观察输出 inv u_inv( .A(aa), .Y(yy) ); initial begin aa 0; #10 aa 1; #10 aa 0; #10 aa 1; #10 $stop; // 停止仿真 end endmodule代码有了接下来是仿真器配置骨架。不同仿真器配置格式不一样这里给两种常见风格你可以按自己用的工具改。settings.json 风格适合图形化仿真器或带配置文件的工具链{ simulator: { name: modelsim, workdir: ./sim, library: work, top: inv_tb, sources: [ rtl/inv.v, tb/inv_tb.v ], wave: { signals: [inv_tb.aa, inv_tb.yy], format: vcd, output: ./sim/inv.vcd }, run: { restart: true, runAll: true } } }config.toml 风格适合脚本化流程[simulator] name modelsim workdir ./sim library work top inv_tb [sources] files [rtl/inv.v, tb/inv_tb.v] [wave] signals [inv_tb.aa, inv_tb.yy] format vcd output ./sim/inv.vcd [run] restart true run_all true这两个骨架的核心字段是一致的源文件列表、顶层模块、库名、波形信号、运行动作。你把它落到自己的工程目录里改掉路径就能用。如果想让模型帮你按现有目录结构生成一份直接把目录树贴进模型对话页面让它输出对应格式即可。4. 验证请求编译、仿真与波形确认配置就绪后进入验证环节。以 ModelSim 为例流程是先把工作目录切到inv.v所在目录新建库编译源文件再挂 testbench 仿真。命令行方式更利于复现可以这样跑vlib work vlog rtl/inv.v tb/inv_tb.v vsim -c work.inv_tb -do add wave /inv_tb/aa; add wave /inv_tb/yy; run -all; quit如果你在图形界面里操作对应动作是change directory 到程序目录new library 建work点 compile 找到inv.v编译done 之后展开 work 库右键inv_tb选择 simulate。打开波形窗口把aa和yy添加进去restart然后 run、run all。预期结果很明确aa在 0 和 1 之间每 10ns 翻转一次yy始终是aa的反相。也就是说aa0时yy1aa1时yy0两条波形完全镜像。如果波形里yy一直是红色或x说明信号没被驱动或没加进波形窗口不是逻辑错误。用 TaoToken 通道做一次验证请求也很直接比如让模型检查你的 testbench 是否漏了timescale或端口连接curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet, messages: [ {role: user, content: 帮我检查这段 Verilog testbench 是否有语法或时序问题\nmodule inv_tb; reg aa; wire yy; inv u_inv(.A(aa),.Y(yy)); initial begin aa0; #10 aa1; #10 $stop; end endmodule} ] }返回内容里如果指出缺少timescale或建议补全激励就说明通道是通的你可以把这类检查固化成脚本每次改完 testbench 跑一遍。5. 本篇常见错排查反相器仿真跑不通绝大多数问题集中在下面几类按顺序排查基本能定位。第一类是timescale缺失或写错。如果 testbench 里没有timescale#10的单位就不确定波形时间轴会乱。确认两个文件都写了timescale 1ns/10ps且位置在模块之前。第二类是端口连接错位。用位置连接.A(aa), .Y(yy)时顺序必须和模块声明一致否则输入输出会接反。建议一律用命名端口连接像上面 testbench 里那样写.A(aa)、.Y(yy)可读性也更好。第三类是波形窗口没加信号。仿真跑完了但波形空白通常是没把aa、yy拖进 wave 窗口。重新 add wave 再 restart、run all。第四类是$stop和$finish混用。$stop是暂停仿真器会停在当前时刻等你继续$finish是结束。如果你希望自动退出用$finish想手动看波形用$stop。第五类是工作目录和库不对。编译报 module not found 多半是源文件没加进当前库或者 workdir 指向了错误目录。确认vlib work和vlog都在同一目录下执行。第六类是 Key 或 API 通道问题。如果模型请求返回 401先检查TAOTOKEN_API_KEY是否设置成功、有没有多余空格返回 404 则确认 base URL 是https://taotoken.net/api不要多加路径。接入相关的报错对照文档里的说明处理https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。提示把每次报错原文连同你的配置一起丢给模型比只贴一句跑不通效率高得多模型能直接定位到具体字段。6. 把闭环固化下来下一步怎么走反相器跑通之后建议把这次的配置骨架和命令存成一个可复用模板下次写与门、或门、D 触发器时直接改源文件列表和顶层模块名就行。真正省时间的不是写代码而是把编译—仿真—看波形—排错这条链路固定成脚本。如果你后面要写更复杂的组合逻辑或时序逻辑可以继续用 TaoToken 的 Coding Plan 做长期编码辅助https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。需要临时验证某个模块行为时用模型对话页面快速问https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。Key 不够用或要分项目隔离就去 api-keys 页面新建https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。我自己的习惯是每加一个新模块先让模型按现有目录生成一份配置骨架再手动核对源文件路径和顶层名最后跑一遍波形确认。这样即使模块变多环境也不会乱。反相器虽小但它是你整条 EDA 链路的第一个验证点把它跑顺了后面的设计才有稳定的落脚点。