第一次接触Gowin FPGA时,最让我头疼的就是如何验证设计的正确性。作为国内主流的FPGA厂商,高云半导体提供了完整的开发工具链,但很多新手在Modelsim仿真环节还是会遇到各种问题。这篇文章将带你完整走一遍从功能仿真到时序仿真的全流程,以UART转总线参考设计为例,手把手教你避开那些我踩过的坑。
功能仿真和时序仿真是FPGA设计验证的两个关键阶段。简单来说,功能仿真就像检查电路逻辑是否正确,而时序仿真则是验证电路在实际运行时能否满足时序要求。我刚开始做FPGA时经常只做功能仿真就烧录,结果板子跑起来各种不稳定,后来才发现是时序没收敛。通过这篇文章,你将学会如何用Modelsim完成这两个关键验证步骤。
首先需要准备好仿真环境。我从高云官网下载了UART转总线参考设计(Gowin_Uart_to_Bus_RefDesign),这个设计非常适合用来学习仿真流程。解压后你会发现项目结构很清晰,包含了RTL代码、测试文件和仿真脚本。
关键文件包括:
高云很贴心地提供了现成的do.bat脚本,直接双击就能启动功能仿真。但我建议你先看看脚本内容,理解每行命令的作用,这对后续调试很有帮助。
打开do.bat,里面其实调用了Modelsim的do文件。我把关键部分拆解一下:
tcl复制# 创建work库
vlib work
vmap work work
# 编译设计文件
vlog -novopt -incr -work work "../../tb/prim_sim.v"
vlog -novopt -incr -work work "../../tb/tb_top.v"
vlog -novopt -incr -work work "../../project/src/top.v"
# 其他设计文件...
# 启动仿真
vsim -novopt work.tb_top
# 添加波形信号
add wave -group "tb_top" {sim:/tb_top/*}
# 运行仿真
run 160000000ns
这个脚本做了三件事:编译设计文件、启动仿真、添加波形。特别注意-novopt参数,它禁用了优化,虽然会降低仿真速度,但能确保信号可见性,调试时非常有用。
第一次运行时可能会遇到这些问题:
我建议在波形窗口多观察几个关键信号:时钟、复位、数据总线等。功能仿真时所有信号都应该与时钟边沿对齐,如果发现毛刺或不定态,就要检查RTL代码了。
时序仿真需要三个关键文件:
这些文件需要通过高云开发工具生成。在GW5AT IDE中完成综合和布局布线后,在project/impl/pnr目录下就能找到.vo和.sdf文件。
时序仿真的do文件与功能仿真有几个关键区别:
tcl复制# 使用时序仿真库
vlog -novopt -incr -work work "../../tb/simlib/gw2a/prim_tsim.v"
# 只编译时序网表文件
vlog -novopt -incr -work work "../../project/impl/pnr/uart_to_bus_demo.vo"
# 加载SDF延时信息
vsim -novopt -gui work.tb_top \
-sdfnoerror -sdfnowarn \
-sdftyp "tb_top/u_top=../../project/impl/pnr/uart_to_bus_demo.sdf"
特别注意-sdftyp参数,这里的路径和例化名必须完全匹配你的设计。我刚开始经常在这里出错,导致延时信息没有正确加载。
时序仿真明显比功能仿真慢,这是正常的,因为要计算实际延时。在波形窗口你会发现信号不再与时钟边沿完美对齐,这就是真实的时序行为。
几个关键观察点:
如果发现时序违规,需要回到设计阶段优化代码或调整约束。我通常会先用小规模测试案例验证时序,确认没问题后再跑完整仿真,这样效率更高。
不要一开始就跑完整设计仿真。我习惯先验证各个子模块的功能,最后再集成测试。这样做有两个好处:定位问题更快,仿真时间更短。
可以改进默认的do文件,添加这些实用功能:
tcl复制# 示例:条件编译
if {$::argc > 0} {
set mode [lindex $::argv 0]
if {$mode == "func"} {
# 功能仿真配置
} elseif {$mode == "timing"} {
# 时序仿真配置
}
}
遇到复杂问题时,这些方法很管用:
$display在测试文件中打印调试信息Modelsim的波形窗口功能很强大,多试试不同的显示格式和分组方式,能大大提高调试效率。
在实际项目中,我遇到过各种仿真问题,这里分享几个典型案例:
案例1:仿真结果与硬件不一致
现象:功能仿真通过,但烧录后板子不工作。最后发现是测试激励没有完全覆盖实际场景。解决方法是在测试文件中模拟更多真实工况,特别是异常情况。
案例2:时序仿真卡死
现象:仿真运行极慢甚至卡住。检查发现是时钟频率设置过高导致。适当降低仿真时钟频率或减少仿真时长可以解决。
案例3:SDF文件未生效
现象:时序仿真波形看起来和功能仿真一样。仔细检查后发现是例化路径写错了。确保-sdftyp参数中的路径与设计层次完全匹配。
仿真过程中遇到问题很正常,关键是要有系统的排查方法:先确认环境配置,再检查脚本参数,最后分析设计本身。养成保存仿真日志的习惯也很重要,出错时能快速定位问题源头。