用FPGA设计CPU
介绍:中央处理器(Central Processing Unit,简称CPU)作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。本文使用RISC-V架构进行设计cpu
原理:
- 将程序和要进行处理的数据,放到计算机的存储系统中。
- 从存储系统中,拿数据,运行相应的程序,得到结果。
运行流程:
- 取指令:程序存储器中的指令首先根据程序入口地址取出,需要发出指令地址和控制信号来执行这一步骤。
- 指令译码:对当前取得的指令进行分析,生成相应的控制命令,以便进行下一步操作。
- 执行指令:根据指令译码生成的操作命令,产生操作控制信号序列,通过运算单元、存储器系统以及输入/输出接口设备执行每条指令的功能。
组成部分:
- 时钟发生器:用于产生CPU各个部件的时钟信号,控制各个部件的运行和同步。
- 指令寄存器:用于存放当前正在执行的指令,从数据总线中获取指令并存储。
- 累加器:用于存放运算结果或中间结果。
- 算术逻辑运算单元(ALU):用于执行各种算术和逻辑运算,根据指令中的操作码执行加法、逻辑与或者异或等操作。
- 数据控制器:用于控制数据在CPU内部各个部件之间的传输和存储。
- 状态控制器:产生各种控制信号,根据CPU的状态来控制整个处理器的运行。
- 程序计数器:用于存储当前正在执行的指令的地址,指示下一条要执行的指令的位置。
- 地址多路器:用于选择输出的地址是程序计数器的地址还是数据/端口的地址,实现对内存、I/O设备的地址选择。
运用:
结构框图:
时序图:(流水线指令)
实验目的:{实现32位的cpu,三级流水,可以运行C语言程序,支持中断,支持JTAG等}
(本实验参考了liangkangnan的RISC-V的设计)
链接:tinyriscv: 一个从零开始写的极简、非常易懂的RISC-V处理器核。
模块框图:
指令运行示意框图:
模块代码
pc_reg模块
`include "defines.v"// PC寄存器模块
module pc_reg(input wire clk,input wire rst,input wire jump_flag_i, // 跳转标志input wire[`InstAddrBus] jump_addr_i, // 跳转地址input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志input wire jtag_reset_flag_i, // 复位标志output reg[`InstAddrBus] pc_o // PC指针);always @ (posedge clk) beginif (rst == `RstEnable || jtag_reset_flag_i) begin// 复位pc_o <= `CpuResetAddr;endelse if (jump_flag_i) begin// 跳转pc_o <= jump_addr_i;endelse if (hold_flag_i >= `Hold_Pc) begin// 暂停pc_o <= pc_o;endelse begin// 地址加4pc_o <= pc_o + 3'd4;endendendmodule
if_id模块
`include "defines.v"// 将指令向译码模块传递
module if_id(input wire clk,input wire rst,input wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志input wire[`INT_BUS] int_flag_i, // 外设中断输入信号output wire[`INT_BUS] int_flag_o, // 外设中断输出信号output wire[`InstBus] inst_o, // 指令内容output wire[`InstAddrBus] inst_addr_o // 指令地址);wire hold_en = (hold_flag_i >= `Hold_If);dff_set #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst_o);dff_set #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr_o);dff_set #(8) int_ff(clk, rst, hold_en, `INT_NONE, int_flag_i, int_flag_o);endmodule
id模块
`include "defines.v"// 译码模块
// 纯组合逻辑电路
module id(input wire rst,// from if_idinput wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址// from regsinput wire[`RegBus] reg1_rdata_i, // 通用寄存器1输入数据input wire[`RegBus] reg2_rdata_i, // 通用寄存器2输入数据// from csr reginput wire[`RegBus] csr_rdata_i, // CSR寄存器输入数据// from exinput wire ex_jump_flag_i, // 跳转标志// to regsoutput reg[`RegAddrBus] reg1_raddr_o, // 读通用寄存器1地址output reg[`RegAddrBus] reg2_raddr_o, // 读通用寄存器2地址// to csr regoutput reg[`MemAddrBus] csr_raddr_o, // 读CSR寄存器地址// to exoutput reg[`MemAddrBus] op1_o,output reg[`MemAddrBus] op2_o,output reg[`MemAddrBus] op1_jump_o,output reg[`MemAddrBus] op2_jump_o,output reg[`InstBus] inst_o, // 指令内容output reg[`InstAddrBus] inst_addr_o, // 指令地址output reg[`RegBus] reg1_rdata_o, // 通用寄存器1数据output reg[`RegBus] reg2_rdata_o, // 通用寄存器2数据output reg reg_we_o, // 写通用寄存器标志output reg[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址output reg csr_we_o, // 写CSR寄存器标志output reg[`RegBus] csr_rdata_o, // CSR寄存器数据output reg[`MemAddrBus] csr_waddr_o // 写CSR寄存器地址);wire[6:0] opcode = inst_i[6:0];wire[2:0] funct3 = inst_i[14:12];wire[6:0] funct7 = inst_i[31:25];wire[4:0] rd = inst_i[11:7];wire[4:0] rs1 = inst_i[19:15];wire[4:0] rs2 = inst_i[24:20];always @ (*) begininst_o = inst_i;inst_addr_o = inst_addr_i;reg1_rdata_o = reg1_rdata_i;reg2_rdata_o = reg2_rdata_i;csr_rdata_o = csr_rdata_i;csr_raddr_o = `ZeroWord;csr_waddr_o = `ZeroWord;csr_we_o = `WriteDisable;op1_o = `ZeroWord;op2_o = `ZeroWord;op1_jump_o = `ZeroWord;op2_jump_o = `ZeroWord;case (opcode)`INST_TYPE_I: begincase (funct3)`INST_ADDI, `INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI, `INST_SLLI, `INST_SRI: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = rs1;reg2_raddr_o = `ZeroReg;op1_o = reg1_rdata_i;op2_o = {{20{inst_i[31]}}, inst_i[31:20]};enddefault: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;endendcaseend`INST_TYPE_R_M: beginif ((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begincase (funct3)`INST_ADD_SUB, `INST_SLL, `INST_SLT, `INST_SLTU, `INST_XOR, `INST_SR, `INST_OR, `INST_AND: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = rs1;reg2_raddr_o = rs2;op1_o = reg1_rdata_i;op2_o = reg2_rdata_i;enddefault: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;endendcaseend else if (funct7 == 7'b0000001) begincase (funct3)`INST_MUL, `INST_MULHU, `INST_MULH, `INST_MULHSU: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = rs1;reg2_raddr_o = rs2;op1_o = reg1_rdata_i;op2_o = reg2_rdata_i;end`INST_DIV, `INST_DIVU, `INST_REM, `INST_REMU: beginreg_we_o = `WriteDisable;reg_waddr_o = rd;reg1_raddr_o = rs1;reg2_raddr_o = rs2;op1_o = reg1_rdata_i;op2_o = reg2_rdata_i;op1_jump_o = inst_addr_i;op2_jump_o = 32'h4;enddefault: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;endendcaseend else beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;endend`INST_TYPE_L: begincase (funct3)`INST_LB, `INST_LH, `INST_LW, `INST_LBU, `INST_LHU: beginreg1_raddr_o = rs1;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteEnable;reg_waddr_o = rd;op1_o = reg1_rdata_i;op2_o = {{20{inst_i[31]}}, inst_i[31:20]};enddefault: beginreg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;endendcaseend`INST_TYPE_S: begincase (funct3)`INST_SB, `INST_SW, `INST_SH: beginreg1_raddr_o = rs1;reg2_raddr_o = rs2;reg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;op1_o = reg1_rdata_i;op2_o = {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]};enddefault: beginreg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;endendcaseend`INST_TYPE_B: begincase (funct3)`INST_BEQ, `INST_BNE, `INST_BLT, `INST_BGE, `INST_BLTU, `INST_BGEU: beginreg1_raddr_o = rs1;reg2_raddr_o = rs2;reg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;op1_o = reg1_rdata_i;op2_o = reg2_rdata_i;op1_jump_o = inst_addr_i;op2_jump_o = {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};enddefault: beginreg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;endendcaseend`INST_JAL: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;op1_o = inst_addr_i;op2_o = 32'h4;op1_jump_o = inst_addr_i;op2_jump_o = {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};end`INST_JALR: beginreg_we_o = `WriteEnable;reg1_raddr_o = rs1;reg2_raddr_o = `ZeroReg;reg_waddr_o = rd;op1_o = inst_addr_i;op2_o = 32'h4;op1_jump_o = reg1_rdata_i;op2_jump_o = {{20{inst_i[31]}}, inst_i[31:20]};end`INST_LUI: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;op1_o = {inst_i[31:12], 12'b0};op2_o = `ZeroWord;end`INST_AUIPC: beginreg_we_o = `WriteEnable;reg_waddr_o = rd;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;op1_o = inst_addr_i;op2_o = {inst_i[31:12], 12'b0};end`INST_NOP_OP: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;end`INST_FENCE: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;op1_jump_o = inst_addr_i;op2_jump_o = 32'h4;end`INST_CSR: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;csr_raddr_o = {20'h0, inst_i[31:20]};csr_waddr_o = {20'h0, inst_i[31:20]};case (funct3)`INST_CSRRW, `INST_CSRRS, `INST_CSRRC: beginreg1_raddr_o = rs1;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteEnable;reg_waddr_o = rd;csr_we_o = `WriteEnable;end`INST_CSRRWI, `INST_CSRRSI, `INST_CSRRCI: beginreg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;reg_we_o = `WriteEnable;reg_waddr_o = rd;csr_we_o = `WriteEnable;enddefault: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;csr_we_o = `WriteDisable;endendcaseenddefault: beginreg_we_o = `WriteDisable;reg_waddr_o = `ZeroReg;reg1_raddr_o = `ZeroReg;reg2_raddr_o = `ZeroReg;endendcaseendendmodule
id_ex 模块
`include "defines.v"// 将译码结果向执行模块传递
module id_ex(input wire clk,input wire rst,input wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址input wire reg_we_i, // 写通用寄存器标志input wire[`RegAddrBus] reg_waddr_i, // 写通用寄存器地址input wire[`RegBus] reg1_rdata_i, // 通用寄存器1读数据input wire[`RegBus] reg2_rdata_i, // 通用寄存器2读数据input wire csr_we_i, // 写CSR寄存器标志input wire[`MemAddrBus] csr_waddr_i, // 写CSR寄存器地址input wire[`RegBus] csr_rdata_i, // CSR寄存器读数据input wire[`MemAddrBus] op1_i,input wire[`MemAddrBus] op2_i,input wire[`MemAddrBus] op1_jump_i,input wire[`MemAddrBus] op2_jump_i,input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志output wire[`MemAddrBus] op1_o,output wire[`MemAddrBus] op2_o,output wire[`MemAddrBus] op1_jump_o,output wire[`MemAddrBus] op2_jump_o,output wire[`InstBus] inst_o, // 指令内容output wire[`InstAddrBus] inst_addr_o, // 指令地址output wire reg_we_o, // 写通用寄存器标志output wire[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址output wire[`RegBus] reg1_rdata_o, // 通用寄存器1读数据output wire[`RegBus] reg2_rdata_o, // 通用寄存器2读数据output wire csr_we_o, // 写CSR寄存器标志output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址output wire[`RegBus] csr_rdata_o // CSR寄存器读数据);wire hold_en = (hold_flag_i >= `Hold_Id);dff_set #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst_o);dff_set #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr_o);dff_set #(1) reg_we_ff(clk, rst, hold_en, `WriteDisable, reg_we_i, reg_we_o);dff_set #(5) reg_waddr_ff(clk, rst, hold_en, `ZeroReg, reg_waddr_i, reg_waddr_o);dff_set #(32) reg1_rdata_ff(clk, rst, hold_en, `ZeroWord, reg1_rdata_i, reg1_rdata_o);dff_set #(32) reg2_rdata_ff(clk, rst, hold_en, `ZeroWord, reg2_rdata_i, reg2_rdata_o);dff_set #(1) csr_we_ff(clk, rst, hold_en, `WriteDisable, csr_we_i, csr_we_o);dff_set #(32) csr_waddr_ff(clk, rst, hold_en, `ZeroWord, csr_waddr_i, csr_waddr_o);dff_set #(32) csr_rdata_ff(clk, rst, hold_en, `ZeroWord, csr_rdata_i, csr_rdata_o);dff_set #(32) op1_ff(clk, rst, hold_en, `ZeroWord, op1_i, op1_o);dff_set #(32) op2_ff(clk, rst, hold_en, `ZeroWord, op2_i, op2_o);dff_set #(32) op1_jump_ff(clk, rst, hold_en, `ZeroWord, op1_jump_i, op1_jump_o);dff_set #(32) op2_jump_ff(clk, rst, hold_en, `ZeroWord, op2_jump_i, op2_jump_o);endmodule
ex模块
`include "defines.v"// 执行模块
// 纯组合逻辑电路
module ex(input wire rst,// from idinput wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址input wire reg_we_i, // 是否写通用寄存器input wire[`RegAddrBus] reg_waddr_i, // 写通用寄存器地址input wire[`RegBus] reg1_rdata_i, // 通用寄存器1输入数据input wire[`RegBus] reg2_rdata_i, // 通用寄存器2输入数据input wire csr_we_i, // 是否写CSR寄存器input wire[`MemAddrBus] csr_waddr_i, // 写CSR寄存器地址input wire[`RegBus] csr_rdata_i, // CSR寄存器输入数据input wire int_assert_i, // 中断发生标志input wire[`InstAddrBus] int_addr_i, // 中断跳转地址input wire[`MemAddrBus] op1_i,input wire[`MemAddrBus] op2_i,input wire[`MemAddrBus] op1_jump_i,input wire[`MemAddrBus] op2_jump_i,// from meminput wire[`MemBus] mem_rdata_i, // 内存输入数据// from divinput wire div_ready_i, // 除法运算完成标志input wire[`RegBus] div_result_i, // 除法运算结果input wire div_busy_i, // 除法运算忙标志input wire[`RegAddrBus] div_reg_waddr_i,// 除法运算结束后要写的寄存器地址// to memoutput reg[`MemBus] mem_wdata_o, // 写内存数据output reg[`MemAddrBus] mem_raddr_o, // 读内存地址output reg[`MemAddrBus] mem_waddr_o, // 写内存地址output wire mem_we_o, // 是否要写内存output wire mem_req_o, // 请求访问内存标志// to regsoutput wire[`RegBus] reg_wdata_o, // 写寄存器数据output wire reg_we_o, // 是否要写通用寄存器output wire[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址// to csr regoutput reg[`RegBus] csr_wdata_o, // 写CSR寄存器数据output wire csr_we_o, // 是否要写CSR寄存器output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址// to divoutput wire div_start_o, // 开始除法运算标志output reg[`RegBus] div_dividend_o, // 被除数output reg[`RegBus] div_divisor_o, // 除数output reg[2:0] div_op_o, // 具体是哪一条除法指令output reg[`RegAddrBus] div_reg_waddr_o,// 除法运算结束后要写的寄存器地址// to ctrloutput wire hold_flag_o, // 是否暂停标志output wire jump_flag_o, // 是否跳转标志output wire[`InstAddrBus] jump_addr_o // 跳转目的地址);wire[1:0] mem_raddr_index;wire[1:0] mem_waddr_index;wire[`DoubleRegBus] mul_temp;wire[`DoubleRegBus] mul_temp_invert;wire[31:0] sr_shift;wire[31:0] sri_shift;wire[31:0] sr_shift_mask;wire[31:0] sri_shift_mask;wire[31:0] op1_add_op2_res;wire[31:0] op1_jump_add_op2_jump_res;wire[31:0] reg1_data_invert;wire[31:0] reg2_data_invert;wire op1_ge_op2_signed;wire op1_ge_op2_unsigned;wire op1_eq_op2;reg[`RegBus] mul_op1;reg[`RegBus] mul_op2;wire[6:0] opcode;wire[2:0] funct3;wire[6:0] funct7;wire[4:0] rd;wire[4:0] uimm;reg[`RegBus] reg_wdata;reg reg_we;reg[`RegAddrBus] reg_waddr;reg[`RegBus] div_wdata;reg div_we;reg[`RegAddrBus] div_waddr;reg div_hold_flag;reg div_jump_flag;reg[`InstAddrBus] div_jump_addr;reg hold_flag;reg jump_flag;reg[`InstAddrBus] jump_addr;reg mem_we;reg mem_req;reg div_start;assign opcode = inst_i[6:0];assign funct3 = inst_i[14:12];assign funct7 = inst_i[31:25];assign rd = inst_i[11:7];assign uimm = inst_i[19:15];assign sr_shift = reg1_rdata_i >> reg2_rdata_i[4:0];assign sri_shift = reg1_rdata_i >> inst_i[24:20];assign sr_shift_mask = 32'hffffffff >> reg2_rdata_i[4:0];assign sri_shift_mask = 32'hffffffff >> inst_i[24:20];assign op1_add_op2_res = op1_i + op2_i;assign op1_jump_add_op2_jump_res = op1_jump_i + op2_jump_i;assign reg1_data_invert = ~reg1_rdata_i + 1;assign reg2_data_invert = ~reg2_rdata_i + 1;// 有符号数比较assign op1_ge_op2_signed = $signed(op1_i) >= $signed(op2_i);// 无符号数比较assign op1_ge_op2_unsigned = op1_i >= op2_i;assign op1_eq_op2 = (op1_i == op2_i);assign mul_temp = mul_op1 * mul_op2;assign mul_temp_invert = ~mul_temp + 1;assign mem_raddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:20]}) & 2'b11;assign mem_waddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]}) & 2'b11;assign div_start_o = (int_assert_i == `INT_ASSERT)? `DivStop: div_start;assign reg_wdata_o = reg_wdata | div_wdata;// 响应中断时不写通用寄存器assign reg_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: (reg_we || div_we);assign reg_waddr_o = reg_waddr | div_waddr;// 响应中断时不写内存assign mem_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: mem_we;// 响应中断时不向总线请求访问内存assign mem_req_o = (int_assert_i == `INT_ASSERT)? `RIB_NREQ: mem_req;assign hold_flag_o = hold_flag || div_hold_flag;assign jump_flag_o = jump_flag || div_jump_flag || ((int_assert_i == `INT_ASSERT)? `JumpEnable: `JumpDisable);assign jump_addr_o = (int_assert_i == `INT_ASSERT)? int_addr_i: (jump_addr | div_jump_addr);// 响应中断时不写CSR寄存器assign csr_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: csr_we_i;assign csr_waddr_o = csr_waddr_i;// 处理乘法指令always @ (*) beginif ((opcode == `INST_TYPE_R_M) && (funct7 == 7'b0000001)) begincase (funct3)`INST_MUL, `INST_MULHU: beginmul_op1 = reg1_rdata_i;mul_op2 = reg2_rdata_i;end`INST_MULHSU: beginmul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;mul_op2 = reg2_rdata_i;end`INST_MULH: beginmul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;mul_op2 = (reg2_rdata_i[31] == 1'b1)? (reg2_data_invert): reg2_rdata_i;enddefault: beginmul_op1 = reg1_rdata_i;mul_op2 = reg2_rdata_i;endendcaseend else beginmul_op1 = reg1_rdata_i;mul_op2 = reg2_rdata_i;endend// 处理除法指令always @ (*) begindiv_dividend_o = reg1_rdata_i;div_divisor_o = reg2_rdata_i;div_op_o = funct3;div_reg_waddr_o = reg_waddr_i;if ((opcode == `INST_TYPE_R_M) && (funct7 == 7'b0000001)) begindiv_we = `WriteDisable;div_wdata = `ZeroWord;div_waddr = `ZeroWord;case (funct3)`INST_DIV, `INST_DIVU, `INST_REM, `INST_REMU: begindiv_start = `DivStart;div_jump_flag = `JumpEnable;div_hold_flag = `HoldEnable;div_jump_addr = op1_jump_add_op2_jump_res;enddefault: begindiv_start = `DivStop;div_jump_flag = `JumpDisable;div_hold_flag = `HoldDisable;div_jump_addr = `ZeroWord;endendcaseend else begindiv_jump_flag = `JumpDisable;div_jump_addr = `ZeroWord;if (div_busy_i == `True) begindiv_start = `DivStart;div_we = `WriteDisable;div_wdata = `ZeroWord;div_waddr = `ZeroWord;div_hold_flag = `HoldEnable;end else begindiv_start = `DivStop;div_hold_flag = `HoldDisable;if (div_ready_i == `DivResultReady) begindiv_wdata = div_result_i;div_waddr = div_reg_waddr_i;div_we = `WriteEnable;end else begindiv_we = `WriteDisable;div_wdata = `ZeroWord;div_waddr = `ZeroWord;endendendend// 执行always @ (*) beginreg_we = reg_we_i;reg_waddr = reg_waddr_i;mem_req = `RIB_NREQ;csr_wdata_o = `ZeroWord;case (opcode)`INST_TYPE_I: begincase (funct3)`INST_ADDI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_add_op2_res;end`INST_SLTI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;end`INST_SLTIU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;end`INST_XORI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i ^ op2_i;end`INST_ORI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i | op2_i;end`INST_ANDI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i & op2_i;end`INST_SLLI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = reg1_rdata_i << inst_i[24:20];end`INST_SRI: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;if (inst_i[30] == 1'b1) beginreg_wdata = (sri_shift & sri_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sri_shift_mask));end else beginreg_wdata = reg1_rdata_i >> inst_i[24:20];endenddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend`INST_TYPE_R_M: beginif ((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begincase (funct3)`INST_ADD_SUB: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;if (inst_i[30] == 1'b0) beginreg_wdata = op1_add_op2_res;end else beginreg_wdata = op1_i - op2_i;endend`INST_SLL: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i << op2_i[4:0];end`INST_SLT: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;end`INST_SLTU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;end`INST_XOR: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i ^ op2_i;end`INST_SR: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;if (inst_i[30] == 1'b1) beginreg_wdata = (sr_shift & sr_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sr_shift_mask));end else beginreg_wdata = reg1_rdata_i >> reg2_rdata_i[4:0];endend`INST_OR: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i | op2_i;end`INST_AND: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = op1_i & op2_i;enddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend else if (funct7 == 7'b0000001) begincase (funct3)`INST_MUL: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = mul_temp[31:0];end`INST_MULHU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = mul_temp[63:32];end`INST_MULH: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;case ({reg1_rdata_i[31], reg2_rdata_i[31]})2'b00: beginreg_wdata = mul_temp[63:32];end2'b11: beginreg_wdata = mul_temp[63:32];end2'b10: beginreg_wdata = mul_temp_invert[63:32];enddefault: beginreg_wdata = mul_temp_invert[63:32];endendcaseend`INST_MULHSU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;if (reg1_rdata_i[31] == 1'b1) beginreg_wdata = mul_temp_invert[63:32];end else beginreg_wdata = mul_temp[63:32];endenddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend else beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endend`INST_TYPE_L: begincase (funct3)`INST_LB: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;mem_req = `RIB_REQ;mem_raddr_o = op1_add_op2_res;case (mem_raddr_index)2'b00: beginreg_wdata = {{24{mem_rdata_i[7]}}, mem_rdata_i[7:0]};end2'b01: beginreg_wdata = {{24{mem_rdata_i[15]}}, mem_rdata_i[15:8]};end2'b10: beginreg_wdata = {{24{mem_rdata_i[23]}}, mem_rdata_i[23:16]};enddefault: beginreg_wdata = {{24{mem_rdata_i[31]}}, mem_rdata_i[31:24]};endendcaseend`INST_LH: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;mem_req = `RIB_REQ;mem_raddr_o = op1_add_op2_res;if (mem_raddr_index == 2'b0) beginreg_wdata = {{16{mem_rdata_i[15]}}, mem_rdata_i[15:0]};end else beginreg_wdata = {{16{mem_rdata_i[31]}}, mem_rdata_i[31:16]};endend`INST_LW: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;mem_req = `RIB_REQ;mem_raddr_o = op1_add_op2_res;reg_wdata = mem_rdata_i;end`INST_LBU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;mem_req = `RIB_REQ;mem_raddr_o = op1_add_op2_res;case (mem_raddr_index)2'b00: beginreg_wdata = {24'h0, mem_rdata_i[7:0]};end2'b01: beginreg_wdata = {24'h0, mem_rdata_i[15:8]};end2'b10: beginreg_wdata = {24'h0, mem_rdata_i[23:16]};enddefault: beginreg_wdata = {24'h0, mem_rdata_i[31:24]};endendcaseend`INST_LHU: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;mem_req = `RIB_REQ;mem_raddr_o = op1_add_op2_res;if (mem_raddr_index == 2'b0) beginreg_wdata = {16'h0, mem_rdata_i[15:0]};end else beginreg_wdata = {16'h0, mem_rdata_i[31:16]};endenddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend`INST_TYPE_S: begincase (funct3)`INST_SB: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;reg_wdata = `ZeroWord;mem_we = `WriteEnable;mem_req = `RIB_REQ;mem_waddr_o = op1_add_op2_res;mem_raddr_o = op1_add_op2_res;case (mem_waddr_index)2'b00: beginmem_wdata_o = {mem_rdata_i[31:8], reg2_rdata_i[7:0]};end2'b01: beginmem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[7:0], mem_rdata_i[7:0]};end2'b10: beginmem_wdata_o = {mem_rdata_i[31:24], reg2_rdata_i[7:0], mem_rdata_i[15:0]};enddefault: beginmem_wdata_o = {reg2_rdata_i[7:0], mem_rdata_i[23:0]};endendcaseend`INST_SH: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;reg_wdata = `ZeroWord;mem_we = `WriteEnable;mem_req = `RIB_REQ;mem_waddr_o = op1_add_op2_res;mem_raddr_o = op1_add_op2_res;if (mem_waddr_index == 2'b00) beginmem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[15:0]};end else beginmem_wdata_o = {reg2_rdata_i[15:0], mem_rdata_i[15:0]};endend`INST_SW: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;reg_wdata = `ZeroWord;mem_we = `WriteEnable;mem_req = `RIB_REQ;mem_waddr_o = op1_add_op2_res;mem_raddr_o = op1_add_op2_res;mem_wdata_o = reg2_rdata_i;enddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend`INST_TYPE_B: begincase (funct3)`INST_BEQ: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = op1_eq_op2 & `JumpEnable;jump_addr = {32{op1_eq_op2}} & op1_jump_add_op2_jump_res;end`INST_BNE: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = (~op1_eq_op2) & `JumpEnable;jump_addr = {32{(~op1_eq_op2)}} & op1_jump_add_op2_jump_res;end`INST_BLT: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = (~op1_ge_op2_signed) & `JumpEnable;jump_addr = {32{(~op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;end`INST_BGE: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = (op1_ge_op2_signed) & `JumpEnable;jump_addr = {32{(op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;end`INST_BLTU: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = (~op1_ge_op2_unsigned) & `JumpEnable;jump_addr = {32{(~op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;end`INST_BGEU: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = (op1_ge_op2_unsigned) & `JumpEnable;jump_addr = {32{(op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;enddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseend`INST_JAL, `INST_JALR: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;jump_flag = `JumpEnable;jump_addr = op1_jump_add_op2_jump_res;reg_wdata = op1_add_op2_res;end`INST_LUI, `INST_AUIPC: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;jump_addr = `ZeroWord;jump_flag = `JumpDisable;reg_wdata = op1_add_op2_res;end`INST_NOP_OP: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;end`INST_FENCE: beginhold_flag = `HoldDisable;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;jump_flag = `JumpEnable;jump_addr = op1_jump_add_op2_jump_res;end`INST_CSR: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;case (funct3)`INST_CSRRW: begincsr_wdata_o = reg1_rdata_i;reg_wdata = csr_rdata_i;end`INST_CSRRS: begincsr_wdata_o = reg1_rdata_i | csr_rdata_i;reg_wdata = csr_rdata_i;end`INST_CSRRC: begincsr_wdata_o = csr_rdata_i & (~reg1_rdata_i);reg_wdata = csr_rdata_i;end`INST_CSRRWI: begincsr_wdata_o = {27'h0, uimm};reg_wdata = csr_rdata_i;end`INST_CSRRSI: begincsr_wdata_o = {27'h0, uimm} | csr_rdata_i;reg_wdata = csr_rdata_i;end`INST_CSRRCI: begincsr_wdata_o = (~{27'h0, uimm}) & csr_rdata_i;reg_wdata = csr_rdata_i;enddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseenddefault: beginjump_flag = `JumpDisable;hold_flag = `HoldDisable;jump_addr = `ZeroWord;mem_wdata_o = `ZeroWord;mem_raddr_o = `ZeroWord;mem_waddr_o = `ZeroWord;mem_we = `WriteDisable;reg_wdata = `ZeroWord;endendcaseendendmodule
clint 模块
`include "defines.v"// core local interruptor module
// 核心中断管理、仲裁模块
module clint(input wire clk,input wire rst,// from coreinput wire[`INT_BUS] int_flag_i, // 中断输入信号// from idinput wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址// from exinput wire jump_flag_i,input wire[`InstAddrBus] jump_addr_i,input wire div_started_i,// from ctrlinput wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志// from csr_reginput wire[`RegBus] data_i, // CSR寄存器输入数据input wire[`RegBus] csr_mtvec, // mtvec寄存器input wire[`RegBus] csr_mepc, // mepc寄存器input wire[`RegBus] csr_mstatus, // mstatus寄存器input wire global_int_en_i, // 全局中断使能标志// to ctrloutput wire hold_flag_o, // 流水线暂停标志// to csr_regoutput reg we_o, // 写CSR寄存器标志output reg[`MemAddrBus] waddr_o, // 写CSR寄存器地址output reg[`MemAddrBus] raddr_o, // 读CSR寄存器地址output reg[`RegBus] data_o, // 写CSR寄存器数据// to exoutput reg[`InstAddrBus] int_addr_o, // 中断入口地址output reg int_assert_o // 中断标志);// 中断状态定义localparam S_INT_IDLE = 4'b0001;localparam S_INT_SYNC_ASSERT = 4'b0010;localparam S_INT_ASYNC_ASSERT = 4'b0100;localparam S_INT_MRET = 4'b1000;// 写CSR寄存器状态定义localparam S_CSR_IDLE = 5'b00001;localparam S_CSR_MSTATUS = 5'b00010;localparam S_CSR_MEPC = 5'b00100;localparam S_CSR_MSTATUS_MRET = 5'b01000;localparam S_CSR_MCAUSE = 5'b10000;reg[3:0] int_state;reg[4:0] csr_state;reg[`InstAddrBus] inst_addr;reg[31:0] cause;assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;// 中断仲裁逻辑always @ (*) beginif (rst == `RstEnable) beginint_state = S_INT_IDLE;end else beginif (inst_i == `INST_ECALL || inst_i == `INST_EBREAK) begin// 如果执行阶段的指令为除法指令,则先不处理同步中断,等除法指令执行完再处理if (div_started_i == `DivStop) beginint_state = S_INT_SYNC_ASSERT;end else beginint_state = S_INT_IDLE;endend else if (int_flag_i != `INT_NONE && global_int_en_i == `True) beginint_state = S_INT_ASYNC_ASSERT;end else if (inst_i == `INST_MRET) beginint_state = S_INT_MRET;end else beginint_state = S_INT_IDLE;endendend// 写CSR寄存器状态切换always @ (posedge clk) beginif (rst == `RstEnable) begincsr_state <= S_CSR_IDLE;cause <= `ZeroWord;inst_addr <= `ZeroWord;end else begincase (csr_state)S_CSR_IDLE: begin// 同步中断if (int_state == S_INT_SYNC_ASSERT) begincsr_state <= S_CSR_MEPC;// 在中断处理函数里会将中断返回地址加4if (jump_flag_i == `JumpEnable) begininst_addr <= jump_addr_i - 4'h4;end else begininst_addr <= inst_addr_i;endcase (inst_i)`INST_ECALL: begincause <= 32'd11;end`INST_EBREAK: begincause <= 32'd3;enddefault: begincause <= 32'd10;endendcase// 异步中断end else if (int_state == S_INT_ASYNC_ASSERT) begin// 定时器中断cause <= 32'h80000004;csr_state <= S_CSR_MEPC;if (jump_flag_i == `JumpEnable) begininst_addr <= jump_addr_i;// 异步中断可以中断除法指令的执行,中断处理完再重新执行除法指令end else if (div_started_i == `DivStart) begininst_addr <= inst_addr_i - 4'h4;end else begininst_addr <= inst_addr_i;end// 中断返回end else if (int_state == S_INT_MRET) begincsr_state <= S_CSR_MSTATUS_MRET;endendS_CSR_MEPC: begincsr_state <= S_CSR_MSTATUS;endS_CSR_MSTATUS: begincsr_state <= S_CSR_MCAUSE;endS_CSR_MCAUSE: begincsr_state <= S_CSR_IDLE;endS_CSR_MSTATUS_MRET: begincsr_state <= S_CSR_IDLE;enddefault: begincsr_state <= S_CSR_IDLE;endendcaseendend// 发出中断信号前,先写几个CSR寄存器always @ (posedge clk) beginif (rst == `RstEnable) beginwe_o <= `WriteDisable;waddr_o <= `ZeroWord;data_o <= `ZeroWord;end else begincase (csr_state)// 将mepc寄存器的值设为当前指令地址S_CSR_MEPC: beginwe_o <= `WriteEnable;waddr_o <= {20'h0, `CSR_MEPC};data_o <= inst_addr;end// 写中断产生的原因S_CSR_MCAUSE: beginwe_o <= `WriteEnable;waddr_o <= {20'h0, `CSR_MCAUSE};data_o <= cause;end// 关闭全局中断S_CSR_MSTATUS: beginwe_o <= `WriteEnable;waddr_o <= {20'h0, `CSR_MSTATUS};data_o <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]};end// 中断返回S_CSR_MSTATUS_MRET: beginwe_o <= `WriteEnable;waddr_o <= {20'h0, `CSR_MSTATUS};data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};enddefault: beginwe_o <= `WriteDisable;waddr_o <= `ZeroWord;data_o <= `ZeroWord;endendcaseendend// 发出中断信号给ex模块always @ (posedge clk) beginif (rst == `RstEnable) beginint_assert_o <= `INT_DEASSERT;int_addr_o <= `ZeroWord;end else begincase (csr_state)// 发出中断进入信号.写完mcause寄存器才能发S_CSR_MCAUSE: beginint_assert_o <= `INT_ASSERT;int_addr_o <= csr_mtvec;end// 发出中断返回信号S_CSR_MSTATUS_MRET: beginint_assert_o <= `INT_ASSERT;int_addr_o <= csr_mepc;enddefault: beginint_assert_o <= `INT_DEASSERT;int_addr_o <= `ZeroWord;endendcaseendendendmodule
ctrl 模块
`include "defines.v"// 控制模块
// 发出跳转、暂停流水线信号
module ctrl(input wire rst,// from exinput wire jump_flag_i,input wire[`InstAddrBus] jump_addr_i,input wire hold_flag_ex_i,// from ribinput wire hold_flag_rib_i,// from jtaginput wire jtag_halt_flag_i,// from clintinput wire hold_flag_clint_i,output reg[`Hold_Flag_Bus] hold_flag_o,// to pc_regoutput reg jump_flag_o,output reg[`InstAddrBus] jump_addr_o);always @ (*) beginjump_addr_o = jump_addr_i;jump_flag_o = jump_flag_i;// 默认不暂停hold_flag_o = `Hold_None;// 按优先级处理不同模块的请求if (jump_flag_i == `JumpEnable || hold_flag_ex_i == `HoldEnable || hold_flag_clint_i == `HoldEnable) begin// 暂停整条流水线hold_flag_o = `Hold_Id;end else if (hold_flag_rib_i == `HoldEnable) begin// 暂停PC,即取指地址不变hold_flag_o = `Hold_Pc;end else if (jtag_halt_flag_i == `HoldEnable) begin// 暂停整条流水线hold_flag_o = `Hold_Id;end else beginhold_flag_o = `Hold_None;endendendmodule
dff_set 模块
module dff_set #(parameter DW = 32
)
(input wire clk ,input wire rst ,input wire hold_flag_i,input wire [DW-1:0] set_data , input wire [DW-1:0] data_i , output reg [DW-1:0] data_o
);always @(posedge clk)beginif(rst == 1'b0 || hold_flag_i == 1'b1)data_o <= set_data;elsedata_o <= data_i;end endmodule
regs 模块
`include "defines.v"// 通用寄存器模块
module regs(input wire clk,input wire rst,// from exinput wire we_i, // 写寄存器标志input wire[`RegAddrBus] waddr_i, // 写寄存器地址input wire[`RegBus] wdata_i, // 写寄存器数据// from jtaginput wire jtag_we_i, // 写寄存器标志input wire[`RegAddrBus] jtag_addr_i, // 读、写寄存器地址input wire[`RegBus] jtag_data_i, // 写寄存器数据// from idinput wire[`RegAddrBus] raddr1_i, // 读寄存器1地址// to idoutput reg[`RegBus] rdata1_o, // 读寄存器1数据// from idinput wire[`RegAddrBus] raddr2_i, // 读寄存器2地址// to idoutput reg[`RegBus] rdata2_o, // 读寄存器2数据// to jtagoutput reg[`RegBus] jtag_data_o // 读寄存器数据);reg[`RegBus] regs[0:`RegNum - 1];// 写寄存器always @ (posedge clk) beginif (rst == `RstDisable) begin// 优先ex模块写操作if ((we_i == `WriteEnable) && (waddr_i != `ZeroReg)) beginregs[waddr_i] <= wdata_i;end else if ((jtag_we_i == `WriteEnable) && (jtag_addr_i != `ZeroReg)) beginregs[jtag_addr_i] <= jtag_data_i;endendend// 读寄存器1always @ (*) beginif (raddr1_i == `ZeroReg) beginrdata1_o = `ZeroWord;// 如果读地址等于写地址,并且正在写操作,则直接返回写数据end else if (raddr1_i == waddr_i && we_i == `WriteEnable) beginrdata1_o = wdata_i;end else beginrdata1_o = regs[raddr1_i];endend// 读寄存器2always @ (*) beginif (raddr2_i == `ZeroReg) beginrdata2_o = `ZeroWord;// 如果读地址等于写地址,并且正在写操作,则直接返回写数据end else if (raddr2_i == waddr_i && we_i == `WriteEnable) beginrdata2_o = wdata_i;end else beginrdata2_o = regs[raddr2_i];endend// jtag读寄存器always @ (*) beginif (jtag_addr_i == `ZeroReg) beginjtag_data_o = `ZeroWord;end else beginjtag_data_o = regs[jtag_addr_i];endendendmodule
csr_reg 模块
`include "defines.v"// CSR寄存器模块
module csr_reg(input wire clk,input wire rst,// form exinput wire we_i, // ex模块写寄存器标志input wire[`MemAddrBus] raddr_i, // ex模块读寄存器地址input wire[`MemAddrBus] waddr_i, // ex模块写寄存器地址input wire[`RegBus] data_i, // ex模块写寄存器数据// from clintinput wire clint_we_i, // clint模块写寄存器标志input wire[`MemAddrBus] clint_raddr_i, // clint模块读寄存器地址input wire[`MemAddrBus] clint_waddr_i, // clint模块写寄存器地址input wire[`RegBus] clint_data_i, // clint模块写寄存器数据output wire global_int_en_o, // 全局中断使能标志// to clintoutput reg[`RegBus] clint_data_o, // clint模块读寄存器数据output wire[`RegBus] clint_csr_mtvec, // mtvecoutput wire[`RegBus] clint_csr_mepc, // mepcoutput wire[`RegBus] clint_csr_mstatus, // mstatus// to exoutput reg[`RegBus] data_o // ex模块读寄存器数据);reg[`DoubleRegBus] cycle;reg[`RegBus] mtvec;reg[`RegBus] mcause;reg[`RegBus] mepc;reg[`RegBus] mie;reg[`RegBus] mstatus;reg[`RegBus] mscratch;assign global_int_en_o = (mstatus[3] == 1'b1)? `True: `False;assign clint_csr_mtvec = mtvec;assign clint_csr_mepc = mepc;assign clint_csr_mstatus = mstatus;// cycle counter// 复位撤销后就一直计数always @ (posedge clk) beginif (rst == `RstEnable) begincycle <= {`ZeroWord, `ZeroWord};end else begincycle <= cycle + 1'b1;endend// write reg// 写寄存器操作always @ (posedge clk) beginif (rst == `RstEnable) beginmtvec <= `ZeroWord;mcause <= `ZeroWord;mepc <= `ZeroWord;mie <= `ZeroWord;mstatus <= `ZeroWord;mscratch <= `ZeroWord;end else begin// 优先响应ex模块的写操作if (we_i == `WriteEnable) begincase (waddr_i[11:0])`CSR_MTVEC: beginmtvec <= data_i;end`CSR_MCAUSE: beginmcause <= data_i;end`CSR_MEPC: beginmepc <= data_i;end`CSR_MIE: beginmie <= data_i;end`CSR_MSTATUS: beginmstatus <= data_i;end`CSR_MSCRATCH: beginmscratch <= data_i;enddefault: beginendendcase// clint模块写操作end else if (clint_we_i == `WriteEnable) begincase (clint_waddr_i[11:0])`CSR_MTVEC: beginmtvec <= clint_data_i;end`CSR_MCAUSE: beginmcause <= clint_data_i;end`CSR_MEPC: beginmepc <= clint_data_i;end`CSR_MIE: beginmie <= clint_data_i;end`CSR_MSTATUS: beginmstatus <= clint_data_i;end`CSR_MSCRATCH: beginmscratch <= clint_data_i;enddefault: beginendendcaseendendend// read reg// ex模块读CSR寄存器always @ (*) beginif ((waddr_i[11:0] == raddr_i[11:0]) && (we_i == `WriteEnable)) begindata_o = data_i;end else begincase (raddr_i[11:0])`CSR_CYCLE: begindata_o = cycle[31:0];end`CSR_CYCLEH: begindata_o = cycle[63:32];end`CSR_MTVEC: begindata_o = mtvec;end`CSR_MCAUSE: begindata_o = mcause;end`CSR_MEPC: begindata_o = mepc;end`CSR_MIE: begindata_o = mie;end`CSR_MSTATUS: begindata_o = mstatus;end`CSR_MSCRATCH: begindata_o = mscratch;enddefault: begindata_o = `ZeroWord;endendcaseendend// read reg// clint模块读CSR寄存器always @ (*) beginif ((clint_waddr_i[11:0] == clint_raddr_i[11:0]) && (clint_we_i == `WriteEnable)) beginclint_data_o = clint_data_i;end else begincase (clint_raddr_i[11:0])`CSR_CYCLE: beginclint_data_o = cycle[31:0];end`CSR_CYCLEH: beginclint_data_o = cycle[63:32];end`CSR_MTVEC: beginclint_data_o = mtvec;end`CSR_MCAUSE: beginclint_data_o = mcause;end`CSR_MEPC: beginclint_data_o = mepc;end`CSR_MIE: beginclint_data_o = mie;end`CSR_MSTATUS: beginclint_data_o = mstatus;end`CSR_MSCRATCH: beginclint_data_o = mscratch;enddefault: beginclint_data_o = `ZeroWord;endendcaseendendendmodule
div 模块
`include "defines.v"// 除法模块
// 试商法实现32位整数除法
// 每次除法运算至少需要33个时钟周期才能完成
module div(input wire clk,input wire rst,// from exinput wire[`RegBus] dividend_i, // 被除数input wire[`RegBus] divisor_i, // 除数input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效input wire[2:0] op_i, // 具体是哪一条指令input wire[`RegAddrBus] reg_waddr_i, // 运算结束后需要写的寄存器// to exoutput reg[`RegBus] result_o, // 除法结果,高32位是余数,低32位是商output reg ready_o, // 运算结束信号output reg busy_o, // 正在运算信号output reg[`RegAddrBus] reg_waddr_o // 运算结束后需要写的寄存器);// 状态定义localparam STATE_IDLE = 4'b0001;localparam STATE_START = 4'b0010;localparam STATE_CALC = 4'b0100;localparam STATE_END = 4'b1000;reg[`RegBus] dividend_r;reg[`RegBus] divisor_r;reg[2:0] op_r;reg[3:0] state;reg[31:0] count;reg[`RegBus] div_result;reg[`RegBus] div_remain;reg[`RegBus] minuend;reg invert_result;wire op_div = (op_r == `INST_DIV);wire op_divu = (op_r == `INST_DIVU);wire op_rem = (op_r == `INST_REM);wire op_remu = (op_r == `INST_REMU);wire[31:0] dividend_invert = (-dividend_r);wire[31:0] divisor_invert = (-divisor_r);wire minuend_ge_divisor = minuend >= divisor_r;wire[31:0] minuend_sub_res = minuend - divisor_r;wire[31:0] div_result_tmp = minuend_ge_divisor? ({div_result[30:0], 1'b1}): ({div_result[30:0], 1'b0});wire[31:0] minuend_tmp = minuend_ge_divisor? minuend_sub_res[30:0]: minuend[30:0];// 状态机实现always @ (posedge clk) beginif (rst == `RstEnable) beginstate <= STATE_IDLE;ready_o <= `DivResultNotReady;result_o <= `ZeroWord;div_result <= `ZeroWord;div_remain <= `ZeroWord;op_r <= 3'h0;reg_waddr_o <= `ZeroWord;dividend_r <= `ZeroWord;divisor_r <= `ZeroWord;minuend <= `ZeroWord;invert_result <= 1'b0;busy_o <= `False;count <= `ZeroWord;end else begincase (state)STATE_IDLE: beginif (start_i == `DivStart) beginop_r <= op_i;dividend_r <= dividend_i;divisor_r <= divisor_i;reg_waddr_o <= reg_waddr_i;state <= STATE_START;busy_o <= `True;end else beginop_r <= 3'h0;reg_waddr_o <= `ZeroWord;dividend_r <= `ZeroWord;divisor_r <= `ZeroWord;ready_o <= `DivResultNotReady;result_o <= `ZeroWord;busy_o <= `False;endendSTATE_START: beginif (start_i == `DivStart) begin// 除数为0if (divisor_r == `ZeroWord) beginif (op_div | op_divu) beginresult_o <= 32'hffffffff;end else beginresult_o <= dividend_r;endready_o <= `DivResultReady;state <= STATE_IDLE;busy_o <= `False;// 除数不为0end else beginbusy_o <= `True;count <= 32'h40000000;state <= STATE_CALC;div_result <= `ZeroWord;div_remain <= `ZeroWord;// DIV和REM这两条指令是有符号数运算指令if (op_div | op_rem) begin// 被除数求补码if (dividend_r[31] == 1'b1) begindividend_r <= dividend_invert;minuend <= dividend_invert[31];end else beginminuend <= dividend_r[31];end// 除数求补码if (divisor_r[31] == 1'b1) begindivisor_r <= divisor_invert;endend else beginminuend <= dividend_r[31];end// 运算结束后是否要对结果取补码if ((op_div && (dividend_r[31] ^ divisor_r[31] == 1'b1))|| (op_rem && (dividend_r[31] == 1'b1))) begininvert_result <= 1'b1;end else begininvert_result <= 1'b0;endendend else beginstate <= STATE_IDLE;result_o <= `ZeroWord;ready_o <= `DivResultNotReady;busy_o <= `False;endendSTATE_CALC: beginif (start_i == `DivStart) begindividend_r <= {dividend_r[30:0], 1'b0};div_result <= div_result_tmp;count <= {1'b0, count[31:1]};if (|count) beginminuend <= {minuend_tmp[30:0], dividend_r[30]};end else beginstate <= STATE_END;if (minuend_ge_divisor) begindiv_remain <= minuend_sub_res;end else begindiv_remain <= minuend;endendend else beginstate <= STATE_IDLE;result_o <= `ZeroWord;ready_o <= `DivResultNotReady;busy_o <= `False;endendSTATE_END: beginif (start_i == `DivStart) beginready_o <= `DivResultReady;state <= STATE_IDLE;busy_o <= `False;if (op_div | op_divu) beginif (invert_result) beginresult_o <= (-div_result);end else beginresult_o <= div_result;endend else beginif (invert_result) beginresult_o <= (-div_remain);end else beginresult_o <= div_remain;endendend else beginstate <= STATE_IDLE;result_o <= `ZeroWord;ready_o <= `DivResultNotReady;busy_o <= `False;endendendcaseendendendmodule
defines 模块
`define CpuResetAddr 32'h0`define RstEnable 1'b0 //低电位有效
`define RstDisable 1'b1
`define ZeroWord 32'h0
`define ZeroReg 5'h0
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define True 1'b1
`define False 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0
`define JumpEnable 1'b1
`define JumpDisable 1'b0
`define DivResultNotReady 1'b0
`define DivResultReady 1'b1
`define DivStart 1'b1
`define DivStop 1'b0
`define HoldEnable 1'b1
`define HoldDisable 1'b0
`define Stop 1'b1
`define NoStop 1'b0
`define RIB_ACK 1'b1
`define RIB_NACK 1'b0
`define RIB_REQ 1'b1
`define RIB_NREQ 1'b0
`define INT_ASSERT 1'b1
`define INT_DEASSERT 1'b0`define INT_BUS 7:0
`define INT_NONE 8'h0
`define INT_RET 8'hff
`define INT_TIMER0 8'b00000001
`define INT_TIMER0_ENTRY_ADDR 32'h4`define Hold_Flag_Bus 2:0
`define Hold_None 3'b000
`define Hold_Pc 3'b001
`define Hold_If 3'b010
`define Hold_Id 3'b011// I type inst
`define INST_TYPE_I 7'b0010011
`define INST_ADDI 3'b000
`define INST_SLTI 3'b010
`define INST_SLTIU 3'b011
`define INST_XORI 3'b100
`define INST_ORI 3'b110
`define INST_ANDI 3'b111
`define INST_SLLI 3'b001
`define INST_SRI 3'b101// L type inst
`define INST_TYPE_L 7'b0000011
`define INST_LB 3'b000
`define INST_LH 3'b001
`define INST_LW 3'b010
`define INST_LBU 3'b100
`define INST_LHU 3'b101// S type inst
`define INST_TYPE_S 7'b0100011
`define INST_SB 3'b000
`define INST_SH 3'b001
`define INST_SW 3'b010// R and M type inst
`define INST_TYPE_R_M 7'b0110011
// R type inst
`define INST_ADD_SUB 3'b000
`define INST_SLL 3'b001
`define INST_SLT 3'b010
`define INST_SLTU 3'b011
`define INST_XOR 3'b100
`define INST_SR 3'b101
`define INST_OR 3'b110
`define INST_AND 3'b111
// M type inst
`define INST_MUL 3'b000
`define INST_MULH 3'b001
`define INST_MULHSU 3'b010
`define INST_MULHU 3'b011
`define INST_DIV 3'b100
`define INST_DIVU 3'b101
`define INST_REM 3'b110
`define INST_REMU 3'b111// J type inst
`define INST_JAL 7'b1101111
`define INST_JALR 7'b1100111`define INST_LUI 7'b0110111
`define INST_AUIPC 7'b0010111
`define INST_NOP 32'h00000001
`define INST_NOP_OP 7'b0000001
`define INST_MRET 32'h30200073
`define INST_RET 32'h00008067`define INST_FENCE 7'b0001111
`define INST_ECALL 32'h73
`define INST_EBREAK 32'h00100073// J type inst
`define INST_TYPE_B 7'b1100011
`define INST_BEQ 3'b000
`define INST_BNE 3'b001
`define INST_BLT 3'b100
`define INST_BGE 3'b101
`define INST_BLTU 3'b110
`define INST_BGEU 3'b111// CSR inst
`define INST_CSR 7'b1110011
`define INST_CSRRW 3'b001
`define INST_CSRRS 3'b010
`define INST_CSRRC 3'b011
`define INST_CSRRWI 3'b101
`define INST_CSRRSI 3'b110
`define INST_CSRRCI 3'b111// CSR reg addr
`define CSR_CYCLE 12'hc00
`define CSR_CYCLEH 12'hc80
`define CSR_MTVEC 12'h305
`define CSR_MCAUSE 12'h342
`define CSR_MEPC 12'h341
`define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340`define RomNum 4096 // rom depth(how many words)`define MemNum 4096 // memory depth(how many words)
`define MemBus 31:0
`define MemAddrBus 31:0`define InstBus 31:0
`define InstAddrBus 31:0// common regs
`define RegAddrBus 4:0
`define RegBus 31:0
`define DoubleRegBus 63:0
`define RegWidth 32
`define RegNum 32 // reg num
`define RegNumLog2 5
tinyriscv 模块
`include "defines.v"// tinyriscv处理器核顶层模块
module tinyriscv(input wire clk , // 时钟信号input wire rst , // 复位信号output wire[`MemAddrBus] rib_ex_addr_o , // 读、写外设的地址input wire[`MemBus] rib_ex_data_i , // 从外设读取的数据output wire[`MemBus] rib_ex_data_o , // 写入外设的数据output wire rib_ex_req_o , // 访问外设请求output wire rib_ex_we_o , // 写外设标志output wire[`MemAddrBus] rib_pc_addr_o , // 取指地址input wire[`MemBus] rib_pc_data_i , // 取到的指令内容input wire[`RegAddrBus] jtag_reg_addr_i , // jtag模块读、写寄存器的地址input wire[`RegBus] jtag_reg_data_i , // jtag模块写寄存器数据input wire jtag_reg_we_i , // jtag模块写寄存器标志output wire[`RegBus] jtag_reg_data_o , // jtag模块读取到的寄存器数据input wire rib_hold_flag_i , // 总线暂停标志input wire jtag_halt_flag_i , // jtag暂停标志input wire jtag_reset_flag_i , // jtag复位PC标志input wire[`INT_BUS] int_i // 中断信号);// pc_reg模块输出信号wire[`InstAddrBus] pc_o;// if_id模块输出信号wire[`InstBus] if_inst_o;wire[`InstAddrBus] if_inst_addr_o;wire[`INT_BUS] if_int_flag_o;// id模块输出信号wire[`RegAddrBus] id_reg1_raddr_o;wire[`RegAddrBus] id_reg2_raddr_o;wire[`InstBus] id_inst_o;wire[`InstAddrBus] id_inst_addr_o;wire[`RegBus] id_reg1_rdata_o;wire[`RegBus] id_reg2_rdata_o;wire id_reg_we_o;wire[`RegAddrBus] id_reg_waddr_o;wire[`MemAddrBus] id_csr_raddr_o;wire id_csr_we_o;wire[`RegBus] id_csr_rdata_o;wire[`MemAddrBus] id_csr_waddr_o;wire[`MemAddrBus] id_op1_o;wire[`MemAddrBus] id_op2_o;wire[`MemAddrBus] id_op1_jump_o;wire[`MemAddrBus] id_op2_jump_o;// id_ex模块输出信号wire[`InstBus] ie_inst_o;wire[`InstAddrBus] ie_inst_addr_o;wire ie_reg_we_o;wire[`RegAddrBus] ie_reg_waddr_o;wire[`RegBus] ie_reg1_rdata_o;wire[`RegBus] ie_reg2_rdata_o;wire ie_csr_we_o;wire[`MemAddrBus] ie_csr_waddr_o;wire[`RegBus] ie_csr_rdata_o;wire[`MemAddrBus] ie_op1_o;wire[`MemAddrBus] ie_op2_o;wire[`MemAddrBus] ie_op1_jump_o;wire[`MemAddrBus] ie_op2_jump_o;// ex模块输出信号wire[`MemBus] ex_mem_wdata_o;wire[`MemAddrBus] ex_mem_raddr_o;wire[`MemAddrBus] ex_mem_waddr_o;wire ex_mem_we_o;wire ex_mem_req_o;wire[`RegBus] ex_reg_wdata_o;wire ex_reg_we_o;wire[`RegAddrBus] ex_reg_waddr_o;wire ex_hold_flag_o;wire ex_jump_flag_o;wire[`InstAddrBus] ex_jump_addr_o;wire ex_div_start_o;wire[`RegBus] ex_div_dividend_o;wire[`RegBus] ex_div_divisor_o;wire[2:0] ex_div_op_o;wire[`RegAddrBus] ex_div_reg_waddr_o;wire[`RegBus] ex_csr_wdata_o;wire ex_csr_we_o;wire[`MemAddrBus] ex_csr_waddr_o;// regs模块输出信号wire[`RegBus] regs_rdata1_o;wire[`RegBus] regs_rdata2_o;// csr_reg模块输出信号wire[`RegBus] csr_data_o;wire[`RegBus] csr_clint_data_o;wire csr_global_int_en_o;wire[`RegBus] csr_clint_csr_mtvec;wire[`RegBus] csr_clint_csr_mepc;wire[`RegBus] csr_clint_csr_mstatus;// ctrl模块输出信号wire[`Hold_Flag_Bus] ctrl_hold_flag_o;wire ctrl_jump_flag_o;wire[`InstAddrBus] ctrl_jump_addr_o;// div模块输出信号wire[`RegBus] div_result_o;wire div_ready_o;wire div_busy_o;wire[`RegAddrBus] div_reg_waddr_o;// clint模块输出信号wire clint_we_o;wire[`MemAddrBus] clint_waddr_o;wire[`MemAddrBus] clint_raddr_o;wire[`RegBus] clint_data_o;wire[`InstAddrBus] clint_int_addr_o;wire clint_int_assert_o;wire clint_hold_flag_o;assign rib_ex_addr_o = (ex_mem_we_o == `WriteEnable)? ex_mem_waddr_o: ex_mem_raddr_o;assign rib_ex_data_o = ex_mem_wdata_o;assign rib_ex_req_o = ex_mem_req_o;assign rib_ex_we_o = ex_mem_we_o;assign rib_pc_addr_o = pc_o;// pc_reg模块例化pc_reg u_pc_reg(.clk(clk),.rst(rst),.hold_flag_i(ctrl_hold_flag_o),.jump_flag_i(ctrl_jump_flag_o),.jump_addr_i(ctrl_jump_addr_o),.jtag_reset_flag_i(jtag_reset_flag_i),.pc_o(pc_o));// ctrl模块例化ctrl u_ctrl(.rst(rst),.jump_flag_i(ex_jump_flag_o),.jump_addr_i(ex_jump_addr_o),.hold_flag_ex_i(ex_hold_flag_o),.hold_flag_rib_i(rib_hold_flag_i),.hold_flag_o(ctrl_hold_flag_o),.hold_flag_clint_i(clint_hold_flag_o),.jump_flag_o(ctrl_jump_flag_o),.jump_addr_o(ctrl_jump_addr_o),.jtag_halt_flag_i(jtag_halt_flag_i));// regs模块例化regs u_regs(.clk(clk),.rst(rst),.we_i(ex_reg_we_o),.waddr_i(ex_reg_waddr_o),.wdata_i(ex_reg_wdata_o),.raddr1_i(id_reg1_raddr_o),.raddr2_i(id_reg2_raddr_o),.rdata1_o(regs_rdata1_o),.rdata2_o(regs_rdata2_o),.jtag_we_i(jtag_reg_we_i),.jtag_addr_i(jtag_reg_addr_i),.jtag_data_i(jtag_reg_data_i),.jtag_data_o(jtag_reg_data_o));// csr_reg模块例化csr_reg u_csr_reg(.clk(clk),.rst(rst),.we_i(ex_csr_we_o),.raddr_i(id_csr_raddr_o),.waddr_i(ex_csr_waddr_o),.data_i(ex_csr_wdata_o),.data_o(csr_data_o),.global_int_en_o(csr_global_int_en_o),.clint_we_i(clint_we_o),.clint_raddr_i(clint_raddr_o),.clint_waddr_i(clint_waddr_o),.clint_data_i(clint_data_o),.clint_data_o(csr_clint_data_o),.clint_csr_mtvec(csr_clint_csr_mtvec),.clint_csr_mepc(csr_clint_csr_mepc),.clint_csr_mstatus(csr_clint_csr_mstatus));// if_id模块例化if_id u_if_id(.clk(clk),.rst(rst),.inst_i(rib_pc_data_i),.inst_addr_i(pc_o),.int_flag_i(int_i),.hold_flag_i(ctrl_hold_flag_o),.int_flag_o(if_int_flag_o),.inst_o(if_inst_o),.inst_addr_o(if_inst_addr_o));// id模块例化id u_id(.rst(rst),.inst_i(if_inst_o),.inst_addr_i(if_inst_addr_o),.reg1_rdata_i(regs_rdata1_o),.reg2_rdata_i(regs_rdata2_o),.ex_jump_flag_i(ex_jump_flag_o),.reg1_raddr_o(id_reg1_raddr_o),.reg2_raddr_o(id_reg2_raddr_o),.inst_o(id_inst_o),.inst_addr_o(id_inst_addr_o),.reg1_rdata_o(id_reg1_rdata_o),.reg2_rdata_o(id_reg2_rdata_o),.reg_we_o(id_reg_we_o),.reg_waddr_o(id_reg_waddr_o),.op1_o(id_op1_o),.op2_o(id_op2_o),.op1_jump_o(id_op1_jump_o),.op2_jump_o(id_op2_jump_o),.csr_rdata_i(csr_data_o),.csr_raddr_o(id_csr_raddr_o),.csr_we_o(id_csr_we_o),.csr_rdata_o(id_csr_rdata_o),.csr_waddr_o(id_csr_waddr_o));// id_ex模块例化id_ex u_id_ex(.clk(clk),.rst(rst),.inst_i(id_inst_o),.inst_addr_i(id_inst_addr_o),.reg_we_i(id_reg_we_o),.reg_waddr_i(id_reg_waddr_o),.reg1_rdata_i(id_reg1_rdata_o),.reg2_rdata_i(id_reg2_rdata_o),.hold_flag_i(ctrl_hold_flag_o),.inst_o(ie_inst_o),.inst_addr_o(ie_inst_addr_o),.reg_we_o(ie_reg_we_o),.reg_waddr_o(ie_reg_waddr_o),.reg1_rdata_o(ie_reg1_rdata_o),.reg2_rdata_o(ie_reg2_rdata_o),.op1_i(id_op1_o),.op2_i(id_op2_o),.op1_jump_i(id_op1_jump_o),.op2_jump_i(id_op2_jump_o),.op1_o(ie_op1_o),.op2_o(ie_op2_o),.op1_jump_o(ie_op1_jump_o),.op2_jump_o(ie_op2_jump_o),.csr_we_i(id_csr_we_o),.csr_waddr_i(id_csr_waddr_o),.csr_rdata_i(id_csr_rdata_o),.csr_we_o(ie_csr_we_o),.csr_waddr_o(ie_csr_waddr_o),.csr_rdata_o(ie_csr_rdata_o));// ex模块例化ex u_ex(.rst(rst),.inst_i(ie_inst_o),.inst_addr_i(ie_inst_addr_o),.reg_we_i(ie_reg_we_o),.reg_waddr_i(ie_reg_waddr_o),.reg1_rdata_i(ie_reg1_rdata_o),.reg2_rdata_i(ie_reg2_rdata_o),.op1_i(ie_op1_o),.op2_i(ie_op2_o),.op1_jump_i(ie_op1_jump_o),.op2_jump_i(ie_op2_jump_o),.mem_rdata_i(rib_ex_data_i),.mem_wdata_o(ex_mem_wdata_o),.mem_raddr_o(ex_mem_raddr_o),.mem_waddr_o(ex_mem_waddr_o),.mem_we_o(ex_mem_we_o),.mem_req_o(ex_mem_req_o),.reg_wdata_o(ex_reg_wdata_o),.reg_we_o(ex_reg_we_o),.reg_waddr_o(ex_reg_waddr_o),.hold_flag_o(ex_hold_flag_o),.jump_flag_o(ex_jump_flag_o),.jump_addr_o(ex_jump_addr_o),.int_assert_i(clint_int_assert_o),.int_addr_i(clint_int_addr_o),.div_ready_i(div_ready_o),.div_result_i(div_result_o),.div_busy_i(div_busy_o),.div_reg_waddr_i(div_reg_waddr_o),.div_start_o(ex_div_start_o),.div_dividend_o(ex_div_dividend_o),.div_divisor_o(ex_div_divisor_o),.div_op_o(ex_div_op_o),.div_reg_waddr_o(ex_div_reg_waddr_o),.csr_we_i(ie_csr_we_o),.csr_waddr_i(ie_csr_waddr_o),.csr_rdata_i(ie_csr_rdata_o),.csr_wdata_o(ex_csr_wdata_o),.csr_we_o(ex_csr_we_o),.csr_waddr_o(ex_csr_waddr_o));// div模块例化div u_div(.clk(clk),.rst(rst),.dividend_i(ex_div_dividend_o),.divisor_i(ex_div_divisor_o),.start_i(ex_div_start_o),.op_i(ex_div_op_o),.reg_waddr_i(ex_div_reg_waddr_o),.result_o(div_result_o),.ready_o(div_ready_o),.busy_o(div_busy_o),.reg_waddr_o(div_reg_waddr_o));// clint模块例化clint u_clint(.clk(clk),.rst(rst),.int_flag_i(if_int_flag_o),.inst_i(id_inst_o),.inst_addr_i(id_inst_addr_o),.jump_flag_i(ex_jump_flag_o),.jump_addr_i(ex_jump_addr_o),.hold_flag_i(ctrl_hold_flag_o),.div_started_i(ex_div_start_o),.data_i(csr_clint_data_o),.csr_mtvec(csr_clint_csr_mtvec),.csr_mepc(csr_clint_csr_mepc),.csr_mstatus(csr_clint_csr_mstatus),.we_o(clint_we_o),.waddr_o(clint_waddr_o),.raddr_o(clint_raddr_o),.data_o(clint_data_o),.hold_flag_o(clint_hold_flag_o),.global_int_en_i(csr_global_int_en_o),.int_addr_o(clint_int_addr_o),.int_assert_o(clint_int_assert_o));endmodule
ram 模块
module ram(input wire rst ,input wire clk ,input wire[31:0] inst_addr_i,output reg[31:0] inst_o
);reg[31:0]ram_mem[0:4095]; //4096 个 32b的 空间 //错// always @(*)begin// if (rst == `RstEnable) begin// inst_o = `ZeroWord;// end else begin// inst_o = ram_mem[inst_addr_i>>2];// end// endalways @(*)beginif (!rst) begininst_o = 32'd0;end else begininst_o = ram_mem[inst_addr_i>>2];endendendmodule
rib 模块
`include "defines.v"// RIB总线模块
module rib(input wire clk,input wire rst,// master 0 interfaceinput wire[`MemAddrBus] m0_addr_i, // 主设备0读、写地址input wire[`MemBus] m0_data_i, // 主设备0写数据output reg[`MemBus] m0_data_o, // 主设备0读取到的数据input wire m0_req_i, // 主设备0访问请求标志input wire m0_we_i, // 主设备0写标志// master 1 interfaceinput wire[`MemAddrBus] m1_addr_i, // 主设备1读、写地址input wire[`MemBus] m1_data_i, // 主设备1写数据output reg[`MemBus] m1_data_o, // 主设备1读取到的数据input wire m1_req_i, // 主设备1访问请求标志input wire m1_we_i, // 主设备1写标志// master 2 interfaceinput wire[`MemAddrBus] m2_addr_i, // 主设备2读、写地址input wire[`MemBus] m2_data_i, // 主设备2写数据output reg[`MemBus] m2_data_o, // 主设备2读取到的数据input wire m2_req_i, // 主设备2访问请求标志input wire m2_we_i, // 主设备2写标志// master 3 interfaceinput wire[`MemAddrBus] m3_addr_i, // 主设备3读、写地址input wire[`MemBus] m3_data_i, // 主设备3写数据output reg[`MemBus] m3_data_o, // 主设备3读取到的数据input wire m3_req_i, // 主设备3访问请求标志input wire m3_we_i, // 主设备3写标志// slave 0 interfaceoutput reg[`MemAddrBus] s0_addr_o, // 从设备0读、写地址output reg[`MemBus] s0_data_o, // 从设备0写数据input wire[`MemBus] s0_data_i, // 从设备0读取到的数据output reg s0_we_o, // 从设备0写标志// slave 1 interfaceoutput reg[`MemAddrBus] s1_addr_o, // 从设备1读、写地址output reg[`MemBus] s1_data_o, // 从设备1写数据input wire[`MemBus] s1_data_i, // 从设备1读取到的数据output reg s1_we_o, // 从设备1写标志// slave 2 interfaceoutput reg[`MemAddrBus] s2_addr_o, // 从设备2读、写地址output reg[`MemBus] s2_data_o, // 从设备2写数据input wire[`MemBus] s2_data_i, // 从设备2读取到的数据output reg s2_we_o, // 从设备2写标志// slave 3 interfaceoutput reg[`MemAddrBus] s3_addr_o, // 从设备3读、写地址output reg[`MemBus] s3_data_o, // 从设备3写数据input wire[`MemBus] s3_data_i, // 从设备3读取到的数据output reg s3_we_o, // 从设备3写标志// slave 4 interfaceoutput reg[`MemAddrBus] s4_addr_o, // 从设备4读、写地址output reg[`MemBus] s4_data_o, // 从设备4写数据input wire[`MemBus] s4_data_i, // 从设备4读取到的数据output reg s4_we_o, // 从设备4写标志// slave 5 interfaceoutput reg[`MemAddrBus] s5_addr_o, // 从设备5读、写地址output reg[`MemBus] s5_data_o, // 从设备5写数据input wire[`MemBus] s5_data_i, // 从设备5读取到的数据output reg s5_we_o, // 从设备5写标志output reg hold_flag_o // 暂停流水线标志);// 访问地址的最高4位决定要访问的是哪一个从设备// 因此最多支持16个从设备parameter [3:0]slave_0 = 4'b0000;parameter [3:0]slave_1 = 4'b0001;parameter [3:0]slave_2 = 4'b0010;parameter [3:0]slave_3 = 4'b0011;parameter [3:0]slave_4 = 4'b0100;parameter [3:0]slave_5 = 4'b0101;parameter [1:0]grant0 = 2'h0;parameter [1:0]grant1 = 2'h1;parameter [1:0]grant2 = 2'h2;parameter [1:0]grant3 = 2'h3;wire[3:0] req;reg[1:0] grant;// 主设备请求信号assign req = {m3_req_i, m2_req_i, m1_req_i, m0_req_i};// 仲裁逻辑// 固定优先级仲裁机制// 优先级由高到低:主设备3,主设备0,主设备2,主设备1always @ (*) beginif (req[3]) begingrant = grant3;hold_flag_o = `HoldEnable;end else if (req[0]) begingrant = grant0;hold_flag_o = `HoldEnable;end else if (req[2]) begingrant = grant2;hold_flag_o = `HoldEnable;end else begingrant = grant1;hold_flag_o = `HoldDisable;endend// 根据仲裁结果,选择(访问)对应的从设备always @ (*) beginm0_data_o = `ZeroWord;m1_data_o = `INST_NOP;m2_data_o = `ZeroWord;m3_data_o = `ZeroWord;s0_addr_o = `ZeroWord;s1_addr_o = `ZeroWord;s2_addr_o = `ZeroWord;s3_addr_o = `ZeroWord;s4_addr_o = `ZeroWord;s5_addr_o = `ZeroWord;s0_data_o = `ZeroWord;s1_data_o = `ZeroWord;s2_data_o = `ZeroWord;s3_data_o = `ZeroWord;s4_data_o = `ZeroWord;s5_data_o = `ZeroWord;s0_we_o = `WriteDisable;s1_we_o = `WriteDisable;s2_we_o = `WriteDisable;s3_we_o = `WriteDisable;s4_we_o = `WriteDisable;s5_we_o = `WriteDisable;case (grant)grant0: begincase (m0_addr_i[31:28])slave_0: begins0_we_o = m0_we_i;s0_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s0_data_o = m0_data_i;m0_data_o = s0_data_i;endslave_1: begins1_we_o = m0_we_i;s1_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s1_data_o = m0_data_i;m0_data_o = s1_data_i;endslave_2: begins2_we_o = m0_we_i;s2_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s2_data_o = m0_data_i;m0_data_o = s2_data_i;endslave_3: begins3_we_o = m0_we_i;s3_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s3_data_o = m0_data_i;m0_data_o = s3_data_i;endslave_4: begins4_we_o = m0_we_i;s4_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s4_data_o = m0_data_i;m0_data_o = s4_data_i;endslave_5: begins5_we_o = m0_we_i;s5_addr_o = {{4'h0}, {m0_addr_i[27:0]}};s5_data_o = m0_data_i;m0_data_o = s5_data_i;enddefault: beginendendcaseendgrant1: begincase (m1_addr_i[31:28])slave_0: begins0_we_o = m1_we_i;s0_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s0_data_o = m1_data_i;m1_data_o = s0_data_i;endslave_1: begins1_we_o = m1_we_i;s1_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s1_data_o = m1_data_i;m1_data_o = s1_data_i;endslave_2: begins2_we_o = m1_we_i;s2_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s2_data_o = m1_data_i;m1_data_o = s2_data_i;endslave_3: begins3_we_o = m1_we_i;s3_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s3_data_o = m1_data_i;m1_data_o = s3_data_i;endslave_4: begins4_we_o = m1_we_i;s4_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s4_data_o = m1_data_i;m1_data_o = s4_data_i;endslave_5: begins5_we_o = m1_we_i;s5_addr_o = {{4'h0}, {m1_addr_i[27:0]}};s5_data_o = m1_data_i;m1_data_o = s5_data_i;enddefault: beginendendcaseendgrant2: begincase (m2_addr_i[31:28])slave_0: begins0_we_o = m2_we_i;s0_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s0_data_o = m2_data_i;m2_data_o = s0_data_i;endslave_1: begins1_we_o = m2_we_i;s1_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s1_data_o = m2_data_i;m2_data_o = s1_data_i;endslave_2: begins2_we_o = m2_we_i;s2_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s2_data_o = m2_data_i;m2_data_o = s2_data_i;endslave_3: begins3_we_o = m2_we_i;s3_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s3_data_o = m2_data_i;m2_data_o = s3_data_i;endslave_4: begins4_we_o = m2_we_i;s4_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s4_data_o = m2_data_i;m2_data_o = s4_data_i;endslave_5: begins5_we_o = m2_we_i;s5_addr_o = {{4'h0}, {m2_addr_i[27:0]}};s5_data_o = m2_data_i;m2_data_o = s5_data_i;enddefault: beginendendcaseendgrant3: begincase (m3_addr_i[31:28])slave_0: begins0_we_o = m3_we_i;s0_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s0_data_o = m3_data_i;m3_data_o = s0_data_i;endslave_1: begins1_we_o = m3_we_i;s1_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s1_data_o = m3_data_i;m3_data_o = s1_data_i;endslave_2: begins2_we_o = m3_we_i;s2_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s2_data_o = m3_data_i;m3_data_o = s2_data_i;endslave_3: begins3_we_o = m3_we_i;s3_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s3_data_o = m3_data_i;m3_data_o = s3_data_i;endslave_4: begins4_we_o = m3_we_i;s4_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s4_data_o = m3_data_i;m3_data_o = s4_data_i;endslave_5: begins5_we_o = m3_we_i;s5_addr_o = {{4'h0}, {m3_addr_i[27:0]}};s5_data_o = m3_data_i;m3_data_o = s5_data_i;enddefault: beginendendcaseenddefault: beginendendcaseendendmodule
仿真验证部分
原理:利用官方提供的32位测试集进行比对,通过python 脚本进行批量化验证
tb 模块
module tb;reg clk;reg rst;wire x3 = tb.open_risc_v_inst.tinyriscv_inst.u_regs.regs[3];wire x26 = tb.open_risc_v_inst.tinyriscv_inst.u_regs.regs[26];wire x27 = tb.open_risc_v_inst.tinyriscv_inst.u_regs.regs[27];always #10 clk = ~clk;initial beginclk <= 1'b1;rst <= 1'b0;#30;rst <= 1'b1; end//rom 初始值initial begin$readmemh("./generated/inst_data.txt",tb.open_risc_v_inst.rom_inst.rom_mem);endinteger r;initial beginwait(x26 == 32'b1);#200;if(x27 == 32'b1) begin$display("############################");$display("######## pass !!!#########");$display("############################");endelse begin$display("############################");$display("######## fail !!!#########");$display("############################");$display("fail testnum = %2d", x3);for(r = 0;r < 31; r = r + 1)begin$display("x%2d register value is %d",r,tb.open_risc_v_inst.open_risc_v_inst.u_regs.regs[r]); end end$finish;endopen_risc_v open_risc_v_inst(.clk (clk),.rst (rst));endmodule
用python进行批量化验证
compile_and_sim.py 文件
import os
import subprocess
import sysdef list_binfiles(path):files = []list_dir = os.walk(path)for maindir, subdir, all_file in list_dir:for filename in all_file:apath = os.path.join(maindir, filename)if apath.endswith('.bin'):files.append(apath)return filesdef bin_to_mem(infile, outfile):binfile = open(infile, 'rb')binfile_content = binfile.read(os.path.getsize(infile))datafile = open(outfile, 'w')index = 0b0 = 0b1 = 0b2 = 0b3 = 0for b in binfile_content:if index == 0:b0 = bindex = index + 1elif index == 1:b1 = bindex = index + 1elif index == 2:b2 = bindex = index + 1elif index == 3:b3 = bindex = 0array = []array.append(b3)array.append(b2)array.append(b1)array.append(b0)datafile.write(bytearray(array).hex() + '\n')binfile.close()datafile.close()def compile():# 获取上一级目录rtl_dir = os.path.abspath(os.path.join(os.getcwd(), ".."))# iverilog 程序iverilog_cmd = ['iverilog']# 编译生成文件iverilog_cmd += ['-o', r'out.vvp']# 头文件(defines.v)路径iverilog_cmd += ['-I', rtl_dir + r'/rtl/cpu']# testbench 文件iverilog_cmd.append(rtl_dir + r'/tb/tb.v')# 内核coreiverilog_cmd.append(rtl_dir + r'/rtl/cpu/defines.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/pc_reg.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/if_id.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/id.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/id_ex.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/ex.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/regs.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/csr_reg.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/ctrl.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/div.v')iverilog_cmd.append(rtl_dir + r'/rtl/cpu/clint.v')# 通用utilsiverilog_cmd.append(rtl_dir + r'/rtl/cpu/dff_set.v')# 顶层cpuiverilog_cmd.append(rtl_dir + r'/rtl/cpu/tinyriscv.v')# 扩展外设iverilog_cmd.append(rtl_dir + r'/rtl/periphery/ram.v')# iverilog_cmd.append(rtl_dir + r'/cpu/rtl/ram.v')# iverilog_cmd.append(rtl_dir + r'/cpu/rtl/debug_button_debounce.v')# iverilog_cmd.append(rtl_dir + r'/cpu/rtl/uart_debug.v')# iverilog_cmd.append(rtl_dir + r'/utils/dual_ram.v')# 顶层sociverilog_cmd.append(rtl_dir + r'/tb/open_risc_v.v')# 编译process = subprocess.Popen(iverilog_cmd)process.wait(timeout=5)def sim():# 1.编译rtl文件compile()# 2.运行vvp_cmd = [r'vvp']vvp_cmd.append(r'out.vvp')process = subprocess.Popen(vvp_cmd)try:process.wait(timeout=10)except subprocess.TimeoutExpired:print('!!!Fail, vvp exec timeout!!!')def run(test_binfile):# 获取上一级路径rtl_dir = os.path.abspath(os.path.join(os.getcwd(), ".."))# 文件名字out_mem = rtl_dir + r'/sim/generated/inst_data.txt'# bin 转 membin_to_mem(test_binfile, out_mem)# 运行仿真sim()if __name__ == '__main__':sys.exit(run(sys.argv[1]))
test_all.py 文件
import os # 导入操作系统模块,用于处理文件和目录路径
import subprocess # 导入子进程模块,用于执行外部命令
import sys # 导入系统模块,用于处理命令行参数def list_binfiles(path):files = [] # 初始化一个空列表,用于存储.bin文件的路径list_dir = os.walk(path) # 使用os.walk遍历指定路径下的所有文件和目录for maindir, subdir, all_file in list_dir: # 遍历每个目录for filename in all_file: # 遍历每个文件apath = os.path.join(maindir, filename) # 构建文件的完整路径if apath.endswith('.bin'): # 判断文件是否以.bin结尾files.append(apath) # 如果是,则将其路径添加到列表中return files # 返回包含所有.bin文件路径的列表def main():# 获取上一级路径rtl_dir = os.path.abspath(os.path.join(os.getcwd(), ".."))# 获取路径下所有.bin文件all_bin_files = list_binfiles(rtl_dir + r'/sim/generated/')anyfail = False# 遍历所有.bin文件,逐个执行for file_bin in all_bin_files:# 构建执行命令,调用compile_and_sim.py脚本并传入.bin文件路径cmd = r'python compile_and_sim.py' + ' ' + file_bin# 使用os.popen执行命令,并获取输出结果f = os.popen(cmd)r = f.read() # 从文件路径中提取测试名称(假设文件路径中包含'-p-'作为分隔符)index = file_bin.index('-p-')print_name = file_bin[index+3:-4]# 关闭文件对象f.close()# 判断输出结果中是否包含'pass',并输出相应的测试结果if (r.find('pass') != -1):print('指令 ' + print_name.ljust(10, ' ') + ' PASS')else:print('指令 ' + print_name.ljust(10, ' ') + ' !!!FAIL!!!')anyfail = Trueif (anyfail == False):print('Congratulation, All PASS...')if __name__ == '__main__':main() # 如果脚本作为主程序运行,则调用main函数
test_one_inst.py 文件
import os
import sys
import subprocess
from compile_and_sim import list_binfiles, bin_to_mem, sim # 明确导入所需的函数# 主函数
def main(name, run_waveform=False):# 获取上一级路径rtl_dir = os.path.abspath(os.path.join(os.getcwd(), ".."))# 定义.bin文件路径bin_dir = os.path.join(rtl_dir, 'sim', 'generated')all_bin_files = list_binfiles(bin_dir)# 查找指定名称的.bin文件test_binfile = next((file for file in all_bin_files if name in file and file.endswith('.bin')), None)if test_binfile is None:raise FileNotFoundError(f"未找到名为 {name} 的 .bin 文件")# 定义输出文件路径out_mem = os.path.join(bin_dir, 'inst_data.txt')# 将.bin文件转换为内存格式bin_to_mem(test_binfile, out_mem)# 运行仿真sim()# 获取波形if run_waveform:gtkwave_cmd = ['gtkwave', 'wavets.vcd']process = subprocess.Popen(gtkwave_cmd)print(f"正在使用 gtkwave 打开波形文件: {gtkwave_cmd[1]}")# 程序入口
if __name__ == '__main__':args = sys.argv[1:]if len(args) < 1:print("必须提供至少一个参数(指令名称)。")sys.exit(1)elif len(args) > 2:print("最多提供两个参数(指令名称和run)。")sys.exit(1)else:run_waveform = args[1].lower() == 'run' if len(args) == 2 else Falsesys.exit(main(args[0], run_waveform))
使用方法
python test_all.py //运行所有测试用例
python test_one_inst.py fence_i //运行fence_i测试用例
python test_one_inst.py fence_i run //运行fence_i测试用例并调出仿真窗口(注意需要下载配置gtkwave 安装链接为Icarus Verilog与GTKWave简介及其下载安装_gtkwave如何下载-CSDN博客)
使用示例
运行 python test_one_inst.py fence_i