Verilog实战:从零开始手把手教你实现寄存器、触发器和锁存器

Verilog实战:从零开始手把手教你实现寄存器、触发器和锁存器

如果你刚开始接触数字电路设计,面对Verilog里那些听起来差不多的“存储单元”——寄存器、触发器、锁存器,是不是感觉有点懵?它们好像都能存数据,但写起代码来又各有各的规矩。别担心,这篇文章就是为你准备的。我们不谈枯燥的理论区别,直接打开编辑器,一行行代码敲下去,在仿真波形里亲眼看看它们到底是怎么“干活”的。我会假设你有一个基础的FPGA开发环境(比如Vivado、Quartus,甚至是开源的Icarus Verilog + GTKWave),跟着步骤走,你不仅能写出正确的代码,更能理解背后的“为什么”,以及如何避开那些新手常踩的坑。准备好了吗?让我们从最基础的触发器开始,一步步构建起你的存储单元知识体系。

1. 基石:从D触发器开始理解时序逻辑

在数字世界的记忆体里,D触发器是最小、最核心的存储单元。你可以把它想象成一个极其守时的哨兵:只有在时钟信号发出明确指令(比如上升沿)的瞬间,它才会看一眼当前的输入数据D,并将其牢牢记住,直到下一个指令到来。这种“边沿触发”的特性,是构建一切稳定时序系统的根基。

1.1 编写你的第一个D触发器

让我们先抛开所有高级功能,实现一个最纯净的、带异步复位的D触发器。所谓异步复位,意味着无论时钟在做什么,只要复位信号有效,输出就必须立刻被清零,这为系统提供了一个确定的初始状态。

module d_flip_flop_basic (
    input wire clk,      // 时钟信号
    input wire rst_n,    // 低电平有效的异步复位信号
    input wire d,        // 数据输入
    output reg q         // 数据输出
);

// 核心逻辑:always块对时钟上升沿和复位下降沿敏感
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        // 复位有效时,无条件将输出清零
        q <= 1'b0;
    end else begin
        // 在时钟上升沿,将输入d的值锁存到输出q
        q <= d;
    end
end

endmodule

注意:这里使用了 <= 非阻塞赋值。在描述时序逻辑时,务必使用非阻塞赋值,这能确保在时钟沿触发的瞬间,所有触发器并行更新,模拟真实的硬件行为。使用阻塞赋值 = 会导致不可预测的仿真结果和综合后的电路功能错误。

这个模块虽然简单,但包含了时序逻辑描述的所有关键要素:敏感列表、边沿检测、条件判断。在仿真中,你会看到 q 只在 clk 的上升沿且 rst_n 为高时,才变化为 d 的值。

1.2 添加同步使能信号

在实际项目中,我们经常需要控制触发器是否在某个时钟周期更新数据,这就需要引入同步使能信号。它不像复位那样具有“最高优先级”,其生效完全依赖于时钟边沿。

module d_flip_flop_with_en (
    input wire clk,
    input wire rst_n,
    input wire en,      // 同步使能信号,高有效
    input wire d,
    output reg q
);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q <= 1'b0;
    end else if (en) begin  // 使能信号有效时,才更新数据
        q <= d;
    end
    // 如果en为0,则q保持原值,无需显式写出
end

endm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值