文章目录
前言
本文主要简单介绍有关FSM(有限状态机)的相关内容,并通过讲解HDLbits上的一道题目lemmings game(旅鼠游戏)介绍Moore型有限状态机的一般解决方法并详述其思路。
一. 有限状态机(Finite State Machine)
1. 介绍
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。
以输出与状态和输入的关系有限状态机可以分为两类:
1.若输出只和状态有关而与输入无关,则称为Moore型状态机;
2.输出不仅和状态有关而且和输入有关系,则称为Mealy型状态机;
关于状态机的一个极度确切的描述是:它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机停止。
什么是状态机
2. 状态机四要素
状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果:
①现态:是指当前所处的状态。
②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
3. 举例说明
画出lemmings1的状态转换图,如下图所示,可以清晰看出状态的转换。按四要素分析,我们假定walk_left为初态,若事件bump_left=1条件满足,则执行动作迁移到walk_right,则walk_right就是我们假定的walk_left的次态,满足状态机的四要素。其他状态转换也可按此分析。
二. 题目
1. lemmings1
1)翻译:
旅鼠游戏涉及大脑相当简单的小动物。如此简单,以至于我们将使用有限状态机对其进行建模。在旅鼠的 2D 世界中,旅鼠可以处于两种状态之一:向左行走或向右行走。如果它撞到障碍物,它会改变方向。特别是,如果旅鼠在左边被撞到,它会向右走。如果它在右边撞到,它会向左走。如果它同时在两侧碰撞,它仍然会改变方向。
实现具有两个状态、两个输入和一个输出的摩尔状态机,用于模拟此行为。
2)题解:
1 . 由题目可知旅鼠可以处于两种状态,向左或者向右行走,我们定义两个parameter参数(LEFT=0,RIGHT=1)分别表示这两种状体,在定义两个reg变量用来存放当现态和次态(state,next_state)。
parameter LEFT=0, RIGHT=1;
reg state, next_state;
2.然后我们需要确定状态的逻辑变换,即确定某个状态的次态,我们可以用一个组合逻辑块。
/// This is a combinational always block
always @(*) begin
// State transition logic
if(state) next_state=bump_right?LEFT:RIGHT;//如果在右行走时碰到墙则改变方向向左
else next_state=bump_left ?RIGHT:LEFT;//如果在左行驶时碰到墙则改变方向向右
end
3.我们需要一个具有异步复位的状态触发器,我们使用一个时许逻辑块。
always @(posedge clk, posedge areset) begin
if(areset) state<=LEFT;
else state<=next_state;
end
4.输出,我们用assign语句赋值即可。
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
5.完整代码如下:
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
output walk_left,
output walk_right);
parameter LEFT=0, RIGHT=1;
reg state, next_state;
always @(*) begin
if(state) next_state=bump_right?LEFT:RIGHT;
else next_state=bump_left ?RIGHT:LEFT;
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if(areset) state<=LEFT;
else state<=next_state;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
2. lemmings2
1)翻译:
除了左右行走外,旅鼠还会倒下(大概会“aaah!”),如果地面消失在它们下面。除了左右行走和颠簸时改变方向外,当ground=0时,旅鼠会摔倒并说“aaah”!当地面重新出现(ground=1)时,旅鼠将恢复以与坠落前相同的方向行走。跌倒时被磕碰不影响行走方向,与地面消失(但尚未下落)或地面再次出现时仍下落时被磕碰,也不影响行走方向。构建一个有限状态机来模拟这种行为。
2)题解:
思路不过多赘述,过程与lemmings1一致,相当于是lemmings1的扩展,此时我们考虑到除去lemmings1的左右行走的状态之外,还需要考虑向右行走时掉下去和向左行走时掉下去的两种状态,则共有4种状态。下面直接放完整代码。
完整代码:
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
output walk_left,
output walk_right,
output aaah );
parameter LEFT=4'b0001,RIGHT=4'b0010,LEFT_FALL=4'b0100,RIGHT_FALL=4'b1000;
reg [3:0] state,next_state;
always @(*) begin
case(state)
LEFT:
if(ground) next_state <= bump_left?RIGHT:LEFT;
else next_state <= LEFT_FALL;
RIGHT:
if(ground) next_state <= bump_right?LEFT:RIGHT;
else next_state <= RIGHT_FALL;
LEFT_FALL:
if(ground) next_state <= LEFT;
else next_state <= state;
RIGHT_FALL:
if(ground) next_state <= RIGHT;
else next_state <= state;
default: next_state <= LEFT;
endcase
end
always @(posedge clk or posedge areset) begin
if(areset) state<=LEFT;
else state<=next_state;
end
assign walk_left = (state==LEFT);
assign walk_right = (state==RIGHT);
assign aaah = (state==LEFT_FALL |state==RIGHT_FALL);//只要掉落就会ahhh
endmodule
3)独热码简述:
此时对这四个状态的编码使用独热码表示,One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。如果使用二进制或格雷码来代表状态,则需要用到解码器才能得知该码代表的状态。使用独热码来代表状态的话,则不需要解码器,因为若第n个位元为1,就代表机器目前在第n个状态。在本题中没有那么严格要求,也可用十进制1,2,3,4来表示,一般写状态机时我们用独热码可能更多。
3. lemmings3
1)翻译:
除了走路和跌倒之外,旅鼠有时还可以被告知做一些有用的事情,比如挖掘(当dig=1时它开始挖掘)。如果旅鼠当前在地面上行走(ground=1且不掉落),则可以挖掘,并将继续挖掘,直到到达另一侧(ground=0)。在这一点上,由于没有地面,它会掉下来(aaah!),然后在它再次落地后继续朝着原来的方向走。与跌倒一样,挖掘时被撞到没有效果,在跌倒或没有地面时被告知要挖掘则被忽略。换句话说,行走的旅鼠可以跌倒、挖掘或改变方向。如果满足这些条件中的一个以上,则 fall 的优先级高于 dig,而 dig 的优先级高于切换方向。扩展有限状态机以模拟此行为。
2)题解:
分析题目得出对比lemmings2又多了两个状态,LEFT_DIG and RIGHT_DIG,总共六个状态,用六位独热码编码,按照lemmings2的基础上进行扩展。
完整代码:
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT = 6'b000001,
RIGHT = 6'b000010,
LEFT_FALL = 6'b000100,
RIGHT_FALL= 6'b001000,
LEFT_DIG = 6'b010000,
RIGHT_DIG = 6'b100000;
reg [5:0] state,next_state;
always @(*) begin
case(state)
LEFT:
if(ground)
next_state=dig?LEFT_DIG:(bump_left?RIGHT:LEFT);
else
next_state=LEFT_FALL;
RIGHT:
if(ground)
next_state=dig?RIGHT_DIG:(bump_right?LEFT:RIGHT);
else
next_state=RIGHT_FALL;
LEFT_FALL:
if(ground)
next_state=LEFT;
else
next_state=state;
RIGHT_FALL:
if(ground)
next_state=RIGHT;
else
next_state=state;
LEFT_DIG:
if(ground)
next_state=state;
else
next_state=LEFT_FALL;
RIGHT_DIG:
if(ground)
next_state=state;
else
next_state=RIGHT_FALL;
default:
next_state=LEFT;
endcase
end
always @(posedge clk or posedge areset) begin
if(areset) state<=LEFT;
else state<=next_state;
end
assign walk_left =(state==LEFT);
assign walk_right=(state==RIGHT);
assign aaah =(state==LEFT_FALL|state==RIGHT_FALL);
assign digging =(state==LEFT_DIG|state==RIGHT_DIG);
endmodule
4. lemmings4
1)翻译:
虽然旅鼠可以走路、跌倒和挖掘,但旅鼠并不是无懈可击的。如果旅鼠跌倒时间过长然后撞到地面,它可能会飞溅。特别是,如果旅鼠跌倒超过 20 个时钟周期然后撞到地面,它会飞溅并永远停止行走、跌倒或挖掘(所有 4 个输出都变为 0),(或直到 FSM 重置)。旅鼠在落地前可以跌落多远没有上限。旅鼠只有在撞到地面时才会飞溅;它们不会在半空中飞溅。
扩展有限状态机以模拟此行为。
2)题解:
1)分析并与lemmings3进行比较,多了一个鼠鼠会死亡的设定,但掉落超过20个时钟周期撞击到地面它会死亡,所以我们需要再多添加一个计数器来计数鼠鼠掉落的时钟数。再对lemmings3的代码进行一些小扩展即可。
计数器模块代码:
reg[8:0] count_time;
always @(posedge clk or posedge areset) begin
if(areset) count_time<=8'd0;
else
if(state==LEFT_FALL |state==RIGHT_FALL) //只要跌落就算
count_time<=count_time+8'd1;
else count_time<=8'd0;
end
2) 需要注意的是最后的输出,当鼠鼠死亡后会停止行走,挖掘,掉落,四个输出(walk_left,walk_right,aaah,digging)全部为0。故每个输出都要考虑鼠鼠是否死亡。
assign walk_left =(state!=DEATH)&(state==LEFT);
assign walk_right=(state!=DEATH)&(state==RIGHT);
assign aaah =(state!=DEATH)&(state==LEFT_FALL|state==RIGHT_FALL);
assign digging =(state!=DEATH)&(state==LEFT_DIG|state==RIGHT_DIG);
完整代码:
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT = 7'b0000001,
RIGHT = 7'b0000010,
LEFT_FALL = 7'b0000100,
RIGHT_FALL= 7'b0001000,
LEFT_DIG = 7'b0010000,
RIGHT_DIG = 7'b0100000,
DEATH = 7'b1000000;
parameter DEATH_TIME = 8'd19;
reg[6:0] state,next_state;
reg[8:0] count_time;
always @(posedge clk or posedge areset) begin
if(areset) count_time<=8'd0;
else
if(state==LEFT_FALL |state==RIGHT_FALL)
count_time<=count_time+8'd1;
else count_time<=8'd0;
end
always @(*) begin
case(state)
LEFT:
if(ground)
next_state=dig?LEFT_DIG:(bump_left?RIGHT:LEFT);
else
next_state=LEFT_FALL;
RIGHT:
if(ground)
next_state=dig?RIGHT_DIG:(bump_right?LEFT:RIGHT);
else
next_state=RIGHT_FALL;
LEFT_FALL:
if(ground)
if(count_time<=DEATH_TIME)
next_state=LEFT;
else
next_state=DEATH;
else
next_state=state;
RIGHT_FALL:
if(ground)
if(count_time<=DEATH_TIME)
next_state=RIGHT;
else
next_state=DEATH;
else
next_state=state;
LEFT_DIG:
if(ground)
next_state=state;
else
next_state=LEFT_FALL;
RIGHT_DIG:
if(ground)
next_state=state;
else
next_state=RIGHT_FALL;
DEATH:
next_state=state;
default:
next_state=LEFT;
endcase
end
always @(posedge clk or posedge areset) begin
if(areset) state<=LEFT;
else state<=next_state;
end
assign walk_left =(state!=DEATH)&(state==LEFT);
assign walk_right=(state!=DEATH)&(state==RIGHT);
assign aaah =(state!=DEATH)&(state==LEFT_FALL|state==RIGHT_FALL);
assign digging =(state!=DEATH)&(state==LEFT_DIG|state==RIGHT_DIG);
endmodule
三. 总结
其实通过这四个题目解答,我们可以观察到我们在解决这个Moore型有限状态机问题时,采用的结构,我们采用独热码进行大致结构总结,用注释进行分析。
如图所示:
module top_module(
input clk,
input areset,
input bump_left,
input bump_right,
output walk_left,
output walk_right); //
parameter //N位独热码
reg[N-1:0] state, next_state; //初态和次态
always @(*) begin // This is a combinational always block 组合逻辑
// 状态的逻辑转换 State transition logic
..........
..........
end
always @(posedge clk or posedge areset) begin // // This is a sequential always block 时序逻辑
// State flip-flops with asynchronous reset 异步复位状态触发器,本题中都是异步。
if(areset) state<=..........;//一般为题目默认的状态
else state<=next_state;
end
/* 同步复位状态触发器
always @(posedge clk) begin
if(reset) state<=..........;
else state<=next_state;
end
*/
// Output logic 输出
assign (output)=.......;
.......................
.......
endmodule
我在上期文章verilog2康威的生命游戏中,那个做法也是用的同样的有限状态机的结构,可以参考对比一下。Conway’s Game of Life
由于个人水平不足也正在学习,难免出现一些错误,望指正,若有更好的想法也可评论或者私信交流。