/// <summary> /// Adds an entry to the rrfTable /// </summary> /// <param name="instr">Instruction to be added to the rrfTable</param> /// <returns>The index (tag) of where it was added</returns> public int addEntry(Instruction instr) { int rrfTag = -1; // We had to create one here because we use emptySlot below RRFEntry emptySlot = new RRFEntry(); // Note we're guaranteed an entry is open because we called spaceAvailable // at a higher level for (int i = 0; i < Config.numRenamingTableEntries; i++) { if (this.rrfTable[i].busy == false) { emptySlot = rrfTable[i]; rrfTag = i; break; } } emptySlot.busy = true; emptySlot.valid = false; // There must be a destination if this instruction requires an RRF entry emptySlot.destReg = instr.dest; // Data stays null until it's updated by an execution result return rrfTag; }
/// <summary> /// Constructor using initializers /// </summary> public ReservationStationEntry(int op1, bool valid1, int op2, bool valid2, int robTag, Instruction instr) { this.op1 = op1; this.valid1 = valid1; this.op2 = op2; this.valid2 = valid2; this.robTag = robTag; this.instr = instr; this.ready = (this.valid1 && this.valid2); this.busy = true; }
/// <summary> /// Add an entry to the reorder buffer /// </summary> /// <param name="instr">the instruction you need to add an entry for</param> public void addEntry(Instruction instr) { if (Config.numReorderBufferEntries - this.buffer.Count > 0) { RobEntry newEntry = new RobEntry(); newEntry.busy = true; newEntry.finished = false; newEntry.instruction = instr; newEntry.valid = this.isNewEntryValid(); newEntry.renameReg = CPU.rrf.findFirstEmptySlot(); this.buffer.Enqueue(newEntry); } }
/// <summary> /// Adds and instruction to the dispatch buffer /// </summary> /// <param name="instr"></param> /// <returns></returns> private bool addInstructionToBuffer(Instruction instr) { if (Config.superScalerFactor - this.dispatchBuffer.Count() > 0) { this.dispatchBuffer.Enqueue(instr); return true; } else { System.Console.WriteLine("ERROR Tried to add instruction to dispatch buffer when it was full!"); return false; } }
/// <summary> /// Puts the instruction into the reservation station, filling the entries /// Note this does not check if ResStation is full, as that check is done at a higher level /// </summary> public void ReceiveInstruction(Instruction instr, int robTag) { // The reservation station entry we're creating ReservationStationEntry thisEntry; // The fields in the entry int op1 = 0, op2 = 0; bool valid1 = false, valid2 = false; SetUpOp(ref op1, ref valid1, instr.source1, instr.source1Imm); SetUpOp(ref op2, ref valid2, instr.source2, instr.source2Imm); thisEntry = new ReservationStationEntry(op1, valid1, op2, valid2, robTag, instr); this.buffer.Add(thisEntry); }
/// <summary> /// Puts the instruction into the rename register file /// </summary> private void dispatchToRenameRegisterFile(Instruction instr) { if (instr.dest != -1) { int rrfTag; // Add entry to Rename Register File rrfTag = CPU.rrf.addEntry(instr); // Update the ARF entry of the destination to busy and its tag to point to the RRF entry CPU.arf.regFile[instr.dest].busy = true; if (rrfTag == -1) { Console.WriteLine("-1 rrf tag!"); } CPU.arf.regFile[instr.dest].tag = rrfTag; } }
/// <summary> /// Determines the Instruction type and checks the appropriate Reservation Station for space /// </summary> /// <param name="instr">The Instrucion that needs moved</param> /// <param name="issueStage">The Issue Stage that will handle the instruction</param> /// <returns>True if there is space available, false otherwise</returns> private bool isReservationStationAvaialble(Instruction instr) { switch (instr.executionType) { case Instruction.ExecutionType.Logical: case Instruction.ExecutionType.Integer: if (CPU.issueStage.integerStation.isFull()) return false; break; case Instruction.ExecutionType.FloatingPoint: if (CPU.issueStage.fpStation.isFull()) return false; break; case Instruction.ExecutionType.Mem: if (CPU.issueStage.memStation.isFull()) return false; break; case Instruction.ExecutionType.MultDiv: if (CPU.issueStage.multDivStation.isFull()) return false; break; case Instruction.ExecutionType.Branch: if (CPU.issueStage.branchStation.isFull()) return false; break; case Instruction.ExecutionType.Nop: // Return True, as we do nto care about Nop break; default: System.Console.WriteLine("Decode Stage found Unknown Instruction Execution Type"); break; } return true; }
/// <summary> /// Checks to see if there is space in all appropriate buffers for the instruction /// </summary> /// <param name="instr">Instruction to be moved</param> /// <param name="issueStage">Issue Stage for instruction</param> /// <param name="rrf">Rename Register File</param> /// <returns>true if the system is ready, false otherwise</returns> private bool systemReadyForInstruction(Instruction instr) { //TODO: Check ROB if (CPU.rob.isFull()) { Statistics.reorderBufferFull++; return false; } // Check to see if there is space available in the reservation stations if (this.isReservationStationAvaialble(instr) == false) { Statistics.reservationStationFull++; return false; } // Check to see if there is space available in the rrf if (CPU.rrf.spaceAvailable() == false) { Statistics.registerRenameFileFull++; return false; } return true; }
/// <summary> /// Puts the instruction into the appropriate reservation station (located in the issue stage) /// </summary> private void dispatchToReservationStation(Instruction instr, int robTag) { switch (instr.executionType) { case Instruction.ExecutionType.Branch: CPU.issueStage.branchStation.ReceiveInstruction(instr, robTag); break; case Instruction.ExecutionType.FloatingPoint: CPU.issueStage.fpStation.ReceiveInstruction(instr, robTag); break; case Instruction.ExecutionType.Logical: case Instruction.ExecutionType.Integer: CPU.issueStage.integerStation.ReceiveInstruction(instr, robTag); break; case Instruction.ExecutionType.Mem: CPU.issueStage.memStation.ReceiveInstruction(instr, robTag); break; case Instruction.ExecutionType.MultDiv: CPU.issueStage.multDivStation.ReceiveInstruction(instr, robTag); break; case Instruction.ExecutionType.Nop: break; } }
/// <summary> /// Puts the instruction into the reorder buffer /// </summary> /// <returns>The tag of the entry used in the reorder buffer</returns> private int dispatchToReorderBuffer(Instruction instr) { CPU.rob.addEntry(instr); // TODO: We're using a queue for the ROB, so we don't really have a tag // to the entries within it. Do we have to change this? return -1; }
/// <summary> /// Perform the Decode Stage /// /// Checks to see if there is a stall on reading more instructions /// from the fetch stage due to a previously detected Branch Misprediction /// that has not completed the execute stage yet. /// /// Then it checks the last two instructions in the fetch stage to see /// if there is branch, and if it was predicted correctly. This Enables /// a stall if necessary /// /// Otherwise, copy instructions from the fetch stage /// /// </summary> public void runCycle() { if(CPU.fetchStage.isEmpty() || this.isFull()) { // Nothing to do here, fetch stage empty or we're full return; } // Make sure that we are not in a stall state waiting on // a branch instruction to finish executing if (CPU.branchMispredictionStall == false) { // Was the last instruction on the last cycle a branch? If yes, we need to check against our // member variable holding the info from that last instruction if (this.lastInstructionWasBranch == true) { Instruction firstInstr = CPU.fetchStage.peekInstruction(); if (true == CPU.fetchStage.isBranchMispredict(this.lastInstruction, firstInstr)) { //branch misprediction! CPU.branchMispredictionStall = true; } else { // No misprediction between fetches, we're good to continue as normal } // Reset this this.lastInstructionWasBranch = false; } // What we want here is to check each instruction one at a time to see if it's a branch instruction. // If it isn't, read it from the fetch buffer into the decode buffer. // If it is, is it the last instruction? If it's the last instruction, set our member variables // accordingly so we can check next time around while (!CPU.fetchStage.isEmpty()) { Instruction currInstr = CPU.fetchStage.getInstruction(); this.addInstructionToBuffer(currInstr); if (!currInstr.isABranch()) { if (this.isFull()) break; } else { // It's a branch; if it's the last instruction in the fetch buffer, we'll need to check // for a mispredict next time around if (CPU.fetchStage.isEmpty()) { this.lastInstruction = currInstr; this.lastInstructionWasBranch = true; } else { // It's not the last instruction, check for mispredict if (true == CPU.fetchStage.isBranchMispredict(currInstr, CPU.fetchStage.peekInstruction())) { //branch misprediction! CPU.branchMispredictionStall = true; } // We may be full now; if we are, break out if (this.isFull()) break; } } } // We should have all the instructions from the fetch buffer now in the decode buffer } // End if(CPU.branchMispredictionStall == false) }
/// <summary> /// Fetches as many instructions from the instruction trace as it can process /// up to super scalar width. Returns how many instructions it fetched. /// </summary> public int Fetch() { int numInstructionsRead = 0; int numSlotsOpen = 0; String line; Random rand = new Random(); if (this.cacheMissed == false) { // We didn't miss the cache last time, so we have to see if we miss this time if (rand.Next(100) < Config.level1CacheInstrMissPercent) { Statistics.level1InstrCacheMisses++; //We did miss cache; set cacheMiss = true and the appropriate cacheMissCountdown this.cacheMissed = true; this.cacheMissCountdown = Config.level1CacheMissPenalty; //Check for Level 2 Cache miss if (rand.Next(100) < Config.level2CacheMissPercent) { Statistics.level2CacheMisses++; //Update cache miss countdown to be main memory access plus the L2 access this.cacheMissCountdown += Config.level2CacheMissPenalty; } return 0; } } else { // We did miss cache. If cacheMissCountdown is > 0, we have to wait more cycles, so we return. // Otherwise, we can move on and fetch. if (this.cacheMissCountdown > 0) { this.cacheMissCountdown--; return 0; } } numSlotsOpen = Config.superScalerFactor - this.fetchBuffer.Count; // Read in numSlotsOpen instructions from the trace file. for(int i = 0; i < numSlotsOpen; i++) { line = this.traceReader.ReadLine(); if (line != null) { numInstructionsRead++; Instruction newInstruction = new Instruction(line); CPU.pc = newInstruction.address; CPU.pc_count++; if(newInstruction.executionType != Instruction.ExecutionType.Nop) fetchBuffer.Enqueue(newInstruction); } else { // ensures that this is onle performed onces if (CPU.lastInstructionFetched == false) { if (this.fetchBuffer.Count > 0) { fetchBuffer.Last().isLastInstruction = true; } else { CPU.decodeStage.decodeBuffer.Last().isLastInstruction = true; } CPU.lastInstructionFetched = true; } } } // Reset cache miss this.cacheMissed = false; return numInstructionsRead; }
/// <summary> /// Checks against two instructions to see if there is a branch mispredict /// </summary> /// <returns>true if there is was mispredict</returns> public bool isBranchMispredict(Instruction first, Instruction next) { if (!first.isABranch()) { return false; } // If we got here, instr is a branch instruction bool branchPrediction = CPU.branchPredictor.predictBranch(first.address); bool actualResult; // if next pc == first pc +8 , branch not taken if (next.address == first.address + 8) { actualResult = false; } else { actualResult = true; } CPU.branchPredictor.updateBranchSM(first.address, branchPrediction, actualResult); // Fixed this...it's an isBranchMISpredict function, // so if branchPrediction != actualResult, you mispredicted--that is, return true return (branchPrediction != actualResult); }