第14章:寄存器
本章对应原书第 351~355 页,属于「第四篇 数字电路篇」。
本章在讲什么?(先看这个)
上一章的锁存器是"反面教材",这一章的寄存器则是时序逻辑的"正面主角"——可以说没有寄存器就没有时序逻辑。寄存器由触发器(Flip-Flop)组成,一个触发器构成一位寄存器,多个触发器可以组成多位寄存器。本章将从 D 触发器的主从结构讲起,弄懂"时钟上升沿采样、其他时刻保持"的机制,再通过设计一个 4 级串联移位寄存器,理解时序逻辑里最重要的概念之一:"打一拍"(延迟一个时钟周期)。
核心概念拆解
寄存器简介
寄存器一般由多个触发器构成,所以先从触发器说起。

上图电路由两个相同的 D 锁存器和两个非门连接而成:F1 是主锁存器,F2 是从锁存器。F1 的输出 Q0 就是 F2 的输入,形成了主从关系;两个锁存器的控制信号都由外部时钟信号 CLK 提供。
工作过程——分前后两拍:
- CLK=0 时(前半拍):CLK 经过非门后作为 F1 的控制信号,此时 F1 控制信号为 1,F1 被选通处于工作状态。若输入 D 为 1,F1 的输出 Q0 就为 1(Q0 同时是 F2 的输入)。但 CLK 经两个非门后到 F2 时为 0,F2 被锁存、处于保持状态,输入 D 无法直接影响输出 Q1。这一阶段:输入信号先存入主锁存器,但不影响输出。
- CLK 由 0 变 1 时(后半拍):经非门后 F1 的控制信号变为 0,主锁存器 F1 被"锁住",Q0 保持当前值,即使 D 再变也不受影响;而经两个非门后 F2 的控制信号为 1,F2 进入工作状态,Q0 作为 F2 的输入直接影响输出 Q1——Q0 为 1 则 Q1 为 1,Q1' 为 0。
结论:在 CLK 由 0 变 1 的一个变化周期内,触发器的输出状态只可能改变一次——这就是"边沿触发",它天然把输入和输出隔离开,避免了锁存器"电平期间直通"的问题。
寄存器的两种连接方式
一个触发器可以看作一位寄存器;多个触发器组成多位寄存器,可以存储多 bit 二进制数据。按输入方式分两种:
触发器并联:多个触发器的输入是相同信号,输出也相同。

以 2bit 寄存器为例:F1、F2 的输入都是 D0,各自经过时钟上升沿采样后输出 Q0、Q1。因为输入相同,输出也相同。
并联状态下 2bit 寄存器的状态表:
| 时钟 CLK | 输入 D0 | 输出 Q0、Q1 | 说明 |
|---|---|---|---|
| 上升沿 | 0/0 | 0、0 | 数据采样 |
| 上升沿 | 1/1 | 1、1 | 数据采样 |
| 下降沿 | X | 保持 | 数据保持 |
| 下降沿 | X | 保持 | 数据保持 |
| 0/1(非沿) | X | 不变 | 数据锁存 |
只有在时钟的上升沿,数据才会被采样;其他时刻数据保持/锁存不变。
触发器串联:输入互相传递——下一个触发器的输入是上一个触发器的输出。

F1 的输入是 D0,上升沿采样后输出 Q0;F2 的输入来自 Q0,所以 F2 的输出比 F1 的输出晚一个时钟周期——这就是常说的"延迟一拍",逻辑电路设计里俗称"打一拍",或寄存一拍。
串联状态下 2bit 寄存器的状态表:
| 时钟 | F1输入 D0 | F1输出/F2输入 Q0 | F2输出 Q1 | 说明 |
|---|---|---|---|---|
| 上升沿 | 数据采样 | / | / | F1采样 |
| 上升沿 | X | 数据采样 | / | F2采样F1上次结果 |
| 下一个上升沿 | X | X | 数据到达 | F1的值传到F2 |
| 0/1(非沿) | 不变 | 不变 | 不变 | 数据锁存 |
当 F1 输入为 1 时,上升沿采样后 F1 输出 1,此时 F2 输出还是 0;下一个上升沿过后,F2 的输出才变为 1。如果更多触发器依次串联,完成的就是多级打拍,也就是逻辑电路里的移位功能——信号在时钟上升沿到来时依次传递到下一个寄存器。
实验任务
设计一个 4 级串联寄存器电路。
程序设计——模块设计
4 级串联寄存器:输入端口 a,输出端口 y,中间用 4 个触发器串联。每个触发器都需要时钟和复位信号,所以还有时钟端口和复位端口。

| 信号名 | 方向 | 端口说明 |
|---|---|---|
| sys_clk | 输入 | 系统时钟,50MHz |
| sys_rst_n | 输入 | 系统复位按键,低电平有效 |
| a | 输入 | 输入信号a |
| y | 输出 | 输出信号y |
绘制波形图

从波形图可以看出:因为是时序逻辑,输入 a 的值会延迟一个时钟周期才赋给 a_reg1;以此类推,每个寄存器的值都延迟一个时钟周期传给下一个寄存器。信号要经过 4 拍才能到达 y。
编写代码
module shfit_reg(
input sys_clk ,//系统时钟
input sys_rst_n ,//系统复位
input a ,//输入信号
output y //输出信号
);
//*****************************************************
//** main code
//*****************************************************
//reg 定义
reg a_reg1; //寄存器1
reg a_reg2; //寄存器2
reg a_reg3; //寄存器3
reg a_reg4; //寄存器4
//对输入信号a进行多次寄存
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
a_reg1 <= 1'b0;
a_reg2 <= 1'b0;
a_reg3 <= 1'b0;
a_reg4 <= 1'b0;
end
else begin
a_reg1 <= a;
a_reg2 <= a_reg1;
a_reg3 <= a_reg2;
a_reg4 <= a_reg3;
end
end
//将a_reg4赋值给y
assign y = a_reg4;
endmodule
代码解读:
- 第 14~17 行定义了 4 个寄存器;
- 第 20 行的
always@(posedge sys_clk or negedge sys_rst_n)是标准时序逻辑写法:时钟上升沿触发,复位信号下降沿(低电平有效)异步复位; - 复位时 4 个寄存器全部清零;正常工作时
a_reg1 <= a; a_reg2 <= a_reg1; ...四级串联; - 第 36 行用 assign 把 a_reg4 连到输出 y。
用 Vivado 的 RTL ANALYSIS 查看 RTL 电路:

图中每个触发器都有 sys_clk 输入端口、异步清零端口和输出端口,输入 a 经过 a_reg1~a_reg4 的串联输出到 y——一个由 4 级寄存器组成的移位寄存器。
仿真验证——编写 TB 文件
`timescale 1ns / 1ns
module tb_shfit_reg();
//reg define
reg sys_clk;
reg sys_rst_n;
reg a;
//wire define
wire y;
//初始化
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
a <= 1'b0;
#201
sys_rst_n <= 1'b1;
#100
a <= 1'b1;
#100
a <= 1'b0;
end
//生成系统时钟50MHz
always #10 sys_clk <= ~sys_clk;
//例化移位寄存器模块
shfit_reg shfit_reg_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.a (a ),
.y (y )
);
endmodule
TB 要点:先复位 201ns 后拉高 sys_rst_n 结束复位;always #10 sys_clk <= ~sys_clk; 每 10ns 翻转一次时钟,产生周期 20ns(50MHz)的系统时钟;a 拉高 100ns 再拉低,制造一个供观察的脉冲。
仿真验证

从波形可以清楚看到移位现象:a 变为 1 之后,下一个时钟上升沿 a_reg1 拉高;再经过一个时钟 a_reg2 拉高;再一个时钟 a_reg3 拉高;a 拉高之后的第 4 个时钟,a_reg4 也由低变高。因为 a_reg4 通过 assign 直接赋给 y,所以 y 的波形和 a_reg4 完全一样。
两个关键观察:触发器的采样只在时钟上升沿进行,其他时候保持之前采样的信号;数据依次移动到下一个触发器——这就是移位的效果。
本章总结
本章介绍了寄存器的相关概念(触发器主从结构、并联与串联),并通过 4 级串联寄存器的仿真直观看到了"延迟一拍"。要养成一个重要思维:看到 always 块下的时序逻辑,就要自然想到会产生延迟一拍的现象——这就是常说的"打拍"操作。打拍在后面的工程中无处不在,比如信号同步、数据处理流水线等。
图片对照
本章图片已按讲解位置分散插入各小节,包括 D 触发器结构图、2bit 寄存器并联/串联示意图、模块框图、波形图、RTL 电路和仿真波形。
初学者容易踩的坑
- 以为输出会"立刻"等于输入:时序逻辑输出延迟一拍才更新,对波形做验证时别忘了留出一个时钟的余量。
- 复位极性搞混:sys_rst_n 是低电平有效,敏感列表写
negedge sys_rst_n,if 条件写!sys_rst_n,三处要一致。 - 串联赋值顺序的误解:
a_reg1 <= a; a_reg2 <= a_reg1;看似"同时"执行,非阻塞赋值保证 a_reg2 拿到的是 a_reg1 的旧值,这正是移位寄存器正确工作的关键;写成阻塞赋值=逻辑就变了。 - 把锁存器和寄存器混为一谈:锁存器电平触发、无时钟、无法时序分析;寄存器(触发器)边沿触发、有时钟、可做时序分析——设计中应避免前者、使用后者。
- 位宽随手写:多位寄存器要按需声明位宽(如
reg [3:0]),本章是 1bit 信号所以不需要,但习惯上要时刻有位宽意识。
小结 & 下一步
本章理解了 D 触发器"上升沿采样、一周期只变一次"的原理,掌握了寄存器并联(同输入同输出)与串联(延迟一拍、移位)两种结构,并完成了 4 级移位寄存器的设计与仿真。建议动手拓展:结合上一章锁存器的内容,对比锁存器和寄存器的区别——提示一下,锁存器最大的危害是什么?记不清的话,试着画一画两者的波形图进行对比,答案自然清晰。