Verilog基础:三段式状态机与输出寄存

相关阅读

Verilog基础icon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/category_12263729.html


        对于Verilog HDL而言,有限状态机(FSM)是一种重要而强大的模块,常见的有限状态机书写方式可以分为一段式,二段式和三段式,笔者强烈建议使用三段式因为这样能使状态机逻辑清晰且易于维护。

        有限状态机有两种基本类型:Mealy机和Moore机。两者的区别在于:Mealy机的下一状态和输出都取决于当前状态和当前输入,而Moore机的下一状态取决于当前状态和当前输入,输出只取决于当前状态。这两类有限状态机的下一状态和输出都是组合逻辑的形式的(指输出不直接来自寄存器的输出),两类状态机的结构如图1、图2所示。

图1 Mealy型状态机

图2 Moore型状态机

        下面以一个简单的例子说明三段式Moore型状态机的书写方式。图3是一个有两个状态的异步复位的Moore机。

图3 一个简单的Moore机 

module top_module (
	input clk,
	input in,
	input rst_n,
	output reg out
);
parameter A = 0;
parameter B = 1;
reg state, next_state;               //定义寄存器变量保存状态信息

//第一段,下一状态组合逻辑
always@(*) begin
	case (state)                     //根据不同的状态和输入,决定下一时钟周期的状态
		A: next_state = in ? A : B;
		B: next_state = in ? B : A;
	endcase
end

//第二段,状态转移时序逻辑
always @(posedge clk, negedge rst_n) begin
	if (!rst_n)     
        state <= B;		             //异步复位到状态B
    else 
        state <= next_state;			
    end

//第三段,输出组合逻辑
always@(*) begin
    if(state == B)
        out = 1;
    else
        out = 0;
end

//因为输出比较简单,这里的第三段的输出组合逻辑也可以用assign连续赋值
//但out此时不能定义为reg
//assign out = (state == B);

endmodule

        对于Mealy型状态机,因为输出直接受输出影响,可能在某些情况下会出现毛刺(即不在时钟边沿的输出变化),所以可以使用寄存器采集输出。对于Moore型状态机,虽然没有输出毛刺的问题,但也可以使用寄存器采集输出以避免大段组合逻辑输出。图4和图5分别给出了寄存输出的Mealy型状态机和Moore型状态机的结构。

图4 寄存输出的Mealy型状态机

图5 寄存输出的Moore型状态机

        上面两图不难理解,但是一个新的问题出现了,即输出会延后一个周期得到,如果既需要当前周期给出输出,又需要对输出寄存,就不能使用当前状态和输入确定输出,而是应该使用下一状态组合逻辑和输入确定输出。图6和图7给出了这种情况下的Mealy型状态机和Moore型状态机。

图6 寄存输出的Mealy型状态机(下一状态)

 图7  寄存输出的Moore型状态机(下一状态)

        对于Mealy状态机,因为需要状态转移和相应状态的输出同时出现,输出寄存器需要保存由下一状态组合逻辑和的输入推导的输出。对于Moore状态机,输出寄存器需要保存由下一状态组合逻辑推导的输出。

        下面用一个更加复杂的有限状态机为例,说明寄存输出的具体写法。这是一个序列检测器,用于检测输入序列中三个连续的1信号,首先给出Moore型序列检测器的Verilog描述。

module Seq_Rec_Moore(output reg D_out, D_out_r1, D_out_r2, input D_in, En, clk, rst_n);
    parameter S_idle = 3'd0;
    parameter S_0 = 3'd1;
    parameter S_1 = 3'd2;
    parameter S_2 = 3'd3;
    parameter S_3 = 3'd4;

    reg [2:0] state, next_state;

    //下一状态组合逻辑
    always@(*)begin
        case(state)
            S_idle: if((En == 1)&&(D_in == 1))
                        next_state = S_1;
                    else if((En == 1)&&(D_in == 0))
                        next_state = S_0;
                    else 
                        next_state = S_idle;
            S_0:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_1;
                    else
                        next_state = S_idle;
            S_1:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_2;
                    else 
                        next_state = S_idle;
            S_2:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_3;
                    else 
                        next_state = S_idle;
            S_3:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_3;
                    else 
                        next_state = S_idle;
            default:    next_state = S_idle;      
        endcase
    end
    
    //状态转移时序逻辑
    always@(posedge clk, negedge rst_n)begin
        if(!rst_n)
            state <= S_idle;
        else
            state <= next_state;
    end

    //输出组合逻辑
    always@(*) begin
        D_out = (state == S_3);
    end

    //寄存输出
    always @(posedge clk, negedge rst_n) begin
        if(!rst_n)
            D_out_r1 <= 0;
        else
            D_out_r1 <= D_out;
    end

    //寄存输出(下一状态)
    always@(posedge clk, negedge rst_n)begin
        if(!rst_n)
            D_out_r2 <= 0;
        else
            D_out_r2 <= (next_state == S_3);
    end
endmodule

        一个简单的testbench如下所示,图8所示的仿真截图显示了三种不同形式的输出。

`timescale 1ns / 1ns
module t_Seq();
  reg D_in, clk, rst_n,En;
  wire D_out, D_out_r1, D_out_r2;

  Seq_Rec_Moore Seq_Rec_Moore_1 (.D_in(D_in), .clk(clk), .rst_n(rst_n), .D_out(D_out), .En(En), .D_out_r1(D_out_r1), .D_out_r2(D_out_r2));

  initial begin
    D_in = 0;
    clk = 0;
    rst_n = 1;
    En = 0;
  end

  initial begin
    #5 rst_n = 0;
    #4 rst_n = 1;
  end

  always begin
    #5 clk = 0;
    #5 clk = 1;
  end

  initial begin
    #5 En =1;
  end

  initial begin
    #5 D_in = 1;
  end
endmodule

图8 Moore状态机仿真截图 

        下面是Mealy型序列检测器的Verilog描述。

module Seq_Rec_Mealy(output reg D_out, D_out_r1, D_out_r2, input D_in, En, clk, rst_n);
    parameter S_idle = 3'd0;
    parameter S_0 = 3'd1;
    parameter S_1 = 3'd2;
    parameter S_2 = 3'd3;
    parameter S_3 = 3'd4;

    reg [2:0] state, next_state;

    //下一状态组合逻辑
    always@(*)begin
        case(state)
            S_idle: if((En == 1)&&(D_in == 1))
                        next_state = S_1;
                    else if((En == 1)&&(D_in == 0))
                        next_state = S_0;
                    else 
                        next_state = S_idle;
            S_0:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_1;
                    else
                        next_state = S_idle;
            S_1:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_2;
                    else 
                        next_state = S_idle;
            S_2:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_3;
                    else 
                        next_state = S_idle;
            S_3:    if(D_in == 0)
                        next_state = S_0;
                    else if(D_in == 1)
                        next_state = S_3;
                    else 
                        next_state = S_idle;
            default:    next_state = S_idle;      
        endcase
    end
    
    //状态转移时序逻辑
    always@(posedge clk, negedge rst_n)begin
        if(!rst_n)
            state <= S_idle;
        else
            state <= next_state;
    end

    //输出组合逻辑
    always@(*) begin
        D_out = (state == S_3)&(D_in == 1);
    end

    //寄存输出
    always @(posedge clk, negedge rst_n) begin
        if(!rst_n)
            D_out_r1 <= 0;
        else
            D_out_r1 <= D_out;
    end

    //寄存输出(下一状态)
    always@(posedge clk, negedge rst_n)begin
        if(!rst_n)
            D_out_r2 <= 0;
        else
            D_out_r2 <= (next_state == S_3)&(D_in == 1);
    end
endmodule

 图9 Mealy状态机仿真截图 

一个简单的testbench如下所示,图9的仿真截图显示了如果使用寄存输出,而输入无法维持到下个时钟沿,则会丢失寄存输出信号。

`timescale 1ns / 1ns
module t_Seq();
  reg D_in, clk, rst_n,En;
  wire D_out, D_out_r1, D_out_r2;

  Seq_Rec_Mealy Seq_Rec_Mealy_1 (.D_in(D_in), .clk(clk), .rst_n(rst_n), .D_out(D_out), .En(En), .D_out_r1(D_out_r1), .D_out_r2(D_out_r2));

  initial begin
    D_in = 0;
    clk = 0;
    rst_n = 1;
    En = 0;
  end

  initial begin
    #5 rst_n = 0;
    #4 rst_n = 1;
  end

  always begin
    #5 clk = 0;
    #5 clk = 1;
  end

  initial begin
    #5 En =1;
  end

  initial begin
    #5 D_in = 1;
    #30 D_in = 0;
    #10 D_in = 1;
    #37 D_in = 0;
  end
endmodule

  • 21
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
当今数字系统中,三段式状态机是最常用的状态机之一。下面是一个简单的三段式状态机示例,该状态机有三个状态:S0,S1和S2。 ``` module three_stage_fsm(input clk, input reset, input x, output reg z); //定义状态 parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10; //定义当前状态和下一个状态 reg [1:0] state, next_state; //状态转移逻辑 always @ (posedge clk, posedge reset) begin if (reset) begin state <= S0; end else begin state <= next_state; end end //组合逻辑 always @ (*) begin case (state) S0: begin if (x) begin next_state = S1; z = 1; end else begin next_state = S0; z = 0; end end S1: begin if (x) begin next_state = S2; z = 1; end else begin next_state = S0; z = 0; end end S2: begin if (x) begin next_state = S2; z = 1; end else begin next_state = S0; z = 0; end end endcase end endmodule ``` 上述代码中,输入时钟信号 `clk`,重置信号 `reset`,输入信号 `x` 和输出信号 `z` 都是模块的输入和输出状态机有三个状态:S0,S1和S2,通过 `parameter` 关键字定义。当前状态和下一个状态都是2位寄存器 `state` 和 `next_state`。 状态转移逻辑使用 always 块,检测时钟和重置信号。如果重置信号为高电平,则当前状态将被重置为 S0,否则当前状态将被更新为下一个状态。组合逻辑使用 always 块,根据当前状态和输入信号 x 计算下一个状态和输出信号 z。根据状态转移图,当状态为 S0 时,如果输入信号为高电平,则下一个状态为 S1,输出信号为高电平;否则下一个状态为 S0,输出信号为低电平。当状态为 S1 时,同样地,如果输入信号为高电平,则下一个状态为 S2,输出信号为高电平。如果输入信号为低电平,则下一个状态为 S0,输出信号为低电平。当状态为 S2 时,无论输入信号如何,下一个状态始终为 S2,输出信号为高电平。 总之,上述代码实现了一个简单的三段式状态机,其状态转移逻辑和组合逻辑使用了 always 块。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

日晨难再

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

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

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

打赏作者

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

抵扣说明:

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

余额充值