Verilog HDL双沿采样(上升沿、下降沿)电路设计(深入理解)

目录

前言

题目

方法一

方法二

注意点

总结


前言

今天下午更新了一篇博客,对于博客中的一个问题我觉得有必要再深入探讨一下,那就是双沿采样电路。

题目

Build a circuit that functionally behaves like a dual-edge triggered flip-flop:

方法一

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

为什么这种方法可以呢?

首先,在上升沿的时候,q_d1变成了d ^ q_d2,那么q = q_d1 ^ q_d2 = d ^ q_d2 ^ q_d2 = d;

接着,在下降沿的时候,q_d2变成了d ^ q_d1,那么q = q_d1 ^ q_d2 = q_d1 ^ d ^ q_d1 = d;

在每个正负沿,q_d1和q_d2交替出现,因此q总会输出最新的值。

这样就可以实现双沿采样,这种方法真是非常巧妙~

方法二

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

    reg q_d1;
    reg q_d2;

    always@(posedge clk)begin
        q_d1 <= d;
    end
    
    always@(negedge clk)begin
        q_d2 <= d;
    end
    
    assign q = clk ? q_d1 : q_d2;
    
endmodule

这种方法更好理解,在上升沿和下降沿分别对d采样,然后根据时钟的正负,选择输出上升沿和下降沿采样后的信号。博主最先想到的答案也是这个。对于做题而言,这个答案没有任何问题,因为毛刺对success不会有很大影响,但是实际应用中,这个电路会产生毛刺。

大家可以想象,在上升沿和下降沿采到d信号以后,q_d1和q_d2会立即变化,同时时钟也会立即变化,时钟和q_d1、q_d2的变化的延迟是不一致的,这就导致了毛刺的出现,这时候的时钟相当于是一个组合逻辑了,由于路径延时的不同,导致组合逻辑到达的时间存在差异,从而会产生毛刺,如下图所示。

为什么方法一不会产生毛刺呢?大家看看代码,方法一的结果是两个寄存器直接异或,没有涉及到时钟信号,方法二的结果需要时钟信号进行判断,而时钟信号时钟的上升沿和下降沿又是触发器的输出,即q_d1、q_d2,因此会产生毛刺。

注意点

不能使用always@(posedge clk or nededge clk),不瞒大家说,博主第一次就尝试了这个方法,但是这种写法是不可综合的,严禁使用!

总结

今天对于这个小问题又多做了一点说明,希望大家能够掌握着两种写法的差异,并且明白毛刺产生的原因。最后希望能和大家一起学习,共同进步~

<think>好的,我现在要解决用户的问题:如何在Verilog中实现上升沿采样。用户已经提供了一些相关的引用资料,我需要仔细分析这些资料,并结合自己的知识来给出一个清晰的回答。 首先,我需要回顾一下Verilog中的基本概念。上升沿采样通常是指在时钟信号的上升沿时刻捕获输入信号的值。这在数字电路设计中非常常见,比如在触发器中,数据在时钟边沿被采样存储。根据引用[1],上升沿检测模块pose_chk的实现方式是使用两个寄存器curr和last,每个时钟上升沿将当前输入in赋值给curr,然后将curr的值传递给last。这样,curr总保存当前周期的输入值,而last保存前一周期的值。输出out是curr与last取反后的逻辑与,即当curr为1且last为0时,表示检测到了上升沿。不过用户的问题是关于采样,而不是边沿检测,所以可能需要调整思路。 根据引用[3]和[4],双沿采样可以通过在posedge和negedge分别采样,并用组合逻辑选择输出。但用户只关心上升沿采样,所以可能更简单。引用[2]提到Verilog HDL上升沿采样,可能是指使用always块在posedge clk时采样输入信号。 接下来,我需要确认用户的需求。用户问的是“上升沿采样”,即如何在时钟上升沿时刻正确捕获输入信号的值。这通常是通过D触发器实现的,每个时钟上升沿将输入d的值存储到寄存器q中。例如,引用[4]中的代码示例虽然尝试双沿触发,但正确的上升沿采样应只在posedge clk时赋值。 需要区分边沿检测和采样。边沿检测是检测信号从低到高的变化,而采样是在边沿时刻读取信号的值。用户的问题更偏向于后者,即在时钟上升沿时刻进行数据采样,这其实是同步设计的基本操作。 可能存在的误区:用户可能混淆了边沿检测和采样。根据引用[1],边沿检测模块的输出是一个脉冲信号,表示上升沿的出现。而采样则是在时钟边沿稳定地捕获数据,如触发器的工作方式。因此,正确的上升沿采样实现应是在always@(posedge clk)块中将输入赋值给寄存器。 另外,需要确保代码符合Verilog语法,使用非阻塞赋值<=,并且正确声明寄存器变量。例如,在引用[3]的方法二中,使用两个always块分别在posedge和negedge采样,但用户只需要posedge的情况。 总结步骤: 1. 在模块中声明时钟clk、输入d和输出q。 2. 使用寄存器(如q_reg)存储采样值。 3. 在always块中,通过posedge clk触发,将d赋值给q_reg。 4. 将q_reg连接到输出q。 需要检查是否有常见错误,比如在多个always块中对同一变量赋值,这会导致综合错误。例如,引用[4]中的代码在两个always块中都对q赋值,这在Verilog中是不允许的,因为会产生多驱动问题。正确的做法是使用单个always块在posedge clk时采样。 最后,生成相关问题需要考虑用户可能进一步的问题,比如如何避免亚稳态、同步复位、或如何实现下降沿采样等。</think>在Verilog中实现上升沿采样主要依托时钟信号的上升沿触发机制,这是同步数字电路设计的核心基础。以下是具体实现方法和注意事项: ### 一、基本实现方法 使用`always`块配合`posedge`时钟边沿检测语法,实现代码如下: ```verilog module posedge_sample( input clk, input d, output reg q ); always@(posedge clk) begin q <= d; // 时钟上升沿采样输入信号 end endmodule ``` 该代码实现了一个D触发器,在时钟上升沿时刻对输入信号`d`进行采样并存储到寄存器`q`中[^2][^4]。 ### 二、关键实现细节 1. **时序控制** `posedge clk`语法明确指定了仅在时钟上升沿触发采样操作,这是实现可靠采样的前提条件[^2] 2. **非阻塞赋值** 使用`<=`运算符确保时序逻辑的正确性,这种赋值方式模拟了硬件并行执行特性 3. **寄存器声明** 输出信号`q`必须声明为`reg`类型,因为它在过程块中被赋值[^1] 4. **亚稳态处理** 当输入信号`d`不满足建立/保持时间时,可通过添加两级触发器实现同步: ```verilog always@(posedge clk) begin q_d1 <= d; // 第一级同步 q <= q_d1; // 第二级同步 end ``` ### 三、典型应用场景 1. 寄存器数据锁存 2. 状态机状态转移 3. 同步信号采样 4. 跨时钟域同步的第一级处理
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值