-- 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.