状态机一般有三种不同的写法,即一段式、两段式和三段式的状态机写法,它们在速度、面积、代码可维护性等各个方面互有优劣。特权同学希望大家不要对任何一种写法给出“一棍子打死”的定论,应该借鉴笔记4中如果…其他与案例语句的分析方式,对三种写法在不同项目应用中进行不同的分析。 下面就前面提出的SRAM控制状态机给出三种不同的写法以及它们综合出的效果,供大家学习参考。wr_req和rd_req作为输入,cmd为输出,状态、状态为状态寄存器。
在设计和实现SRAM控制状态机时,采用一段式、两段式和三段式的写法确实会有不同的优缺点。下面我将为SRAM控制状态机提供三种不同的写法,并对它们的特点进行简要分析。
一段式状态机(Sequential One-Process State Machine)
写法:所有逻辑(包括状态转移和输出逻辑)都写在同一个进程中。
特点:
优点:代码结构简单,易于理解。
缺点:当状态机变得复杂时,代码可能会变得冗长和难以维护。输出逻辑可能会依赖于多个状态条件,导致代码可读性和可测试性降低。
综合效果:面积可能较小(因为只有一个进程),但速度可能不是最优的,尤其是在状态转移和输出逻辑都很复杂的情况下。
两段式状态机(Sequential Two-Process State Machine)
写法:将状态转移逻辑和输出逻辑分开到两个不同的进程中。状态转移进程更新状态寄存器,输出逻辑进程根据当前状态产生输出。
特点:
优点:提高了代码的可读性和可维护性。输出逻辑不再依赖于多个状态条件,更容易进行测试。
缺点:需要两个进程,可能稍微增加一些面积开销。
综合效果:速度和面积之间取得了较好的平衡。
三段式状态机(Mealy State Machine 或 Sequential Three-Process State Machine)
写法:将状态转移逻辑、输入处理和输出逻辑分别放到三个不同的进程中。
特点:
优点:进一步提高了代码的可读性和可维护性。输出逻辑可以直接依赖于输入和当前状态,使得状态机能够响应更复杂的输入模式。
缺点:需要三个进程,可能增加面积开销。
综合效果:适用于复杂且需要快速响应输入变化的状态机。
一段式状态机代码如下:
reg[3;0]cstate; always @(posedge clk or negedge rst n) beginif(!rst n)begin cstate <= IDLE; cmd <= 3b111; end else case(cstate) IDLE:if(wr _req)begin cstate<= WR S1; emd <= 3'b011; end end else if(rd reg)begin cstate<=RD S1; cnd<= 3b011: end else begin cstate<=IDLE cmd<= 3bl11; end WR S1:begin cstate<=WR S2: cmd<= 3'b101: end WR S2:begin cstate<=IDLE: cmd<= 3b111: end RD S1:if(wr reg)begin cstate<=NR S2: cmd<= 3'b101; end else begin cstate<=RD S2 cnd<= 3b110; end RD S2:i桿粱读Ề(wr reg)begin cstate<=WRS1: cmd<= 3b011; end else begin cstate<=IDLE cmd<= 3'b111; end default:cstate<=IDLE; endcase end
一段式状态机RTL视图:
ResourceUsageTotal logic elements 8Combinational with no register 1Register only 0Combinational with a register 7Logic element usage by number of LUT inputs-- 4 input functions 2--3 input functions 4--2 input functions 2--1 input functions 0--0 input functions 0Logic elements by mode-- normal mode 8arithmetic mode 0qfbk mode 0register cascade mode 0--synchronous clear/load mode 0--asynchronous clear/load mode 7Total registers 7I/0 pins 7Maximum fan-out node wr _regMaximum fan- out 7Total fan -out 41Average fan – out 2.73
两段式状态机两段式状态机代码如下:
reg[3:0]cstate;reg[3:0]nstate;always @(posedge clk or negedge rst_n)if(!rst n)cstate<=IDE;else cstate<= nstate;always @(cstate or wr _req or rd req) begincase(cstate)IDLE :if(wr _req)beginnstate =WR Sl;cmd = 3'b011;encelse if(rd req)beginnstate=RD S1;cmd = 3'b011;endelse beginnstate =IDLE:cmd = 3b111;endWR_S1:beginnstate =WR S2;cmd = 3'b101;endWR_S2:beginnstate =IDLE;cmd = 3'b111;endRD_Sl:if(wr_req)beginnstate =WR S2;cmd = 3'b101;endelse beginnstate=RD S2:endcmd = 3'b110endRD_S2:if(wr _req)beginnstate =WR S;cmd = 3'b011,endelse beginnstate =IDE;cmd = 3'b111;enddefault:nstate =IDLE;endcaseend
两段式状态机RTL视图:
两段式状态机综合后资源使用报告:
Resource UsageTotal logic elements 9-- Combinational with no register 9-- Register only 9Combinational with a register 5Logic element usage by number of LUT inputs-4 input functions 2--3 input functions 4--2 input functions 2--1 input functions 1--0 input functions 0Logic elements by mode-- normal mode 9arithmetic mode 0qfbk mode 0register cascade 0modesynchronous clear/load 0modeasynchronous clear/load mode 5 Total registers 5I/0 pins 7Maximum fan - out node wr_reqMaximum fan – out 7Total fan -out 38
三段式状态机
三段式状态机代码如下
reg[3:0]cstate;reg[3:0]nstate;always @(posedge clk or negedge rst n)if(!rst n)cstate<= IDLE;else cstate<= nstate;always @(cstate or wr req or rd req) begincase(cstate)IDLE :if(wr reg)nstate = WR Sl,else if(rd req)nstate =RD_Sl,else nstate =IDLE;WR S1:nstate =WR_S2;WR_S2:nstate =ILE;RD_S1:if(wr reg)nstate=WR S2;else nstate=RDS2:RD_S2 :if(wr reg)nstate=WR S1;else nstate =IDLE:default:nstate=IDE;endcaseendalways @(posedge clk or negedge rst_n) begin3'b111;if(!rst n)cmdelsecase(nstate)IDLE :if(wr_reg)cmd <= 3'b011;endelse if(rd reg)cmd <= 3'b011;else cmd<= 3'b111;WR S1:cmd <= 3'b101;WR_S2 :cmd <= 3'b111;RD S1:if(wr_req)cmd <= 3'b101;else cmd<= 3'b110;RD S2:if(wr_reg)cd<= 3'b011;else cmd<= 3b111;default:;endcaseend
三段式状态机RTL视图:
三段式状态机综合后资源使用报告:
Resource UsageTotal logic elements 12Combinational with no register 5Register only 2Combinational with a register 5Logic element usage by number of LUr inputs--4 input functions 3--3 input functions 3--2 input functions 2--1 input functions 2--0 input functions 0Logic elements by mode--normal mode 12--arithmetic mode 0--qfbk mode 0--register cascade mode 0--synchronous clear/load mode 0--asynchronous clear/load mode 7Total registers 7I/0 pins 7Maximum fan - out node clkMaximum fan -out 7Total fan – out 46Average fan – out 2.42
从上面的三个实例来看,一段式状态机似乎是一锅端,把所有逻辑(包括输人、输出、状态)都在一个 always里解决了;这种写法看上去好像很简捷,但是往往不利于维护,也许这个实例中体现得还不那么明显,如果状态复杂一些就很容易出错了;这种写法一般不太推荐,但是在一些简单的状态机中还是可以使用的。两段式状态机是一种常用的写法,它把时序逻辑和组合逻辑划分开来,时序逻辑里进行当前状态和下一状态的切换,组合逻辑里实现各个输人、输出以及状态判断;这种写法相对容易维护,不过组合逻辑输出较易出现毛刺等常见问题。三段式状态机写法也是一种比较推荐的写法,代码容易维护,时序逻辑的输出解决了两段式写法中组合逻辑的毛刺问题;但是从资源消耗上来讲,三段式的资源消耗多一些;另外,三段式从输入到输出比一段式和两段式会延时一个时钟周期。另外有一点提醒大家注意,所谓的一段式、两段式、三段式写法不能单纯从几个always语句来区分,必须清楚它们不同的逻辑划分。
状态机转移图: