5.5 修改OpenMIPS以实现逻辑、位移操作和空指令
为了实现逻辑、位移操作与空指令,需要修改ID和EX模块。
5.5.1 修改译码阶段的ID模块
修改宏定义defines.v
defines.v +=
/** EXE_* 功能码 或 指令码 **/ `define EXE_AND 6'b100100 `define EXE_OR 6'b100101 `define EXE_XOR 6'b100110 `define EXE_NOR 6'b100111 `define EXE_ANDI 6'b001100 `define EXE_ORI 6'b001101 `define EXE_XORI 6'b001110 `define EXE_LUI 6'b001111 `define EXE_SLL 6'b000000 `define EXE_SLLV 6'b000100 `define EXE_SRL 6'b000010 `define EXE_SRLV 6'b000110 `define EXE_SRA 6'b000011 `define EXE_SRAV 6'b000111 `define EXE_SYNC 6'b001111 `define EXE_PREF 6'b110011 `define EXE_SPECIAL_INST 6'b000000
以下是对指令编码和指令的映射算法:
修改后的代码如下:
`include "defines.h" module id ( input wire rst, input wire[`InstAddrBus] pc_i, input wire[`InstBus] inst_i, //处于执行阶段的指令要写入的目的寄存器信息 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, //从regfile读取的数据 input wire[`RegBus] reg1_data_i, input wire[`RegBus] reg2_data_i, //送到regfile的信息 output reg reg1_read_o, output reg reg2_read_o, output reg[`RegAddrBus] reg1_addr_o, output reg[`RegAddrBus] reg2_addr_o, //送到执行阶段的信息 output reg[`AluOpBus] aluop_o, output reg[`AluSelBus] alusel_o, output reg[`RegBus] reg1_o, output reg[`RegBus] reg2_o, output reg[`RegAddrBus] wd_o, output reg wreg_o ); 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]; reg[`RegBus] imm; reg instvalid; always @ (*) begin if (rst == `RstEnable) begin aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP; wd_o <= `NOPRegAddr; wreg_o <= `WriteDisable; instvalid <= `InstValid; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; reg1_addr_o <= `NOPRegAddr; reg2_addr_o <= `NOPRegAddr; imm <= 32'h0; end else begin aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP; wd_o <= inst_i[15:11]; wreg_o <= `WriteDisable; instvalid <= `InstInvalid; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; reg1_addr_o <= inst_i[25:21]; reg2_addr_o <= inst_i[20:16]; imm <= `ZeroWord; case (op) `EXE_SPECIAL_INST: begin case (op2) 5'b00000: begin case (op3) `EXE_OR:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_OR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_AND:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_AND_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_XOR:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_XOR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_NOR:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_NOR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SLLV:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SLL_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SRLV: begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SRL_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SRAV:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SRA_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SYNC: begin wreg_o <= `WriteDisable; aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1; instvalid <= `InstValid; end default:begin end endcase end default: begin end endcase end `EXE_ORI:begin //ORI指令 wreg_o <= `WriteEnable; aluop_o <= `EXE_OR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ANDI:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_AND_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_XORI:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_XOR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LUI:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_OR_OP; alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {inst_i[15:0], 16'h0}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_PREF:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; instvalid <= `InstValid; end default:begin end endcase //case op if (inst_i[31:21] == 11'b00000000000) begin if (op3 == `EXE_SLL) begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SLL_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11]; instvalid <= `InstValid; end else if ( op3 == `EXE_SRL ) begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SRL_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11]; instvalid <= `InstValid; end else if ( op3 == `EXE_SRA ) begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SRA_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1; imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11]; instvalid <= `InstValid; end end end //if end //always endmodule
AND指令的译码过程:
ANDI指令的译码过程:
SLLV指令的译码过程
LUI指令的译码过程
SLL指令的译码过程
5.5.2 修改执行阶段的EX模块
`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_o, output reg wreg_o, output reg[`RegBus] wdata_o ); reg[`RegBus] logicout; //保存逻辑运算结果 reg[`RegBus] shiftres; //保存位移运算结果 //进行逻辑运算 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 //if end //always //进行位移运算 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 //if end //always //根据alusel_i选择最终的运算结果 always @ (*) begin wd_o <= wd_i; wreg_o <= wreg_i; case (alusel_i) `EXE_RES_LOGIC:begin wdata_o <= logicout; end `EXE_RES_SHIFT:begin wdata_o <= shiftres; end default:begin wdata_o <= `ZeroWord; end endcase end endmodule
来源:https://www.cnblogs.com/ycc1997/p/12210149.html