赞
踩
分享一个GPU服务器租赁平台(价格十分优惠,有4090,3090,A6000等)
参考《自己动手写CPU》这本书,这本书算是手把手教学写CPU,比较适合初学者。这里完成五级流水结构的处理器,实现70条左右的指令,基本实现全部整数指令,开发工具是Vivado。
设计的处理器是五级流水处理器,取指,译码,执行,访存,回写。
(1)取指: 取出指令存储器中的指令,PC值递增,准备取下一条指令。
(2)译码:对指令进行译码,依据译码结果,从32个通用寄存器中取出源操作数,有的 指令要求两个源操作数都是寄存器的值,比如or指令,有的指令要求其中一 个源操作数是指令中立即数的扩展,比如ori指令,所以这里有两个复用器, 用于依据指令要求,确定参与运算的操作数,最终确定的两个操作数会送到执 行阶段。
(3)执行:依据译码阶段送入的源操作数、操作码,进行运算,对于ori指令而言, 就是进行逻辑“或”运算,运算结果传递到访存阶段。
(4)访存:对于ori指令,在访存阶段没有任何操作,直接将运算结果向下传递到回写阶 段。
(5)回写:将运算结果保存到目的寄存器。
指令执行周期
指令类别 | 指令名 | 周期 |
---|---|---|
除法指令 | div,divu | 36 |
乘累加指令 | madd,maddu | 2 |
乘累减指令 | msub,msubu | 2 |
其余指令 | … | 1 |
(1)取指阶段
PC模块;给出指令地址,其中实现指令指针寄存器PC,该寄存器的值就是指令地址,
对应 pc_reg.v文件。
IF/ID模块:实现取指与译码阶段之间的寄存器,将取指阶段的结果(取得的指令、 指令地址等信息)在下一个时钟传递到译码阶段,对应if_id.v文件。
(2)译码阶段
ID模块:对指令进行译码,译码结果包括运算类型、运算所需的源操作数、要 写入的目的寄存器地址等,对应 idv文件。
Regfile模块:实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操 作和一个寄存器的写操作,对应Regfile.v文件。
ID/EX模块:实现译码与执行阶段之间的寄存器,将译码阶段的结果在下一个时钟周 期传递到执行阶段,对应 id_ex.v。
(3)执行阶段
EX模块:依据译码阶段的结果,进行指定的运算,给出运算结果。对应.ex.v文件。 DIV模块:进行除法运算的模块,对应 div.v文件。
EX/MEM 模块:实现执行与访存阶段之间的寄存器,将执行阶段的结果在下一个时 钟周期传递到访存阶段,对应 ex_mem.v文件。
(4)访存阶段
MEM模块:如果是加载、存储指令,那么会对数据存储器进行访问。此外,还会在 该模块进行异常判断。对应mem.v文件。
MEM/WB模块:实现访存与回写阶段之间的寄存器,将访存阶段的结果在下一个时 钟周期传递到回写阶段,对应mem_wb.v文件。
(5)回写阶段
HILO模块:实现寄存器 HI、LO,在乘法、除法指令的处理过程中会使用到这两个 寄存器。
1.ctrl 模块定义
2.data_ram模块定义
3.div模块定义
4.ex模块定义
5.ex_mem模块定义
6.hilo_reg模块定义
7.id模块定义
8.id_ex模块定义
9.if_id模块定义
10.inst_rom模块定义
11.mem模块定义
12.mem_wb模块定义
13.openmips模块定义
14.openmips_min_sopc模块定义
15.pc_reg模块定义
16.Regfile模块定义
逻辑以及移位指令操作过程
逻辑以及移位指令结构图
逻辑以及移位指令数据流图
移动指令操作过程
移动指令结构图
移动指令数据流图
算术指令数据流图
除法状态转换图
试除法流程图
暂停流水结构图
转移指令操作过程
转移指令结构图
转移指令数据流图
加载存储指令结构图
加载存储指令数据流图
`include"defines.v" module pc_reg( input wire clk, input wire rst, input wire[5:0] stall,//来自控制模块的ctrl input wire branch_flag_i, input wire[`RegBus] branch_target_address_i, output reg[`InstAddrBus] pc, output reg ce ); always @ (posedge clk)begin if (rst == `RstEnable)begin ce <= `ChipDisable; end else begin ce <= `ChipEnable; end end always @ (posedge clk) begin if (ce == `ChipDisable) begin pc <= 32'h0;// end else if(stall[0] == `NoStop) begin if(branch_flag_i == `Branch)begin pc <= branch_target_address_i; end else begin pc <= pc + 4'h4; end end end endmodule
`include"defines.v" module if_id( input wire clk, input wire rst, input wire[5:0] stall, // 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32 input wire[`InstAddrBus] if_pc, input wire[`InstBus] if_inst, //对应译码阶段的信号 output reg[`InstAddrBus] id_pc, output reg[`InstBus] id_inst ); always @ (posedge clk)begin if(rst == `RstEnable) begin id_pc <= `ZeroWord; // 复位的时候pc为0 id_inst <= `ZeroWord;// 复位的时候指令也为0.实际就是空指令 end else if(stall[1] == `Stop && stall[2] == `NoStop) begin id_pc <= `ZeroWord; id_inst <= `ZeroWord; end else if(stall[1] == `NoStop) begin id_pc <= if_pc; //其余时刻向下传递取指令阶段的值 id_inst <= if_inst; end end endmodule
`include"defines.v" module Regfile( input wire clk, input wire rst, //写端口 input wire we, input wire[`RegAddrBus] waddr, input wire[`RegBus] wdata, //读端口 input wire re1, input wire[`RegAddrBus]raddr1, output reg[`RegBus] rdata1, //读端口 input wire re2, input wire[`RegAddrBus] raddr2, output reg[`RegBus] rdata2 ); /********************************************** 第一段 : 定义32个32位寄存器 *************************/ reg[`RegBus] regs[0:`RegNum-1]; /********************************************** 第二段 : 写操作 *************************/ always @ (posedge clk) begin if (rst == `RstDisable)begin if((we == `WriteEnable) && (waddr != `RegNumLog2'h0))begin regs[waddr] <= wdata; end end end /********************************************** 第三段 : 读端口1的读操作 **************************/ always @ (*) begin if(rst == `RstEnable)begin rdata1 <= `ZeroWord; end else if(raddr1 == `RegNumLog2'h0)begin rdata1 <= `ZeroWord; end else if((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin rdata1 <= wdata; end else if(re1 == `ReadEnable)begin rdata1 <= regs[raddr1]; end else begin rdata1 <= `ZeroWord; end end /********************************************** 第四段 : 读端口2的读操作 ***************************/ always @ (*) begin if(rst == `RstEnable) begin rdata2 <= `ZeroWord; end else if(raddr2 == `RegNumLog2'h0)begin rdata2 <= `ZeroWord; end else if((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable))begin rdata2 <= wdata; end else if(re2 == `ReadEnable)begin rdata2 <= regs[raddr2]; end else begin rdata2 <= `ZeroWord; end end endmodule
include"defines.v" module if_id( input wire clk, input wire rst, input wire[5:0] stall, // 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32 input wire[`InstAddrBus] if_pc, input wire[`InstBus] if_inst, //对应译码阶段的信号 output reg[`InstAddrBus] id_pc, output reg[`InstBus] id_inst ); always @ (posedge clk)begin if(rst == `RstEnable) begin id_pc <= `ZeroWord; // 复位的时候pc为0 id_inst <= `ZeroWord;// 复位的时候指令也为0.实际就是空指令 end else if(stall[1] == `Stop && stall[2] == `NoStop) begin id_pc <= `ZeroWord; id_inst <= `ZeroWord; end else if(stall[1] == `NoStop) begin id_pc <= if_pc; //其余时刻向下传递取指令阶段的值 id_inst <= if_inst; end end endmodule
`include"defines.v" module id( input wire rst, input wire[`InstAddrBus] pc_i, input wire[`InstBus] inst_i, // 时延 input wire is_in_delayslot_i, // 读取的RegFile的值 input wire[`RegBus] reg1_data_i, input wire[`RegBus] reg2_data_i, //输出到Regfile的信息 output reg reg1_read_0, output reg reg2_read_0, output reg[`RegAddrBus] reg1_addr_0, output reg[`RegAddrBus] reg2_addr_0, //处于执行阶段的指令的运算结果 input wire ex_wreg_i, input wire[`RegBus] ex_wdata_i, input wire[`RegAddrBus] ex_wd_i, //处于访存阶段的指令的运算结果 input wire mem_wreg_i, input wire[`RegBus] mem_wdata_i, input wire[`RegAddrBus] mem_wd_i, // 分支时延 output reg next_inst_in_delayslot_0, output reg branch_flag_0, output reg[`RegBus] branch_target_address_0, output reg[`RegBus] link_addr_0, output reg is_in_delayslot_0, //送到执行阶段的信息 output reg[`AluOpBus] aluop_0, output reg[`AluSelBus] alusel_0, output reg[`RegBus] reg1_0, output reg[`RegBus] reg2_0, output reg[`RegAddrBus]wd_0, output reg wreg_0, output wire stallreq, output wire[`RegBus] inst_0 ); //取指令的指令码,功能码 wire[5:0] op = inst_i[31:26]; wire[4:0] op2 = inst_i[10:6]; wire[5:0] op3 = inst_i[5:0]; wire[4:0] op4 = inst_i[20:16]; wire[`RegBus] pc_plus_8; wire[`RegBus] pc_plus_4; wire[`RegBus] imm_sll2_signedext; //指示指令是否有效 reg instvalid; //保存指令执行需要的立即数 reg[`RegBus] imm; assign pc_plus_8 = pc_i + 8; assign pc_plus_4 = pc_i + 4; //对应分支指令中的offset左移两位,再符号拓展到32位 assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0],2'b00}; assign stallreq = `NoStop; assign inst_0 = inst_i; // inst_0的值就是译码阶段的指令 /************************** 第一段: 对指令进行译码 **************************************/ always @ (*) begin if(rst == `RstEnable) begin aluop_0 <= `EXE_NOP_OP; alusel_0 <= `EXE_RES_NOP; wd_0 <= `NOPRegAddr; wreg_0 <= `WriteDisable; instvalid <= `InstValid; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; reg1_addr_0 <= `NOPRegAddr; reg2_addr_0 <= `NOPRegAddr; imm <= 32'h0; link_addr_0 <= `ZeroWord; branch_target_address_0 <= `ZeroWord; branch_flag_0 <= `NotBranch; next_inst_in_delayslot_0 <= `NotInDelaySlot; end else begin aluop_0 <= `EXE_NOP_OP; alusel_0 <= `EXE_RES_NOP; wd_0 <= inst_i[15:11]; wreg_0 <= `WriteDisable; instvalid <= `InstInvalid; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; reg1_addr_0 <= inst_i[25:21]; // 默认通过 Regfile 读端口1读取的寄存器地址 reg2_addr_0 <= inst_i[20:16]; // 默认通过 Regfile 读端口2读取的寄存器地址 imm <= `ZeroWord; link_addr_0 <= `ZeroWord; branch_target_address_0 <= `ZeroWord; branch_flag_0 <= `NotBranch; next_inst_in_delayslot_0 <= `NotInDelaySlot; case(op) `EXE_SPECIAL_INST:begin case(op2) 5'b00000:begin case(op3) `EXE_OR:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_OR_OP; alusel_0 <= `EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_AND:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_AND_OP; alusel_0 <= `EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_XOR:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_XOR_OP; alusel_0 <= `EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_NOR:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_NOR_OP; alusel_0 <= `EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_DIV:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_DIV_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_DIVU:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_DIVU_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_JR:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_JR_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; link_addr_0 <= `ZeroWord; branch_target_address_0 <= reg1_0; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; instvalid <= `InstValid; end `EXE_JALR:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_JALR_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[15:11]; link_addr_0 <= pc_plus_8; branch_target_address_0 <= reg1_0; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; instvalid <= `InstValid; end `EXE_SLLV:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SLL_OP; alusel_0 <= `EXE_RES_SHIFT; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SRLV:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SRL_OP; alusel_0 <= `EXE_RES_SHIFT; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SRAV:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SRA_OP; alusel_0 <= `EXE_RES_SHIFT; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SYNC:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_NOP_OP; alusel_0 <= `EXE_RES_NOP; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MFHI:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MFHI_OP; alusel_0 <= `EXE_RES_MOVE; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_MFLO:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MFLO_OP; alusel_0 <= `EXE_RES_MOVE; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_MTHI:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MTHI_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_MTLO:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MTLO_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_MOVN:begin aluop_0 <= `EXE_MOVN_OP; alusel_0 <= `EXE_RES_MOVE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; if(reg2_0!=`ZeroWord)begin wreg_0 <= `WriteEnable; end else begin wreg_0 <= `WriteDisable; end end `EXE_MOVZ:begin aluop_0 <= `EXE_MOVZ_OP; alusel_0 <= `EXE_RES_MOVE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; if(reg2_0==`ZeroWord)begin wreg_0 <= `WriteEnable; end else begin wreg_0 <= `WriteDisable; end end `EXE_SLT:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SLT_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SLTU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SLTU_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_ADD:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_ADD_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_ADDU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_ADDU_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SUB:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SUB_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SUBU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SUBU_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MULT:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MULT_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MULTU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MULTU_OP; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end default:begin end endcase end default:begin end endcase end `EXE_J:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_J_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; link_addr_0 <= `ZeroWord; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; instvalid <= `InstValid; branch_target_address_0 <= {pc_plus_4[31:28],inst_i[25:0],2'b00}; end `EXE_JAL:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_JAL_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; wd_0 <= 5'b11111; link_addr_0 <= pc_plus_8; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; instvalid <= `InstValid; branch_target_address_0 <= {pc_plus_4[31:28],inst_i[25:0],2'b00}; end `EXE_BEQ:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BEQ_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; if(reg1_0 == reg2_0)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BGTZ:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BGTZ_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; if((reg1_0[31] == 1'b0) && (reg1_0 != `ZeroWord))begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BLEZ:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BLEZ_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; if((reg1_0[31] == 1'b1) || (reg1_0 == `ZeroWord))begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BNE:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BLEZ_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; if(reg1_0 != reg2_0)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_REGIMM_INST:begin case(op4) `EXE_BGEZ:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BGEZ_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; if(reg1_0[31] == 1'b0)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BGEZAL:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_BGEZAL_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; link_addr_0 <= pc_plus_8; wd_0 <= 5'b11111; instvalid <= `InstValid; if(reg1_0[31] == 1'b0)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BLTZ:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_BGEZAL_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; if(reg1_0[31] == 1'b1)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end `EXE_BLTZAL:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_BGEZAL_OP; alusel_0 <= `EXE_RES_JUMP_BRANCH; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; link_addr_0 <= pc_plus_8; wd_0 <= 5'b11111; instvalid <= `InstValid; if(reg1_0[31] == 1'b1)begin branch_target_address_0 <= pc_plus_4 + imm_sll2_signedext; branch_flag_0 <= `Branch; next_inst_in_delayslot_0 <= `InDelaySlot; end end default:begin end endcase end `EXE_LB: begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LB_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LBU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LBU_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LH:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LH_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LHU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LHU_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LW:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LW_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LWL:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LWL_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LWR:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_LWR_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_SB:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_SB_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SH:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_SH_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SW:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_SW_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SWL:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_SWL_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_SWR:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_SWR_OP; alusel_0 <= `EXE_RES_LOAD_STORE; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_ORI:begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_OR_OP; alusel_0 <=`EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {16'h0,inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ANDI:begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_AND_OP; alusel_0 <=`EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {16'h0,inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_XORI:begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_XOR_OP; alusel_0 <=`EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {16'h0,inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LUI:begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_OR_OP; alusel_0 <=`EXE_RES_LOGIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {inst_i[15:0],16'h0}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_PREF:begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_NOP_OP; alusel_0 <=`EXE_RES_NOP; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_SLTI:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SLT_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_SLTIU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_SLTU_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ADDI:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_ADDI_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ADDIU:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_ADDIU_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_0 <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_SPECIAL2_INST:begin case(op3) `EXE_CLZ:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_CLZ_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_CLO:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_CLO_OP; alusel_0 <= `EXE_RES_ARITHMETIC; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b0; instvalid <= `InstValid; end `EXE_MUL:begin wreg_0 <= `WriteEnable; aluop_0 <= `EXE_MUL_OP; alusel_0 <= `EXE_RES_MUL; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MADD:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_MADD_OP; alusel_0 <= `EXE_RES_MUL; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MADDU:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_MADDU_OP; alusel_0 <= `EXE_RES_MUL; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MSUB:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_MSUB_OP; alusel_0 <= `EXE_RES_MUL; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end `EXE_MSUBU:begin wreg_0 <= `WriteDisable; aluop_0 <= `EXE_MSUBU_OP; alusel_0 <= `EXE_RES_MUL; reg1_read_0 <= 1'b1; reg2_read_0 <= 1'b1; instvalid <= `InstValid; end default:begin end endcase end default:begin end endcase if(inst_i[31:21] == 11'b00000000000)begin if(op3 == `EXE_SLL)begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_SLL_OP; alusel_0 <=`EXE_RES_SHIFT; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_0 <= inst_i[15:11]; instvalid <= `InstValid; end else if(op3 == `EXE_SRL) begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_SRL_OP; alusel_0 <=`EXE_RES_SHIFT; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_0 <= inst_i[15:11]; instvalid <= `InstValid; end else if(op3 == `EXE_SRA) begin wreg_0 <=`WriteEnable; aluop_0 <=`EXE_SRA_OP; alusel_0 <=`EXE_RES_SHIFT; reg1_read_0 <= 1'b0; reg2_read_0 <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_0 <= inst_i[15:11]; instvalid <= `InstValid; end end end end /**************************** 第二段: 确定进行运算的源操作数 1**************************/ always @ (*) begin if(rst == `RstEnable) begin reg1_0 <= `ZeroWord; end else if((reg1_read_0 == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_0))begin reg1_0 <= ex_wdata_i; end else if((reg1_read_0 == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_0))begin reg1_0 <= mem_wdata_i; end else if(reg1_read_0 == 1'b1) begin reg1_0 <= reg1_data_i; //Regfile 读端口1的输出值 end else if(reg1_read_0 == 1'b0) begin reg1_0 <= imm; end else begin reg1_0 <= `ZeroWord; end end /************************** 第三段:确定进行运算的源操作数2 ***********************************/ always @ (*) begin if(rst == `RstEnable)begin reg2_0 <= `ZeroWord; end else if((reg2_read_0 == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_0))begin reg2_0 <= ex_wdata_i; end else if((reg2_read_0 == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_0))begin reg2_0 <= mem_wdata_i; end else if(reg2_read_0 == 1'b1) begin reg2_0 <= reg2_data_i;//Regfile 读端口2的输出值 end else if(reg2_read_0 == 1'b0) begin reg2_0 <= imm; end else begin reg2_0 <= `ZeroWord; end end always @ (*) begin if(rst == `RstEnable)begin is_in_delayslot_0 <= `NotInDelaySlot; end else begin is_in_delayslot_0 <= is_in_delayslot_i; end end Endmodule
include"defines.v" module id_ex( input wire clk, input wire rst, input wire[5:0] stall, //从译码阶段传递过来的信息 input wire[`AluOpBus] id_aluop, input wire[`AluSelBus] id_alusel, input wire[`RegBus] id_reg1, input wire[`RegBus] id_reg2, input wire[`RegAddrBus] id_wd, input wire id_wreg, //跳转时延 input wire[`RegBus] id_link_address, input id_is_in_delayslot, input wire next_inst_in_delayslot_i, //load input wire[`RegBus] id_inst, //传递到执行阶段的信息 output reg[`AluOpBus] ex_aluop, output reg[`AluSelBus] ex_alusel, output reg[`RegBus] ex_reg1, output reg[`RegBus] ex_reg2, output reg[`RegAddrBus] ex_wd, output reg ex_wreg , //跳转时延 output reg[`RegBus] ex_link_address, output reg ex_is_in_delayslot, output reg is_in_delayslot_0, //load output reg[`RegBus] ex_inst ); always @ (posedge clk) begin if(rst == `RstEnable) begin ex_aluop <= `EXE_NOP_OP; ex_alusel <= `EXE_RES_NOP; ex_reg1 <= `ZeroWord; ex_reg2 <= `ZeroWord; ex_wd <= `NOPRegAddr; ex_wreg <= `WriteDisable; ex_link_address <= `ZeroWord; ex_is_in_delayslot <= `NotInDelaySlot; is_in_delayslot_0 <=`NotInDelaySlot; ex_inst <= `ZeroWord; end else if(stall[2] == `Stop && stall[3] == `NoStop) begin ex_aluop <= `EXE_NOP_OP; ex_alusel <= `EXE_RES_NOP; ex_reg1 <= `ZeroWord; ex_reg2 <= `ZeroWord; ex_wd <= `NOPRegAddr; ex_wreg <= `WriteDisable; ex_link_address <= `ZeroWord; ex_is_in_delayslot <= `NotInDelaySlot; ex_inst <= `ZeroWord; end else if(stall[2] == `NoStop)begin ex_aluop <= id_aluop; ex_alusel <= id_alusel; ex_reg1 <= id_reg1; ex_reg2 <= id_reg2; ex_wd <= id_wd; ex_wreg <= id_wreg; ex_link_address <= id_link_address; ex_is_in_delayslot <= id_is_in_delayslot; is_in_delayslot_0 <= next_inst_in_delayslot_i; ex_inst <= id_inst; end end Endmodule
`include"defines.v" module ex( input wire rst, // 译码阶段送到执行阶段的信息 input wire[`AluOpBus] aluop_i, input wire[`AluSelBus] alusel_i, input wire[`RegBus] reg1_i, input wire[`RegBus] reg2_i, input wire[`RegAddrBus] wd_i, input wire wreg_i, // 执行的结果 output reg[`RegAddrBus] wd_0, output reg wreg_0, output reg[`RegBus] wdata_0, // HILO 模块给出的HI,LO 寄存器的值 input wire[`RegBus] hi_i, input wire[`RegBus] lo_i, // 回写阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关问题 input wire[`RegBus] wb_hi_i, input wire[`RegBus] wb_lo_i, input wire wb_whilo_i, //访存阶段的指令是否要写 HI,LO,用于检测HI,LO寄存器带来的数据相关问题 input wire[`RegBus] mem_hi_i, input wire[`RegBus] mem_lo_i, input wire mem_whilo_i, input wire[`DoubleRegBus] hilo_temp_i, input wire[1:0] cnt_i, //来自除法模块的输入 input wire[`DoubleRegBus] div_result_i, input wire div_ready_i, //tiaozhuan input wire[`RegBus] link_address_i, input wire is_in_delayslot_i, //load input wire[`RegBus] inst_i, output reg[`DoubleRegBus] hilo_temp_0, output reg[1:0] cnt_0, //处于执行阶段的指令对HI,LO寄存器的写操作请求 output reg[`RegBus] hi_0, output reg[`RegBus] lo_0, output reg whilo_0, //到除法模块的输出 output reg[`RegBus] div_opdata1_0, output reg[`RegBus] div_opdata2_0, output reg div_start_0, output reg signed_div_0, output reg stallreq, //load output wire[`AluOpBus] aluop_0, output wire[`RegBus] mem_addr_0, output wire[`RegBus] reg2_0 ); //保存逻辑运算的结果 reg[`RegBus] logicout; //保存移位运算结果 reg[`RegBus] shiftres; //移动操作的结果 reg[`RegBus] moveres; //保存HI寄存器的最新值 reg[`RegBus] HI; //保存LO寄存器的最新值 reg[`RegBus] LO; //送到访存阶段 wire ov_sum; //保存溢出情况 wire reg1_eq_reg2;//第一个操作数是否等于第二个操作数 wire reg1_lt_reg2;//第一个操作数是否小于第二个操作数 reg[`RegBus] arithmeticres;//保存算术运算的结果 wire[`RegBus] reg2_i_mux;//保存输入的第二个操作数reg2_i的补码 wire[`RegBus] reg1_i_not;//保存输入的第一个操作数reg1_i取反后的值 wire[`RegBus] result_sum;//保存加法结果 wire[`RegBus] opdata1_mult;//乘法操作中的被乘数 wire[`RegBus] opdata2_mult;//乘法操作中的乘数 wire[`DoubleRegBus] hilo_temp; // 临时保存乘法结果,宽度为64位 reg[`DoubleRegBus] hilo_temp1; reg[`DoubleRegBus] mulres;//保存乘法结果,宽度为64位 reg stallreq_for_madd_msub; reg stallreq_for_div;//是否由于除法运算导致流水线暂停 assign aluop_0 = aluop_i; assign mem_addr_0 = reg1_i + {{16{inst_i[15]}},inst_i[15:0]}; assign reg2_0 = reg2_i; assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) || (aluop_i == `EXE_SLT_OP)) ? (~reg2_i) + 1 : reg2_i; assign result_sum = reg1_i + reg2_i_mux; assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31])); assign reg1_it_reg2 = ((aluop_i == `EXE_SLT_OP))?((reg1_i[31] && !reg2_i[31]) || (!reg1_i[31] && !reg2_i[31] && result_sum[31]) || (reg1_i[31] && reg2_i[31] && result_sum[31])):(reg1_i < reg2_i); assign reg1_i_not = ~reg1_i; always @ (*) begin if(rst == `RstEnable) begin arithmeticres <= `ZeroWord; end else begin case(aluop_i) `EXE_SLT_OP,`EXE_SLTU_OP:begin arithmeticres <= reg1_it_reg2; end `EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:begin arithmeticres<=result_sum; end `EXE_SUB_OP,`EXE_SUBU_OP:begin arithmeticres <= result_sum; end `EXE_CLZ_OP:begin arithmeticres <= reg1_i[31] ? 0:reg1_i[30] ? 1: reg1_i[29] ? 2:reg1_i[28] ? 3: reg1_i[27] ? 4:reg1_i[26] ? 5: reg1_i[25] ? 6:reg1_i[24] ? 7: reg1_i[23] ? 8:reg1_i[22] ? 9: reg1_i[21] ? 10:reg1_i[20] ? 11: reg1_i[19] ? 12:reg1_i[18] ? 13: reg1_i[17] ? 14:reg1_i[16] ? 15: reg1_i[15] ? 16:reg1_i[14] ? 17: reg1_i[13] ? 18:reg1_i[12] ? 19: reg1_i[11] ? 20:reg1_i[10] ? 21: reg1_i[9] ? 22:reg1_i[8] ? 23: reg1_i[7] ? 24:reg1_i[6] ? 25: reg1_i[5] ? 26:reg1_i[4] ? 27: reg1_i[3] ? 28:reg1_i[2] ? 29: reg1_i[1] ? 30:reg1_i[0] ? 31: 32; end `EXE_CLO_OP:begin arithmeticres <= (reg1_i_not[31] ? 0:reg1_i_not[30] ? 1: reg1_i_not[29] ? 2:reg1_i_not[28] ? 3: reg1_i_not[27] ? 4:reg1_i_not[26] ? 5: reg1_i_not[25] ? 6:reg1_i_not[24] ? 7: reg1_i_not[23] ? 8:reg1_i_not[22] ? 9: reg1_i_not[21] ? 10:reg1_i_not[20] ? 11: reg1_i_not[19] ? 12:reg1_i_not[18] ? 13: reg1_i_not[17] ? 14:reg1_i_not[16] ? 15: reg1_i_not[15] ? 16:reg1_i_not[14] ? 17: reg1_i_not[13] ? 18:reg1_i_not[12] ? 19: reg1_i_not[11] ? 20:reg1_i_not[10] ? 21: reg1_i_not[9] ? 22:reg1_i_not[8] ? 23: reg1_i_not[7] ? 24:reg1_i_not[6] ? 25: reg1_i_not[5] ? 26:reg1_i_not[4] ? 27: reg1_i_not[3] ? 28:reg1_i_not[2] ? 29: reg1_i_not[1] ? 30:reg1_i_not[0] ? 31: 32); end default:begin arithmeticres <= `ZeroWord; end endcase end end //乘法运算 assign opdata1_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg1_i[31] == 1'b1)) ? (~reg1_i + 1) : reg1_i; assign opdata2_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg2_i[31] == 1'b1)) ? (~reg2_i + 1) : reg2_i; assign hilo_temp = opdata1_mult * opdata2_mult; always @ (*) begin if(rst == `RstEnable) begin mulres <= {`ZeroWord,`ZeroWord}; end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i ==`EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) begin if(reg1_i[31]^reg2_i[31] == 1'b1) begin mulres <= ~hilo_temp + 1; end else begin mulres <= hilo_temp; end end else begin mulres <= hilo_temp; end end always @ (*) begin if(rst == `RstEnable)begin {HI,LO} <= {`ZeroWord,`ZeroWord}; end else if(mem_whilo_i == `WriteEnable) begin {HI,LO} <= {mem_hi_i,mem_lo_i}; end else if(wb_whilo_i == `WriteEnable) begin {HI,LO} <= {wb_hi_i,wb_lo_i}; end else begin {HI,LO} <= {hi_i,lo_i}; end end always @ (*) begin if(rst == `RstEnable) begin moveres <= `ZeroWord; end else begin moveres <= `ZeroWord; case(aluop_i) `EXE_MFHI_OP:begin moveres <= HI; end `EXE_MFLO_OP:begin moveres <= LO; end `EXE_MOVZ_OP:begin moveres <= reg1_i; end `EXE_MOVN_OP:begin moveres <= reg1_i; end default:begin end endcase end end /********************************** 第一段:依据aluop_i指示的运算子类型进行运算 **************************************/ always @ (*) begin if(rst == `RstEnable)begin logicout <= `ZeroWord; end else begin case (aluop_i) `EXE_OR_OP:begin logicout <= reg1_i | reg2_i; end `EXE_AND_OP:begin logicout <= reg1_i & reg2_i; end `EXE_NOR_OP:begin logicout <= ~(reg1_i | reg2_i); end `EXE_XOR_OP:begin logicout <= reg1_i ^ reg2_i; end default:begin logicout <= `ZeroWord; end endcase end end // 进行移位运算 always @ (*) begin if(rst == `RstEnable) begin shiftres <= `ZeroWord; end else begin case (aluop_i) `EXE_SLL_OP:begin shiftres <= reg2_i << reg1_i[4:0]; end `EXE_SRL_OP:begin shiftres <= reg2_i >> reg1_i[4:0]; end `EXE_SRA_OP:begin shiftres <= ({32{reg2_i[31]}} << (6'd32 - {1'b0,reg1_i[4:0]})) | reg2_i >> reg1_i[4:0]; end default:begin shiftres <= `ZeroWord; end endcase end end /****************************************** 第二段 :依据aluse1_i指示的运算类型,选择一个运算结果作为最终结果 *************/ always @ (*) begin wd_0 <= wd_i; // wd_0 等于wd_i,要写的目的寄存器地址 if(((aluop_i == `EXE_ADD_OP) || (aluop_i==`EXE_ADDI_OP) || (aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin wreg_0 <= `WriteDisable; end else begin wreg_0 <= wreg_i; end case(alusel_i) `EXE_RES_LOGIC: begin wdata_0 <= logicout; // wdata_0中存放运算结果 end `EXE_RES_SHIFT:begin wdata_0 <= shiftres; end `EXE_RES_MOVE:begin wdata_0 <= moveres; end `EXE_RES_ARITHMETIC:begin wdata_0 <= arithmeticres; end `EXE_RES_MUL:begin wdata_0 <= mulres[31:0]; end `EXE_RES_JUMP_BRANCH:begin wdata_0<= link_address_i; end default: begin wdata_0 <= `ZeroWord; end endcase end always @ (*) begin if( rst == `RstEnable)begin hilo_temp_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b00; stallreq_for_madd_msub <= `NoStop; end else begin case (aluop_i) `EXE_MADD_OP,`EXE_MADDU_OP:begin if(cnt_i == 2'b00) begin hilo_temp_0 <= mulres; cnt_0 <= 2'b01; hilo_temp1 <= {`ZeroWord,`ZeroWord}; stallreq_for_madd_msub <= `Stop; end else if(cnt_i == 2'b01)begin hilo_temp_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b10; hilo_temp1 <= hilo_temp_i + {HI,LO}; stallreq_for_madd_msub<= `NoStop; end end `EXE_MSUB_OP,`EXE_MSUBU_OP:begin if(cnt_i == 2'b00)begin hilo_temp_0 <= ~mulres + 1; cnt_0 <= 2'b01; stallreq_for_madd_msub <= `Stop; end else if(cnt_i == 2'b01)begin hilo_temp_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b10; hilo_temp1 <= hilo_temp_i + {HI,LO}; stallreq_for_madd_msub <= `NoStop; end end default:begin hilo_temp_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b00; stallreq_for_madd_msub <= `NoStop; end endcase end end //除法运算 always @ (*)begin if(rst == `RstEnable)begin stallreq_for_div <= `NoStop; div_opdata1_0 <= `ZeroWord; div_opdata2_0 <= `ZeroWord; div_start_0 <= `DivStop; signed_div_0 <= 1'b0;//singed_div_0 end else begin stallreq_for_div <= `NoStop; div_opdata1_0 <= `ZeroWord; div_opdata2_0 <= `ZeroWord; div_start_0 <= `DivStop; signed_div_0 <= 1'b0; case(aluop_i) `EXE_DIV_OP:begin if(div_ready_i == `DivResultNotReady) begin div_opdata1_0 <= reg1_i; div_opdata2_0 <= reg2_i; div_start_0 <= `DivStart; signed_div_0 <= 1'b1; stallreq_for_div <= `Stop; end else if(div_ready_i == `DivResultReady) begin div_opdata1_0 <= reg1_i; div_opdata2_0 <= reg2_i; div_start_0 <= `DivStop; signed_div_0 <= 1'b1; stallreq_for_div <= `NoStop; end else begin div_opdata1_0 <= `ZeroWord; div_opdata2_0 <= `ZeroWord; div_start_0 <= `DivStop; signed_div_0 <= 1'b0; stallreq_for_div <= `NoStop; end end `EXE_DIVU_OP:begin if(div_ready_i == `DivResultNotReady)begin div_opdata1_0 <= reg1_i; div_opdata2_0 <= reg2_i; div_start_0 <= `DivStart; signed_div_0 <= 1'b0; stallreq_for_div <= `Stop; end else if(div_ready_i == `DivResultReady)begin div_opdata1_0 <= reg1_i; div_opdata2_0 <= reg2_i; div_start_0 <= `DivStop; signed_div_0 <= 1'b0; stallreq_for_div <= `NoStop; end else begin div_opdata1_0 <= `ZeroWord; div_opdata2_0 <= `ZeroWord; div_start_0 <= `DivStop; signed_div_0 <= 1'b0; stallreq_for_div <= `NoStop; end end default:begin end endcase end end //暂停流水线 always @ (*) begin stallreq = stallreq_for_madd_msub || stallreq_for_div; end always @ (*) begin if(rst == `RstEnable) begin whilo_0 <= `WriteDisable; hi_0 <= `ZeroWord; lo_0 <= `ZeroWord; end else if((aluop_i == `EXE_MSUB_OP) || (aluop_i == `EXE_MSUBU_OP))begin whilo_0 <= `WriteEnable; hi_0 <= hilo_temp1[63:32]; lo_0 <= hilo_temp1[31:0]; end else if((aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MADDU_OP))begin whilo_0 <= `WriteEnable; hi_0 <= hilo_temp1[63:32]; lo_0 <= hilo_temp1[31:0]; end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))begin whilo_0 <= `WriteEnable; hi_0 <= div_result_i[63:32]; lo_0 <= div_result_i[31:0]; end else if((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MULTU_OP)) begin whilo_0<=`WriteEnable; hi_0 <= mulres[63:32]; lo_0 <= mulres[31:0]; end else if(aluop_i == `EXE_MTHI_OP)begin whilo_0 <= `WriteEnable; hi_0 <= reg1_i; lo_0 <= LO; end else if(aluop_i == `EXE_MTLO_OP)begin whilo_0 <= `WriteEnable; hi_0 <= HI; lo_0 <= reg1_i; end else begin whilo_0 <= `WriteDisable; hi_0 <= `ZeroWord; lo_0 <= `ZeroWord; end end endmodule
module div( input wire clk, input wire rst, input wire signed_div_i, input wire[31:0] opdata1_i, input wire[31:0] opdata2_i, input wire start_i, input wire annul_i, output reg[63:0] result_0, output reg ready_0 ); wire[32:0] div_temp; reg[5:0] cnt;//记录试商法进行了几轮,当等于32时,表示试商法结束 reg[64:0] dividend; reg[1:0] state; reg[31:0] divisor; reg[31:0] temp_op1; reg[31:0] temp_op2; assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor}; always @ (posedge clk)begin if(rst == `RstEnable) begin state <= `DivFree; ready_0 <= `DivResultNotReady; result_0 <= {`ZeroWord,`ZeroWord}; end else begin case(state) `DivFree:begin if(start_i == `DivStart && annul_i == 1'b0)begin if(opdata2_i == `ZeroWord)begin state <= `DivByZero; end else begin state <= `DivOn; cnt <= 6'b000000; if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1)begin temp_op1 = ~opdata1_i + 1; end else begin temp_op1 = opdata1_i; end if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1)begin temp_op2 = ~opdata2_i + 1; end else begin temp_op2 = opdata2_i; end dividend <= {`ZeroWord,`ZeroWord}; dividend[32:1] <= temp_op1; divisor <= temp_op2; end end else begin ready_0 <= `DivResultNotReady; result_0 <= {`ZeroWord,`ZeroWord}; end end `DivByZero:begin dividend <= {`ZeroWord,`ZeroWord}; state <= `DivEnd; end `DivOn:begin if(annul_i == 1'b0)begin if(cnt != 6'b100000 )begin if(div_temp[32] == 1'b1) begin dividend <= {dividend[63:0],1'b0}; end else begin dividend <= {div_temp[31:0],dividend[31:0],1'b1}; end cnt <= cnt+1; end else begin if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin dividend[31:0] <= (~dividend[31:0] + 1); end if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin dividend[64:33] <= (~dividend[64:33] + 1); end state <= `DivEnd; cnt<=6'b000000; end end else begin state <= `DivFree; end end `DivEnd:begin result_0 <= {dividend[64:33],dividend[31:0]}; ready_0 <= `DivResultReady; if(start_i == `DivStop) begin state <= `DivFree; ready_0 <= `DivResultNotReady; result_0 <= {`ZeroWord,`ZeroWord}; end end endcase end end endmodule
include"defines.v" module ex_mem( input wire clk, input wire rst, input wire[5:0] stall, // 来自执行阶段的信息 input wire[`RegAddrBus] ex_wd, input wire ex_wreg, input wire[`RegBus] ex_wdata, input wire[`RegBus] ex_hi, input wire[`RegBus] ex_lo, input wire ex_whilo, input wire[`DoubleRegBus] hilo_i, input wire[1:0] cnt_i, //load input wire[`AluOpBus] ex_aluop, input wire[`RegBus] ex_mem_addr, input wire[`RegBus] ex_reg2, output reg[`AluOpBus] mem_aluop, output reg[`RegBus] mem_mem_addr, output reg[`RegBus] mem_reg2, output reg[`DoubleRegBus] hilo_0, output reg[1:0] cnt_0, //送到访存阶段的信息 output reg[`RegAddrBus] mem_wd, output reg mem_wreg, output reg[`RegBus] mem_wdata, output reg[`RegBus] mem_hi, output reg[`RegBus] mem_lo, output reg mem_whilo ); always @ (posedge clk) begin if(rst == `RstEnable) begin mem_wd <= `NOPRegAddr; mem_wreg <= `WriteDisable; mem_wdata<= `ZeroWord; mem_hi <= `ZeroWord; mem_lo <= `ZeroWord; mem_whilo <= `WriteDisable; hilo_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b00; mem_aluop <= `EXE_NOP_OP; mem_mem_addr <= `ZeroWord; mem_reg2 <= `ZeroWord; end else if(stall[3] == `Stop && stall[4] == `NoStop)begin mem_wd <= `NOPRegAddr; mem_wreg <= `WriteDisable; mem_wdata<= `ZeroWord; mem_hi <= `ZeroWord; mem_lo <= `ZeroWord; mem_whilo <= `WriteDisable; hilo_0 <= hilo_i; cnt_0 <= cnt_i; mem_aluop <= `EXE_NOP_OP; mem_mem_addr <= `ZeroWord; mem_reg2 <= `ZeroWord; end else if(stall[3] == `NoStop) begin mem_wd <= ex_wd; mem_wreg <= ex_wreg; mem_wdata <= ex_wdata; mem_hi <= ex_hi; mem_lo <= ex_lo; mem_whilo <= ex_whilo; hilo_0 <= {`ZeroWord,`ZeroWord}; cnt_0 <= 2'b00; mem_aluop <= ex_aluop; mem_mem_addr <= ex_mem_addr; mem_reg2 <= ex_reg2; end else begin hilo_0 <= hilo_i; cnt_0 <= cnt_i; end end endmodule
`include"defines.v" module mem( input wire rst, // 来自执行阶段的信息 input wire[`RegAddrBus] wd_i, input wire wreg_i, input wire[`RegBus] wdata_i, input wire[`RegBus] hi_i, input wire[`RegBus] lo_i, input wire whilo_i, //load input wire[`AluOpBus] aluop_i, input wire[`RegBus] mem_addr_i, input wire[`RegBus] reg2_i, // ram input wire[`RegBus] mem_data_i, //送到RAM的信息 output reg[`RegBus] mem_addr_0, output wire mem_we_0, output reg[3:0] mem_sel_0, output reg[`RegBus] mem_data_0, output reg mem_ce_0, //访存阶段的结构 output reg[`RegAddrBus] wd_0, output reg wreg_0, output reg[`RegBus] wdata_0, output reg[`RegBus] hi_0, output reg[`RegBus] lo_0, output reg whilo_0 ); wire[`RegBus] zero32; reg mem_we; assign mem_we_0 = mem_we; assign zer032 = `ZeroWord; always @ (*) begin if(rst == `RstEnable) begin wd_0 <= `NOPRegAddr; wreg_0 <= `WriteDisable; wdata_0 <= `ZeroWord; hi_0 <= `ZeroWord; lo_0 <= `ZeroWord; whilo_0 <= `WriteDisable; mem_addr_0 <= `ZeroWord; mem_we <= `WriteDisable; mem_sel_0 <= 4'b0000; mem_data_0 <= `ZeroWord; mem_ce_0 <= `ChipDisable; end else begin wd_0 <= wd_i; wreg_0 <= wreg_i; wdata_0 <= wdata_i; hi_0 <= hi_i; lo_0 <= lo_i; whilo_0 <= whilo_i; mem_addr_0 <= `ZeroWord; mem_we <= `WriteDisable; mem_sel_0 <= 4'b1111; mem_ce_0 <= `ChipDisable; case(aluop_i) `EXE_LB_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= {{24{mem_data_i[31]}},mem_data_i[31:24]}; mem_sel_0 <= 4'b1000; end 2'b01:begin wdata_0 <= {{24{mem_data_i[23]}},mem_data_i[23:16]}; mem_sel_0 <= 4'b0100; end 2'b10:begin wdata_0 <= {{24{mem_data_i[15]}},mem_data_i[15:8]}; mem_sel_0 <= 4'b0010; end 2'b11:begin wdata_0 <= {{24{mem_data_i[7]}},mem_data_i[7:0]}; mem_sel_0 <= 4'b0001; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_LBU_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= {{24{1'b0}},mem_data_i[31:24]}; mem_sel_0 <= 4'b1000; end 2'b01:begin wdata_0 <= {{24{1'b0}},mem_data_i[23:16]}; mem_sel_0 <= 4'b0100; end 2'b10:begin wdata_0 <= {{24{1'b0}},mem_data_i[15:8]}; mem_sel_0 <= 4'b0010; end 2'b11:begin wdata_0 <= {{24{1'b0}},mem_data_i[7:0]}; mem_sel_0 <= 4'b0001; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_LH_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= {{16{mem_data_i[31]}},mem_data_i[31:16]}; mem_sel_0 <= 4'b1100; end 2'b10:begin wdata_0 <= {{16{mem_data_i[15]}},mem_data_i[15:0]}; mem_sel_0 <= 4'b0011; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_LHU_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= {{16{1'b0}},mem_data_i[31:16]}; mem_sel_0 <= 4'b1100; end 2'b10:begin wdata_0 <= {{16{1'b0}},mem_data_i[15:0]}; mem_sel_0 <= 4'b0011; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_LW_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteDisable; wdata_0 <= mem_data_i; mem_sel_0 <= 4'b1111; mem_ce_0 <= `ChipEnable; end `EXE_LWL_OP:begin mem_addr_0 <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteDisable; mem_sel_0 <= 4'b1111; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= mem_data_i[31:0]; end 2'b01:begin wdata_0 <= {mem_data_i[23:0],reg2_i[7:0]}; end 2'b10:begin wdata_0 <= {mem_data_i[15:0],reg2_i[15:0]}; end 2'b11:begin wdata_0 <= {mem_data_i[7:0],reg2_i[23:0]}; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_LWR_OP:begin mem_addr_0 <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteDisable; mem_sel_0 <= 4'b1111; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_0 <= {reg2_i[31:8],mem_data_i[31:24]}; end 2'b01:begin wdata_0 <= {reg2_i[31:16],mem_data_i[31:16]}; end 2'b10:begin wdata_0 <= {reg2_i[31:24],mem_data_i[31:8]}; end 2'b11:begin wdata_0 <= mem_data_i; end default:begin wdata_0 <= `ZeroWord; end endcase end `EXE_SB_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteEnable; mem_data_0 <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]}; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_0 <= 4'b1000; end 2'b01:begin mem_sel_0 <= 4'b0100; end 2'b10:begin mem_sel_0 <= 4'b0010; end 2'b11:begin mem_sel_0 <= 4'b0001; end default:begin mem_sel_0 <= 4'b0000; end endcase end `EXE_SH_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteEnable; mem_data_0 <= {reg2_i[15:0],reg2_i[15:0]}; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_0 <= 4'b1100; end 2'b10:begin mem_sel_0 <= 4'b0011; end default:begin mem_sel_0 <= 4'b0000; end endcase end `EXE_SW_OP:begin mem_addr_0 <= mem_addr_i; mem_we <= `WriteEnable; mem_data_0 <= reg2_i; mem_sel_0 <= 4'b1111; mem_ce_0 <= `ChipEnable; end `EXE_SWL_OP:begin mem_addr_0 <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteEnable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_0 <= 4'b1111; mem_data_0 <= reg2_i; end 2'b01:begin mem_sel_0 <= 4'b0111; mem_data_0 <= {zero32[7:0],reg2_i[31:8]}; end 2'b10:begin mem_sel_0 <= 4'b0011; mem_data_0 <= {zero32[15:0],reg2_i[31:16]}; end 2'b11:begin mem_sel_0 <= 4'b0001; mem_data_0 <= {zero32[23:0],reg2_i[31:24]}; end default:begin mem_sel_0 <= 4'b0000; end endcase end `EXE_SWR_OP:begin mem_addr_0 <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteEnable; mem_ce_0 <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_0 <= 4'b1000; mem_data_0 <= {reg2_i[7:0],zero32[23:0]}; end 2'b01:begin mem_sel_0 <= 4'b1100; mem_data_0 <= {reg2_i[15:0],zero32[15:0]}; end 2'b10:begin mem_sel_0 <= 4'b1110; mem_data_0 <= {reg2_i[23:0],zero32[7:0]}; end 2'b11:begin mem_sel_0 <= 4'b1111; mem_data_0 <= reg2_i[31:0]; end default:begin mem_sel_0 <= 4'b0000; end endcase end default:begin end endcase end end Endmodule
`include"defines.v" module mem_wb( input wire clk, input wire rst, input wire[5:0] stall, //访存阶段的结果 input wire[`RegAddrBus] mem_wd, input wire mem_wreg, input wire[`RegBus] mem_wdata, input wire[`RegBus] mem_hi, input wire[`RegBus] mem_lo, input wire mem_whilo, //送到回写阶段的信息 output reg[`RegAddrBus] wb_wd, output reg wb_wreg, output reg[`RegBus] wb_wdata, output reg[`RegBus] wb_hi, output reg[`RegBus] wb_lo, output reg wb_whilo ); always @ (posedge clk)begin if(rst == `RstEnable) begin wb_wd <= `NOPRegAddr; wb_wreg <= `WriteDisable; wb_wdata <= `ZeroWord; wb_hi <= `ZeroWord; wb_lo <=`ZeroWord; wb_whilo <=`WriteDisable; end else if(stall[4] == `Stop && stall[5] == `NoStop) begin wb_wd <= `NOPRegAddr; wb_wreg <= `WriteDisable; wb_wdata <= `ZeroWord; wb_hi <= `ZeroWord; wb_lo <=`ZeroWord; wb_whilo <=`WriteDisable; end else if (stall[4] == `NoStop) begin wb_wd <= mem_wd; wb_wreg <= mem_wreg; wb_wdata <= mem_wdata; wb_hi <= mem_hi; wb_lo <= mem_lo; wb_whilo <= mem_whilo; end end endmodule
`include"defines.v" module hilo_reg( input wire clk, input wire rst, // 写端口 input wire we, input wire[`RegBus] hi_i, input wire[`RegBus] lo_i, //读端口 output reg[`RegBus] hi_0, output reg[`RegBus] lo_0 ); always @ (posedge clk) begin if (rst == `RstEnable)begin hi_0 <= `ZeroWord; lo_0 <= `ZeroWord; end else if((we == `WriteEnable)) begin hi_0 <= hi_i; lo_0 <= lo_i; end end Endmodule
include"defines.v" module openmips( input wire clk, input wire rst, input wire[`RegBus] rom_data_i, output wire[`RegBus] rom_addr_0, input wire[`RegBus] ram_data_i, output wire[`RegBus] ram_addr_0, output wire[`RegBus] ram_data_0, output wire ram_we_0, output wire[3:0] ram_sel_0, output wire ram_ce_0, output wire rom_ce_0 ); //连接IF/ID模块与译码阶段ID 模块的变量 wire [`InstAddrBus] pc; wire [`InstAddrBus] id_pc_i; wire [`InstBus] id_inst_i; //连接译码阶段ID模块输出与 ID / EX 模块的输入变量 wire[`AluOpBus] id_aluop_0; wire[`AluSelBus] id_alusel_0; wire[`RegBus] id_reg1_0; wire[`RegBus] id_reg2_0; wire id_wreg_0; wire[`RegAddrBus]id_wd_0; wire is_in_delayslot_0; wire[`RegBus] link_addr_0; wire next_inst_in_delayslot_0; wire[`RegBus] inst_0; //送到pc_reg wire[`RegBus] branch_target_address_0; wire branch_flag_0; // 连接ID / EX 模块输出与执行阶段 EX 模块的输入的变量 wire[`AluOpBus] ex_aluop_i; wire[`AluSelBus] ex_alusel_i; wire[`RegBus] ex_reg1_i; wire[`RegBus] ex_reg2_i; wire ex_wreg_i; wire[`RegAddrBus]ex_wd_i; wire ex_is_in_delayslot_i; wire[`RegBus] ex_link_address_i; wire[`RegBus] ex_inst_i; //送到pc wire ex_is_in_delayslot_0; //连接执行阶段EX 模块的输出与EX/MEM 模块的输入的变量 wire ex_wreg_0; wire[`RegAddrBus]ex_wd_0; wire[`RegBus] ex_wdata_0; wire[`RegBus] ex_hi_0; wire[`RegBus] ex_lo_0; wire ex_whilo_0; wire[7:0] ex_aluop_0; wire[`RegBus] ex_mem_addr_0; wire[`RegBus] ex_reg2_0; //连接EX/MEM 模块的输出与访存阶段MEM模块的输入的变量 wire mem_wreg_i; wire[`RegAddrBus]mem_wd_i; wire[`RegBus] mem_wdata_i; wire mem_whilo_i; wire[`RegBus] mem_hi_i; wire[`RegBus] mem_lo_i; wire[7:0] mem_aluop; wire[`RegBus] mem_mem_addr; wire[`RegBus] mem_reg2; //连接访存阶段MEM模块的输出与MEM/WB模块的输入的变量 wire mem_wreg_0; wire[`RegAddrBus] mem_wd_0; wire[`RegBus] mem_wdata_0; wire mem_whilo_0; wire[`RegBus] mem_hi_0; wire[`RegBus] mem_lo_0; //mem -> ram wire[`RegBus] mem_addr_0; wire mem_we_0; wire[3:0] mem_sel_0; wire[`RegBus] mem_data_0; wire mem_ce_0; //连接MEM/WB模块的输出与回写阶段的输入的变量 wire wb_wreg_i; wire[`RegAddrBus]wb_wd_i; wire[`RegBus] wb_wdata_i; wire wb_whilo_i; wire[`RegBus] wb_hi_i; wire[`RegBus] wb_lo_i; //连接译码阶段ID模块与通用寄存器Regfile模块的变量 wire reg1_read; wire reg2_read; wire[`RegBus] reg1_data; wire[`RegBus] reg2_data; wire[`RegAddrBus]reg1_addr; wire[`RegAddrBus]reg2_addr; //HILO wire[`RegBus] hi_0; wire[`RegBus] lo_0; //ctrl wire[5:0] stall; wire stallreq_id; wire stallreq_ex; //乘累加和乘累减 wire[1:0] ex_cnt_0; wire[`DoubleRegBus]ex_hilo_0; wire[1:0] ex_mem_cnt_0; wire[`DoubleRegBus]ex_mem_hilo_0; //DIV wire signed_div; wire[31:0] div_opdata1; wire[31:0] div_opdata2; wire div_start; wire[63:0] div_result; wire div_ready; //pc_reg 例化 pc_reg pc_reg0(.clk(clk),.rst(rst),.stall(stall),.branch_flag_i(branch_flag_0),.branch_target_address_i(branch_target_address_0),.pc(pc),.ce(rom_ce_0)); assign rom_addr_0 = pc;//指令存储器的输入地址就是pc的值 // if/id 模块例化 if_id if_id0(.clk(clk),.rst(rst),.stall(stall),.if_pc(pc),.if_inst(rom_data_i),.id_pc(id_pc_i),.id_inst(id_inst_i)); //译码阶段的例化 id id0(.rst(rst),.pc_i(id_pc_i),.inst_i(id_inst_i), .is_in_delayslot_i(ex_is_in_delayslot_0), //来自Regfile模块的输入 .reg1_data_i(reg1_data),.reg2_data_i(reg2_data), //送到regfile模块的信息 .reg1_read_0(reg1_read),.reg2_read_0(reg2_read), .reg1_addr_0(reg1_addr),.reg2_addr_0(reg2_addr), .ex_wreg_i(ex_wreg_0), .ex_wdata_i(ex_wdata_0), .ex_wd_i(ex_wd_0), .mem_wreg_i(mem_wreg_0), .mem_wdata_i(mem_wdata_0), .mem_wd_i(mem_wd_0), //yanshifenzi .next_inst_in_delayslot_0(next_inst_in_delayslot_0), .branch_flag_0(branch_flag_0), .branch_target_address_0(branch_target_address_0), .link_addr_0(link_addr_0), .is_in_delayslot_0(is_in_delayslot_0), //送到ID/EX模块的信息 .aluop_0(id_aluop_0),.alusel_0(id_alusel_0), .reg1_0(id_reg1_0),.reg2_0(id_reg2_0), .wd_0(id_wd_0),.wreg_0(id_wreg_0), .stallreq(stallreq_id), .inst_0(inst_0) ); //通用寄存器Regfile模块例化 Regfile regfile1( .clk(clk), .rst(rst), .we(wb_wreg_i), .waddr(wb_wd_i), .wdata(wb_wdata_i), .re1(reg1_read), .raddr1(reg1_addr), .rdata1(reg1_data), .re2(reg2_read), .raddr2(reg2_addr), .rdata2(reg2_data) ); //ID/EX模块例化 id_ex id_ex0( .clk(clk), .rst(rst),.stall(stall), //从译码阶段 ID 模块传递过来的信息 .id_aluop(id_aluop_0), .id_alusel(id_alusel_0), .id_reg1(id_reg1_0), .id_reg2(id_reg2_0), .id_wd(id_wd_0), .id_wreg(id_wreg_0), //跳转时延 .id_link_address(link_addr_0), .id_is_in_delayslot(is_in_delayslot_0), .next_inst_in_delayslot_i(next_inst_in_delayslot_0), .id_inst(inst_0), //传递到执行阶段EX模块的信息 .ex_aluop(ex_aluop_i), .ex_alusel(ex_alusel_i), .ex_reg1(ex_reg1_i), .ex_reg2(ex_reg2_i), .ex_wd(ex_wd_i), .ex_wreg(ex_wreg_i), //跳转时延 .ex_link_address(ex_link_address_i), .ex_is_in_delayslot(ex_is_in_delayslot_i), .is_in_delayslot_0(ex_is_in_delayslot_0), .ex_inst(ex_inst_i) ); //EX 模块例化 ex ex0( .rst(rst), // 从ID/EX 模块传递过来的信息 .aluop_i(ex_aluop_i), .alusel_i(ex_alusel_i), .reg1_i(ex_reg1_i), .reg2_i(ex_reg2_i), .wd_i(ex_wd_i), .wreg_i(ex_wreg_i), //输出到EX/MEM模块的信息 .wd_0(ex_wd_0), .wreg_0(ex_wreg_0), .wdata_0(ex_wdata_0), //hilo传递过来的值 .hi_i(hi_0), .lo_i(lo_0), .wb_hi_i(wb_hi_i), .wb_lo_i(wb_lo_i), .wb_whilo_i(wb_whilo_i), .mem_hi_i(mem_hi_0), .mem_lo_i(mem_lo_0), .mem_whilo_i(mem_whilo_0), .inst_i(ex_inst_i), .cnt_i(ex_mem_cnt_0), .hilo_temp_i(ex_mem_hilo_0), .div_result_i(div_result), .div_ready_i(div_ready), .link_address_i(ex_link_address_i), .is_in_delayslot_i(ex_is_in_delayslot_i), .cnt_0(ex_cnt_0), .hilo_temp_0(ex_hilo_0), .hi_0(ex_hi_0), .lo_0(ex_lo_0), .whilo_0(ex_whilo_0), .div_start_0(div_start), .div_opdata2_0(div_opdata2), .div_opdata1_0(div_opdata1), .signed_div_0(signed_div), .stallreq(stallreq_ex), .aluop_0(ex_aluop_0), .mem_addr_0(ex_mem_addr_0), .reg2_0(ex_reg2_0) ); // EX/MEM 模块例化 ex_mem ex_mem0( .clk(clk), .rst(rst), .stall(stall), // 来自执行阶段EX模块的信息 .ex_wd(ex_wd_0), .ex_wreg(ex_wreg_0), .ex_wdata(ex_wdata_0), .ex_whilo(ex_whilo_0), .ex_hi(ex_hi_0), .ex_lo(ex_lo_0), .cnt_i(ex_cnt_0), .hilo_i(ex_hilo_0), .cnt_0(ex_mem_cnt_0), .hilo_0(ex_mem_hilo_0), .ex_aluop(ex_aluop_0), .ex_mem_addr(ex_mem_addr_0), .ex_reg2(ex_reg2_0), // 送到访存阶MEM 模块的信息 .mem_wd(mem_wd_i), .mem_wreg(mem_wreg_i), .mem_wdata(mem_wdata_i), .mem_whilo(mem_whilo_i), .mem_hi(mem_hi_i), .mem_lo(mem_lo_i), .mem_aluop(mem_aluop), .mem_mem_addr(mem_mem_addr), .mem_reg2(mem_reg2) ); // MEM模块例化 mem mem0( .rst(rst), //来自EX/MEM 模块的信息 .wd_i(mem_wd_i), .wreg_i(mem_wreg_i), .wdata_i(mem_wdata_i), .whilo_i(mem_whilo_i), .hi_i(mem_hi_i), .lo_i(mem_lo_i), .mem_data_i(ram_data_i), .aluop_i(mem_aluop), .mem_addr_i(mem_mem_addr), .reg2_i(mem_reg2), .mem_addr_0(mem_addr_0), .mem_we_0(mem_we_0), .mem_sel_0(mem_sel_0), .mem_data_0(mem_data_0), .mem_ce_0(mem_ce_0), // 送到MEM/WB模块的信息 .wd_0(mem_wd_0), .wreg_0(mem_wreg_0), .wdata_0(mem_wdata_0), .whilo_0(mem_whilo_0), .hi_0(mem_hi_0), .lo_0(mem_lo_0) ); assign ram_addr_0 = mem_addr_0 ; assign ram_data_0 = mem_data_0; assign ram_we_0 = mem_we_0; assign ram_sel_0 = mem_sel_0; assign ram_ce_0 = mem_ce_0; //MEM/WB 模块例化 mem_wb mem_wb0( .clk(clk), .rst(rst), .stall(stall), //来自访存阶段MEM模块的信息 .mem_wd(mem_wd_0), .mem_wreg(mem_wreg_0), .mem_wdata(mem_wdata_0), .mem_whilo(mem_whilo_0), .mem_hi(mem_hi_0), .mem_lo(mem_lo_0), //送到回写阶段的信息 .wb_wd(wb_wd_i), .wb_wreg(wb_wreg_i), .wb_wdata(wb_wdata_i), .wb_whilo(wb_whilo_i), .wb_hi(wb_hi_i), .wb_lo(wb_lo_i) ); hilo_reg hilo_reg0(.clk(clk),.rst(rst),.we(wb_whilo_i),.hi_i(wb_hi_i),.lo_i(wb_lo_i),.hi_0(hi_0),.lo_0(lo_0)); ctrl ctrl0(.rst(rst),.stallreq_from_id(stallreq_id),.stallreq_from_ex(stallreq_ex),.stall(stall)); div div0(.clk(clk),.rst(rst),.signed_div_i(signed_div),.opdata1_i(div_opdata1),.opdata2_i(div_opdata2),.start_i(div_start), .annul_i(1'b0),.result_0(div_result),.ready_0(div_ready)); endmodule
include"defines.v" module openmips_min_sopc( input wire clk, input wire rst ); //连接指令存储器 wire[`InstAddrBus] inst_addr; wire[`InstBus] inst; wire rom_ce; //连接ram wire[`RegBus] ram_addr; wire[`RegBus] ram_data_i; wire[`RegBus] ram_data_o; wire[3:0] ram_sel; wire ram_we; wire ram_ce; //例化处理器 OpenMIPS openmips openmips0( .clk(clk), .rst(rst), .rom_addr_0(inst_addr), .rom_data_i(inst), .ram_data_i(ram_data_o), .ram_addr_0(ram_addr), .ram_data_0(ram_data_i), .ram_we_0(ram_we), .ram_sel_0(ram_sel), .ram_ce_0(ram_ce), .rom_ce_0(rom_ce) ); // 例化指令存储器 ROM inst_rom inst_rom0( .ce(rom_ce), .addr(inst_addr), .inst(inst) ); data_ram data_ram0(.clk(clk),.addr(ram_addr),.data_i(ram_data_i),.sel(ram_sel),.we(ram_we),.ce(ram_ce),.data_0(ram_data_o)); endmodule
include"defines.v" module data_ram( input wire clk, input wire ce, input wire we, input wire[`DataAddrBus] addr, input wire[3:0] sel, input wire[`DataBus] data_i, output reg[`DataBus] data_0 ); reg[`ByteWidth] data_mem0[0:`DataMemNum-1]; reg[`ByteWidth] data_mem1[0:`DataMemNum-1]; reg[`ByteWidth] data_mem2[0:`DataMemNum-1]; reg[`ByteWidth] data_mem3[0:`DataMemNum-1]; //写 always @(posedge clk)begin if(ce == `ChipDisable)begin //data_0 <= `ZeroWord; end else if(we == `WriteEnable) begin if(sel[3] == 1'b1) begin data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24]; end if(sel[2] == 1'b1)begin data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16]; end if(sel[1] == 1'b1)begin data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8]; end if(sel[0] == 1'b1)begin data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0]; end end end //读 always @ (*) begin if(ce == `ChipDisable)begin data_0 <= `ZeroWord; end else if( we == `WriteDisable)begin data_0 <= {data_mem3[addr[`DataMemNumLog2+1:2]], data_mem2[addr[`DataMemNumLog2+1:2]], data_mem1[addr[`DataMemNumLog2+1:2]], data_mem0[addr[`DataMemNumLog2+1:2]]}; end else begin data_0 <= `ZeroWord; end end endmodule
`include"defines.v" module inst_rom( input wire ce, input wire[`InstAddrBus] addr, output reg[`InstBus] inst ); //定义一个数组,大小是InstMenNum,元素宽度是InstBus reg[`InstBus] inst_mem[0:`InstMemNum-1]; initial $readmemh("C:\\Users\\86183\\Desktop\\mips\\inst_rom.txt",inst_mem); /*initial begin inst_mem[0] = 32'h34011100; inst_mem[1] = 32'h34020020; inst_mem[2] = 32'h3403ff00; inst_mem[3] = 32'h3404ffff; end*/ //当复位信号无效时,依据输入的地址,给出指令存储器ROM对应的元素 always @ (*) begin if(ce == `ChipDisable) begin inst <= `ZeroWord; end else begin inst <= inst_mem[addr[`InstMemNumLog2 +1:2]]; end end endmodule
define RstEnable 1'b1 //复位有效信号 `define RstDisable 1'b0 //复位信号无效 `define ZeroWord 32'h00000000 //32位的数值0 `define WriteEnable 1'b1 //使能写 `define WriteDisable 1'b0 //禁止写 `define ReadEnable 1'b1 //使能读 `define ReadDisable 1'b0 //禁止读 `define AluOpBus 7:0 // 译码阶段的输出 aluop_o的宽度 `define AluSelBus 2:0 // 译码阶段的输出 alusel_o的宽度 `define InstValid 1'b0 //指令有效 `define InstInvalid 1'b1 //指令无效 `define True_v 1'b1 //逻辑“真” `define False_v 1'b0 //逻辑“假” `define ChipEnable 1'b1 //芯片使能 `define ChipDisable 1'b0 //芯片禁止 //*******************************与具体指令有关的宏定义************************************// `define EXE_NOP 6'b000000 `define EXE_AND 6'b100100 // and `define EXE_OR 6'b100101 //or `define EXE_XOR 6'b100110 //xor `define EXE_NOR 6'b100111 //nor `define EXE_ANDI 6'b001100 //andi `define EXE_ORI 6'b001101 //ori `define EXE_XORI 6'b001110 //xori `define EXE_LUI 6'b001111 //lui `define EXE_SLL 6'b000000 //sll `define EXE_SLLV 6'b000100 //sllv `define EXE_SRL 6'b000010 //sra `define EXE_SRLV 6'b000110 //srlv `define EXE_SRA 6'b000011 //sra `define EXE_SRAV 6'b000111 //srav `define EXE_SYNC 6'b001111 //sync `define EXE_PREF 6'b110011 //pref `define EXE_SPECIAL_INST 6'b000000 //special `define EXE_MOVZ 6'b001010 // movz `define EXE_MOVN 6'b001011 // movn `define EXE_MFHI 6'b010000 // mfhi `define EXE_MTHI 6'b010001 // mthi `define EXE_MFLO 6'b010010 // mflo `define EXE_MTLO 6'b010011 // mtlo `define EXE_SLT 6'b101010 `define EXE_SLTU 6'b101011 `define EXE_SLTI 6'b001010 `define EXE_SLTIU 6'b001011 `define EXE_ADD 6'b100000 `define EXE_ADDU 6'b100001 `define EXE_SUB 6'b100010 `define EXE_SUBU 6'b100011 `define EXE_ADDI 6'b001000 `define EXE_ADDIU 6'b001001 `define EXE_CLZ 6'b100000 `define EXE_CLO 6'b100001 `define EXE_MULT 6'b011000 `define EXE_MULTU 6'b011001 `define EXE_MUL 6'b000010 `define EXE_MADD 6'b000000 `define EXE_MADDU 6'b000001 `define EXE_MSUB 6'b000100 `define EXE_MSUBU 6'b000101 `define EXE_DIV 6'b011010 `define EXE_DIVU 6'b011011 `define EXE_J 6'b000010 `define EXE_JAL 6'b000011 `define EXE_JALR 6'b001001 `define EXE_JR 6'b001000 `define EXE_BEQ 6'b000100 `define EXE_BGEZ 5'b00001 `define EXE_BGEZAL 5'b10001 `define EXE_BGTZ 6'b000111 `define EXE_BLEZ 6'b000110 `define EXE_BLTZ 5'b00000 `define EXE_BLTZAL 5'b10000 `define EXE_BNE 6'b000101 `define EXE_LB 6'b100000 `define EXE_LBU 6'b100100 `define EXE_LH 6'b100001 `define EXE_LHU 6'b100101 `define EXE_LW 6'b100011 `define EXE_LWL 6'b100010 `define EXE_LWR 6'b100110 `define EXE_SB 6'b101000 `define EXE_SH 6'b101001 `define EXE_SW 6'b101011 `define EXE_SWL 6'b101010 `define EXE_SWR 6'b101110 `define EXE_REGIMM_INST 6'b000001 `define EXE_SPECIAL2_INST 6'b011100 //AluOp `define EXE_NOP_OP 8'b00000000 `define EXE_AND_OP 8'b00000001 // and `define EXE_OR_OP 8'b00000010 //or `define EXE_XOR_OP 8'b00000011 //xor `define EXE_NOR_OP 8'b00000100 //nor `define EXE_ANDI_OP 8'b00000101 //andi `define EXE_ORI_OP 8'b00000110 //ori `define EXE_XORI_OP 8'b00000111 //xori `define EXE_LUI_OP 8'b00001000 //lui `define EXE_SLL_OP 8'b00001001 //sll `define EXE_SLLV_OP 8'b00001010 //sllv `define EXE_SRL_OP 8'b00001011 //sra `define EXE_SRLV_OP 8'b00001100 //srlv `define EXE_SRA_OP 8'b00001101 //sra `define EXE_SRAV_OP 8'b00001110 //srav `define EXE_SYNC_OP 8'b00001111 //sync `define EXE_PREF_OP 8'b00010000 //pref `define EXE_SPECIAL_INST_OP 8'b00010001 //special `define EXE_MFHI_OP 8'b00010010 `define EXE_MFLO_OP 8'b00010011 `define EXE_MTHI_OP 8'b00010100 `define EXE_MTLO_OP 8'b00010101 `define EXE_MOVN_OP 8'b00010110 `define EXE_MOVZ_OP 8'b00010111 `define EXE_SLT_OP 8'b00011000 `define EXE_SLTU_OP 8'b00011001 `define EXE_SLTI_OP 8'b00011010 `define EXE_SLTIU_OP 8'b00011011 `define EXE_ADD_OP 8'b00011100 `define EXE_ADDU_OP 8'b00011101 `define EXE_SUB_OP 8'b00011110 `define EXE_SUBU_OP 8'b00011111 `define EXE_ADDI_OP 8'b00100000 `define EXE_ADDIU_OP 8'b00100001 `define EXE_CLZ_OP 8'b00100010 `define EXE_CLO_OP 8'b00100011 `define EXE_MULT_OP 8'b00100100 `define EXE_MULTU_OP 8'b00100101 `define EXE_MUL_OP 8'b00100110 `define EXE_MADD_OP 8'b00100111 `define EXE_MADDU_OP 8'b00101000 `define EXE_MSUB_OP 8'b00101001 `define EXE_MSUBU_OP 8'b00101010 `define EXE_DIV_OP 8'b00101011 `define EXE_DIVU_OP 8'b00101100 `define EXE_J_OP 8'b00101101 `define EXE_JAL_OP 8'b00101110 `define EXE_JALR_OP 8'b00101111 `define EXE_JR_OP 8'b00110000 `define EXE_BEQ_OP 8'b00110001 `define EXE_BGEZ_OP 8'b00110010 `define EXE_BGEZAL_OP 8'b00110011 `define EXE_BGTZ_OP 8'b00110100 `define EXE_BLEZ_OP 8'b00110101 `define EXE_BLTZ_OP 8'b00110110 `define EXE_BLTZAL_OP 8'b00110111 `define EXE_BNE_OP 8'b00111000 `define EXE_LB_OP 8'b00111001 `define EXE_LBU_OP 8'b00111010 `define EXE_LH_OP 8'b00111011 `define EXE_LHU_OP 8'b00111100 `define EXE_LW_OP 8'b00111101 `define EXE_LWL_OP 8'b00111110 `define EXE_LWR_OP 8'b00111111 `define EXE_SB_OP 8'b01000000 `define EXE_SH_OP 8'b01000001 `define EXE_SW_OP 8'b01000010 `define EXE_SWL_OP 8'b01000011 `define EXE_SWR_OP 8'b01000100 //AluSel `define EXE_RES_LOGIC 3'b001 `define EXE_RES_SHIFT 3'b010 `define EXE_RES_NOP 3'b000 `define EXE_RES_MOVE 3'b011 `define EXE_RES_ARITHMETIC 3'b100 `define EXE_RES_MUL 3'b101 `define EXE_RES_JUMP_BRANCH 3'b110 `define EXE_RES_LOAD_STORE 3'b111 //**********************************与指令存储器ROM有关的宏定义***************************************// `define InstAddrBus 31:0 //ROM的地址总线宽度 `define InstBus 31:0 //ROM的数据总线宽度 `define InstMemNum 131071 //ROM的实际大小为128KB `define InstMemNumLog2 17 //ROM实际使用的地址线宽度 //**********************************与通用寄存器Regffile有关的宏定义****************************************// `define RegAddrBus 4:0 //Regfile模块的地址线宽度 `define RegBus 31:0 //Regfile模块的数据线宽度 `define RegWidth 32 //通用寄存器的宽度 `define DoubleRegWidth 64 //两倍的通用寄存器的宽度 `define DoubleRegBus 63:0 //两倍的通用寄存器的数据线宽度 `define RegNum 32 //通用寄存器数量 `define RegNumLog2 5 //寻址通用寄存器使用的地址位数 `define NOPRegAddr 5'b00000 // /************************ 暂停阶段 ***/ `define Stop 1'b1 `define NoStop 1'b0 /************************ 除法 ****/ `define DivFree 2'b00 `define DivByZero 2'b01 `define DivOn 2'b10 `define DivEnd 2'b11 `define DivResultReady 1'b1 `define DivResultNotReady 1'b0 `define DivStart 1'b1 /************************* 转移 **************/ `define Branch 1'b1 //转移 `define NotBranch 1'b0 // 不转移 `define InDelaySlot 1'b1 `define NotInDelaySlot 1'b0 /***************************** ram ******************************/ `define DataAddrBus 31:0 `define DataBus 31:0 `define DataMemNum 131071 `define DataMemNumLog2 17 `define ByteWidth 7:0 `define DivStop 1'b0
1 逻辑指令仿真测试
1.1 MIPS 汇编代码以及对应机器码
#机器码 # 汇编代码 #运算结果
3c010101 lui $1,0x0101 #$1 = 0x01010000
34210101 ori $1,$1,0x0101 # $1 = 0x01010101
34221100 ori $2,$1,0x1100 # $2 = 0x01011101
00220825 or $1,$1,$2 # $1 = 0x01011101
302300fe andi$3,$1,0x00fe # $3 = 0x00000000
00610824 and $1,$3,$1 # $1 = 0x00000000
3824ff00 xori$4,$1,0xff00 # $4 = 0x0000ff00
00810826 xor $1,$4,$1 # $1 = 0x0000ff00
00810827 nor $1,$4,$1 # $1 = ffff00ff
1.2 仿真波形图
逻辑指令仿真总览图 1
逻辑指令仿真局部放大图 2
1.3 结果分析
MARS最终运行情况图 3
在MARS中得到的结果在7.1.1中的运算结果中有展示,图3为最终结果,对比仿真结果与MARS中得到的结果可以得知二者完全吻合,仿真波形图也符合五级流水的规则。
2 移位与空指令仿真测试
2.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3c020404 lui $2,0x0404 #$2 = 0x04040000
34420404 ori $2,$2,0x0404#$2 = 0x04040404
34070007 ori $7,$0,0x7
34050005 ori $5,$0,0x5
34080008 ori $8,$0,0x8
00000000 nop
#################### 第一段####################
00021200 sll $2,$2,8 #$2 = 0x04040400
00e21004 sllv$2,$2,$7 #$2 = 0x02020000
00021202 srl $2,$2,8 #$2 = 0x00020200
00a21006 srlv$2,$2,$5 #$2 = 0x00001010
00000000 nop
################## 第二段 ######################
000214c0 sll $2,$2,19 #$2 = 0x80800000
00021403 sra $2,$2,16 #$2 = 0xffff8080
01021007 srav$2,$2,$8 #$2 = 0xffffff80
################## 第三段 ######################
2.2 仿真波形图
移位与空指令仿真总览图 4
移位与空指令第一段仿真图 5
移位与空指令第二段仿真图 6
移位与空指令第三段仿真图 7
2.3 结果分析
在MARS中得到的结果在7.2.1中的运算结果中有展示,对比仿真结果与MARS中得到的结果可以得知二者完全吻合,仿真波形图也符合五级流水的规则。
3 移动指令仿真测试
3.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3c010000 lui $1,0x0000 # $1 = 0x00000000
3c02ffff lui $2,0xffff # $2 = 0xffff0000
3c030505 lui $3,0x0505 # $3 = 0x05050000
3c040000 lui $4,0x0000 # $4 = 0x00000000
0041200a movz $4,$2,$1 # $4 = 0xffff0000
0061200b movn $4,$3,$1 # $4 = 0xffff0000
0062200b movn $4,$3,$2 # $4 = 0x05050000
0043200a movz $4,$2,$3 # $4 = 0x05050000
00000011 mthi $0 # hi = 0x00000000
00400011 mthi $2 # hi = 0xffff0000
00600011 mthi $3 # hi = 0x05050000
00600013 mtlo $3 # lo = 0x05050000
00400013 mtlo $2 # lo = 0xffff0000
00200013 mtlo $1 # lo = 0x00000000
3.2 仿真波形图
移动指令仿真第一部分图
移动指令仿真第二部分图
3.3 结果分析
移动指令与8086的mov 很类似,不过mips指令的移动指令内容更加丰富,然后结果也与预期相同
4 算术指令仿真测试
4.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
34018000 ori $1,$0,0x8000 # $1 = 0x00008000
00010c00 sll $1,$1,16 # $1 = 0x80000000
34210010 ori $1,$1,0x0010 # $1 = 0x80000010
34028000 ori $2,$0,0x8000 # $2 = 0x00008000
00021400 sll $2,$2,16 # $2 = 0x80000000
34420001 ori $2,$2,0x0001 # $2 = 0x80000001
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
00411821 addu $3,$2,$1 # $3 = 0x00000011
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
00411820 add $3,$2,$1 # $2 + $1,有符号加法,结果溢出# $3 = 0x00000000
00231822 sub $3,$1,$3 # $3 = 0x80000010
00621823 subu $3,$3,$2 # $3 = 0xf
20630002 addi $3,$3,2 # $3 = 0x11
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
24638000 addiu $3,$3,0x8000 # $3 = 0xffff8000
3401ffff or $1,$0,0xffff # $1 = 0x0000ffff
00010c00 sll $1,$1,16 # $1 = 0xffff0000
0020102a slt $2,$1,$0 # $2 = 1
0020102b sltu $2,$1,$0 # $2 = 0
28228000 slti $2,$1,0x8000 # $2 = 1
2c228000 sltiu $2,$1,0x8000 # $2 = 1
3c010000 lui $1,0x0000 # $1 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000000
70201020 clz $2,$1 # $2 = 0x00000020
3c01ffff lui $1,0xffff # $1 = 0xffff0000
3421ffff ori $1,$1,0xffff # $1 = 0xffffffff
70201020 clz $2,$1 # $2 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000020
3c01a100 lui $1,0xa100 # $1 = 0xa1000000
70201020 clz $2,$1 # $2 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000000
3c011100 lui $1,0x1100 # $1 = 0x11000000
70201020 clz $2,$1 # $2 = 0x00000003
70201021 clo $2,$1 # $2 = 0x00000000
3401ffff ori $1,$0,0xffff
00010c00 sll $1,$1,16
3421fffb ori $1,$1,0xfffb # $1 = -5
34020006 ori $2,$0,6 # $2 = 6
70221802 mul $3,$1,$2 # $3 = -30 = 0xffffffe2
00220018 mult $1,$2 # HI = 0xffffffff LO = 0xffffffe2
00220019 multu $1,$2 # HI = 0x5 LO = 0xffffffe2
00000000 nop
00000000 nop
4.2 仿真波形图
算术指令第一部分图
算术指令第二部分图
算术指令第三部分图
算术指令第四部分图
4.3 结果分析
与预期结果相符合,与运算结果相符合
5 乘累加乘累减指令仿真测试
5.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3401ffff ori $1,$0,0xffff
00010c00 sll $1,$1,16
3421fffb ori $1,$1,0xfffb
34020006 ori $2,$0,6
00220018 mult $1,$2 # hi = 0xffffffff lo = 0xffffffe2
70220000 madd $1,$2 # hi = 0xffffffff lo = 0xffffffc4
70220001 maddu $1,$2 # hi = 0x5 lo = 0xffffffa6
70220004 msub $1,$2 # hi = 0x5 lo = 0xffffffc4
70360005 msubu $1,$22 # hi = 0xffffffff lo = 0xffffffe2
5.2 仿真波形图
乘累加,乘累减仿真图
5.3 结果分析
与5.1的预算结果完全吻合,且与MARS结果完全吻合
6 除法指令仿真测试
6.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运行结果
3402ffff ori $2,$0,0xffff
00021400 sll $2,$2,16
3442fff1 ori $2,$2,0xfff1 # $2 = -15
34030011 ori $3,$0,0x11 # $3 = 17
0043001a div $zero,$2,$3 # hi = 0xfffffff1 lo = 0x0
0043001b divu $zero,$2,$3 # hi = 0x00000003 lo = 0x0f0f0f0e
0062001a div $zero,$3,$2 # hi = 2 lo = 0xffffffff
00000000 nop
6.2 仿真波形图
除法指令仿真图
6.3 结果分析
除法指令执行周期长,因为采用的是试除法,而被除数与除数的长度都为32位,因此需要至少32个周期,如果出现除数为0的情况,div模块的状态机中也有对应状态表示该情况
7 分支指令仿真测试
7.1 MIPS 汇编代码以及对应机器码、
#机械指令 #汇编代码 #运行结果
34038000 ori $3,$0,0x8000
00031c00 sll $3,$3,16 # 设置$3 =0x80000000
34010001 ori $1,$0,0x0001 # $1 =0x1
10000003 beq $0,$0,s1 # 转移到s1处
34010002 ori $1,$0,0x0002 # $1 =0x2,这是延迟槽指令
t1:
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s1:
34010003 ori $1,$0, 0x0003 # $1 =0x3
04110007 bgezal $0,s2 # 转移到s2处,
#同时设置$31为0×2c
03e1001a div $zero,$31,$1 # 此时$31 =0x2c, $1=0x3,
#所以除法结果为# HI =0x2,
#Lo =Oxe,这是延迟槽指令
34011100 ori $1,$0,0x1100
34011111 ori $1,$0,0x1111
1420000e bne $1, $0,s3
00000000 nop
34011100 ori $1,$0,0x1100
34011111 ori $1,$0,0x1111
s2:
34010004 ori $1,$0,0x0004 # $1=0x4
10630009 beq $3,$3,s3 # $3等于$3,所以会发生转移,
#目的地址是s3
03e00825 or $1,$31,$0 # $1= Ox2c,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1, $0,0x1100
t2:
34010007 ori $1,$0,0x0007 # $1 =0x7
34010008 ori $1,$0,0x0008 # $1 = 0x8
1c200008 bgtz $1,s4 # 此时$1为0×8,大于0,
#所以转移至标号s4处
34010009 ori $1,$0,0x0009 # $1 =0x9,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s3:
34010005 ori $1,$0,0x0005 # $1 = 0x5
0421fff8 bgez $1,t2 # 此时$1为0×5,大于0,
#所以转移至前面的标号2处
34010006 ori $1,$0,0x0006 # $1= 0x6,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s4:
3401000a ori $1,$0,0x000a # $1= 0xa
0471fff9 bgezal $3,s3 # 此时$3为0x80000000,
#小于0,所以不发生转移
001f0825 or $1, $0,$31 # $1=0×10c
3401000b ori $1,$0,0x000b # $1=0xb
3401000c ori $1, $0, 0x000c # $1=0xc
3401000d ori $1, $0, 0x000d # $1 = 0xd
3401000e ori $1,$0,0x000e # $1 = Oxe
04600002 bltz $3,s5 # 此时$3为0x80000000,小于0, # 所以发生转移,转移至s5处
3401000f ori $1,$0,0x000f # $1 =0xf,这是延迟槽指令
34011100 ori $1,$0,0x1100
s5:
34010010 ori $1,$0,0x0010 # $1 = 0x10
1820ffe9 blez $1,t2 # 此时$1为0x10,大于0,
#所以不发生转移
34010011 ori $1,$0,0x0011 # $1 = 0x11
34010012 ori $1,$0,0x0012 # $1 = 0x12
34010013 ori $1,$0,0x0013 # $1 = 0x13
04700002 bltzal $3,s6 # 此时$3为0x80000000,小于0, # 所以发生转移,转移到s6处
001f0825 or $1,$0,$31 # $1 = 0x14c,这是延迟槽指令
34011100 ori $1,$0,0x1100
s6:
34010014 ori $1,$0,0x0014 # $1 = 0x14
00000000 nop
7.2 仿真波形图
分支指令仿真第一部分图
分支指令仿真第二部分图
分支指令仿真第三部分图
分支指令仿真第四部分图
分支指令仿真第五部分图
7.3 结果分析
分支有别于跳转,分支跳转时跳转的位置是相对于当前执行的指令的地址的下一条指令地址
7.8 跳转指令仿真测试
7.8.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
34010001 ori $1,$0,0x0001 # $1 = 0x1
08000005 j $1 # 转移到$1处
34010002 ori $1,$0,0x0002 # $1 =0x2,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s1:
34010003 ori $1,$0,0x0003 # $1 =0x3
0c00000d jal s2 # 转移到$2处
#同时设置$31为0x2c
03e1001a div $zero,$31,$1 # 此时$31 =0x20, $1 =0x3,
#所以得到除法结果
#HI =0x2,LO =0xa,这是延迟槽指令
00000000 nop
34010005 ori $1,$0,0x0005 # $1=0x5
34010006 ori $1,$0,0x0006 # $1=0x6
08000013 j s3 # 转移到s3处
00000000 nop
s2:
03e01009 jalr $2,$31 # 此时$31为0x20,
#所以转移到0×20,同时设置
#$20x3c
00400825 or $1,$2,$0 # $1=0x3c,这是延迟槽指令
34010009 ori $1,$0,0x0009 # $1 =0x9
3401000a ori $1,$0,0x000a # $1 =Oxa
08000019 j s4 # 转移到s4处
00000000 nop
s3:
34010007 ori $1,$0,0x0007 # $1 = 0x7
00400008 jr $2 # 此时$2为0x3c,
#所以转移到0x3c处
34010008 ori $1,$0,0x0008 # $1 = 0x8,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s4:
00000000 nop
8.2 仿真波形图
在这里插入图片描述
跳转指令仿真第一部分图
跳转指令仿真第二部分图
跳转指令仿真第三部分图
8.3 结果分析
因为跳转指令在执行时,不会立马跳转而是先执行指令槽指令,就是跳转指令下一条指令,然后在跳转,仿真结果正确,与MARS运行结果不同,因为起始地址从0x00003000开始的,而本MIPSCPU初始地址是从0x00000000开始的,但是将对应位置更改过后,能正常运行
9. 存储加载指令仿真测试
9.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
#####################第一段:测试sb、 lb、lbu指令############
3403eeff ori $3,$0,0xeeff # $3 =0x0000eeff
a0030003 sb $3,0x3($0) # 向RAM地址0x3处存储0xff,
#[0x3] = 0xff
00031a02 srl $3,$3,8 # 逻辑右移8位,$3 = 0x000000ee
a0030002 sb $3,0x2($0) # 向RAM地址0x2处存储0xee,
#[0x2] = 0xee
3403ccdd ori $3,$0,0xccdd # $3 =0x0000ccdd
a0030001 sb $3,0x1($0) # 向RAM地址0x1处存储0xdd,
#[0x1] = 0xdd
00031a02 srl $3,$3,8 # 逻辑右移8位,$3 =0x000000cc
a0030000 sb $3,0x0($0) # 向RAM地址0x0处存储0xcc,
#[0x0] = 0xcc
80010003 lb $1,0x3($0) # 加载0x3处的字节并作符号扩展,
#$1 =0xffffffff
90010002 lbu $1,0x2($0) # 并加载0×2处的字节并作无符号扩展,
#$1 = 0x000000ee
###################第二段:测试sh、lh、 lhu指令##########
3403aabb ori $3,$0,0xaabb # $3=0x0000aabb
a4030004 sh $3,0x4($0) # 向RAM地址0x4处存储0xaabb,
# [0x4]=0xaa, [0x5] = 0xbb
94010004 lhu $1,0x4($0) # 加载0x4处的半字并作无符号扩展,
#$1 = 0x0000aabb
84010004 lh $1,0x4($0) # 加载0x4处的半字并作符号扩展,
#$1 = 0xffffaabb
34038899 ori $3,$0,0x8899 # $3 = 0x00008899
a4030006 sh $3,0x6($0) # 向RAM地址0x6处存储0x8899,
#[0x6] = 0x88,
#[0x7] = 0x99
84010006 lh $1,0x6($0) # 加载0x6处的半字并作符号扩展,
#$1 = 0xffff8899
94010006 lhu $1,0x6($0) # 加载0x6处的半字并作无符号扩展,
#$1 = 0x00008899
##################第三段:测试sw、lw、lwl、 lwr##############
# 经过上面指令的执行,此时RAM的内容如下
# [0x0] = 0xcc, [0x1] = 0xdd
# [0x2] = 0xee, [0x3] = 0xff
# [0x4] = 0xaa, [0x5] = 0xbb
# [0x6] = 0x88, [0x7] = 0x99
34034455 ori $3,$0,0x4455
00031c00 sll $3,$3,0x10
34636677 ori $3,$3,0x6677 # $3 = 0x44556677
ac030008 sw $3,0x8 ($0) # 向RAM地址0x8处存储0x44556677,
# [0x8]= 0x44,[0x9] =0x55,
# [0xa] = 0x66,[0xb]= 0x77
8c010008 lw $1,0x8($0) # 加载0x8处的字,$1 =0x44556677
88010005 lwl $1,0x5($0) # 非对齐加载指令1wl,执行后使得
#$1 =0xbb889977
98010008 lwr $1,0x8($0) # 非对齐加载指令1wr,
#执行后使得$1 = 0xbb889900
00000000 nop
############## 第四段:测试swl、swr指令###############
b8010002 swr $1,0x2($0) # 非对齐存储指令swr,执行效果如下
# [0x0]=0x88, [0x1] =0x99,
# [0x2]=0x44,[0x3]= 0xff
a8010007 swl $1,0x7($0) # 非对齐存储指令swl,执行效果如下
# [0x4]=0xaa,[0x5] = 0xbb,
# [0x6]=0x88,[0x7] = 0xbb
8c010000 lw $1,0x0($0) # 加载RAM地址0x0处的字,
#$1= 0x000044ff,
# 验证swr指令的执行效果
8c010004 lw $1,0x4($0) # 加载RAM地址0x4处的字,
#$1 = 0xaabb8800,
9.2 仿真波形图
存储加载指令仿真第一部分图
存储加载指令仿真第二部分图
存储加载指令仿真第三部分图
9.3 结果分析
结果与MARS不太一样因为我这写的是大端法存储,Mars是小端法,所以数据不同
数据冲突解决方式
流水线结构紧密,每一条指令基本上参与绝大部分的模块,执行效率很高,不过也有一些问题,因为流水线每一个周期在正常情况下都会读取一个指令,然后很容易出现相邻指令共用同一个寄存器的现象,比如 ori $1,$2,0x12,和 ori $3,$1,0x15,因为前一个指令最后需要把值存入$1寄存器中,但是因为第二条指令访问$1寄存器的时候,第一条指令还未将结果写回,
间隔相邻指令之间也存在这样的情况。
我采用了这样的方式规避间隔相邻指令数据冲突的问题,这是一个判断,如果发现当前要读取的寄存 器和下一个时钟上升沿要写入的数据相同则可以把该数据赋值给输出数据。
而相邻情况总共有三种解决方法:1.插入暂停周期,2.编译器调度,3.数据前推
我采用的是比较简单的第三种方式数据前推的方式来解决该方法,不过这样该方法需要一个前提就是 新的寄存器的值可以在执行阶段计算出来,然而加载指令不满足,因为加载指令是在访存阶段执行的。解决方法在第五部分也是有体现的,就是将ex模块传入ex_mem的wdata_0 以及 wd_0、wreg_0 回传到id模块,MEM模块也是如此将送到mem_wb模块的
wdata_0 以及 wd_0、wreg_0 回传到id模块,在id模块中添加一些新的判断,如果待读取的内容和上面二者之一符合就将这其数据送到对应的输出数据中去。
暂停流水线模块小结
为了执行div,divu,madd,maddu,msub,msubu这些指令需要添加暂停流水线模块ctrl模块
该模块在前面第三部分有描述,当在执行阶段执行上述指令时ex模块会发出通向ctrl模块的请求暂停信号,然后计算完成过后就会恢复流水线的流通,该内容的实现过程如下描述:
首先以madd为例,madd是将{HO,LO}<- rs * rt + {HO,LO},当执行阶段读取到该指令是madd时,因为ex模块内敏感参数列表是全部输入信号,意思是当ex_mem模块有回传的信号和数据,或者id_ex有送来的信号和数据,只要导致了输入端的信号或者数据发生了变化ex模块就会执行,首先送来的数据有两个操作数,这两个操作数是从rs和rt寄存器中读取的数据,这两个操作数会最先被转换为补码,然后直接进行乘法运算,该内容在ex模块中有十分详细的介绍,进行乘法运算过后(极短时间内完成),就会执行
1.{HI,LO}<=从mem,mem_wb,hilo 这三个模块回写的hi,lo的值,2.
2.然后进入了madd的开始阶段,mulres赋值给hilo_temp_0,设置st allreq_for_madd_msub = 1,初始化hilo_temp1并且将cnt_0的值改变为2’b01;
3.因为stallreq_for_madd_msub = 1,所以导致stallreq的值为1,因此改变了ctrl模块 的值,让ctrl输出了stall对应的信号,stall = 6’b001111
然后下一个周期的时钟上升沿到来时,送到ex_mem的cnt_0,和hilo_temp_0回送到ex模块,然后此时stall的信号已经暂停了取指,译码,执行三阶段的进行,访存和回写继续进行,这导致从前面模块过来的大部分数据是保持不变的,比如指令的值,pc的值,这样的话进入ex模块的信号还是madd的信号,因此上面的三个步骤又会执行一次,HI,LO的值就绪,因为 cnt_i = 2’b01所以进入了第二阶段,完成了计算,并且向ctrl模块传达了取消暂停的信号,当下一个周期到来时,流水线又恢复了正常 ,div等也是这样
其他情况说明
因为mars 通过任务书的要求得到是指令存储地址从 0x00003000开始的一些列机器码,所以针对这种情况有两种解决方法
1.配合mars的起始地址,更改处理器的初始地址
2.更改生成的机器码
第一种方式难度较大,因为目前无办法让从txt文本读取的指令从0x00003000开始存,有一些比较小道的方法就是只取pc前10位来取指令,这样造成的问题就是指令条数不能超过256条,否则会出现错误,所以权衡下我还是使用第二种方法,第二种方法其实需要更改的内容不多,因为只要j指令会用到具体的指令存储地址,分支指令用的是相对偏移地址,所以真正需要修改的内容不多。
其次就是mars采用的小端法存储数据,而这里采用的是大端法存储数据,因为写得太早已经成型,后期无时间修改
雷思磊.自己动手写CPU. 北京: 电子工业出版社.2014.9
代码仍然存在部分bug,分支指令和其他指令进行了较为复杂的搭配时会出现一些费解的bug,在短暂的课设期间没有查明原因,现在暂时没有时间进行debug,需要工程文件和测试用的机器指令可以留言。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。