Verilog-实现基于状态机的序列检测--一段式状态机、二段式状态机、三段式状态机

一、状态机的基本概念

1.为什么要使用状态机

  硬件设计需要串行设计思想,而用Verilog描述的电路大多都是并行实现的,但是对于实际的项目工程,往往需要让硬件来做一些具有顺序的工作,这就要用到状态机的思想。状态机简单的来说就是通过不同的状态迁移来完成一些特定的顺序逻辑

2. 构成状态机的基本要素

  • 输入:引发状态变化的条件
  • 输出:状态变化后引起的变化
  • 状态:S0、S1、S2、S3

以博主浅谈Moore型和Mealy型以及序列检测状态图中的序列检测图为例。
在这里插入图片描述

二、关于一段式、二段式、三段式有效状态机状态机

有限状态机:高效的顺序控制模块模型

1. 一段式状态机

  将所有的逻辑(输入、输出、状态)在一个always块里进行描述,这种写法看起来简单,但对于复杂的状态会容易出错,并且在大型项目中这些代码是不利于维护的。

2. 二段式状态机

  将时序逻辑和组合逻辑划分开来,时序逻辑进行当前状态和下一状态的切换,组合逻辑实现输入、输出以及状态的判断,这种写法相对容易维护,不过组合逻辑输出容易出现毛刺等问题。

3. 三段式状态机

  代码易维护,时序逻辑的输出解决了二段式写法中组合逻辑的毛刺问题,但是三段式消耗的资源相对多一点,并且三段式从输入到输出比一段式和二段式会延时一个时钟周期。

三、三种状态机的Verilog实现

输入序列为:010101101 ; 凡收到输入序列101时,输出为1

1. 一段式状态机代码实现

一段式状态机代码
`timescale 1ns/1ps
module fsm_1 (
    input clk,      //50MHZ
    input rstn,     //复位信号
    input data_in,

    output reg data_out
);


//序列检测101--可重叠Mealy型--需要三个状态
    parameter S0 = 3'b001,  //独热码 -- 速度快,资源占用多
              S1 = 3'b010, 
              S2 = 3'b100;
/*             
    parameter S0 = 2'b00,  //二进制编码 -- 资源占用少,速度慢
              S1 = 2'b01, 
              S2 = 2'b10;
*/  
  reg [2:0] c_state;
//fsm 一段式写法  简单状态机可用,复杂的状态容易出错且不利于维护
always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
       c_state  <= S0;
       data_out <= 0;
    end
    else begin
        case(c_state)
          S0:  begin 
                  if(data_in == 1)begin  
                      c_state  <= S1; 
                      data_out <= 0;
                  end 
                  else begin
                      c_state  <= S0;
                      data_out <= 0;
                    end 
                end 
          S1:  begin 
                  if(data_in == 0)begin 
                      c_state  <= S2;
                      data_out <= 0; 
                    end
                  else begin
                      c_state  <= S1;
                      data_out <= 0;  
                    end
                end 
          S2:  begin 
                  if(data_in == 1) begin //Mealy型状态机,其输出和S2状态、输入值都有关系
                      c_state  <= S1; 
                      data_out <= 1;
                    end
                  else begin
                      c_state  <= S0; 
                      data_out <= 0; 
                    end
                end 
          default : begin  c_state = S0; end    
        endcase
    end
end

endmodule



Testbench
`timescale 1ns/1ps
module fsm_tb;

reg clk = 0;
reg rstn = 0;
reg data_in = 0;

wire data_out;

//fsm_2 ; fsm_3 仿真内容相同,只需要修改例化名称即可
fsm_1 dut (
  .clk       (clk      ),
  .rstn      (rstn     ),
  .data_in   (data_in  ),
  .data_out  (data_out )
);

always
  #10  clk = ! clk ; //50Mhz

initial begin
  #50 rstn = 1;
      
      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end


      #1000;
       $finish;
  end
  
endmodule

2. 二段式状态机代码实现

二段式状态机代码
`timescale 1ns/1ps
module fsm_2 ( 
    input clk,     //50MHZ
    input rstn,    //复位信号
    input data_in, 

    output wire data_out
);

//序列检测101--可重叠Mealy型--需要三个状态
    parameter S0 = 3'b001,  //独热码 -- 速度快,资源占用多
              S1 = 3'b010, 
              S2 = 3'b100;
/*             
    parameter S0 = 2'b00,  //二进制编码 -- 资源占用少,速度慢
              S1 = 2'b01, 
              S2 = 2'b10;
*/  
    
  reg [2:0] c_state;
  reg [2:0] n_state;
//fsm 二段式写法  写法相对容易维护,不过组合逻辑输出容易出现毛刺等问题
//第一个always块:进行当前状态和下一个状态的切换  时序逻辑    
always @(posedge clk or negedge rstn) begin
       if(!rstn)
         c_state <= S0;
       else 
         c_state <= n_state;
  end


//第二个always块:实现状态跳转判断  组合逻辑   阻塞赋值 =
always @(*) begin
    case(c_state)
        S0 : n_state  = (data_in == 1) ? S1 : S0;  
        S1 : n_state  = (data_in == 0) ? S2 : S1;  
        S2 : n_state  = (data_in == 1) ? S1 : S0;  

       default : n_state = S0;       
    endcase
end
   
assign data_out = (data_in == 1) && (c_state == S2);

endmodule

Testbench
`timescale 1ns/1ps
module fsm_tb;

reg clk = 0;
reg rstn = 0;
reg data_in = 0;

wire data_out;

//fsm_1 ; fsm_3 仿真内容相同,只需要修改例化名称即可
fsm_2 dut (
  .clk       (clk      ),
  .rstn      (rstn     ),
  .data_in   (data_in  ),
  .data_out  (data_out )
);

always
  #10  clk = ! clk ; //50Mhz

initial begin
  #50 rstn = 1;
      
      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end


      #1000;
       $finish;
  end
  
endmodule

3. 三段式状态机代码实现

三段式状态机代码
`timescale 1ns/1ps
module fsm_2 ( 
    input clk,     //50MHZ
    input rstn,    //复位信号
    input data_in, 

    output reg data_out
);

//序列检测101--可重叠Mealy型--需要三个状态
    parameter S0 = 3'b001,  //独热码 -- 速度快,资源占用多
              S1 = 3'b010, 
              S2 = 3'b100;
/*             
    parameter S0 = 2'b00,  //二进制编码 -- 资源占用少,速度慢
              S1 = 2'b01, 
              S2 = 2'b10;
*/  
    
  reg [2:0] c_state;
  reg [2:0] n_state;
//fsm 二段式写法  写法相对容易维护,不过组合逻辑输出容易出现毛刺等问题
//第一个always块:进行当前状态和下一个状态的切换  时序逻辑    
always @(posedge clk or negedge rstn) begin
       if(!rstn)
         c_state <= S0;
       else 
         c_state <= n_state;
  end


//第二个always块:实现状态跳转判断  组合逻辑   阻塞赋值 =
always @(*) begin
    case(c_state)
        S0 : n_state  = (data_in == 1) ? S1 : S0;  
        S1 : n_state  = (data_in == 0) ? S2 : S1;  
        S2 : n_state  = (data_in == 1) ? S1 : S0;  

       default : n_state = S0;       
    endcase
end

//时序逻辑输出 
always@(posedge clk or negedge rstn)begin
  if(!rstn)
      data_out <= 1'b0;
  else if((data_in ==1) && (c_state == S2))
      data_out <= 1'b1;
  else
      data_out <= 1'b0;
end

endmodule

Testbench
`timescale 1ns/1ps
module fsm_tb;

reg clk = 0;
reg rstn = 0;
reg data_in = 0;

wire data_out;

//fsm_1 ; fsm_2 仿真内容相同,只需要修改例化名称即可
fsm_3 dut (
  .clk       (clk      ),
  .rstn      (rstn     ),
  .data_in   (data_in  ),
  .data_out  (data_out )
);

always
  #10  clk = ! clk ; //50Mhz

initial begin
  #50 rstn = 1;
      
      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 1;
      end

      @(posedge clk) begin
         data_in <= 0;
      end

      @(posedge clk) begin
         data_in <= 1;
      end


      #1000;
       $finish;
  end
  
endmodule




Verilog状态机三段式是指状态机Verilog写法中,将状态机的功能分为三个部分:状态转换逻辑、状态更新逻辑和输出逻辑。这种写法通常用于描述有限状态机的行为。状态转换逻辑决定下一个状态是什么,状态更新逻辑更新当前状态,而输出逻辑决定在每个状态下的输出信号。 引用提到了一段、两段三段式状态机写法。这三种写法在速度、面积和代码可维护性等方面各有优劣。其中,三段式状态机的特点是将状态转换、状态更新和输出逻辑分别独立实现,使得代码更加清晰和易于理解。 引用指出,在网络上搜索"三段式状态机"时,大多数给出的例子都是基于next_state输出的,很少看到基于current_state输出的。这导致了一种思维定势,即认为三段式状态机的第三段只能基于next_state描述,实际上这是不正确的。 根据引用中的描述,Mealy型状态机是一种常见的状态机类型,其状态变化不仅取决于当前状态,还取决于当前输入条件。输出信号不仅取决于状态,还取决于输入信号。因此,在实现Mealy型状态机时,三段式写法可以更好地描述状态转换、状态更新和输出逻辑。 总结起来,Verilog状态机三段式是一种常见的描述有限状态机行为的写法,其中包括状态转换逻辑、状态更新逻辑和输出逻辑。这种写法能够提高代码的可读性和可维护性,并且能够灵活地适应不同类型的状态机,如Mealy型状态机。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [verilog 有限状态机的基本概念和三种写法介绍](https://blog.csdn.net/qq_39507748/article/details/108763514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [数电和Verilog-时序逻辑实例四:状态机三段式描述)](https://blog.csdn.net/weixin_44915807/article/details/125001040)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值