数字电路中有限状态机(FSM)的设计方法

本文调研了数字电路中有限状态机(FSM)的设计方法,并针对ASIC实现进行分析。内容涵盖FSM的不同编码风格(一段式、两段式、三段式)、状态编码方案、状态转换图的绘制工具、RTL工程师常见面试题、设计与综合优化技巧、验证方法,以及结合PCIe链路训练状态机(LTSSM)的案例分析。通过这份报告,读者将全面了解ASIC开发中FSM设计的最佳实践。

引言

有限状态机(FSM)是在数字电路中用于描述时序逻辑行为的基本模型。一个好的RTL级FSM设计应当具备以下要素:

  • 安全稳定:FSM不会进入死循环或不可预知的非法状态,综合实现后应无毛刺等不稳定现象,状态转移逻辑要完备blog.youkuaiyun.com

  • 速度满足要求:FSM的时序性能要满足设计频率要求blog.youkuaiyun.com

  • 面积效率高:FSM占用硬件资源应尽量小,满足面积约束blog.youkuaiyun.com

  • 易读易维护:FSM的代码风格清晰、易于理解,方便后续修改和扩展blog.youkuaiyun.com

下面将从FSM的编码结构、状态编码、状态图绘制、面试问题、优化技巧、验证方法和PCIe LTSSM案例等方面逐一展开讨论。

FSM设计的编码结构:一段式、两段式、三段式

在RTL中描述有限状态机有多种编码风格,最常见的是一段式、两段式和三段式。它们指的是使用几个过程(process)或always块来实现状态寄存器和组合逻辑。下面分别介绍这三种结构,并比较它们的特点、适用场景及代码示例。

一段式状态机

结构特点:将状态寄存器的更新、状态转移条件判断以及状态输出全部在一个时序过程(如一个always @(posedge clk)块)中描述blog.youkuaiyun.com。这种方式不区分“当前状态”(current state)和“下一状态”(next state),所有逻辑写在一起。

代码示例(Verilog):

verilog

// 一段式FSM示例:简单两态状态机(A<->B之间切换) parameter A = 1'b0, B = 1'b1; reg state, out; always @(posedge clk or posedge reset) begin if(reset) begin state <= B; out <= 1'b1; end else begin case(state) B: if(in) begin // stay in B state <= B; out <= 1'b1; end else begin // transition to A state <= A; out <= 1'b0; end A: if(in) begin // stay in A state <= A; out <= 1'b0; end else begin // transition to B state <= B; out <= 1'b1; end default: begin // 默认情况 state <= B; out <= 1'b1; end endcase end end

上述代码中,state既作为当前状态又存储了下一状态,out为输出。在同一个时钟过程里,根据输入in和当前state决定状态转移和输出。优点是实现简单,代码量相对少,状态和输出行为集中描述。但这种“一锅煮”的风格也有明显缺点:

  • 不利代码规范:时序逻辑和组合逻辑混在一个过程里,违背将时序部分和组合部分分离的良好风格blog.youkuaiyun.com。代码冗长且不易阅读维护blog.youkuaiyun.com

  • 不利综合优化:所有逻辑在一个块中,可能增加综合工具优化难度,给时序约束和布局布线带来挑战blog.youkuaiyun.com

  • 潜在毛刺风险:如果处理不当,输出可能在组合条件改变时瞬间出现毛刺。不过由于此风格中输出也是寄存器(如上例out在时钟沿更新),毛刺可避免。

适用场景:由于一段式FSM代码维护困难且可能导致综合问题,一般不推荐使用blog.youkuaiyun.com。只有在状态极其简单且设计人员非常谨慎时才可能考虑,否则应选用下述更规范的方法。

两段式状态机

结构特点:使用两个过程来描述FSM:一个时序过程保存状态寄存器(更新当前状态为下一状态),一个组合过程计算下一状态(以及输出逻辑)。典型实现是:一个always @(posedge clk)过程更新current_state <= next_state,另一个always @(*)过程根据current_state和输入计算next_state和输出。两段式结构会显式区分“当前状态”和“下一状态”。

代码示例(Verilog,两段式Moore状态机,输出随状态变化):

verilog

parameter A = 1'b0, B = 1'b1; reg current_state, next_state; reg out; // 时序过程:状态寄存器更新 always @(posedge clk or posedge reset) begin if(reset) current_state <= B; else current_state <= next_state; end // 组合过程:次态逻辑和输出逻辑 always @(*) begin case(current_state) B: begin // 状态转移条件判断 if(in) next_state = B; else next_state = A; // 输出逻辑(Moore型,只与状态有关) out = 1'b1; end A: begin if(in) next_state = A; else next_state = B; out = 1'b0; end default: begin // 防止综合出现latch next_state = B; out = 1'b1; end endcase end

上例中输出out是在组合逻辑中根据状态赋值的(Moore输出)。两段式FSM的优点在于:

  • 时序、组合分离:状态寄存器更新和下一状态计算分开,代码结构清晰,符合RTL编码规范blog.youkuaiyun.com。这样也更利于时序分析和约束。

  • 性能较优:由于状态寄存器将组合逻辑一分为二(输入到次态逻辑、次态逻辑到状态寄存器),缩短了组合逻辑路径,从而获得更高时序性能blog.youkuaiyun.com

  • 综合友好:大多数综合工具对这种清晰分离的描述能很好地优化映射。blog.youkuaiyun.com

缺点:两段式通常输出为组合逻辑,当外部输入在时钟边沿附近变化时,输出可能因为组合逻辑直接受输入影响而产生毛刺blog.youkuaiyun.com。例如上述Moore机输出虽然仅依赖状态,不受输入直接影响,一般无毛刺;但如果是Mealy型输出(依赖当前输入),在组合逻辑中可能出现毛刺。这种不稳定因素需要设计者注意。在时序允许情况下,可以选择将输出注册化(变为三段式结构)来彻底避免毛刺。

适用场景:两段式FSM被广泛推荐用于大多数设计blog.youkuaiyun.com。它代码简洁明了、可靠性高,兼顾性能和资源,占据主流。

注:在两段式描述中,也可以选择将输出逻辑从次态组合逻辑中再拆分出来,形成单独一个组合过程。比如上例也可以将out的赋值放到另一个always @(*)中按状态决定。这种写法本质上仍是两段式(因为输出没有寄存),但有时被误称为“三段式的第三段”blog.youkuaiyun.comblog.youkuaiyun.com。需要明确的是,这样拆分输出纯粹是代码风格上的,为了模块化输出逻辑,与真正的三段式(输出寄存)有本质区别blog.youkuaiyun.com。综合结果表明,无论输出和次态逻辑是否放在同一个组合块中,电路实现没有差别blog.youkuaiyun.com。因此,大多数情况下两段式即可满足要求,除非希望进一步寄存输出避免毛刺。

三段式状态机

结构特点:三段式FSM在两段式的基础上增加第三个时序过程,专门用于寄存输出(对于Moore型输出)或寄存需要同步的控制信号。也就是说,采用一个时序过程保存状态、一个组合过程计算下一状态、再用一个时序过程根据“下一状态”(或当前状态)来更新输出寄存器blog.youkuaiyun.com。其目的在于让输出完全由时钟同步产生,摆脱组合逻辑的不稳定性。

代码示例(Verilog,三段式FSM,对上一例改进,将输出寄存):

verilog

parameter A = 1'b0, B = 1'b1; reg current_state, next_state; reg out; // 时序过程1:状态寄存器更新(同两段式) always @(posedge clk or posedge reset) begin if(reset) current_state <= B; else current_state <= next_state; end // 组合过程:计算next_state(同两段式) always @(*) begin case(current_state) B: next_state = (in ? B : A); A: next_state = (in ? A : B); default: next_state = B; endcase end // 时序过程2:输出寄存同步(用next_state判断输出) always @(posedge clk or posedge reset) begin if(reset) out <= 1'b1; else if(next_state == B) out <= 1'b1; else out <= 1'b0; end

这里第三个always @(posedge clk)根据计算出的next_state来设置输出out寄存器的值(确保输出只有在时钟边沿变化)。这种结构彻底杜绝了组合输出的毛刺隐患blog.youkuaiyun.comblog.youkuaiyun.com。三段式FSM的优势主要在:

  • 输出稳定:所有输出信号均由寄存器驱动,不会因为输入的瞬变而在时钟间隔内产生毛刺blog.youkuaiyun.comblog.youkuaiyun.com。对时序敏感的下游逻辑更安全。

  • 设计规范:输出时序路径独立控制,更利于全局时序规划和路径分组blog.youkuaiyun.com。在FPGA/CPLD器件上通常能得到更好的布局布线效果blog.youkuaiyun.com

缺点:由于输出寄存器的加入,从输入到输出需要经过两级组合逻辑(次态逻辑 + 输出决策逻辑)再到寄存器blog.youkuaiyun.comblog.youkuaiyun.com。这样可能拉长路径时延,使某些输出相关路径时序变紧。在复杂FSM中,三段式会比两段式多耗费一些寄存器资源。此外,实现Mealy型输出时三段式需要特别小心:如果输出依赖输入且寄存在时钟边沿,那么输入变化可能无法及时反映,或需引入额外组合逻辑,增大设计复杂度blog.youkuaiyun.comblog.youkuaiyun.com

适用场景:三段式FSM在需要严格输出稳定(无毛刺)或输出需要与时钟强同步的场合下使用效果最佳。例如,对控制时序要求严格的ASIC设计中,经常采用三段式寄存输出以保证可靠性。在多数常规情况下,两段式已足够,不过三段式被视为最优推荐的编码风格之一blog.youkuaiyun.com

编码风格比较

下面表格总结了一段式、两段式、三段式FSM描述方法的比较blog.youkuaiyun.com

比较项目 一段式 FSM 两段式 FSM 三段式 FSM
推荐使用程度 ✗ 不推荐
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值