HDLBits练习汇总-14-时序逻辑设计测试–状态机(二)-FPGA常见问题社区-FPGA CPLD-ChipDebug

HDLBits练习汇总-14-时序逻辑设计测试–状态机(二)

 

 

水箱问题(Exams/ece241 2013 q4)

一个大水库的水为几个用户服务。为了保持足够高的水位,三个传感器以5英寸的间隔垂直放置。当水位高于最高传感器S3时,输入流量应为零。当液位低于最低传感器(Si)时,流量应处于最大(公称流量阀和补充流量阀均打开)。当水位在上下两个传感器之间时,流量由两个因素决定:水位和上次传感器变化前的水位。每个水位都有一个与之相关的名义流量,如下表所示。如果传感器的变化表明以前的水平低于当前水平,则应该发生名义流量。如果之前的水平高于当前水平,应通过打开补充流量阀(由AFR控制)来增加流量。画出水库控制器的摩尔模型状态图。清楚地指出每个状态的所有状态转换和输出。FSM的输入是S1, S2和S3;输出为FR1,FR2,FR3和△FR。

水箱问题

还包括一个高电平有效同步复位,可将状态机复位到与水位长时间处于低位时相当的状态(未置位传感器,并且所有四个输出均置位)。

模块声明

module top_module (
    input clk,
    input reset,
    input [3:1] s,
    output fr3,
    output fr2,
    output fr1,
    output dfr
);

 

题目解析

对于本题来说,主要的关键就是设计状态转移图,然后理清输出的逻辑即可完成整体设计。对于水箱的状态,从上图中的状态可以看出对应状态的输出,对于水箱的水位状态,例如处于低于S1时,此时的状态可能为持续低于S1或者水位上升将水位处于S1和S2之间。其余状态同理,状态变化为低于当前、高于当前或者保持不变。对于输出状态dfr,如果之前的水平高于当前水平dfr置位为高。

答案

状态转移图

module top_module (
    input clk,
    input reset,
    input [3:1] s,
    output fr3,
    output fr2,
    output fr1,
    output dfr
);

 

Lemmings1

游戏旅鼠涉及大脑相当简单的小动物。如此简单,以至于我们将使用有限状态机对其进行建模。

在莱明斯的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);

 

答案:

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;

    always @(posedge clk, posedge areset) begin
        // State flip-flops with asynchronous reset
        if(areset==1)begin
            state<=LEFT;
        end
        else begin
            state<=next_state;
        end
    end

    always @(*) begin
        // State transition logic
        case (state)
            LEFT:begin
                if (bump_left==1) begin
                    next_state = RIGHT;
                end else begin
                    next_state = LEFT;
                end
            end
            RIGHT:begin
                if (bump_right==1) begin
                    next_state = LEFT;
                end else begin
                    next_state = RIGHT;
                end
            end
        endcase
    end

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

endmodule

 

Lemmings2

除了左右行走之外,如果地面消失在它们下面,旅鼠还会摔倒(大概会“啊!”)。

除了左右行走并在碰撞时改变方向外,当地面=0时,旅鼠会摔倒并说“啊!当地面重新出现(地面=1)时,旅鼠将恢复以与坠落前相同的方向行走。跌倒时被撞不会影响行走方向,在与地面相同的周期内被撞到消失(但尚未下落),或者地面在仍然下落时再次出现时,也不会影响行走方向。

构建一个对此行为进行建模的有限状态机。

时序示意图

状态转移图示例如下:

状态转移图

模块声明

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

 

答案

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_LEFT=2,FALL_RIGHT=3;
    reg [1:0] state;
    reg [1:0] next_state;

    always @(posedge clk, posedge areset) begin
        // State flip-flops with asynchronous reset
        if(areset==1)begin
            state<=LEFT;
        end
        else begin
            state<=next_state;
        end
    end

    always @(*) begin
        // State transition logic
        case (state)
            LEFT:begin
                if(ground==0)begin
                    next_state = FALL_LEFT;
                end
                else if (bump_left==1) begin
                    next_state = RIGHT;
                end 
                else begin
                    next_state = LEFT;
                end
            end
            RIGHT:begin
                if(ground==0)begin
                    next_state = FALL_RIGHT;
                end 
                else if (bump_right==1) begin
                    next_state = LEFT;
                end
                else begin
                    next_state = RIGHT;
                end
            end
            FALL_LEFT:begin
                if(ground==1)begin
                    next_state = LEFT;
                end
                else begin
                    next_state = FALL_LEFT;
                end
            end
            FALL_RIGHT:begin
                if(ground==1)begin
                    next_state = RIGHT;
                end
                else begin
                    next_state = FALL_RIGHT;
                end
            end
        endcase
    end

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

 

Lemmings3

除了行走和跌倒之外,有时还可以告诉旅鼠做有用的事情,比如挖掘(当 dig=1 时开始挖掘)。如果旅鼠目前在地面上行走(地面=1并且没有掉落),则可以挖掘,并且将继续挖掘,直到到达另一侧(地面=0)。在这一点上,由于没有地面,它会掉下来(啊啊!),然后一旦它再次落地,就继续向原来的方向走。与跌倒一样,在挖掘时被撞到没有影响,并且在跌倒或没有地面时被告知要挖掘会被忽略。

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

时序示意图如下:

时序示意图

根据题目给出示意状态转移图如下:

状态转移图

模块声明

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

答案

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_LEFT=2,FALL_RIGHT=3,DIG_L=4,DIG_R=5;     reg [2:0] state;     reg [2:0] next_state;      always @(posedge clk, posedge areset) begin         // State flip-flops with asynchronous reset         if(areset==1)begin             state<=LEFT;         end         else begin             state<=next_state;         end     end      always @(*) begin         // State transition logic         case (state)             LEFT:begin                 if(ground==0)begin                     next_state = FALL_LEFT;                 end                 else if (dig==1) begin                     next_state = DIG_L;                 end                  else if (bump_left==1) begin                     next_state = RIGHT;                 end                  else begin                     next_state = LEFT;                 end             end             RIGHT:begin                 if(ground==0)begin                     next_state = FALL_RIGHT;                 end                 else if (dig==1) begin                     next_state = DIG_R;                 end                   else if (bump_right==1) begin                     next_state = LEFT;                 end                 else begin                     next_state = RIGHT;                 end             end             FALL_LEFT:begin                 if(ground==1)begin                     next_state = LEFT;                 end                 else begin                     next_state = FALL_LEFT;                 end             end             FALL_RIGHT:begin                 if(ground==1)begin                     next_state = RIGHT;                 end                 else begin                     next_state = FALL_RIGHT;                 end             end             DIG_L:begin                 if(ground==0)begin                     next_state = FALL_LEFT;                 end                 else begin                     next_state = DIG_L;                 end             end             DIG_R:begin                 if(ground==0)begin                     next_state = FALL_RIGHT;                 end                 else begin                     next_state = DIG_R;                 end             end             default:begin                 next_state = LEFT;             end         endcase     end      // Output logic     assign walk_left = (state == LEFT);     assign walk_right = (state == RIGHT);     assign digging = (state == DIG_R)||(state == DIG_L);     assign aaah = (state == FALL_RIGHT)||(state == FALL_LEFT); endmodule 

lemmings4

虽然旅鼠可以走路、跌倒和挖掘,但旅鼠并非无懈可击。如果旅鼠跌落时间过长然后着地,它可能会飞溅。特别是,如果旅鼠掉落超过 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 );   

答案

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_LEFT=2,FALL_RIGHT=3,DIG_L=4,DIG_R=5,SPLAT=6;     reg [2:0] state;     reg [2:0] next_state;      always @(posedge clk, posedge areset) begin         // State flip-flops with asynchronous reset         if(areset==1)begin             state<=LEFT;         end         else begin             state<=next_state;         end     end      always @(*) begin         // State transition logic         case (state)             LEFT:begin                 if(ground==0)begin                     next_state = FALL_LEFT;                 end                 else if (dig==1) begin                     next_state = DIG_L;                 end                  else if (bump_left==1) begin                     next_state = RIGHT;                 end                  else begin                     next_state = LEFT;                 end             end             RIGHT:begin                 if(ground==0)begin                     next_state = FALL_RIGHT;                 end                 else if (dig==1) begin                     next_state = DIG_R;                 end                   else if (bump_right==1) begin                     next_state = LEFT;                 end                 else begin                     next_state = RIGHT;                 end             end             FALL_LEFT:begin                 if(timeout==1&&ground==1)begin                     next_state = SPLAT;                 end                 else if(ground==1)begin                     next_state = LEFT;                 end                 else begin                     next_state = FALL_LEFT;                 end             end             FALL_RIGHT:begin                 if(timeout==1&&ground==1)begin                     next_state = SPLAT;                 end                 else if(ground==1)begin                     next_state = RIGHT;                 end                 else begin                     next_state = FALL_RIGHT;                 end             end             SPLAT:begin                 next_state = SPLAT;             end             DIG_L:begin                 if(ground==0)begin                     next_state = FALL_LEFT;                 end                 else begin                     next_state = DIG_L;                 end             end             DIG_R:begin                 if(ground==0)begin                     next_state = FALL_RIGHT;                 end                 else begin                     next_state = DIG_R;                 end             end             default:begin                 next_state = LEFT;             end         endcase     end      // Output logic     assign walk_left = (state == LEFT);     assign walk_right = (state == RIGHT);     assign digging = (state == DIG_R)||(state == DIG_L);     assign aaah = (state == FALL_RIGHT)||(state == FALL_LEFT);      //aaah计数     reg [4:0] aaah_cnt=0;     always @(posedge clk) begin         if(aaah==1)begin             aaah_cnt<=aaah_cnt+1;         end         else begin             aaah_cnt<=0;         end     end     reg timeout=0;     always @(*) begin         if(areset==1)             timeout=0;         else if(aaah_cnt==20)             timeout=1;         else             timeout=timeout;       end endmodule 

Fsm onehot

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

状态转移图

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

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

模块声明

module top_module(     input in,     input [9:0] state,     output [9:0] next_state,     output out1,     output out2); 

答案

module top_module(     input in,     input [9:0] state,     output [9:0] next_state,     output out1,     output out2);      parameter S0 = 'd0,S1 = 'd1,S2 = 'd2,S3 = 'd3,               S4 = 'd4,S5 = 'd5,S6 = 'd6,S7 = 'd7,               S8 = 'd8,S9 = 'd9;      assign next_state[0] = ~in & (state[S0] | state[S1] | state[S2] | state[S3] | state[S4] | state[S7] | state[S8] | state[S9]);     assign next_state[1] = in & (state[S0] | state[S8] | state[S9]);     assign next_state[2] = in & state[S1];     assign next_state[3] = in & state[S2];     assign next_state[4] = in & state[S3];     assign next_state[5] = in & state[S4];     assign next_state[6] = in & state[S5];     assign next_state[7] = in & (state[S6] | state[S7]);     assign next_state[8] = ~in & state[S5];     assign next_state[9] = ~in & state[S6];      assign out1 = (state[S8])||(state[S9]);     assign out2 = (state[S7])||(state[S9]);  endmodule 

Fsm ps2

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

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

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

一些时序图来解释所需的行为,在无错误条件下,每三个字节形成一条消息:

无错误条件

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

发生错误时,搜索字节 1

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

图片[15]-HDLBits练习汇总-14-时序逻辑设计测试–状态机(二)-FPGA常见问题社区-FPGA CPLD-ChipDebug

模块声明

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

答案

module top_module(     input clk,     input [7:0] in,     input reset,    // Synchronous reset     output done); //      parameter BYTE1 = 'd0,BYTE2 = 'd1,BYTE3 = 'd2,DONE = 'd3;     reg [1:0] state;     reg [1:0] next_state;     // State flip-flops (sequential)     always @(posedge clk) begin         if(reset==1)begin             state<=BYTE1;         end         else begin             state<=next_state;         end     end      // State transition logic (combinational)     always @(*) begin         case (state)             BYTE1:begin                 if(in[3]==0)begin                     next_state = BYTE1;                 end                  else begin                     next_state = BYTE2;                 end             end             BYTE2:begin                 next_state = BYTE3;             end             BYTE3:begin                 next_state = DONE;             end             DONE:begin                 if(in[3]==0)begin                     next_state = BYTE1;                 end                  else begin                     next_state = BYTE2;                 end             end             default:next_state = BYTE1;         endcase     end      // Output logic     assign done = (state == DONE); endmodule 

Fsm ps2data

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

每当断言完成信号时,out_bytes都需要有效。你可以在其他时间输出任何东西(即,不在乎)。

时序示意图

模块声明

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

答案

module top_module(     input clk,     input [7:0] in,     input reset,    // Synchronous reset     output [23:0] out_bytes,     output done); //      parameter BYTE1 = 'd0,BYTE2 = 'd1,BYTE3 = 'd2,DONE = 'd3;     reg [1:0] state;     reg [1:0] next_state;     // State flip-flops (sequential)     always @(posedge clk) begin         if(reset==1)begin             state<=BYTE1;         end         else begin             state<=next_state;         end     end      // State transition logic (combinational)     always @(*) begin         case (state)             BYTE1:begin                 if(in[3]==0)begin                     next_state = BYTE1;                 end                  else begin                     next_state = BYTE2;                 end             end             BYTE2:begin                 next_state = BYTE3;             end             BYTE3:begin                 next_state = DONE;             end             DONE:begin                 if(in[3]==0)begin                     next_state = BYTE1;                 end                  else begin                     next_state = BYTE2;                 end             end             default:next_state = BYTE1;         endcase     end     reg [7:0] in_r0;     reg [7:0] in_r1;     reg [7:0] in_r2;     always @(posedge clk ) begin         in_r0<=in;         in_r1<=in_r0;         in_r2<=in_r1;     end     // Output logic     assign done = (state == DONE);   always @(*) begin     if(done==1)         out_bytes={in_r2,in_r1,in_r0};   end endmodule 

 

请登录后发表评论

    没有回复内容