-- Resident.Mesa; edited by Levin on September 7, 1978 3:30 PM -- * * * * * Modified for Pilot/Mesa * * * * * DIRECTORY AllocDefs: FROM "allocdefs" USING [AllocInfo, MakeSwappedIn], AltoDefs: FROM "altodefs" USING [PageSize], BootDefs: FROM "bootdefs", CodeDefs: FROM "codedefs" USING [ Codebase, CodeHandle, ReleaseCode], ControlDefs: FROM "controldefs" USING [ ATPreg, AV, AVItem, ControlLink, CSegPrefix, EntryVectorItem, EPRange, FrameHandle, FrameVec, Free, GetReturnLink, GFT, GFTIndex, GFTItem, GlobalFrameHandle, LargeReturnSlot, Lreg, MainBodyIndex, MaxAllocSlot, NullFrame, NullGlobalFrame, OTPreg, Port, ProcDesc, SD, SetReturnFrame, SetReturnLink, SpecialReturnSlot, StateVector, WDCreg, XTPreg, XTSreg], CoreSwapDefs: FROM "coreswapdefs" USING [ ExternalStateVector, PuntInfo, SVPointer], FrameDefs: FROM "framedefs", GlobalFrameDefs: FROM "Globalframedefs" USING[GlobalFrameHandle], ImageDefs: FROM "imagedefs" USING [AbortMesa, PuntMesa], InlineDefs: FROM "inlinedefs" USING [BITAND, BITOR], KeyDefs: FROM "keydefs" USING [Keys], Mopcodes: FROM "mopcodes" USING [zKFCB, zPOP, zSTARTIO], NovaOps: FROM "novaops" USING [NovaInLd, NovaOutLd], NucleusDefs: FROM "nucleusdefs", ProcessDefs: FROM "processdefs" USING [ ActiveWord, CV, DisableInterrupts, DisableTimeout, EnableInterrupts, Enter, Fork, GetPriority, ParityLevel, Priority, ReEnter, SetPriority, Wait, WakeupsWaiting], SDDefs: FROM "sddefs" USING [ sAllocTrap, SD, sInterrupt, sIOResetBits, sProcessBreakpoint, sXferTrap], SegmentDefs: FROM "segmentdefs" USING [ AddressFromPage, DataSegmentAddress, DataSegmentHandle, DefaultBase, DeleteDataSegment, FileSegmentHandle, NewFrameSegment], TrapDefs: FROM "trapdefs" USING [ TraceNext, TraceOff, TrapParameter, TrapStatus], XMESA: FROM "XMesaPrivateDefs" USING [XFileSegmentObject, XMremote], --XM XMesaDefs: FROM "XMesaDefs" USING [LongAddressFromPage, XCOPY]; --XM DEFINITIONS FROM AltoDefs, ControlDefs; Resident: PROGRAM IMPORTS AllocDefs, CodeDefs, ProcessDefs, SegmentDefs, XMesaDefs --XM EXPORTS FrameDefs, NucleusDefs, TrapDefs --XM SHARES ProcessDefs, XMESA = --XM BEGIN -- allocation of frame space LargeFrameSlot: CARDINAL = 12; FrameSize: PUBLIC PROCEDURE [fsi: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN[IF fsi >= LENGTH[FrameVec] THEN fsi ELSE 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 = PageSize; ExtraSpace: ARRAY [0..ExtraSpaceSize) OF WORD; InitNewSpace: POINTER = LOOPHOLE[InlineDefs.BITOR[LOOPHOLE[BASE[ExtraSpace]],3]]; InitWordsLeft: CARDINAL = BASE[ExtraSpace]+ExtraSpaceSize-InitNewSpace; NULLPtr: FrameHandle = LOOPHOLE[0]; AllocTrap: PROCEDURE [otherframe: FrameHandle] RETURNS [myframe: FrameHandle] = BEGIN OPEN ProcessDefs, SegmentDefs; ATFrame: TYPE = POINTER TO FRAME [AllocTrap]; state: StateVector; newframe: FrameHandle; newseg: DataSegmentHandle; eventry: EntryVectorItem; --XM 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 ← REGISTER[Lreg]; 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; ProcessDefs.EnableInterrupts[]; -- guarantees one more instruction TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← LOOPHOLE[REGISTER[ATPreg]]; 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]; BEGIN OPEN f: LOOPHOLE[newG, GlobalFrameDefs.GlobalFrameHandle]; --XM cb: LONG POINTER ← IF f.code.highByte # 0 THEN LONG[f.code.shortCodebase] ELSE f.code.codebase; XMesaDefs.XCOPY[from: @LOOPHOLE[cb, LONG POINTER TO CSegPrefix].entry[findex+ep], to: LONG[@eventry], nwords: SIZE[EntryVectorItem]]; END; findex ← eventry.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; NewSpacePtr ← (p←DataSegmentAddress[newseg←NewFrameSegment[1]]) + 3; LOOPHOLE[p,pSegHeader]↑ ← [newseg,SegListHead]; SegListHead ← p; WordsLeft ← PageSize-3; END; ENDLOOP END ELSE BEGIN SELECT findex FROM --XM >MaxAllocSlot => fsize ← findex; --XM =MaxAllocSlot => --XM BEGIN OPEN f: LOOPHOLE[newG, GlobalFrameDefs.GlobalFrameHandle]; --XM cb: LONG POINTER ← IF f.code.highByte # 0 THEN LONG[f.code.shortCodebase] ELSE f.code.codebase; XMesaDefs.XCOPY[from: cb + CARDINAL[eventry.initialpc]-1, to: LONG[@fsize], nwords: 1]; END; ENDCASE => fsize ← FrameVec[findex]; --XM p ← DataSegmentAddress[newseg ← NewFrameSegment[(fsize + PageSize + 3)/PageSize]]; p↑ ← newseg; (p+2)↑ ← fsize; (p+3)↑ ← LargeReturnSlot; newframe ← p + 4; END; IF alloc THEN BEGIN state.dest ← myframe.returnlink; state.stk[state.stkptr] ← newframe; state.stkptr ← state.stkptr+1; END ELSE BEGIN IF dest.tag # indirect THEN BEGIN state.dest ← newframe; newframe.accesslink ← newG; newframe.pc ← eventry.initialpc; newframe.returnlink ← myframe.returnlink; END ELSE BEGIN IF findex = MaxAllocSlot THEN ImageDefs.PuntMesa[]; state.dest ← dest; newframe.accesslink ← LOOPHOLE[AV[findex].link]; AV[findex].frame ← newframe; END; state.source ← myframe.returnlink; END; SD[SDDefs.sAllocTrap] ← myframe; ENDLOOP; END; FlushLargeFrames: PUBLIC PROCEDURE = BEGIN p: POINTER; item: ItemPointer ← @AV[LargeReturnSlot]; WHILE item.tag = frame DO p ← item.frame; item.frame ← p↑; SegmentDefs.DeleteDataSegment[LOOPHOLE[(p-4)↑]]; ENDLOOP; END; -- other traps UnboundProcedure: PUBLIC SIGNAL [dest: ControlLink] RETURNS [ControlLink] = CODE; UnboundProcedureTrap: PROCEDURE = BEGIN dest: ControlLink; state: StateVector; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← LOOPHOLE[REGISTER[OTPreg]]; ProcessDefs.EnableInterrupts[]; state.source ← GetReturnLink[]; state.dest ← SIGNAL UnboundProcedure[dest]; RETURN WITH state END; StartFault: PUBLIC SIGNAL [dest: GlobalFrameHandle] = CODE; CodeInconsistency: PUBLIC SIGNAL [frame: GlobalFrameHandle] = CODE; Start: PUBLIC PROCEDURE [dest: GlobalFrameHandle] = BEGIN state: StateVector; control: GlobalFrameHandle; state ← STATE; IF dest = NullGlobalFrame OR dest.started THEN ERROR StartFault[dest]; IF (control ← dest.global[0]) # NullGlobalFrame AND ~control.started THEN Start[control]; --SwapInCode[dest]; --IF dest.code.prefix.fill = 1 THEN SIGNAL CodeInconsistency[dest]; --SegmentDefs.Unlock[dest.codesegment]; -- -- Roy, please fix this-- IF ~dest.started THEN BEGIN state.dest ← ControlLink[procedure[ gfi: dest.gfi, ep: MainBodyIndex, tag: procedure]]; state.source ← GetReturnLink[]; dest.started ← TRUE; RETURN WITH state END ELSE IF state.stkptr # 0 THEN SIGNAL StartFault[dest]; RETURN END; Restart: PUBLIC PROCEDURE [dest: GlobalFrameHandle] = BEGIN csegpfx: CSegPrefix; --XM frame: FrameHandle; IF dest = NullGlobalFrame THEN ERROR StartFault[dest]; IF ~dest.started THEN Start[dest]; XMesaDefs.XCOPY[from: CodeDefs.Codebase[dest], to: LONG[@csegpfx], nwords: SIZE[CSegPrefix]]; --XM CodeDefs.ReleaseCode[dest]; IF ~csegpfx.stops THEN ERROR StartFault[dest]; IF (frame ← dest.global[0]) # NullFrame THEN BEGIN frame.returnlink ← GetReturnLink[]; SetReturnFrame[frame]; END; RETURN END; CodeTrap: PROCEDURE = BEGIN dest: ControlLink; state: StateVector; frame: GlobalFrameHandle; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← LOOPHOLE[REGISTER[OTPreg]]; ProcessDefs.EnableInterrupts[]; state.dest ← dest; state.source ← 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 Start[frame]; SwapInCode[frame]; CodeDefs.ReleaseCode[frame]; RETURN WITH state; END; SwapInCode: PUBLIC PROCEDURE [f: GlobalFrameHandle] = BEGIN OPEN g: LOOPHOLE[f, GlobalFrameDefs.GlobalFrameHandle], SegmentDefs; seg: FileSegmentHandle; -- It is believed that Disabling during SwapIn is unnecessary -- as long as ALL interrupt code is locked. The -- Swapper should have segment locks to help fix this. info: AllocDefs.AllocInfo = [0,easy,bottomup, initial, code, FALSE, FALSE]; AllocDefs.MakeSwappedIn[(seg ← CodeDefs.CodeHandle[f]), DefaultBase, info]; ProcessDefs.DisableInterrupts[]; IF f.code.swappedout THEN BEGIN -- Don't call FileSegmentAddress; it's not locked! IF g.code.highHalf # 0 THEN BEGIN --XM offset: CARDINAL ← f.code.offset; --XM g.code.shortCodebase ← SegmentDefs.AddressFromPage[seg.VMpage]+offset; --XM WITH s: seg SELECT FROM --XM remote => --XM BEGIN OPEN xs: LOOPHOLE[seg, POINTER TO remote XMESA.XFileSegmentObject]; --XM IF xs.proc = XMESA.XMremote THEN --XM g.code.codebase ← XMesaDefs.LongAddressFromPage[xs.info.XMpage]+offset; --XM END; --XM ENDCASE; --XM END; --XM f.code.swappedout ← FALSE; END; ProcessDefs.EnableInterrupts[]; RETURN END; -- Parity Errors ParityError: PUBLIC SIGNAL [address: POINTER] = CODE; PhantomParityError: PUBLIC SIGNAL = CODE; ParityProcess: PROCEDURE = BEGIN OPEN ProcessDefs; p: ORDERED POINTER; dummy: MONITORLOCK; error: CONDITION; ww: POINTER TO MACHINE DEPENDENT RECORD [ other: [0..77777B], parity: BOOLEAN] ← LOOPHOLE[ProcessDefs.WakeupsWaiting]; POP: PROCEDURE [WORD] = MACHINE CODE BEGIN Mopcodes.zPOP END; [] ← Enter[@dummy]; DisableTimeout[@error]; CV[ParityLevel] ← @error; DO -- forever Wait[@dummy, @error, error.timeout]; WHILE ~ReEnter[@dummy, @error] DO NULL ENDLOOP; ActiveWord↑ ← 0; 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; InitParity: PROCEDURE = BEGIN OPEN ProcessDefs; save: Priority ← GetPriority[]; SetPriority[LAST[Priority]]; [] ← Fork[ParityProcess]; SetPriority[save]; RETURN END; -- Getting the Debugger level: 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[]; SetReturnLink[LOOPHOLE[CSPort, Port].dest]; StartIO[SD[SDDefs.sIOResetBits]]; -- reset IO devices ESV.level ← level; xferTrapStatus ← REGISTER[XTSreg]; xferTrapHandler ← SD[SDDefs.sXferTrap]; SD[SDDefs.sXferTrap] ← REGISTER[Lreg]; REGISTER[XTSreg] ← TrapDefs.TraceOff; savewdc ← REGISTER[WDCreg]; flag ← NovaOps.NovaOutLd[OutLd,CoreSwapDefs.PuntInfo↑.pCoreFP,ESV]; REGISTER[WDCreg] ← savewdc; SELECT flag FROM 0 => NovaOps.NovaInLd[InLd,CoreSwapDefs.PuntInfo↑.pDebuggerFP,ESV]; 1 => level ← ESV.level; ENDCASE => ESV.reason ← proceed; REGISTER[XTSreg] ← xferTrapStatus; SD[SDDefs.sXferTrap] ← xferTrapHandler; ENDLOOP; END; Break: 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: TrapDefs.TrapStatus; state ← STATE; state.dest ← f ← state.source; state.source ← REGISTER[Lreg]; f.pc ← [IF f.pc < 0 THEN -f.pc ELSE (1-f.pc)]; xferTrapStatus ← REGISTER[XTSreg]; ProcessBreakpoint[@state]; IF xferTrapStatus.state = on THEN REGISTER[XTSreg] ← TrapDefs.TraceNext; RETURN WITH state END; -- Worry mode breakpoints WorryBreaker: PROCEDURE RETURNS [FrameHandle] = BEGIN worrystate: StateVector; worryframe: FrameHandle; worryESV: CoreSwapDefs.ExternalStateVector; xferTrapStatus: TrapDefs.TrapStatus; worrystate.instbyte ← 0; worrystate.stkptr ← 1; worrystate.stk[0] ← REGISTER[Lreg]; worrystate.dest ← ControlDefs.GetReturnLink[]; ProcessDefs.DisableInterrupts[]; DO xferTrapStatus ← REGISTER[XTSreg]; IF xferTrapStatus.state = on THEN REGISTER[XTSreg] ← TrapDefs.TraceNext; ProcessDefs.EnableInterrupts[]; TRANSFER WITH worrystate; ProcessDefs.DisableInterrupts[]; worrystate ← STATE; worrystate.dest ← worryframe ← worrystate.source; worrystate.source ← REGISTER[Lreg]; worryframe.pc ← [IF worryframe.pc < 0 THEN -worryframe.pc ELSE (1-worryframe.pc)]; worryESV ← CoreSwapDefs.PuntInfo↑.puntESV; worryESV.state ← @worrystate; worryESV.reason ← worrybreak; DO WBPort[@worryESV]; SELECT worryESV.reason FROM proceed => EXIT; kill => ImageDefs.AbortMesa[]; showscreen => UNTIL KeyDefs.Keys.Spare3 = down DO NULL ENDLOOP; ENDCASE; worryESV.reason ← return; ENDLOOP; ENDLOOP; END; continueTracing: BOOLEAN; Notify: PROCEDURE = MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sInterrupt END; StartTrace: PROCEDURE [ loc: POINTER, val: UNSPECIFIED, mask: WORD, equal: BOOLEAN] = BEGIN OPEN TrapDefs, ControlDefs; state: StateVector; trapParam: TrapParameter; status: TrapStatus; frame: FrameHandle; ep: CARDINAL; lval: UNSPECIFIED; continueTracing ← TRUE; state ← STATE; state.dest ← GetReturnLink[]; SDDefs.SD[SDDefs.sXferTrap] ← state.source ← REGISTER[Lreg]; ProcessDefs.DisableInterrupts[]; DO lval ← InlineDefs.BITAND[loc↑, mask]; IF (IF equal THEN val = lval ELSE val # lval) THEN Notify[]; IF ~continueTracing THEN BEGIN ProcessDefs.EnableInterrupts[]; RETURN WITH state; END ELSE BEGIN REGISTER[XTSreg] ← TraceNext; ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; END; ProcessDefs.DisableInterrupts[]; state ← STATE; trapParam ← REGISTER[XTPreg]; status ← REGISTER[XTSreg]; REGISTER[XTSreg] ← TraceOff; SELECT status.reason FROM other => SetReturnLink[ IF state.source = NullFrame THEN trapParam.link ELSE state.source]; localCall => BEGIN ep ← (trapParam.ep-2)/2; frame ← state.source; trapParam.link ← ControlLink[procedure[tag: procedure, gfi: frame.accesslink.gfi+ep/EPRange, ep: ep MOD EPRange]]; SetReturnFrame[frame]; END; return => BEGIN frame ← trapParam.frame-6; trapParam.link ← frame.returnlink; SetReturnFrame[frame]; END; ENDCASE; state.dest ← trapParam.link; IF status.reason = return THEN BEGIN Free[frame]; state.source ← NullFrame; END; ENDLOOP; END; StopTrace: PROCEDURE = BEGIN continueTracing ← FALSE; RETURN END; -- Main Body; STOP; InitParity[]; END.