第03课 · 组合逻辑
组合逻辑MUX译码器Verilator
📌 学习目标:掌握组合逻辑电路设计方法,实现多路选择器(MUX)、译码器(Decoder)、编码器(Encoder),并通过 Verilator 仿真验证。
一、组合逻辑概述
组合逻辑电路的输出仅取决于当前输入,与历史状态无关。这是与时序逻辑的核心区别。组合逻辑电路:
- 没有存储元件(无触发器、寄存器)
- 没有反馈回路(无环路)
- 输出 = f(输入) — 纯函数
二、多路选择器(MUX)
多路选择器从多个输入中选择一个输出,是 CPU 数据通路中最关键的组件之一。
2.1 2选1 MUX
sel=0 时输出 d0,sel=1 时输出 d1。逻辑表达式:Y = (~sel & d0) | (sel & d1)
| sel | d0 | d1 | Y |
| 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 1 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 0 |
| 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 0 |
| 1 | 1 | 1 | 1 |
2.2 4选1 MUX
2位选择信号从4个输入中选1个输出。
2.3 8选1 MUX
3位选择信号从8个输入中选1个输出。
三、译码器(Decoder)
译码器将 n 位二进制输入转换为 2ⁿ 条输出线中的一条有效信号。
3.1 2-4 译码器
| A1 | A0 | Y3 | Y2 | Y1 | Y0 |
| 0 | 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 0 | 1 | 0 | 0 |
| 1 | 1 | 1 | 0 | 0 | 0 |
3.2 3-8 译码器
常用于内存地址译码和指令译码。
四、优先编码器(Priority Encoder)
当多个输入同时有效时,优先编码器输出优先级最高的输入编码。
五、Verilog 实现
module mux2to1 (
input d0, d1, sel,
output y
);
assign y = sel ? d1 : d0;
endmodule
module mux4to1 (
input [3:0] d,
input [1:0] sel,
output y
);
assign y = d[sel];
endmodule
module decoder2to4 (
input [1:0] a,
input en,
output [3:0] y
);
assign y = en ? (4'b0001 << a) : 4'b0000;
endmodule
module priority_encoder4 (
input [3:0] din,
output [1:0] dout,
output valid
);
assign valid = |din;
assign dout = din[3] ? 2'b11 :
din[2] ? 2'b10 :
din[1] ? 2'b01 :
2'b00;
endmodule
5.1 测试台
module tb_combo_logic;
reg d0, d1, sel1;
wire y_mux2;
reg [3:0] d4;
reg [1:0] sel4;
wire y_mux4;
reg [1:0] dec_a;
reg dec_en;
wire [3:0] dec_y;
reg [3:0] pe_in;
wire [1:0] pe_out;
wire pe_valid;
mux2to1 u_mux2 (.d0(d0), .d1(d1), .sel(sel1), .y(y_mux2));
mux4to1 u_mux4 (.d(d4), .sel(sel4), .y(y_mux4));
decoder2to4 u_dec (.a(dec_a), .en(dec_en), .y(dec_y));
priority_encoder4 u_pe (.din(pe_in), .dout(pe_out), .valid(pe_valid));
integer pass = 0, fail = 0;
initial begin
$display("--- 2选1 MUX 测试 ---");
for (integer i = 0; i < 8; i = i + 1) begin
{d0, d1, sel1} = i[2:0]; #1;
if (y_mux2 !== (sel1 ? d1 : d0)) begin
$display("FAIL MUX2: d0=%b d1=%b sel=%b y=%b", d0, d1, sel1, y_mux2);
fail = fail + 1;
end else pass = pass + 1;
end
$display("--- 4选1 MUX 测试 ---");
d4 = 4'b1010;
for (integer i = 0; i < 4; i = i + 1) begin
sel4 = i[1:0]; #1;
if (y_mux4 !== d4[sel4]) begin
$display("FAIL MUX4: sel=%b y=%b exp=%b", sel4, y_mux4, d4[sel4]);
fail = fail + 1;
end else pass = pass + 1;
end
$display("--- 2-4 译码器 测试 ---");
dec_en = 1;
for (integer i = 0; i < 4; i = i + 1) begin
dec_a = i[1:0]; #1;
if (dec_y !== (4'b0001 << dec_a)) begin
$display("FAIL DEC: a=%b y=%b", dec_a, dec_y);
fail = fail + 1;
end else pass = pass + 1;
end
dec_en = 0; dec_a = 2'b00; #1;
if (dec_y !== 4'b0000) fail = fail + 1;
else pass = pass + 1;
$display("--- 优先编码器 测试 ---");
pe_in = 4'b1000; #1;
if (pe_out !== 2'b11 || pe_valid !== 1) fail = fail+1; else pass = pass+1;
pe_in = 4'b0110; #1;
if (pe_out !== 2'b10 || pe_valid !== 1) fail = fail+1; else pass = pass+1;
pe_in = 4'b0000; #1;
if (pe_valid !== 0) fail = fail+1; else pass = pass+1;
$display("========================================");
$display("组合逻辑测试: PASS=%0d FAIL=%0d", pass, fail);
if (fail == 0) $display("✅ MUX+译码器+编码器全部验证通过!");
else $display("❌ 存在失败!");
$display("========================================");
$finish;
end
endmodule
六、Verilator 编译命令
verilator --cc combo_logic.v --exe tb_combo_logic.v \
--build --top-module tb_combo_logic
./obj_dir/Vtb_combo_logic
📊 预期输出:
--- 2选1 MUX 测试 ---
--- 4选1 MUX 测试 ---
--- 2-4 译码器 测试 ---
--- 优先编码器 测试 ---
========================================
组合逻辑测试: PASS=16 FAIL=0
✅ MUX+译码器+编码器全部验证通过!
========================================
七、组合逻辑在 CPU 中的应用
- MUX:寄存器文件读端口选择、ALU 操作选择、下一条 PC 选择
- 译码器:指令译码、地址译码、控制信号生成
- 编码器:中断优先级编码、键扫描
- 比较器:分支条件判断(BEQ/BNE)
🤔 思考题:如何用多个 2选1 MUX 级联构成 8选1 MUX?需要几级?
💡 提示:3级树形结构,第一级4个2选1→第二级2个2选1→第三级1个2选1
🏆 成就解锁:组合逻辑设计师
✅ Verilator 仿真验证通过
✅ 多路选择器 MUX 验证正确
✅ 译码器 Decoder 验证正确
✅ 优先编码器验证正确
🎯 下一目标:算术运算电路 → 第04课:加法器