第06课 · 触发器

时序逻辑D触发器T触发器JK触发器

📌 学习目标:掌握 D/T/JK 三种触发器的原理、特性表和 Verilog 实现,通过 Verilator 验证时序行为。

一、从组合逻辑到时序逻辑

组合逻辑的输出仅取决于当前输入,没有记忆能力。时序逻辑引入了存储元件,输出取决于当前输入和历史状态

触发器(Flip-Flop)是最基本的存储元件:

二、D 触发器(Data Flip-Flop)

D 触发器是最常用的触发器,在 RISC-V CPU 中广泛使用。

功能:在时钟上升沿,将 D 输入传递到 Q 输出。

CLK 上升沿DQ(下一状态)
001
110

带异步复位和使能的 D 触发器:

rstenCLK ↑DQ(next)
1XXX0
00XQ(保持)
0100
0111

三、T 触发器(Toggle Flip-Flop)

T 触发器在 T=1 时翻转输出,T=0 时保持。常用于计数器设计。

CLK ↑TQ(next)
0Q(保持)
1Q̄(翻转)

特征方程:Q(next) = T ⊕ Q

四、JK 触发器

JK 触发器是功能最全的触发器,可以实现 D 和 T 触发器的所有功能。

CLK ↑JKQ(next)功能
00Q保持
010复位
101置位
11翻转

特征方程:Q(next) = J·Q̄ + K̄·Q

五、Verilog 实现

// flipflops.v — D/T/JK 触发器 // D 触发器(带异步复位、使能) module d_ff ( input clk, rst, en, d, output reg q ); always @(posedge clk or posedge rst) begin if (rst) q <= 1'b0; else if (en) q <= d; end endmodule // T 触发器(带异步复位) module t_ff ( input clk, rst, t, output reg q ); always @(posedge clk or posedge rst) begin if (rst) q <= 1'b0; else if (t) q <= ~q; end endmodule // JK 触发器(带异步复位) module jk_ff ( input clk, rst, j, k, output reg q ); always @(posedge clk or posedge rst) begin if (rst) q <= 1'b0; else case ({j, k}) 2'b00: q <= q; // 保持 2'b01: q <= 1'b0; // 复位 2'b10: q <= 1'b1; // 置位 2'b11: q <= ~q; // 翻转 endcase end endmodule

5.1 测试台

// tb_flipflops.v — 触发器测试台 module tb_flipflops; reg clk, rst; // D FF 信号 reg d_en, d_in; wire d_q; // T FF 信号 reg t_in; wire t_q; // JK FF 信号 reg j_in, k_in; wire jk_q; d_ff u_dff (.clk(clk), .rst(rst), .en(d_en), .d(d_in), .q(d_q)); t_ff u_tff (.clk(clk), .rst(rst), .t(t_in), .q(t_q)); jk_ff u_jkff (.clk(clk), .rst(rst), .j(j_in), .k(k_in), .q(jk_q)); integer pass = 0, fail = 0; task check_d; input expected; begin if (d_q !== expected) begin $display("FAIL D_FF: expected=%b got=%b", expected, d_q); fail=fail+1; end else pass=pass+1; end endtask task check_t; input expected; begin if (t_q !== expected) begin $display("FAIL T_FF: expected=%b got=%b", expected, t_q); fail=fail+1; end else pass=pass+1; end endtask task check_jk; input expected; begin if (jk_q !== expected) begin $display("FAIL JK_FF: expected=%b got=%b", expected, jk_q); fail=fail+1; end else pass=pass+1; end endtask always #5 clk = ~clk; initial begin clk = 0; rst = 1; d_en = 0; d_in = 0; t_in = 0; j_in = 0; k_in = 0; #12; rst = 0; // 释放复位 // D FF: 加载1 d_en = 1; d_in = 1; #10; check_d(1); // D FF: 保持(en=0) d_en = 0; d_in = 0; #10; check_d(1); // D FF: 加载0 d_en = 1; d_in = 0; #10; check_d(0); // T FF: 翻转3次 t_in = 1; #10; check_t(1); #10; check_t(0); #10; check_t(1); // T FF: 保持 t_in = 0; #10; check_t(1); // JK FF: 置位 (J=1,K=0) j_in = 1; k_in = 0; #10; check_jk(1); // JK FF: 保持 (J=0,K=0) j_in = 0; k_in = 0; #10; check_jk(1); // JK FF: 复位 (J=0,K=1) j_in = 0; k_in = 1; #10; check_jk(0); // JK FF: 翻转 (J=1,K=1) j_in = 1; k_in = 1; #10; check_jk(1); #10; check_jk(0); // 复位测试 rst = 1; #10; check_d(0); check_t(0); check_jk(0); $display("========================================"); $display("触发器测试: PASS=%0d FAIL=%0d", pass, fail); if (fail == 0) $display("✅ D/T/JK 触发器时序验证全部通过!"); else $display("❌ 存在失败!"); $display("========================================"); $finish; end endmodule

六、Verilator 编译命令

verilator --cc flipflops.v --exe tb_flipflops.v \ --build --top-module tb_flipflops ./obj_dir/Vtb_flipflops

七、触发器的关键概念

类型特征方程主要用途
D FFQ(n+1) = D数据寄存、流水线寄存
T FFQ(n+1) = T ⊕ Q计数器、分频器
JK FFQ(n+1) = JQ̄ + K̄Q通用触发器

🤔 思考题:如何用 D 触发器实现 T 触发器?如何用 JK 触发器实现 D 触发器?

💡 提示:D_FF + XOR = T_FF;JK_FF 令 K=J̄ 即为 D_FF

🏆 成就解锁:时序逻辑入门

✅ Verilator 仿真验证通过

✅ D 触发器:加载、保持、复位验证正确

✅ T 触发器:翻转、保持验证正确

✅ JK 触发器:置位、复位、保持、翻转验证正确

🎯 下一目标:多位寄存器 → 第07课:寄存器