-- NonResident.mesa; edited by Levin, January 25, 1979 8:31 AM DIRECTORY AllocDefs: FROM "allocdefs" USING [AllocHandle, AllocInfo, GetAllocationObject], AltoDefs: FROM "altodefs" USING [BYTE, PageNumber, PageSize], CodeDefs: FROM "codedefs" USING [ Codebase, CodeHandle, ReleaseCode], ControlDefs: FROM "controldefs" USING [ Alloc, ControlLink, CSegPrefix, EntryVectorItem, EPRange, FrameCodeBase, FrameHandle, Free, GetReturnFrame, GetReturnLink, GFT, GFTIndex, GFTItem, GlobalFrameHandle, InstWord, Lreg, MainBodyIndex, MaxAllocSlot, NullEpBase, NullFrame, NullGlobalFrame, Port, PortHandle, SD, StateVector], CoreSwapDefs: FROM "CoreSwapDefs", FrameDefs: FROM "framedefs" USING [FrameSize], GlobalFrameDefs: FROM "GlobalFrameDefs" USING [GlobalFrameHandle], ImageDefs: FROM "imagedefs", InlineDefs: FROM "inlinedefs" USING [ BITAND, BITNOT, BITSHIFT, BITXOR, COPY, DIVMOD, LDIVMOD, LongCARDINAL, LongDiv, LongDivMod, LongMult], LoadStateDefs: FROM "loadstatedefs" USING [ ConfigIndex, ConfigNull, EnterGfi, InputLoadState, MapRealToConfig, ReleaseLoadState], MiscDefs: FROM "miscdefs", Mopcodes: FROM "mopcodes" USING [zDADD, zDCOMP, zDSUB, zINC, zPORTI], NucleusDefs: FROM "nucleusdefs", ProcessDefs: FROM "processdefs" USING [DisableInterrupts, EnableInterrupts], Resident: FROM "resident" USING [ AllocTrap, Break, CodeTrap, CSPort, level, MemorySwap, Restart, Start, UnboundProcedureTrap, WBPort, WorryBreaker], SDDefs: FROM "sddefs" USING [ sAllocTrap, sAlternateBreak, sBLTE, sBLTEC, sBreak, sBYTBLTE, sBYTBLTEC, sControlFault, sCopy, sCoreSwap, SD, sDivSS, sError, sGFTLength, sIOResetBits, sLongDiv, sLongDivMod, sLongMod, sLongMul, sRestart, sStackError, sStart, sStringInit, sSwapTrap, sUnbound, sUnNew], SegmentDefs: FROM "segmentdefs" USING [ DeleteFileSegment, EnumerateFileSegments, FileSegmentHandle, SwapIn, SwapError, Unlock], TrapDefs: FROM "trapdefs" USING [UnboundProcedure], XMESA: FROM "XMesaPrivateDefs" USING [ChocolateToVanilla, VanillaToChocolate, WhichWay, XFileSegmentHandle, XMremote], XMesaDefs: FROM "XMesaDefs" USING [DefaultBase0, DefaultXMBase, GetMemoryConfig, LongAddressFromPage, LowHalfPtr, XFileSegmentAddress, XCOPY]; DEFINITIONS FROM ControlDefs; NonResident: PROGRAM IMPORTS AllocDefs, FrameDefs, LoadStateDefs, ResidentPtr: Resident, SegmentDefs, TrapDefs, CodeDefs, XMESA, XMesaDefs --XM EXPORTS FrameDefs, NucleusDefs, TrapDefs, XMESA, CoreSwapDefs SHARES XMESA, ControlDefs, ImageDefs, Resident = BEGIN -- Global Frame Table management gftrover: CARDINAL ← 0; -- okay to start at 0 because incremented before used NoGlobalFrameSlots: PUBLIC SIGNAL [CARDINAL] = CODE; EnumerateGlobalFrames: PUBLIC PROCEDURE [ proc: PROCEDURE [GlobalFrameHandle] RETURNS [BOOLEAN]] RETURNS [GlobalFrameHandle] = BEGIN i: GFTIndex; frame: GlobalFrameHandle; gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT; FOR i IN [0..SD[SDDefs.sGFTLength]) DO frame ← gft[i].frame; IF frame # NullGlobalFrame AND gft[i].epbase = 0 AND proc[frame] THEN RETURN[frame]; ENDLOOP; RETURN[NullGlobalFrame] END; EnterGlobalFrame: PUBLIC PROCEDURE [frame: GlobalFrameHandle, nslots: CARDINAL] RETURNS [entryindex: GFTIndex] = BEGIN gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT; i, imax, n, epoffset: CARDINAL; i ← gftrover; imax ← SD[SDDefs.sGFTLength] - nslots; n ← 0; DO IF (i ← IF i>=imax THEN 1 ELSE i+1) = gftrover THEN SIGNAL NoGlobalFrameSlots[nslots]; IF gft[i].frame # NullGlobalFrame THEN n ← 0 ELSE IF gft[i].epbase = NullEpBase THEN n ← 0 ELSE IF (n ← n+1) = nslots THEN EXIT; ENDLOOP; entryindex ← (gftrover←i)-nslots+1; epoffset ← 0; FOR i IN [entryindex..gftrover] DO gft[i] ← GFTItem[frame, epoffset]; epoffset ← epoffset + EPRange; ENDLOOP; RETURN END; RemoveGlobalFrame: PUBLIC PROCEDURE [frame: GlobalFrameHandle] = BEGIN gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT; sd: POINTER TO ARRAY [0..0) OF CARDINAL ← SD; i: CARDINAL; FOR i ← frame.gfi, i+1 WHILE i<sd[SDDefs.sGFTLength] AND gft[i].frame=frame DO gft[i] ← IF frame.copied THEN GFTItem[NullGlobalFrame,0] ELSE GFTItem[NullGlobalFrame,NullEpBase]; ENDLOOP; RETURN END; -- Traps StackError: PUBLIC ERROR [FrameHandle] = CODE; StackErrorTrap: PROCEDURE = BEGIN state: StateVector; foo: BOOLEAN; state ← STATE; foo ← TRUE; IF foo THEN ERROR StackError[GetReturnFrame[]]; END; NullPort: PortHandle = LOOPHOLE[0]; PortFault: PUBLIC ERROR = CODE; LinkageFault: PUBLIC ERROR = CODE; ControlFault: PUBLIC SIGNAL [source: FrameHandle] RETURNS [ControlLink] = CODE; PORTI: PROCEDURE = MACHINE CODE BEGIN Mopcodes.zPORTI END; ControlFaultTrap: PROCEDURE = BEGIN errorStart, savedState: StateVector; p, q: PortHandle; sourceFrame, self: FrameHandle; savedState ← STATE; self ← REGISTER[Lreg]; IF PortCall[self.returnlink] THEN BEGIN p ← self.returnlink.port; q ← p.dest.port; sourceFrame ← p.frame; IF q = NullPort THEN errorStart.stk[0] ← LinkageFault ELSE BEGIN q↑ ← Port[links[NullFrame,[indirect[port[p]]]]]; errorStart.stk[0] ← PortFault; END; errorStart.stk[1] ← 0; errorStart.instbyte ← 0; errorStart.stkptr ← 2; errorStart.source ← sourceFrame.returnlink; errorStart.dest ← SD[SDDefs.sError]; IF savedState.stkptr = 0 THEN RETURN WITH errorStart -- RESPONDING port ELSE BEGIN p.frame ← self; TRANSFER WITH errorStart; PORTI; p.frame ← sourceFrame; savedState.source ← p; savedState.dest ← p.dest; RETURN WITH savedState; END; END ELSE BEGIN savedState.source ← self.returnlink; savedState.dest ← SIGNAL ControlFault[savedState.source]; RETURN WITH savedState END; END; PortCall: PROCEDURE [source: ControlLink] RETURNS [BOOLEAN] = BEGIN portcall: BOOLEAN ← FALSE; WHILE source.tag = indirect DO source ← source.link↑; ENDLOOP; IF source.tag = frame AND FrameDefs.ReturnByte[source.frame,0] = Mopcodes.zPORTI THEN portcall ← TRUE; RETURN[portcall] END; ReturnByte: PUBLIC PROCEDURE [frame: FrameHandle, byteoffset: INTEGER] RETURNS [byte: AltoDefs.BYTE] = BEGIN OPEN SegmentDefs; g: GlobalFrameHandle = frame.accesslink; iw: InstWord; --XM bytePC: CARDINAL = byteoffset + (IF frame.pc<0 THEN 2*(-frame.pc)+1 ELSE 2*frame.pc); XMesaDefs.XCOPY[from: CodeDefs.Codebase[g] + bytePC/2, to: LONG[@iw], nwords: SIZE[InstWord]];--XM byte ← IF bytePC MOD 2 # 0 THEN iw.oddbyte ELSE iw.evenbyte; CodeDefs.ReleaseCode[g]; RETURN END; -- Frame manipulation InvalidGlobalFrame: PUBLIC SIGNAL [frame: GlobalFrameHandle] = CODE; ValidateGlobalFrame: PUBLIC PROCEDURE [g: GlobalFrameHandle] = BEGIN IF ~ValidGlobalFrame[g] THEN SIGNAL InvalidGlobalFrame[g]; END; ValidGlobalFrame: PROCEDURE [g: GlobalFrameHandle] RETURNS[BOOLEAN] = BEGIN RETURN[LOOPHOLE[g, ControlLink].tag = frame AND g.gfi < SD[SDDefs.sGFTLength] AND --XM GFT[g.gfi].frame = g] --XM END; GlobalFrame: PUBLIC PROCEDURE [link: UNSPECIFIED] RETURNS [GlobalFrameHandle] = BEGIN OPEN l: LOOPHOLE[link, ControlLink]; DO SELECT l.tag FROM frame => BEGIN IF link = 0 THEN RETURN[NullGlobalFrame]; IF ValidGlobalFrame[link] THEN RETURN[link]; IF ValidGlobalFrame[l.frame.accesslink] THEN RETURN[l.frame.accesslink]; RETURN[NullGlobalFrame] END; procedure => RETURN[GFT[l.gfi].frame]; indirect => link ← l.link↑; unbound => link ← SIGNAL TrapDefs.UnboundProcedure[link]; ENDCASE ENDLOOP END; Copy: PROCEDURE [old: GlobalFrameHandle] RETURNS [new: GlobalFrameHandle] = BEGIN linkspace: CARDINAL ← 0; codebase: LONG POINTER TO CSegPrefix; csegpfx: CSegPrefix; --XM cseg: SegmentDefs.FileSegmentHandle; --XM ValidateGlobalFrame[old]; codebase ← CodeDefs.Codebase[old]; [new, linkspace] ← AllocGlobalFrame[old, codebase]; IF ~old.codelinks THEN --XM BEGIN InlineDefs.COPY[from: old-linkspace, to: new, nwords: linkspace]; --XM new ← new+linkspace; --XM END; cseg ← CodeDefs.CodeHandle[old]; new↑ ← [gfi:, unused: 0, alloced: TRUE, shared: TRUE, copied: TRUE, started: FALSE, trapxfers: FALSE, codelinks: old.codelinks, code:, codesegment: cseg, global:]; XMesaDefs.XCOPY[from: codebase, to: LONG[@csegpfx], nwords: SIZE[CSegPrefix]]; --XM new.gfi ← FrameDefs.EnterGlobalFrame[new, csegpfx.ngfi]; --XM new.code.offset ← XMesaDefs.LowHalfPtr[codebase] - XMesaDefs.LowHalfPtr[XMesaDefs.XFileSegmentAddress[cseg]]; --XM new.code.swappedout ← TRUE; new.global[0] ← NullGlobalFrame; old.shared ← TRUE; CodeDefs.ReleaseCode[old]; RETURN END; MakeFsi: PUBLIC PROCEDURE [words: CARDINAL] RETURNS [fsi: CARDINAL] = BEGIN FOR fsi IN [0..MaxAllocSlot) DO IF FrameDefs.FrameSize[fsi] >= words THEN RETURN; ENDLOOP; RETURN[words] END; AllocGlobalFrame: PROCEDURE [ old: GlobalFrameHandle, cp: LONG POINTER TO CSegPrefix] RETURNS [frame: GlobalFrameHandle, linkspace: CARDINAL] = BEGIN size, nlinks: CARDINAL; FrameSizePair: TYPE = MACHINE DEPENDENT RECORD[size2, size1: CARDINAL]; --XM fsizes: FrameSizePair; --XM csegpfx: CSegPrefix; --XM mbEntry: EntryVectorItem; --XM pbody: LONG POINTER; --XM XMesaDefs.XCOPY[from: @cp.entry[MainBodyIndex], to: LONG[@mbEntry], nwords: SIZE[EntryVectorItem]]; --XM pbody ← cp+CARDINAL[mbEntry.initialpc]; --XM XMesaDefs.XCOPY[from: pbody-2, to: LONG[@fsizes], nwords: SIZE[FrameSizePair]]; --XM size ← IF mbEntry.framesize = MaxAllocSlot THEN fsizes.size2 ELSE fsizes.size1; --XM XMesaDefs.XCOPY[from: cp, to: LONG[@csegpfx], nwords: SIZE[CSegPrefix]]; --XM nlinks ← csegpfx.nlinks; --XM linkspace ← nlinks + InlineDefs.BITAND[-LOOPHOLE[nlinks, INTEGER], 3B]; --XM frame ← Alloc[MakeFsi[FrameDefs.FrameSize[size]+(IF old.codelinks THEN 0 ELSE linkspace)]]; --XM RETURN END; UnNew: PROCEDURE [frame: GlobalFrameHandle] = BEGIN csegpfx: CSegPrefix; --XM cseg: SegmentDefs.FileSegmentHandle; sharer: GlobalFrameHandle ← NullGlobalFrame; original: GlobalFrameHandle ← NullGlobalFrame; copy: GlobalFrameHandle ← NullGlobalFrame; codebase: LONG POINTER TO CSegPrefix; fcb: FrameCodeBase; nothers: CARDINAL ← 0; nlinks: CARDINAL; RemoveAllTraces: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN OPEN gf: LOOPHOLE[f, GlobalFrameDefs.GlobalFrameHandle]; seg: SegmentDefs.FileSegmentHandle; IF f#frame THEN BEGIN IF f.global[0] = frame AND ~f.started THEN f.global[0] ← NullFrame; seg ← CodeDefs.CodeHandle[f]; IF cseg = seg THEN BEGIN nothers ← nothers + 1; sharer ← f; ProcessDefs.DisableInterrupts[]; IF (IF f.code.swappedout THEN gf.code.offset = fcb.offset ELSE gf.code.codebase = LOOPHOLE[frame, GlobalFrameDefs.GlobalFrameHandle].code.codebase) THEN IF f.copied THEN copy ← f ELSE original ← f; ProcessDefs.EnableInterrupts[]; END; END; RETURN[FALSE]; END; ValidateGlobalFrame[frame]; codebase ← CodeDefs.Codebase[frame]; XMesaDefs.XCOPY[from: codebase, to: LONG[@csegpfx], nwords: SIZE[CSegPrefix]]; --XM nlinks ← csegpfx.nlinks; --XM cseg ← CodeDefs.CodeHandle[frame]; fcb.offset ← frame.code.codebase - XMesaDefs.LowHalfPtr[XMesaDefs.XFileSegmentAddress[cseg]]; --XM fcb.swappedout ← TRUE; [] ← FrameDefs.EnumerateGlobalFrames[RemoveAllTraces]; CodeDefs.ReleaseCode[frame]; IF original = NullGlobalFrame AND ~frame.copied AND copy # NullGlobalFrame THEN BEGIN OPEN LoadStateDefs; config: ConfigIndex; cgfi: GFTIndex; copy.copied ← FALSE; [] ← InputLoadState[]; [cgfi: cgfi, config: config] ← MapRealToConfig[frame.gfi]; EnterGfi[cgfi: 0, rgfi: frame.gfi, config: ConfigNull]; EnterGfi[cgfi: cgfi, rgfi: copy.gfi, config: config]; ReleaseLoadState[]; END; IF frame.shared THEN BEGIN IF nothers = 1 THEN sharer.shared ← FALSE END ELSE BEGIN OPEN SegmentDefs; DeleteFileSegment[cseg ! SwapError => CONTINUE]; END; FrameDefs.RemoveGlobalFrame[frame]; IF frame.alloced THEN BEGIN Align: PROCEDURE [POINTER, WORD] RETURNS [POINTER] = LOOPHOLE[InlineDefs.BITAND]; IF frame.codelinks THEN Free[frame] ELSE Free[Align[frame - nlinks, 177774B]] END; END; MoveLockedCode: PUBLIC PROCEDURE [direction: XMESA.WhichWay] = BEGIN OPEN SegmentDefs; alloc: AllocDefs.AllocHandle ← AllocDefs.GetAllocationObject[]; CheckOne: PROCEDURE [fseg: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN OPEN seg: LOOPHOLE[fseg, XMESA.XFileSegmentHandle]; ChangeFlavorProc: TYPE = PROCEDURE[newVMpage: AltoDefs.PageNumber] RETURNS [AltoDefs.PageNumber]; MoveThisSegment: PROCEDURE[basePage: AltoDefs.PageNumber, proc: ChangeFlavorProc] = BEGIN OPEN XMesaDefs; ResidentCodeInfo: AllocDefs.AllocInfo = [0, hard, bottomup, initial, code, TRUE, FALSE]; oldVMpage, newVMpage: AltoDefs.PageNumber; delta: LONG INTEGER; UpdateCodebase: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN OPEN frame: LOOPHOLE[f, GlobalFrameDefs.GlobalFrameHandle]; IF CodeDefs.CodeHandle[f] = fseg AND ~frame.code.swappedout THEN SELECT direction FROM up => frame.code.codebase ← LONG[frame.code.shortCodebase] + delta; down => BEGIN frame.code.codebase ← frame.code.codebase + delta; IF frame.code.highHalf # 0 THEN ERROR; frame.code.handle ← fseg; END; ENDCASE; RETURN[FALSE] END; -- body of MoveThisSegment SwapIn[fseg]; newVMpage ← alloc.alloc[basePage, fseg.pages, fseg, ResidentCodeInfo]; ProcessDefs.DisableInterrupts[]; oldVMpage ← proc[newVMpage]; XCOPY[from: LongAddressFromPage[oldVMpage], to: LongAddressFromPage[newVMpage], nwords: AltoDefs.PageSize * fseg.pages]; delta ← AltoDefs.PageSize * (LONG[LOOPHOLE[newVMpage,INTEGER]] - LONG[LOOPHOLE[oldVMpage,INTEGER]]); [] ← EnumerateGlobalFrames[UpdateCodebase]; alloc.update[oldVMpage, fseg.pages, free, NIL]; alloc.update[newVMpage, fseg.pages, inuse, fseg]; ProcessDefs.EnableInterrupts[]; Unlock[fseg]; END; -- body of CheckOne IF seg.class = code AND seg.lock > 0 THEN WITH s:seg SELECT FROM disk => SELECT direction FROM up => BEGIN VtC: ChangeFlavorProc = BEGIN RETURN[XMESA.VanillaToChocolate[fseg, newVMpage]] -- note variant changes here!! END; MoveThisSegment[XMesaDefs.DefaultXMBase, VtC]; END; down => NULL; ENDCASE; remote => IF s.proc = XMESA.XMremote THEN SELECT direction FROM up => NULL; down => BEGIN CtV: ChangeFlavorProc = BEGIN RETURN[XMESA.ChocolateToVanilla[@seg, newVMpage]] -- note variant changes here!! END; MoveThisSegment[XMesaDefs.DefaultBase0, CtV]; END; ENDCASE; ENDCASE; RETURN[FALSE] END; -- body of MoveLockedCode IF ~XMesaDefs.GetMemoryConfig[].useXM THEN RETURN; [] ← EnumerateFileSegments[CheckOne]; END; -- unimplemented instructions BlockEqual: PROCEDURE [p1: POINTER, n: CARDINAL, p2: POINTER] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; FOR i IN [0 .. n) DO IF (p1+i)↑ # (p2+i)↑ THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] END; ByteArray: TYPE = PACKED ARRAY [0..0) OF AltoDefs.BYTE; --XM PPA: TYPE = POINTER TO ByteArray; --XM ByteBlockEqual: PROCEDURE [p1: PPA, n: CARDINAL, p2: PPA] RETURNS [BOOLEAN] = BEGIN RETURN[BlockEqual[p1: p1, p2: p2, n: n/2] AND p1[n-1] = p2[n-1]] END; BlockEqualCode: PROCEDURE [p1: POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [result: BOOLEAN] = BEGIN frame: GlobalFrameHandle = GetReturnFrame[].accesslink; codebase: LONG POINTER ← CodeDefs.Codebase[frame]+offset; --XM i: CARDINAL; imax, j: CARDINAL; --XM bsize: CARDINAL = 10; --XM codeblock: ARRAY [0..bsize) OF UNSPECIFIED; --XM FOR j ← 0, j+bsize UNTIL j >= n --XM DO --XM imax ← MIN[bsize, n-j]; --XM XMesaDefs.XCOPY[from: codebase+j, to: LONG[@codeblock[0]], nwords: imax]; --XM FOR i IN [0..imax) --XM DO IF codeblock[i] # (p1+j+i)↑ THEN GOTO NotEqual; ENDLOOP; --XM REPEAT --XM NotEqual => result ← FALSE; --XM FINISHED => result ← TRUE; --XM ENDLOOP; --XM CodeDefs.ReleaseCode[frame]; RETURN END; ByteBlockEqualCode: PROCEDURE [p1: POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [result: BOOLEAN] = BEGIN frame: GlobalFrameHandle = GetReturnFrame[].accesslink; i: CARDINAL; codebase: LONG POINTER ← CodeDefs.Codebase[frame]+offset; --XM imax, j: CARDINAL; --XM bsize: CARDINAL = 10; --XM codeblock: ARRAY [0..bsize) OF UNSPECIFIED; --XM FOR j ← 0, j+bsize UNTIL j >= n/2 --XM DO --XM imax ← MIN[bsize, n/2-j]; --XM XMesaDefs.XCOPY[from: codebase+j, to: LONG[@codeblock[0]], nwords: imax]; --XM FOR i IN [0..imax) --XM DO IF codeblock[i] # (p1+j+i)↑ THEN GOTO NotEqual; ENDLOOP; --XM REPEAT --XM NotEqual => result ← FALSE; --XM FINISHED => result ← LOOPHOLE[p1, PPA][n-1] = LOOPHOLE[@codeblock, PPA][imax*2-1]; --XM ENDLOOP; --XM CodeDefs.ReleaseCode[frame]; RETURN END; -- data shuffling StringInit: PROCEDURE [coffset, n: CARDINAL, reloc, dest: POINTER] = BEGIN OPEN ControlDefs; g: GlobalFrameHandle = GetReturnFrame[].accesslink; i: CARDINAL; codebase: LONG POINTER ← CodeDefs.Codebase[g]+coffset; --XM imax, j: CARDINAL; --XM bsize: CARDINAL = 10; --XM codeblock: ARRAY [0..bsize) OF UNSPECIFIED; --XM FOR j ← 0, j+bsize UNTIL j >= n --XM DO --XM imax ← MIN[bsize, n-j]; --XM XMesaDefs.XCOPY[from: codebase+j, to: LONG[@codeblock[0]], nwords: imax]; --XM FOR i IN [0..imax) --XM DO (dest+j+i)↑ ← codeblock[i] + reloc; ENDLOOP; --XM ENDLOOP; --XM CodeDefs.ReleaseCode[g]; RETURN END; -- long, signed and mixed mode arithmetic DIVMOD: PROCEDURE [n,d: CARDINAL] RETURNS [QR] = LOOPHOLE[InlineDefs.DIVMOD]; LDIVMOD: PROCEDURE [nlow,nhigh,d: CARDINAL] RETURNS [QR] = LOOPHOLE[InlineDefs.LDIVMOD]; QR: TYPE = RECORD [q, r: INTEGER]; PQR: TYPE = POINTER TO QR; LongSignDivide: PROCEDURE [numhigh: INTEGER, pqr: PQR] = BEGIN negnum,negden: BOOLEAN ← FALSE; IF negden ← (pqr.r < 0) THEN pqr.r ← -pqr.r; IF negnum ← (numhigh < 0) THEN BEGIN IF pqr.q = 0 THEN numhigh ← -numhigh ELSE BEGIN pqr.q ← -pqr.q; numhigh ← InlineDefs.BITNOT[numhigh] END; END; pqr↑ ← LDIVMOD[nlow: pqr.q, nhigh: numhigh, d: pqr.r]; -- following assumes TRUE = 1; FALSE = 0 IF InlineDefs.BITXOR[LOOPHOLE[negnum],LOOPHOLE[negden]] # 0 THEN pqr.q ← -pqr.q; IF negnum THEN pqr.r ← -pqr.r; RETURN END; DivSS: PROCEDURE = BEGIN state: StateVector; p: PQR; t: CARDINAL; state ← STATE; state.stkptr ← t ← state.stkptr-1; state.dest ← GetReturnLink[]; p ← @state.stk[t-1]; LongSignDivide[numhigh: (IF p.q<0 THEN -1 ELSE 0), pqr: p]; RETURN WITH state END; LongCARDINAL: TYPE = InlineDefs.LongCARDINAL; DAdd: PROCEDURE [a,b: LongCARDINAL] RETURNS [LongCARDINAL] = MACHINE CODE BEGIN Mopcodes.zDADD END; DSub: PROCEDURE [a,b: LongCARDINAL] RETURNS [LongCARDINAL] = MACHINE CODE BEGIN Mopcodes.zDSUB END; DCompare: PROCEDURE [a,b: LongCARDINAL] RETURNS [{less, equal, greater}] = MACHINE CODE BEGIN Mopcodes.zDCOMP; Mopcodes.zINC END; DDivMod: PROCEDURE [num, den: LongCARDINAL] RETURNS [quotient, remainder: LongCARDINAL] = BEGIN OPEN InlineDefs; negNum, negDen: BOOLEAN ← FALSE; qq: CARDINAL; count: [0..31); lTemp: LongCARDINAL; IF LOOPHOLE[num.highbits, INTEGER] < 0 THEN BEGIN negNum ← TRUE; num ← DSub[[0,0],num]; END; IF LOOPHOLE[den.highbits, INTEGER] < 0 THEN BEGIN negDen ← TRUE; den ← DSub[[0,0],den]; END; IF den.highbits = 0 THEN BEGIN [quotient.highbits, qq] ← LongDivMod[[lowbits:num.highbits,highbits:0],den.lowbits]; [quotient.lowbits, remainder.lowbits] ← LongDivMod[[lowbits:num.lowbits,highbits:qq],den.lowbits]; remainder.highbits ← 0; END ELSE BEGIN count ← 0; quotient.highbits ← 0; lTemp ← den; WHILE lTemp.highbits # 0 DO -- normalize lTemp.lowbits ← BITSHIFT[lTemp.lowbits,-1] + BITSHIFT[lTemp.highbits,15]; lTemp.highbits ← BITSHIFT[lTemp.highbits,-1]; count ← count + 1; ENDLOOP; qq ← LongDiv[num,lTemp.lowbits]; -- trial quotient qq ← BITSHIFT[qq,-count]; lTemp ← LongMult[den.lowbits,qq]; -- multiply by trial quotient lTemp.highbits ← lTemp.highbits + den.highbits*qq; UNTIL DCompare[lTemp, num] # greater DO -- decrease quotient until product is small enough lTemp ← DSub[lTemp,den]; qq ← qq - 1; ENDLOOP; quotient.lowbits ← qq; remainder ← DSub[num,lTemp]; END; IF BITXOR[LOOPHOLE[negNum],LOOPHOLE[negDen]] # 0 THEN quotient ← DSub[[0,0],quotient]; IF negNum THEN remainder ← DSub[[0,0],remainder]; RETURN END; DDiv: PROCEDURE [a,b: LongCARDINAL] RETURNS [LongCARDINAL] = BEGIN OPEN InlineDefs; RETURN[DDivMod[a,b].quotient] END; DMod: PROCEDURE [a,b: LongCARDINAL] RETURNS [r: LongCARDINAL] = BEGIN OPEN InlineDefs; [remainder: r] ← DDivMod[a,b]; RETURN END; DMultiply: PROCEDURE [a,b: LongCARDINAL] RETURNS [product: LongCARDINAL] = BEGIN OPEN InlineDefs; product ← LongMult[a.lowbits, b.lowbits]; product.highbits ← product.highbits + a.lowbits*b.highbits + a.highbits*b.lowbits; RETURN END; GetLevel: PUBLIC PROCEDURE RETURNS [INTEGER] = BEGIN RETURN[ResidentPtr.level] END; SetLevel: PUBLIC PROCEDURE [l: INTEGER] = BEGIN ResidentPtr.level ← l; END; Init: PROCEDURE = BEGIN OPEN SDDefs; sd: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD; resident: POINTER TO FRAME [Resident] ← ResidentPtr; sd[sStackError] ← StackErrorTrap; sd[sControlFault] ← ControlFaultTrap; sd[sBLTE] ← BlockEqual; sd[sBYTBLTE] ← ByteBlockEqual; sd[sBLTEC] ← BlockEqualCode; sd[sBYTBLTEC] ← ByteBlockEqualCode; sd[sStringInit] ← StringInit; sd[sDivSS] ← DivSS; sd[sLongMul] ← DMultiply; sd[sLongDivMod] ← DDivMod; sd[sLongMod] ← DMod; sd[sLongDiv] ← DDiv; sd[sCopy] ← Copy; sd[sUnNew] ← UnNew; BEGIN OPEN resident; sd[sAllocTrap] ← AllocTrap[AllocTrap[NullFrame]]; sd[sSwapTrap] ← CodeTrap; sd[sUnbound] ← UnboundProcedureTrap; sd[sStart] ← Start; sd[sRestart] ← Restart; sd[sBreak] ← Break; sd[sAlternateBreak] ← WorryBreaker[]; sd[sIOResetBits] ← 3; LOOPHOLE[CSPort,Port].in ← MemorySwap; LOOPHOLE[CSPort,Port].out ← @WBPort; sd[sCoreSwap] ← LOOPHOLE[WBPort,Port].out ← @CSPort; WBPort[NIL]; level ← -1; END; END; -- Main Body; Init[]; END...