Verilog单边沿检测和双边沿检测的方法(HDLBits例题)

1.单边沿检测

边沿检测是用来检测某一信号是否发送了从0至1或者从1至0的变化,有同步和异步之分。
同步边沿检测:是使用一个基准时钟,即在同一个时钟下来检测一个信号的上升沿或者下降沿。
异步边沿检测:是利用D触发器来实现边沿检测。

HDLBits例题: 单边沿检测例题

例题
题目:对于8位向量中的每一位,检测输入信号在一个时钟周期内从0变化到下一个时钟周期的1(类似于正边缘检测)。输出位应该在0到1转换发生后的循环中设置。

解法是让该信号再过一级触发器,令 in_r <= in; 有点像打了一拍,然后当判断到前一次信号为1(in == 1),这一次信号为0(in_r == 0)时即发生了信号0至1的跳变。这就是上升沿检测

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] in_r;
    always@(posedge clk)begin
        in_r <= in;
        pedge <= in & ~in_r;
    end
        

endmodule

另外检测下降沿的话也是同样的原理,让该信号再过一级触发器,令 in_r <= in; 然后当判断到前一次信号为0(in == 0),这一次信号为1(in_r == 1)时即发生了信号0至1的跳变。

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] in_d;
    always@(posedge clk)begin
        in_d <= in;
        pedge <= ~in & in_d;
    end
        

endmodule

2.双边沿检测的方法

同样用HDLBits里的一道例题来做说明:双边沿检测例题
双边沿检测
题目:你熟悉的触发器是在时钟的正边缘触发的,或者是在时钟的负边缘触发的。双边触发触发器是在时钟的两个边触发的。然而,fpga没有双边触发触发器,并且always @(posedge clk或negedge clk)不被接受为法律敏感性列表。

这一题乍一想,,感觉可以用always @(posedge clk或negedge clk)或者用两个触发器,即两个always语句,一个判断posedge一个判断negedge,但是这样是不行的 😭 ……
但是可以用其他方法解决,这里提供两种解法:
①:

module top_module (
    input clk,
    input d,
    output q
);

    reg [1:0] tmp;
    always @ (posedge clk) begin
        tmp[0] <= d;
    end
    always @ (negedge clk) begin
        tmp[1] <= d;
    end
    
    assign q = clk?tmp[0]:tmp[1];
endmodule

这种比较常规,另一种方法会更妙一些。
②,利用两次异或等于本身的方法,即p^d ^p = d的这种想法来做:

module top_module (
    input clk,
    input d,
    output q
);
    reg n,p; 
    always@(posedge clk)begin
        p <= d ^ n;
    end
    always@(negedge clk)begin
        n <= d ^ p;	
    end    
    assign q = p ^ n;
endmodule

👌