【hdlbits】个人学习交流分享(带答案)——finite state machines(FSM)

hdlbits网站:HDLBits (01xz.net)

有限状态机部分难度比较大,在这一部分我花了比其他另外四个部分都多的时间,几乎占了我刷整个hdlbits一半的时间,死了很多脑细胞,写的我头昏脑胀。一个是很多有些题目作者的表达并不好,项目要求描述的并不清楚,最准确的还是时序图,时序图是不会说谎的。另外一个就是这一部分对初学者难度确实更大,先要弄懂作者题目的需求,然后根据需求要做出正确的状态机设计和输出逻辑的设计,这部分代码长一些,状态机部分也是整个hdlbits的精华内容,所以这部分除了代码,我写的分析的内容也会多一些。

正文:

finite state machines

simple FSM1(asynchronous reset)

eda8cac5084942d0aeb73ed271875e78.png

Moore状态机,一个输入in,一个输出out,两个状态A和B,异步复位areset

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output out);//三段式状态机  

    parameter A=0, B=1; 
    reg state, next_state;

    always @(*) begin    //组合逻辑块:状态转换的逻辑判断
        case(state)
            A:next_state=in?A:B;
            B:next_state=in?B:A;
            default:next_state=B;//防止进入未设定状态产生latch锁死,设定default后可以自启动
        endcase
    end

    always @(posedge clk, posedge areset) begin    // 时序逻辑块:执行状态变换
        if(areset)
            state<=B;
        else
            state<=next_state;
    end

    // Output logic
    assign out = (state ==B);
    
endmodule

simple FSM1(synchronous reset)

57e65b034b474ae297386bd33ae43bf2.png

Moore状态机,一个输入in,一个输出out,两个状态A和B,同步复位reset

题目给了一段式状态机模板,我就顺着写了,非常不建议写一段式状态机。

// Note the Verilog-1995 module declaration syntax here:
module top_module(clk, reset, in, out);
    input clk;
    input reset;    // Synchronous reset to state B
    input in;
    output out;//  
    reg out;
    //一段式状态机(不提倡这么写)

    reg present_state, next_state;
    parameter A=1'b0,B=1'b1;

    always @(posedge clk) begin
        if (reset) begin  
            present_state<=B;
            out<=1'b1;
        end else begin
            case (present_state)// state transition logic
                A:next_state=in?A:B;
                B:next_state=in?B:A;
                default:next_state=B;
            endcase

            // State flip-flops
            present_state = next_state;   

            case (present_state)//  output logic
                B:out<=1'b1;
                A:out<=1'b0;
                default:out<=1'b1;    
            endcase
        end
    end
endmodule

simple FSM2(asynchronous reset)

7924ef4d24e3431db6fe4ab9d5706c43.png

Moore状态机,两个输入j和k,一个输出out,两个状态OFF和ON,异步复位areset

module top_module(
    input clk,
    input areset,    // Asynchronous reset to OFF
    input j,
    input k,
    output out); // 三段式

    parameter OFF=0, ON=1; 
    reg state, next_state;

    always @(*) begin
        case(state)
            ON:next_state=k?OFF:ON;
            OFF:next_state=j?ON:OFF;
            default:next_state=OFF;
        endcase
    end

    always @(posedge clk, posedge areset) begin
        if(areset)
            state<=OFF;
        else
            state<=next_state;
    end

    // Output logic
    assign out = (state == ON);

endmodule

simple FSM2(synchronous reset)

a1d596b188454e19b489e91582842b87.png

Moore状态机,两个输入j和k,一个输出out,两个状态OFF和ON,同步复位reset

module top_module(
    input clk,
    input reset,    // Synchronous reset to OFF
    input j,
    input k,
    output out); //  

    parameter OFF=0, ON=1; 
    reg state, next_state;

    always @(*) begin
        case(state)
            OFF:next_state=j?ON:OFF;
            ON:next_state=k?OFF:ON;
            default:next_state=OFF;
        endcase
    end

    always @(posedge clk) begin
        if(reset)
            state<=OFF;
        else
            state<=next_state;
    end

    // Output logic
    assign out = (state == ON);

endmodule

simple state transitions3

83cf8f0ec4a54b34944d60d39f49df7e.png

要求实现此状态机的状态转换逻辑和输出逻辑(组合逻辑部分)

状态转移图:

0a55ce4273b848cea3cf1530ffd811ce.jpeg

Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D。

module top_module(
    input in,
    input [1:0] state,
    output [1:0] next_state,
    output out); //

    parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;

    // State transition logic: next_state = f(state, in)
    always @(*)begin
        case(state)
            A:next_state=in?B:A;
            B:next_state=in?B:C;
            C:next_state=in?D:A;
            D:next_state=in?B:C;
            default:next_state=A;
        endcase
    end

    // Output logic:  out = f(state) for a Moore state machine
    assign out=(state==D);

endmodule

simple one-hot state transitions3

83cf8f0ec4a54b34944d60d39f49df7e.png

本题可以设独热码是A=4'b0001,B=4'b0010,C=4'b0100,D=4'b1000,独热码保证每个状态只有一个 state bit 为1,其他都为0。这意味着可以通过检查特定位的值来判别是否处于特定状态。本题中[0]/[1]/[2]/[3]分别是A/B/C/D的状态位(state bit)

要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。

状态转移图:

0a55ce4273b848cea3cf1530ffd811ce.jpeg

本题与上题放在前后可以做对比,正常写状态机的状态转移逻辑,都是根据现态(current_state)和触发条件转移到哪个次态(next_state),这是current_state→next_state的思路,也就是看现态(current_state)指出去的箭头。

这里题目要求通过独热编码来检查状态转换逻辑,这里从次态(next-state)出发,分析什么样的现态(current_state)加什么样的条件会得到该次态,这是next_state→current_state的思路(一种逆向的思路),也就是看指向次态(next_state)的箭头。

更详细的信息可以参考作者的解释:

c558d1edbcc543d3ac93b16c64a291b7.png

module top_module(
    input in,
    input [3:0] state,
    output [3:0] next_state,
    output out); //

    parameter A=0, B=1, C=2, D=3;//A=0,B=1,C=2,D=3是一个[3:0]state位索引

    // State transition logic: Derive an equation for each state flip-flop.
    assign next_state[A] = (state[A]&~in)|(state[C]&~in);
    assign next_state[B] = (state[A]&in)|(state[B]&in)|(state[D]&in);
    assign next_state[C] = (state[B]&~in)|(state[D]&~in);
    assign next_state[D] = (state[C]&in);

    // Output logic: 
    assign out = (state[D]);

endmodule

因为这里独热码设为了A=4‘b0001,B=4'b0010,C=4'b0100,D=4'b1000,所以上面这段代码A=0,B=1,C=2,D=3其实是一个[3:0]state bit的索引,如果不写parameter,还可以这样写:

module top_module(
    input in,
    input [3:0] state,
    output [3:0] next_state,
    output out); //

    // State transition logic: Derive an equation for each state flip-flop.
    assign next_state[0] = (state[0]&~in)|(state[2]&~in);
    assign next_state[1] = (state[0]&in)|(state[1]&in)|(state[3]&in);
    assign next_state[2] = (state[1]&~in)|(state[3]&~in);
    assign next_state[3] = (state[2]&in);

    // Output logic: 
    assign out = (state[3]);

endmodule

simple FSM3(asynchronous reset)

83cf8f0ec4a54b34944d60d39f49df7e.png

Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D,异步复位。

module top_module(
    input clk,
    input in,
    input areset,
    output  out); //
    parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
    reg [1:0]current_state,next_state;

    // 主控状态转移逻辑
    always @(*)begin
        case(current_state)
            A:next_state=in?B:A;
            B:next_state=in?B:C;
            C:next_state=in?D:A;
            D:next_state=in?B:C;
            default:next_state=A;
        endcase
    end

    // 主控执行逻辑
    always @(posedge clk,posedge areset)begin
        if(areset)
            current_state<=A;
        else
            current_state<=next_state;
    end

    // 输出逻辑
    assign out=(current_state==D);

endmodule

simple FSM3(synchronous reset)

83cf8f0ec4a54b34944d60d39f49df7e.png

Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D,同步复位。

module top_module(
    input clk,
    input in,
    input reset,
    output out); //三段式
    
    parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
    reg [1:0]current_state,next_state;

    // 主控状态转移逻辑
    always @(*)begin
        case(current_state)
            A:next_state=in?B:A;
            B:next_state=in?B:C;
            C:next_state=in?D:A;
            D:next_state=in?B:C;
            default:next_state=A;
        endcase
    end

    // 主控执行逻辑
    always @(posedge clk)begin
        if(reset)
            current_state<=A;
        else
            current_state<=next_state;
    end

    // 输出逻辑
    assign out=(current_state==D);

endmodule

design a Moore FSM

9b1efb78d7d149ea8e2aa141bcf82e3b.png

module top_module (
    input clk,
    input reset,
    input [3:1] s,
    output reg fr3,
    output reg fr2,
    output reg fr1,
    output reg dfr
); 
    parameter H3=4'b1000,B32=4'b0100,B21=4'b0010,L1=4'b0001;//4个状态:high s3,between s3s2,between s2s1, low s1,
    reg [3:0]current_state,next_state;
    
    always @(posedge clk)begin//主控执行逻辑
        if (reset) begin
            current_state<=L1;
        end
        else begin
            current_state<=next_state;
        end            
    end
    always @(*)begin//主控状态转移逻辑
        case(s)
            3'b000:next_state=L1;
            3'b001:next_state=B21;
            3'b011:next_state=B32;
            3'b111:next_state=H3;
            default:next_state=L1;
        endcase
    end
    always @(posedge clk)begin//{fr3,fr2,fr1}的输出逻辑
        if(reset) begin
            {fr3,fr2,fr1}<=3'b111;
        end
        else begin
            case(next_state)
                L1:{fr3,fr2,fr1}<=3'b111;
                B21:{fr3,fr2,fr1}<=3'b011;
                B32:{fr3,fr2,fr1}<=3'b001;
                H3:{fr3,fr2,fr1}<=3'b000;
                default:{fr3,fr2,fr1}<=3'b111;
            endcase
        end
    end
    always @(posedge clk)begin//dfr的输出逻辑
        if(reset) begin
            dfr<=1'b1;
        end
        else begin
            if(next_state<current_state) begin
                 dfr<=1'b1;
            end
            else if(next_state>current_state) begin
                dfr<=1'b0;                
            end
            else 
                dfr<=dfr;
        end  
    end
endmodule

lemmings 1

0837e6b840574b1e8c96da8a92ddc609.png

用摩尔状态机实现,两种状态LEFT和RIGHT,两个输入bump_left和bump_right,两个输出walk_left和walk_right;

状态转移图:

efd2322b33e94200b2c2a07adab286dc.png

代码:

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 current_state, next_state;

    always @(*) begin// State transition logic
        case(current_state)
            LEFT:next_state=bump_left?RIGHT:LEFT;
            RIGHT:next_state=bump_right?LEFT:RIGHT;
            default:next_state=LEFT;
        endcase
    end

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

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

endmodule

lemmings 29376ed577e6d4d2bb8f35d17796402ee.png

优先级:下落>碰撞,所以下落时候无视碰撞信号

用摩尔状态机实现,四种状态LEFT、RIGHT、FALL_LEFT和FALL_RIGHT,三个输入bump_left、 bump_right和ground,三个输出walk_left、walk_right和aaah

状态转移图(粗黑色箭头代表areset复位到的状态):

12eeaba98f134e5583e5e09ca0f87199.jpeg

代码:

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=4'b0001,RIGHT=4'b0010,FALL_LEFT=4'b0100,FALL_RIGHT=4'b1000;
    reg [3:0]current_state,next_state;
    
    always@(*)begin主控状态转移逻辑
        case(current_state)
            LEFT:begin
                if(!ground) begin//地面消失,向左下落
                    next_state=FALL_LEFT;
                end
                else begin//在地面上向左走
                    if(bump_left) begin//碰撞改向右走
                        next_state=RIGHT;
                    end
                    else begin
                        next_state=LEFT;//没碰撞继续向左走
                    end
                end
            end
            RIGHT:begin
                if(!ground) begin//地面消失,向右下落
                    next_state=FALL_RIGHT;
                end
                else begin//在地面上向右走
                    if(bump_right) begin//碰撞改向左走
                        next_state=LEFT;
                    end
                    else begin
                        next_state=RIGHT;//没碰撞继续向右走
                    end
                end
            end
            FALL_LEFT:begin
                if(ground) begin
                    next_state=LEFT;
                end
                else begin
                    next_state=FALL_LEFT;
                end
            end
            FALL_RIGHT:begin
                if(ground) begin
                    next_state=RIGHT;
                end
                else begin
                    next_state=FALL_RIGHT;
                end
            end
            default:next_state=LEFT;
        endcase
    end
    
    always @(posedge clk or posedge areset)begin//主控执行逻辑
        if(areset) begin
            current_state<=LEFT;
        end
        else begin
            current_state<=next_state;
        end
    end
    //输出逻辑    
    assign walk_left=(current_state==LEFT);
    assign walk_right=(current_state==RIGHT);
    assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT)); 
        
endmodule

lemmings 3

71b40a61ca934dc782588bd9c5ca5f6f.png

用摩尔状态机实现,六种状态LEFT、RIGHT、FALL_LEFT、FALL_RIGHT、DIG_LEFT和DIG_RIGHT,四个输入bump_left、 bump_right、dig和ground,四个输出walk_left、walk_right、aaah和digging

优先级:fall>dig>bump,下落和挖掘时候忽略碰撞输入信号,下落时候忽略挖掘信号

状态转移图(粗黑色箭头代表areset复位到的状态):

a156987fa4d141a7a24854d4d5a1165d.jpeg

代码:

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=6'b000001,RIGHT=6'b000010,DIG_LEFT=6'b000100,DIG_RIGHT=6'b001000,FALL_LEFT=6'b010000,FALL_RIGHT=6'b100000;
    reg [5:0]current_state,next_state;
    
    always@(*)begin//主控状态转移逻辑
        case(current_state)
            LEFT:begin
                if(!ground) begin
                    next_state=FALL_LEFT;//地面消失下落
                end
                else begin//有地面
                    if(dig) begin//挖掘
                        next_state=DIG_LEFT;
                    end
                    else if(bump_left) begin//不挖掘碰撞了向右走
                        next_state=RIGHT;
                    end
                    else begin//不挖掘不碰撞继续向左走
                        next_state=LEFT;
                    end
                end
            end
            RIGHT:begin
                if(!ground) begin
                    next_state=FALL_RIGHT;//地面消失下落
                end
                else begin//有地面
                    if(dig) begin//挖掘
                        next_state=DIG_RIGHT;
                    end
                    else if(bump_right) begin//不挖掘碰撞了向左走
                        next_state=LEFT;
                    end
                    else begin//不挖掘不碰撞继续向右走
                        next_state=RIGHT;
                    end
                end
            end
            DIG_LEFT:begin
                if(!ground) begin
                    next_state=FALL_LEFT;
                end
                else begin
                    next_state=DIG_LEFT;
                end
            end
            DIG_RIGHT:begin
                if(!ground) begin
                    next_state=FALL_RIGHT;
                end
                else begin
                    next_state=DIG_RIGHT;
                end
            end
            FALL_LEFT:begin
                if(ground) begin
                    next_state=LEFT;
                end
                else begin
                    next_state=FALL_LEFT;
                end
            end
            FALL_RIGHT:begin
                if(ground) begin
                    next_state=RIGHT;
                end
                else begin
                    next_state=FALL_RIGHT;
                end
            end
            default:next_state=LEFT;
        endcase        
    end
    
    always@(posedge clk or posedge areset)begin//主控执行逻辑
        if(areset) begin
            current_state<=LEFT;
        end
        else begin
           current_state<=next_state; 
        end
    end
    //输出逻辑
    assign walk_left=(current_state==LEFT);
    assign walk_right=(current_state==RIGHT);
    assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT));
    assign digging=((current_state==DIG_LEFT)||(current_state==DIG_RIGHT));
    
endmodule

lemmings 4

优先级:die>fall>dig>bump,死亡状态忽略任何输入信号,fall状态忽略dig和bump信号,dig状态忽略bump信号

0370e1ba4f5e4ebfa11a702e5956b416.png

用摩尔状态机实现,七种状态LEFT、RIGHT、FALL_LEFT、FALL_RIGHT、DIG_LEFT、DIG_RIGHT和DIE,四个输入bump_left、 bump_right、dig和ground,四个输出walk_left、walk_right、aaah和digging。

本题引入了下落超过20个周期落地会摔死飞溅的设定,所以需要编写一个计数器fallcount实现对下落周期的计数。

状态转移图(粗黑色箭头代表areset复位到的状态):

a4de45668c274ea995bb6f6a80c9fb8a.jpeg

lemmings4是在lemmings3的基础上完善的版本,这里对比lemmings3题目多了一个DIE状态,只有FALL_LEFT和FALL_RIGHT才可能转移成DIE状态,所以LEFT、RIGHT、DIG_LEFT、DIG_RIGHT这四个状态的转移逻辑没有变,直接copy过来就可以。输出逻辑的assign式子中没有DIE状态,即DIE状态四个assign式子的输出(walk_left、walk_right、aaah和digging)都为0,也满足了题干要求的“飞溅死亡后所有 4 个输出全变为 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 ); 
    parameter LEFT=7'b0000001,
              RIGHT=7'b0000010,
              DIG_LEFT=7'b0000100,
              DIG_RIGHT=7'b0001000,
              FALL_LEFT=7'b0010000,
              FALL_RIGHT=7'b0100000,
              DIE=7'b1000000;
    reg [6:0] current_state,next_state;
    reg [100:0]fallcount;
    
    always@(posedge clk or posedge areset)begin//主控状态执行逻辑
        if(areset) begin
            current_state<=LEFT;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always@(*)begin//主控状态转移逻辑
        case(current_state)
            LEFT:begin
                if(!ground) begin
                    next_state=FALL_LEFT;//地面消失下落
                end
                else begin//有地面
                    if(dig) begin//挖掘
                        next_state=DIG_LEFT;
                    end
                    else if(bump_left) begin//不挖掘碰撞了向右走
                        next_state=RIGHT;
                    end
                    else begin//不挖掘不碰撞继续向左走
                        next_state=LEFT;
                    end
                end
            end
            RIGHT:begin
                if(!ground) begin
                    next_state=FALL_RIGHT;//地面消失下落
                end
                else begin//有地面
                    if(dig) begin//挖掘
                        next_state=DIG_RIGHT;
                    end
                    else if(bump_right) begin//不挖掘碰撞了向左走
                        next_state=LEFT;
                    end
                    else begin//不挖掘不碰撞继续向右走
                        next_state=RIGHT;
                    end
                end
            end
            DIG_LEFT:begin
                if(!ground) begin
                    next_state=FALL_LEFT;
                end
                else begin
                    next_state=DIG_LEFT;
                end
            end
            DIG_RIGHT:begin
                if(!ground) begin
                    next_state=FALL_RIGHT;
                end
                else begin
                    next_state=DIG_RIGHT;
                end
            end
            FALL_LEFT:begin
                if(!ground) begin//没有地面则继续下落
                    next_state=FALL_LEFT;
                end
                else begin
                    if(fallcount<='d20) begin//下落20个周期内落地,继续向左走
                        next_state=LEFT;
                    end
                    else begin//下落20个周期以上落地,死
                        next_state=DIE;
                    end 
                end
            end
            FALL_RIGHT:begin
                if(!ground) begin//没有地面则继续下落
                    next_state=FALL_RIGHT;
                end
                else begin
                    if(fallcount<='d20) begin//下落20个周期内落地,继续向左走
                        next_state=RIGHT;
                    end
                    else begin//下落20个周期以上落地,死
                        next_state=DIE;
                    end 
                end
            end
            DIE:begin
                    next_state=DIE;//除非异步复位areset,否则永远保持在死亡状态
            end
            default:next_state=LEFT;
        endcase
    end
    
    always@(posedge clk or posedge areset)begin//fallount对旅鼠下落周期计数
        if(areset) begin
            fallcount<='d0;
        end
        else if((next_state==FALL_LEFT)||(next_state==FALL_RIGHT))begin//下一个状态仍然下落继续计数
            fallcount<=fallcount+'d1;
        end 
        else begin//下一个周期不下落则计数归0
            fallcount<='d0;
        end
    end
    //输出逻辑
    assign walk_left=(current_state==LEFT);
    assign walk_right=(current_state==RIGHT);
    assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT));
    assign digging=((current_state==DIG_LEFT)||(current_state==DIG_RIGHT));
    
endmodule

one-hot FSM

0d38bc26053143ada0f2fd6672ac7f86.png

要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。

可参考:Fsm3onehot - HDLBits (01xz.net)

module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);
    assign next_state[0]=(~in&state[0])|(~in&state[1])|(~in&state[2])|(~in&state[3])|(~in&state[4])|(~in&state[7])|(~in&state[8])|(~in&state[9]);
    assign next_state[1]=(in&state[0])|(in&state[8])|(in&state[9]);
    assign next_state[2]=(in&state[1]);
    assign next_state[3]=(in&state[2]);
    assign next_state[4]=(in&state[3]);
    assign next_state[5]=(in&state[4]);
    assign next_state[6]=(in&state[5]);
    assign next_state[7]=(in&state[6])|(in&state[7]);
    assign next_state[8]=(~in&state[5]);
    assign next_state[9]=(~in&state[6]);
    
    assign out1=(state[8]|state[9]);
    assign out2=(state[7]|state[9]);

endmodule

PS/2 packet parser

61d20c16cbf142ec92cbe6e20ddc6db7.png

用摩尔状态机实现,四个状态WAIT、BYTE1、BYTE2、BYTE3,一个输入in,一个输出done

状态转移图:

b922cd6f5ddd45728e193ad74d72ef89.jpeg

代码:

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done); //
    parameter WAIT=4'b0001,BYTE1=4'b0010,BYTE2=4'b0100,BYTE3=4'b1000;
    reg [3:0]current_state,next_state;
    
    always@(posedge clk)begin
        if(reset) begin
            current_state<=WAIT;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            WAIT:begin//等待状态
                if(in[3])begin//in[3]为1,字节流有效,接收字节流数据
                    next_state=BYTE1;
                end
                else begin//否则,字节流无效,丢弃数据继续等待
                    next_state=WAIT;
                end
            end
            BYTE1:begin
                 next_state=BYTE2;
            end
            BYTE2:begin
                 next_state=BYTE3;
            end
            BYTE3:begin
                if(in[3])beginin[3]为1,字节流有效,接收字节流数据
                   next_state=BYTE1; 
                end
                else begin//否则,字节流无效,丢弃数据开始等待状态
                   next_state=WAIT; 
                end
            end
        endcase
    end
                    
    assign done=(current_state==BYTE3);

endmodule

PS/2 packet parser and datapath

这题对比上一题状态机的设计是一样的,所以直接copy过来就好。要求再添加一个24 位(3 字节)的数据路径out_bytes用来传输接收到的3字节数据包。

根据题意,该协议一次发送3字节的数据,这里我有两种理解方法:

一、3字节数据串行传输

如果串行传输,out_bytes可看作一个以字节为单位的左移移位寄存器(因为byte1先被送来),数据流是这样传输的:

a647c63bc1e04720bef0689702216a64.jpeg

题目还要求done信号有效时,out_bytes也需要是有效的,当然也可以在其他时间传输任何内容(即其他时间对out_bytes是否传输不做要求),可以看时序图来理解

500f27c9bb4a463691762da45984f1ea.png

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output reg[23:0] out_bytes,
    output done); 
    // FSM from fsm_ps2
    parameter WAIT=4'b0001,BYTE1=4'b0010,BYTE2=4'b0100,BYTE3=4'b1000;
    reg [3:0]current_state,next_state;
    
    always@(posedge clk)begin
        if(reset) begin
            current_state<=WAIT;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            WAIT:begin
                if(in[3])begin
                    next_state=BYTE1;
                end
                else begin
                    next_state=WAIT;
                end
            end
            BYTE1:begin
                 next_state=BYTE2;
            end
            BYTE2:begin
                 next_state=BYTE3;
            end
            BYTE3:begin
                if(in[3])begin
                   next_state=BYTE1; 
                end
                else begin
                   next_state=WAIT; 
                end
            end
        endcase
    end
                    
    
    // New: Datapath to store incoming bytes.
    always @(posedge clk)begin//串行传输
        if(reset)begin
            out_bytes<=24'b0;
        end
        else if(next_state==BYTE1) begin//BYTE1/2/3状态下in输入是有效数据会被接收,接收完串行传输给out_bytes
            out_bytes<={out_bytes[15:0],in}; 
        end
        else if(next_state==BYTE2) begin
            out_bytes<={out_bytes[15:0],in}; 
        end
        else if(next_state==BYTE3) begin
            out_bytes<={out_bytes[15:0],in}; 
        end
        else begin//WAIT状态in输入是无效数据会被丢弃,out_bytes不会被更新
            out_bytes<=out_bytes;
        end
    end
    
    assign done=(current_state==BYTE3);   
        
endmodule

BYTE1/2/3状态下in输入是有效数据会被接收,接收完传输给out_bytes;而且因为是非阻塞赋值,

所以数据传输是这样的:

4e3263cbc84a4ba98e25c235ae167760.png

二、3字节数据并行传输

如图,代码一看就懂

2013005f39994fa99eedff590b9af3db.jpeg

    always @(posedge clk)begin//并行传输
        if(reset)begin
            out_bytes<=24'b0;
        end
        else if(next_state==BYTE1) begin//BYTE1/2/3状态下in输入是有效数据会被接收,并行传输给out_bytes
            out_bytes<={in,out_bytes[15:0]}; 
        end
        else if(next_state==BYTE2) begin
            out_bytes<={out_bytes[23:16],in,out_bytes[7:0]}; 
        end
        else if(next_state==BYTE3) begin
            out_bytes<={out_bytes[23:8],in}; 
        end
        else begin//WAIT状态in输入是无效数据会被丢弃,out_bytes不会被更新
            out_bytes<=out_bytes;
        end
    end

serial receiver

2ced17c7946442d0a3e989d2645f9a26.png

用摩尔状态机实现,五个状态IDLE、START、DATA、STOP和WAIT,一个输入in,一个输出done。

状态转移图:

79cc6c79f40849f583125b86d9de3b30.jpeg

需要注意的是,START模式传输数据最终有两种可能:

正确传输,跳转到STOP模式;或者错误传输,跳转到WAIT模式。所以STOP和WAIT模式不会在一次8位数据传输中都出现,两者是互斥的关系,所以不会有STOP和WAIT状态之间的转换。

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output reg done
); 
    parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
    reg [4:0]current_state,next_state;
    reg [3:0]data_count;
    
    always @(posedge clk)begin//主控执行逻辑
        if(reset)begin
            current_state<=IDLE;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin//状态转移逻辑
        case(current_state) 
            IDLE:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            START:begin
                next_state=DATA;
            end
            DATA:begin
                if(data_count==8&&in==1)begin
                    next_state=STOP;
                end
                else if(data_count==8&&in==0)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=DATA;
                end
            end
            STOP:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            WAIT:begin
                if(!in)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=IDLE;
                end
            end
            default:next_state=IDLE;
        endcase
        
    end
    
    always @(posedge clk)begin//给DATA状态接收到的数据的位数计数
        if(reset)begin
            data_count<=4'h0;
        end
        else if(next_state==DATA)begin
            data_count<=data_count+4'h1;
        end        
        else begin
            data_count<=4'h0;
        end
    end
    
    always @(posedge clk)begin//输出逻辑
        if(next_state==STOP)
            done<=1;
        else
            done<=0;
    end
    
endmodule

serial receiver and datapath

6c27a3c1a75748a4a026335c417273c5.png

这题对比上一题状态机的设计是一样的,所以直接copy过来就好。要求再添加一个8位(1字节)的数据路径out_byte用来传输(寄存)接收到的有效数据。

根据题意,out_byte是8位宽的数据传输路径,in输入一次发送的也是8位,所以out_byte恰好可以寄存一次的数据,该协议首先发送最低有效位。这里我有两种理解方法:

一、8位数据串行传输

也就是将out_byte看作一个以位为单位的移位寄存器。因为串行协议首先发送出最低有效位,最先送到out_byte的也是最低有效位,所以数据流传输方向如下(这样8位数据全部装入out_byte后最低有效位在out_byte[0],没有大小端颠倒。如果数据流是左移且最低有效位先传入,8位数据全部装入out_byte后最低有效位在out_byte[7],大小端颠倒,数据传输出现错误):

55aad6e5ea2c4c8aa6bc88049fb0665d.jpeg

代码如下:

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output reg done
); 
    // Use FSM from Fsm_serial
    parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
    reg [4:0]current_state,next_state;
    reg [3:0]data_count;
    
    always @(posedge clk)begin//主控执行逻辑
        if(reset)begin
            current_state<=IDLE;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin//状态转移逻辑
        case(current_state) 
            IDLE:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            START:begin
                next_state=DATA;
            end
            DATA:begin
                if(data_count==8&&in==1)begin
                    next_state=STOP;
                end
                else if(data_count==8&&in==0)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=DATA;
                end
            end
            STOP:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            WAIT:begin
                if(!in)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=IDLE;
                end
            end
            default:next_state=IDLE;
        endcase
        
    end
    
    always @(posedge clk)begin
        if(reset)begin
            data_count<=4'h0;
        end
        else if(next_state==DATA)begin
            data_count<=data_count+4'h1;
        end        
        else begin
            data_count<=4'h0;
        end
    end
    
    always @(posedge clk)begin
        if(next_state==STOP)
            done<=1;
        else
            done<=0;
    end    
    // New: Datapath to latch input bits.
    always @(posedge clk)begin
        if(reset)begin
            out_byte<=8'b0;
        end
        else if(next_state==DATA)begin
            out_byte<={in,out_byte[7:1]};//DATA状态输入的数据,串行传输寄存到out_byte中
        end
        else begin
            out_byte<=out_byte;//没有接收有效数据,out_byte不会被更新
        end
    end

endmodule

一、8位数据并行传输

该协议首先发送最低有效位,DATA状态的第1个clk内,data_count为0,in寄存在out_byte[0]中,第2个clk内,data_count为1,in寄存在out_byte[1]中,后面到第8个clk同理。

ec381c00019d4a13ab08ffd68aaf3a17.jpeg

out_byte段的代码改为

always @(posedge clk)begin
        if(reset)begin
            out_byte<=8'b0;
        end
        else if(next_state==DATA)begin//DATA状态输入的数据,并行传输寄存到out_byte中
            out_byte[data_count]<=in;//注意不是out_byte[data_count-1]<=in;
        end
        else begin
            out_byte<=out_byte;//没有接收有效数据,out_byte不会被更新
        end
    end

其实只是把out_byte段的

out_byte<={in,out_byte[7:1]};

改成了

out_byte[data_count]<=in;

(易错)注意不要写成

out_byte[data_count-1]<=in;

例:现在是START状态,data_count为0,下一clk是DATA状态第一个clk(next_state==DATA),记为DATA1。当上升沿(posedge clk)到来,从START→DATA时刻:

data_count段执行:

data_count<=data_count+4'h1

非阻塞赋值,加1后data_count变为1

同一时刻out_byte段并行执行:

out_byte[data_count]<=in;

但因为上面data_count 是非阻塞赋值,所以这一句中data_count还是旧值0,这样DATA状态第1个clk输入in装入data_count[0]

类推在DATA第8个(最后1个)clk,data_count加1变为8(满足data_count==8,下一状态转变成STOP/WAIT),输入in装入data_count[7],即DATA状态完成了8 bit输入in装入[7:0]data_count。

serial receiver with parity checking

8ef41d6878ca471bae40e1f9af47f79b.png

本题在上一题的基础上进行奇偶校验的奇校验,在每个数据字节后添加一个额外的校验位,用于检测正确性(这一位用来检测传输的数据是否正确,不是真正有用的数据,所以传输给out_byte时候要丢弃这一位)

对比上一题, 需要更改的有以下几个

1.声明一个data_in中间的寄存器,存8位数据data_in[7:0]和奇校验位data_in[8],之后把data_in[7:0]传给out_byte,丢弃奇校验位

2.因为中间DATA多了一位,DATA转到WAIT或者STOP模式的判断条件从data_count==8改为data_count==9

3.写data_in数据传输逻辑(这里我写的数据并行传输)和重写out_byte段数据传输逻辑

4.注意odd位是奇校验位,odd为1说明奇校验通过,所以done=1的判断条件要有odd==1,out_byte<=data_in的判断条件要有odd==1。

e8817b12e0944e32ab7c395a72a5851a.jpeg

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output reg done
); 
    // Modify FSM and datapath from Fsm_serialdata
    parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
    reg [4:0]current_state,next_state;
    reg [3:0]data_count;
    reg odd;
    reg [8:0]data_in;
    
    always @(posedge clk)begin//主控执行逻辑
        if(reset)begin
            current_state<=IDLE;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin//状态转移逻辑
        case(current_state) 
            IDLE:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            START:begin
                next_state=DATA;
            end
            DATA:begin
                if(data_count==9&&in==1)begin
                    next_state=STOP;
                end
                else if(data_count==9&&in==0)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=DATA;
                end
            end
            STOP:begin
                if(!in)begin
                    next_state=START;
                end
                else begin
                    next_state=IDLE;
                end
            end
            WAIT:begin
                if(!in)begin
                    next_state=WAIT;
                end
                else begin
                    next_state=IDLE;
                end
            end
            default:next_state=IDLE;
        endcase
        
    end
    
    always @(posedge clk)begin//对接收到的数据位数计数
        if(reset)begin
            data_count<=4'h0;
        end
        else if(next_state==DATA)begin
            data_count<=data_count+4'h1;
        end        
        else begin
            data_count<=4'h0;
        end
    end
    
    always @(posedge clk)begin
        if(next_state==STOP&&odd==1)在STOP状态且校验通过才认为传输的数据正确有效,done为1
            done<=1;
        else
            done<=0;
    end    
    // New: Datapath to latch input bits.
    always @(posedge clk)begin//data_in的数据传输逻辑
        if(reset)begin
           data_in<=8'b0; 
        end
        else if(next_state==DATA)begin//DATA状态接收数据时,data_in进行数据传输
            data_in<={in,data_in[8:1]};//数据串行传输
        end
        else begin
            data_in<=data_in;//没有接收有效数据,data_in不会被更新
        end
    end
    always @(posedge clk)begin//out_byte的数据传输逻辑
        if(reset)begin
           out_byte<=8'd0;
        end
        else if(next_state==STOP&&odd==1)begin//在STOP状态且校验通过才把data_in[7:0]赋给out_byte
            out_byte<=data_in[7:0];
        end
        else begin
            out_byte<=8'd0;
        end
    end
     
    // New: Add parity checking.
    parity parity_1(clk,(next_state==START),in,odd);//奇校验,进入START状态时,即开始新的1byte数据传输,odd状态复位

endmodule

如果想写数据串行传输,只需要把data_in部分的

data_in[data_count]<=in;

改为

data_in<={in,data_in[8:1]};

sequence recognitio

序列识别状态机

e68dc640dfab48baad818368b593479d.png

用摩尔状态机实现,十个状态(其中ONE到SIX状态代表检测到第几个1),一个输入in,三个输出disc、err、flag

状态转移图:

d1cb3677f11449c18ddda6710b92ea07.jpeg

题目只是要我们识别这三种状态,其他如何丢弃等等更多细节不需要关心,所以代码如下:

module top_module(
    input clk,
    input reset,    // Synchronous reset
    input in,
    output disc,
    output flag,
    output err);
    parameter IDLE=4'd0,ONE=4'd1,TWO=4'd2,THREE=4'd3,FOUR=4'd4;
    parameter FIVE=4'd5,SIX=4'd6,DISC=4'd7,FLAG=4'd8,ERROR=4'd9;
    reg [3:0]current_state,next_state;
    
    always@(posedge clk)begin
        if(reset)begin
           current_state<=IDLE; 
        end
        else begin
           current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            IDLE:next_state=in?ONE:IDLE;
            ONE:next_state=in?TWO:IDLE;
            TWO:next_state=in?THREE:IDLE;
            THREE:next_state=in?FOUR:IDLE;
            FOUR:next_state=in?FIVE:IDLE;
            FIVE:next_state=in?SIX:DISC;
            SIX:next_state=in?ERROR:FLAG;
            DISC:next_state=in?ONE:IDLE;
            FLAG:next_state=in?ONE:IDLE;
            ERROR:next_state=in?ERROR:IDLE;
            default:next_state=IDLE;
        endcase
    end
    
    assign disc=(current_state==DISC);
    assign flag=(current_state==FLAG);
    assign err=(current_state==ERROR);

endmodule

Q8:design a Mealy FSM

题目描述:实现一个 Mealy 型有限状态机,该机可识别 输入x 上的序列 “101”。 FSM 有一个输出信号 z,当检测到 “101” 序列时,z被置位为 logic-1。异步低电平复位。要求状态机必须写 3 种状态。FSM 应识别重叠序列,如10101识别出两次“101”

序列识别状态机

根据题意画如下状态转移图:

174623cbe6bb4d578b22566079cfe1bf.jpeg

状态中,S1是输入为???,S2是输入为1??,S3是输入为10?

module top_module (
    input clk,
    input aresetn,    // Asynchronous active-low reset
    input x,
    output z ); 
    parameter S1=3'b001,S2=3'b010,S3=3'b100;//S1是输入为???,S2是输入为1??,S3是输入为10?.
    reg [2:0]current_state,next_state;
    always @(posedge clk or negedge aresetn)begin
        if(!aresetn)begin
            current_state<=S1;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            S1:next_state=x?S2:S1;
            S2:next_state=x?S2:S3;
            S3:next_state=x?S2:S1;//识别重叠序列,10101中间的1既是第一个101的后一个1,也是第二个101的前一个1,所以S3状态下x为1,next_state是S2
            default:next_state=S1;
        endcase
    end
    
    assign z=(current_state==S3&&x==1);//代表是101序列
    
endmodule

Q5b:serial two's complementer(Mealy FSM)

我把Q5a和Q5b顺序反过来了,这样分析更符合逻辑更合适

本题为米利状态机,两个状态,一个输入x,一个输出z,首先是根据状态转移图无脑暴力解法

7ce1527d070a486c86900a02dd4ce886.png

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
    parameter A=2'b01,B=2'b10;
    reg [1:0]current_state,next_state;
    always @(posedge clk or posedge areset)begin
        if(areset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            A:next_state=x?B:A;
            B:next_state=B;
            default:next_state=A;
        endcase
    end
    
    assign z=(current_state==A&&x==1)|(current_state==B&&x==0);
endmodule

可以更深层次的思考:

2cd45a7a93d14eaea63dec158f0f36d2.png

正数补码是他本身,负数补码是数值位取反+1,下面我们只看负数的数值位:

原码:00110100,取反为11001011,再+1为11001100,所以负数取反还有另一种理解方式,就是从最低位数出现的第一个1的位往下的位都不变(本题100不变),往上的数值位全取反(本题00110变为11001)

本题米利状态机给的状态转移图,A状态就是低位位不变的部分,所以输出位z与输入位x相同,B状态是高位位取反的部分,所以输出位z与输入位x相反。A状态在x=1时代表从低位开始输入遇到了第一个1,再往上的位要取反了,所以变为B状态。

7ce1527d070a486c86900a02dd4ce886.png

理解了这个意思后,我们可以有另一种输出逻辑

    always@(*)begin
        case(current_state)
            A:z=x;
            B:z=~x;
            default:z=x;
        endcase
    end

Q5a:serial two's complementer(Moore FSM)

题目给的那个时序图是错误的,正确时序图应该是这样子

2cd45a7a93d14eaea63dec158f0f36d2.png

基于上一题的分析,我们可以设置本题的Moore状态机

A状态(低位位不变且输入为0)、B状态(低位位不变且输入为1)、C状态(高位位取反且输入为0)、D状态(高位位取反且输入为1),例如(该例中的数认为是负数,且只写出了数值位)

原码:00110100,补码:11001100,低3位是位不变(110),高5位是位取反(00110变为11001),这8位对应状态为CCDDCBAA

理解了这些状态的意思,画状态转移图

656cfda8fb7d4aa6b293115669d8338d.jpeg

代码如下:

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
    parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
    reg [1:0]current_state,next_state;
    always @(posedge clk or posedge areset)begin
        if(areset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            A:next_state=x?B:A;
            B:next_state=x?D:C;
            C:next_state=x?D:C;
            D:next_state=x?D:C;
            default:next_state=A;
        endcase
    end
    
    always@(*)begin
        case(current_state)
            A:z=0;
            B:z=1;
            C:z=1;
            D:z=0;
            default:z=0;
        endcase
    end

endmodule

Q3a:FSM

A是复位状态。当s为1,下一个clk进入状态B,进入状态B就监测输入w,每3个clk输入的w有两个1一个0(101/110/011),下一clk就把z置1,时序图如下

bb258c14dff24c738cd992e88a93e5d1.png

根据题目状态转移图的提示,我稍微修改一下

用mealy状态机实现,两个输入s和w,一个输出z,四个状态(A是复位状态,B1是B状态每轮监测w输入3个clk的第1个clk,B2是B状态每轮监测w输入3个clk的第2个clk,B3是B状态每轮监测w输入3个clk的第3个clk)

状态转移图:a3398d84f2ee4e2da0add46c2f233380.jpeg

一个错误的写法:

module top_module (
    input clk,
    input reset,   // Synchronous reset
    input s,
    input w,
    output z
);
    parameter A=2'b00,B1=2'b01,B2=2'b10,B3=2'b11;
    reg [1:0]current_state,next_state;
    reg w1,w2,w3;
    
    always @(*)begin//状态转移逻辑
        case(current_state)
            A:next_state=s?B1:A;
            B1:next_state=B2;
            B2:next_state=B3;
            B3:next_state=B1;
            default:next_state=A;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(posedge clk)begin
        if(reset)begin
            {w1,w2,w3}<=3'b000; 
        end
        else if(next_state==B1)begin
            w1<=w?1'b1:1'b0;//寄存B1状态w的数据
        end
        else if(next_state==B2)begin
            w2<=w?1'b1:1'b0;//寄存B2状态w的数据
        end
        else if(next_state==B3)begin
            w3<=w?1'b1:1'b0;//寄存B3状态w的数据
        end
        else begin
            w1<=w1;
            w2<=w2;
            w3<=w3; 
        end
    end
    
    assign z=({w1,w2,w3}==3'b011||{w1,w2,w3}==3'b101||{w1,w2,w3}==3'b110);
    
endmodule

看仿真时序图是这样的

343c8facb3ae4d10b4df8f4258a067e6.png

根据时序图可以知道,这里把w1w2w3复位都置0,刚进入B状态,在第一个B1状态w为1所以把w1置1,第一个B2状态w为1所以把w2置1,这样满足了{w1,w2,w3}为1,下一个clk(第一个B3状态)时候就会输出z为1(监测到了{w1,w2,w3}为110,但是这个w3为0是A状态复位的默认值),这不是我们要的结果,出现错误

我们想要的是监测一轮完整B1B2B3状态(也就是三个clk),如果满足{w1,w2,w3}=110/101/011,在下一个clk(也就是下一轮的B1状态)输出z=1,所以修正assign z的输出条件,代码:

module top_module (
    input clk,
    input reset,   // Synchronous reset
    input s,
    input w,
    output z
);
    parameter A=2'b00,B1=2'b01,B2=2'b10,B3=2'b11;
    reg [1:0]current_state,next_state;
    reg w1,w2,w3;
    
    always @(*)begin//状态转移逻辑
        case(current_state)
            A:next_state=s?B1:A;
            B1:next_state=B2;
            B2:next_state=B3;
            B3:next_state=B1;
            default:next_state=A;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(posedge clk)begin
        if(reset)begin
            {w1,w2,w3}<=3'b000; 
        end
        else if(next_state==B1)begin
            w1<=w?1'b1:1'b0;//寄存B1状态w的数据
        end
        else if(next_state==B2)begin
            w2<=w?1'b1:1'b0;//寄存B2状态w的数据
        end
        else if(next_state==B3)begin
            w3<=w?1'b1:1'b0;//寄存B3状态w的数据
        end
        else begin
            w1<=w1;
            w2<=w2;
            w3<=w3; 
        end
    end
    
    assign z=(current_state==B1)&&({w1,w2,w3}==3'b011||{w1,w2,w3}==3'b101||{w1,w2,w3}==3'b110);
    //加了current_state==B1的条件,确保{w1,w2,w3}的值都是上一轮B1B2B3状态新得到的w数据
    
endmodule

Q3b:FSM

9863bdf521d845de9a1c17eb65a1a8bd.png

根据状态转移表写状态机(y代表现态,Y代表次态)

module top_module (
    input clk,
    input reset,   // Synchronous reset
    input x,
    output z
);
    parameter Y0=3'b000,Y1=3'b001,Y2=3'b010,Y3=3'b011,Y4=3'b100;
    reg [2:0]current_state,next_state;
    
    always @(posedge clk)begin
        if(reset)begin
            current_state<=Y0;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            Y0:next_state=x?Y1:Y0;
            Y1:next_state=x?Y4:Y1;
            Y2:next_state=x?Y1:Y2;
            Y3:next_state=x?Y2:Y1;
            Y4:next_state=x?Y4:Y3;
            default:next_state=Y1;
        endcase
    end
    
    assign z=(current_state==Y3)|(current_state==Y4);
endmodule

Q3c:FSM logic

这个题虽然给的背景是状态机,也给了clk信号,但是让实现的是组合逻辑函数Y0和z,所以本质就是组合逻辑问题

ddfa3dc260a94a0eafe8a1017d687fa9.png

(y代表现态,Y代表次态)

module top_module (
    input clk,
    input [2:0] y,
    input x,
    output Y0,
    output z
);
    always @(*)begin
        case(y)
            3'b000:Y0=x?1:0;
            3'b001:Y0=x?0:1;
            3'b010:Y0=x?1:0;
            3'b011:Y0=x?0:1;
            3'b100:Y0=x?0:1;
            default:Y0=0;
        endcase
    end
    assign z = (y == 3'b011) | (y == 3'b100);

endmodule

第二种写法:parameter定义

module top_module (
    input clk,
    input [2:0] y,
    input x,
    output Y0,
    output z
);
    parameter A=3'b000,B=3'b001,C=3'b010,D=3'b011,E=3'b100;
    reg [2:0]Y;
    always @(*)begin
        case(y)
            A:Y=x?B:A;
            B:Y=x?E:B;
            C:Y=x?B:C;
            D:Y=x?C:B;
            E:Y=x?E:D;
            default:Y=A;
        endcase
    end
    assign Y0=Y[0];
    assign z = (y==D)|(y==E);

endmodule

Q6b:FSM next_state logic

1e64b74952d74f58b0ec2159b1843af0.png

本题题目要求用y[3:1]=000,001,010,011,100,101分别代表A,B,C,D,E,F状态,根据状态转移图作状态转移表

0acafa21bee244b89cecbdda51058654.jpeg

代码如下:

module top_module (
    input [3:1] y,
    input w,
    output Y2);
    parameter A=3'b000,B=3'b001,C=3'b010,D=3'b011,E=3'b100,F=3'b101;
    reg [3:1]Y;
    always @(*)begin
        case(y)
            A:Y=w?A:B;
            B:Y=w?D:C;
            C:Y=w?D:E;
            D:Y=w?A:F;
            E:Y=w?D:E;
            F:Y=w?D:C;
            default:Y=A;
        endcase
    end
    assign Y2=Y[2];
endmodule

Q6c:FSM one-hot next-state logic

可参考题目:Fsm3onehot - HDLBits (01xz.net)

Fsm onehot - HDLBits (01xz.net)

本题状态转移逻辑和上一题相同,状态转移图也相同。题目要求用独热码来编码,用y[6:1]=000001,000010,000100,001000,010000,100000代表A,B,C,D,E,F状态。

状态转移表和上题相同,但编码不同(本题用独热码),要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。

05101be7eb8243738c01f00bddd26b8e.jpeg

module top_module (
    input [6:1] y,
    input w,
    output Y2,
    output Y4);
    parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
    reg [6:1]Y;
    always @(*)begin
        case(y)
            A:Y=w?A:B;
            B:Y=w?D:C;
            C:Y=w?D:E;
            D:Y=w?A:F;
            E:Y=w?D:E;
            F:Y=w?D:C;
            default:Y=A;
        endcase
    end
    assign Y2=(y[1]&~w);
    assign Y4=(y[2]&w)|(y[3]&w)|(y[5]&w)|(y[6]&w);

endmodule

Q6:FSM

1e64b74952d74f58b0ec2159b1843af0.png

按照状态转移图写状态机即可

module top_module (
    input clk,
    input reset,     // synchronous reset
    input w,
    output z);
    parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
    reg [5:0]current_state,next_state;
    
    always @(posedge clk)begin
        if(reset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            A:next_state=w?A:B;
            B:next_state=w?D:C;
            C:next_state=w?D:E;
            D:next_state=w?A:F;
            E:next_state=w?D:E;
            F:next_state=w?D:C;
            default:next_state=A;
        endcase
    end
    assign z=(current_state==E)||(current_state==F);

endmodule

Q2a:FSM

4c8467dbb45e452389c66890ace0ed3b.png

按照状态转移图写状态机即可

module top_module (
    input clk,
    input reset,     // synchronous reset
    input w,
    output z);
    parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
    reg [5:0]current_state,next_state;
    
    always @(posedge clk)begin
        if(reset)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state)
            A:next_state=w?B:A;
            B:next_state=w?C:D;
            C:next_state=w?E:D;
            D:next_state=w?F:A;
            E:next_state=w?E:D;
            F:next_state=w?C:D;
            default:next_state=A;
        endcase
    end
    assign z=(current_state==E)|(current_state==F);

endmodule

Q2b:one-hot FSM equations

可参考:Fsm3onehot - HDLBits (01xz.net)

Fsm onehot - HDLBits (01xz.net)

Exams/m2014 q6c - HDLBits (01xz.net)

本题状态转移图(逻辑)和上一题一样。另外本题其实和上面Q6c是一种题,只是状态转换逻辑不一样,本质思路是一样的,换汤不换药。

要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。

状态转移表:

d7d0447c1b56418697b353d92d629618.jpeg

代码:

module top_module (
    input [5:0] y,
    input w,
    output Y1,
    output Y3
);
    parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
    reg [5:0]Y;
    
    always @(*)begin
        case(y)
            A:Y=w?B:A;
            B:Y=w?C:D;
            C:Y=w?E:D;
            D:Y=w?F:A;
            E:Y=w?E:D;
            F:Y=w?C:D;
            default:Y=A;
        endcase
    end
    assign Y1=(y[0]&w);
    assign Y3=(y[1]&~w)|(y[2]&~w)|(y[4]&~w)|(y[5]&~w);
    
endmodule

Q2a:FSM

FSM 充当仲裁电路,它控制对某种类型资源的访问。每个设备通过设置请求信号r[i] = 1 来请求资源。 设备1、设备2、设备3的r[i] 分别是r[1] 、r[2] 、r[3],对应状态B、C、D。只要没有请求,FSM 就会保持状态A。当一个或多个请求发生,则 FSM 决定哪个设备优先使用资源,并且将该设备的g[i]信号设置为 1 。其中资源分配优先级:设备1>设备2>设备3

a2558ef685ce4b63bfab49f32e5576b9.png

module top_module (
    input clk,
    input resetn,    // active-low synchronous reset
    input [3:1] r,   // request
    output [3:1] g   // grant
); 
    parameter A=4'b0001,B=4'b0010,C=4'b0100,D=4'b1000;
    reg[3:0]current_state,next_state;
    
    always @(posedge clk)begin
        if(!resetn)begin
            current_state<=A;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always @(*)begin
        case(current_state) 
            A:begin
                casez(r) //请求优先级r1>r2>r3
                    3'bzz1:next_state=B;
                    3'bz10:next_state=C;
                    3'b100:next_state=D;
                    3'b000:next_state=A;
                    default:next_state=A;
                endcase
            end
            B:begin
                next_state=r[1]?B:A;
            end
            C:begin
                next_state=r[2]?C:A;
            end
            D:begin
                next_state=r[3]?D:A;
            end
            default:next_state=A;
        endcase
    end
    assign g[1]=(current_state==B);
    assign g[2]=(current_state==C);
    assign g[3]=(current_state==D);
    
endmodule

Q2b:another FSM

题目描述:有两个输入x和y,两个输出f和g,resetn是同步低电平复位,复位置在A状态,当复位信号无效时,下一个clk把f置为1保持(保持为1的时间为一个clk),f为1的clk之后监测x值。当监测到连续三个clk  输入x的序列为“101”时,下一个clk把g置为1同时开始监测y,从开始监测算起如果两个clk内出现y=1,就把g永远置1(除非复位resetn),否则把g永远置0(除非复位resetn)

分析:有两个输入x和y,两个输出f和g,设置9个状态,状态转移图如下:

370d58d4ab80435c856ba39fa2fa2e0d.jpeg

A状态是默认状态(复位到的状态),F是f=1的状态(维持一个clk),之后监测x,S1是x序列为???,S2是x序列为1??,S3是x序列为10?,x序列为101进入SS1状态开始监测y,SS1是监测y的第1个clk,SS2是监测y的第2个clk,FOREVER_1代表g永远为1的状态,FOREVER_0代表g永远为0的状态

module top_module (
    input clk,
    input resetn,    // active-low synchronous reset同步低电平复位
    input x,
    input y,
    output f,
    output g
); 
    parameter A=4'b0000,F=4'b0001,S1=4'b0010,S2=4'b0011,S3=4'b0100;
    parameter SS1=4'b0101,SS2=4'b0110,FOREVER_1=4'b0111,FOREVER_0=4'b1000;
    reg [3:0]current_state,next_state;
    //状态转移逻辑
    always @(*)begin
        case(current_state)
            A:next_state=F;
            F:next_state=S1;
            S1:next_state=x?S2:S1;
            S2:next_state=x?S2:S3;
            S3:next_state=x?SS1:S1;
            SS1:next_state=y?FOREVER_1:SS2;
            SS2:next_state=y?FOREVER_1:FOREVER_0;
            FOREVER_1:next_state=FOREVER_1;//除非复位,g永远为1
            FOREVER_0:next_state=FOREVER_0;//除非复位,g永远为0
            default:next_state=A;
        endcase
    end
    //状态执行逻辑
    always @(posedge clk)begin
        if(!resetn)begin
           current_state<=A; 
        end
        else begin
           current_state<=next_state; 
        end
    end
    //输出逻辑
    assign f=(current_state==F);
    always @(*)begin
        case(current_state)
            SS1:g=1;
            SS2:g=1;
            FOREVER_1:g=1;
            default:g=0;
        endcase
    end
endmodule

buliding lager circuits

counter with period 1000

807241f0b4604a32af143b90aa45c5c9.png

module top_module (
    input clk,
    input reset,
    output reg[9:0] q);
    always @(posedge clk)begin
        if(reset)
            q<=10'd0;
        else if(q==10'd999)
            q<=10'd0;
        else
            q<=q+10'd1;
    end
endmodule

4-bit shift register and down counter

本题是移位寄存器和递减计数器的结合

a468dcae61bf4b3c86231c8723a531ef.png

module top_module (
    input clk,
    input shift_ena,
    input count_ena,
    input data,
    output reg[3:0] q);
    always@(posedge clk)begin
        if(shift_ena)begin
            q<={q[2:0],data}; 
        end
        else if(count_ena==1)begin//q为4'b0000了还可以继续减1,向下溢出为4'b1111
            q<=q-4'b1;
        end
        else begin
            q<=q;
        end
    end
endmodule

FSM:sequence 1101 recognizer

序列识别状态机

d4498fa8295c417fb6e9db57fb59ac1f.png

一个输入data,一个输出start_shifting,五个状态(S1代表data序列为????,S2代表data序列为1???,S3代表data序列为11??,S4代表data序列为110?,当识别到序列1101后,进入START_SHIFT_1状态,表示start_shifting为1)

状态转移图

bad8a5168f784a30b83c5e7fb2081664.jpeg

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);
    parameter S1=3'b000,S2=3'b001,S3=3'b010,S4=3'b011,START_SHIFT_1=3'b100;
    reg [2:0]current_state,next_state;
    
    always @(*)begin
        case(current_state)
            S1:next_state=data?S2:S1;
            S2:next_state=data?S3:S1;
            S3:next_state=data?S3:S4;
            S4:next_state=data?START_SHIFT_1:S1;
            START_SHIFT_1:next_state=START_SHIFT_1;//识别到1101序列后,start_shifting 永远为1
            default:next_state=S1;
        endcase
    end
    always @(posedge clk)begin
        if(reset)begin
            current_state<=S1;
        end
        else begin
            current_state<=next_state; 
        end
    end
    
    assign start_shifting=(current_state==START_SHIFT_1);

endmodule

FSM:enable with register

本题是用reset信号控制shift_ena的状态机。

看时序图,reset为1,下一个clk进入复位到的IDLE状态,把shift_ena置1,当reset为0后,shift_ena保持为1四个clk(第一个clk还在IDLE状态,后面三个clk分别在SHIFT_ENA_2、SHIFT_ENA_3、SHIFT_ENA_4状态),再之后shift_ena永远为0(除非reset复位)

c89678f5992549ecb71aa073a3b9a3b9.png

设置状态机,一个输入reset,一个输出shift_ena,五个状态IDLE(复位到的状态)、SHIFT_ENA_2(reset为0后shift_ena保持为1的第2个clk)、SHIFT_ENA_3(reset为0后shift_ena保持为1的第3个clk)、SHIFT_ENA_4(reset为0后shift_ena保持为1的第4个clk)和FOREVER_0(shift_ena永远为0的状态)

状态转移图:

ef757a5c76a14f5280c7524c4f18cf10.jpeg

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    parameter IDLE=3'b000,SHIFT_ENA_2=3'b001,SHIFT_ENA_3=3'b010;
    parameter SHIFT_ENA_4=3'b011,FOREVER_0=3'b100;
    reg [2:0]current_state,next_state;
    
    always@(*)begin
        case(current_state)
            IDLE:next_state=SHIFT_ENA_2;
            SHIFT_ENA_2:next_state=SHIFT_ENA_3;
            SHIFT_ENA_3:next_state=SHIFT_ENA_4;
            SHIFT_ENA_4:next_state=FOREVER_0;
            FOREVER_0:next_state=FOREVER_0;
            default:next_state=IDLE;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)begin
            current_state<=IDLE;
        end
        else begin
            current_state<=next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            IDLE:shift_ena=1;
            SHIFT_ENA_2:shift_ena=1;
            SHIFT_ENA_3:shift_ena=1;
            SHIFT_ENA_4:shift_ena=1;
            FOREVER_0:shift_ena=0;
            default:shift_ena=0;
        endcase
    end

endmodule

FSM:the complete FSM

题目:要实现一个计时器(结合时序图来看)

1.当接收到data输入的“1101”序列就启动计时器开始工作,之后4个clk将shift_ena置1

2.shift_ena置1保持4个clk后开始计数(counting),等待接收到done_counting为1(通知计时器计时完成)就停止计数

3.停止计时后(done置1表示计时器计时完成)进入等待状态,等待用户确认,当用户确认后返回ack为1,计时器就从done为1的完成工作状态回到最初状态。

但本题只要实现控制计时器的有限状态机。不包括 data path (counters 和一些 comparators)

2a9aa38de33d4d72bda07b0a0024724e.png

输入有data、done_counting、ack,输出有shift_ena、counting、done,设置了十个状态。

S状态(data输入序列为“????”)、S1状态(data输入序列为“1???”)、S11状态(data输入序列为“11??”)、S110状态(data输入序列为“110?”)、data输入序列为“1101”进入B0状态(shift_ena为1的第1个clk)、B1状态(shift_ena为1的第2个clk)、B2状态(shift_ena为1的第3个clk)、B3状态(shift_ena为1的第4个clk),COUNT状态(计时状态)、WAIT(完成计时工作等待用户确认状态)

状态转移图:

b144bd6b62f648c49f4a14a598799e01.png

代码:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,//移位使能信号
    output counting,//为1表示计时器计时状态
    input done_counting,//计时器接收到该信号停止计时
    output done,//为1表示整个计时工作完成在等待状态
    input ack );//表示用户确认的信号
    parameter S=4'b0000,S1=4'b0001,S11=4'b0010,S110=4'b0011,B0=4'b0100;
    parameter B1=4'b0101,B2=4'b0110,B3=4'b0111,COUNT=4'b1000,WAIT=4'b1001;
    reg [3:0]current_state,next_state;
    //状态转移逻辑
    always@(*)begin
        case(current_state)
            S:next_state=data?S1:S;
            S1:next_state=data?S11:S;
            S11:next_state=data?S11:S110;
            S110:next_state=data?B0:S;
            B0:next_state=B1;
            B1:next_state=B2;
            B2:next_state=B3;
            B3:next_state=COUNT;
            COUNT:next_state=done_counting?WAIT:COUNT;
            WAIT:next_state=ack?S:WAIT;
            default:next_state=S;
        endcase
    end
    //状态执行逻辑
    always@(posedge clk)begin
        if(reset)begin
            current_state<=S;
        end
        else begin
            current_state<=next_state;  
        end
    end
    //输出逻辑
    always@(*)begin
        case(current_state)
            B0:shift_ena=1;
            B1:shift_ena=1;
            B2:shift_ena=1;
            B3:shift_ena=1;
            default:shift_ena=0;
        endcase
    end
    
    assign counting=(current_state==COUNT);
    assign done=(current_state==WAIT);
    
endmodule

the complete timer

这个题是对前面五道题的综合,所以难度也很高

题目:要实现一个计时器(要结合时序图来看,另外本题的[3:0]delay和[3:0]count是一个东西,这里作者写的乱糟糟的,在题干描述写的delay变量,时序图和给的module配置输出写的count)

1.当接收到data输入的“1101”序列就启动计时器开始工作,之后4个clk将4位data输入移动到count中(通过移位实现)

2.移位完成后开始计时,根据count的值之后计时(count+1)×1000个clk。

3.计时完成后停止计时(把done置1表示计时器计时完成),进入计时完成等待状态,并等待用户确认,当用户确认后返回ack为1,计时器就从done为1的完成工作状态回到最初状态。

计时器的计时逻辑:计时分为(count+1)个大周期,每个周期里面有1000个clk,我们要输出每个大周期内剩余的clk(题目output没给,要自己设置)。其实要计时的周期数就是{count,remain-time},remain-time可以看作低三位(个十百位),count看作更高的千和万位。

计时器有两个输入:data(输入数据)、ack(用户返回的确认信号)

三个输出:count(表示计时当前处在哪个大周期)、counting(为1表示在计时状态)、done(为1表示计时工作完成在等待状态)

bb94b5d3efc84f0291f2925de7ad4458.png

我设置了几个中间变量:shift_ena(移位使能信号,为1表示在移位状态,将data移入count)、done_counting(计时器接收到该信号停止计时)、remain_time(每个大周期中当前剩余的clk,可能的取值从999到0)

状态转移逻辑和上一题相同:

b144bd6b62f648c49f4a14a598799e01.png

代码:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,//表示计时的大周期数
    output counting,//为1表示在计时状态
    output done,//为1表示计时工作完成在等待状态
    input ack );//用户返回的确认信号
    
    //控制计时器计时的状态机
    parameter S=4'b0000,S1=4'b0001,S11=4'b0010,S110=4'b0011,B0=4'b0100;
    parameter B1=4'b0101,B2=4'b0110,B3=4'b0111,COUNT=4'b1000,WAIT=4'b1001;
    reg [3:0]current_state,next_state;
    wire shift_ena;//移位使能信号,为1时将“1101”后面4个clk的data移入count中
    wire done_counting;//计时器接收到该信号停止计时
    reg [9:0]remain_time;//每个大周期中当前剩余的clk,可能的取值从999到0
    
    //状态转移逻辑
    always@(*)begin
        case(current_state)
            S:next_state=data?S1:S;
            S1:next_state=data?S11:S;
            S11:next_state=data?S11:S110;
            S110:next_state=data?B0:S;
            B0:next_state=B1;
            B1:next_state=B2;
            B2:next_state=B3;
            B3:next_state=COUNT;
            COUNT:next_state=done_counting?WAIT:COUNT;
            WAIT:next_state=ack?S:WAIT;
            default:next_state=S;
        endcase
    end
    
    //状态执行逻辑
    always@(posedge clk)begin
        if(reset)begin
            current_state<=S;
        end
        else begin
            current_state<=next_state;  
        end
    end
    
    always@(*)begin//移位使能shift_ena有效的触发条件
        case(current_state)
            B0:shift_ena=1;
            B1:shift_ena=1;
            B2:shift_ena=1;
            B3:shift_ena=1;
            default:shift_ena=0;
        endcase
    end
    
    always@(posedge clk)begin//remain_time的转换逻辑
        if(reset)begin
            remain_time<=10'd0;
        end
        else if(counting==1'b1&&remain_time==10'd0)begin//如果remain_time计到0后面还有计时大周期,remain_time回到999计下一个大周期的剩余clk;如果后面没有大周期remain_time就没有意义了,将remain_time保持在默认值,本题默认值我也设置在999,所以这里不需要区分后面是不是还有大计数周期,只要remain_time到0了下一个clk就会回到999
            remain_time<=10'd999;
        end 
        else if(counting==1'b1)begin
            remain_time<=remain_time-10'd1;
        end
        else begin
            remain_time<=10'd999;//默认remain_time置在10'd999,保证了刚进入计时状态时remain_time的数值就是正确的
        end
    end
    
    //输出逻辑    
    always@ (posedge clk)begin//count的转换逻辑
        if(reset)begin
            count<=4'd0;
        end
        else if(shift_ena)begin//移位状态(4个clk)把4位的data赋给[3:0]count
            count<={count[2:0],data};
        end
        else if(counting)begin//计时状态,count递减到0
            count<=(remain_time==10'd0)?count-4'd1:count;
        end
        else begin
            count<=count;
        end
    end
            
    
    
    assign done_counting=(remain_time==10'b0&&count==4'd0);
    assign counting=(current_state==COUNT);//
    assign done=(current_state==WAIT);

endmodule

FSM:one-hot logic equations

给定独热编码:(S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10'b0000000001, 10'b0000000010, 10'b0000000100, ... , 10'b1000000000)

要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。

这种题目前面遇到很多遍了:Fsm3onehot - HDLBits (01xz.net)

Fsm3onehot - HDLBits

Exams/m2014 q6c - HDLBits (01xz.net)

Exams/2012 q2b - HDLBits (01xz.net)

b144bd6b62f648c49f4a14a598799e01.png

module top_module(
    input d,
    input done_counting,
    input ack,
    input [9:0] state,    // 10-bit one-hot current state
    output B3_next,
    output S_next,
    output S1_next,
    output Count_next,
    output Wait_next,
    output done,
    output counting,
    output shift_ena
); //

    // You may use these parameters to access state bits using e.g., state[B2] instead of state[6].
    parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;

    assign B3_next=state[B2];
    assign S_next=(state[S]&~d)|(state[S1]&~d)|(state[S110]&~d)|(state[Wait]&ack);
    assign S1_next=(state[S]&d);
    assign Count_next=(state[B3])|(state[Count]&~done_counting);
    assign Wait_next=(state[Count]&done_counting)|(state[Wait]&~ack);
    assign done=state[Wait];
    assign counting=state[Count];
    assign shift_ena=state[B0]|state[B1]|state[B2]|state[B3];

endmodule

到这里状态机的部分就算结束了,从上手做hdlbits状态机题目到后来整理错题纠正错误,然后编写这篇超长的文章,前前后后花了12天的时间,几乎花了我刷整个hdlbits一半的时间(一共花了25天左右),不过这个硬骨头终于是啃下来了,状态机的部分就告一段落了。

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值