target
Modify the sopc that has been tested before, add data RAM for it, test the implementation of general loading instructions, and add special loading and storage instructions.
This paper discusses the load related problems caused by loading instructions, gives the solution of OpenMIPS, and verifies the solution effect.
Load storage instruction description
31-26 | 25-21 | 20-16 | 15-0 | useage | function |
---|---|---|---|---|---|
LB(100000) | base | rt | offset | lb rt,offset(base) | Read a byte from the address specified in memory, then expand the symbol to 32 bits and save it to the general register with address rt |
LBU(100100) | base | rt | offset | lbu rt,offset(base) | Ibid., signed to unsigned |
LH(100001) | base | rt | offset | lh rt,offset(base) | Read one and a half words from the load address specified in memory, then expand the symbol to 32 bits and save it to the general register with address rt. The instruction requires the address of the lowest order to be 0 |
LHU(100101) | base | rt | offset | lhu rt,offset(base) | Ibid., signed to unsigned |
LW(100011) | base | rt | offset | lw rt,offset(base) | Read a word from the load address specified in the memory and save it to the general register with address rt. the instruction has address alignment requirements, and the lowest two bits of the load address are required to be 00 |
Load address = signed_extended(offset) + GPR[base]
Firstly, the 16 bit offset symbol is extended to 32 bits, and then added to the value of the general register with address base to obtain the load address
Storage instruction description
31-26 | 25-21 | 20-16 | 15-0 | useage | function |
---|---|---|---|---|---|
SB(101000) | base | rt | offset | sb rt,offset(base) | Stores the lowest byte of the general-purpose register with address rt to the specified address in memory |
SH(101001) | base | rt | offset | sh rt,offset(base) | Store the lowest two bytes of the general-purpose register with address rt to the specified address in memory. The instruction has address alignment requirements, which requires that the lowest bit of the calculated storage address is 0 |
SW(101011) | base | rt | offset | sw rt,offset(base) | Stores the value of the general-purpose register with address rt to the specified address in memory. This instruction has address alignment requirements. It requires that the lowest two digits of the calculated storage address be 00 |
Storage address = signed_extended(offset) + GPR[base]
The 16 bit offset symbol is extended to 32 bits, and then added to the value of the general register with address base to obtain the storage address
Load store instruction usage example
Addressing by byte, in the big end mode, the high order of data is saved in the low address of memory, and the low order of data is saved in the high address of memory.
Use the sb instruction to store 0x81 data at 0x50, and the high bit of the data is stored in the low address of the memory.
Use the sh instruction to store 0x8281 at 0x54. The low order of the data is saved in the high address.
Use the sw instruction to store 0x84838281 at 0x58
Next, use the load instruction
- Use lbu to load a byte at 0x58. The read byte is 0x84, and the unsigned extension is 0x00000084 to 32 bits.
- Use lb to load a byte from 0x58. The read byte is 0x84, and the signed byte is extended to 32 bits 0xffff84.
- Use lhu to load one and a half words from 0x58. The read bytes are half words (in 32-bit Cpu, one word is 4 bytes, and half words are 2 bytes). The read byte is 0x8483. The unsigned extension to 32 bits is 0x00008483
- Use lh to load a half word from 0x5a and read 2 bytes. The read byte is 0x8281. The instruction has address alignment requirements. The minimum bit of the loaded address is 0, which is 1 at this time, which does not meet the requirements.
Loading instruction lwl,lwr description
31-26 | 25-21 | 20-16 | 15-0 | useage | function |
---|---|---|---|---|---|
LWL(100010) | base | rt | offset | lwl rt,offset(base) | Load the most significant part of a word from the load address specified in memory, without address alignment requirements. |
LWR(100110) | base | rt | offset | lwr rt,offset(base) | Load the least significant part of a word from the load address specified in memory. There is no address alignment requirement. |
lwl calculation method:
Here is the effect in big end mode
Loading address loadaddr = signed_extended(offset)+GPR[base]
n = loadaddr[1:0]
loadaddr_align = loadaddr - n;
The lwl instruction functions from the address loadaddr_ Load a word and 4 bytes at align. Save the lowest 4-n bytes of the word to the high-order of the general-purpose register with address rt and keep the low order unchanged.
lwl $1,5($0) rt = $1
lwr calculation method:
Loading address loadaddr = signed_extended(offset)+GPR[base]
n = loadaddr[1:0]
loaddr_align =loadaddr - n;
The lwr instruction functions from the address loadaddr_ Load a word and 4 bytes at align. Save the highest n+1 bytes of the word to the low bit of the general register with address rt and keep the high bit unchanged.
The combination of LWL and LWR instructions can load a word with a non aligned address, and only two instructions are needed
Description of stored instructions
31-26 | 25-21 | 20-16 | 15-0 | useage | function |
---|---|---|---|---|---|
SWL(101010) | base | rt | offset | swl rt,offset(base) | Store the high-order part of the general-purpose register with the address rt into the address specified in the memory. The last two bits of the storage address determine which bytes of the rt general-purpose register to be stored. The swl instruction has no alignment requirements for the storage instruction (store the maximum 4-n bytes of the general-purpose register with the address rt into storeaddr) |
SWR(101110) | base | rt | offset | swr rt,offset(base) | Non aligned instructions, stored to the right. Store the low-order part of the general-purpose register with address rt to the specified address in memory. The last two bits of the storage address determine which bytes of the general-purpose register with address rt are to be stored (store the lowest n+1 bytes of the general-purpose register with address rt to storeaddr) |
storeaddr =signed_extended(offset) + GPR[base]
n=storeaddr[1:0]
storeaddr_align=storeaddr-n
It is the same except that the load is changed to storage.
Implementation of loading and storing instructions
The loading instruction is decoded in the decoding stage to obtain the operation type and sub operation type, as well as the data to be stored. These information are transmitted to the execution stage, and then sent to the memory access stage. The memory access stage sets the access signal to the data memory RAM according to these information. The data read from RAM needs to be aligned and adjusted according to the type of loading instruction and loading address, and the adjusted result is written into the destination register as the final result.
Modification of data flow diagram
Compared with before, the access to data memory RAM is added in the memory access stage. At the same time, the data written to the destination register may be the result of the execution stage or the data loaded from RAM in the memory access stage. Therefore, add a selector in the memory access stage to select.
Modification of system structure
Modification of code module
Decoding stage
id.v
The decoding phase ID increases the output signal inst_o instruction in the decoding stage, the value will be passed to the execution stage, and the ex module uses the value of the signal (instruction in the decoding stage) to calculate the loading and storage address mem_addr_o.
`include "define.v" module id( input wire rst, input wire[`InstAddrBus] pc_i, input wire[`InstBus] inst_i, input wire[`RegBus] reg1_data_i, input wire[`RegBus] reg2_data_i, input wire is_in_delayslot_i,//Whether it is in the delay slot instruction //Information sent to regfile output reg reg1_read_o, output reg reg2_read_o, output reg[`RegAddrBus] reg1_addr_o, output reg[`RegAddrBus] reg2_addr_o, //Information sent to the execution phase 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, //The result of an instruction in execution input wire ex_wreg_i, input wire[`RegBus] ex_wdata_i, input wire[`RegAddrBus] ex_wd_i, input wire[`AluOpBus] ex_aluop_i, //The operation result of the instruction in the memory access stage input wire mem_wreg_i, input wire[`RegBus] mem_wdata_i, input wire[`RegAddrBus] mem_wd_i, output wire stallreq, output reg next_inst_in_delayslot_o,//Is the next instruction a delay slot output reg branch_flag_o,//Whether transfer occurs output reg[`RegBus] branch_target_address_o,//Destination address of transfer to output reg[`RegBus] link_addr_o,//Return address of the transfer instruction to be saved output reg is_in_delayslot_o,//Whether the currently decoded instruction is in the delay slot output wire[`RegBus] inst_o //Newly added output interface ); 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;//Save the address of the second instruction after the instruction in the current decoding stage wire[`RegBus] pc_plus_4;//Save the instruction address immediately following the instruction in the current decoding stage wire[`RegBus] imm_sll2_signedext;//The offset in the corresponding branch instruction is shifted to the left by two bits, and then the symbol is extended to the value of 32 bits reg[`RegBus] imm; reg instvalid; assign stallreq = `NoStop;//This signal will be assigned a value when loading and storing instructions are realized assign imm_sll2_signedext = {{14{inst_i[15]}},inst_i[15:0],2'b00}; //imm_sll2_signedext shifts the offset in the corresponding branch instruction by two bits to the left, and then extends the symbol to the value of 32 bits assign pc_plus_8 = pc_i+8; assign pc_plus_4 = pc_i+4; assign stallreq = `NoStop; assign inst_o = inst_i;//Instructions in decoding stage always @ (*) begin if (rst == `RstEnable) begin aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP;//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; link_addr_o <= `ZeroWord;//Return address of the transfer instruction to be saved branch_target_address_o <= `ZeroWord;//Destination address of transfer to branch_flag_o <= `NotBranch;//No transfer next_inst_in_delayslot_o <= `NotInDelaySlot;//Is the next instruction in the delay slot end else begin //Initialize first 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];//rs reg2_addr_o <= inst_i[20:16];//rt imm <= `ZeroWord; link_addr_o <= `ZeroWord; branch_target_address_o <= `ZeroWord; branch_flag_o <= `NotBranch; next_inst_in_delayslot_o <= `NotInDelaySlot; case (op)//Instruction code `EXE_SPECIAL_INST: begin //The instruction code is SPECIAL case(op2)//Function code 5'b00000: begin case(op3) //Determine which instruction is based on the function code `EXE_OR: begin //or R-type instruction rs|rt - > Rd 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;//R rs&rt ->rd 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;// R rs^rt ->rd 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;// R rs~|rt ->rd 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_SRLV_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_SRAV_OP; alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SYNC:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_NOP_OP; alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MFHI:begin//Assign the value of the special register hi to the register with address rd wreg_o <= `WriteEnable; aluop_o <= `EXE_MFHI_OP; alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_MFLO:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_MFLO_OP; alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_MTHI:begin//Hi < - RS write special register wreg_o <= `WriteEnable; aluop_o <= `EXE_MTHI_OP; alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_MTLO:begin //Lo < - RS write special register wreg_o <= `WriteEnable; aluop_o <= `EXE_MTLO_OP; reg1_read_o <= 1'b1;//rs reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_MOVN:begin//Judge if the value of rt register is not 0, assign the value of rs to rd, otherwise the value of rd remains unchanged //wreg_o <= `WriteEnable; aluop_o <= `EXE_MOVN_OP; alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; //reg2_ The value of O is the value of the register with address rt if(reg2_o != `ZeroWord)begin wreg_o <= `WriteEnable; end else begin wreg_o <= `WriteDisable; end end `EXE_MOVZ:begin //Judge if the value of rt register is 0, assign the value of rs to rd, otherwise the value of rd remains unchanged aluop_o <= `EXE_MOVZ_OP; alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; if(reg2_o == `ZeroWord)begin wreg_o <= `WriteEnable; end else begin wreg_o <= `WriteDisable; end end `EXE_SLT:begin//slt instruction Rd < - (RS < RT) wreg_o <= `WriteEnable; aluop_o <= `EXE_SLT_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SLTU:begin //sltu instruction wreg_o <= `WriteEnable; aluop_o <= `EXE_SLTU_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_ADD:begin//rd<-rs+rt wreg_o <= `WriteEnable; aluop_o <= `EXE_ADD_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_ADDU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDU_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SUB:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SUB_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_SUBU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SUBU_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MULT:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_MULT_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MULTU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_MULTU_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_DIV:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_DIV_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_DIVU:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_DIVU_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_JR:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_JR_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1;//The rs register needs to be used reg2_read_o <= 1'b0; wd_o <= inst_i[15:11]; link_addr_o <= pc_plus_8;//Return address branch_target_address_o <= reg1_o;//Destination address of transfer to branch_flag_o <= `Branch;//Whether transfer occurs next_inst_in_delayslot_o <= `InDelaySlot;//The next instruction is not in the delay slot instvalid <= `InstValid; end `EXE_JALR:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_JALR_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; wd_o <= inst_i[15:11]; link_addr_o <= pc_plus_8; branch_target_address_o <= reg1_o; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; instvalid <= `InstValid; end default:begin end endcase end default:begin //aluop_o <= `EXE_NOP_OP; //alusel_o <= `EXE_RES_OP; //wd_o <= `NOPRegAddr; //wreg_o <= `WriteDisable; //instvalid <= `InstValid; //reg1_read_o <= `ReadDisable; //reg2_read_o <= `ReadDisable; //reg1_addr_o <= inst_i[25:21]; //reg2_addr_o <= inst_i[20:16]; end endcase//op3 end // 5'b00000 `EXE_J:begin wreg_o <= `WriteDisable;//Whether to write to the destination register in the decoding stage aluop_o <= `EXE_J_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; link_addr_o <= `ZeroWord; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; instvalid <= `InstValid; branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};//Address of transfer destination end `EXE_JAL:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_JAL_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0; wd_o <= 5'b11111;//Address register $1 of destination register to write link_addr_o <= pc_plus_8;//Return address of the transfer instruction to be saved branch_flag_o <= `Branch;//Flag of transfer occurrence next_inst_in_delayslot_o <= `InDelaySlot; instvalid <= `InstValid; branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00}; end `EXE_BEQ:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_BEQ_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1;//Need to compare rs and rt reg2_read_o <= 1'b1; instvalid <= `InstValid; if(reg1_o == reg2_o)begin //If the value of rs is reg1_ The value of O and rd is reg2_o equal transfer branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BGTZ:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_BGTZ_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1;//rs reg2_read_o <= 1'b0; instvalid <= `InstValid; if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))begin branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BLEZ:begin wreg_o <= `WriteDisable;//Whether to write to the destination register in the decoding stage aluop_o <= `EXE_BLEZ_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; if((reg1_o[31] == 1'b1)&&(reg1_o != `ZeroWord))begin branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BNE:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_BNE_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; if(reg1_o != reg2_o)begin branch_target_address_o <= pc_plus_4+imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_REGIMM_INST:begin case(op4) `EXE_BLTZAL:begin//bltzal wreg_o <= `WriteEnable; aluop_o <= `EXE_BGEZAL_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; link_addr_o <= pc_plus_8; wd_o <= 5'b11111; instvalid <= `InstValid; if(reg1_o[31] == 1'b1) begin//reg1_o<0 branch_target_address_o <= pc_plus_4+imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BLTZ:begin//bltz wreg_o <= `WriteDisable; aluop_o <= `EXE_BGEZAL_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; if(reg1_o[31] == 1'b1)begin branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BGEZ:begin//bgez wreg_o <= `WriteDisable; aluop_o <= `EXE_BGEZ_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; if(reg1_o[31] == 1'b0)begin//The value of rs is greater than or equal to 0 branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end `EXE_BGEZAL:begin//bgezal wreg_o <= `WriteEnable; aluop_o <= `EXE_BGEZAL_OP; alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; link_addr_o <= pc_plus_8; wd_o <= 5'b11111; instvalid <= `InstValid; if(reg1_o[31] == 1'b0)begin branch_target_address_o <= pc_plus_4 + imm_sll2_signedext; branch_flag_o <= `Branch; next_inst_in_delayslot_o <= `InDelaySlot; end end default:begin end endcase // op2 end `EXE_ORI:begin //ORI instruction 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]}; //Immediate 0 extension wd_o <= inst_i[20:16]; // Read rt address instvalid <= `InstValid; end `EXE_ANDI:begin //andi 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];//rt instvalid = `InstValid; end `EXE_XORI:begin//xori 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//lui wreg_o <= `WriteEnable;//Notice the typographical errors in the book 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//pref 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 */ `EXE_SLTI:begin //slti rt <- (rs < (sign_extended)immediate) wreg_o <= `WriteEnable; aluop_o <= `EXE_SLT_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_SLTIU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_SLTU_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ADDI:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDI_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_ADDIU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDIU_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; imm <= {{16{inst_i[15]}},inst_i[15:0]}; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LB:begin//Write the loading result to the destination register wreg_o <= `WriteEnable; aluop_o <= `EXE_LB_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1;//Calculating the load destination address requires the register value with address base reg2_read_o <= 1'b0; wd_o <= inst_i[20:16];//Destination register address instvalid <= `InstValid; end `EXE_LBU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_LBU_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LH:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_LH_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LHU:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_LHU_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LW:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_LW_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LWL:begin//The loading result to the left needs to be written to the destination register [20:16] wreg_o <= `WriteEnable; aluop_o <= `EXE_LWL_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_LWR:begin//Load right wreg_o <= `WriteEnable; aluop_o <= `EXE_LWR_OP; alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; wd_o <= inst_i[20:16]; instvalid <= `InstValid; end `EXE_SB:begin //There is no need to write a general register to calculate the value of the register whose address is base that needs to be used to store the target address wreg_o <= `WriteDisable; aluop_o <= `EXE_SB_OP; reg1_read_o <= 1'b1; //[25:21] reg1_addr_o ======> base reg2_read_o <= 1'b1; instvalid <= `InstValid; alusel_o <= `EXE_RES_LOAD_STORE; end `EXE_SH:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_SH_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; alusel_o <= `EXE_RES_LOAD_STORE; end `EXE_SW:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_SW_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; alusel_o <= `EXE_RES_LOAD_STORE; end `EXE_SWL:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_SWL_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; alusel_o <= `EXE_RES_LOAD_STORE; end `EXE_SWR:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_SWR_OP; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; alusel_o <= `EXE_RES_LOAD_STORE; end `EXE_SPECIAL2_INST:begin//(op) case(op3) `EXE_CLZ:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_CLZ_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_CLO:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_CLO_OP; alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid; end `EXE_MUL:begin wreg_o <= `WriteEnable; aluop_o <= `EXE_MUL_OP; alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MADD:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_MADD_OP; alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MADDU:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_MADDU_OP; alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MSUB:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_MSUB_OP; alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end `EXE_MSUBU:begin wreg_o <= `WriteDisable; aluop_o <= `EXE_MSUBU_OP; alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid; end default:begin end endcase //EXE_SPECIAL_INST2 case end default:begin end endcase //case op if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sra 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 //endcase //end end //if end end //always /* Data push forward Give reg1_o two cases are added in the assignment process 1:If the register to be read by Regfile module reading port 1 is the destination register to be written in the execution stage, the result of the execution stage is directly transferred to ex_wdata_i as reg1_ Value of O 2:If the register to be read by Regfile module reading port 1 is the destination register to be written in the memory access stage, the result of the memory access stage is directly mem_wdata_i as reg1_ Value of O*/ always @ (*) begin if(rst == `RstEnable) begin reg1_o <= `ZeroWord; end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_o)) begin reg1_o <= ex_wdata_i; end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_o)) begin reg1_o <= mem_wdata_i; end else if(reg1_read_o == 1'b1) begin reg1_o <= reg1_data_i; end else if(reg1_read_o == 1'b0) begin reg1_o <= imm; end else begin reg1_o <= `ZeroWord; end end always @ (*) begin if(rst == `RstEnable) begin reg2_o <= `ZeroWord; end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_o)) begin reg2_o <= ex_wdata_i; end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_o)) begin reg2_o <= mem_wdata_i; end else if(reg2_read_o == 1'b1) begin reg2_o <= reg2_data_i; end else if(reg2_read_o == 1'b0) begin reg2_o <= imm; end else begin reg2_o <= `ZeroWord; end end //Output variable is_in_delayslot_o indicates whether the instruction in the current decoding stage is a delay slot instruction always @ (*)begin if(rst == `RstEnable)begin is_in_delayslot_o <= `NotInDelaySlot; end else begin //Directly equal to is_in_delayslot_i is_in_delayslot_o <= is_in_delayslot_i; end end endmodule
id_ex.v
`include "define.v" //At the rising edge of the clock cycle, the result of the decoding stage is passed to the execution stage*/ module id_ex( input wire clk, input wire rst, //Information transmitted from decoding stage 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, //Information from control module input wire[5:0] stall , input wire[`RegBus] id_link_address, input wire id_is_in_delayslot, input wire next_inst_in_delayslot_i, input wire[`RegBus] id_inst, //The instruction that the signal from the id module is currently in the decoding stage //Information passed to the execution phase 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_o, output reg[`RegBus] ex_inst //The instruction passed to the ex module that is currently in the execution phase ); 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; ex_inst <= `ZeroWord; end else if(stall[2] == `Stop && stall[3] == `NoStop)begin//Execute stop memory access continue 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//Execution continues 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; ex_inst <= id_inst; is_in_delayslot_o <= next_inst_in_delayslot_i; /*end else 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; end*/ end end endmodule
Execution module
ex.v
`include "define.v" //ex.v execution module module ex( //Information sent from decoding stage to execution stage 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, input wire rst, //HILO module gives the value of hi and lo registers input wire[`RegBus] hi_i, input wire[`RegBus] lo_i, //Whether the instruction in the write back phase should write hi and lo is used to detect the data related problems caused by hi and lo registers input wire[`RegBus] wb_hi_i, input wire[`RegBus] wb_lo_i, input wire wb_whilo_i, //Whether the instruction in the memory access stage should write hi and lo is used to detect the data related problems caused by hi and lo registers input wire[`RegBus] mem_hi_i, input wire[`RegBus] mem_lo_i, input wire mem_whilo_i, //Added input port input wire[`DoubleRegBus] hilo_temp_i,//Save multiplication results input wire[1:0] cnt_i,//Which cycle is in the implementation phase //Add input from division module input wire[`DoubleRegBus] div_result_i, input wire div_ready_i, //The return address to be saved for the branch instruction in the execution stage input wire[`RegBus] link_address_i, //Whether the instruction in the current execution stage is in the delay slot input wire is_in_delayslot_i, //New input port inst_i. Its value is the instruction currently in execution input wire[`RegBus] inst_i,//Instructions currently in execution //Write operation request of instruction in execution phase to lo and hi registers output reg[`RegBus] hi_o, output reg[`RegBus] lo_o, output reg whilo_o, //Results of execution output reg[`RegAddrBus] wd_o, output reg wreg_o, output reg[`RegBus] wdata_o, output reg stallreq, output reg[`DoubleRegBus] hilo_temp_o, output reg[1:0] cnt_o, //Output added to division module output reg[`RegBus] div_opdata1_o, output reg[`RegBus] div_opdata2_o, output reg div_start_o, output reg signed_div_o, //output reg is_in_delayslot_o, //The following new output interfaces are prepared for loading and storing instructions output wire[`AluOpBus] aluop_o, //Subtype to be operated on during execution output wire[`RegBus] mem_addr_o,//Load the memory address corresponding to the storage instruction output wire[`RegBus] reg2_o//Store the data to be stored by the instruction, or the address of the destination register to be loaded by the LWL and LWR instructions ); //Save the result of logical operation reg[`RegBus] logicout; //Save the result of the shift operation reg[`RegBus] shiftres; //Save the results of the move operation reg[`RegBus] moveres; //Save the latest values of hi and lo registers reg[`RegBus] HI; reg[`RegBus] LO; //Is the pipeline suspended due to division reg stallreq_for_div; /***********************Chapter 7 new definitions of some variables***********************/ wire ov_sum;//Save overflow wire reg1_eq_reg2;//Is the first operand equal to the second operand wire reg1_lt_reg2;//Is the first operand less than the second operand reg[`RegBus] arithmeticres;//Save the result of arithmetic operation reg[`DoubleRegBus] mulres;//Save the result of multiplication wire[`RegBus] reg2_i_mux;//Save the input second operand reg2_ Complement of I wire[`RegBus] reg1_i_not;//Save the first operand entered reg1_i take the inverse value wire[`RegBus] result_sum;//Save addition results wire[`RegBus] opdata1_mult;//Multiplicand in multiplication operation wire[`RegBus] opdata2_mult;//Multiplier in multiplication operation wire[`DoubleRegBus] hilo_temp;//Temporarily save the multiplication result with a width of 64 bits reg [`DoubleRegBus] hilo_temp1; reg stallreq_for_madd_msub; //aluop_o will be passed to the storage access stage, which will be used to determine the loading and storage types assign aluop_o = aluop_i; //mem_addr_o will be passed to the memory access stage, which is the memory address corresponding to the loading and storage instructions. Here reg1_i is the value of the general-purpose register with address base in the loading and storage instruction //By calculating mem_addr_o. Understand why the ID module adds an output interface Inst in the decoding stage_ o assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]}; //reg2_i is the data to be stored by the storage instruction, or the original value of the destination register to be loaded by the LWL and LWR instructions, which is passed through reg2_o interface transfer to memory access stage assign reg2_o = reg2_i; /******************************************************************* ** Paragraph 1: according to aluop_ The operator type indicated by I** *******************************************************************/ always @ (*) begin//1 if(rst == `RstEnable) begin//2 logicout <= `ZeroWord; end//2 else begin//3 case(aluop_i)//4 `EXE_OR_OP:begin//5 logical or logicout <= reg1_i|reg2_i; end `EXE_AND_OP: begin //Logic and logicout <= reg1_i®2_i; end `EXE_NOR_OP:begin //Logical or not logicout <= ~(reg1_i|reg2_i); end `EXE_XOR_OP:begin //Logical XOR logicout <= reg1_i^reg2_i; end default:begin//6 logicout <= `ZeroWord; end//6 endcase//4 end//3 end//1 always @ (*) begin if(rst == `RstEnable)begin shiftres <= `ZeroWord; end else begin case(aluop_i) `EXE_SLL_OP:begin //Logical shift left shiftres <= reg2_i << reg1_i[4:0]; end `EXE_SRL_OP:begin //Logical shift right shiftres <= reg2_i >> reg1_i[4:0]; end `EXE_SRA_OP:begin//Arithmetic shift right 1 shiftres <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) |/*rt Shift sa bit to the right*/ reg2_i>>reg1_i[4:0]; end default:begin shiftres <= `ZeroWord; end endcase end end /****************************************************************** ****The third paragraph: get the latest value of hi and lo registers. Here we need to solve the problems related to data**** ******************************************************************/ 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};//The instructions in the memory access stage shall be written to hi and lo registers end else if(wb_whilo_i == `WriteEnable)begin {HI,LO} <= {wb_hi_i,wb_lo_i};//The instruction in the write back phase should write hi and lo registers end end /******************************************************************* ******************Section 4: MFHI,MFLO,MOVN,MOVZ instructions******************** *******************************************************************/ always @ (*) begin if(rst == `RstEnable) begin moveres <= `ZeroWord; end else begin moveres <= `ZeroWord; case(aluop_i) `EXE_MFHI_OP:begin //rd<-hi moveres <= HI;//The value of HI is the result of the move operation end `EXE_MFLO_OP:begin //rd<-lo moveres <= LO; end `EXE_MOVN_OP:begin //rd<-rs moveres <= reg1_i; end `EXE_MOVZ_OP:begin //rd<-rs moveres <= reg1_i; end default:begin end endcase end end /*************************************************************** *******For mthi and mtlo instructions, you need to give while_ o,hi_ o,lo_ Value of O******* ***************************************************************/ always @ (*)begin if(rst == `RstEnable) begin whilo_o <= `WriteDisable; hi_o <= `ZeroWord; lo_o <= `ZeroWord; end else if(aluop_i == `EXE_MTHI_OP)begin whilo_o <= `WriteEnable; hi_o <= reg1_i; lo_o <= LO;//Write HI register, so LO remains unchanged end else if(aluop_i == `EXE_MTLO_OP)begin whilo_o <= `WriteEnable; hi_o <= HI; lo_o <= reg1_i; end else begin whilo_o <= `WriteDisable; hi_o <= `ZeroWord; lo_o <= `ZeroWord; end end //end //endmodule /************************************************************* ******************Paragraph 5: calculate the values of the following five variables****************** *************************************************************/ /*(1)If it is subtraction or signed comparison, reg2_i_mux equals the second operand reg2_ Complement of I, Otherwise reg2_i_mux is equal to the second operand 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; /*(2)There are three situations: A:If it is an addition operation, reg2_i_mux is the second operand reg2_i. So result_sum is the result of addition B:In case of subtraction, reg2_i_mux is the second operand reg2_i's complement, so result_sum is the result of subtraction C:If it is a signed comparison operation, reg2_i_mux is the second operand reg2_i's complement, so result_sum is subtraction For the result of the operation, you can judge whether the result of subtraction is less than 0, and then judge the first operand reg1_ Is I less than the second operand reg2_i*/ assign result_sum = reg1_i + reg2_i_mux; /*(3)Calculate whether the overflow occurs. When the addition instruction add and addi and the subtraction instruction sub are executed, it is necessary to judge whether the overflow occurs when one of the following two conditions is met A:reg1_i Is a positive number, reg2_i_mux is positive, but the sum of the two is negative B:reg1_i Negative, reg2_i_mux is negative, but the sum of the two is positive*/ //I don't understand this. I understand it on March 10, 2022 assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31])&&(!result_sum[31])); /*(4)There are two ways to calculate whether operand 1 is less than operand 2: A:aluop_i Is EXE_SLT_OP stands for signed comparison operation 1.reg1_i Negative, reg2_i is a positive number, obviously reg1_i is less than reg2_i 2.reg1_i Positive, reg2_i is a positive number and reg1_i minus reg2_ When the value of I is less than 0(result_sum is negative), reg1_i is less than reg2_i 3.reg1_i Negative, reg2_i is negative and reg1_i minus reg2_ When the value of I is less than 0(result_sum is negative), reg1_i is less than reg2_i B:When comparing unsigned numbers, the comparison operator is directly used to compare reg1_i and reg2_i*/ assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP))?((reg1_i[31]&&!reg2_i[31])||(!reg1_i[31]&&!reg2_i[31]&&result_sum[31])||(reg1_i[31]&®2_i[31]&&result_sum[31])):(reg1_i<reg2_i); //(5) The operand 1 is inversely assigned to reg1 bit by bit_ i_ not assign reg1_i_not = ~reg1_i; /***************************************************************** *****Paragraph 6: assign value to arithmetics variable according to different arithmetic operation types******* *****************************************************************/ always @ (*) begin if(rst == `RstEnable)begin arithmeticres <= `ZeroWord; end else begin case(aluop_i) //Select operation type `EXE_SLT_OP,`EXE_SLTU_OP:begin arithmeticres <= reg1_lt_reg2;//Comparison operation end `EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:begin arithmeticres <= result_sum;//Addition operation end `EXE_SUB_OP,`EXE_SUBU_OP:begin arithmeticres <= result_sum;//Subtraction operation end `EXE_CLZ_OP:begin //Count operation clz 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]?20:reg1_i[0]?31:32; end `EXE_CLO_OP:begin //Counting operation clo 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 /***************************************************************** ************************Paragraph 7: multiplication*********************** *****************************************************************/ /*(1)The multiplicand instructions MADD and MSUB that obtain the multiplication operation are signed multiplication if the first operand reg1_i is a negative number Then take reg1_ The complement of I is the multiplicand, on the contrary, reg1 is used directly_ I is the multiplicand. If it is a signed multiplication and the multiplicand is negative, the complement is taken*/ 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; //(2) Obtain the multiplier of the multiplication operation. If it is a signed multiplication and the multiplier is negative, take the complement 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; //(3) Get the temporary multiplication result and save it in the variable Hilo_ In temp assign hilo_temp = opdata1_mult * opdata2_mult; /*(4)The temporary multiplication result is corrected, and the final multiplication result is saved in the variable mulres. There are mainly the following two points A:If it is signed multiplication instruction mult and mul, the temporary multiplication result needs to be corrected as follows: A1:If both the multiplicand and the multiplier are positive and negative, Hilo is required for the temporary multiplication result_ Temp finds the complement and assigns it to mulres as the final multiplication result A2:If the multiplicand has the same sign as the multiplier, then Hilo_ The value of temp is assigned to the variable mulres as the final multiplication result B:If it is an unsigned multiplication instruction multu, then Hilo_ The value of temp is assigned to the variable mulres as the final multiplication result */ always @ (*) begin//1 if(rst == `RstEnable) begin//2 mulres <= {`ZeroWord,`ZeroWord}; end/*2*/ else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))begin//3 if(reg1_i[31]^reg2_i[31] == 1'b1)begin//4 the multiplicand and multiplier are positive and negative mulres <= ~hilo_temp+1; end/*4*/ else begin//5 the multiplicand and multiplier have the same sign mulres <= hilo_temp; end//5 end/*3*/ else begin//6 unsigned multiplication mulres <= hilo_temp; end//6 end//1 /***************************************************************** ****************Paragraph 8: determine the data to be written to the destination register***************** *****************************************************************/ always @ (*)begin wd_o <= wd_i; //If it is an add,addi,sub,subi instruction and overflow occurs, set wreg_o is WriteEnable, indicating that the destination register is not written if(((aluop_i == `EXE_ADD_OP)||(aluop_i == `EXE_ADDI_OP)||(aluop_i == `EXE_SUB_OP))&&(ov_sum == 1'b1))begin wreg_o <= `WriteDisable; end else begin wreg_o <= wreg_i; end case(alusel_i) `EXE_RES_LOGIC:begin wdata_o <= logicout; end `EXE_RES_SHIFT:begin wdata_o <= shiftres; end `EXE_RES_MOVE:begin wdata_o <= moveres; end `EXE_RES_ARITHMETIC:begin//Simple arithmetic operation instructions other than multiplication wdata_o <= arithmeticres; end `EXE_RES_MUL:begin//Multiplication instruction mul wdata_o <= mulres[31:0]; end `EXE_RES_JUMP_BRANCH:begin wdata_o <= link_address_i; end default:begin wdata_o <= `ZeroWord; end endcase end//always /**************************************************************** ********************Paragraph 10: multiplication and accumulation, multiplication and subtraction************************ ****************************************************************/ //MADD MADDU MSUB MSUBU instruction always @ (*) begin if(rst == `RstEnable) begin hilo_temp_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 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 //Execute the first clock cycle hilo_temp_o <= mulres;//At this time, the multiplication result mulres is passed through the interface hilo_temp_o output to EX/MEM module for use in the next clock cycle cnt_o <= 2'b01; hilo_temp1 <= {`ZeroWord,`ZeroWord}; stallreq_for_madd_msub <= `Stop;//Multiply accumulate instruction requests pipeline pause end else if(cnt_i == 2'b01) begin//Execute the second clock cycle hilo_temp_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 2'b10; hilo_temp1 <= hilo_temp_i+{HI,LO}; //hilo_temp_i is the multiplication result of the last clock cycle stallreq_for_madd_msub <= `NoStop;//When the execution of multiply accumulate instruction ends, the pipeline pause is no longer requested end end `EXE_MSUB_OP,`EXE_MSUBU_OP:begin if(cnt_i == 2'b00) begin hilo_temp_o <= ~mulres+1; cnt_o <= 2'b01; stallreq_for_madd_msub <= `Stop; end else if(cnt_i == 2'b01) begin hilo_temp_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 2'b10; hilo_temp1 <= hilo_temp_i +{HI,LO}; stallreq_for_madd_msub <= `NoStop; end end default:begin hilo_temp_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 2'b00; stallreq_for_madd_msub <= `NoStop; end endcase end end /**************************************************************** ******Paragraph 12: output DIV module control information and obtain the results given by DIV module********* ****************************************************************/ always @ (*) begin if(rst == `RstEnable)begin stallreq_for_div <= `NoStop; div_opdata1_o <= `ZeroWord; div_opdata2_o <= `ZeroWord; div_start_o <= `DivStop; signed_div_o <= 1'b0; end else begin stallreq_for_div <= `NoStop; div_opdata1_o <= `ZeroWord; div_opdata2_o <= `ZeroWord; div_start_o <= `DivStop; signed_div_o <= 1'b0; case(aluop_i) `EXE_DIV_OP:begin if(div_ready_i == `DivResultNotReady) begin div_opdata1_o <= reg1_i;//Divisor div_opdata2_o <= reg2_i;//Divisor div_start_o <= `DivStart;//Start division signed_div_o <= 1'b1;//Signed Division stallreq_for_div <= `Stop;//Request pipeline pause end else if(div_ready_i == `DivResultReady) begin div_opdata1_o <= reg1_i; div_opdata2_o <= reg2_i; div_start_o <= `DivStop;//End Division signed_div_o <= 1'b1; stallreq_for_div <= `NoStop;//Pipeline pause is no longer requested end else begin div_opdata1_o <= `ZeroWord; div_opdata2_o <= `ZeroWord; div_start_o <= `DivStop; signed_div_o <= 1'b0; stallreq_for_div <= `NoStop; end end `EXE_DIVU_OP:begin if(div_ready_i == `DivResultNotReady) begin div_opdata1_o <= reg1_i; div_opdata2_o <= reg2_i; div_start_o <= `DivStart; signed_div_o <= 1'b0;//Unsigned Division stallreq_for_div <= `Stop; end else if(div_ready_i == `DivResultReady) begin div_opdata1_o <= reg1_i; div_opdata2_o <= reg2_i; div_start_o <= `DivStop; signed_div_o <= 1'b0; stallreq_for_div <= `NoStop; end else begin div_opdata1_o <= `ZeroWord; div_opdata2_o <= `ZeroWord; div_start_o <= `DivStop; signed_div_o <= 1'b0; stallreq_for_div <= `NoStop; end end default:begin end endcase end end /**************************************************************** *********************Paragraph 11: suspension of assembly lines************************* ****************************************************************/ //At present, only multiply accumulate and multiply subtract instructions will cause pipeline pause, so stallreq=stallreq_for_madd_msub always @ (*) begin stallreq = stallreq_for_madd_msub || stallreq_for_div; end /**************************************************************** ****************Paragraph 9: determine (modify) the operation information of hi and lo registers********* ****************************************************************/ always @ (*)begin if(rst == `RstEnable) begin whilo_o <= `WriteDisable; hi_o <= `ZeroWord; lo_o <= `ZeroWord; end else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MULTU_OP))begin //mult,multu instruction whilo_o <= `WriteEnable; hi_o <= mulres[63:32]; lo_o <= mulres[31:0]; end else if(aluop_i == `EXE_MTHI_OP)begin whilo_o <= `WriteEnable; hi_o <= reg1_i; lo_o <= LO;//Write HI register, so LO remains unchanged end else if(aluop_i == `EXE_MTLO_OP)begin whilo_o <= `WriteEnable; hi_o <= HI; lo_o <= reg1_i; end else if((aluop_i == `EXE_MSUB_OP)||(aluop_i == `EXE_MSUBU_OP))begin whilo_o <= `WriteEnable; hi_o <= hilo_temp1[63:32]; lo_o <= hilo_temp1[31:0]; end else if((aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MADDU_OP))begin whilo_o <= `WriteEnable; hi_o <= hilo_temp1[63:32]; lo_o <= hilo_temp1[31:0]; end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))begin whilo_o <= `WriteEnable; hi_o <= div_result_i[63:32]; lo_o <= div_result_i[31:0]; end else begin whilo_o <= `WriteDisable; hi_o <= `ZeroWord; lo_o <= `ZeroWord; end end endmodule
ex_mem.v
`include "define.v" module ex_mem( input wire clk, input wire rst, //Information from control module input wire[5:0] stall, //Information from execution phase 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 interface added for loading and storing instructions input wire[`AluOpBus] ex_aluop, //Subtype to be operated on during execution input wire[`RegBus] ex_mem_addr,//The memory address corresponding to the loading and storage instructions in the execution stage input wire[`RegBus] ex_reg2,//The execution stage stores the data to be stored by the instruction, or the original value of the destination register to be written by the LWL and LWR instructions //Added input interface input wire[`DoubleRegBus] hilo_i, input wire[1:0] cnt_i, //input wire[5:0] stall, //Information sent to the storage access stage 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 , //Added output port output reg[`DoubleRegBus] hilo_o, output reg[1:0] cnt_o, //Output interface added for loading and storing instructions output reg[`AluOpBus] mem_aluop,//The subtype of the instruction to be operated in the memory access stage output reg[`RegBus] mem_mem_addr,//The memory address corresponding to the loading and storage instructions in the memory access stage output reg[`RegBus] mem_reg2//The memory access stage stores the data to be stored by the instruction, or the original value of the destination register to be written by LWL and LWR ); /*When the pipeline execution phase is suspended, the signal Hilo is input_ I through output interface hilo_o send out, Input signal cnt_i via output interface cnt_o send out. The rest of the time, hilo_o = 0,cnt_o is also 0.*/ 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_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 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_o <= hilo_i; cnt_o <= 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_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 2'b00; mem_aluop <= ex_aluop; mem_mem_addr <= ex_mem_addr; mem_reg2 <= ex_reg2; end else begin hilo_o <= hilo_i; cnt_o <= cnt_i; end //if end //always endmodule
Memory access module
mem.v
`include "define.v" //mem.v storage access //The results of the input execution phase are directly used as the output module mem( input wire rst, input wire clk, //Information from execution phase 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, //Add an interface, information from the memory access stage, and add an access interface to the data memory RAM input wire [`AluOpBus]aluop_i, //The subtype of the operation to be performed by the instruction in the memory access stage input wire [`RegBus] mem_addr_i,//The memory address corresponding to the loading and storage instruction in the memory access stage input wire [`RegBus] reg2_i, //New interface information from external data memory RAM input wire[`RegBus] mem_data_i,//Data read from ram //Results of the deposit access phase output reg[`RegAddrBus] wd_o, output reg wreg_o, output reg[`RegBus] wdata_o, output reg[`RegBus] hi_o, output reg[`RegBus] lo_o, output reg whilo_o, //Add an interface to send the information to the external data memory RAM output reg[`RegBus] mem_addr_o,//ram address to access output wire mem_we_o,//Is it a write operation? Is it a write operation output reg[3:0] mem_sel_o,//Byte select signal output reg[`RegBus] mem_data_o,//Address to write to data store output reg mem_ce_o//Data memory enable signal ); wire[`RegBus] zero32; reg mem_we; assign mem_we_o = mem_we;//Read and write signals of external data memory ram assign zero32 = `ZeroWord; always @ (*) begin if(rst == `RstEnable) begin wd_o <= `NOPRegAddr; wreg_o <= `WriteDisable; wdata_o <= `ZeroWord; hi_o <= `ZeroWord; lo_o <= `ZeroWord; whilo_o <= `WriteDisable; mem_addr_o <= `ZeroWord; mem_we <= `WriteDisable; mem_sel_o <= 4'b0000; mem_data_o <= `ZeroWord; mem_ce_o <= `ChipDisable; end else begin wd_o <= wd_i; wreg_o <= wreg_i; wdata_o <= wdata_i; hi_o <= hi_i; lo_o <= lo_i; whilo_o <= whilo_i; mem_we <= `WriteDisable; mem_addr_o <= `ZeroWord; mem_sel_o <= 4'b1111; mem_ce_o <= `ChipDisable; case(aluop_i)//Subtype of operation to be performed in memory access stage `EXE_LB_OP:begin //Read a byte, expand unsigned to 32 bits, and save it in the register with address rt mem_addr_o <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0])//The last two digits of the ram address to be accessed 2'b00:begin //Read data memory ram at 0x mem_ addr_ Bytes at I [1:0] wdata_o <={{24{mem_data_i[31]}},mem_data_i[31:24]}; //Highest position mem_sel_o <= 4'b1000;//0x0 end 2'b01:begin wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};//Secondary high mem_sel_o <= 4'b0100;//0x1 end 2'b10:begin wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]}; mem_sel_o <= 4'b0010;//0x2 end 2'b11:begin wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]}; mem_sel_o <= 4'b0001; //0x3 end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_LBU_OP:begin mem_addr_o <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_o <= {{24{1'b0}},mem_data_i[31:24]}; mem_sel_o <= 4'b1000; end 2'b01:begin wdata_o <= {{24{1'b0}},mem_data_i[23:16]}; mem_sel_o <= 4'b0100; end 2'b10:begin wdata_o <= {{24{1'b0}},mem_data_i[15:8]}; mem_sel_o <= 4'b0010; end 2'b11:begin wdata_o <= {{24{1'b0}},mem_data_i[7:0]}; mem_sel_o <= 4'b0001; end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_LH_OP:begin //Read half word 2 bytes mem_addr_o <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};//Read the lowest 8 bits mem_sel_o <= 4'b1100;//Read 2 bytes from 0x0 end 2'b10:begin wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]}; mem_sel_o <= 0011; end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_LHU_OP:begin mem_addr_o <= mem_addr_i; mem_we <= `WriteDisable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_o <= {{16{1'b0}},mem_data_i[31:16]}; mem_sel_o <= 4'b1100; end 2'b10:begin wdata_o <= {{16{1'b0}},mem_data_i[15:0]}; mem_sel_o <= 4'b0011; end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_LW_OP:begin //Load a word mem_addr_o <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteDisable; mem_sel_o <= 4'b1111; mem_ce_o <= `ChipEnable; wdata_o <= mem_data_i; end `EXE_LWL_OP:begin //Loading the most significant part of a word from the specified address in memory allows non aligned loading mem_addr_o <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteDisable; mem_sel_o <= 4'b1111; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0])//The slave address is mem_ addr_ Load a word at O and save the lowest 4-n bytes of the word to the high and low bits of the rt register 2'b00:begin wdata_o <= mem_data_i[31:0];//32-bit (4-0) * 8 end 2'b01:begin wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};//24 bits (4-1) * 8 end 2'b10:begin wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};//16 bits (4-2) * 8 end 2'b11:begin wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};//8 bits (4-3) * 8 end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_LWR_OP:begin mem_addr_o <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteDisable; mem_sel_o <= 4'b1111; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin wdata_o <= {reg2_i[31:8],mem_data_i[31:24]};//Save 8 bits in low order end 2'b01:begin wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};//Save 16 bits in low order end 2'b10:begin wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};//Save the upper 24 bits in the lower order end 2'b11:begin wdata_o <= mem_data_i; end default:begin wdata_o <= `ZeroWord; end endcase end `EXE_SB_OP:begin//Stores the lowest byte of the general-purpose register with address rt to the specified address in memory mem_addr_o <= mem_addr_i; mem_we <= `WriteEnable; mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]}; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0])//The high bit of data is stored in the low address of memory 2'b00:begin mem_sel_o <= 4'b1000; end 2'b01:begin mem_sel_o <= 4'b0100; end 2'b10:begin mem_sel_o <= 4'b0010; end 2'b11:begin mem_sel_o <= 4'b0001; end default:begin mem_sel_o <= 4'b0000; end endcase end `EXE_SH_OP:begin//Store the lowest two bytes of the general-purpose register with address rt, and save the low order 2 to the high address mem_addr_o <= mem_addr_i; mem_we <= `WriteEnable; mem_data_o <= {reg2_i[15:0],reg2_i[15:0]}; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_o <= 4'b1100; end 2'b10:begin mem_sel_o <= 4'b0011; end default:begin mem_sel_o <= `ZeroWord; end endcase end `EXE_SW_OP:begin mem_addr_o <= mem_addr_i; mem_we <= `WriteEnable; mem_ce_o <= `ChipEnable; mem_sel_o <= 4'b1111; end /*Store the high-order part of the general-purpose register with address rt to the address specified in memory, The last two bits of the storage address determine which bytes of the rt general register to store, swl Instruction has no alignment requirements for stored instructions Store the maximum 4-n bytes of the general-purpose register with address rt in storeaddr*/ `EXE_SWL_OP:begin//The non aligned storage instruction stores the high-order part of the general-purpose register with address rt to the left at the specified address in memory //The last two bits of the storage address determine which bytes of the rt general-purpose register to store mem_addr_o <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteEnable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0])//Determines which bytes of the rt general register are stored 2'b00:begin mem_sel_o <= 4'b1111; mem_data_o <= reg2_i; end 2'b01:begin mem_sel_o <= 4'b0111; mem_data_o <= {zero32[7:0],reg2_i[31:8]};//Store up to 4-1 bytes (24 bits) in storeaddr end 2'b10:begin mem_sel_o <= 4'b0011;//16bits mem_data_o <= {zero32[15:0],reg2_i[31:16]}; end 2'b11:begin mem_sel_o <= 4'b0001; mem_data_o <= {zero32[23:0],reg2_i[31:24]}; end default:begin mem_sel_o <= 4'b000; end endcase end `EXE_SWR_OP:begin mem_addr_o <= {mem_addr_i[31:2],2'b00}; mem_we <= `WriteEnable; mem_ce_o <= `ChipEnable; case(mem_addr_i[1:0]) 2'b00:begin mem_sel_o <= 4'b1000; mem_data_o <= {reg2_i[7:0],zero32[23:0]}; end 2'b01:begin mem_sel_o <= 4'b1100; mem_data_o <= {reg2_i[15:0],zero32[15:0]}; end 2'b10:begin mem_sel_o <= 4'b1110; mem_data_o <= {reg2_i[23:0],zero32[7:0]}; end 2'b11:begin mem_sel_o <= 4'b1111; mem_data_o <= reg2_i[31:0]; end default:begin mem_sel_o <= `ZeroWord; end endcase end default:begin end endcase end end endmodule
Instantiation (must be wrong every time!!!)
openmips.v
`include "define.v" module openmips( input wire clk, input wire rst, input wire[`RegBus] rom_data_i, output wire[`RegBus] rom_addr_o, output wire rom_ce_o, //Connect data memory data_ram input wire[`RegBus] ram_data_i, output wire[`RegBus] ram_addr_o, output wire[`RegBus] ram_data_o, output wire ram_we_o, output wire[3:0] ram_sel_o, output wire[3:0] ram_ce_o ); wire[`InstAddrBus] pc; wire[`InstAddrBus] id_pc_i; wire[`InstBus] id_inst_i; //Connect the output of ID module in decoding stage with the input of ID/EX module wire[`AluOpBus] id_aluop_o; wire[`AluSelBus] id_alusel_o; wire[`RegBus] id_reg1_o; wire[`RegBus] id_reg2_o; wire id_wreg_o; wire[`RegAddrBus] id_wd_o; wire id_is_in_delayslot_o; wire[`RegBus] id_link_address_o; wire[`RegBus] id_inst_o; //Connect the output of ID/EX module with the input of EX module in execution stage 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; //Connect the output of the execution stage EX module with the input of the EX/MEM module wire ex_wreg_o; wire[`RegAddrBus] ex_wd_o; wire[`RegBus] ex_wdata_o; wire[`RegBus] ex_hi_o; wire[`RegBus] ex_lo_o; wire ex_whilo_o; wire[`AluOpBus] ex_aluop_o; wire[`RegBus] ex_mem_addr_o; wire[`RegBus] ex_reg1_o; wire[`RegBus] ex_reg2_o; //Connect the output of EX/MEM module with the input of MEM module in memory access stage wire mem_wreg_i; wire[`RegAddrBus] mem_wd_i; wire[`RegBus] mem_wdata_i; wire[`RegBus] mem_hi_i; wire[`RegBus] mem_lo_i; wire mem_whilo_i; wire[`AluOpBus] mem_aluop_i; wire[`RegBus] mem_mem_addr_i; wire[`RegBus] mem_reg1_i; wire[`RegBus] mem_reg2_i; //Connect the output of MEM module and the input of MEM/WB module in memory access stage wire mem_wreg_o; wire[`RegAddrBus] mem_wd_o; wire[`RegBus] mem_wdata_o; wire[`RegBus] mem_hi_o; wire[`RegBus] mem_lo_o; wire mem_whilo_o; //Connect the output of the MEM/WB module with the input of the write back phase wire wb_wreg_i; wire[`RegAddrBus] wb_wd_i; wire[`RegBus] wb_wdata_i; wire[`RegBus] wb_hi_i; wire[`RegBus] wb_lo_i; wire wb_whilo_i; //Connection between Regfile and general register decoding module wire reg1_read; wire reg2_read; wire[`RegBus] reg1_data; wire[`RegBus] reg2_data; wire[`RegAddrBus] reg1_addr; wire[`RegAddrBus] reg2_addr; //Connect the output of the execution stage and hilo module and read the HI and LO registers wire[`RegBus] hi; wire[`RegBus] lo; //Connect execution phase and ex_reg module for multi cycle MADD, MADDU, MSUB, MSUBU instructions wire[`DoubleRegBus] hilo_temp_o; wire[1:0] cnt_o; wire[`DoubleRegBus] hilo_temp_i; wire[1:0] cnt_i; wire[`DoubleRegBus] div_result; wire div_ready; wire[`RegBus] div_opdata1; wire[`RegBus] div_opdata2; wire div_start; wire div_annul; wire signed_div; wire is_in_delayslot_i; wire is_in_delayslot_o; wire next_inst_in_delayslot_o; wire id_branch_flag_o; wire[`RegBus] branch_target_address; wire[5:0] stall; wire stallreq_from_id; wire stallreq_from_ex; //pc_reg instantiation pc_reg pc_reg0( .clk(clk), .rst(rst), .stall(stall), .branch_flag_i(id_branch_flag_o), .branch_target_address_i(branch_target_address), .pc(pc), .ce(rom_ce_o) ); assign rom_addr_o = pc; //IF/ID modularization 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) ); //Decoding phase ID module id id0( .rst(rst), .pc_i(id_pc_i), .inst_i(id_inst_i), .ex_aluop_i(ex_aluop_o), .reg1_data_i(reg1_data), .reg2_data_i(reg2_data), //The destination register information to be written by the instruction in the execution phase .ex_wreg_i(ex_wreg_o), .ex_wdata_i(ex_wdata_o), .ex_wd_i(ex_wd_o), //The destination register information to be written by the instruction in the memory access stage .mem_wreg_i(mem_wreg_o), .mem_wdata_i(mem_wdata_o), .mem_wd_i(mem_wd_o), .is_in_delayslot_i(is_in_delayslot_i), //Information sent to regfile .reg1_read_o(reg1_read), .reg2_read_o(reg2_read), .reg1_addr_o(reg1_addr), .reg2_addr_o(reg2_addr), //Information sent to ID/EX module .aluop_o(id_aluop_o), .alusel_o(id_alusel_o), .reg1_o(id_reg1_o), .reg2_o(id_reg2_o), .wd_o(id_wd_o), .wreg_o(id_wreg_o), .inst_o(id_inst_o), .next_inst_in_delayslot_o(next_inst_in_delayslot_o), .branch_flag_o(id_branch_flag_o), .branch_target_address_o(branch_target_address), .link_addr_o(id_link_address_o), .is_in_delayslot_o(id_is_in_delayslot_o), .stallreq(stallreq_from_id) ); //Regfile instantiation of general register 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 module id_ex id_ex0( .clk(clk), .rst(rst), .stall(stall), //Information transmitted from ID module of decoding stage .id_aluop(id_aluop_o), .id_alusel(id_alusel_o), .id_reg1(id_reg1_o), .id_reg2(id_reg2_o), .id_wd(id_wd_o), .id_wreg(id_wreg_o), .id_link_address(id_link_address_o), .id_is_in_delayslot(id_is_in_delayslot_o), .next_inst_in_delayslot_i(next_inst_in_delayslot_o), .id_inst(id_inst_o), //Information passed to the execution stage EX module .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_o(is_in_delayslot_i), .ex_inst(ex_inst_i) ); //EX module ex ex0( .rst(rst), //Information sent to the execution stage EX module .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), .hi_i(hi), .lo_i(lo), .inst_i(ex_inst_i), .wb_hi_i(wb_hi_i), .wb_lo_i(wb_lo_i), .wb_whilo_i(wb_whilo_i), .mem_hi_i(mem_hi_o), .mem_lo_i(mem_lo_o), .mem_whilo_i(mem_whilo_o), .hilo_temp_i(hilo_temp_i), .cnt_i(cnt_i), .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), //EX module output to EX/MEM module information .wd_o(ex_wd_o), .wreg_o(ex_wreg_o), .wdata_o(ex_wdata_o), .hi_o(ex_hi_o), .lo_o(ex_lo_o), .whilo_o(ex_whilo_o), .hilo_temp_o(hilo_temp_o), .cnt_o(cnt_o), .div_opdata1_o(div_opdata1), .div_opdata2_o(div_opdata2), .div_start_o(div_start), .signed_div_o(signed_div), .aluop_o(ex_aluop_o), .mem_addr_o(ex_mem_addr_o), .reg2_o(ex_reg2_o), .stallreq(stallreq_from_ex) ); //EX/MEM module ex_mem ex_mem0( .clk(clk), .rst(rst), .stall(stall), //Information from execution stage EX module .ex_wd(ex_wd_o), .ex_wreg(ex_wreg_o), .ex_wdata(ex_wdata_o), .ex_hi(ex_hi_o), .ex_lo(ex_lo_o), .ex_whilo(ex_whilo_o), .ex_aluop(ex_aluop_o), .ex_mem_addr(ex_mem_addr_o), .ex_reg2(ex_reg2_o), .hilo_i(hilo_temp_o), .cnt_i(cnt_o), //Information sent to MEM module in memory access stage .mem_wd(mem_wd_i), .mem_wreg(mem_wreg_i), .mem_wdata(mem_wdata_i), .mem_hi(mem_hi_i), .mem_lo(mem_lo_i), .mem_whilo(mem_whilo_i), .mem_aluop(mem_aluop_i), .mem_mem_addr(mem_mem_addr_i), .mem_reg2(mem_reg2_i), .hilo_o(hilo_temp_i), .cnt_o(cnt_i) ); //MEM module instantiation mem mem0( .rst(rst), //Information from EX/MEM module .wd_i(mem_wd_i), .wreg_i(mem_wreg_i), .wdata_i(mem_wdata_i), .hi_i(mem_hi_i), .lo_i(mem_lo_i), .whilo_i(mem_whilo_i), .aluop_i(mem_aluop_i), .mem_addr_i(mem_mem_addr_i), .reg2_i(mem_reg2_i), //Information from memory .mem_data_i(ram_data_i), //Information sent to MEM/WB module .wd_o(mem_wd_o), .wreg_o(mem_wreg_o), .wdata_o(mem_wdata_o), .hi_o(mem_hi_o), .lo_o(mem_lo_o), .whilo_o(mem_whilo_o), //Information sent to memory .mem_addr_o(ram_addr_o), .mem_we_o(ram_we_o), .mem_sel_o(ram_sel_o), .mem_data_o(ram_data_o), .mem_ce_o(ram_ce_o) ); //MEM/WB module mem_wb mem_wb0( .clk(clk), .rst(rst), .stall(stall), //Information from MEM module in memory access stage .mem_wd(mem_wd_o), .mem_wreg(mem_wreg_o), .mem_wdata(mem_wdata_o), .mem_hi(mem_hi_o), .mem_lo(mem_lo_o), .mem_whilo(mem_whilo_o), //Information sent to write back phase .wb_wd(wb_wd_i), .wb_wreg(wb_wreg_i), .wb_wdata(wb_wdata_i), .wb_hi(wb_hi_i), .wb_lo(wb_lo_i), .wb_whilo(wb_whilo_i) ); hilo_reg hilo_reg0( .clk(clk), .rst(rst), //Write port .we(wb_whilo_i), .hi_i(wb_hi_i), .lo_i(wb_lo_i), //Read port 1 .hi_o(hi), .lo_o(lo) ); ctrl ctrl0( .rst(rst), .stallreq_from_id(stallreq_from_id), //Pause request from execution phase .stallreq_from_ex(stallreq_from_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_o(div_result), .ready_o(div_ready) ); endmodule
openmips_min_sopc.v
`include "define.v" //openmips_min_sopc.v module openmips_min_sopc( input wire clk, input wire rst ); //Connection instruction memory wire[`InstAddrBus] inst_addr; wire[`InstBus] inst; wire rom_ce; //Connecting external data storage wire mem_we_i; wire [`RegBus]mem_addr_i; wire [`RegBus]mem_data_i; wire [`RegBus]mem_data_o; wire[3:0] mem_sel_i; wire mem_ce_i; //Instantiation processor openmips openmips0( .clk(clk), .rst(rst), .rom_addr_o(inst_addr), .rom_data_i(inst), .rom_ce_o(rom_ce), .ram_we_o(mem_we_i), .ram_addr_o(mem_addr_i), .ram_sel_o(mem_sel_i), .ram_data_o(mem_data_i), .ram_data_i(mem_data_o), .ram_ce_o(mem_ce_i) ); //Instantiated instruction memory inst_rom inst_rom0( .ce(rom_ce), .inst(inst), .addr(inst_addr) ); //Instantiated external data memory RAM data_ram data_ram0( .clk(clk), .we(mem_we_i), .addr(mem_addr_i), .sel(mem_sel_i), .data_i(mem_data_i), .data_o(mem_data_o), .ce(mem_ce_i) ); endmodule
test data
inst_rom.S
.org 0x0 .set noat .set noreorder .set nomacro .global _start _start: ori $3,$0,0xeeff sb $3,0x3($0) # [0x3] = 0xff srl $3,$3,8 sb $3,0x2($0) # [0x2] = 0xee ori $3,$0,0xccdd sb $3,0x1($0) # [0x1] = 0xdd srl $3,$3,8 sb $3,0x0($0) # [0x0] = 0xcc lb $1,0x3($0) # $1 = 0xffffffff lbu $1,0x2($0) # $1 = 0x000000ee nop ori $3,$0,0xaabb sh $3,0x4($0) # [0x4] = 0xaa, [0x5] = 0xbb lhu $1,0x4($0) # $1 = 0x0000aabb lh $1,0x4($0) # $1 = 0xffffaabb ori $3,$0,0x8899 sh $3,0x6($0) # [0x6] = 0x88, [0x7] = 0x99 lh $1,0x6($0) # $1 = 0xffff8899 lhu $1,0x6($0) # $1 = 0x00008899 ori $3,$0,0x4455 sll $3,$3,0x10 ori $3,$3,0x6677 sw $3,0x8($0) # [0x8] = 0x44, [0x9]= 0x55, [0xa]= 0x66, [0xb] = 0x77 lw $1,0x8($0) # $1 = 0x44556677 lwl $1, 0x5($0) # $1 = 0xbb889977 lwr $1, 0x8($0) # $1 = 0xbb889944 nop swr $1, 0x2($0) # [0x0] = 0x88, [0x1] = 0x99, [0x2]= 0x44, [0x3] = 0xff swl $1, 0x7($0) # [0x4] = 0xaa, [0x5] = 0xbb, [0x6] = 0x88, [0x7] = 0x44 lw $1, 0x0($0) # $1 = 0x889944ff lw $1, 0x4($0) # $1 = 0xaabb8844 _loop: j _loop nop
inst_rom.data
3403eeff a0030003 00031a02 a0030002 3403ccdd a0030001 00031a02 a0030000 80010003 90010002 00000000 3403aabb a4030004 94010004 84010004 34038899 a4030006 84010006 94010006 34034455 00031c00 34636677 ac030008 8c010008 88010005 98010008 00000000 b8010002 a8010007 8c010000 8c010004 0800001f 00000000
Results (changes in reg1 and reg3) $1 and $3
The detailed design may open another article...