本文介绍了一个32位RISC-V CPU的Verilog实现,支持RV32I指令集。
该设计采用五级流水线结构(IF、ID、EX、MEM、WB),包含寄存器堆、ALU、控制单元等核心模块。
关键特性包括:
1) 支持R/I/S/B/U/J六种指令格式;
2) 实现加法、移位、比较等基本运算;
3) 包含数据内存读写功能;
4) 采用流水线寄存器实现阶段间数据传递。
测试模块验证了ADDI、ADD、SW、LW等指令的执行流程。
该设计可作为RISC-V处理器的教学参考实现,展示了从指令解码到执行完成的完整数据通路。
RISCV_CPU.v
// 32位RISCV CPU设计 - 支持RV32I指令集
// 顶层模块
module riscv_cpu (
input wire clk, // 时钟信号
input wire reset, // 复位信号
input wire [31:0] inst, // 从指令内存读取的指令
input wire [31:0] data_in, // 从数据内存读取的数据
output wire [31:0] pc, // 程序计数器
output wire [31:0] addr, // 数据内存地址
output wire [31:0] data_out, // 写入数据内存的数据
output wire mem_write // 数据内存写使能
);
// 流水线寄存器
reg [31:0] IF_ID_pc, IF_ID_inst;
reg [31:0] ID_EX_pc, ID_EX_rs1_data, ID_EX_rs2_data;
reg [4:0] ID_EX_rd, ID_EX_rs1, ID_EX_rs2;
reg [31:0] ID_EX_imm;
reg [3:0] ID_EX_alu_ctrl;
reg ID_EX_reg_write, ID_EX_mem_write, ID_EX_mem_read;
reg ID_EX_alu_src, ID_EX_mem_to_reg;
reg [31:0] EX_MEM_pc, EX_MEM_alu_result, EX_MEM_rs2_data;
reg [4:0] EX_MEM_rd;
reg EX_MEM_reg_write, EX_MEM_mem_write, EX_MEM_mem_read, EX_MEM_mem_to_reg;
reg [31:0] MEM_WB_alu_result, MEM_WB_data_in;
reg [4:0] MEM_WB_rd;
reg MEM_WB_reg_write, MEM_WB_mem_to_reg;
// 程序计数器
reg [31:0] pc_reg;
assign pc = pc_reg;
// 指令取指阶段 (IF)
always @(posedge clk or posedge reset) begin
if (reset) begin
pc_reg <= 32'h00000000;
IF_ID_pc <= 32'h00000000;
IF_ID_inst <= 32'h00000000;
end else begin
pc_reg <= pc_reg + 4;
IF_ID_pc <= pc_reg;
IF_ID_inst <= inst;
end
end
// 寄存器堆
reg [31:0] reg_file [31:0];
wire [31:0] rs1_data, rs2_data;
wire [4:0] rs1, rs2, rd;
wire reg_write;
assign rs1 = IF_ID_inst[19:15];
assign rs2 = IF_ID_inst[24:20];
assign rd = IF_ID_inst[11:7];
// 读取寄存器
assign rs1_data = (rs1 == 5'b00000) ? 32'h00000000 : reg_file[rs1];
assign rs2_data = (rs2 == 5'b00000) ? 32'h00000000 : reg_file[rs2];
// 写入寄存器
assign reg_write = MEM_WB_reg_write;
always @(posedge clk) begin
if (reg_write && (MEM_WB_rd != 5'b00000)) begin
reg_file[MEM_WB_rd] <= MEM_WB_mem_to_reg ? MEM_WB_data_in : MEM_WB_alu_result;
end
end
// 立即数生成
wire [31:0] imm;
imm_gen imm_gen_unit (
.inst(IF_ID_inst),
.imm(imm)
);
// 控制单元
wire alu_src, mem_to_reg, mem_read, mem_write_internal, branch;
wire [1:0] alu_op;
control_unit control_unit (
.opcode(IF_ID_inst[6:0]),
.alu_src(alu_src),
.mem_to_reg(mem_to_reg),
.reg_write_internal(reg_write_internal),
.mem_read(mem_read),
.mem_write(mem_write_internal),
.branch(branch),
.alu_op(alu_op)
);
// ALU控制
wire [3:0] alu_ctrl;
alu_control alu_control_unit (
.alu_op(alu_op),
.funct3(IF_ID_inst[14:12]),
.funct7(IF_ID_inst[31:25]),
.alu_ctrl(alu_ctrl)
);
// 指令解码阶段 (ID)
always @(posedge clk or posedge reset) begin
if (reset) begin
ID_EX_pc <= 32'h00000000;
ID_EX_rs1_data <= 32'h00000000;
ID_EX_rs2_data <= 32'h00000000;
ID_EX_rd <= 5'b00000;
ID_EX_rs1 <= 5'b00000;
ID_EX_rs2 <= 5'b00000;
ID_EX_imm <= 32'h00000000;
ID_EX_alu_ctrl <= 4'b0000;
ID_EX_reg_write <= 1'b0;
ID_EX_mem_write <= 1'b0;
ID_EX_mem_read <= 1'b0;
ID_EX_alu_src <= 1'b0;
ID_EX_mem_to_reg <= 1'b0;
end else begin
ID_EX_pc <= IF_ID_pc;
ID_EX_rs1_data <= rs1_data;
ID_EX_rs2_data <= rs2_data;
ID_EX_rd <= rd;
ID_EX_rs1 <= rs1;
ID_EX_rs2 <= rs2;
ID_EX_imm <= imm;
ID_EX_alu_ctrl <= alu_ctrl;
ID_EX_reg_write <= reg_write_internal;
ID_EX_mem_write <= mem_write_internal;
ID_EX_mem_read <= mem_read;
ID_EX_alu_src <= alu_src;
ID_EX_mem_to_reg <= mem_to_reg;
end
end
// ALU操作数选择
wire [31:0] alu_op2 = ID_EX_alu_src ? ID_EX_imm : ID_EX_rs2_data;
// ALU单元
wire [31:0] alu_result;
wire alu_zero;
alu alu_unit (
.a(ID_EX_rs1_data),
.b(alu_op2),
.alu_ctrl(ID_EX_alu_ctrl),
.result(alu_result),
.zero(alu_zero)
);
// 执行阶段 (EX)
always @(posedge clk or posedge reset) begin
if (reset) begin
EX_MEM_pc <= 32'h00000000;
EX_MEM_alu_result <= 32'h00000000;
EX_MEM_rs2_data <= 32'h00000000;
EX_MEM_rd <= 5'b00000;
EX_MEM_reg_write <= 1'b0;
EX_MEM_mem_write <= 1'b0;
EX_MEM_mem_read <= 1'b0;
EX_MEM_mem_to_reg <= 1'b0;
end else begin
EX_MEM_pc <= ID_EX_pc;
EX_MEM_alu_result <= alu_result;
EX_MEM_rs2_data <= ID_EX_rs2_data;
EX_MEM_rd <= ID_EX_rd;
EX_MEM_reg_write <= ID_EX_reg_write;
EX_MEM_mem_write <= ID_EX_mem_write;
EX_MEM_mem_read <= ID_EX_mem_read;
EX_MEM_mem_to_reg <= ID_EX_mem_to_reg;
end
end
// 内存访问阶段 (MEM)
assign addr = EX_MEM_alu_result;
assign data_out = EX_MEM_rs2_data;
assign mem_write = EX_MEM_mem_write;
always @(posedge clk or posedge reset) begin
if (reset) begin
MEM_WB_alu_result <= 32'h00000000;
MEM_WB_data_in <= 32'h00000000;
MEM_WB_rd <= 5'b00000;
MEM_WB_reg_write <= 1'b0;
MEM_WB_mem_to_reg <= 1'b0;
end else begin
MEM_WB_alu_result <= EX_MEM_alu_result;
MEM_WB_data_in <= data_in;
MEM_WB_rd <= EX_MEM_rd;
MEM_WB_reg_write <= EX_MEM_reg_write;
MEM_WB_mem_to_reg <= EX_MEM_mem_to_reg;
end
end
// 写回阶段 (WB) - 已在寄存器堆中实现
endmodule
// 立即数生成模块
module imm_gen (
input wire [31:0] inst,
output wire [31:0] imm
);
reg [31:0] imm_reg;
assign imm = imm_reg;
always @(*) begin
case (inst[6:0])
// I-type
7'b0010011, 7'b0000011, 7'b1100111: begin
imm_reg = {{20{inst[31]}}, inst[31:20]};
end
// S-type
7'b0100011: begin
imm_reg = {{20{inst[31]}}, inst[31:25], inst[11:7]};
end
// B-type
7'b1100011: begin
imm_reg = {{19{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0};
end
// U-type
7'b0110111, 7'b0010111: begin
imm_reg = {inst[31:12], 12'b0};
end
// J-type
7'b1101111: begin
imm_reg = {{11{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0};
end
default: begin
imm_reg = 32'h00000000;
end
endcase
end
endmodule
// 控制单元
module control_unit (
input wire [6:0] opcode,
output wire alu_src,
output wire mem_to_reg,
output wire reg_write_internal,
output wire mem_read,
output wire mem_write,
output wire branch,
output wire [1:0] alu_op
);
reg alu_src_reg, mem_to_reg_reg, reg_write_reg, mem_read_reg, mem_write_reg, branch_reg;
reg [1:0] alu_op_reg;
assign alu_src = alu_src_reg;
assign mem_to_reg = mem_to_reg_reg;
assign reg_write_internal = reg_write_reg;
assign mem_read = mem_read_reg;
assign mem_write = mem_write_reg;
assign branch = branch_reg;
assign alu_op = alu_op_reg;
always @(*) begin
case (opcode)
// R-type
7'b0110011: begin
alu_src_reg = 1'b0;
mem_to_reg_reg = 1'b0;
reg_write_reg = 1'b1;
mem_read_reg = 1'b0;
mem_write_reg = 1'b0;
branch_reg = 1'b0;
alu_op_reg = 2'b10;
end
// I-type - ALU
7'b0010011: begin
alu_src_reg = 1'b1;
mem_to_reg_reg = 1'b0;
reg_write_reg = 1'b1;
mem_read_reg = 1'b0;
mem_write_reg = 1'b0;
branch_reg = 1'b0;
alu_op_reg = 2'b11;
end
// I-type - Load
7'b0000011: begin
alu_src_reg = 1'b1;
mem_to_reg_reg = 1'b1;
reg_write_reg = 1'b1;
mem_read_reg = 1'b1;
mem_write_reg = 1'b0;
branch_reg = 1'b0;
alu_op_reg = 2'b00;
end
// S-type - Store
7'b0100011: begin
alu_src_reg = 1'b1;
mem_to_reg_reg = 1'b0;
reg_write_reg = 1'b0;
mem_read_reg = 1'b0;
mem_write_reg = 1'b1;
branch_reg = 1'b0;
alu_op_reg = 2'b00;
end
// B-type - Branch
7'b1100011: begin
alu_src_reg = 1'b0;
mem_to_reg_reg = 1'b0;
reg_write_reg = 1'b0;
mem_read_reg = 1'b0;
mem_write_reg = 1'b0;
branch_reg = 1'b1;
alu_op_reg = 2'b01;
end
default: begin
alu_src_reg = 1'b0;
mem_to_reg_reg = 1'b0;
reg_write_reg = 1'b0;
mem_read_reg = 1'b0;
mem_write_reg = 1'b0;
branch_reg = 1'b0;
alu_op_reg = 2'b00;
end
endcase
end
endmodule
// ALU控制单元
module alu_control (
input wire [1:0] alu_op,
input wire [2:0] funct3,
input wire [6:0] funct7,
output wire [3:0] alu_ctrl
);
reg [3:0] alu_ctrl_reg;
assign alu_ctrl = alu_ctrl_reg;
always @(*) begin
case (alu_op)
2'b00: begin // Load/Store
alu_ctrl_reg = 4'b0010; // ADD
end
2'b01: begin // Branch
alu_ctrl_reg = 4'b0110; // SUB
end
2'b10: begin // R-type
case (funct3)
3'b000: begin
if (funct7 == 7'b0000000) begin
alu_ctrl_reg = 4'b0010; // ADD
end else begin
alu_ctrl_reg = 4'b0110; // SUB
end
end
3'b001: alu_ctrl_reg = 4'b0011; // SLL
3'b010: alu_ctrl_reg = 4'b0111; // SLT
3'b011: alu_ctrl_reg = 4'b1000; // SLTU
3'b100: alu_ctrl_reg = 4'b0000; // XOR
3'b101: begin
if (funct7 == 7'b0000000) begin
alu_ctrl_reg = 4'b0101; // SRL
end else begin
alu_ctrl_reg = 4'b1001; // SRA
end
end
3'b110: alu_ctrl_reg = 4'b0001; // OR
3'b111: alu_ctrl_reg = 4'b1010; // AND
default: alu_ctrl_reg = 4'b0000;
endcase
end
2'b11: begin // I-type ALU
case (funct3)
3'b000: alu_ctrl_reg = 4'b0010; // ADDI
3'b001: alu_ctrl_reg = 4'b0011; // SLLI
3'b010: alu_ctrl_reg = 4'b0111; // SLTI
3'b011: alu_ctrl_reg = 4'b1000; // SLTIU
3'b100: alu_ctrl_reg = 4'b0000; // XORI
3'b101: begin
if (funct7[5] == 1'b0) begin
alu_ctrl_reg = 4'b0101; // SRLI
end else begin
alu_ctrl_reg = 4'b1001; // SRAI
end
end
3'b110: alu_ctrl_reg = 4'b0001; // ORI
3'b111: alu_ctrl_reg = 4'b1010; // ANDI
default: alu_ctrl_reg = 4'b0000;
endcase
end
default: alu_ctrl_reg = 4'b0000;
endcase
end
endmodule
// ALU模块
module alu (
input wire [31:0] a,
input wire [31:0] b,
input wire [3:0] alu_ctrl,
output wire [31:0] result,
output wire zero
);
reg [31:0] result_reg;
assign result = result_reg;
assign zero = (result_reg == 32'h00000000);
always @(*) begin
case (alu_ctrl)
4'b0000: result_reg = a ^ b; // XOR
4'b0001: result_reg = a | b; // OR
4'b0010: result_reg = a + b; // ADD
4'b0011: result_reg = a << b[4:0]; // SLL
4'b0100: result_reg = a >> b[4:0]; // SRL
4'b0101: result_reg = a >> b[4:0]; // SRL (逻辑右移)
4'b0110: result_reg = a - b; // SUB
4'b0111: result_reg = (a < b) ? 32'h00000001 : 32'h00000000; // SLT
4'b1000: result_reg = ({1'b0, a} < {1'b0, b}) ? 32'h00000001 : 32'h00000000; // SLTU
4'b1001: result_reg = $signed(a) >>> b[4:0]; // SRA (算术右移)
4'b1010: result_reg = a & b; // AND
default: result_reg = 32'h00000000;
endcase
end
endmodule
// 测试模块
module riscv_cpu_test;
reg clk, reset;
reg [31:0] inst, data_in;
wire [31:0] pc, addr, data_out;
wire mem_write;
// 实例化CPU
riscv_cpu cpu (
.clk(clk),
.reset(reset),
.inst(inst),
.data_in(data_in),
.pc(pc),
.addr(addr),
.data_out(data_out),
.mem_write(mem_write)
);
// 时钟生成
always begin
clk = 0;
#5;
clk = 1;
#5;
end
// 生成VCD文件
initial begin
$dumpfile("riscv_cpu_sim.vcd");
$dumpvars(0, riscv_cpu_test);
end
// 测试程序
initial begin
// 初始化
reset = 1;
inst = 32'h00000000;
data_in = 32'h00000000;
#10;
// 复位释放
reset = 0;
// 测试指令 - ADDI x1, x0, 5
inst = 32'h00500093;
#10;
// 测试指令 - ADDI x2, x0, 10
inst = 32'h00a00113;
#10;
// 测试指令 - ADD x3, x1, x2
inst = 32'h002081b3;
#10;
// 测试指令 - SW x3, 0(x1)
inst = 32'h0030a023;
#10;
// 测试指令 - LW x4, 0(x1)
inst = 32'h0000a283;
data_in = 32'h0000000f;
#10;
// 结束测试
#10;
$finish;
end
// 监控输出
initial begin
$monitor("Time: %0t, PC: %h, Inst: %h, RegWrite: %b, MemWrite: %b, Addr: %h, DataOut: %h",
$time, pc, inst, cpu.MEM_WB_reg_write, mem_write, addr, data_out);
end
endmodule
7156

被折叠的 条评论
为什么被折叠?



