当前位置:   article > 正文

verilog实现1101序列检测_1101序列检测器

1101序列检测器

学习状态机,这是数电部分非常重要的基础知识,现在利用Verilog来实现,并用modelsim进行仿真。
序列检测并非完全等价于状态机,而是状态机重要应用之一。本次实验进行序列检测1101,当这个序列出现时,输出高电位,其他状态都为0。
常见的序列检测有循环检测和非循环检测两种,循环检测就是上一个序列结尾可以作为下一个序列的开端,例如110110111001101,在第一个1101到来后会输出1,同时结尾1也可以作为下一个1101序列的开端,因此整个序列可以产生3个高电位;而如果是非循环检测,每一个序列不能重复使用,上个1101出现后,这4位信号被“丢弃”,只有下一个完整的1101出现才再次出现高电位输出,则对于这整个序列来说只输出2个高电位。
这对于状态机编码来说会产生一定的差别,对于循环编码而言,可以画出以下状态机图
在这里插入图片描述
状态d出现后,下一位输入如果是1,则继续可以作为下一个1101序列的开端,因此可以回到b状态。
而对于非循环编码来说,其状态机图可以如下所示

在这里插入图片描述
这里引入了新的状态e,为了使电路可以正常循环往复,虽然名为“非循环检测”,还是要把e状态的下一个状态与a状态链接起来。
对于状态机的画法是数电时序逻辑知识的基础部分,如果不清楚应当重新回到数电部分进行理解,这里强调一句,我们一般假定第一个状态是被检测状态首位的非状态。例如我们这里要检测1101,即我们总是假定,此处的a状态是“输入为0的一个状态”,因此才有状态图中状态a当下一位输入为1时进入下一个新状态,而如果输入仍为0则保持原状态。
下面进行Verilog编码,首先是核心代码

module state_machine (
    input        sys_clk,
    input        sys_rst_n,
    input        din,
    output  reg  dout
);

    // 非循环检测状态赋值
    // localparam a = 3'b000;
    // localparam b = 3'b001;
    // localparam c = 3'b010;
    // localparam d = 3'b011;
    // localparam e = 3'b100;

    //循环检测状态赋值
    localparam a = 2'b00;
    localparam b = 2'b01;
    localparam c = 2'b10;
    localparam d = 2'b11;

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

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n) begin
            current_state <= a;
        end else begin
            current_state <= next_state;
        end
    end

    //1101序列检测器
    always @(*) begin
        case (current_state)
            a:if(din==1'b1) begin
                next_state = b;
            end else begin
                next_state = a;
            end 
            b:if(din==1'b1) begin
                next_state = c;
            end else begin
                next_state = a;
            end
            c:if(din==1'b0) begin
                next_state = d;
            end else begin
                next_state = c;
            end
            d:if(din==1'b1) begin
                next_state = b;
            end else begin
                next_state = a;
            end
            //如果是非循环检测则需要引入以下代码
            // e:if(din==1'b1) begin
            //     next_state = b;
            // end else begin
            //     next_state = a;
            // end
            default: next_state = a;
        endcase
    end

    always@* begin
        if(current_state==d && next_state==b) begin
            dout <= 1;
        end else begin
            dout <= 0;
        end
    end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

下面是编写testbench代码

`timescale 1ns/1ps

module tb_state_machine();

reg   sys_clk;
reg   sys_rst_n;

reg   din;

wire   dout;

parameter  PERIOD = 20;  

// parameter  DIN_LIST = 21'b10111011011010010020;

reg [20:0] din_list;
integer i;



always begin
    sys_clk = 1'b0;
    #(PERIOD/2) sys_clk = 1'b1;
    #(PERIOD/2);
end


initial begin
    sys_rst_n <= 1'b0;
    // din_list <= DIN_LIST;
    #20
    sys_rst_n <= 1'b1;
    din <= 1'b0;
    // for (i = 0; i < 21 ;i=i+1 ) begin
    //     #PERIOD
    //     din <= din_list[i];
    // end
    #20    //注意,此处每一个间隔时间必须与PERIOD时间相同,否则无法正常识别
    din <= 1'b1;
    #20
    din <= 1'b0;
    #20
    din <= 1'b1;
    #20
    din <= 1'b1;
    #20
    din <= 1'b1;
    #20
    din <= 1'b0;
    #20
    din <= 1'b1;
    #20
    din <= 1'b1;
    #20
    din <= 1'b0;
    #20
    din <= 1'b1;
    #20
    din <= 1'b1;
    #20
    din <= 1'b0;
    #20
    din <= 1'b1;
    #20
    din <= 1'b0;
end

// always 
//     #(PERIOD/2) sys_clk = ~sys_clk;

// always@(posedge sys_clk or negedge sys_rst_n) begin
//  #20
//  din_list = {din_list[19:0],din[20]};

state_machine u_state_machine (
    .sys_clk    (sys_clk),
    .sys_rst_n  (sys_rst_n),
    .din        (din),
    .dout       (dout)
);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

我这里编写的testbench比较繁琐,其中注释部分标出了另一种用for循环产生一批序列的方法。注意,我已经在代码中用注释标出,序列产生的时间间隔必须与时钟周期相等,否则状态机无法正常识别!
用modelsim进行仿真,结果如下
在这里插入图片描述
这是循环检测结果,可见,对于序列010111011011010成功识别到了三次,产生三次高电位。修改代码就可以实现非循环检测,这里不再赘述。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/676647
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&