FPGA基础——旅鼠游戏(FSM)

FSM(Finite State Machine)

分为2大类:

第一类,若输出只和状态有关而与输入无关,则称为Moore状态机

第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

Mealy状态机,常采用一段式写法,只用了一个always语句,所有的状态转移,判断状态转移条件,数据输出都在一个always语句里,缺点是如果状态太多,会使整段程序显的冗长。

Moore状态机,常采用三段式的写法,状态转移用了一个always语句,判断状态转移条件是组合逻辑always @(*),采用了一个always语句,数据输出也是单独的 always语句,这样写起来比较直观清晰,状态很多时也不会显得繁琐。


1. 旅鼠游戏介绍

  在《旅鼠》这款游戏中,小动物的大脑相当简单。简单到我们要用一个有限状态机来建立模型。在《旅鼠》的2D世界中,旅鼠可能会处于两种状态之一:向左走或向右走。如果碰到障碍物,它会改变方向。特别是,如果一只旅鼠被撞到左边,它就会向右走。如果它在右边被撞到,它就会向左走。如果它同时在两边碰撞,它仍然会改变方向。

                                                    

 

 

  实现一个Moore状态机,它有两个状态、两个输入和一个输出来模拟这种行为。

 

 1 module top_module (
 2     input clk,
 3     input areset,    //异步复位
 4     input bump_left,  
 5     input bump_right,
 6     output walk_left,
 7     output walk_right
 8 );
 9 
10     
11 // 状态参数设置,常见:二进制码、格雷码、独热码、BCD码 12 parameter WL=0, WR=1; 13 reg state;  //当前状态 14 reg next;   //下个状态  15 16 17 // Combinational always block for state transition logic. Given the current state and inputs, 18 // what should be next state be? 19 // Combinational always block: Use blocking assignments. 20 always@(*) begin 21 case (state) 22 WL: next = bump_left ? WR : WL; 23 WR: next = bump_right ? WL : WR; 24 endcase 25 end 26 27 28 // Combinational always block for state transition logic. Given the current state and inputs, 29 // what should be next state be? 30 // Combinational always block: Use blocking assignments. 31 always @(posedge clk, posedge areset) begin 32 if (areset) state <= WL; 33 else state <= next; 34 end 35 36 37 // 输出组合逻辑。 38 // In more complex circuits, a combinational always block may be more suitable. 39 assign walk_left = (state==WL); 40 assign walk_right = (state==WR); 41 42 43 endmodule

 2.旅鼠游戏补充

除了左右行走,旅鼠还会在地面消失时摔倒(可能会发出“啊!”的声音)。除了左右行走和颠簸时改变方向外,当地面=0时,旅鼠还会摔倒并说“啊!”当地面重新出现(地面=1)时,旅鼠会继续沿著坠落前的方向行走。摔倒时被撞不会影响行走方向,在地面消失(但还没有摔倒)的同一周期内被撞,或摔倒时地面重新出现,也不会影响行走危难。

 

 

除了行走和跌倒,有时候还会让旅鼠做一些有用的事情,比如挖(当挖=1时它就开始挖了)。如果旅鼠正在地面上行走(地面=1并且没有掉下来),它可以继续挖掘,直到它到达另一边(地面=0)。在这一点上,因为没有地面,它会掉下来(啊!),然后在它再次撞击地面时继续朝原来的方向走。就像摔倒一样,在挖的时候被撞到是没有影响的,在摔倒或没有地面的时候被告知挖也被忽略了。

 

 

 

 

虽然旅鼠可以走路、摔倒和挖洞,但旅鼠并非无懈可击。如果旅鼠跌倒的时间过长就会撞到地面,它可能会GG。特别是,如果旅鼠跌倒超过20个时钟周期,然后击中地面,它将GG和停止行走,掉落,或挖掘(所有4个输出变成0),永远(或直到FSM重置)。旅鼠在落地前坠落的距离没有上限。旅鼠只有在撞击地面时才会GG;它们不会在半空中GG。

                                                    

 

 

 1 module top_module(
 2     input clk,
 3     input areset,    // Freshly brainwashed Lemmings walk left.
 4     input bump_left,
 5     input bump_right,
 6     input ground,
 7     input dig,
 8     output walk_left,
 9     output walk_right,
10     output aaah,
11     output digging ); 
12     parameter LEFT = 4'd0, RIGHT = 4'd1, FALL_L = 4'd2, FALL_R = 4'd3;
13     parameter DIG_L = 4'd4, DIG_R = 4'd5, DYING = 4'd6, SPLAT = 4'd7; 
14     reg    [3:0]    current_state;
15     reg [3:0]    next_state;
16     reg cnt_start;
17     reg [4:0]cnt_fall;
18     
19     always@(posedge clk or posedge areset)begin
20         if(areset)begin
21             current_state <= LEFT;
22         end
23         else begin
24             current_state <= next_state;
25         end
26     end
27     
28     always@(*)begin
29         case(current_state)
30             LEFT:begin
31                 next_state = ground ? (dig ? DIG_L : (bump_left ? RIGHT : LEFT)) : FALL_L;
32             end
33             RIGHT:begin
34                 next_state = ground ? (dig ? DIG_R : (bump_right ? LEFT : RIGHT)) : FALL_R;
35             end
36             FALL_L:begin
37                 next_state = ground ? LEFT : ((cnt_fall==5'd20)?DYING:FALL_L);
38             end
39             FALL_R:begin
40                 next_state = ground ? RIGHT : ((cnt_fall==5'd20)?DYING:FALL_R);
41             end
42             DIG_L:begin
43                 next_state = ground ? DIG_L : FALL_L;
44             end
45             DIG_R:begin
46                 next_state = ground ? DIG_R : FALL_R;
47             end
48             DYING:begin
49                 next_state = ground ? SPLAT : DYING;
50             end
51             SPLAT:begin
52                 next_state = SPLAT;
53             end
54             default:begin
55                 next_state = LEFT;
56             end
57         endcase
58     end    
59     
60     always@(posedge clk or posedge areset)begin
61         if(areset)
62             cnt_fall <= 0;
63         else if(cnt_start) 
64             cnt_fall <= cnt_fall+1'b1;
65         else
66             cnt_fall <= 0;
67     end
68 
69     assign cnt_start = (next_state==FALL_L) || (next_state==FALL_R);
70     
71     assign walk_left = (current_state == LEFT);
72     assign walk_right = (current_state == RIGHT);
73     assign digging = (current_state == DIG_L || current_state == DIG_R);
74     assign aaah = (current_state == FALL_L || current_state == FALL_R || current_state == DYING);
75 
76 endmodule

 

posted on 2021-03-25 20:50  一曲挽歌  阅读(364)  评论(0编辑  收藏  举报

导航