HDLBits中文版,标准参考答案 | 3.2.5 Finite State Machines | 有限状态机(2)

关注 望森FPGA  查看更多FPGA资讯

这是望森的第 17 期分享

作者 | 望森
来源 | 望森FPGA

目录

1 Lemmings 1

2 Lemmings 2

3 Lemmings 3

4 Lemmings 4

5 One-hot FSM | 独热 FSM

6 PS/2 packet parser | PS/2 数据包解析器

7 PS/2 packet parser anddatapath | PS/2 数据包解析器和数据路径


本文中的代码都能够正常运行,请放心食用😋~

练习的官方网站是:https://hdlbits.01xz.net/

注:作者将每个练习的知识点都放在了题目和答案之后


1 Lemmings 1

题目:

游戏《旅鼠》涉及的动物大脑相当简单。非常简单,我们将使用有限状态机对其进行建模。

在《旅鼠》的 2D 世界中,旅鼠可以处于两种状态之一:向左行走或向右行走。如果撞到障碍物,它会改变方向。具体来说,如果旅鼠左侧受到撞击,它会向右行走。如果右侧受到撞击,它会向左行走。如果两侧同时受到撞击,它仍会改变方向。

实现一个 Moore 状态机,该状态机具有两个状态、两个输入和一个输出,可以对此行为进行建模。

答案:

我的答案:
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 LEFT=1'b0, RIGHT=1'b1; 

    wire LEFT2LEFT,LEFT2RIGHT,RIGHT2RIGHT,RIGHT2LEFT;

    always @(posedge clk or posedge areset) begin    // This is a sequential always block
        // State flip-flops with asynchronous reset
        if(areset)begin
            state <= LEFT;
        end
        else begin
            state <= next_state;
        end
    end
    
    always @(*) begin    // This is a combinational always block
        // State transition logic
        case(state)
            LEFT : begin
                if (LEFT2LEFT)begin
                    next_state = LEFT;
                end
                else if (LEFT2RIGHT)begin
                    next_state = RIGHT;
                end
            end
            RIGHT : begin
                if (RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (RIGHT2LEFT)begin
                    next_state = LEFT;
                end
            end
            default next_state = state;
        endcase
    end
    
    assign LEFT2LEFT         = !bump_left;
    assign LEFT2RIGHT         = bump_left;
    assign RIGHT2RIGHT         = !bump_right;
    assign RIGHT2LEFT         = bump_right;

    // Output logic
    // assign out = (state == ...);
    assign walk_left         = (state == LEFT);
    assign walk_right         = (state == RIGHT);

endmodule

参考答案:
module top_module (
        input clk,
        input areset,
        input bump_left,
        input bump_right,
        output walk_left,
        output walk_right
);

        // Give state names and assignments. I'm lazy, so I like to use decimal numbers.
        // It doesn't really matter what assignment is used, as long as they're unique.
        parameter WL=0, WR=1;
        reg state;
        reg next;
    
    
    // Combinational always block for state transition logic. Given the current state and inputs,
    // what should be next state be?
    // Combinational always block: Use blocking assignments.    
    always@(*) begin
                case (state)
                        WL: next = bump_left  ? WR : WL;
                        WR: next = bump_right ? WL : WR;
                endcase
    end
    
    
    // Combinational always block for state transition logic. Given the current state and inputs,
    // what should be next state be?
    // Combinational always block: Use blocking assignments.    
    always @(posedge clk, posedge areset) begin
                if (areset) state <= WL;
        else state <= next;
        end
                
                
        // Combinational output logic. In this problem, an assign statement are the simplest.
        // In more complex circuits, a combinational always block may be more suitable.                
        assign walk_left = (state==WL);
        assign walk_right = (state==WR);

        
endmodule

知识点:

提示:


2 Lemmings 2

题目:

除了左右行走外,如果脚下的地面消失,旅鼠还会摔倒(大概会发出“啊啊啊”的声音)。

除了左右行走和被撞时改变方向外,当地面 = 0 时,旅鼠还会摔倒并发出“啊啊啊”的声音。当地面重新出现(地面 = 1 时),旅鼠会继续沿摔倒前的方向行走。摔倒时被撞不会影响行走方向,在地面消失(但尚未摔倒)的同一周期内被撞,或者在摔倒时地面重新出现,也不会影响行走方向。

构建一个有限状态机来模拟此行为。

答案:

1.状态转换图

2.代码

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, ...
    reg [1:0] state, next_state;
        parameter LEFT=2'd0, RIGHT=2'd1,FALL_LEFT=2'd2,FALL_RIGHT=2'd3; 

    wire LEFT2LEFT,LEFT2RIGHT,LEFT2FALL_LEFT,RIGHT2RIGHT,RIGHT2LEFT,RIGHT2FALL_RIGHT
    ,FALL_LEFT2FALL_LEFT,FALL_LEFT2LEFT,FALL_RIGHT2FALL_RIGHT,FALL_RIGHT2RIGHT;

    always @(posedge clk or posedge areset) begin    // This is a sequential always block
        // State flip-flops with asynchronous reset
        if(areset)begin
            state <= LEFT;
        end
        else begin
            state <= next_state;
        end
    end
    
    always @(*) begin    // This is a combinational always block
        // State transition logic
        case(state)
            LEFT : begin
                if (LEFT2LEFT)begin
                    next_state = LEFT;
                end
                else if (LEFT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
            end
            RIGHT : begin
                if (RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (RIGHT2LEFT)begin
                    next_state = LEFT;
                end
                else if (RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
            end
            FALL_LEFT : begin
                if (FALL_LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
                else if (FALL_LEFT2LEFT)begin
                    next_state = LEFT;
                end
            end
            FALL_RIGHT : begin
                if (FALL_RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
                else if (FALL_RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
            end
            default next_state = state;
        endcase
    end
    
    assign LEFT2LEFT                         = !bump_left && ground;
    assign LEFT2RIGHT                         = bump_left && ground;
    assign LEFT2FALL_LEFT                 = !ground;
    assign RIGHT2RIGHT                         = !bump_right && ground;
    assign RIGHT2LEFT                         = bump_right && ground;
    assign RIGHT2FALL_RIGHT         = !ground;
    assign FALL_LEFT2FALL_LEFT      = !ground;
    assign FALL_LEFT2LEFT                 = ground;
    assign FALL_RIGHT2FALL_RIGHT    = !ground;
    assign FALL_RIGHT2RIGHT         = ground;

    // Output logic
    // assign out = (state == ...);
    assign walk_left        = (state == LEFT);
    assign walk_right       = (state == RIGHT);
    assign aaah                 = (state == FALL_LEFT) || (state == FALL_RIGHT);
    
endmodule

知识点:

提示:


3 Lemmings 3

题目:

除了行走和跌倒,有时还可以命令旅鼠做一些有用的事情,比如挖掘(当 dig=1 时,它会开始挖掘)。如果旅鼠当前正在地面上行走( ground=1 且没有跌倒),它可以挖掘,并会继续挖掘直到到达另一侧( ground=0 )。此时,由于没有地面,它会跌倒(aaah!),然后再次接触地面后继续沿其原始方向行走。与跌倒一样,在挖掘时受到撞击不会产生任何影响,并且在跌倒或没有地面时被告知挖掘会被忽略。

(换句话说,行走的旅鼠可以跌倒、挖掘或切换方向。如果满足这些条件中的多个条件,则跌倒的优先级高于挖掘,而挖掘的优先级高于切换方向。)

扩展您的有限状态机以模拟此行为。

答案:

1.状态转换图

2.代码

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, next_state;
    parameter LEFT=3'd0, RIGHT=3'd1,DIG_LEFT=3'd2,DIG_RIGHT=3'd3,FALL_LEFT=3'd4,FALL_RIGHT=3'd5; 

    wire LEFT2LEFT,LEFT2RIGHT,LEFT2DIG_LEFT,LEFT2FALL_LEFT,
    RIGHT2RIGHT,RIGHT2LEFT,RIGHT2DIG_RIGHT,RIGHT2FALL_RIGHT,
    DIG_LEFT2FALL_LEFT,DIG_LEFT2DIG_LEFT,
    DIG_RIGHT2FALL_RIGHT,DIG_RIGHT2DIG_RIGHT,
    FALL_LEFT2FALL_LEFT,FALL_LEFT2LEFT,
    FALL_RIGHT2FALL_RIGHT,FALL_RIGHT2RIGHT;

    always @(posedge clk or posedge areset) begin    // This is a sequential always block
        // State flip-flops with asynchronous reset
        if(areset)begin
            state <= LEFT;
        end
        else begin
            state <= next_state;
        end
    end
    
    always @(*) begin    // This is a combinational always block
        // State transition logic
        case(state)
            LEFT : begin
                if (LEFT2LEFT)begin
                    next_state = LEFT;
                end
                else if (LEFT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (LEFT2DIG_LEFT)begin
                    next_state = DIG_LEFT;
                end
                else if (LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
            end
            RIGHT : begin
                if (RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (RIGHT2LEFT)begin
                    next_state = LEFT;
                end
                else if (RIGHT2DIG_RIGHT)begin
                    next_state = DIG_RIGHT;
                end
                else if (RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
            end
            DIG_LEFT : begin
                if (DIG_LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
                else if (DIG_LEFT2DIG_LEFT)begin
                    next_state = DIG_LEFT;
                end
            end
            DIG_RIGHT : begin
                if (DIG_RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
                else if (DIG_RIGHT2DIG_RIGHT)begin
                    next_state = DIG_RIGHT;
                end
            end
            FALL_LEFT : begin
                if (FALL_LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
                else if (FALL_LEFT2LEFT)begin
                    next_state = LEFT;
                end
            end
            FALL_RIGHT : begin
                if (FALL_RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
                else if (FALL_RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
            end
            default next_state = LEFT;
        endcase
    end
    
    /*bump_left,bump_right,ground,dig,*/
    
    assign LEFT2LEFT                = !bump_left && ground && !dig;
    assign LEFT2RIGHT               = bump_left && ground && !dig;
    assign LEFT2DIG_LEFT            = ground && dig;
    assign LEFT2FALL_LEFT           = !ground;
    
    assign RIGHT2RIGHT              = !bump_right && ground && !dig;
    assign RIGHT2LEFT               = bump_right && ground && !dig;
    assign RIGHT2DIG_RIGHT          = ground && dig;
    assign RIGHT2FALL_RIGHT         = !ground;
    
    assign DIG_LEFT2FALL_LEFT      = !ground;
    assign DIG_LEFT2DIG_LEFT        = ground;
    
    assign DIG_RIGHT2FALL_RIGHT     = !ground;
    assign DIG_RIGHT2DIG_RIGHT      = ground ;
    
    assign FALL_LEFT2FALL_LEFT      = !ground;
    assign FALL_LEFT2LEFT           = ground;
    
    assign FALL_RIGHT2FALL_RIGHT    = !ground;
    assign FALL_RIGHT2RIGHT         = ground;

    // Output logic
    assign walk_left        = (state == LEFT);
    assign walk_right       = (state == RIGHT);
    assign aaah             = (state == FALL_LEFT) || (state == FALL_RIGHT);
    assign digging               = (state == DIG_LEFT) || (state == DIG_RIGHT);
    
endmodule

知识点:

提示:


4 Lemmings 4

题目:

尽管旅鼠可以行走、跌倒和挖洞,但它们并非无懈可击。如果旅鼠跌倒时间过长,然后撞到地面,它就会 splatter 四分五裂。具体来说,如果旅鼠跌倒超过 20 个时钟周期,然后撞到地面,它就会四分五裂并停止行走、跌倒或挖洞(所有 4 个输出都变为 0),永远(或直到 FSM 重置)。旅鼠在撞到地面之前可以跌倒多远没有上限。旅鼠只有在撞到地面时才会四分五裂;它们不会在半空中四分五裂。

扩展您的有限状态机以模拟此行为。

跌倒 20 个周期是可以存活的:

跌落21次导致四分五裂:

答案:

1.状态转换图

2.代码

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, next_state;
    parameter LEFT=3'd0, RIGHT=3'd1,DIG_LEFT=3'd2,DIG_RIGHT=3'd3,
    FALL_LEFT=3'd4,FALL_RIGHT=3'd5,SLATTER=3'd6; 
    
    reg [4:0] cnt_fall;
    reg FALL_20clk;
    
    wire LEFT2LEFT,LEFT2RIGHT,LEFT2DIG_LEFT,LEFT2FALL_LEFT,
    RIGHT2RIGHT,RIGHT2LEFT,RIGHT2DIG_RIGHT,RIGHT2FALL_RIGHT,
    DIG_LEFT2FALL_LEFT,DIG_LEFT2DIG_LEFT,
    DIG_RIGHT2FALL_RIGHT,DIG_RIGHT2DIG_RIGHT,
    FALL_LEFT2FALL_LEFT,FALL_LEFT2LEFT,FALL_LEFT2SLATTER,
    FALL_RIGHT2FALL_RIGHT,FALL_RIGHT2RIGHT,FALL_RIGHT2SLATTER;

        //FALL counter & 20clk flag
    always @(posedge clk or posedge areset) begin
        if(areset)begin
            cnt_fall <= 5'd0;
        end
        else if(state == FALL_LEFT || state == FALL_RIGHT)begin
            cnt_fall <= cnt_fall + 5'd1;
        end
        else begin
            cnt_fall <= 5'd0;
        end
    end
    always @(*) begin 
        if(areset)begin
            FALL_20clk = 1'd0;
        end
        else if(cnt_fall > 5'd19)begin
            FALL_20clk = 1'd1;
        end
        else begin
            FALL_20clk = FALL_20clk;
        end
    end
    
    always @(posedge clk or posedge areset) begin
        if(areset)begin
            state <= LEFT;
        end
        else begin
            state <= next_state;
        end
    end
    
    always @(*) begin
        case(state)
            LEFT : begin
                if (LEFT2LEFT)begin
                    next_state = LEFT;
                end
                else if (LEFT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (LEFT2DIG_LEFT)begin
                    next_state = DIG_LEFT;
                end
                else if (LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
            end
            RIGHT : begin
                if (RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (RIGHT2LEFT)begin
                    next_state = LEFT;
                end
                else if (RIGHT2DIG_RIGHT)begin
                    next_state = DIG_RIGHT;
                end
                else if (RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
            end
            DIG_LEFT : begin
                if (DIG_LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
                else if (DIG_LEFT2DIG_LEFT)begin
                    next_state = DIG_LEFT;
                end
            end
            DIG_RIGHT : begin
                if (DIG_RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
                else if (DIG_RIGHT2DIG_RIGHT)begin
                    next_state = DIG_RIGHT;
                end
            end
            FALL_LEFT : begin
                if (FALL_LEFT2FALL_LEFT)begin
                    next_state = FALL_LEFT;
                end
                else if (FALL_LEFT2LEFT)begin
                    next_state = LEFT;
                end
                else if (FALL_LEFT2SLATTER)begin
                    next_state = SLATTER;
                end
            end
            FALL_RIGHT : begin
                if (FALL_RIGHT2FALL_RIGHT)begin
                    next_state = FALL_RIGHT;
                end
                else if (FALL_RIGHT2RIGHT)begin
                    next_state = RIGHT;
                end
                else if (FALL_RIGHT2SLATTER)begin
                    next_state = SLATTER;
                end
            end
            SLATTER : begin
                next_state = SLATTER;
            end
            default next_state = LEFT;
        endcase
    end
    
    /*bump_left,bump_right,ground,dig,*/
    assign LEFT2LEFT                = !bump_left && ground && !dig;
    assign LEFT2RIGHT               = bump_left && ground && !dig;
    assign LEFT2DIG_LEFT            = ground && dig;
    assign LEFT2FALL_LEFT           = !ground;
    
    assign RIGHT2RIGHT              = !bump_right && ground && !dig;
    assign RIGHT2LEFT               = bump_right && ground && !dig;
    assign RIGHT2DIG_RIGHT          = ground && dig;
    assign RIGHT2FALL_RIGHT         = !ground;
    
    assign DIG_LEFT2FALL_LEFT      = !ground;
    assign DIG_LEFT2DIG_LEFT        = ground;
    
    assign DIG_RIGHT2FALL_RIGHT     = !ground;
    assign DIG_RIGHT2DIG_RIGHT      = ground ;
    
    assign FALL_LEFT2FALL_LEFT      = !ground;
    assign FALL_LEFT2LEFT           = ground && !FALL_20clk;
    assign FALL_LEFT2SLATTER        = ground && FALL_20clk;
    
    assign FALL_RIGHT2FALL_RIGHT    = !ground;
    assign FALL_RIGHT2RIGHT         = ground && !FALL_20clk;
    assign FALL_RIGHT2SLATTER       = ground && FALL_20clk;

    // Output logic
    assign walk_left        = (state == LEFT);
    assign walk_right       = (state == RIGHT);
    assign aaah             = (state == FALL_LEFT) || (state == FALL_RIGHT);
    assign digging          = (state == DIG_LEFT) || (state == DIG_RIGHT);
    
endmodule

知识点:

提示:使用 FSM 来控制计数器,追踪 Lemming 下落的时间长度。


5 One-hot FSM | 独热 FSM

题目:

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

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

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

提示:

通过查看状态转换图的入边,可以推导出独热状态转换逻辑的逻辑方程。

答案:

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] = (state[S0] & !in) | (state[S1] & !in) | (state[S2] & !in) | (state[S3] & !in) | (state[S4] & !in) | 
    (state[S7] & !in) | (state[S8] & !in) | (state[S9] & !in) ;
    assign next_state[S1] = (state[S0] & in) | (state[S8] & in) | (state[S9] & in) ; 
    assign next_state[S2] = state[S1] & in ; 
    assign next_state[S3] = state[S2] & in ; 
    assign next_state[S4] = state[S3] & in ; 
    assign next_state[S5] = state[S4] & in ; 
    assign next_state[S6] = state[S5] & in ; 
    assign next_state[S7] = (state[S6] & in) | (state[S7] & in) ; 
    assign next_state[S8] = state[S5] & !in ; 
    assign next_state[S9] = state[S6] & !in ; 
 
    assign out1 = state[S8] | state[S9] ; 
    assign out2 = state[S7] | state[S9] ; 
 
endmodule

6 PS/2 packet parser | PS/2 数据包解析器

题目:

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

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

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

一些时序图用于解释所需行为

在无错误的情况下,每三个字节形成一条消息:

当发生错误时,搜索字节1:

请注意,这与 1xx 序列识别器不同。这里不允许重叠序列:

答案:

1.状态转换图

2.代码

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

    reg [1:0] state, next_state;
    parameter BYTE1=2'd0, BYTE2=2'd1, BYTE3=2'd2, DONE=2'd3; 
    wire BYTE12BYTE1,BYTE12BYTE2,DONE2BYTE1,DONE2BYTE2;
    
    // State transition logic (combinational)
    always @(posedge clk) begin
        if(reset)begin
            state <= BYTE1;
        end
        else begin
            state <= next_state;
        end
    end

    always @(*) begin
        case(state)
            BYTE1 : begin
                if (BYTE12BYTE1)begin
                    next_state = BYTE1;
                end
                else if (BYTE12BYTE2)begin
                    next_state = BYTE2;
                end
            end
            BYTE2 : begin
                next_state = BYTE3;
            end
            BYTE3 : begin
                next_state = DONE;
            end
            DONE : begin
                if (DONE2BYTE1)begin
                    next_state = BYTE1;
                end
                else if (DONE2BYTE2)begin
                    next_state = BYTE2;
                end
            end
            default next_state = 2'd0;
        endcase
    end
    
    assign BYTE12BYTE1       = in[3] == 0;
    assign BYTE12BYTE2       = in[3] == 1;
    assign DONE2BYTE1        = in[3] == 0;
    assign DONE2BYTE2        = in[3] == 1;

    // Output logic
    assign done         = (state == DONE);
    

endmodule

知识点:

提示:

  • 尽管 in[7:0] 是一个字节,但 FSM 只有一个输入:in[3]。

  • 您需要 4 个状态。三个状态可能行不通,因为其中一个状态需要断言 done,而对于每个收到的消息,done 只会断言一个周期。


7 PS/2 packet parser anddatapath | PS/2 数据包解析器和数据路径

题目:

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

只要 done 信号被置位,out_bytes 就必须有效。您可以在其他时间输出任何内容(即,无关紧要)。

例如:

答案:

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

// FSM from fsm_ps2
    reg [1:0] state, next_state;
    parameter BYTE1=2'd0, BYTE2=2'd1, BYTE3=2'd2, DONE=2'd3; 
    wire BYTE12BYTE1,BYTE12BYTE2,DONE2BYTE1,DONE2BYTE2;
    
    // State transition logic (combinational)
    always @(posedge clk) begin
        if(reset)begin
            state <= BYTE1;
        end
        else begin
            state <= next_state;
        end
    end

    always @(*) begin
        case(state)
            BYTE1 : begin
                if (BYTE12BYTE1)begin
                    next_state = BYTE1;
                end
                else if (BYTE12BYTE2)begin
                    next_state = BYTE2;
                end
            end
            BYTE2 : begin
                next_state = BYTE3;
            end
            BYTE3 : begin
                next_state = DONE;
            end
            DONE : begin
                if (DONE2BYTE1)begin
                    next_state = BYTE1;
                end
                else if (DONE2BYTE2)begin
                    next_state = BYTE2;
                end
            end
            default next_state = 2'd0;
        endcase
    end
    
    assign BYTE12BYTE1       = in[3] == 0;
    assign BYTE12BYTE2       = in[3] == 1;
    assign DONE2BYTE1        = in[3] == 0;
    assign DONE2BYTE2        = in[3] == 1;

    // Output logic
    assign done         = (state == DONE);
// New: Datapath to store incoming bytes.
    reg [23:0] in_temp;
    always @(posedge clk) begin
        in_temp <= {in_temp[15:0],in};
    end
    assign out_bytes = (state == DONE) ? in_temp : 0 ;
    
endmodule

知识点:

提示:

使用 PS/2 数据包解析器的 FSM 并添加数据路径来捕获传入的字节。

讲解:

在上题基础上,增加三个字节的寄存器,在 DONE 状态时输出数据即可。


- END -

公z号/CSDN搜索【望森FPGA】,查看更多FPGA资讯~

相关推荐文章,点击跳转:

望森FPGA的HDLBits合集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望森FPGA

谢谢你的支持,这对我很重要~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值