Verilog编程技巧01——如何编写三段式状态机

news2025/6/7 11:51:50

前言

Verilog编程技巧系列文章将聚焦于介绍Verilog的各种编程范式或者说技巧,编程技巧和编程规范有部分重合,但并非完全一样。规范更注重编码的格式,像变量命名、缩进、注释风格等,而编程技巧则更偏重更直观易读、更便于维护、综合效果更好的Verilog/SV代码写法,像:如何编写状态机、如何进行参数化设计、如何进行流水线设计等。可以说编程技巧就是一些编程套路,熟练掌握这些技巧可帮助我们更高效的完成FPGA开发工作。

本文是Verilog编程技巧系列的第一篇文章,介绍了如何编写三段式状态机。

在FPGA设计中,三段式状态机因其结构清晰、可靠性高等特点,成为实现状态机的最佳方式。本文主要说明了以下问题:

  1. 如何评价一个状态机写的好不好;
  2. 为什么三段式状态机更好;
  3. 为什么更推荐独热码;
  4. 第三段输出逻辑应该怎么写。

最后,本文分享了Verilog与SV的三段式状态机模板。通过阅读本文,你将能够更深入的理解三段式状态机的写法及其背后的原理。

本文主要参考了Clifford E. Cummings的文章,他是数字电路设计领域的技术先驱,享有一定国际声誉。他的文章可从此网站(界面如下图)下载:http://www.sunburst-design.com/papers/。他的一些关于状态机的文章给本文的一些结论提供了理论和实验支撑。

一. 什么是状态机

状态机是描述系统行为的数学模型。包含状态(系统某时刻状况)、转移(状态间切换)、事件(触发转移因素)和动作(转移时执行的操作),用于分析和设计系统逻辑,在多领域广泛应用。

依据状态数量,状态机可分为两类:

特征有限状态机(FSM)无限状态机(ISM)
全称与简称Finite State Machine,简称FSMInfinite State Machine,简称ISM
状态数量有限无限
转移方式离散、明确条件可能连续(如基于变量变化)
典型应用离散逻辑控制连续系统或复杂动态系统

在HDL编码时,我们构建的总是有限状态机,所以这里我们说的状态机默认是指有限状态机

依据输出与当前状态的关系,状态机也可分为两类:

状态机类型输出决定因素特点描述
Moore型(摩尔型)仅取决于当前状态任意时刻,只要状态确定,输出就确定,输出与输入无关
Mealy型(米利型)取决于当前状态和输入信号输出不仅和当前状态有关,还受当前输入的影响

这两种状态机的命名均来源于人名,看着比较奇怪。

实际应用中,无需刻意去区分状态机属于哪种类型,没有什么意义。

在Verilog/SV编码中,状态机应用极其广泛,它几乎可以描述所有逻辑,也就是说如果你想,所有的模块的内部逻辑都可以写成状态机。所以,研究如何编写更好的状态机很有必要。

二. 一段、二段、三段与四段式状态机

在Verilog/SV中,状态机按功能可以分为三个部分:

  1. 状态转移:负责在不同的状态之间进行切换,它决定了状态机如何从当前状态迁移到下一个状态。
  2. 状态判断:根据当前状态和输入信号来确定下一个状态是什么。
  3. 输出逻辑:根据当前状态机的状态来产生相应的输出信号。

根据这三部分在代码中用几个always块来描述,可将状态机分为以下几种:

2.1 一段式状态机

状态转移、状态判断与输出逻辑全都写在同一个always块中,称为一段式状态机。示例如下:

// 状态定义
localparam S0 = 1'b0, S1 = 1'b1;
reg state;

// 状态转移、判断与输出
always @(posedge clk) begin
  if (~rstn) {state, out} <= {S0, 1'b0};
  else
    case (state)
      S0: if (in) state <= S1; else state <= S0; out <= 1'b0;
      S1: if (in) {state, out} <= {S0, 1'b1}; else state <= S0;
      default: {state, out} <= {S0, 1'b0};
    endcase
end

出于排版的考虑,去掉了非必要的begin-end,尽量缩短了代码行数,下同。

2.2 二段式状态机

状态转移写在一个时序always块中状态判断与输出写在一个组合always块中,称为二段式状态机。示例如下:

// 状态定义
localparam S0 = 1'b0, S1 = 1'b1;
reg state, next;

// 第一段:时序逻辑,状态转移
always @(posedge clk) begin
  if (~rstn) state <= S0;
  else state <= next;
end

// 第二段:组合逻辑,次态和输出逻辑
always @(*) begin
  case (state)
    S0: if (in) {next, out} = {S1, 1'b0}; else {next, out} = {S0, 1'b0};
    S1: if (in) {next, out} = {S0, 1'b1}; else {next, out} = {S0, 1'b0};
    default: {next, out} = {S0, 1'b0};
  endcase
end

2.3 三段式状态机

状态转移写在一个时序always块中状态判断写在一个组合always块中输出写在一个时序或组合always块中,称为三段式状态机。示例如下:

// 状态定义
localparam S0 = 1'b0, S1 = 1'b1;
reg state, next;

// 第一段:时序逻辑,状态转移
always @(posedge clk) begin
  if (~rstn) state <= S0;
  else state <= next;
end

// 第二段:组合逻辑,计算次态
always @(*) begin
  case (state)
    S0: next = in ? S1 : S0;
    S1: next = in ? S0 : S0;
    default: next = S0;
  endcase
end

// 第三段:时序逻辑,输出逻辑
always @(posedge clk) begin
  if (~rstn) out_a <= 1'b0;
  else out_a <= (state == S1 && in) ? 1'b1 : 1'b0;
end

// 第三段:组合逻辑,输出逻辑
always @(*) begin
  out_b = (state == S1 && in) ? 1'b1 : 1'b0;
end

对于第三段,因为时序逻辑的输出相对组合逻辑会慢一个时钟周期,如果对输出延时有极高的要求,则可以考虑用组合逻辑。但通常还是建议用时序逻辑,时序逻辑的输出更加稳定(无竞争和冒险),也更便于整体的时序分析和约束。

2.4 四段式状态机

四段式状态机是将三段式状态机的输出写成两个always块,一个固定为组合always块,写输出使能逻辑;另一个固定为时序always块,写输出逻辑。示例如下:

// 前面与三段式相同,仅第三段输出逻辑并分为两段
// 组合逻辑,输出使能
always @(*) begin
  out_en = (state == S1 && in);
end

// 时序逻辑,输出逻辑
always @(posedge clk) begin
  if (~rstn)
    out <= 1'b0;
  else if (out_en) 
    out <= 1'b1;
  else 
    out <= 1'b0;
end

从实现的功能上来说,三段式和四段式完全相同,但在设计理念灵活性可维护性等方面,两者存在明显区别:

对比维度三段式状态机四段式状态机
核心思想输出与状态/输入直接耦合,无中间控制信号。引入输出使能信号(out_en),分离输出条件与赋值逻辑。
代码结构输出逻辑与状态转移混合在时序逻辑中。输出使能(组合逻辑)与输出赋值(时序逻辑)分离,模块化更清晰。
输出条件修改需直接修改时序逻辑中的条件判断,可能影响其他逻辑。只需修改组合逻辑中的out_en,输出赋值逻辑保持不变。
扩展性新增输出条件需修改时序逻辑,可能导致冗余。新增条件只需扩展out_en逻辑,不影响输出赋值部分。
适用场景简单场景(如固定序列检测、单一输出控制)。复杂场景(如多条件输出、动态使能控制)。

总的来说,四段式状态机在负责场景有一些代码维护上的优势。

根据2019 CummingsSNUG2019SV_FSM 状态机设计.pdf中的内容,四段式状态机在复杂逻辑的综合中会有一定优势,但三段式代码更加简洁,更符合直观逻辑,所以在FPGA开发中,作者推荐总是优先使用三段式,仅在复杂场景开发的最后,将三段式改为四段式,以提升综合效果。

综合效果:指的是综合工具对不同代码写法的优化支持程度。现代综合工具对四段式会有更好的优化效果,使得四段式在资源效率和时序性能方面通常优于三段式,但具体效果还需实测。

综上,针对FPGA开发,本文仅讨论三段式状态机,如需针对复杂场景进行优化,各位同学可根据需要将三段式改为四段式,并实际比较综合后的资源效率和时序性能确定最终方案。

三. 什么样的状态机是好的状态机?

换句话说,评价一个状态机好坏的标准是什么?一般来说,可以从以下4个维度进行评价:

  1. 可维护性:代码易于修改、扩展,适应需求变更。

  2. 可读性:代码结构清晰、逻辑紧凑,避免冗余,便于阅读理解。

  3. 可调试性:支持高效的仿真验证,便于在仿真或实测时快速定位问题。

  4. 综合效果:对综合工具友好,代码在转化为硬件时的面积、速度与功耗等性能指标优异。

上述四种状态机从这四个维度进行评价,表格如下:

指标一段式二段式三段式四段式
可维护性★★★★★★★★★
可读性★★★★★★★★
可调试性★★★★★★★★
综合效果★★★★★★★★★

说明:

  1. 一颗星(★)表示“差”,两颗星(★★)表示“良”,三颗星(★★★)表示“优” 。
  2. 四段式的综合效果在非常复杂场景可能略好于三段式,但绝大多数场景下,三段式的综合效果同样优异,两者区别不大,所以两者都标注为三颗星。

对于一个功能需求来说,最重要的两件事是开发效率模块性能。可维护性、可读性和可调试性影响开发效率,综合效果则影响模块性能。

综上,我们可以得出结论:

  1. 永远不应该用一段式状态机:一段式状态机逻辑不清,导致代码难以维护、调试和扩展,极易成为"屎山代码"的一部分。其唯一优势(综合效果高)完全无法抵消后期维护的灾难性代价。即使在非常简单的场景中,也不应该使用。
  2. 不推荐用二段式状态机:二段式虽然分离了部分逻辑,但输出仍依赖组合逻辑,存在 输出毛刺风险时序收敛困难,且可调试性和综合效果低于三段式,没有独特的应用场景优势。
  3. 不推荐直接用四段式状态机:四段式虽然逻辑分层更彻底,但会导致 代码冗余开发效率下降。它仅适用于极少数复杂场景(例如多路独立输出需严格时序控制),对大多数设计属于"过度设计"。
  4. 仅推荐使用三段式状态机:三段式是经过验证的最佳实践,没有短板。

四. 状态编码的类型和优缺点

状态编码指的是状态机的不同状态用怎样的二进制去表示,状态编码一般有以下几种类型:

  1. 二进制码(Binary):用二进制自然序列表示状态,N个状态需满足 2^N ≥ S(S为状态总数)。8个状态编码为 000, 001, 010, 011, 100, 101, 110, 111
  2. 格雷码(Gray Code):相邻状态仅有一位不同,形成循环单步跳变。3位格雷码为 000, 001, 011, 010, 110, 111, 101, 100
  3. 独热码(One-Hot):每个状态独占一个比特位,总位数等于状态数(N = S)。3个状态编码为 100, 010, 001
  4. 零空闲独热码(Zero-Idle One-Hot):独热码基础上引入全零( 000...)作为空闲状态,其他状态为单一高位。5个状态编码为 0000(空闲态), 1000, 0100, 0010, 0001
  5. 独冷码(One-Cold):与独热码相反,每个状态由唯一一个低电平位(0)表示,其他位为1。3个状态编码为 011, 101, 110
  6. 约翰逊码(Johnson Code):也称为扭环码(Twisted Ring Code),是一种特殊的环形移位码,相邻状态通过左移或右移,然后补移出位的反码生成,最终形成一个环。3位右移约翰逊码为 000, 100, 110, 111, 011, 001(循环)。
  7. 混合编码(Hybrid Encoding):高位独热码 + 低位二进制码。状态数>20时,平衡资源与性能。

在FPGA设计中,零空闲独热码、独冷码与独热码的资源消耗和实现逻辑高度相似,而约翰逊码和混合编码的实际应用场景较为局限。因此,工程中的核心选择通常集中在以下三种编码:二进制码、格雷码和独热码。这三种编码方式的优缺点对比如下表:

指标二进制码(Binary)格雷码(Gray Code)独热码(One-Hot)
时序逻辑资源消耗
(触发器,FF)
★★★★☆
极低:仅需 ⌈log2(N)⌉ 个触发器(N为状态数)
★★★☆☆
:触发器数与二进制相同,但需额外触发器存储转换码(可选)
★★☆☆☆
:需 N 个触发器,但FPGA中触发器资源充足
组合逻辑资源消耗
(LUT)
★★☆☆☆
中高:状态跳变需复杂组合逻辑(如状态译码器)
★★★☆☆
:需异或门实现码值转换
★★★★☆
极低:状态跳变仅需单比特操作
时序性能★★☆☆☆
:多比特翻转限制频率
★★★☆☆
中高:单比特跳变,但转换逻辑增加延迟
★★★★★
最优:单比特跳变,路径最短,适合高频
功耗★★☆☆☆
:多比特翻转动态功耗大
★★★★☆
:单比特翻转降低功耗
★★★☆☆
:静态功耗略高(触发器多),动态功耗低
容错性★☆☆☆☆
:非法状态多,需额外检测
★★★☆☆
:非法状态较少
★★★★☆
:非法状态极易检测(非单比特为1)
可读性★★★☆☆
:自然顺序易理解,跳变逻辑复杂
★★☆☆☆
中低:编码非自然排列,需查表辅助
★★★★★
极优:每个状态对应唯一比特,仿真直观
推荐优先级★★☆☆☆
- 资源敏感型设计
- 简单状态机
★★★☆☆
- 低功耗/跨时钟域
- 异步FIFO
★★★★★
- FPGA高频设计
- 状态数≤16

星级说明:

  • ★★★★★: 强烈推荐(显著优势,无替代方案)
  • ★★★★☆: 推荐(优势明显,适用场景明确)
  • ★★★☆☆: 一般推荐(需权衡利弊)
  • ★★☆☆☆: 不推荐(仅限特定场景)
  • ★☆☆☆☆: 避免使用(缺陷明显)

由此可以得出结论

  1. 二进制码(★★☆☆☆)
    • 仅限极简设计(如ASIC或低成本FPGA),需承担时序和功耗风险。
    • 添加输出寄存器过滤毛刺。
  2. 格雷码(★★★☆☆)
    • 低功耗/跨时钟域专用,如异步FIFO指针同步,但需手动添加转换逻辑。
    • 避免在复杂状态机中滥用。
  3. 独热码(★★★★★)
    • FPGA设计首选,因LUT资源占用低、时序性能最优、容错性高,完美适配FPGA架构。
    • 仅需注意状态数≤16(超过时可混合编码)。

所以,在FPGA中进行状态机设计时,总是应该使用独热码

五. 第三段输出应该用组合逻辑还是时序逻辑?

指标组合逻辑输出时序逻辑输出
优点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402858.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智启未来:当知识库遇见莫奈的调色盘——API工作流重构企业服务美学

目录 引言 一、初识蓝耘元生代MaaS平台 1.1 平台架构 1.2 平台的优势 1.3 应用场景 二、手把手教你如何在蓝耘进行注册 &#xff08;1&#xff09;输入手机号&#xff0c;将验证码正确填入即可快速完成注册 &#xff08;2&#xff09;进入下面的页面表示已经成功注册&…

如何在 Windows 11 中永久更改默认浏览器:阻止 Edge 占据主导地位

在 Windows 11 中更改默认浏览器对于新手或技术不太熟练的用户来说可能会令人沮丧。 为什么要在 Windows 11 中更改默认浏览器? 这是一个重要的问题:你为什么要从 Microsoft Edge 切换过来? 生态系统集成:如果你已经在广泛使用 Google 服务,Chrome 可以提供无缝集成。同…

量子比特实现方式

经典计算机是通过电子电路运转起来的。使用硅制半导体制成的名为晶体管的小元件发挥了开关的作用&#xff0c;将其与金属布线组合起来即可实现逻辑门&#xff0c;再将逻辑门集成起来就能制造出经典计算机。量子计算机的制造过程则要复杂许多&#xff0c;因为量子计算机既需要量…

智慧水务发展迅猛:从物联网架构到AIoT系统的跨越式升级

AI大模型引领智慧水务迈入新纪元 2025年5月25日&#xff0c;水利部自主研发的“水利标准AI大模型”正式发布&#xff0c;它标志着水务行业智能化进程的重大突破。该模型集成1800余项水利标准、500余项法规及海量科研数据&#xff0c;支持立项、编制、审查等全流程智能管理&…

Java高级 | 【实验五】Spring boot+mybatis操作数据库

隶书文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 系列文章&#xff1a;Java高级 | 【实验一】Springboot安装及测试 |最新-CSDN博客 Java高级 | 【实验二】Springboot 控制器类相关注解知识-CSDN博客 Java高级 | 【实验三】Springboot 静…

在MATLAB中使用自定义的ROS2消息

简明结论&#xff1a; 无论ROS2节点和MATLAB运行在哪&#xff0c;MATLAB本机都必须拥有自定义消息源码并本地用ros2genmsg生成&#xff0c;才能在Simulink里订阅这些消息。只要你想让MATLAB或Simulink能识别自定义消息&#xff0c;必须把消息包源码(.msg等)拷到本机指定目录&a…

【MATLAB去噪算法】基于ICEEMDAN联合小波阈值去噪算法

ICEEMDAN联合小波阈值去噪算法相关文献 &#xff08;注&#xff1a;目前相关论文较少&#xff0c;应用该套代码可发直接一些水刊&#xff09; 一、CEEMDAN的局限性 模式残留噪声问题&#xff1a;原始CEEMDAN在计算每个IMF时直接对噪声扰动的信号进行模态分解并平均。 后果&a…

XXTEA,XTEA与TEA

TEA、XTEA和XXTEA都是分组加密算法&#xff0c;它们在设计、安全性、性能等方面存在显著区别。以下是它们的主要区别&#xff1a; 密钥长度 TEA&#xff1a;使用128位密钥。 XTEA&#xff1a;通常使用128位或256位密钥。 XXTEA&#xff1a;密钥长度更灵活&#xff0c;可以使用任…

机器人玩转之---嵌入式开发板基础知识到实战选型指南(包含ORIN、RDK X5、Raspberry pi、RK系列等)

1. 基础知识讲解 1.1 什么是嵌入式开发板&#xff1f; 嵌入式开发板是一种专门设计用于嵌入式系统开发的硬件平台&#xff0c;它集成了微处理器、内存、存储、输入输出接口等核心组件于单块印刷电路板上。与传统的PC不同&#xff0c;嵌入式开发板具有体积小、功耗低、成本适中…

腾讯云国际版和国内版账户通用吗?一样吗?为什么?

在当今全球化的数字化时代&#xff0c;云计算服务成为众多企业和个人拓展业务、存储数据的重要选择。腾讯云作为国内领先的云服务提供商&#xff0c;其国际版和国内版备受关注。那么&#xff0c;腾讯云国际版和国内版账户是否通用&#xff1f;它们究竟一样吗&#xff1f;背后又…

OrCAD X Capture CIS设计小诀窍系列第二季--03.如何在Capture中输出带有目录和元器件信息的PDF

背景介绍&#xff1a;我们在进行原理图设计时&#xff0c;经常需要输出PDF来查看或评审&#xff0c;但通过”Print”功能导出的PDF较为简单&#xff0c;只能查看设计视图&#xff1b;而通过使用Ghostscript软件可以输出带有目录和元器件信息的PDF&#xff0c;让设计师可以直接在…

汽车的安全性能测试:试验台铁地板的重要性

汽车的安全性能测试是非常重要的&#xff0c;其中试验台铁地板的设计和材料选择起着至关重要的作用。试验台铁地板是指在进行汽车碰撞、侧翻等试验时&#xff0c;用于支撑汽车底部和提供稳定支撑的重要部件。 在进行汽车碰撞试验时&#xff0c;试验台铁地板的设计和材料需要具…

实践指南:从零开始搭建RAG驱动的智能问答系统

LLM 赋能的最强大的应用之一是复杂的问答 (Q&A) 聊天机器人。这些是可以回答关于特定来源信息问题的应用程序。这些应用程序使用一种称为检索增强生成的技术&#xff0c;或 RAG。本文将展示如何基于 LangChain 构建一个简单的基于非结构化数据文本数据源的问答应用程序。 温…

边缘计算服务器

边缘计算服务器的核心要点解析&#xff0c;综合技术架构、应用场景与部署方案&#xff1a; 一、核心定义与技术特性‌ 本质定位‌ 部署在网络边缘侧的专用计算设备&#xff08;如工厂车间、智慧路灯等&#xff09;&#xff0c;直接处理终端设备&#xff08;传感器、摄像头等…

第R9周:阿尔茨海默病诊断(优化特征选择版)

文章目录 1. 导入数据2. 数据处理2.1 患病占比2.2 相关性分析2.3 年龄与患病探究 3. 特征选择4. 构建数据集4.1 数据集划分与标准化4.2 构建加载 5. 构建模型6. 模型训练6.1 构建训练函数6.2 构建测试函数6.3 设置超参数 7. 模型训练8. 模型评估8.1 结果图 8.2 混淆矩阵9. 总结…

电动螺丝刀-多实体拆图建模案例

多实体建模要注意下面两点&#xff1a; 多实体建模的合并结果一定要谨慎在实际工作中多实体建模是一个非常好的思路&#xff0c;先做产品的整体设计&#xff0c;再将个体零件导出去做局部细节设计 电动螺丝刀模型动图展示 爆炸视图动图展示 案例素材点击此处获取 建模步骤 1. …

当丰收季遇上超导磁测量:粮食产业的科技新征程

麦浪藏光阴&#xff0c;心田种丰年&#xff01;又到了一年中最令人心潮澎湃的粮食丰收季。金色的麦浪随风翻滚&#xff0c;沉甸甸的稻穗谦逊地低垂着&#xff0c;处处洋溢着丰收的喜悦。粮食产业&#xff0c;无疑是国家发展的根基与命脉&#xff0c;是民生稳定的压舱石。在现代…

电子电气架构 --- 什么是功能架构?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

AudioRelay 0.27.5 手机充当电脑音响

—————【下 载 地 址】——————— 【​本章下载一】&#xff1a;https://pan.xunlei.com/s/VOS4MvfPxrnfS2Zu_YS4egykA1?pwdi2we# 【​本章下载二】&#xff1a;https://pan.xunlei.com/s/VOS4MvfPxrnfS2Zu_YS4egykA1?pwdi2we# 【百款黑科技】&#xff1a;https://uc…

NVIDIA Dynamo:数据中心规模的分布式推理服务框架深度解析

NVIDIA Dynamo&#xff1a;数据中心规模的分布式推理服务框架深度解析 摘要 NVIDIA Dynamo是一个革命性的高吞吐量、低延迟推理框架&#xff0c;专为在多节点分布式环境中服务生成式AI和推理模型而设计。本文将深入分析Dynamo的架构设计、核心特性、代码实现以及实际应用示例&…