Verilog实现常见电路(二)

常见电路系列连接

https://blog.csdn.net/weixin_40634481/article/details/122940873?spm=1001.2014.3001.5501icon-default.png?t=M1H3https://blog.csdn.net/weixin_40634481/article/details/122940873?spm=1001.2014.3001.5501

目录:

一、边沿检测

二、串并转换

三、分频器

四、异步复位同步释放

五、序列信号产生器

六、序列检测器

四、异步复位同步释放

上来先来三个问题

问题一:为什么要用异步复位同步释放?

答:这个问题要从同步复位和异步复位优缺点来解释,异步复位的缺点是其可能会引起亚稳态,同步复位的缺点是需要消耗较多的资源优点是降低了亚稳态出现的概率,而异步复位同步释放即保留了异步复位的功能,又避免了异步复位释放时所面临的recovery或者removal违例的问题。

问题二:异步复位同步释放是怎么工作的?

答:

我的理解就是单比特数据通过打拍的方式来降低亚稳态发生的概率,当rst_async_n信号有效时第二个触发器的输出为低电平,复位有效,如果rst_async_n信号释放时刚好在clk上升沿,则第一个触发器的输出可能是亚稳态,通过打一拍的方式可以降低亚稳态的概率(关于亚稳态的问题计划到后面会详细总结一篇文章)

问题三:为什么触发器的输入端直接给1'b1而不是复位信号?

答:这样也是为了节省资源,减少了一个反相器。

always@(posedge clk or negedge rst_async_n)
    if(~rst_n)begin
        rst_n_d1 <= 1'b0;
        rst_n_d2 <= 1'b0;
    end
    else begin
        rst_n_d1 <= 1'b1;
        rst_n_d2 <= rst_n_d1;
    end
assign rst_sync_n=rst_n_d2;

五、序列信号产生器

module sequence_gen(
    input clk,
    input rst_n,

    output reg dout
);
localparam [4:0] s0=5'b00001,
                 s1=5'b00010,
                 s2=5'b00100,
                 s3=5'b01000,
                 s4=5'b10000;
reg [4:0] state,next_state;

always@(posedge clk or negedge rst_n)
    if(~rst_n)
        state<=s0;
    else
        state<=next_state;

always@(*)
    case(state)
        s0:next_state=s1;
        s1:next_state=s2;
        s2:next_state=s3;
        s3:next_state=s4;
        s4:next_state=s0;
        default:next_state=s0;
    endcase

always@(posedge clk or negedge rst_n)
    if(~rst_n)
        dout<=1'b0;
    else
        case(next_state)
            s0:dout=1'b0;
            s1:dout=1'b0;
            s2:dout=1'b1;
            s3:dout=1'b0;
            s4:dout=1'b1;
        endcase


endmodule

仿真代码

`timescale 1ns/1ns
module tb_sequence();
parameter PERIOD=10;
bit clk;
reg rst_n;
wire dout;

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

initial begin
    rst_n=0;
    #PERIOD;
    rst_n=1;
end 

sequence_gen u_sequence_gen(
    .clk   (clk   ),
    .rst_n (rst_n ),
    .dout  (dout  )
);
endmodule

波形图

六、序列发生器

有”1101“序列输入时输出1否则输出0

先画状态机

module seqdetection(
    input clk,
    input rst_n,
    input data_i,

    output flag
);
localparam IDLE=5'b00001,
           s0=5'b00010,
           s1=5'b00100,
           s2=5'b01000,
           s3=5'b10000;
reg [4:0] state,next_state;

always@(posedge clk or negedge rst_n)
    if(~rst_n)
        state<=IDLE;
    else
        state<=next_state;

always@(*)
    case(state)
        IDLE:if(data_i)
                next_state=s0;
            else
                next_state=IDLE;
        s0:if(data_i)
                next_state=s1;
            else
                next_state=IDLE; 
        s1:if(data_i)
                next_state=s1;
            else
                next_state=s2;   
        s2:if(data_i)
                next_state=s3;
            else
                next_state=IDLE;    
        s3:if(data_i)
                next_state=s1;
            else
                next_state=IDLE;
    endcase
           
assign flag=(state==s3)?1'b1:1'b0;
endmodule 

仿真代码

`timescale 1ns/1ps
module tb_seqdetection ();
    
parameter PERIOD=10;
bit clk;
reg rst_n;
reg data_i;
wire flag;

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

initial begin
    rst_n=0;
    #PERIOD;
    rst_n = 1;
    repeat(2) seq_gen();
    data_i=1;
    #PERIOD;
    data_i=0;
    #PERIOD;
    data_i=0;
    seq_gen();
end

task seq_gen;
begin
    data_i=1;
    #PERIOD;
    data_i=1;
    #PERIOD;
    data_i=0;
    #PERIOD;
    data_i=1;
    #PERIOD;
end
endtask

seqdetection u_seqdetection(
    .clk    (clk    ),
    .rst_n  (rst_n  ),
    .data_i (data_i ),
    .flag   (flag   )
);

endmodule

波形图