diff --git a/rtl/mips_cpu_alu.v b/rtl/mips_cpu_alu.v index f7baa22..cf49895 100644 --- a/rtl/mips_cpu_alu.v +++ b/rtl/mips_cpu_alu.v @@ -1,11 +1,18 @@ module mips_cpu_alu( + input logic clk, //clock for special registers Hi and Lo + input logic rst, input logic[31:0] A, //Bus A - Input from the Readdata1 output from the reg file which corresponds to rs. input logic[31:0] B, //Bus B - Input from the Readdata2 output from the reg file which corresponds to rt. Or from the 16-bit immediate sign extended to 32-bit value taken from Instr[15-0]. input logic [4:0] ALUOp, // 5-bit output from Control that tells the alu what operation to do from a list of 20 distinct alu operations(see below). - input logic [4:0] shamt, //5-bit input used to specify shift amount for shift operations. Taken directly from the R-type instruction (Non-Variable) or from + input logic [4:0] shamt, //5-bit input used to specify shift amount for shift operations. Taken directly from the R-type instruction (Non-Variable) or from GPR rs (Variable) + input logic[31:0] Hi_in, + input logic[31:0] Lo_in, + input logic SpcRegWriteEn, output logic ALUCond, //If a relevant condition is met, this output goes high(Active High). Note: Relevant as in related to current condition being tested. - output logic[31:0] ALURes // The ouput of the ALU + output logic[31:0] ALURes, // The ouput of the ALU + output logic[31:0] ALUHi, //Special Hi Register output + output logic[31:0] ALULo //Special Hi Register output ); /* @@ -37,7 +44,8 @@ Alu Operations: - Greater Than or Equal to (>=) (signed) - Negative Equality(=/=) (signed) -Implementation Operation: A design choice used for implmentation. - - Pass-through (Used to implement MTHI and MTLO, as these instructions do not need the ALU but the alu is in the pathway to the regfile, so the register value simply passes through.) + - MTHI (move the contents of GPR rs to special register Hi) + - MTLO (move the contents of GPR rs to special register Lo) */ @@ -62,17 +70,35 @@ Alu Operations: GRT = 5'd16, GEQ = 5'd17, NEQ = 5'd18, - PAS = 5'd19, + // PAS = 5'd19, no need for PAS as it was based on faulty reasoning that speical registers Hi and Lo are in the reg file. SLT = 5'd20,//signed compare SLTU = 5'd21,//unsigned compare MULU = 5'd22,//unsigned divide - DIVU = 5'd23//unsigned multiply + DIVU = 5'd23,//unsigned multiply + MTHI = 5'd24, + MTLO = 5'd25 } Ops; Ops ALUOps; //Note confusing naming to avoid potential duplicate variable naming errors, as a result of enum implemetnation. +logic signed[63:0] SMulRes;//signed result of multiplication. +logic[63:0] UMulRes;//unsigned result of multiplication. +logic[31:0] temp_Hi; +logic[31:0] temp_Lo; + +reg [31:0] Hi; +reg [31:0] Lo; + +assign ALUHi = Hi;//combinatorial read of Hi register +assign ALULo = Lo;//combinatorial read of Lo register + +initial begin + Hi <= 32'd0; + Lo <= 32'd0; +end + always_comb begin assign ALUOps = ALUOp; case(ALUOps) @@ -85,11 +111,14 @@ Ops ALUOps; //Note confusing naming to avoid potential duplicate variable naming end MUL: begin - ALURes = $signed(A) * $signed(B); + SMulRes = $signed(A) * $signed(B); + temp_Hi = SMulRes[63:32]; + temp_Lo = SMulRes[31:0]; end DIV: begin - ALURes = $signed(A) / $signed(B); + temp_Lo = $signed(A) / $signed(B); + temp_Hi = $signed(A) % $signed(B); end AND: begin @@ -205,13 +234,35 @@ Ops ALUOps; //Note confusing naming to avoid potential duplicate variable naming end MULU: begin - ALURes = $signed(A) * $signed(B); + UMulRes = A * B; + temp_Hi = UMulRes[63:32]; + temp_Lo = UMulRes[31:0]; end DIVU: begin - ALURes = $signed(A) / $signed(B); + temp_Lo = A / B; + temp_Hi = A % B; + end + + MTHI: begin + temp_Hi = Hi_in; + end + + MTLO: begin + temp_Lo = Lo_in; end endcase end + + always_ff @(posedge clk) begin + if(rst)begin + Hi <= 0; + Lo <= 0; + end else if (SpcRegWriteEn) begin + Hi <= temp_Hi; + Lo <= temp_Lo; + end + + end endmodule \ No newline at end of file diff --git a/rtl/mips_cpu_control.v b/rtl/mips_cpu_control.v index d3fe86f..40b5aa4 100644 --- a/rtl/mips_cpu_control.v +++ b/rtl/mips_cpu_control.v @@ -5,12 +5,13 @@ module mips_cpu_control( output logic[1:0] CtrlRegDst, output logic[1:0] CtrlPC, output logic CtrlMemRead, - output logic[1:0] CtrlMemtoReg, + output logic[2:0] CtrlMemtoReg, output logic[4:0] CtrlALUOp, output logic[4:0] Ctrlshamt, output logic CtrlMemWrite, output logic CtrlALUSrc, - output logic CtrlRegWrite + output logic CtrlRegWrite, + output logic CtrlSpcRegWriteEn ); typedef enum logic[5:0]{ @@ -53,6 +54,8 @@ typedef enum logic[5:0]{ SRAV = 6'd7, JR = 6'd8, JALR = 6'd9, + MFLO = 6'd18, + MFHI = 6'd16, MTHI = 6'd17, MTLO = 6'd19, MULT = 6'd24, @@ -87,7 +90,7 @@ always @(*) begin if((op==ADDIU) || (op==ANDI) || (op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LUI) || (op==LW) || (op==LWL) || (op==LWR) || (op==ORI) || (op==SLTI) || (op==SLTIU) || (op==XORI))begin CtrlRegDst = 2'd0; //Write address comes from rt $display("CTRLREGDST: Rt"); - end else if ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==JALR) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR)))begin + end else if ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==JALR) || (funct==MFLO) || (funct==MFHI) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR)))begin CtrlRegDst = 2'd1; //Write address comes from rd $display("CTRLREGDST: Rd"); end else if (op == JAL)begin @@ -106,17 +109,21 @@ always @(*) begin //$display("Ctrl PC Jump Register"); end else begin CtrlPC = 2'd0; /*/$display("Ctrl PC No Jump/Branch");*/end // No jumps or branches, just increment to next word - //CtrlMemRead and CtrlMemtoReg logic -- Interesting quirk that they have the same logic. Makes sense bc you'd only want to select the read data out when the memory itself is read enabled. + //CtrlMemRead and CtrlMemtoReg logic -- Interesting quirk that they have the same logic where both are concerned. Makes sense bc you'd only want to select the read data out when the memory itself is read enabled. if((op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LW) || (op==LWL) || (op==LWR))begin CtrlMemRead = 1;//Memory is read enabled - CtrlMemtoReg = 2'd1;//write data port of memory is fed from data memory + CtrlMemtoReg = 3'd1;//write data port of regfile is fed from data memory $display("Memory read enabled"); - end else if ((op==ADDIU) || (op==ANDI) || (op==ORI) || (op==SLTI) || (op==SLTIU) || (op==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==DIV) || (funct==DIVU) || (funct==MTHI) || (funct==MTLO) || (funct==MULT) || (funct==MULTU) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR))))begin + end else if ((op==ADDIU) || (op==ANDI) || (op==ORI) || (op==SLTI) || (op==SLTIU) || (op==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR))))begin CtrlMemRead = 0;//Memory is read disabled - CtrlMemtoReg = 2'd0;//write data port of memory is fed from ALURes + CtrlMemtoReg = 3'd0;//write data port of regfile is fed from ALURes $display("Memory read disabled"); end else if ((op==JAL) || ((op==SPECIAL)&&(funct == JALR)))begin - CtrlMemtoReg = 2'd2;//write data port of memory is fed from PC + 8 + CtrlMemtoReg = 3'd2;//write data port of regfile is fed from PC + 8 + end else if ((op==SPECIAL)&&(funct == MTHI)))begin + CtrlMemtoReg = 3'd3;//write data port of regfile is fed from ALUHi + end else if ((op==SPECIAL)&&(funct == MTLO)))begin + CtrlMemtoReg = 3'd4;//write data port of regfile is fed from ALULo end else begin CtrlMemRead = 1'bx;end//Not all instructions are encompassed so, added incase for debug purposes //CtrlALUOp Logic @@ -146,8 +153,10 @@ always @(*) begin $display("LB IN CONTROL"); end else if(op==LUI)begin CtrlALUOp = 5'd7;//SLL from ALUOps - end else if((op==SPECIAL)&&((funct==MTHI) || (funct==MTLO)))begin - CtrlALUOp = 5'd19;//PAS from ALUOps + end else if((op==SPECIAL)&&((funct==MTHI)))begin + CtrlALUOp = 5'd24;//MTHI from ALUOps + end else if((op==SPECIAL)&&((funct==MTLO)))begin + CtrlALUOp = 5'd25;//MTLO from ALUOps end else if((op==SPECIAL)&&(funct==MULT))begin CtrlALUOp = 5'd2;//MUL from ALUOps end else if((op==SPECIAL)&&(funct==MULTU))begin @@ -197,6 +206,11 @@ always @(*) begin CtrlMemWrite = 1;//Memory is write enabled end else begin CtrlMemWrite = 0;end//default is 0 to ensure no accidental overwriting. + //CtrlSpcRegWriteEn logic + if((op==SPECIAL)&&((funct==MTHI) || (funct==MTLO)))begin + CtrlSpcRegWriteEn = 1;//Special register Hi and Lo are write enabled + end else begin CtrlSpcRegWriteEn = 0;end//default is 0 to ensure no accidental overwriting. + //CtrlALUSrc logic if((op==ADDIU) || (op==ANDI) || (op==LUI) || (op==ORI) || (op==SLTI) || (op==SLTIU) || (op==XORI) || (op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LW) || (op==LWL) || (op==LWR) || (op==SB) || (op==SH) || (op==SW))begin CtrlALUSrc = 1;//ALU Bus B is fed from the 16-bit immediate sign extended to 32-bit value taken from Instr[15-0] @@ -205,7 +219,7 @@ always @(*) begin end else begin CtrlALUSrc = 1'bx;end //CtrlRegWrite logic - if((op==ADDIU) || (op==ANDI) || (op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LUI) || (op==LW) || (op==LWL) || (op==LWR) || (op==ORI) || (op==SLTI) || (op==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==DIV) || (funct==DIVU) || (funct==MULT) || (funct==MULTU) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR)))) begin + if((op==ADDIU) || (op==ANDI) || (op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LUI) || (op==LW) || (op==LWL) || (op==LWR) || (op==ORI) || (op==SLTI) || (op==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==MFLO) || (funct==MFHI) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR)))) begin CtrlRegWrite = 1;//The Registers are Write Enabled end else begin CtrlRegWrite = 0;end // The Registers are Write Disabled end diff --git a/rtl/mips_cpu_harvard.v b/rtl/mips_cpu_harvard.v index 00cd6ba..b54f787 100644 --- a/rtl/mips_cpu_harvard.v +++ b/rtl/mips_cpu_harvard.v @@ -30,7 +30,8 @@ logic[31:0] out_pc_out, out_ALURes, out_readdata1, out_readdata2, in_B, in_write logic[4:0] in_readreg1, in_readreg2, in_writereg, out_shamt, out_ALUOp; logic[5:0] in_opcode; logic out_ALUCond, out_RegWrite, out_ALUSrc, out_MemWrite, out_MemRead; -logic[1:0] out_RegDst, out_PC, out_MemtoReg; +logic[1:0] out_RegDst, out_PC; +logic[2:0] out_MemtoReg; assign in_readreg1 = instr_readdata[25:21]; assign in_readreg2 = instr_readdata[20:16]; @@ -52,15 +53,21 @@ always @(*) begin //Picking which output should be written to regfile. case(out_MemtoReg) - 2'd0:begin + 3'd0:begin in_writedata = out_ALURes;//Output from ALU Result. end - 2'd1:begin + 3'd1:begin in_writedata = data_readdata;//Output from Data Memory. end - 2'd2:begin + 3'd2:begin in_writedata = (out_pc_out + 32'd8);//Output from PC +8. end + 3'd3:begin + in_writedata = (out_ALUHi); + end + 3'd4:begin + in_writedata = (out_ALULo); + end endcase //Picking which output should be taken as the second operand for ALU. @@ -99,7 +106,8 @@ mips_cpu_control control( //instance of the 'mips_cpu_control' module called 'co .Ctrlshamt(out_shamt), .CtrlMemWrite(out_MemWrite), .CtrlALUSrc(out_ALUSrc), - .CtrlRegWrite(out_RegWrite) + .CtrlRegWrite(out_RegWrite), + .CtrlSpcRegWriteEn(out_SpcRegWriteEn) ); mips_cpu_regfile regfile( @@ -119,13 +127,20 @@ mips_cpu_regfile regfile( mips_cpu_alu alu( //Inputs to ALU + .clk(clk), + .rst(reset), .A(out_readdata1), //operand 1 taken from 'Read data 1' aka the data stored in GPR rs. .B(in_B), //operand 2 taken either from: 'Read data 2' aka the data stored in rt; or 16-bit immediate sign extended to 32 bits. .ALUOp(out_ALUOp), //Operation selection for ALU decided, and output by control. .shamt(out_shamt), //Shift amount required for shift instruction taken from control. + .Hi_in(out_readdata1), + .Lo_in(out_readdata1), + .SpcRegWriteEn(out_SpcRegWriteEn), //Outputs from ALU .ALUCond(out_ALUCond), //condition used by control to decide on branch instructions. - .ALURes(out_ALURes) //output/result of operation that goes to either: 'Address' port of Data Memory; or 'Write Data' port of the register file. + .ALURes(out_ALURes), //output/result of operation that goes to either: 'Address' port of Data Memory; or 'Write Data' port of the register file. + .ALUHi(out_ALUHi), //Special register Hi output to be used for MFHI instructions - feeds in_writedata. + .ALULo(out_ALULo), //Special register Hi output to be used for MFLO instructions - feeds in_writedata. ); endmodule