前面刷完了基础的moore与mealy状态机,从这开始刷的状态机稍微复杂了一点,在基础的状态机中加入了计数器的成分。本文章分次更新。
一、Q3a:FSM
这题的话,是在moore状态机的基础上加入了一个时钟计数器和数据计数器。不过这个状态机还是比较简单,因为计数器只影响了输出结果,并没有参与状态转移过程。首先来看题:
考虑具有输入s和w的有限状态机,假设FSM从称为A的复位状态开始,如下所示。只要s = 0,FSM就保持在状态A,当s = 1时,它进入状态B。一旦进入状态B,FSM将在接下来的三个时钟周期内检查输入w的值。如果在其中两个时钟周期w = 1,则FSM必须在下一个时钟周期将输出z设置为1。否则z必须为0。FSM在接下来的三个时钟周期继续检查w,依此类推。下面的时序图说明了不同w值所需的z值。
使用尽可能少的状态。请注意,s输入仅用于状态A,因此只需考虑w输入。
状态机部分自然不用说,关键在于两个计数器对输出z的影响。计数器设计的三个核心要义:复位值与开始值,加一条件,开始/结束条件。
可以看到,两个计数器存在两个周期
复位值与开始值:时钟计数器和数据计数器的复位值都为0;时钟计数器的开始值为0,数据计数器开始值为0或1(因为数据计数器开始值需要根据上一clk判断初值);
加一条件:时钟为clk上升沿,w_cnt为clk上升沿且w==1
结束条件:时钟为clk_cnt=2,数据为clk_cnt=0;
所以代码如下:
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
//0.状态空间定义
parameter A=2'b01; parameter B=2'b10;
reg [1:0]state;
reg [1:0]next_state;
//1.判断次态组合逻辑
always @(*) begin
if (reset) next_state=A;
else begin
case (state)
A: next_state=s?B:A;
B: next_state=B;
default: next_state=next_state;
endcase
end
end
//2.状态转移时序逻辑
always @(posedge clk ) begin
if (reset) state<=A;
else state<=next_state;
end
//3.状态执行动作
//状态B时钟计数
reg [1:0] clk_cnt;
always @(posedge clk ) begin
if (reset) clk_cnt<=0;
else begin
case (state)
A: clk_cnt<=0;
B: if(clk_cnt<2) clk_cnt<=clk_cnt+1; else clk_cnt<=0;
default: clk_cnt<=clk_cnt;
endcase
end
end
//数据计数器
//开始,结束,和加一受到clk_cnt限制
reg [1:0] w_cnt;
always @(posedge clk ) begin
if(reset) w_cnt<=0;
else begin
case (clk_cnt)
0: if(w==1) w_cnt<=1; else w_cnt<=0;
1: if(w==1) w_cnt<=w_cnt+1; else w_cnt<=w_cnt;
2: if(w==1) w_cnt<=w_cnt+1; else w_cnt<=w_cnt;
default: w_cnt<=w_cnt;
endcase
end
end
//组合逻辑输出
assign z=(clk_cnt==0&&w_cnt==2&&state==B);
endmodule