第13课 · 控制单元
控制信号指令译码Main Decoder
📌 学习目标:实现 RISC-V 主译码器,根据指令 opcode 和 funct3 生成所有控制信号,通过 Verilator 验证指令到控制信号的映射。
一、控制单元的作用
控制单元是 CPU 的"大脑",它根据当前指令生成所有控制信号,指挥数据通路中的各个组件协同工作。
指令 ──→ 控制单元 ──→ 控制信号
├── PCSrc (PC选择: +4 / 跳转)
├── ALUSrc (ALU B端: rs2 / imm)
├── MemRead (数据存储器读)
├── MemWrite(数据存储器写)
├── MemToReg(写回选择: ALU / Mem)
├── RegWrite(寄存器写使能)
├── ALUOp (ALU操作类型)
└── Branch (分支使能)
二、控制信号定义
| 信号 | 0 | 1 | 说明 |
| RegWrite | 不写 | 写 | 寄存器文件写使能 |
| MemRead | 不读 | 读 | 数据存储器读使能 |
| MemWrite | 不写 | 写 | 数据存储器写使能 |
| ALUSrc | rs2 | imm | ALU 第二操作数来源 |
| MemToReg | ALU | Mem | 写回数据来源 |
| PCSrc | PC+4 | 跳转 | PC 下一值选择 |
| Branch | 不分支 | 可能分支 | 分支指令标志 |
三、各指令的控制信号
| 指令 | RegW | MemR | MemW | ALUSrc | MemToReg | Branch | PCSrc | ALUOp |
| ADD | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 00 |
| SUB | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 00 |
| AND/OR/XOR | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 00 |
| ADDI | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 01 |
| LW | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 01 |
| SW | 0 | 0 | 1 | 1 | X | 0 | 0 | 01 |
| BEQ | 0 | 0 | 0 | 0 | X | 1 | 0 | 10 |
| JAL | 1 | 0 | 0 | X | 0 | 0 | 1 | XX |
四、Verilog 实现
module control (
input [6:0] opcode,
input [2:0] funct3,
input [6:0] funct7,
output reg reg_write,
output reg mem_read,
output reg mem_write,
output reg alu_src,
output reg mem_to_reg,
output reg branch,
output reg pc_src,
output reg [1:0] alu_op
);
always @(*) begin
reg_write = 0; mem_read = 0; mem_write = 0;
alu_src = 0; mem_to_reg = 0; branch = 0;
pc_src = 0; alu_op = 2'b00;
case (opcode)
7'b0110011: begin
reg_write = 1;
alu_src = 0;
alu_op = 2'b00;
end
7'b0010011: begin
reg_write = 1;
alu_src = 1;
alu_op = 2'b01;
end
7'b0000011: begin
reg_write = 1;
mem_read = 1;
alu_src = 1;
mem_to_reg = 1;
alu_op = 2'b01;
end
7'b0100011: begin
mem_write = 1;
alu_src = 1;
alu_op = 2'b01;
end
7'b1100011: begin
branch = 1;
alu_op = 2'b10;
end
7'b1101111: begin
reg_write = 1;
pc_src = 1;
end
7'b1100111: begin
reg_write = 1;
pc_src = 1;
alu_src = 1;
end
7'b0110111, 7'b0010111: begin
reg_write = 1;
alu_src = 1;
end
endcase
end
endmodule
4.1 测试台
module tb_control;
reg [6:0] opcode;
reg [2:0] funct3;
reg [6:0] funct7;
wire reg_write, mem_read, mem_write, alu_src;
wire mem_to_reg, branch, pc_src;
wire [1:0] alu_op;
control uut (.*);
integer pass=0, fail=0;
task check; input rw,mr,mw,as,m2r,br,ps; input [1:0] ao; begin
if (reg_write!==rw||mem_read!==mr||mem_write!==mw||alu_src!==as||
mem_to_reg!==m2r||branch!==br||pc_src!==ps||alu_op!==ao) begin
$display("FAIL opcode=%b: rw=%b mr=%b mw=%b as=%b m2r=%b br=%b ps=%b ao=%b",
opcode, reg_write, mem_read, mem_write, alu_src,
mem_to_reg, branch, pc_src, alu_op);
fail=fail+1;
end else pass=pass+1;
end endtask
initial begin
opcode=7'b0110011; funct3=3'b000; funct7=7'b0; #1;
check(1,0,0,0,0,0,0,2'b00);
opcode=7'b0010011; #1;
check(1,0,0,1,0,0,0,2'b01);
opcode=7'b0000011; #1;
check(1,1,0,1,1,0,0,2'b01);
opcode=7'b0100011; #1;
check(0,0,1,1,0,0,0,2'b01);
opcode=7'b1100011; #1;
check(0,0,0,0,0,1,0,2'b10);
opcode=7'b1101111; #1;
check(1,0,0,0,0,0,1,2'b00);
opcode=7'b0110111; #1;
check(1,0,0,1,0,0,0,2'b00);
$display("========================================");
$display("控制单元测试: PASS=%0d FAIL=%0d", pass, fail);
if (fail == 0) $display("✅ 指令→控制信号映射全部正确!");
else $display("❌ 存在失败!");
$display("========================================");
$finish;
end
endmodule
五、Verilator 编译命令
verilator --cc control.v --exe tb_control.v \
--build --top-module tb_control
./obj_dir/Vtb_control
🤔 思考题:如果设计一个新的自定义指令,需要修改哪些控制信号?如何保证不影响已有指令?
💡 提示:在 case 中增加新分支,确保 default 安全;测试回归
🏆 成就解锁:控制单元设计师
✅ Verilator 仿真验证通过
✅ 8 类指令的控制信号映射正确
✅ R/I/S/B/J/U 各类型译码正确
✅ 理解控制信号与数据通路的协作关系
🎯 下一目标:完整单周期 CPU → 第14课:单周期CPU