verilog实现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

下面是编写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

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

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值