Verilog 写状态机总是乱套,有没有一套「模板」?

开放3 回答 96 浏览

刚开始用 Verilog 写状态机,老师讲的是「三段式」写法,但我自己写的时候要么状态跳转有漏项,要么综合后波形跟预期完全不一样。尤其是带计数器、握手信号(ready/valid)的时候,很容易写出「看着能运行,实际一堆隐含锁存器和时序违例」的代码。想请教:在实际 FPGA 工程里,大家写状态机会遵循什么固定模板?比如状态枚举、状态转移、输出逻辑分别怎么组织?有没有一些典型示例可以照着改,比如「串口接收」「简单总线握手」「数据包解析」这几类场景?

分享:

3 个回答

  • 码电路的小王

    先说个可能不太中听的话:你写状态机乱,八成不是三段式没背熟,而是「状态还没想清楚就开始敲 always」。三段式本身只是个落地格式,它治不了设计上的糊涂。真正在工程里管用的是「一图一表一模板」:先在纸上画状态转移图,再列一张输入/输出条件表,最后才套模板写代码。图里每个箭头都要标清楚「从哪个状态、在什么条件下、跳到哪个状态、输出什么」,画不出来就说明你还没想明白,这时候写 RTL 一定是边写边猜,综合出来自然和预期对不上。

    模板本身其实很朴素。时序 always 块只干一件事:把 next_state 寄存成 cur_state,需要寄存的输出也放这里。组合 always 块里 case (cur_state),把当前状态下所有可能的输入组合都覆盖到,default 分支必须给出明确赋值——这是隐含锁存器最常见的来源,只要有一条路径没赋值,综合工具就给你推断出 latch。输出逻辑尽量只和状态有关,减少对输入的直接组合依赖,这样波形干净、时序也好收敛。编码上推荐 enum 加独立的 next_state 变量,别硬编码二进制,仿真时波形里直接显示状态名,调试效率差好几倍。

    关于计数器,我的建议是把它当成状态机的一个附属寄存器单独维护,不要塞进状态编码里。比如「计数到 N 就跳转」,计数器的清零和使能条件跟着状态走,而跳转判断放在组合逻辑里读计数值。握手信号 ready/valid 更是这样:先想清楚谁拉高 valid、谁拉高 ready、什么条件下保持、什么条件下撤销,写成一句话再映射到状态,千万别在 RTL 里一边敲一边想,那样十有八九会写出 valid 和 ready 互相死等、或者 valid 撤销太早丢数据的 bug。

    练习路径上,我建议你先老老实实实现三个模板并跑仿真:计数器完成进下一状态的计数型状态机、带 ready/valid 的两段握手、串口接收(空闲→起始位→数据位→校验→停止位)。重点不是写出来,而是在 testbench 里刻意制造边界情况——突发停止、输入抖动、握手中途撤销——看你的状态机是不是还能正确回到空闲。练到这几类场景你能不假思索地写对,模板才算真的长在手上。你现在是卡在状态划分本身,还是组合逻辑漏赋值导致的锁存器告警?这两个方向的排查顺序不太一样。

    最后提醒一句:综合后的波形和预期不符,先看综合日志里的 latch 和 width mismatch 告警,再看是不是状态编码被工具重新优化了。很多时候问题不在逻辑,而在你没意识到自己写了个「组合环」。

  • 码电路的阿明

    其实先别急着背模板,你打开综合日志看看有没有 latch 推断的 warning,十有八九问题都在那儿。状态跳转漏项基本都是 case 没写全加 default 没兜底,先把这两个补上再说别的。

  • 单片机爱好者

    个人感觉最值得先固化下来的习惯,是把「状态」和「输出」在脑子里分成两层。状态只回答一个问题:我现在处在哪个阶段;输出只回答另一个问题:处在这个阶段时,各个信号该是什么值。你把这两件事混在一起写,就会出现「看着能跑但波形诡异」的情况——因为输出的组合路径偷偷依赖了输入,综合出来一堆毛刺和锁存器。

    落到写法上,用枚举定义状态、单独声明 cur_state 和 next_state,时序块只管寄存,组合块里 case 覆盖全部状态加 default。输出如果能只跟状态走就别掺输入,像串口接收里的波特率计数、简单握手里的 valid 拉高,都可以挂在状态上。ready/valid 这种握手,先在纸上写清楚谁先动、什么时候撤销,再翻译成状态跳转,比在 RTL 里现想省事得多。建议你先照着串口接收这个例子改,跑通仿真再谈别的。用的什么仿真工具,波形里状态是显示名字还是二进制?

登录后可在本页底部提交回答

提问者

电子技术萌新查看主页
浏览「其他」

描述场景与已尝试方案,更容易获得有效解答

相关问题

同分类

提问建议

  • 标题写清核心疑问,避免「求助」「请问」等空泛用语
  • 正文补充环境、版本、报错信息或截图
  • 先搜索本站是否已有相近问题,减少重复提问
  • 若与课程相关,请标明课时或章节便于讲师定位