HDLBits Verilog编程题128-131 Lemmings系列游戏状态机

HDLBits Lemmings系列游戏状态机

  • Lemmings1
  • Lemmings2
  • Lemmings3
  • Lemmings4

为直观易于理解,状态机采用三段式写法,每个转移条件单独给出。输出需使用逻辑电路, 使用时序电路会比参考波形晚一个时钟周期。
注意:在设计状态机时需要充分考虑转换条件和优先级问题。
链接:https://hdlbits.01xz.net/wiki/Lemmings1

Lemmings1

当前进方向发生碰撞时调转方向
HDLBits Verilog编程题128-131 Lemmings系列游戏状态机_第1张图片
Lemmings1 状态转换图
此题较为简单直接根据状态及转化写代码。

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;
    parameter S0 = 1, S1 = 0;
    wire S02S1;
    wire S12S0;
    
	assign S02S1 = bump_left == 1;
    assign S12S0 = bump_right == 1;
    always @(*) begin
        // State transition logic
        case(state)
            S0:begin
                if(S02S1)
                    next_state = S1;
                else 
                    next_state = state;
            end
            S1:begin
                if(S12S0)
                    next_state = S0;
                else 
                    next_state = state;
            end
        endcase
    end

    always @(posedge clk, posedge areset) begin
        // State flip-flops with asynchronous reset
        if(areset)
            state <= S0;
        else
            state <= next_state;
    end
    
    assign walk_left = (state == S0);
    assign walk_right = (state == S1);

endmodule

Lemmings2

增加ground输入和aaah输出,当ground=0(没有地面)时,坠落aaah=1(结束游戏);当地面恢复时,回到坠落前的前进方向。
注意:左右方向转换的条件中ground=1是必要的,即只有在有地面时才可能有方向变换
HDLBits Verilog编程题128-131 Lemmings系列游戏状态机_第2张图片
Lemmings2 状态转换图

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 ); 
    
    reg [3:0] state_c, state_n;
    parameter left = 0, right = 1, leftgr = 2, rightgr = 3;
    wire left2right, right2left, leftgr2left, left2leftgr, right2rightgr, rightgr2right;
    
    always@(posedge clk or posedge areset) begin
        if(areset)
            state_c <= left;
        else 
            state_c <= state_n;
    end
    
    always@(*) begin
        case (state_c)
            left:begin
                if(left2right)
                    state_n = right;
                else if(left2leftgr)
                    state_n = leftgr;
                else 
                    state_n = state_c;
            end
            right:begin
                if(right2left)
                    state_n = left;
                else if(right2rightgr)
                    state_n = rightgr;
                else 
                    state_n = state_c;
            end
            leftgr:begin
                if(leftgr2left)
                    state_n = left;
                else 
                    state_n = state_c;
            end
            rightgr:begin
                if(rightgr2right)
                    state_n = right;
                else 
                    state_n = state_c;
            end
        endcase
    end
    assign left2right = bump_left && ground && state_c == left;
    assign left2leftgr = ground == 0 && state_c == left;
    assign right2left = bump_right && ground && state_c == right;
    assign right2rightgr = ground == 0 && state_c == right;
    assign leftgr2left = ground && state_c == leftgr;
    assign rightgr2right = ground && state_c == rightgr;
                  
    assign walk_left = state_c == left;
    assign walk_right = state_c == right;
    assign aaah = (state_c == leftgr) || (state_c == rightgr);
           

endmodule

Lemmings3

增加dig(挖掘)输入和digging(正在挖掘)输出。在行进过程中若出现挖掘条件(dig=1),则进行挖掘,直至没有地面(ground=0)坠落为止;当地面恢复(ground=1)时,回到坠落前的前进方向。
注意:优先级:fall>dig>switch direction,因此在转换时需要按优先级排列。
HDLBits Verilog编程题128-131 Lemmings系列游戏状态机_第3张图片
Lemmings3状态转换图

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 ); 
    
    reg [2:0] state_c, state_n;
    parameter left=0, right=1, dig_left=2, dig_right=3, fall_left=4, fall_right=5;
    wire left2right, left2dig_left, left2fall_left, dig_left2fall_left, fall_left2left;
    wire right2left, right2dig_right, right2fall_right, dig_right2fall_right, fall_right2right;
    
    always@(posedge clk or posedge areset) begin
        if(areset)
            state_c <= left;
        else
        	state_c <= state_n;
    end
    
    always@(*) begin
        case (state_c)
            left:begin
                if(left2fall_left)			//考虑优先级
                    state_n = fall_left;
                else if(left2dig_left)
                    state_n = dig_left;
                else if(left2right)
                    state_n = right;
                else
                    state_n = state_c;
            end
            right:begin
                if(right2fall_right)
                    state_n = fall_right;
                else if(right2dig_right)
                    state_n = dig_right;
                else if(right2left)
                    state_n = left;
                else 
                    state_n = state_c;
            end
            dig_left:begin
                if(dig_left2fall_left)
                    state_n = fall_left;
                else 
                    state_n = state_c;
            end
            dig_right:begin
                if(dig_right2fall_right)
                    state_n = fall_right;
                else 
                    state_n = state_c;
            end
            fall_left:begin
                if(fall_left2left)
                    state_n = left;
                else
                    state_n = state_c;
            end
            fall_right:begin
                if(fall_right2right)
                    state_n = right;
                else
                    state_n = state_c;
            end
            default:state_n = left;
        endcase
    end
    
    assign left2right = bump_left && ground && state_c==left;
    assign left2dig_left = dig && ground && state_c==left;
    assign left2fall_left = ground==0 && state_c==left;
    assign dig_left2fall_left = ground==0 && state_c==dig_left;
    assign fall_left2left = ground && state_c==fall_left;
    
    assign right2left = bump_right && ground && state_c==right;
    assign right2dig_right = dig && ground && state_c==right;
    assign right2fall_right = ground==0 && state_c==right;
    assign dig_right2fall_right = ground==0 && state_c==dig_right;
    assign fall_right2right = ground && state_c==fall_right;
    
    assign walk_left = state_c==left;
    assign walk_right = state_c==right;
    assign aaah = (state_c==fall_left) || (state_c==fall_right);
    assign digging = (state_c==dig_left) || (state_c==dig_right);

endmodule

Lemmings4

增加坠落计时条件,当坠落时开始计时,超过20个周期则游戏结束(所有输出变为0,只有复位时才重新开始游戏)
注意:每个状态转移条件需要较为严格的限制;根据实际参考波形,超过20个周期且重新回到地面(ground=1)时才更新状态
HDLBits Verilog编程题128-131 Lemmings系列游戏状态机_第4张图片
Lemmings4状态转换图
为方便理解,状态转移寄存器和计数寄存器分开写。其中计数cnt根据实际参考波形需要充分的位数,若范围过小可能不符合参考波形。

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 ); 

    reg [2:0] state_c, state_n;
    parameter Left=0, Right=1, Dig_l=2, Dig_r=3, Fall_l=4, Fall_r=5, Overtime=6;
    wire Left2Right, Left2Dig_l, Left2Fall_l, Dig_l2Fall_l, Fall_l2Overtime, Fall_l2Left;
    wire Right2Left, Right2Dig_r, Right2Fall_r, Dig_r2Fall_r, Fall_r2Overtime, Fall_r2Right;
    wire over;
    int cnt; //为使cnt位数充分大,定义为int型
    wire cnt_add;
    
    always@(posedge clk or posedge areset) begin
        if(areset)
            state_c <= Left;
        else 
            state_c <= state_n;
    end
    
    always@(*) begin
        case (state_c)
            Left:begin
                if(Left2Fall_l)
                    state_n = Fall_l;
                else if(Left2Dig_l)
                    state_n = Dig_l;
                else if(Left2Right)
                    state_n = Right;
                else 
                    state_n = state_c;
            end
            Right:begin
                if(Right2Fall_r)
                    state_n = Fall_r;
                else if(Right2Dig_r)
                    state_n = Dig_r;
                else if(Right2Left)
                    state_n = Left;
                else 
                    state_n = state_c;
            end    
            Dig_l:begin
                if(Dig_l2Fall_l)
                    state_n = Fall_l;
                else
                    state_n = state_c;
            end
            Dig_r:begin
                if(Dig_r2Fall_r)
                    state_n = Fall_r;
                else
                    state_n = state_c;
            end
            Fall_l:begin
                if(Fall_l2Left)
                    state_n = Left;
                else if(Fall_l2Overtime)
                    state_n = Overtime;
                else
                    state_n = state_c;
            end
            Fall_r:begin
                if(Fall_r2Right)
                    state_n = Right;
                else if(Fall_r2Overtime)
                    state_n = Overtime;
                else
                    state_n = state_c;
            end 
            Overtime:begin
                state_n = state_c;
            end
        endcase
    end
   
    assign Left2Right = bump_left && ground && state_c==Left;
    assign Left2Dig_l = dig && state_c==Left;
    assign Left2Fall_l = ground==0 && state_c==Left;
    assign Dig_l2Fall_l = ground==0 && state_c==Dig_l;
    assign Fall_l2Overtime = over && ground && state_c==Fall_l;		//在坠落状态下,地面恢复且超时游戏结束
    assign Fall_l2Left = ground && over==0 && state_c==Fall_l;		//在坠落状态下,地面恢复且计时未到时才转换到行进方向
    
    assign Right2Left = bump_right && ground && state_c==Right;
    assign Right2Dig_r = dig && state_c==Right;
    assign Right2Fall_r = ground==0 && state_c==Right;
    assign Dig_r2Fall_r = ground==0 && state_c==Dig_r;
    assign Fall_r2Overtime = over && ground && state_c==Fall_r;
    assign Fall_r2Right = ground && over==0 && state_c==Fall_r;
    
    assign walk_left = state_c==Left;
    assign walk_right = state_c==Right;
    assign aaah = (state_c==Fall_l) || (state_c==Fall_r);
    assign digging = (state_c==Dig_l) || (state_c==Dig_r);
    
    always@(posedge clk or posedge areset) begin
        if(areset)
            cnt <= 0;
        else if(cnt_add)
            cnt <= cnt+1;
        else
            cnt <= 0;
    end
    assign cnt_add = state_c==Fall_l || state_c==Fall_r; //坠落时开始计时
    assign over = (cnt > 20-1)?1:0;   //计时超过20个周期
 
endmodule

你可能感兴趣的:(Verilog)