-- LaurelResident.Mesa; edited by Taft on May 2, 1983 5:20 PM -- Copyright Xerox Corporation 1979, 1980 -- Same as Resident.mesa for Mesa 6 except that the InterruptProcess has been -- removed (Laurel has its own version), and the Alto-I parity error at 600 bug -- has been programmed around. DIRECTORY AltoDefs USING [PageSize], AltoFileDefs USING [CFP], BcplOps USING [BcplInLd, BcplOutLd], ControlDefs USING [ AV, AVItem, ControlLink, EntryInfo, FrameHandle, FrameVec, GFT, GFTIndex, GFTItem, GlobalFrameHandle, LargeReturnSlot, Port, PrefixHandle, ProcDesc, SpecialReturnSlot, StateVector, TraceNext, TraceOff, TrapStatus], CoreSwapDefs USING [ExternalStateVector, PuntInfo, SVPointer], DiskDefs USING [CBNil, NextDiskCommand], FrameDefs USING [SwapInCode], FrameOps USING [ GetReturnLink, MyLocalFrame, ReleaseCode, SetReturnFrame, SetReturnLink, Start], ImageDefs USING [AbortMesa, PuntMesa], InlineDefs USING [BITOR], KeyDefs USING [KeyBits, Keys, updown], LaurelInterrupt USING [], Mopcodes USING [zKFCB, zPOP, zRBL, zSTARTIO], NucleusOps USING [], ProcessDefs USING [DisableInterrupts, EnableInterrupts], ProcessOps USING [ActiveWord, ReadWDC, WakeupsWaiting, WriteWDC], Runtime USING [], SDDefs USING [sAllocTrap, SD, sIOResetBits, sProcessBreakpoint, sXferTrap], SDOps USING [], SegmentDefs USING [ DataSegmentAddress, DataSegmentHandle, DefaultMDSBase, DeleteDataSegment, FrameDS, MakeDataSegment], TrapDefs USING [], TrapOps USING [ReadATP, ReadOTP, ReadXTS, WriteXTS]; Resident: MONITOR IMPORTS BcplOps, FrameDefs, FrameOps, ImageDefs, InlineDefs, LaurelInterrupt, ProcessDefs, ProcessOps, SegmentDefs, TrapOps EXPORTS CoreSwapDefs, FrameOps, NucleusOps, Runtime, SDOps, TrapDefs SHARES LaurelInterrupt = BEGIN OPEN ControlDefs; -- allocation of frame space LargeFrameSlot: CARDINAL = 12; FrameSize: PUBLIC PROCEDURE [fsi: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN[FrameVec[fsi]] END; pgft: TYPE = POINTER TO ARRAY [0..0) OF GFTItem; ItemPointer: TYPE = POINTER TO ControlDefs.AVItem; FrameSegment: TYPE = MACHINE DEPENDENT RECORD [ segment: SegmentDefs.DataSegmentHandle, link: POINTER TO FrameSegment, size, fsi: CARDINAL]; -- maintain a list of all new "permanent" frame segments; SegHeader: PUBLIC TYPE = RECORD [ seg: SegmentDefs.DataSegmentHandle, link: pSegHeader]; pSegHeader: PUBLIC TYPE = POINTER TO SegHeader; SegListHead: PUBLIC pSegHeader _ NIL; ExtraSpaceSize: CARDINAL = 170B; ExtraSpace: ARRAY [0..ExtraSpaceSize) OF WORD; InitNewSpace: POINTER = LOOPHOLE[InlineDefs.BITOR[BASE[ExtraSpace], 3]]; InitWordsLeft: CARDINAL = BASE[ExtraSpace] + ExtraSpaceSize - InitNewSpace; NULLPtr: FrameHandle = LOOPHOLE[0]; AllocTrap: PUBLIC PROCEDURE [otherframe: FrameHandle] RETURNS [myframe: FrameHandle] = BEGIN OPEN SegmentDefs; ATFrame: TYPE = POINTER TO FRAME[AllocTrap]; state: StateVector; newframe: FrameHandle; newseg: DataSegmentHandle; long: BOOLEAN; i, fsize, fIndex: CARDINAL; p: POINTER; newG: GlobalFrameHandle; NewSpacePtr: POINTER; WordsLeft: CARDINAL _ 0; recurring: BOOLEAN _ otherframe = NULLPtr; alloc: BOOLEAN; dest, tempdest: ControlLink; gfi: GFTIndex; ep: CARDINAL; myframe _ FrameOps.MyLocalFrame[]; state.dest _ myframe.returnlink; state.source _ 0; state.instbyte _ 0; state.stk[0] _ myframe; state.stkptr _ 1; ProcessDefs.DisableInterrupts[]; -- so that undo below works DO ENABLE ANY => ImageDefs.PuntMesa[]; IF ~recurring THEN BEGIN LOOPHOLE[otherframe, ATFrame].NewSpacePtr _ InitNewSpace; LOOPHOLE[otherframe, ATFrame].WordsLeft _ InitWordsLeft; AV[SpecialReturnSlot] _ [data[0, empty]]; END; -- the following RR and POP is to guarantee that there is no NOOP between -- the DWDC and the LST [] _ TrapOps.ReadATP[]; ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; state _ STATE; dest _ TrapOps.ReadATP[]; SDDefs.SD[SDDefs.sAllocTrap] _ otherframe; myframe.returnlink _ state.source; tempdest _ dest; DO SELECT tempdest.tag FROM frame => BEGIN alloc _ TRUE; fIndex _ LOOPHOLE[tempdest, CARDINAL]/4; EXIT END; procedure => BEGIN OPEN proc: LOOPHOLE[tempdest, ProcDesc]; gfi _ proc.gfi; ep _ proc.ep; [frame: newG, epbase: fIndex] _ GFT[gfi]; -- use fIndex as temp long _ newG.code.highByte = 0; IF long THEN BEGIN GetEntryInfo: PROCEDURE [LONG POINTER] RETURNS [EntryInfo] = MACHINE CODE BEGIN Mopcodes.zRBL, 1 END; info: EntryInfo _ GetEntryInfo[ @LOOPHOLE[newG.code.longbase, LONG PrefixHandle].entry[ fIndex + ep]]; fIndex _ info.framesize; END ELSE fIndex _ LOOPHOLE[newG.code.shortbase, PrefixHandle].entry[ fIndex + ep].info.framesize; alloc _ FALSE; EXIT END; indirect => tempdest _ tempdest.link^; ENDCASE => ImageDefs.PuntMesa[]; ENDLOOP; IF ~recurring THEN FlushLargeFrames[] ELSE IF (p _ AV[SpecialReturnSlot].link) # LOOPHOLE[AVItem[data[0, empty]]] THEN BEGIN WordsLeft _ WordsLeft + (NewSpacePtr - p + 1); NewSpacePtr _ p - 1; AV[SpecialReturnSlot] _ [data[0, empty]]; END; IF fIndex < LargeFrameSlot THEN BEGIN fsize _ FrameVec[fIndex] + 1; -- includes overhead word THROUGH [0..1] DO p _ NewSpacePtr + 1; IF fsize <= WordsLeft THEN BEGIN newframe _ p; (p - 1)^ _ IF recurring THEN SpecialReturnSlot ELSE fIndex; WordsLeft _ WordsLeft - fsize; NewSpacePtr _ NewSpacePtr + fsize; EXIT; END ELSE BEGIN IF recurring THEN ImageDefs.PuntMesa[]; FOR i DECREASING IN [0..fIndex) DO IF FrameVec[i] < WordsLeft THEN BEGIN (p - 1)^ _ i; p^ _ AV[i].link; AV[i].link _ p; EXIT; END; ENDLOOP; newseg _ MakeDataSegment[DefaultMDSBase, 1, [hard, topdown, frame]]; newseg.type _ FrameDS; NewSpacePtr _ (p _ DataSegmentAddress[newseg]) + 3; LOOPHOLE[p, pSegHeader]^ _ [newseg, SegListHead]; SegListHead _ p; WordsLeft _ AltoDefs.PageSize - 3; END; ENDLOOP END ELSE BEGIN fsize _ FrameVec[fIndex]; p _ DataSegmentAddress[ newseg _ MakeDataSegment[ base: DefaultMDSBase, info: [hard, topdown, frame], pages: (fsize + AltoDefs.PageSize + 3)/AltoDefs.PageSize]]; newseg.type _ FrameDS; newframe _ p + 4; LOOPHOLE[p, POINTER TO FrameSegment]^ _ [segment: newseg, link: NIL, size: fsize, fsi: LargeReturnSlot]; END; IF alloc THEN BEGIN state.dest _ myframe.returnlink; state.stk[state.stkptr] _ newframe; state.stkptr _ state.stkptr + 1; END ELSE BEGIN state.dest _ dest; newframe.accesslink _ LOOPHOLE[AV[fIndex].link]; AV[fIndex].frame _ newframe; state.source _ myframe.returnlink; END; SDDefs.SD[SDDefs.sAllocTrap] _ myframe; ENDLOOP; END; -- FlushLargeFrames' frame must be larger than MDSRegion Update's frame FlushLargeFrames: PUBLIC PROCEDURE = BEGIN p: ARRAY [0..10) OF POINTER; -- ensure large enough frame item: ItemPointer _ @AV[LargeReturnSlot]; WHILE item.tag = frame DO p[0] _ item.frame; item.frame _ p[0]^; SegmentDefs.DeleteDataSegment[LOOPHOLE[(p[0] - 4)^]]; ENDLOOP; END; -- other traps UnboundProcedure: PUBLIC SIGNAL [dest: ControlLink] RETURNS [ControlLink] = CODE; UnboundProcedureTrap: PUBLIC PROCEDURE = BEGIN dest: ControlLink; state: StateVector; ProcessDefs.DisableInterrupts[]; state _ STATE; dest _ TrapOps.ReadOTP[]; ProcessDefs.EnableInterrupts[]; state.source _ FrameOps.GetReturnLink[]; state.dest _ SIGNAL UnboundProcedure[dest]; RETURN WITH state END; CodeTrap: PUBLIC PROCEDURE = BEGIN dest: ControlLink; state: StateVector; frame: GlobalFrameHandle; ProcessDefs.DisableInterrupts[]; state _ STATE; dest _ TrapOps.ReadOTP[]; ProcessDefs.EnableInterrupts[]; state.dest _ dest; state.source _ FrameOps.GetReturnLink[]; DO SELECT dest.tag FROM frame => BEGIN frame _ dest.frame.accesslink; EXIT END; procedure => BEGIN frame _ GFT[dest.gfi].frame; EXIT END; ENDCASE => dest _ dest.link^; ENDLOOP; IF ~frame.started THEN FrameOps.Start[[frame[frame]]]; FrameDefs.SwapInCode[frame]; FrameOps.ReleaseCode[frame]; RETURN WITH state; END; -- Parity Errors ParityError: PUBLIC SIGNAL [address: POINTER] = CODE; PhantomParityError: PUBLIC SIGNAL = CODE; parityWakeup: PUBLIC CONDITION; ParityProcess: PUBLIC ENTRY PROCEDURE = BEGIN OPEN ProcessOps; p: ORDERED POINTER; ww: POINTER TO MACHINE DEPENDENT RECORD [ other: [0..77777B], parity: BOOLEAN] _ LOOPHOLE[WakeupsWaiting]; etherPostLoc: POINTER = LOOPHOLE[600B]; POP: PROCEDURE [WORD] = MACHINE CODE BEGIN Mopcodes.zPOP END; DO -- forever WAIT parityWakeup; ActiveWord^ _ 0; etherPostLoc^ _ etherPostLoc^; IF ~ww.parity THEN FOR p DECREASING IN [LOOPHOLE[0]..LOOPHOLE[177000B]) DO POP[p^]; IF ww.parity THEN BEGIN SIGNAL ParityError[p]; EXIT END; REPEAT FINISHED => SIGNAL PhantomParityError; ENDLOOP; ww.parity _ FALSE; ActiveWord^ _ 77777B; ENDLOOP; END; -- Getting the Debugger level: PUBLIC INTEGER; StartIO: PROCEDURE [CARDINAL] = MACHINE CODE BEGIN Mopcodes.zSTARTIO END; CSPort: PORT RETURNS [POINTER TO CoreSwapDefs.ExternalStateVector]; WBPort: PORT [POINTER TO CoreSwapDefs.ExternalStateVector]; MemorySwap: PROCEDURE [ESV: POINTER TO CoreSwapDefs.ExternalStateVector] = BEGIN savewdc: UNSPECIFIED; xferTrapStatus: UNSPECIFIED; xferTrapHandler: UNSPECIFIED; flag: [0..2]; DO ESV _ CSPort[]; FrameOps.SetReturnLink[LOOPHOLE[CSPort, Port].dest]; StartIO[SDDefs.SD[SDDefs.sIOResetBits]]; -- reset IO devices ESV.level _ level; xferTrapStatus _ TrapOps.ReadXTS[]; xferTrapHandler _ SDDefs.SD[SDDefs.sXferTrap]; SDDefs.SD[SDDefs.sXferTrap] _ FrameOps.MyLocalFrame[]; TrapOps.WriteXTS[TraceOff]; UNTIL DiskDefs.NextDiskCommand^ = DiskDefs.CBNil DO NULL ENDLOOP; savewdc _ ProcessOps.ReadWDC[]; flag _ BcplOps.BcplOutLd[OutLd, CoreSwapDefs.PuntInfo^.pCoreFP, ESV]; ProcessOps.WriteWDC[savewdc]; SELECT flag FROM 0 => BcplOps.BcplInLd[InLd, CoreSwapDefs.PuntInfo^.pDebuggerFP, ESV]; 1 => level _ ESV.level; ENDCASE => ESV.reason _ proceed; TrapOps.WriteXTS[xferTrapStatus]; SDDefs.SD[SDDefs.sXferTrap] _ xferTrapHandler; ENDLOOP; END; Break: PUBLIC PROCEDURE = -- executed by (non-worry) BRK instruction BEGIN ProcessBreakpoint: PROCEDURE [CoreSwapDefs.SVPointer] = MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sProcessBreakpoint END; f: FrameHandle; state: StateVector; xferTrapStatus: TrapStatus; state _ STATE; state.dest _ f _ state.source; state.source _ FrameOps.MyLocalFrame[]; f.pc _ [IF f.pc < 0 THEN -f.pc ELSE (1 - f.pc)]; ProcessBreakpoint[@state]; xferTrapStatus _ TrapOps.ReadXTS[]; IF xferTrapStatus.state = on THEN TrapOps.WriteXTS[TraceNext]; RETURN WITH state END; -- Worry mode breakpoints WorryBreaker: PUBLIC PROCEDURE RETURNS [FrameHandle] = BEGIN state: StateVector; frame: FrameHandle; esv: CoreSwapDefs.ExternalStateVector; xferTrapStatus: TrapStatus; state.instbyte _ 0; state.stkptr _ 1; state.stk[0] _ FrameOps.MyLocalFrame[]; state.dest _ FrameOps.GetReturnLink[]; ProcessDefs.DisableInterrupts[]; ProcessDefs.DisableInterrupts[]; DO xferTrapStatus _ TrapOps.ReadXTS[]; IF xferTrapStatus.state = on THEN TrapOps.WriteXTS[TraceNext]; -- previous WR is aligned so now 2 DWDCs to prevent a NOOP ProcessDefs.EnableInterrupts[]; ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; ProcessDefs.DisableInterrupts[]; state _ STATE; frame _ state.dest _ state.source; FrameOps.SetReturnFrame[frame]; state.source _ FrameOps.MyLocalFrame[]; frame.pc _ [IF frame.pc < 0 THEN -frame.pc ELSE (1 - frame.pc)]; esv _ CoreSwapDefs.PuntInfo^.puntESV; esv.state _ @state; esv.reason _ worrybreak; DO OPEN KeyDefs; WBPort[@esv]; SELECT esv.reason FROM proceed => EXIT; kill => ImageDefs.AbortMesa[]; showscreen => UNTIL Keys.Spare3 = down OR Keys.FR5 = down DO NULL ENDLOOP; ENDCASE; esv.reason _ return; ENDLOOP; ENDLOOP; END; WorryCallDebugger: PUBLIC PROCEDURE RETURNS [FrameHandle] = BEGIN state: StateVector; esv: CoreSwapDefs.ExternalStateVector; state.instbyte _ 0; state.stkptr _ 1; state.stk[0] _ FrameOps.MyLocalFrame[]; state.dest _ FrameOps.GetReturnLink[]; ProcessDefs.DisableInterrupts[]; DO -- the following RR and POP is to guarantee that there is no NOOP between -- the DWDC and the LST [] _ TrapOps.ReadATP[]; ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; state _ STATE; state.dest _ state.source; FrameOps.SetReturnFrame[state.dest]; state.source _ FrameOps.MyLocalFrame[]; esv _ CoreSwapDefs.PuntInfo^.puntESV; esv.state _ @state; esv.reason _ worrycall; DO OPEN KeyDefs; WBPort[@esv]; SELECT esv.reason FROM proceed => EXIT; kill => ImageDefs.AbortMesa[]; showscreen => UNTIL Keys.Spare3 = down OR Keys.FR5 = down DO NULL ENDLOOP; ENDCASE; esv.reason _ return; ENDLOOP; ENDLOOP; END; -- Initialization FrameOps.Start[LOOPHOLE[LaurelInterrupt]]; END.