<> <> <> <> <<>> DIRECTORY Basics USING [CompareInt, Comparison], DragOpsCross USING [EUConstIndex, EUStackSize, FieldDescriptor, FourBytes, IFUOverflow, IFUStackSize, Inst, IOOperand, ioRescheduleRequest, ioResetRequest, LRBformat, LRRBformat, PCmdFormat, ProcessorRegister, QRformat, RJBformat, RRformat, TrapIndex, TwoBytes, TwoHalves, Word, ZerosByte, ZerosWord], DragOpsCrossUtils USING [AddDelta, ByteToCard, CardToFieldDescriptor, CardToWord, HalfToCard, TrapIndexToBytePC, VanillaAdd, VanillaSub, WordToBytes, WordToCard, WordToHalves, WordToInt, XopToBytePC], HandCodingUtil USING [GetInstArray, GetRegArray], IO USING [PutFR, rope], LizardHeart USING [ALUOps, ChangeLogger, Control, DoALUOp, FieldUnit, InstDoneProc, InstStartProc, IOChangeProc, LizardIFUStackIndex, LizardIFUStackSize, MemChangeProc, NoFault, OutsideEnvelope, Processor, RegChangeProc, RegPlus, RegToWord, StackPlus, TrapPC, WillPushOverflow, WordToReg], LizardLiver USING [], LizardTweaker USING [OpcodeHandler, OpcodeRegistry, OpcodeRegistryEntry, OpcodeRegistryRep]; LizardLiverImpl: CEDAR PROGRAM IMPORTS Basics, DragOpsCrossUtils, HandCodingUtil, IO, LizardHeart EXPORTS LizardLiver, LizardTweaker = BEGIN OPEN DragOpsCross, DragOpsCrossUtils, LizardHeart; CARD: TYPE = LONG CARDINAL; careful: BOOL _ TRUE; <> Register: PUBLIC PROC [inst: Inst, handler: LizardTweaker.OpcodeHandler, data: REF _ NIL] = { <> IF opcodeRegistry = NIL THEN opcodeRegistry _ NEW[LizardTweaker.OpcodeRegistryRep _ ALL[LizardTweaker.OpcodeRegistryEntry[NIL, NIL]]]; opcodeRegistry[inst] _ [handler, data]; flagsArray[inst].callMesa _ TRUE; }; opcodeRegistry: LizardTweaker.OpcodeRegistry _ NIL; Execute: PUBLIC PROC [processor: Processor, thisPC: Word, inst: Inst, rest: Word] RETURNS [newPC, rtnPC: Word, control: Control _ nextInst] = { trapCode: TrapIndex _ NoFault; logger: ChangeLogger = processor.logger; <> regS: ProcessorRegister = WordToReg[processor.regs[ifuS]]; <> regL: ProcessorRegister _ WordToReg[processor.regs[ifuL]]; <> sM1: ProcessorRegister _ StackPlus[regS, -1]; <> euBusyReg: ProcessorRegister _ processor.euBusyReg; <> <> flags: InstFlags _ flagsArray[inst]; cycles: NAT _ flags.cycles; alphaBetaGammaDeltaZ: CARD _ WordToCard[rest]; stackEffect: INTEGER _ flags.stackEffect; resReg: ProcessorRegister _ StackPlus[regS, stackEffect]; <> topOfStack: Word _ IF flags.usesTop THEN RegFetchInline[regS] ELSE ZerosWord; <> resWord: Word _ topOfStack; <> resAddr: Word _ topOfStack; <> bytes: CARDINAL _ flags.bytes; dispatch: Inst _ SELECT TRUE FROM flags.mod16 => VAL[ORD[inst] - (ORD[inst] MOD 16)], ENDCASE => inst; <> alphaBetaZ: CARDINAL _ 0; alphaZ: CARDINAL _ 0; betaZ: CARDINAL _ 0; formBytes2: TwoBytes; <> formBytes3: FourBytes; <> <> RegFetch: PROC [reg: ProcessorRegister] RETURNS [Word] = { <> IF reg = euBusyReg THEN { processor.stats.cycles _ processor.stats.cycles + 1; processor.stats.regBusyCycles _ processor.stats.regBusyCycles + 1; euBusyReg _ euJunk; }; IF NOT processor.regsGood[reg] THEN InitFault[reg]; RETURN [processor.regs[reg]]; }; RegFetchInline: PROC [reg: ProcessorRegister] RETURNS [Word] = INLINE { <> IF reg = euBusyReg THEN { processor.stats.cycles _ processor.stats.cycles + 1; processor.stats.regBusyCycles _ processor.stats.regBusyCycles + 1; euBusyReg _ euJunk; }; IF NOT processor.regsGood[reg] THEN InitFault[reg]; RETURN [processor.regs[reg]]; }; InitFault: PROC [reg: ProcessorRegister] = { SIGNAL OutsideEnvelope[IO.PutFR["Register %g was read before it was initialized.", IO.rope[HandCodingUtil.GetRegArray[][reg]]]]; }; RegStore: PROC [reg: ProcessorRegister, word: Word] = { <> IF logger # NIL THEN { regChange: RegChangeProc _ logger.regChange; IF regChange # NIL THEN { old: Word _ processor.regs[reg]; SELECT reg FROM ifuEldestPC => old _ processor.ifuStack[processor.eldest].pc; ifuEldestL => { old _ LOOPHOLE[processor.ifuStack[processor.eldest].status]; }; ifuYoungestPC => old _ processor.ifuStack[processor.youngest].pc; ifuYoungestL => old _ LOOPHOLE[processor.ifuStack[processor.youngest].status]; ENDCASE; regChange[logger.data, processor, reg, old, word]; }; }; processor.regsGood[reg] _ TRUE; processor.regs[reg] _ word; }; FastRegStore: PROC [reg: ProcessorRegister, word: Word] = INLINE { <> IF logger # NIL THEN { regChange: RegChangeProc _ logger.regChange; IF regChange # NIL THEN { old: Word _ processor.regs[reg]; regChange[logger.data, processor, reg, old, word]; }; }; processor.regsGood[reg] _ TRUE; processor.regs[reg] _ word; }; <> MemFetch: PROC [addr: Word] RETURNS [word: Word, code: TrapIndex] = INLINE { rejectCycles: INT; [word, code, rejectCycles] _ processor.euCache.fetch[ processor.euCache, addr, processor.stats.cycles, processor.userMode]; IF rejectCycles # 0 THEN processor.stats.cycles _ processor.stats.cycles + rejectCycles; IF code = NoFault THEN processor.stats.euFetches _ processor.stats.euFetches + 1 ELSE FastRegStore[euMAR, addr]; }; MemStore: PROC [addr: Word, word: Word] RETURNS [tx: TrapIndex] = { rejectCycles: INT; old: Word; [old, tx, rejectCycles] _ processor.euCache.store[ processor.euCache, addr, word, processor.stats.cycles, processor.userMode]; IF rejectCycles # 0 THEN processor.stats.cycles _ processor.stats.cycles + rejectCycles; IF tx = NoFault THEN { processor.stats.euStores _ processor.stats.euStores + 1; IF logger # NIL THEN { memChange: MemChangeProc _ logger.memChange; IF memChange # NIL THEN memChange[logger.data, processor, addr, old, word]; }; } ELSE FastRegStore[euMAR, addr]; }; IOFetch: PROC [cmd: PCmdFormat, addr: Word] RETURNS [word: Word, code: TrapIndex] = { <> RETURN [ZerosWord, NoFault]; }; IOStore: PROC [cmd: PCmdFormat, addr: Word, word: Word] RETURNS [TrapIndex] = { <> IF logger # NIL THEN { ioChange: IOChangeProc _ logger.ioChange; IF ioChange # NIL THEN ioChange[logger.data, processor, addr, IOFetch[cmd, addr].word, word]; }; SELECT WordToCard[word] FROM ioRescheduleRequest => { processor.rescheduleRequested _ TRUE; }; ioResetRequest => { processor.resetRequested _ TRUE; }; ENDCASE; RETURN [NoFault]; }; <> CalcReg: PROC [aux,opt: BOOL, regX: [0..15], dest: BOOL _ FALSE] RETURNS [reg: ProcessorRegister] = INLINE { <> IF NOT opt THEN RETURN [IF aux THEN RegPlus[euAux, regX] ELSE StackPlus[regL, regX]]; <<>> <> SELECT regX FROM IN EUConstIndex => RETURN [RegPlus[euConstant, regX]]; 12 => RETURN [regS]; 13 => RETURN [sM1]; ENDCASE; <> IF dest THEN {stackEffect _ stackEffect+1; RETURN [StackPlus[regS, 1]]}; <> stackEffect _ stackEffect - 1; RETURN [IF regX = 14 THEN regS ELSE sM1]; }; <> CauseTrap: PROC [code: TrapIndex] = { <> rtnPC _ thisPC; stackEffect _ 0; IF processor.trapsEnabled THEN SELECT TRUE FROM LizardHeart.WillPushOverflow[processor] => <> code _ IFUStackOverflowTrap; ENDCASE; newPC _ TrapPC[code]; control _ doAbort; IF code = IFUStackOverflowTrap THEN processor.stats.stackOver _ processor.stats.stackOver + 1; }; AdjustL: PROC [from: ProcessorRegister] RETURNS [BOOL] = { newValue: ProcessorRegister = StackPlus[from, alphaZ]; SELECT alphaZ FROM IN [EUStackSize/4..256-EUStackSize/4) => IF careful THEN SIGNAL OutsideEnvelope["VERY suspicious L adjustment!"]; ENDCASE; FastRegStore[ifuL, RegToWord[newValue]]; RETURN [TRUE]; }; <> AdjustS: PROC [from: ProcessorRegister] RETURNS [BOOL] = { newValue: ProcessorRegister = StackPlus[from, alphaZ]; SELECT alphaZ FROM IN [EUStackSize/4..256-EUStackSize/4) => IF careful THEN SIGNAL OutsideEnvelope["VERY suspicious S adjustment!"]; ENDCASE; IF processor.trapsEnabled THEN { sLimit: ProcessorRegister = WordToReg[processor.regs[ifuSLimit]]; IF (newValue.ORD-sLimit.ORD+EUStackSize) MOD EUStackSize IN [0..16) THEN { CauseTrap[EUStackOverflowTrap]; RETURN [FALSE]; }; }; FastRegStore[ifuS, RegToWord[newValue]]; RETURN [TRUE]; }; WillEUStackOverflow: PROC RETURNS [overflow: BOOL _ FALSE] = INLINE { IF stackEffect # 0 AND processor.trapsEnabled THEN { newS: ProcessorRegister = StackPlus[regS, stackEffect]; sLimit: ProcessorRegister = WordToReg[processor.regs[ifuSLimit]]; delta: CARDINAL = LOOPHOLE[newS.ORD-sLimit.ORD]; IF delta MOD EUStackSize IN [0..16) THEN { overflow _ TRUE; IF stackEffect < 0 AND careful THEN SIGNAL OutsideEnvelope["Backing up S into EU overflow!"]; }; }; }; newPC _ rtnPC _ AddDelta[bytes, thisPC]; <> IF flags.callMesa AND opcodeRegistry # NIL THEN { entry: LizardTweaker.OpcodeRegistryEntry _ opcodeRegistry[inst]; IF entry.handler # NIL THEN IF NOT entry.handler[entry.data, processor, inst, rest] THEN RETURN; }; <<**** This is where we log the start of the instruction, providing that someone is interested.>> IF logger # NIL THEN { instStart: InstStartProc _ logger.instStart; IF instStart # NIL THEN instStart[logger.data, processor, thisPC, inst, rest]; }; SELECT bytes FROM 2 => { alphaZ _ alphaBetaGammaDeltaZ; formBytes2 _ [LOOPHOLE[inst], LOOPHOLE[alphaZ]]; }; 3 => { alphaBetaZ _ alphaBetaGammaDeltaZ; alphaZ _ alphaBetaZ / 256; betaZ _ alphaBetaZ MOD 256; formBytes3 _ [LOOPHOLE[inst], LOOPHOLE[alphaZ], LOOPHOLE[betaZ], ZerosByte]; }; ENDCASE => NULL; processor.euBusyReg _ euJunk; <> { <> <<>> SELECT dispatch FROM dDFC => { <> newPC _ rest; GO TO call; }; dLIQB => { <> resWord _ rest; GO TO storeReg; }; dADDQB, dSUBQB => { <> [resWord, trapCode] _ DoALUOp[ processor, topOfStack, rest, IF inst = dADDQB THEN SAdd ELSE SSub, ALUCondOver]; GO TO aluDone; }; dJ5 => { <> GO TO noCheck; }; dJQB => { <> newPC _ rest; GO TO jump; }; <<>> dOR, dAND, dRX, dBC, dADD, dSUB, dLADD, dLSUB => { <> op: ALUOps; cond: TrapIndex _ ALUCondFalse; wordA: Word = RegFetchInline[sM1]; SELECT inst FROM dOR => { <> op _ Or; }; dAND => { <> op _ And; }; dRX => { <> resAddr _ VanillaAdd[wordA, topOfStack]; GO TO memFetch; }; dBC => { <= 0; S_S-1>> op _ BndChk; cond _ ALUCondBC; }; dADD => { <> op _ SAdd; cond _ ALUCondOver; }; dSUB => { <> op _ SSub; cond _ ALUCondOver; }; dLADD => { <> op _ LAdd; cond _ ALUCondIL; }; dLSUB => { <> op _ LSub; cond _ ALUCondIL; }; ENDCASE => GO TO xop; [resWord, trapCode] _ DoALUOp[processor, wordA, topOfStack, op, cond]; GO TO aluDone; }; dDUP => GO TO storeReg; <> dDIS => GO TO done; <> dEXDIS => GO TO storeReg; <> dSFC => { <> newPC _ topOfStack; GO TO call; }; dSFCI => { <> [newPC, trapCode] _ MemFetch[topOfStack]; IF trapCode # NoFault THEN GO TO memFault; GO TO call; }; dRETN => GO TO return; <> dKFC => { <> IF LizardHeart.WillPushOverflow[processor] THEN CauseTrap[IFUStackOverflowTrap] ELSE newPC _ CardToWord[DragOpsCrossUtils.XopToBytePC[inst]]; control _ doAbort; GO TO done; }; dJ1 => GO TO noCheck; <> dJSD => { <> newPC _ topOfStack; IF WillEUStackOverflow[] THEN GO TO euOverflow; GO TO jump; }; dJSR => { <> newPC _ VanillaAdd[thisPC, topOfStack]; IF WillEUStackOverflow[] THEN GO TO euOverflow; GO TO jump; }; dLC0, dLC1, dLC2, dLC3, dLC4, dLC5, dLC6, dLC7, dLC8, dLC9, dLC10, dLC11 => { <> resReg _ RegPlus[euConstant, ORD[inst] MOD 16]; GO TO pushReg; }; dLR0 => { <> resReg _ StackPlus[regL, ORD[inst] MOD 16]; GO TO pushReg; }; dSR0 => { <> resReg _ StackPlus[regL, ORD[inst] MOD 16]; GO TO storeReg; }; dQOR, dQAND, dQRX, dQBC, dQADD, dQSUB, dQLADD, dQLSUB => { OPEN form: LOOPHOLE[formBytes2, QRformat]; wordB: Word _ RegFetchInline[CalcReg[form.aux, form.opt, form.reg]]; op: ALUOps; cond: TrapIndex _ ALUCondFalse; sd: [0..1] _ 1; srcReg: ProcessorRegister _ regS; SELECT form.aOp FROM topAtop => sd _ 0; <> pushAtop => {}; <> pushA0 => srcReg _ euConstant; <> pushA1 => srcReg _ RegPlus[euConstant, 1]; <> ENDCASE; topOfStack _ RegFetchInline[srcReg]; -- the A operand word resReg _ StackPlus[regS, sd]; -- the C register stackEffect _ stackEffect + sd; -- the change to stack effect SELECT inst FROM dQOR => { <> op _ Or; }; dQAND => { <> op _ And; }; dQRX => { <> resAddr _ VanillaAdd[topOfStack, wordB]; GO TO memFetch; }; dQBC => { <= 0>> op _ BndChk; cond _ ALUCondBC; }; dQADD => { <> op _ SAdd; cond _ ALUCondOver; }; dQSUB => { <> op _ SSub; cond _ ALUCondOver; }; dQLADD => { <> op _ LAdd; cond _ ALUCondIL; }; dQLSUB => { <> op _ LSub; cond _ ALUCondIL; }; ENDCASE => ERROR; [resWord, trapCode] _ DoALUOp[processor, topOfStack, wordB, op, cond]; GO TO aluDone; }; dALS => { <> [] _ AdjustL[regS]; GO TO noCheck; }; dAL => { <> [] _ AdjustL[regL]; GO TO noCheck; }; dASL => { <> [] _ AdjustS[regL]; GO TO noCheck; }; dAS => { <> [] _ AdjustS[regS]; GO TO noCheck; }; dCST => { <> <<[S+1] _ ([S-2]+AlphaZ)^;>> <> <> resAddr _ AddDelta[alphaZ, RegFetch[StackPlus[regS, -2]]]; [resWord, trapCode] _ MemFetch[resAddr]; SELECT TRUE FROM trapCode # NoFault => GO TO memFault; WillEUStackOverflow[] => GO TO euOverflow; ENDCASE; RegStore[resReg, resWord]; IF resWord = topOfStack THEN { <> resWord _ RegFetch[sM1]; GO TO memStore; }; <> [] _ MemFetch[resAddr]; GO TO noCheck; }; dRET => { <> IF NOT AdjustS[regL] THEN GO TO noCheck; GO TO return; }; dLIP => { <> reg: ProcessorRegister _ LOOPHOLE[alphaZ]; IF reg > euLast THEN cycles _ cycles + 4; <> SELECT reg FROM ifuEldestPC => { <> eldest: NAT _ processor.eldest; entries: NAT _ processor.stackEntries; IF processor.userMode THEN GO TO modeFault; resWord _ processor.ifuStack[eldest].pc; IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuEldestPC."] ELSE { IF WillEUStackOverflow[] THEN GO TO euOverflow; <> processor.eldest _ (eldest + 1) MOD LizardIFUStackSize; processor.stackEntries _ entries - 1; }; }; ifuEldestL => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuEldestL."]; resWord _ LOOPHOLE[processor.ifuStack[processor.eldest].status]; }; ifuYoungestPC => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuYoungestPC."]; resWord _ processor.ifuStack[processor.youngest].pc; }; ifuYoungestL => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuYoungestL."]; resWord _ LOOPHOLE[processor.ifuStack[processor.youngest].status]; }; ENDCASE => resWord _ RegFetch[reg]; GO TO storeReg }; dSIP => { <> <> reg: ProcessorRegister _ LOOPHOLE[alphaZ]; IF processor.userMode THEN GO TO modeFault; [] _ WillEUStackOverflow[]; <> IF reg > euLast THEN cycles _ cycles + 4; <> resReg _ reg; SELECT reg FROM ifuEldestPC => { <> entries: NAT _ processor.stackEntries+1; eldest: NAT _ processor.eldest; IF LizardHeart.WillPushOverflow[processor] THEN { CauseTrap[IFUStackOverflowTrap]; GO TO done; }; processor.stackEntries _ entries; eldest _ (eldest + (LizardIFUStackSize - 1)) MOD LizardIFUStackSize; processor.eldest _ eldest; processor.ifuStack[eldest].pc _ resWord; GO TO storeRegIFU; }; ifuEldestL => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuEldestL."]; processor.ifuStack[processor.eldest].status _ LOOPHOLE[resWord]; GO TO storeRegIFU; }; ifuYoungestPC => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuYoungestPC."]; processor.ifuStack[processor.youngest].pc _ resWord; GO TO storeRegIFU; }; ifuYoungestL => { IF processor.stackEntries = 0 THEN SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuYoungestL."]; processor.ifuStack[processor.youngest].status _ LOOPHOLE[resWord]; GO TO storeRegIFU; }; ENDCASE; GO TO storeReg; }; dLIB => { <> resWord _ CardToWord[alphaZ]; GO TO storeReg; }; dADDB, dSUBB => { <> [resWord, trapCode] _ DoALUOp[ processor, topOfStack, CardToWord[alphaZ], IF inst = dADDB THEN SAdd ELSE SSub, ALUCondOver]; GO TO aluDone; }; dJ2 => GO TO noCheck; <> dJB => { <> alphaS: INT _ alphaZ; IF alphaZ > 127 THEN alphaS _ alphaS - 256; newPC _ AddDelta[alphaS, thisPC]; GO TO jump; }; dRB => GO TO memFetchAlpha; <> dWB => { <> resWord _ RegFetch[sM1]; GO TO memStoreAlpha; }; dRSB => GO TO memFetchAlpha; <> dWSB => { <> resAddr _ RegFetch[sM1]; GO TO memStoreAlpha; }; dIODA, dIOD, dION => { <> ioOp: IOOperand = [LOOPHOLE[alphaZ], LOOPHOLE[betaZ]]; pDataA: Word _ AddDelta[ByteToCard[ioOp.pDataA], (IF inst = dIODA THEN topOfStack ELSE CardToWord[0])]; WITH ioOp.pCmd SELECT FROM otherCmd: PCmdFormat.other => {}; cacheCmd: PCmdFormat.cache => { SELECT cacheCmd.direction FROM read => { IF inst = dIOD THEN resReg _ StackPlus[regS, stackEffect _ 1]; [resWord, trapCode] _ IOFetch[ioOp.pCmd, pDataA]; IF trapCode # NoFault THEN GO TO memFault; IF inst = dION THEN GO TO done; processor.euBusyReg _ resReg; GO TO storeReg; }; write => { SELECT inst FROM dIOD => stackEffect _ -1; dIODA => {resWord _ RegFetch[sM1]; stackEffect _ -2}; ENDCASE; trapCode _ IOStore[ioOp.pCmd, pDataA, resWord]; IF trapCode # NoFault THEN GO TO memFault; GO TO done; }; ENDCASE => ERROR; }; ENDCASE => ERROR; }; dPSB => { <> resAddr _ RegFetch[sM1]; GO TO memStoreAlpha; }; dLRI0 => { <> OPEN form: LOOPHOLE[formBytes2, LRBformat]; resAddr _ RegFetchInline[StackPlus[regL, form.reg]]; GO TO memFetchAlpha; }; dSRI0 => { <> OPEN form: LOOPHOLE[formBytes2, LRBformat]; resAddr _ RegFetchInline[StackPlus[regL, form.reg]]; GO TO memStoreAlpha; }; dROR, dRAND, dRRX, dRBC, dRADD, dRSUB, dRLADD, dRLSUB, dRXOR, dRFU, dRVADD, dRVSUB, dRUADD, dRUSUB => { OPEN form: LOOPHOLE[formBytes3, RRformat]; aux: BOOL = form.aux; regA: ProcessorRegister = CalcReg[aux, form.aOpt, form.a]; wordA: Word = RegFetchInline[regA]; regB: ProcessorRegister = CalcReg[aux, form.bOpt, form.b]; wordB: Word = RegFetchInline[regB]; op: ALUOps; cond: TrapIndex _ ALUCondFalse; resReg _ CalcReg[aux, form.cOpt, form.c, TRUE]; { <> firstProtectedAux: ProcessorRegister = euAux; lastProtectedAux: ProcessorRegister = VAL[ORD[firstProtectedAux]+7]; firstProtectedConst: ProcessorRegister = euConstant; lastProtectedConst: ProcessorRegister = VAL[ORD[firstProtectedConst]+11]; firstReadonlyConst: ProcessorRegister = euConstant; lastReadonlyConst: ProcessorRegister = VAL[ORD[firstProtectedConst]+3]; SELECT resReg FROM IN [firstProtectedAux..lastProtectedAux] => IF processor.userMode THEN GO TO modeFault; IN [firstProtectedConst..lastProtectedConst] => { IF processor.userMode THEN GO TO modeFault; IF resReg IN [firstReadonlyConst..lastReadonlyConst] THEN { SIGNAL OutsideEnvelope["Storing into readonly register not permited!"]; resWord _ CardToWord[ORD[resReg]]; trapCode _ NoFault; GO TO aluDone; } }; ENDCASE; }; SELECT inst FROM dROR => { <> op _ Or; }; dRAND => { <> op _ And; }; dRRX => { <> resAddr _ VanillaAdd[wordA, wordB]; GO TO memFetch; }; dRBC => { <= 0>> op _ BndChk; cond _ ALUCondBC; }; dRADD => { <> op _ SAdd; cond _ ALUCondOver; }; dRSUB => { <> op _ SSub; cond _ ALUCondOver; }; dRLADD => { <> op _ LAdd; cond _ ALUCondIL; }; dRLSUB => { <> op _ LSub; cond _ ALUCondIL; }; dRXOR => { <> op _ Xor; }; dRFU => { <> fd: FieldDescriptor = CardToFieldDescriptor[ HalfToCard[WordToHalves[RegFetch[euField]][1]] ]; resWord _ FieldUnit[wordA, wordB, fd]; GO TO storeReg; }; dRVADD => { <> resWord _ VanillaAdd[wordA, wordB]; GO TO storeReg; }; dRVSUB => { <> resWord _ VanillaSub[wordA, wordB]; GO TO storeReg; }; dRUADD => { <> op _ UAdd; }; dRUSUB => { <> op _ USub; }; ENDCASE => ERROR; [resWord, trapCode] _ DoALUOp[processor, wordA, wordB, op, cond]; GO TO aluDone; }; dLGF => { <> resAddr _ AddDelta[alphaBetaZ, RegFetch[euAux]]; GO TO memFetch; }; dLIDB => { <> resWord _ CardToWord[alphaBetaZ]; GO TO storeReg; }; dADDDB, dSUBDB => { <> [resWord, trapCode] _ DoALUOp[ processor, topOfStack, CardToWord[alphaBetaZ], IF inst = dADDDB THEN SAdd ELSE SSub, ALUCondOver]; GO TO aluDone; }; dJ3 => GO TO noCheck; <> dJDB => { <> newPC _ AddDelta[LOOPHOLE[alphaBetaZ, INTEGER], thisPC]; GO TO jump; }; dLFC => { <> newPC _ AddDelta[LOOPHOLE[alphaBetaZ, INTEGER], thisPC]; GO TO call; }; dRAI, dRRI, dWAI, dWRI => { OPEN form: LOOPHOLE[formBytes3, LRRBformat]; baseReg: ProcessorRegister _ SELECT inst FROM dRAI, dWAI => RegPlus[euAux, form.reg2], ENDCASE => StackPlus[regL, form.reg2]; resReg _ StackPlus[regL, form.reg1]; resAddr _ RegFetchInline[baseReg]; SELECT inst FROM dRAI, dRRI => { <> <> GO TO memFetchAlpha; }; dWAI, dWRI => { <> <> resWord _ RegFetchInline[resReg]; GO TO memStoreAlpha; }; ENDCASE => ERROR; }; dRJEB, dRJEBJ, dRJGB, dRJGBJ, dRJGEB, dRJGEBJ, dRJLB, dRJLBJ, dRJLEB, dRJLEBJ, dRJNEB, dRJNEBJ => { <> OPEN form: LOOPHOLE[formBytes3, RJBformat]; comparison: Basics.Comparison; regA: ProcessorRegister _ regS; SELECT form.aOp FROM c0 => regA _ euConstant; c1 => regA _ SUCC[euConstant]; top => regA _ regS; popTop => {regA _ regS; stackEffect _ stackEffect - 1}; ENDCASE; resWord _ RegFetchInline[regA]; comparison _ Basics.CompareInt[ WordToInt[resWord], WordToInt[RegFetchInline[CalcReg[form.aux, form.opt, form.reg]]]]; IF WillEUStackOverflow[] THEN GO TO euOverflow; SELECT inst FROM dRJEB, dRJEBJ => IF comparison = equal THEN GO TO condJump; dRJGB, dRJGBJ => IF comparison = greater THEN GO TO condJump; dRJGEB, dRJGEBJ => IF comparison # less THEN GO TO condJump; dRJLB, dRJLBJ => IF comparison = less THEN GO TO condJump; dRJLEB, dRJLEBJ => IF comparison # greater THEN GO TO condJump; dRJNEB, dRJNEBJ => IF comparison # equal THEN GO TO condJump; ENDCASE => ERROR; <> GO TO condFall; }; dJEBB, dJEBBJ => < PC_PC+BetaS; S_S-1>> IF topOfStack = CardToWord[alphaZ] THEN GO TO condJump ELSE GO TO condFall; dJNEBB, dJNEBBJ => < PC_PC+BetaS; S_S-1>> IF topOfStack # CardToWord[alphaZ] THEN GO TO condJump ELSE GO TO condFall; dSHL => { <> topOfStack _ ZerosWord; GO TO storeField; }; dSHR => GO TO storeField; <> dSHDL => { <> resWord _ RegFetch[sM1]; GO TO storeField; }; dSHDR => { <> resWord _ topOfStack; topOfStack _ RegFetch[sM1]; GO TO storeField; }; dFSDB => { <> resWord _ VanillaAdd[CardToWord[alphaBetaZ], topOfStack]; resReg _ euField; GO TO storeReg; }; x311b, x313b, x337b, x340b, x344b, x350b, x354b => { SIGNAL OutsideEnvelope[IO.PutFR["Opcode %g has undefined effects", IO.rope[HandCodingUtil.GetInstArray[][inst]]]]; GO TO xop; }; ENDCASE => NULL; GO TO xop; EXITS done => { <> IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap]; }; noCheck => { <> }; xop => { <> stackEffect _ 0; control _ doCall; newPC _ CardToWord[DragOpsCrossUtils.XopToBytePC[inst]]; SELECT TRUE FROM LizardHeart.WillPushOverflow[processor: processor] => CauseTrap[IFUStackOverflowTrap]; bytes > 1 => { <> cycles _ cycles+1; stackEffect _ 1; resWord _ rest; IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE RegStore[StackPlus[regS, stackEffect], resWord]; }; ENDCASE; }; condJump => { <> betaS: INT _ betaZ; IF betaZ > 127 THEN betaS _ betaS - 256; newPC _ AddDelta[betaS, thisPC]; IF flags.predictJump THEN processor.stats.jumpGood _ processor.stats.jumpGood + 1 ELSE { control _ doSwitch; processor.stats.fallThruBad _ processor.stats.fallThruBad + 1; cycles _ cycles+3; }; IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap]; }; condFall => { <> IF flags.predictJump THEN { control _ doSwitch; processor.stats.jumpBad _ processor.stats.jumpBad + 1; cycles _ cycles+3; } ELSE processor.stats.fallThruGood _ processor.stats.fallThruGood + 1; IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap]; }; jump => { <> processor.stats.jumps _ processor.stats.jumps + 1; control _ doSwitch; }; call => { SELECT TRUE FROM LizardHeart.WillPushOverflow[processor] => CauseTrap[IFUStackOverflowTrap]; WillEUStackOverflow[] => CauseTrap[EUStackOverflowTrap]; ENDCASE => { processor.stats.calls _ processor.stats.calls + 1; control _ doCall; }; }; return => { <> SELECT processor.stackEntries FROM = 0 => SIGNAL OutsideEnvelope["IFU control stack is empty during return!"]; > IFUStackSize => SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; > IFUOverflow => IF processor.trapsEnabled THEN SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; ENDCASE; control _ doReturn; rtnPC _ processor.ifuStack[processor.youngest].pc; <> }; modeFault => { <> CauseTrap[ModeFault]; }; euOverflow => { <> CauseTrap[EUStackOverflowTrap]; }; pushReg => { <> IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE FastRegStore[StackPlus[regS, 1], RegFetchInline[resReg]]; }; storeField => { <> IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE FastRegStore[resReg, FieldUnit[resWord, topOfStack, CardToFieldDescriptor[alphaBetaZ]]]; }; storeRegIFU => { <> IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE RegStore[resReg, resWord]; }; storeReg => { <> IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE FastRegStore[resReg, resWord]; }; aluDone => { SELECT TRUE FROM trapCode # NoFault => CauseTrap[trapCode]; WillEUStackOverflow[] => CauseTrap[EUStackOverflowTrap]; ENDCASE => FastRegStore[resReg, resWord]; }; memFault => { CauseTrap[trapCode]; }; memFetch => { IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE { [resWord, trapCode] _ MemFetch[resAddr]; SELECT TRUE FROM trapCode # NoFault => CauseTrap[trapCode]; ENDCASE => {FastRegStore[resReg, resWord]; processor.euBusyReg _ resReg}; }; }; memFetchAlpha => { IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap] ELSE { [resWord, trapCode] _ MemFetch[AddDelta[alphaZ, resAddr]]; SELECT TRUE FROM trapCode # NoFault => CauseTrap[trapCode]; ENDCASE => {FastRegStore[resReg, resWord]; processor.euBusyReg _ resReg}; }; }; memStore => { SELECT TRUE FROM WillEUStackOverflow[] => CauseTrap[EUStackOverflowTrap]; ENDCASE => { trapCode _ MemStore[resAddr, resWord]; IF trapCode # NoFault THEN CauseTrap[trapCode]; }; }; memStoreAlpha => { resAddr _ AddDelta[alphaZ, resAddr]; SELECT TRUE FROM WillEUStackOverflow[] => CauseTrap[EUStackOverflowTrap]; ENDCASE => { trapCode _ MemStore[resAddr, resWord]; IF trapCode # NoFault THEN CauseTrap[trapCode]; }; }; }; IF stackEffect # 0 THEN processor.regs[ifuS] _ RegToWord[StackPlus[regS, stackEffect]]; processor.stats.cycles _ processor.stats.cycles + cycles; IF control # doAbort THEN processor.stats.instructions _ processor.stats.instructions+1; IF logger # NIL THEN { instDone: InstDoneProc _ logger.instDone; IF instDone # NIL THEN instDone[logger.data, processor, newPC, rtnPC, control, cycles]; }; }; flagsArray: REF ARRAY Inst OF InstFlags _ NIL; InstFlags: TYPE = RECORD [ usesTop: BOOL _ FALSE, predictJump: BOOL _ FALSE, mod16: BOOL _ FALSE, callMesa: BOOL _ FALSE, cycles: [0..15] _ 1, bytes: [0..7] _ 1, stackEffect: [-2..1] _ 0]; InitFlagsArray: PROC = { defaultFlags: InstFlags _ []; flagsArray _ NEW[ARRAY Inst OF InstFlags]; FOR inst: Inst IN Inst DO bytes: NAT _ ORD[inst] / 64; flags: InstFlags _ defaultFlags; IF bytes = 0 THEN IF ORD[inst] < 40B THEN bytes _ 1 ELSE bytes _ 5; flags.bytes _ bytes; SELECT inst FROM dWB, dWSB => flags.stackEffect _ -2; dDIS, dEXDIS, dSFC, dJSD, dJSR, dPSB, dSIP, dSHDL, dSHDR, dFSDB, dJEBB, dJEBBJ, dJNEBB, dJNEBBJ, IN[dOR..dLSUB], IN [dSR0..dSR15], IN [dSRI0..dSRI15] => flags.stackEffect _ -1; dLIQB, dDUP, dCST, dLIP, dLIB, dRSB, dLGF, dLIDB, IN [dLC0..dLC11], IN [dLR0..dLR15], IN [dLRI0..dLRI15], x060b, x063b, x215b, x223b, IN [x234b..x236b], IN [x364b..x367b], IN [x374b..x377b] => flags.stackEffect _ 1; ENDCASE; SELECT inst FROM dCST => flags.cycles _ 8; dSFC, dSFCI, dJSD, dJSR => flags.cycles _ 4; dRET, dRETN, dKFC => flags.cycles _ 2; ENDCASE; SELECT inst FROM IN [dSR0..dSR15], IN [dSRI0..dSRI15], IN[dOR..dLSUB], dDUP, dEXDIS, dSFC, dSFCI, dJSD, dJSR, dCST, dSIP, dADDQB, dSUBQB, dADDB, dSUBB, dRB, dWB, dRSB, dWSB, dPSB, dADDDB, dSUBDB, dJEBB, dJEBBJ, dJNEBB, dJNEBBJ, dSHL, dSHR, dSHDL, dSHDR, dFSDB, dIODA, dIOD, dION => flags.usesTop _ TRUE; ENDCASE; SELECT inst FROM dRJEBJ, dRJGBJ, dRJGEBJ, dRJLBJ, dRJLEBJ, dRJNEBJ, dJEBBJ, dJNEBBJ => flags.predictJump _ TRUE; ENDCASE; SELECT inst FROM IN [dSR0..dSR15], IN [dSRI0..dSRI15], IN [dLR0..dLR15], IN [dLRI0..dLRI15] => flags.mod16 _ TRUE; ENDCASE; flagsArray[inst] _ flags; ENDLOOP; }; InitFlagsArray[]; END.