HDLBits(十 二)学习笔记——有限状态机(Fsm hdlc - q2bfsm )

两点说明

个人收获:我们在写状态机的时候,在第三段描述输出,以及第二段状态转移的部分有需要注意的地方。
1、对于输出,我们一般用寄存器输出,尽量少的使用assign语句,因为用寄存器输出可带来更好的时序。
2、对于状态机的条件,我们发生有时候条件是当前状态state,有时候状态是下一状态next_state,但是怎么判断用哪个呢?
当我们采用组合逻辑的时候,用当前状态
当我们使用时序逻辑的时候,会打一拍,因此用下一状态。

Fsm hdlc

解码连续的数据位流,以查找指示帧(数据包)开始和结束的位模式。恰好6个连续的1(即01111110)是指示帧边界的“标志flag”,为了避免数据流意外包含“标志”,发送方每5个连续1后插入一个零,接收方必须检测并丢弃该值。如果有 7 个或更多个连续 1,我们还需要发出错误信号。因此:

0111110:每5个1后插入一个0,检测后进行丢弃——disc。
01111110:出现连续6个1,可标记帧(标志)的开头/结尾——flag。
01111111…:有连续7个或者更多1出现,发出错误信号——err。
解题:
根据题目,我们可以确定出五个状态:
IDLE空闲状态,DATA数据流状态,FLAG标志状态,DISC丢弃状态,ERROR错误状态
在这里插入图片描述

module top_module(
    input  clk,
    input  reset,    // Synchronous reset
    input  in,
    output  reg disc,
    output  reg flag,
    output  reg err
);

    parameter IDLE  = 5'b00001;
    parameter DATA  = 5'b00010;
    parameter DISC  = 5'b00100;
    parameter FLAG  = 5'b01000;
    parameter ERROR = 5'b10000;

    reg [4:0] current_state;
    reg [4:0] next_state;
    reg [2:0] counter;

    always @(*) begin
        case(current_state)
            IDLE:begin
                next_state = in ? DATA : IDLE;
            end
            DATA:begin
                case(counter)
                    3'd5:   next_state = in ? DATA : DISC;
                    3'd6:   next_state = in ? ERROR : FLAG;
                    default:next_state = in ? DATA : IDLE;
                endcase
            end
            DISC:begin
                next_state = in ? DATA : IDLE;
            end
            FLAG:begin
                next_state = in ? DATA : IDLE;
            end
            ERROR:begin
                next_state = in ? ERROR : IDLE;
            end
        endcase
    end

    always @(posedge clk) begin
        if(reset)begin
            current_state <= IDLE;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(posedge clk) begin
        if(reset)begin
            disc <= 1'd0;
            flag <= 1'd0;
            err  <= 1'd0;
            counter <= 3'd0;
        end
        else begin
            case(next_state)
                DATA:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= counter + 1'd1;
                end
                DISC:begin
                    disc <= 1'd1;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
                FLAG:begin
                    disc <= 1'd0;
                    flag <= 1'd1;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
                ERROR:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd1;
                    counter <= 3'd0;
                end
                default:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
            endcase
        end
    end

endmodule

q8 Mealy 型有限状态机

实现一个 Mealy 型有限状态机,该状态机可识别名为 x 的输入信号上的序列“101”。您的 FSM 应具有输出信号 z,当检测到“101”序列时,该信号被断言为 logic-1(也就是检测到101输出逻辑1,否则为0)。FSM 还应具有低电平有效异步复位
状态机中可能只有 3 个状态。
可识别重叠的序列,意思是当输入10101的时候可以分别在3和5时刻都输出z = 1。因此可能在第一位的基础上检测第二位的情况。

module top_module (
    input clk,
    input aresetn,    // Asynchronous active-low reset
    input x,
    output z
); 
    parameter S0 = 3'b001;
    parameter S1 = 3'b010;
    parameter S2 = 3'b100;
    
    reg [2:0] state;
    reg [2:0] next_state;  
//第一段,时序逻辑描述状态寄存器
    always @(posedge clk or negedge aresetn)
        if(!aresetn)
            state <= S0;
        else
            state <= next_state;
//第二段,组合逻辑描述状态转移
    always @ (*)
        case(state)
            S0: next_state = x ? S1 : S0;
            S1: next_state = x ? S1 : S2;
            S2: next_state = x ? S1 : S0;
            default:next_state = S0;
        endcase
//第三段,组合逻辑描述输出
  
      assign  z = (state == S2) ? x : 1'b0; //因为该题为米利状态机,那么输出与输入x有关,因此可以这么写

endmodule

q5a 单输入单输出串行 2 的补码摩尔状态机

首先我们要了解2的补码如何计算?
简单来说就是取反后加1。例如 给出一个序列数 100100,其2的补码:011011 + 1 = 011100
下图可看出,输出z的左边是LSB低位,右边是MSB高位。因此若输入是00110100,那么进行2的补码计算为11001100.
在这里插入图片描述
该题的重点在于进位的处理,进行+1操作的时候,需要进位,但是我们不知道最终需要进位到哪一位,因此采用状态机来解决。
分析:如果输入的低位都是0,那么取反后为1,同时进行+1操作,就需要进位。另外只要低位是0,那么就会一直进位,直到不断检测到输入为1,此时取反+1后不需要进位操作。此时阶段可用一个状态表示(检测1的过程,若没检测到,继续检测,否则跳转到下一状态),下一状态是对输入进行输出,因为此过程已经不涉及进位了。
该题是摩尔状态机,输出与输入无关,因此这里要用到三个状态。

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 

    parameter S0 = 3'b001;
    parameter S1 = 3'b010;
    parameter S2 = 3'b100;
    
    reg [2:0] state;
    reg [2:0] next_state;  
//第一段,时序逻辑描述状态寄存器
    always @(posedge clk or posedge areset)
        if(areset)
            state <= S0;
        else
            state <= next_state;
//第二段,组合逻辑描述状态转移
    always @ (*)
        case(state)
            S0: next_state = x ? S1 : S0;
            S1: next_state = x ? S2 : S1;
            S2: next_state = x ? S2 : S1;
            default:next_state = S0;
        endcase
//第三段,组合逻辑描述输出
  
    assign  z = (state == S1) ;//因为该题为摩尔状态机,那么输出与输入x无关,因此不能和上题一样,若符合某条件输出x的值。

endmodule  

q5b

在这里插入图片描述
可看出共两个状态,题目要求采用独热码编码。
状态A可看出,z的值与x相同,因此当A为真的时候,我们即可通过A&&x来进行z的判断,若x为0,z为0,x为1,z为1.
同理,状态B,z的值与x相反,因此当B为真的时候,我们可通过B&&(~x)来进行z的判断,若x为0,z为1,x为1,z为0.

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 

    parameter S0 = 2'b01;
    parameter S1 = 2'b10;
    reg [1:0] current_state;
    reg [1:0] next_state;
//第一段,状态寄存器
    always @(posedge clk or posedge areset) begin
        if(areset)begin
            current_state <= S0;
        end
        else begin
            current_state <= next_state;
        end
    end
 //第二段,描述状态转移   
    always @(*) begin
        case(current_state)
            S0:     next_state = x ? S1 : S0;
            S1:     next_state = S1;
        endcase
    end


//描述输出
    assign z = ((current_state == S0) && x) || ((current_state == S1) && ~x);

endmodule

q3fsm(引入计数器)

当s=1时,进入B状态后,检查w的值,如果在接下来的三个周期中w值恰好有两个周期都为1,则z输出1,否则z输出0。
注意,q8中涉及到重叠序列的情况,但是通过该题的波形图可看到是没有进行重叠序列检测的。

要求:使用尽可能少的状态,因此本题目就仅仅用AB两个状态,然后B状态中对w值的判断用计数器来搞。
首先设计一个计数器,对三个周期的w进行统计,同时定义一个数来记录w值的加法结果,当计数三次的时候,可以统计三次w值相加,同时如果加起来是2,说明有两个w值为1.
在这里插入图片描述


```bash
module top_module (
    input clk,
    input reset,   // Synchronous reset
    input s,
    input w,
    output z
);
    parameter A = 2'b01;
    parameter B = 2'b10;
    reg [1:0] state,next_state;
    reg [1:0] counter,num;
    
    //第一段,状态寄存器
    always @ (posedge clk)begin
        if(reset)
            state <= A;
        else
            state <= next_state;
    end
    //第二段,状态转移,根据s判断
    always @ (*)begin
        case(state)
            A: next_state = s ? B:A;
            B: next_state = B;
        endcase
    end
    //对B状态内的w进行判断
    //设计计数器
    always @ (posedge clk)begin
        if(reset)
            counter <= 2'b0;
        else if(counter == 2'd2)
            counter <= 2'b0;
        else if(state == B)
            counter <= counter + 1'b1;
        else
            counter <= counter;         
    end
    //对进入状态B后的w值进行判断,同时还要判断是否三个周期内有两个w值为1
     always @ (posedge clk)begin
         if(reset)
             num <= 1'b0;
         else if(counter == 2'b0)begin //初值或者计数满 ,就可以进行新的统计
             num <= w ? 1'b1 : 1'b0;
         end
         else if(state == B)
             num <= w ? (num + 1'b1) : num;
         else
            num <= 1'b0; 
     end
   //第三段 结果的输出
    assign z = (state == B && counter == 2'd0 && num == 2'd2);       
endmodule

q3bfsm 根据状态分配表写状态机

该题给出如下的表达来写状态机,可看到有五种状态。复位的时候是状态000
下一状态与输入x有关,将x作为判断状态转移的条件。根据如下的表即可得到状态转移图。
在这里插入图片描述

module top_module (
    input  clk,
    input  reset,   // Synchronous reset
    input  x,
    output z
);
    parameter S0 = 3'b000;
    parameter S1 = 3'b001;
    parameter S2 = 3'b010;
    parameter S3 = 3'b011;
    parameter S4 = 3'b100;
    
    reg [2:0] state,next_state;
    
    //第一段 状态寄存器
    always @ (posedge clk)
        if(reset)
            state <= S0;
        else
            state <= next_state;
    //第二段,状态转移
    always @ (*)
        case(state)
            S0: next_state = x ? S1 : S0;
			S1: next_state = x ? S4 : S1;
			S2: next_state = x ? S1 : S2;
			S3: next_state = x ? S2 : S1;
			S4: next_state = x ? S4 : S3;
        endcase
    
    //第三段,描述输出
    always @ (*)
        if(state == S3 || state == S4)
            z = 1'b1;
        else if(state == S0 || state == S1 || state == S2)
            z = 1'b0;
        else
            z = 1'b0; 

endmodule

q3c

将Y[0]与z表示出来。
z直接找输出z对应的1的位置,然后找到对应的当前状态进行表示即可。
找Y[0]为1的情况,然后找到对应的当前状态进行表示即可。
在这里插入图片描述

module top_module (
    input clk,
    input [2:0] y,
    input x,
    output Y0,
    output z
);
    //输出一般用寄存器输出,能获得较好的时序
    
    always @ (*) begin
        Y0 = ((( ~y[2]&y[0]) | (y == 3'b100) ) &~x ) | ((~y[2]&~y[0])&x);
        z  = (y == 3'b011) | (y == 3'b100);
    end
   
endmodule

q6b 根据状态转换图写状态分配表

下面状态机有一个输入 w 和一个输出 z
在这里插入图片描述
我们需要根据上面的状态图来写状态分配表,最终只实现 y[2] 的下一状态逻辑。
在这里插入图片描述
注意括号的对应。

module top_module (
    input [3:1] y,
    input w,
    output Y2
);
    
    always @ (*)
        Y2 = (~w & (~y[2] & y[1])) | (w & ((~y[2] & y[1]) |( y == 3'b010) | y==3'b100));

endmodule

q6c

与上题类似,共六种状态,根据w的值进行下一状态的跳转,但是状态赋值处采用独热码的方式。
在这里插入图片描述
为下一状态信号 Y2 和 Y4 编写逻辑表达式。
在这里插入图片描述

module top_module (
    input [6:1] y,
    input w,
    output Y2,
    output Y4
);
    always @ (*)begin
        Y2 = ~w & y[1];
        Y4 = (w & (y[2] | y[3] |y[5] |y[6] ));
    end

endmodule

q6

实现该状态机
在这里插入图片描述
通过上状态转移图,我们也可以画状态分配表,也可以直接写,w为状态转移条件,同时有6个状态ABCDE,另外输出值z在状态EF处为1.

module top_module (
    input clk,
    input reset,     // synchronous reset
    input w,
    output z
);
    parameter A = 6'b000001;
    parameter B = 6'b000010;
    parameter C = 6'b000100;
    parameter D = 6'b001000;
    parameter E = 6'b010000;
    parameter F = 6'b100000;
    
    reg [5:0] state ;
    reg [5:0] next_state ;
    
    
    //第一段,状态寄存器
    always @ (posedge clk)
        if(reset)
            state <= A;
        else
            state <= next_state;
    //第二段,组合逻辑进行状态转移
    always @ (*)begin
        case(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
     
    //第三段,组合逻辑描述输出z
    always @ (*)begin
        z = (state == 6'b010000 | state == 6'b100000);
    end
     
endmodule

q2fsm

在这里插入图片描述
和上题一样,无非是状态转移处变化了。

module top_module (
    input clk,
    input reset,     // synchronous reset
    input w,
    output z
);
    parameter A = 6'b000001;
    parameter B = 6'b000010;
    parameter C = 6'b000100;
    parameter D = 6'b001000;
    parameter E = 6'b010000;
    parameter F = 6'b100000;
    
    reg [5:0] state ;
    reg [5:0] next_state ;
    
    
    //第一段,状态寄存器
    always @ (posedge clk)
        if(reset)
            state <= A;
        else
            state <= next_state;
    //第二段,组合逻辑进行状态转移
    always @ (*)begin
        case(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
     
    //第三段,组合逻辑描述输出z
    always @ (*)begin
        z = (state == E | state == F);
    end
     
endmodule

q2b 采用独热码编写

在这里插入图片描述
题目连个要求:
采用独热码编码。
y[5:0]
输y[1]和y[3]。——为更清楚,还是画状态分配表找下一状态(B和D)
只编写输出逻辑,不写状态机的一二段
在这里插入图片描述

module top_module (
    input [5:0] y,
    input w,
    output Y1,
    output Y3
);
    

    //第三段,组合逻辑描述输出Y1和Y3
    always @ (*)begin
        Y1 = w & y[0];
        Y3 = ~w & ( y[1] | y[2] | y[4] | y[5] );
    end
     
endmodule

q2afsm 用状态机实现仲裁

此 FSM 充当仲裁器电路,它控制三个请求设备对某种类型资源的访问。
关于状态的转换:
每个设备通过设置信号 r[i] = 1 来请求资源,其中 r[i] 为 r[1]、r[2] 或 r[3]。——输入是三位的
每个 r[i] 都是 FSM 的输入信号,代表三个器件之一。只要没有请求,FSM 就会一直保持在状态 A 中。
当一个或多个请求发生时,从而FSM 将决定哪个设备获得使用资源的授权。

关于输出:
当一个或多个请求发生时,FSM 将决定哪个设备获得使用资源的授权,将该设备的 g[i] 信号设置为 1 的状态。
有一个优先级系统,因为设备 1 的优先级高于设备 2,而设备 3 的优先级最低。因此,例如,仅当设备 3 是 FSM 处于状态 A 时发出请求的唯一设备时,它才会获得授权。一旦设备 i 被 FSM 授予授权,只要其请求 r[i] = 1,该设备就会继续获得授权。
在这里插入图片描述

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;
    parameter B = 4'b0010;
    parameter C = 4'B0100;
    parameter D = 4'b1000;
    
    reg [3:0] state,next_state; //注意位数
    
    //第一段
    always@(posedge clk)
        if(!resetn)
            state <= A;
        else 
            state <= next_state;
    //第二段
    always @(*)
        case(state)
            A:begin
                if(r[1] == 3'b1)
                   next_state = B;
                else if(r[2] == 3'b1)
                    next_state = C;
                else if(r[3] == 3'b1)
                    next_state = D;
                else
                    next_state = A;
            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:begin
                next_state = A;
            end
        endcase
    //第三段
    always@(*)begin
        g[1] = (state == B);
        g[2] = (state == C);
        g[3] = (state == D);
    end
    
endmodule

q2bfsm 根据题目要求来画状态图

用于控制某种类型电机的有限状态机。FSM具有来自电机的输入x和y,并产生控制电机的输出f和g。还有一个名为 clk 的时钟输入和一个名为 resetn 的同步低电平复位输入。
工作方式:
复位时为状态A
输出 f 是采用时序逻辑进行输出,当复位信号被取消置位时,在下一个时钟边沿之后,FSM必须在一个时钟周期内将输出f设置为1。

当 x 在三个连续的时钟周期中生成值 1、0、1 时(检测101序列),则 g 应在下一个时钟周期中设置为 1。——此阶段状态转移的条件是x
在保持 g = 1 的同时,FSM 进行两个序列输入y的检测 。如果 y 为01,10,11,则 FSM 应永久保持 g = 1(直到重置)。但是,如果y为00,则 FSM 应永久设置 g = 0(直到重置)。

在这里插入图片描述

module top_module (
    input clk,
    input resetn,    // active-low synchronous reset
    input x,
    input y,
    output f,
    output g
); 
    //九个状态则不用独热码
    parameter IDLE   = 4'd0;
    parameter OUT_F  = 4'd1;
    parameter OUT_X1 = 4'd2;
    parameter OUT_X2 = 4'd3;
    parameter OUT_X3 = 4'd4;
    parameter OUT_G1 = 4'd5;
    parameter OUT_G2 = 4'd6;
    parameter KEEP1  = 4'd7;
    parameter ZERO   = 4'd8;
    
    reg [3:0] state,next_state;
    
    //状态寄存器
    always @ (posedge clk)
        if(!resetn)
            state <= IDLE;
        else 
            state <= next_state;
    //状态转移
    always @ (*)
        case(state)
            IDLE  : next_state = OUT_F;
			OUT_F : next_state = OUT_X1;
			OUT_X1: next_state = x ? OUT_X2 : OUT_X1;
			OUT_X2: next_state = x ? OUT_X2 : OUT_X3;
			OUT_X3: next_state = x ? OUT_G1 : OUT_X1;
			OUT_G1: next_state = y ? KEEP1 : OUT_G2;
			OUT_G2: next_state = y ? KEEP1 : ZERO;
			KEEP1 : next_state = KEEP1;
			ZERO  : next_state = ZERO;
            default:next_state = IDLE;
        endcase
    
    //描述输出
    always @ (posedge clk)
        if(!resetn)
            f <= 1'b0;
        else if(next_state == OUT_F)
            f <= 1'b1;
        else
            f <= 1'b0;
    
        always @ (*)begin
        g = (state == OUT_G1 |  state == OUT_G2 |state == KEEP1 );
        end
endmodule
  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fighting_FPGA

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值