RISCV CPU 设计

本文介绍了一个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TaoSense

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值