HDLbits day10

5.10Lemmings1

在旅鼠的 2D 世界中,旅鼠可以处于以下两种状态之一:向左行走或向右行走。如果遇到障碍物,它会切换方向。特别是,如果 Lemming 撞到左边,它会向右走。如果它撞到右边,它会向左走。如果它同时在两侧碰撞,它仍然会切换方向。

实现一个具有两个状态、两个输入和一个输出的摩尔状态机来模拟这种行为。

module top_module(
    input clk,
    input areset,    // 刚洗脑的袋鼠向左走.
    input bump_left,
    input bump_right,
    output walk_left,
    output walk_right); 
    
    reg state, next_state;
    parameter LEFT=0,RIGHT=1;

    always @(*) begin
        // State transition logic
        case(state)
            LEFT:next_state<=(bump_left==1)?RIGHT:LEFT;
            RIGHT:next_state<=(bump_right==1)?LEFT:RIGHT;
        endcase
    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

5.11、Lemmings2

除了左右走动和碰撞时改变方向外,当ground=0时,旅鼠会摔倒并说“啊啊!”。当地面重新出现 ( ground=1 ) 时,旅鼠将继续沿与坠落前相同的方向行走。跌倒时被撞不影响行走方向,与地面消失(但尚未跌倒)同一个周期被撞,或仍在跌倒时再次出现地面时,也不影响行走方向。

构建一个模拟这种行为的有限状态机。

1)在1的基础上多了坠落状态,且在掉落时方向与碰撞无关;

2)因为要记录掉落前的方向所以分为fl,fr(向左掉落,向右掉落)两个状态。

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=0,RIGHT=1,FALL_L=2,FALL_R=3;
    reg [1:0] state,next_state;
    
    always@(*)
        begin
            case(state)
            LEFT:begin
                if(ground==0)
                    next_state<=FALL_L;
                else if(bump_left)
                    next_state<=RIGHT;
                else
                    next_state<=LEFT;
            end
            RIGHT:begin
                if(ground==0)
                    next_state<=FALL_R;
                else if(bump_right)
                    next_state<=LEFT;
                else
                    next_state<=RIGHT;
            end
            FALL_L:next_state<=(ground==0)?FALL_L:LEFT;
            FALL_R:next_state<=(ground==0)?FALL_R:RIGHT;
            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=(ground==0);错误
    assign aaah=(state==FALL_L|state==FALL_R);

endmodule

5.12、Lemmings3

除了走路和摔倒之外,旅鼠有时会被告知做一些有用的事情,比如挖掘(当dig=1时它开始挖掘)。如果旅鼠当前在地面上行走(ground=1并且没有下落),它可以挖掘,并且会继续挖掘直到它到达另一边(ground=0)。到那时,由于没有地面,它会掉下来(啊啊!),然后一旦再次撞到地面,就继续沿原来的方向行走。与坠落一样,挖掘时被撞到没有效果,并且在坠落或没有地面时被告知要挖掘被忽略。

(换句话说,行走的旅鼠可以跌倒、挖掘或切换方向。如果满足这些条件中的一个以上,则跌倒的优先级高于 dig,而 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=0,RIGHT=1,FALL_L=2,FALL_R=3,DIG_L=4,DIG_R=5;
    reg [2:0] state,next_state;
    
    always@(*)
        begin
            case(state)
                LEFT:next_state<=ground?(dig?DIG_L:(bump_left?RIGHT:LEFT)):FALL_L;
                RIGHT:next_state<=ground?(dig?DIG_R:(bump_right?LEFT:RIGHT)):FALL_R;
                FALL_L:next_state<=ground?LEFT:FALL_L;
                FALL_R:next_state<=ground?RIGHT:FALL_R;
                DIG_L:next_state<=ground?DIG_L:FALL_L;
                DIG_R:next_state<=ground?DIG_R:FALL_R;
            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==FALL_L|state==FALL_R);
    assign digging=(state==DIG_L|state==DIG_R);

endmodule

5.13、Lemmings4

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

扩展您的有限状态机来模拟这种行为。

跌倒20个周期是可以生存的,跌倒 21 个周期会导致飞溅。

 

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=0,RIGHT=1,FALL_L=2,FALL_R=3,DIG_L=4,DIG_R=5,SPLAT=6;
    reg [2:0] state,next_state;
    integer count;
    
    //下一个状态
    always@(*)
        begin
            case(state)
                LEFT:next_state<=ground?(dig?DIG_L:(bump_left?RIGHT:LEFT)):FALL_L;
                RIGHT:next_state<=ground?(dig?DIG_R:(bump_right?LEFT:RIGHT)):FALL_R;
                FALL_L:next_state<=ground?(count>19?SPLAT:LEFT):FALL_L;
                FALL_R:next_state<=ground?(count>19?SPLAT:RIGHT):FALL_R;
                DIG_L:next_state<=ground?DIG_L:FALL_L;
                DIG_R:next_state<=ground?DIG_R:FALL_R;
                SPLAT:next_state<=SPLAT;
            endcase
        end
   
    //状态交换
    always@(posedge clk or posedge areset)
        begin
            if(areset)
                state<=LEFT;
            else
                state<=next_state;
        end
    
    //计数器
    always@(posedge clk or posedge areset)
        begin
            if(areset)
                count<=0;
            else if(state==FALL_L|state==FALL_R)
                count<=count+1;
            else
                count<=0;
        end
    
    assign walk_left=(state==LEFT);
    assign walk_right=(state==RIGHT);
    assign aaah=(state==FALL_L|state==FALL_R);
    assign digging=(state==DIG_L|state==DIG_R);
    
     /*always @(*)
        case(state)
            LEFT : {walk_left,walk_right,aaah,digging} = 4'b1000;
            RIGHT : {walk_left,walk_right,aaah,digging} = 4'b0100;
            FALL_L : {walk_left,walk_right,aaah,digging} = 4'b0010;
            FALL_R : {walk_left,walk_right,aaah,digging} = 4'b0010;
            DIG_L : {walk_left,walk_right,aaah,digging} = 4'b0001;
            DIG_R : {walk_left,walk_right,aaah,digging} = 4'b0001;
            SPLAT: {walk_left,walk_right,aaah,digging} = 4'b0000;  
        endcase 
        */

endmodule

5.14、Fsm onehot

给定以下具有 1 个输入和 2 个输出的状态机:

Fsmonehot.png

假设此状态机使用 one-hot 编码,其中state[0]state[9]分别对应于状态 S0 到 S9。除非另有说明,否则输出为零。

实现状态机的状态转换逻辑输出逻辑部分(但不是状态触发器)。您在state[9:0]中获得当前状态,并且必须生成next_state[9:0]和两个输出。假设 one-hot 编码,通过检查推导逻辑方程。(测试台将使用非一个热输入进行测试,以确保您不会尝试做更复杂的事情)。

module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);
    
    parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5,s6=6,s7=7,s8=8,s9=9;
    
    assign next_state[s0] = ~in & (state[s0]|state[s1]|state[s2]|state[s3]|state[s4]|state[s7]|state[s8]|state[9]);
    assign next_state[s1] =  in & (state[s0]|state[s8]|state[s9]);
    assign next_state[s2] =  in & state[s1];
    assign next_state[s3] =  in & state[s2];
    assign next_state[s4] =  in & state[s3];
    assign next_state[s5] =  in & state[s4];
    assign next_state[s6] =  in & state[s5];
    assign next_state[s7] =  in & (state[s6]|state[s7]);
    assign next_state[s8] = ~in & state[s5];
    assign next_state[s9] = ~in & state[s6];
    
    assign out1=(state[s8]==1|state[s9]==1);
    assign out2=(state[s7]==1|state[s9]==1);
    
endmodule

5.15、Fsm ps2

PS/2 鼠标协议发送三个字节长的消息。然而,在连续的字节流中,消息的开始和结束位置并不明显。唯一的指示是每个三字节消息的第一个字节总是有bit[3]=1(但其他两个字节的bit[3]可能是1或0,具体取决于数据)。

我们想要一个有限状态机,当给定输入字节流时,它将搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到一个带有bit[3]=1的字节。然后我们假设这是消息的第 1 个字节,并在收到所有 3 个字节后发出消息的接收信号(完成)。

FSM 应该在成功接收到每个消息的第三个字节后立即在循环中 发出完成信号。

检测一个3字节序列,该3字节格式中,第一个字节的bit[3]是1,其他不知道。

因此,当判断到bit[3]=1时,表示一次传输的开始,连续接收3字节后再判断。

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // 同步复位
    output done); //

    parameter BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;
    reg[1:0] state,next_state;
    
    // State transition logic (combinational)
    always@(*)
        begin
            case(state)
                BYTE1:next_state<=in[3]?BYTE2:BYTE1;
                BYTE2:next_state<=BYTE3;
                BYTE3:next_state<=DONE;
                DONE:next_state<=in[3]?BYTE2:BYTE1;
            endcase
        end

    // State flip-flops (sequential)
    always@(posedge clk)
        begin
            if(reset)
                state<=BYTE1;
            else
                state<=next_state;
        end
 
    // Output logic
    assign done=(state==DONE);

endmodule

5.16、Fsm ps2data

现在您有了一个状态机,可以识别 PS/2 字节流中的三字节消息,添加一个数据路径,该路径也将在收到数据包时输出 24 位(3 字节)消息(out_bytes[23:16]是第一个字节,out_bytes[15:8]是第二个字节,依此类推)。

每当断言完成信号时, out_bytes 都需要有效。您可以在其他时间输出任何内容(即不关心)。

大概意思:在上一题的基础上,将接收的3个字节数据,在接收完后完整的输出。

在上一题的基础上,通过寄存器先寄存收到的数据,最后合并输出。

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output [23:0] out_bytes,
    output done); //

    parameter BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;
    reg[1:0] state,next_state;
    reg[23:0] data;
    
    // FSM from fsm_ps2
    always@(*)
        begin
            case(state)
                BYTE1:next_state<=in[3]?BYTE2:BYTE1;
                BYTE2:next_state<=BYTE3;
                BYTE3:next_state<=DONE;
                DONE:next_state<=in[3]?BYTE2:BYTE1;
            endcase
        end
    
    always@(posedge clk)
        begin
            if(reset)
                state<=BYTE1;
            else
                state<=next_state;
        end
    
    
    // New: Datapath to store incoming bytes.
    assign done = (state == DONE);

    always @(posedge clk) begin
        if (reset) begin
            data <= 24'd0;
        end
        else begin
            data[23:16] <= data[15:8];
            data[15:8] <= data[7:0];
            data[7:0]  <= in;
        end
    end

    assign out_bytes = (done) ? data : 24'd0; 
endmodule

 

posted @ 2022-05-20 19:46  super_sweet  阅读(32)  评论(0编辑  收藏  举报