<> <> <> <<0. Stack frames are saved/restored with traps disabled.>> <<1. Stack frames (from the euStack and ifuStack) are saved in dump frames.>> <<2. Dump frames are fixed-size (20 words) blocks of resident memory.>> <<3. A dump frame never contains more than one stack frame, but a stack frame may require several dump frames.>> <<4. A dummy frame is maintained at the eldest position in the stack to handle stack underflow, since there is no trap for stack underflow.>> <<>> DIRECTORY DragonProcessOffsets, DragOpsCross, HandCoding, HandCodingPseudos; DragonStackSave: CEDAR PROGRAM IMPORTS HandCoding, HandCodingPseudos = BEGIN OPEN DragonProcessOffsets, HandCoding, HandCodingPseudos; Word: TYPE = DragOpsCross.Word; StackLog: NAT = 7; <> RegArray: TYPE = ARRAY Reg OF Word; DumpFrame: TYPE = LONG POINTER TO DumpFrameRep; DumpFrameRep: TYPE = RECORD [ link: DumpFrame, -- link to previous frame lastPC: Word, -- continuation PC for this frame nRegs: Word, -- number of regs used for this frame at last save others: DumpFrame, -- if # NIL, then it is a pointer to an aux frame regs: RegArray -- addressable by local regs ]; linkOffset: NAT = 0; constLink: ConstSpec = const0; lastPCOffset: NAT = 1; constLastPC: ConstSpec = const1; nRegsOffset: NAT = 2; constNRegs: ConstSpec = const2; othersOffset: NAT = 3; constOthers: ConstSpec = const3; regOff: CARDINAL = 4; -- offset of DumpBlock.regs LocalAllocationRep: TYPE = RECORD [ lockPtr: GlobalAllocationPtr, -- pointer to global lock for frame allocation ptrs: LocalArray -- start of frame pointers ]; LocalArray: TYPE = ARRAY [0..16] OF DumpFrame; <> <> GlobalAllocationPtr: TYPE = LONG POINTER TO GlobalAllocationRep; GlobalAllocationRep: TYPE = RECORD [ lockPtr: Word, -- pointer to global lock for frame allocation gFree: Word, -- pointer to the next free frame in frames emergency: Word, -- pointer to the emergency limit for frames (not yet used) frames: GlobalArray -- space for the global pool of dump frames ]; GlobalArray: TYPE = ARRAY [0..1024] OF DumpFrame; <> <> StackMargin: NAT _ 8; <> framesToTransfer: NAT _ 4; <> <<>> StackUnderflowTrap: PROC = { <> setupLabel: Label = GenLabel[]; restoreLabel: Label = GenLabel[]; entryLabel: Label = GenLabelHere[]; freeRoutineLabel: Label = GenLabel[]; flushLabel: Label = GenLabel[]; MakeLabelGlobal["DragonStack.StackUnderflowTrap", entryLabel]; DisableTraps[]; <> <<>> drLFC[UseLabel16[flushLabel]]; <> SetLabel[flushLabel]; <> GetYoungestPC[]; <> GetEldestPC[]; <> drRJNEBJ[TRUE, popSrc, UseLabel8[flushLabel]]; <> ProcedureEntry[NIL, 0]; <> <<>> {loopLabel: Label = GenLabelHere[]; <> drLFC[UseLabel16[restoreLabel]]; <> DisableTraps[]; <> <<>> drJB[UseLabel8[loopLabel]]; <> }; SetLabel[freeRoutineLabel]; <> <> FreeDumpFrame[]; <> drRETN[]; <> <<>> SetLabel[setupLabel]; <> <<([S] = L = (oldL - #regs) MOD StackSize; [S-1] = #regs; [S-2] = 16)>> <<(sLimit = (L - StackMargin) MOD StackSize)>> <<(temp = hook'; hook = temp^)>> drLIB[16]; LRegI[hook, constNRegs]; <> <<([S] = #regs, [S-1] = 16)>> GetYoungestL[]; drRVSUB[c: topDst, a: topSrc, b: belowSrc]; <> <<([S] = oldL - #regs; [S-1] = #regs; [S-2] = 16)>> ExtractField[first: 32-StackLog, bits: StackLog]; <> <<([S] = (oldL - #regs) MOD StackSize; [S-1] = #regs; [S-2] = 16)>> drDUP[]; SetYoungestL[]; <> <<([S] = newL; [S-1] = #regs; [S-2] = 16).>> MoveReg[temp, hook]; <> MoveRegI[hook, hook, constLink]; <> drDUP[]; drSUBB[StackMargin]; <> <<([S] = newL-StackMargin; [S-1] = newL; [S-2] = #regs; [S-3] = 16)>> ExtractField[first: 32-StackLog, bits: StackLog]; SetSPLimit[]; <> <<(sLimit = (newL-StackMargin) MOD StackSize)>> <<([S] = newL; [S-1] = #regs; [S-2] = 16)>> drRETN[]; <> <<([S] = newL; [S-1] = #regs; [S-2] = 16)>> <<>> {shortLabel: Label = GenLabel[]; <> <<>> SetLabel[restoreLabel]; drLFC[3]; <> drLFC[UseLabel16[setupLabel]]; <> <<([S] = L = (oldL - #regs) MOD StackSize; [S-1] = #regs; [S-2] = 16)>> <<>> SetYoungestL[]; <> <<([S] = #regs; [S-1] = 16)>> LRegI[hook, constLastPC]; SetYoungestPC[]; <> drRJGEBJ[popLeft: FALSE, right: topSrc, dist: UseLabel8[shortLabel]]; <> {loopLabel: Label = GenLabelHere[]; < 16, so dump the first 16.>> <<>> <> FOR i: NAT IN [0..15] DO drRAI[reg1: [reg[i]], reg2: temp, disp: regOff+i]; ENDLOOP; LRegI[temp, constOthers]; <> <<([S] = nextDumpFrame; [S-1] = #regs; [S-2] = 16)>> drLFC[UseLabel16[freeRoutineLabel]]; <> SReg[temp]; <> <<([S] = #regs; [S-1] = 16)>> drARL[16]; drSUBB[16]; <> drRJLB[popLeft: FALSE, right: topSrc, dist: UseLabel8[loopLabel]]; <> }; SetLabel[shortLabel]; <> {jumpLabel: Label = GenLabel[]; <> drRVADD[c: belowDst, a: topSrc, b: topSrc]; <<([S] = #regs; [S-1] = 2*#regs)>> drRVADD[c: belowDst, a: belowSrc, b: belowSrc]; <<([S] = #regs; [S-1] = 4*#regs)>> drRVSUB[c: belowDst, a: popSrc, b: belowSrc]; <<([S] = -3*#regs)>> IndexedJump[dest: jumpLabel]; <> FOR i: NAT DECREASING IN [0..15] DO drRAI[reg1: [reg[i]], reg2: temp, disp: regOff+i]; ENDLOOP; SetLabel[jumpLabel]; }; drLFC[UseLabel16[freeRoutineLabel]]; <> <<>> <> <<>> drRETT[]; <<"Return" to the restored frame, enabling traps as we go. S is not changed.>> }; }; IFUStackOverflowTrap: PROC = { <> entryLabel: Label = GenLabelHere[]; callLabel: Label = GetGlobalLabel["DragonStack.InternalSaveEldest"]; MakeLabelGlobal["DragonStack.IFUStackOverflowTrap", entryLabel]; GetEldestPC[]; <> drLFC[UseLabel16[callLabel]]; <> <> GetEldestL[]; PReg[temp]; drSUBB[StackMargin]; <> ExtractField[first: 32-StackLog, bits: StackLog]; SetSPLimit[]; <> SetEldestPC[]; LReg[temp]; SetEldestL[]; <> drRETT[]; <> }; EUStackOverflowTrap: PROC = { <> entryLabel: Label = GenLabelHere[]; callLabel: Label = GetGlobalLabel["DragonStack.InternalSaveEldest"]; MakeLabelGlobal["DragonStack.EUStackOverflowTrap", entryLabel]; GetEldestPC[]; <> {loopLabel: Label = GenLabelHere[]; drLFC[UseLabel16[callLabel]]; <> LRegI[hook, constNRegs]; drRJNEB[right: const0, popLeft: TRUE, dist: UseLabel8[loopLabel]]; <> }; <> <<>> GetEldestL[]; PReg[temp]; drSUBB[StackMargin]; <> ExtractField[first: 32-StackLog, bits: StackLog]; SetSPLimit[]; <> SetEldestPC[]; LReg[temp]; SetEldestL[]; <> drRETT[]; <> }; RescheduleTrap: PROC = { <> entryLabel: Label = GenLabel[]; exitLabelLabel: Label = GenLabel[]; callLabel: Label = GetGlobalLabel["DragonStack.StackOverflowCall"]; schedBase: RegSpec = reg0; junkReg: RegSpec = reg1; nastyLabel: Label = GenLabel[]; trySched: Label = GenLabel[]; noSched: Label = GenLabel[]; callSched: Label = GenLabel[]; followOrders: Label = GenLabel[]; ProcedureEntry[entryLabel, 0]; MakeLabelGlobal["DragonStack.RescheduleTrap", entryLabel]; <> GetYoungestPC[]; <> <<([S] == schedBase = youngest PC)>> GetEldestPC[]; <> <<([S] == junkReg = eldest PC; [S-1] = youngest PC)>> drRJEB[popLeft: FALSE, right: schedBase, dist: UseLabel8[nastyLabel]]; <> <<([S] == junkReg = garbage; [S-1] == schedBase = garbage)>> <<>> drRAI[schedBase, global, pdSchedulerBase]; <> drRAI[junkReg, process, pdProcessPriority]; <> <> drLRIn[schedBase, pdSchedulerPriority]; <<[S] = lowest priority running process>> drRJGB[popLeft: TRUE, right: junkReg, dist: UseLabel8[trySched]]; SetLabel[noSched]; <> drRAI[junkReg, processor, pdProcessorOrders]; <> drJNEBB[UseLabel8[followOrders], LOOPHOLE[DragOpsCross.ProcessorOrders[reset]]]; <> <> <<>> drDIS[]; -- clear off the stack drRETT[]; <> SetLabel[nastyLabel]; <> <<([S] = eldest PC; [S-1] = youngest PC)>> <<>> SetEldestPC[]; <> drJ1[]; drJ1[]; <> drRET[0]; <> <<>> SetLabel[trySched]; <> <<>> LReg[schedBase]; IF pdSchedulerLock # 0 THEN drADDB[pdSchedulerLock]; <<([S] = addr of sched lock)>> LReg[process]; drLC0[]; <<([S] = 0; [S-1] = process addr; [S-2] = addr of sched lock)>> drCST[]; <> <<([S] = sample; [S-1] = 0; [S-2] = process addr; [S-3] = addr of sched lock)>> drRJEB[popLeft: TRUE, right: popSrc, dist: UseLabel8[callSched]]; <> drAS[2]; <> drJB[UseLabel8[noSched]]; <> <<>> SetLabel[callSched]; <> drAS[2]; <> drRRI[junkReg, schedBase, pdSchedulerOwnerCall]; drSFC[]; <> drRETT[]; <> SetLabel[followOrders]; <> drLRIn[schedBase, pdSchedulerOrdersCall]; drSFC[]; <> drRETT[]; <> }; InternalSaveEldest: PROC = { <> setupLabel: Label = GenLabel[]; allocRoutineLabel: Label = GenLabel[]; { SetLabel[allocRoutineLabel]; <> AllocDumpFrame[]; <> drLC0[]; drPSB[othersOffset]; <> drRETN[]; <> }; { <> <> <<[S] = newBlock; [S-1] = PC for dummy frame; hook = frame chain>> <> <<[S] = #regs; [S-1] = 16; L = L of frame to save>> localHook: RegSpec = reg0; localNRegs: RegSpec = reg1; ProcedureEntry[setupLabel, 1]; <> LReg[hook]; drPSB[linkOffset]; <> <<([S] = localHook = newBlock; (localHook+linkOffset)^ = hook)>> PReg[hook]; PReg[temp]; <> <<([S] = localHook = hook = temp = newBlock)>> GetEldestL[]; drDUP[]; SetYoungestL[]; <> <<([S] = localNRegs = L of frame to save; [S-1] = localHook)>> GetEldestPC[]; drSRIn[localHook, lastPCOffset]; <> <<((localHook+lastPCOffset)^ = PC of frame to save; [S-1] = localHook)>> GetEldestL[]; drRVSUB[c: topDst, a: topSrc, b: localNRegs]; <> <<([S] = localNRegs = eldestL - localNRegs'; [S-1] = localHook)>> ExtractField[first: 32-StackLog, bits: StackLog]; <> <<([S] = localNRegs = #regs = (eldestL - localNRegs') MOD StackSize)>> <<>> drWRI[localNRegs, localHook, nRegsOffset]; <> <<(localHook+nRegsOffset)^ = localNRegs>> <<>> drLIB[16]; SReg[localHook]; <<([S] = #regs; [S-1] = 16)>> drRETN[]; <> }; {entryLabel: Label = GenLabelHere[]; shortLabel: Label = GenLabel[]; MakeLabelGlobal["DragonStack.InternalSaveEldest", entryLabel]; drLFC[UseLabel16[allocRoutineLabel]]; <> <<([S] = newBlock; [S-1] = PC of dummy frame)>> drLFC[UseLabel16[setupLabel]]; <> <<([S] = #regs; [S-1] = 16)>> drRJGEBJ[popLeft: FALSE, right: topSrc, dist: UseLabel8[shortLabel]]; <> {loopLabel: Label = GenLabelHere[]; <<>> < 16, so dump the first 16. The save block to use has already been allocated, and its address is in temp.>> FOR i: NAT IN [0..15] DO drWAI[reg1: [reg[i]], reg2: temp, disp: regOff+i]; ENDLOOP; LReg[temp]; <> <<([S] = temp = oldBlock; [S-1] = #regs; [S-2] = 16)>> drLFC[UseLabel16[allocRoutineLabel]]; <> <<([S] = newBlock; [S-1] = temp = oldBlock; [S-2] = #regs; [S-3] = 16)>> PReg[temp]; drWSB[othersOffset]; <> <> <<(temp = (temp'+othersOffset)^ = newBlock; [S] = #regs; [S-1] = 16)>> drARL[16]; drSUBB[16]; <> <<([S] = #regs; [S-1] = 16)>> drRJLB[popLeft: FALSE, right: topSrc, dist: UseLabel8[loopLabel]]; <> }; <<>> SetLabel[shortLabel]; <<(#regs IN [0..16]; [S] = #regs; [S-1] = 16)>> {jumpLabel: Label = GenLabel[]; <> drRVADD[c: belowDst, a: topSrc, b: topSrc]; <<([S] = #regs; [S-1] = 2*#regs)>> drRVADD[c: belowDst, a: belowSrc, b: belowSrc]; <<([S] = #regs; [S-1] = 4*#regs)>> drRVSUB[c: belowDst, a: popSrc, b: belowSrc]; <<([S] = -3*#regs)>> IndexedJump[jumpLabel]; <> FOR i: NAT DECREASING IN [0..15] DO <> drWAI[reg1: [reg[i]], reg2: temp, disp: regOff+i]; ENDLOOP; SetLabel[jumpLabel]; }; drRETN[]; <> }; }; AllocDumpFrame: PROC = { <> exitLabel: Label = GenLabel[]; enterLabel: Label = GenLabelHere[]; LRegI[free, const0]; <> drRJNEBJ[right: const0, popLeft: FALSE, dist: UseLabel8[exitLabel]]; <> drRRX[c: topDst, a: base, b: const0]; <> LReg[process]; <> drLC0[]; <> {retryLabel: Label = GenLabelHere[]; drCST[0]; <> drRJEB[right: popSrc, popLeft: FALSE, dist: UseLabel8[retryLabel]]; <> drAS[2]; <> }; SubReg[free, const4]; <> LRegI[base, const0]; drRSB[1]; <> FOR i: NAT IN [0..4) DO drRSB[i]; LReg[free]; drWB[i]; <<(free+i)^ _ (gFree+i)^>> ENDLOOP; drADDB[framesToTransfer]; <> drPSB[1]; <> drLC0[]; drWSB[0]; <> drJB[UseLabel8[enterLabel]]; <> SetLabel[exitLabel]; <> AddReg[free, const1]; <> }; FreeDumpFrame: PROC [] = { <> exitLabel: Label = GenLabel[]; enterLabel: Label = GenLabelHere[]; drRVSUB[c: pushDst, a: free, b: const1]; <> drRJNEBJ[popLeft: FALSE, right: base, dist: UseLabel8[exitLabel]]; <> drRRX[c: topDst, a: base, b: const0]; <> LReg[process]; <> drLC0[]; <> {retryLabel: Label = GenLabelHere[]; drCST[0]; <> drRJEB[right: popSrc, popLeft: FALSE, dist: UseLabel8[retryLabel]]; <> drAS[2]; <> }; LRegI[base, const1]; drRSB[1]; <> drSUBB[4]; <> FOR i: NAT IN [0..4) DO LReg[free]; drRB[i]; drPSB[i]; <<(gFree+i)^ _ (free+i)^>> ENDLOOP; drPSB[1]; <> drLC0[]; drWSB[0]; <> drRVADD[c: pushDst, a: free, b: const3]; <> SetLabel[exitLabel]; <> <> PReg[free]; LReg[temp]; drWSB[0]; <<(free _ [S]-)^ _ temp>> }; All: PROC = { InternalSaveEldest[]; <> IFUStackOverflowTrap[]; EUStackOverflowTrap[]; RescheduleTrap[]; StackUnderflowTrap[]; }; END.