手写一个简易的多周期 MIPS CPU (5)

ExtSel:EXE 阶段 ANDI、ORI、XORI

ExtSel = ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && (OpCode == `OP_ANDI || OpCode == `OP_ORI || OpCode == `OP_XORI)) ? 0 : 1;

PCSrc:IF 或 ID 阶段 JR 为 PC_REG_JUMP,IF 或 ID 阶段 J、JAL 为 PC_ABS_JUMP,EXE 阶段 BEQ、BNE、BLTZ 为 PC_REL_JUMP,否则均为 PC_NEXT

if ((State == `STATE_IF || State == `STATE_ID) && OpCode == `OP_JR) PCSrc = `PC_REG_JUMP; else if ((State == `STATE_IF || State == `STATE_ID) && (OpCode == `OP_J || OpCode == `OP_JAL)) PCSrc = `PC_ABS_JUMP; else if ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && (OpCode == `OP_BEQ && Zero) || (OpCode == `OP_BNE && !Zero) || (OpCode == `OP_BLTZ && Sign)) PCSrc = `PC_REL_JUMP; else PCSrc = `PC_NEXT;

RegDst:ID 阶段 JAL 为 b00,WB 阶段 ADDIU、ANDI、ORI、XORI、SLTI、LW 为 b01,否则均为 b10

if (State == `STATE_ID && OpCode == `OP_JAL) RegDst = 2'b00; else if ((State == `STATE_WB_AL || State == `STATE_WB_LD) && (OpCode == `OP_ADDIU || OpCode == `OP_ANDI || OpCode == `OP_ORI || OpCode == `OP_XORI || OpCode == `OP_SLTI || OpCode == `OP_LW)) RegDst = 2'b01; else RegDst = 2'b10;

ALUOp:根据真值表即可得出

case (OpCode) `OP_ADD, `OP_ADDIU, `OP_SW, `OP_LW: ALUOp = `ALU_OP_ADD; `OP_SUB, `OP_BEQ, `OP_BNE, `OP_BLTZ: ALUOp = `ALU_OP_SUB; `OP_SLL: ALUOp = `ALU_OP_SLL; `OP_ORI: ALUOp = `ALU_OP_OR; `OP_AND, `OP_ANDI: ALUOp = `ALU_OP_AND; `OP_SLTI, `OP_SLT: ALUOp = `ALU_OP_SLT; `OP_XORI: ALUOp = `ALU_OP_XOR; endcase

PCWre:ID 阶段 J、JAL、JR,或 EXE 阶段 BEQ、BNE、BLTZ,或 MEM 阶段 SW,或 WB 阶段。另外,为保证在每条指令最初阶段的时钟上升沿 PC 发生改变,需要在上一条指令的最后一个下降沿将 PCWre 设置为 1,这样才能保证 PC 在每条指令最开始的时钟上升沿改变。

always @(negedge CLK) begin case (State) `STATE_ID: begin if (OpCode == `OP_J || OpCode == `OP_JAL || OpCode == `OP_JR) PCWre <= 1; end `STATE_EXE_AL, `STATE_EXE_BR, `STATE_EXE_LS: begin if (OpCode == `OP_BEQ || OpCode == `OP_BNE || OpCode == `OP_BLTZ) PCWre <= 1; end `STATE_MEM: begin if (OpCode == `OP_SW) PCWre <= 1; end `STATE_WB_AL, `STATE_WB_LD: PCWre <= 1; default: PCWre <= 0; endcase end 逻辑算术运算单元

该模块是一个32位的ALU单元,会根据控制信号对输入的操作数进行不同的运算,例如加、减、与、或等。

module ALU( input [2:0] ALUOp, input [31:0] A, input [31:0] B, output Sign, output Zero, output reg [31:0] Result ); always @(*) begin case (ALUOp) `ALU_OP_ADD: Result = (A + B); `ALU_OP_SUB: Result = (A - B); `ALU_OP_SLL: Result = (B << A); `ALU_OP_OR: Result = (A | B); `ALU_OP_AND: Result = (A & B); `ALU_OP_LT: Result = (A < B) ? 1 : 0; `ALU_OP_SLT: Result = (((A < B) && (A[31] == B[31])) || ((A[31] && !B[31]))) ? 1 : 0; `ALU_OP_XOR: Result = (A ^ B); endcase $display("[ALU] calculated result [%h] from a = [%h] aluOpCode = [%b] b = [%h]", Result, A, ALUOp, B); end assign Zero = (Result == 0) ? 1 : 0; assign Sign = Result[31]; endmodule 寄存器组

该模块为一个32位而拥有32个寄存的寄存器组。寄存器组接受 InstructionMemory 的输入,输出对应寄存器的数据,从而实现读取寄存器里的数据的功能。

module RegisterFile( input CLK, input RST, input WE, input [4:0] ReadReg1, input [4:0] ReadReg2, input [4:0] WriteReg, input [31:0] WriteData, output [31:0] ReadData1, output [31:0] ReadData2 ); reg [31:0] register[1:31]; integer i; assign ReadData1 = ReadReg1 == 0 ? 0 : register[ReadReg1]; assign ReadData2 = ReadReg2 == 0 ? 0 : register[ReadReg2]; always @(negedge CLK or negedge RST) begin if (!RST) begin for (i = 1; i < 32; i = i + 1) begin register[i] = 0; end end else if (WE && WriteReg) begin register[WriteReg] <= WriteData; $display("[RegisterFile] wrote data [%h] into reg $[%d]", WriteData, WriteReg); end end endmodule 符号扩展单元

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjsgx.html