HDLBits-Verilog题目-状态机FSM-Lemmings题目解法/答案

前两个题目较为简单,用二段式和三段式都可以。

Lemmings3加了个digging,优先级介于fall和walk之间,和fall的区别在于:
ground信号完全决定lemming会不会fall,而dig信号的作用是让它开始digging,停止digging需要ground为0

三段式FSM,代码如下:

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 WL = 0, WR = 1, FL = 2, FR = 3, DL = 4, DR = 5;
    reg [2:0] st, next_st;
    
    wire [3:0] inp_w;
    assign inp_w = {ground, dig, bump_left, bump_right};
    
    always @(*) begin
        casez(inp_w)
            4'b0???: begin  //ground为0,下个状态必fall
                case(st)
                    WL, FL, DL: next_st = FL;
                    WR, FR, DR: next_st = FR;
                    default: next_st = st;
                endcase
            end
            4'b11??: begin  //dig信号,fall时不受影响
                case(st)
                    WL, DL: next_st = DL;
                    WR, DR: next_st = DR;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    default: next_st = st;
                endcase
            end
            4'b1010: begin  //以下case中,fall变为walk,方向不受影响;digging不变
                case(st)
                    WL, WR: next_st = WR;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1001: begin
                case(st)
                    WL, WR: next_st = WL;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1011: begin
                case(st)
                    WL: next_st = WR;
                    WR: next_st = WL;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1000: begin
                case(st)
                    WL, WR, DL, DR: next_st = st;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    default: next_st = st;
                endcase
            end
        endcase
    end
    
    always @(posedge clk or posedge areset) begin
        if(areset)
            st <= WL;
        else
            st <= next_st;
    end
    
    assign walk_left = (st == WL);
    assign walk_right = (st == WR);
    assign aaah = (st == FL || st == FR);
    assign digging = (st == DL || st == DR);

endmodule

Lemmings4相较于3加了摔s的功能,fall了超过20个clk会摔s
加一个clk上升沿always语句,用于赋值计数寄存器count_fall;状态替换的always语句加一个死亡判断,别的都不用变

三段式FSM,代码如下:

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 WL = 0, WR = 1, FL = 2, FR = 3, DL = 4, DR = 5, SP = 6;
    reg [2:0] st, next_st;
    
    wire [3:0] inp_w;
    assign inp_w = {ground, dig, bump_left, bump_right};
    
    reg [4:0] count_fall;
    //reg dying;
    
    always @(*) begin
        casez(inp_w)
            4'b0???: begin  //ground为0,下个状态必fall
                case(st)
                    WL, FL, DL: next_st = FL;
                    WR, FR, DR: next_st = FR;
                    default: next_st = st;
                endcase
            end
            4'b11??: begin  //dig信号,fall时不受影响
                case(st)
                    WL, DL: next_st = DL;
                    WR, DR: next_st = DR;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    default: next_st = st;
                endcase
            end
            4'b1010: begin  //以下case中,fall变为walk,方向不受影响;digging不变
                case(st)
                    WL, WR: next_st = WR;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1001: begin
                case(st)
                    WL, WR: next_st = WL;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1011: begin
                case(st)
                    WL: next_st = WR;
                    WR: next_st = WL;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    DL, DR: next_st = st;
                    default: next_st = st;
                endcase
            end
            4'b1000: begin
                case(st)
                    WL, WR, DL, DR: next_st = st;
                    FL: next_st = WL;
                    FR: next_st = WR;
                    default: next_st = st;
                endcase
            end
        endcase
    end
    
    always @(posedge clk or posedge areset) begin
        if(areset)
            st <= WL;
        else if(count_fall == 5'd20 && next_st != FL && next_st != FR)
            st <= SP;
        else
            st <= next_st;
    end
    
    always @(posedge clk or posedge areset) begin
        if(areset) begin
            count_fall <= 'b0;
            //dying <= 'b0;
        end
        else if(st == FL || st == FR) begin
            if(count_fall != 5'd20)
            	count_fall <= count_fall + 5'b1;
        end
        else 
            count_fall <= 'b0;
    end
    
    assign walk_left = (st == SP) ? 1'b0 : (st == WL);
    assign walk_right = (st == SP) ? 1'b0 : (st == WR);
    assign aaah = (st == SP) ? 1'b0 : (st == FL || st == FR);
    assign digging = (st == SP) ? 1'b0 : (st == DL || st == DR);

endmodule

你可能感兴趣的:(Verilog学习笔记,fpga开发)