InstructionExecute: PUBLIC PROC [processor: Processor, mi: MicroInstruction] = { p: Processor = processor; -- for a short name SELECT control FROM nextInst => {}; doSwitch => ForceBufferEmpty[]; doCall, doAbort, doReturn => { lastCallDelta: INT _ p.stats.instructions - p.lastCallRtn; ForceBufferEmpty[]; IF control = doReturn THEN { currentSize: NAT _ p.stackEntries; stackedStatus: TamarinOps.StackedStatusWord _ p.ifuStack[youngest].status; SELECT currentSize FROM = 0 => { SIGNAL OutsideEnvelope["IFU control stack empty on return!"]; thisPC _ TrapPC[StackUnderflowTrap]; GO TO badGnus; }; > IFUStackSize => { SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; GO TO badGnus; }; > IFUOverflow => IF stackedStatus.trapsEnabled THEN { SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; GO TO badGnus; }; ENDCASE; p.trapsEnabled _ stackedStatus.trapsEnabled; p.userMode _ stackedStatus.userMode; p.stackEntries _ currentSize - 1; thisPC _ p.ifuStack[youngest].pc; p.regs[ifuL] _ regL _ RegToWord[VAL[stackedStatus.lBase]]; p.youngest _ youngest _ (youngest + (MonkeyIFUStackSize - 1)) MOD MonkeyIFUStackSize; EXITS badGnus => {}; } ELSE { newSize: NAT _ p.stackEntries+1; stackedStatus: TamarinOps.StackedStatusWord _ [ version: CurrentProcVersion, userMode: p.userMode, trapsEnabled: p.trapsEnabled, lBase: ORD[WordToReg[regL]] ]; IF newSize > IFUStackSize THEN SIGNAL OutsideEnvelope["IFU control stack too full!"] ELSE { p.stackEntries _ newSize; p.youngest _ youngest _ (youngest + 1) MOD MonkeyIFUStackSize; }; p.ifuStack[youngest] _ [rtnPC, stackedStatus]; IF control = doAbort THEN p.userMode _ p.trapsEnabled _ FALSE; IF tx # NoFault THEN IF p.logger # NIL AND p.logger.instDone # NIL THEN p.logger.instDone[p.logger.data, p, newPC, rtnPC, doAbort, cycles]; }; SELECT lastCallDelta FROM >= 3, < 0 => {}; ENDCASE => { cycles _ cycles + (3-lastCallDelta); p.stats.returnInterlockCycles _ p.stats.returnInterlockCycles + lastCallDelta; }; p.lastCallRtn _ p.stats.instructions; }; ENDCASE => ERROR; p.regs[ifuPC] _ thisPC; p.stats.cycles _ p.stats.cycles+cycles; p.stats.instBytes _ p.stats.instBytes+nBytes; }; MemoryCycle: PROC [processor: Processor] ~ { IF instBuffer.busyUntil <= initCycles+cycles THEN { IF valid <= max-bytesPerWord THEN { fetchPC: Word _ IntToWord[WordToInt[newPC] + valid]; IF instBuffer.validWords = instBuffer.max THEN FlushInstWord[]; [wordAddr, rbi] _ BytePCToWordAddress[[fetchPC]]; IF rbi # 0 THEN ERROR; -- rats! we blew it! [word, tx, rCycles] _ p.ifuCache.fetch[p.ifuCache, wordAddr, initCycles+cycles, p.userMode]; p.stats.lookaheadProbes _ p.stats.lookaheadProbes + 1; IF rCycles # 0 THEN { instBuffer.busyUntil _ p.ifuCache.sharedBase.busyUntil; p.stats.lookaheadRejects _ p.stats.lookaheadRejects + rCycles; }; IF tx = NoFault THEN { instBuffer[instBuffer.validWords] _ word; instBuffer.validWords _ instBuffer.validWords + 1; }; tx _ NoFault; }; }; }; MonkeyHeartImpl.extras Last Edited by: Ross February 3, 1987 3:48:57 pm PST Last Edited by: Ross February 3, 1987 10:18:02 am PST Continue with the new PC. This will be the case even if we are branching. A mispredicted jump will have cleared the instruction buffer in MonkeyLiver.Execute. Continue with the new PC, but also flush the instruction buffer. This is the case for mispredicted jumps, or for stack jumps. For doCall & doAbort, just push the PC, the overflow checking was done by the instruction execution. We force kernel with traps disabled. We get here due to an early fault (like an IFUPageFault). The idea is to log the completion of the instruction, although no instruction was really started! This aids "shadow" simulations like McCreight's. We must delay to allow changes in the IFU stack from the last call/return to become stable. This test is somewhat conservative, since multi-cycle instructions will allow the ifuStack to be stable sooner than this. However, this is a cheap way to estimate this extra delay. Try to fetch ahead if the bus is not busy, and we need more bytes in the instruction buffer. Note that this may cause more contention for the bus than we might like, but that the bytes should be ready at the proper time in straight-line code. The instruction buffer is not trying to fetch anything from the cache, so we can use the cache to try to get the next instruction. There is room to get more words into the buffer We have completely filled the inst buffer, but still need more, so shift out the lowest address word, and update the base address and # of bytes valid. The reject cycles occur in the background, and are not counted towards elapsed cycles. But we do keep track of the next time that the ifu cache will be available. The fetch was successful, so we can put more bytes into the inst buffer. Note that we restrict the max bytes in the buffer to be a multiple of bytesPerWord. There will be no wraparound in the buffer for this word fetch. Make sure that the readahead fault does not show up later. ΚΙ˜codešœ™K™4K™K™5K™—šΟnœΟkœžœ1˜PKšœΟc˜.K˜šžœ ž˜šœ˜Kšœ ™ —šœ ˜ Kšœ~™~Kšœ˜—šœ˜Kšœžœ(˜:Kšœ˜šžœ˜šžœ˜Kšœ žœ˜"KšœJ˜Jšžœ ž˜˜Kšžœ7˜=Kšœ$˜$Kšžœžœ ˜K˜—˜KšžœA˜GKšžœžœ ˜K˜—šœ˜šžœžœ˜$KšžœA˜GKšžœžœ ˜K˜——Kšžœ˜—Kšœ,˜,Kšœ$˜$Kšœ!˜!Kšœ!˜!Kšœ žœ˜:Kšœ>žœ˜UKšžœ˜K˜—šžœ˜Kšœd™dKšœ žœ˜ šœ/˜/Kšœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜—šžœ˜Kšž œ/˜:šžœ˜Kšœ˜Kšœ'žœ˜>K˜——Kšœ.˜.šžœž˜Kšœ$™$Kšœžœ˜$—šžœž˜KšœΞ™Ξš žœ žœžœžœž˜2KšœC˜C——K˜——šžœž˜K˜šžœ˜ Kšœ’™’Kšœ$˜$KšœN˜NK˜——Kšœ%˜%Kšœ˜—Kšžœžœ˜—Kšœ˜Kšœ'˜'Kšœ-˜-K˜K˜—š œžœ˜-Kšœσ™σšžœ+žœ˜3Kšœ‚™‚šžœžœ˜#Kšœ/™/Kšœ4˜4šžœ(žœ˜?Kšœ—™——Kšœ1˜1Kšžœ žœžœŸ˜,Kšœ\˜\Kšœ6˜6šžœ žœ˜Kšœ£™£Kšœ7˜7Kšœ>˜>K˜—šžœžœ˜Kšœέ™έKšœ)˜)Kšœ2˜2K˜—šœ ˜ Kšœ:™:—K˜—Kšœ˜—K˜K˜K˜—J˜—…— ‚]