网络知识 娱乐 04【verilog实战】串行数据流特定序列循环检测器的设计与功能验证(附源码)

04【verilog实战】串行数据流特定序列循环检测器的设计与功能验证(附源码)

写在前面,昨天一网友问了我关于状态机的问题,借此做一个记录:设计一个可循环检测的序列检测器记录,该模块使用moore型状态机实现,使用独热码编码。


虚拟机:VMware -14.0.0.24051
环 境:ubuntu 18.04.1
脚 本:makefile(点击直达)
应用工具:vcs 和 verdi


文章目录

  • 一、Demand
  • 二、Spec
  • (1)Analyze
  • (2)Interface Description
  • (3)FSM
  • 三、Design and Functional Verification
  • (1)RTL
  • (2)Test Bench
  • 四、Result


一、Demand

  模块功能是检测串行数据流中,一个5位数二进制10010出现的情况,实现循环检测(检测到10010之后,如果后续数据输入为010),即序列为10010010xxx,需检测到出现2次该序列,搭建测试平台进行功能验证。

二、Spec

(1)Analyze

  依需求可知,需检测的序列宽度为5,那么算上IDLE状态,状态机一共有6个状态,可设定为IDLE,S1,S2,S3,S4,S5。采用独热码编码。每检测到一次序列,输出一个信号,并且计数器自加1,以此记录一共检测到多少次。

在低速系统中,状态机中状态的个数 < 4个,使用二进制码编码
在低速系统中,状态机中状态的个数在4~24个,使用独热码编码
在低速系统中,状态机中状态的个数>24个,使用格雷码编码

(2)Interface Description

Signal NameWidthDirectionDescription
clk1inputSystem clk signal, xxMhz
rst1inputSystem reset signal
data1inputDetected data
result1outputDetection result signal
res_cnt2outputThe number of occurrences of the sequence

(3)FSM

在这里插入图片描述

三、Design and Functional Verification

(1)RTL

//-- modified by xlinxdu, 2022/04/24
module check #(
  parameter WIDHT = 2
)(
  input                   clk_i    ,
  input                   rst_n_i  ,

  //-- interface
  input                   data_i   ,
  output reg              result_o ,
  output reg [WIDHT-1:0]  res_cnt_o //(sum)
);

//-- state define
parameter  IDLE = 6'b00_0001;
parameter  S1   = 6'b00_0010;
parameter  S2   = 6'b00_0100;
parameter  S3   = 6'b00_1000;
parameter  S4   = 6'b01_0000;
parameter  S5   = 6'b10_0010;

reg  [5:0] cur_state;//current state
reg  [5:0] nxt_state;//next state

wire       result_s ;//sum
reg        nres_cnt ;//


/*-----------------------------------------------
 -----------  updata of current state  ----------
-----------------------------------------------*/

always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    cur_state <= 6'b0;
  end
  else begin
    cur_state <= nxt_state;
  end
end


/*-----------------------------------------------
 --------------  transfer of state  -------------
-----------------------------------------------*/

always @ (*) begin
  case(cur_state) 
    IDLE: if(data_i) nxt_state = S1  ;
          else       nxt_state = IDLE;

    S1  : if(data_i) nxt_state = S1  ;
          else       nxt_state = S2  ; 

    S2  : if(data_i) nxt_state = S1  ;
          else       nxt_state = S3  ;

    S3  : if(data_i) nxt_state = S4  ;
          else       nxt_state = IDLE;

    S4  : if(data_i) nxt_state = S1  ;
          else       nxt_state = S5  ;

    S5  : if(data_i) nxt_state = S1  ;
          else       nxt_state = S3  ;

    default:         nxt_state = IDLE;
  endcase
end

/*-----------------------------------------------
 ---------  updata of result counter  -----------
-----------------------------------------------*/
always @ (*) begin
  if(nxt_state == S5) begin
    nres_cnt = 1'b1;
  end
  else begin
    nres_cnt = 1'b0;//clear 
  end
end

always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    res_cnt_o <= 2'b0;
  end
  else begin
    res_cnt_o <= res_cnt_o + nres_cnt;
  end
end

/*-----------------------------------------------
 ---------- updata of result_o   ----------
-----------------------------------------------*/

//assign result_s = (cur_state == S4) ? 1'b1 : 1'b0;
assign result_s = (nxt_state == S5) ? 1'b1 : 1'b0;

always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    result_o <= 1'b0;
  end
  else begin
    result_o <= result_s;
  end
end

endmodule

(2)Test Bench

module tb_check;
  reg         clk_i    ;
  reg         rst_n_i  ;
  reg         data_i   ;

  wire        result_o ;
  wire  [1:0] res_cnt_o;

reg [17:0] data_check;

initial begin
  clk_i = 0 ;
  rst_n_i = 1;
  data_i = 0;
  data_check = 18'b10_1001_0001_0010_0100;

  #5 rst_n_i = 0;
  #10 rst_n_i = 1;
end

always begin
  data_i = data_check[17];
  #60 data_check = (data_check << 1'b1);
end


check tb_check(
               .clk_i    (clk_i    ),
               .rst_n_i  (rst_n_i  ),
               .data_i   (data_i   ),
               .result_o (result_o ),
               .res_cnt_o(res_cnt_o)
);

always begin
  #30 clk_i = ~clk_i;
end



initial begin
  #2000 $finish;
  
  $fsdbDumpfile("check.fsdb");
  $fsdbDumpvars            ;
  $fsdbDumpMDA             ;
end

endmodule

四、Result

在这里插入图片描述
  在测试平台中,输入的数据为data_check = 18’b10_1001_0001_0010_0100,转换成串行数据流输入到被测试模块DUT中,见上图三个框,10010出现了三次。功能实现了在每检测一次输出一个信号,记一次数,保证了模块基本的数据通路。


作者:xlinxdu
版权:本文是作者原创,版权归作者所有。
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。