-- MMTraps.Mesa; edited by Sandman on May 17, 1979 3:14 PM -- Edited by Forrest on July 15, 1980 8:14 PM DIRECTORY AltoDefs USING [BYTE, PageSize], ControlDefs USING [ AV, AVItem, ControlLink, ControlModule, EntryInfo, FrameHandle, FrameVec, GFT, GFTIndex, GFTItem, GlobalFrameHandle, LargeReturnSlot, MainBodyIndex, NullControl, NullFrame, NullGlobalFrame, PrefixHandle, PrefixInfo, ProcDesc, SpecialReturnSlot, StateVector, SVPointer], CoreSwapDefs USING [SVPointer], FrameDefs, FrameOps USING [ Free, GetReturnFrame, GetReturnLink, MyLocalFrame, SetReturnFrame, Start], ImageDefs USING [PuntMesa], InlineDefs USING [ BITNOT, BITOR, BITSHIFT, BITXOR, COPY, DIVMOD, LDIVMOD, LongDiv, LongDivMod, LongMult, LongNumber], MMInit, MMSDEntries, Mopcodes USING [zDESCBS, zKFCB, zRBL, zSFC], ProcessDefs USING [DisableInterrupts, EnableInterrupts], SDDefs USING [sAllocTrap, SD, sProcessBreakpoint], SegmentDefs USING [ DataSegmentAddress, DataSegmentHandle, DeleteDataSegment, DefaultBase, MakeDataSegment], TrapDefs, TrapOps USING [ReadATP, ReadOTP]; MMTraps: PROGRAM IMPORTS FrameOps, ImageDefs, InlineDefs, ProcessDefs, SegmentDefs, TrapOps EXPORTS FrameDefs, FrameOps, MMInit, MMSDEntries, TrapDefs = PUBLIC BEGIN OPEN ControlDefs; -- allocation of frame space LargeFrameSlot: CARDINAL = 12; FrameSize: PUBLIC PROC [fsi: CARDINAL] RETURNS [CARDINAL] = { RETURN[FrameVec[fsi]] }; 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; ExtraSpaceSize: CARDINAL = 128; 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: PROC [otherframe: FrameHandle] RETURNS [myframe: FrameHandle] = BEGIN OPEN ProcessDefs, 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[]; -- guarantees one more instruction 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 => { alloc ← TRUE; fIndex ← LOOPHOLE[tempdest, CARDINAL]/4; EXIT }; 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: PROC [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 { (p-1)↑ ← i; p↑ ← AV[i].link; AV[i].link ← p; EXIT }; ENDLOOP; NewSpacePtr ← (p←DataSegmentAddress[newseg← MakeDataSegment[DefaultBase,1,[hard, bottomup, frame]]]) + 3; WordsLeft ← AltoDefs.PageSize-3; END; ENDLOOP END ELSE BEGIN fsize ← FrameVec[fIndex]; p ← DataSegmentAddress[ newseg ← MakeDataSegment[ DefaultBase, (fsize + AltoDefs.PageSize + 3)/AltoDefs.PageSize, [hard, bottomup, frame]]]; 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: PUBLIC PROC = 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: PROC = BEGIN dest: ControlLink; state: StateVector; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← TrapOps.ReadOTP[]; [] ← ERROR UnboundProcedure[dest]; END; CodeTrap: PROC = 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]]]; SwapInCode[frame]; RETURN WITH state; END; SwapInCode: PUBLIC PROC [f: GlobalFrameHandle] = BEGIN IF ~f.code.out THEN RETURN; f.code.out ← FALSE; f.code.shortbase ← f.code.handle + f.code.offset; RETURN END; -- Getting the Debugger Break: PROC = -- executed by (non-worry) BRK instruction BEGIN ProcessBreakpoint: PROC [CoreSwapDefs.SVPointer] = MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sProcessBreakpoint END; f: FrameHandle; state: StateVector; 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]; RETURN WITH state END; StackError: PUBLIC ERROR = CODE; StackErrorTrap: PROC = { state: StateVector; state ← STATE; ERROR StackError }; ControlFault: PUBLIC SIGNAL [source: FrameHandle] RETURNS [ControlLink] = CODE; ControlFaultTrap: PROC = BEGIN savedState: StateVector; savedState ← STATE; [] ← ERROR ControlFault[FrameOps.MyLocalFrame[]]; END; StartFault: PUBLIC SIGNAL [dest: GlobalFrameHandle] = CODE; MainBody: PROCEDURE [GlobalFrameHandle] RETURNS [ControlLink] = MACHINE CODE BEGIN Mopcodes.zDESCBS, MainBodyIndex END; Call: PROCEDURE [ControlLink] = MACHINE CODE BEGIN Mopcodes.zSFC END; Start: PUBLIC PROCEDURE [cm: ControlModule] = BEGIN state: StateVector; state ← STATE; IF ~cm.multiple THEN BEGIN IF cm.frame = NullGlobalFrame OR cm.frame.started THEN ERROR StartFault[cm.frame]; -- FrameDefs.ValidateGlobalFrame[cm.frame]; StartCM[cm.frame.global[0], cm.frame, @state]; IF ~cm.frame.started THEN BEGIN cm.frame.started ← TRUE; StartWithState[cm.frame, @state]; END ELSE IF state.stkptr # 0 THEN SIGNAL StartFault[cm.frame]; END ELSE BEGIN StartCM[cm, NIL, NIL]; IF state.stkptr # 0 THEN SIGNAL StartFault[cm.frame]; END; RETURN END; StartCM: PROCEDURE [ cm: ControlModule, frame: GlobalFrameHandle, state: ControlDefs.SVPointer] = BEGIN SELECT TRUE FROM cm = NullControl => RETURN; cm.multiple => BEGIN i, length: CARDINAL; cm.multiple ← FALSE; IF (length ← cm.list.nModules) = 0 THEN RETURN; cm.list.nModules ← 0; FOR i IN [0..length) DO StartCM[[frame[cm.list.frames[i]]], frame, state]; ENDLOOP; FrameOps.Free[cm.list]; END; cm.frame.started => RETURN; ENDCASE => BEGIN control: ControlModule ← cm.frame.global[0]; IF control # cm THEN StartCM[control, frame, state]; IF ~cm.frame.started THEN BEGIN cm.frame.started ← TRUE; IF frame # cm.frame THEN Call[MainBody[cm.frame]] ELSE StartWithState[frame, state]; END; END; RETURN END; StartWithState: PROCEDURE [ frame: GlobalFrameHandle, state: ControlDefs.SVPointer] = BEGIN OPEN ControlDefs; s: StateVector ← state↑; retFrame: FrameHandle ← FrameOps.GetReturnLink[].frame; s.dest ← MainBody[frame]; s.source ← retFrame.returnlink; FrameOps.Free[retFrame]; RETURN WITH s; END; Restart: PUBLIC PROCEDURE [dest: GlobalFrameHandle] = BEGIN stops: BOOLEAN; frame: FrameHandle; IF dest = NullGlobalFrame THEN ERROR StartFault[dest]; -- FrameDefs.ValidateGlobalFrame[dest]; IF ~dest.started THEN Start[[frame[dest]]]; -- FrameDefs.SwapInCode[dest]; IF dest.code.highByte = 0 THEN BEGIN GetPrefixInfo: PROC [LONG POINTER] RETURNS [PrefixInfo] = MACHINE CODE BEGIN Mopcodes.zRBL, 1 END; stops ← GetPrefixInfo[dest.code.longbase].stops; END ELSE stops ← LOOPHOLE[dest.code.shortbase, PrefixHandle].header.info.stops; -- FrameOps.ReleaseCode[dest]; IF ~stops THEN ERROR StartFault[dest]; IF (frame ← dest.global[0]) # NullFrame THEN BEGIN frame.returnlink ← FrameOps.GetReturnLink[]; FrameOps.SetReturnFrame[frame]; END; RETURN END; -- unimplemented instructions BlockEqual: PROC [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; PPA: TYPE = POINTER TO PACKED ARRAY [0..0) OF AltoDefs.BYTE; ByteBlockEqual: PROC [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: PROC [p1: POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [BOOLEAN] = BEGIN frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink; RETURN[BlockEqual[p1: p1, n: n, p2: frame.code.shortbase+offset]] END; ByteBlockEqualCode: PROC [p1: POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [BOOLEAN] = BEGIN frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink; RETURN[ByteBlockEqual[p1: p1, n: n, p2: frame.code.shortbase+offset]] END; -- data shuffling StringInit: PROC [coffset, n: CARDINAL, reloc, dest: POINTER] = BEGIN OPEN ControlDefs; g: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink; InlineDefs.COPY[from: g.code.shortbase+coffset, to: dest, nwords: n]; FOR i: CARDINAL IN [0..n) DO (dest+i)↑ ← (dest+i)↑ + reloc ENDLOOP; RETURN END; -- long, signed and mixed mode arithmetic DIVMOD: PROC [n,d: CARDINAL] RETURNS [QR] = LOOPHOLE[InlineDefs.DIVMOD]; LDIVMOD: PROC [nlow, nhigh,d: CARDINAL] RETURNS [QR] = LOOPHOLE[InlineDefs.LDIVMOD]; QR: TYPE = RECORD [q, r: INTEGER]; PQR: TYPE = POINTER TO QR; LongSignDivide: PROC [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[negnum, negden] # 0 THEN pqr.q ← -pqr.q; IF negnum THEN pqr.r ← -pqr.r; RETURN END; SignDivide: PROC = BEGIN state: ControlDefs.StateVector; p: PQR; t: CARDINAL; state ← STATE; state.stkptr ← t ← state.stkptr-1; state.dest ← FrameOps.GetReturnLink[]; p ← @state.stk[t-1]; LongSignDivide[numhigh: (IF p.q<0 THEN -1 ELSE 0), pqr: p]; RETURN WITH state END; DDivMod: PROC [ num, den: Number] RETURNS [quotient, remainder: Number] = BEGIN negNum, negDen: BOOLEAN ← FALSE; IF LOOPHOLE[num.highbits, INTEGER] < 0 THEN BEGIN negNum ← TRUE; num.li ← -num.li; END; IF LOOPHOLE[den.highbits, INTEGER] < 0 THEN BEGIN negDen ← TRUE; den.li ← -den.li; END; [quotient: quotient, remainder: remainder] ← DUnsignedDivMod[num: num, den: den]; IF InlineDefs.BITXOR[negNum,negDen] # 0 THEN quotient.li ← -quotient.li; IF negNum THEN remainder.li ← -remainder.li; RETURN END; DDiv: PROC [a,b: Number] RETURNS [Number] = { RETURN[DDivMod[a,b].quotient] }; DMod: PROC [a,b: Number] RETURNS [r: Number] = { [remainder: r] ← DDivMod[a,b]; RETURN }; DMultiply: PROC [a,b: Number] RETURNS [product: Number] = BEGIN product.lc ← InlineDefs.LongMult[a.lowbits, b.lowbits]; product.highbits ← product.highbits + a.lowbits*b.highbits + a.highbits*b.lowbits; RETURN END; Number: PRIVATE TYPE = InlineDefs.LongNumber; DUnsignedDivMod: PROC [ num, den: Number] RETURNS [quotient, remainder: Number] = BEGIN OPEN InlineDefs; qq: CARDINAL; count: [0..31); lTemp: Number; IF den.highbits = 0 THEN BEGIN [quotient.highbits, qq] ← LongDivMod[ LOOPHOLE[Number[num[lowbits:num.highbits, highbits:0]]], den.lowbits]; [quotient.lowbits, remainder.lowbits] ← LongDivMod[ LOOPHOLE[Number[num[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.lc, lTemp.lowbits]; -- trial quotient qq ← BITSHIFT[qq, -count]; lTemp.lc ← LongMult[den.lowbits, qq]; -- multiply by trial quotient lTemp.highbits ← lTemp.highbits + den.highbits*qq; UNTIL lTemp.lc <= num.lc DO -- decrease quotient until product is small enough lTemp.lc ← lTemp.lc - den.lc; qq ← qq - 1; ENDLOOP; quotient.lowbits ← qq; remainder.lc ← num.lc - lTemp.lc; END; RETURN END; DUnsignedDiv: PROC [a,b: Number] RETURNS [Number] = { RETURN[DUnsignedDivMod[a,b].quotient] }; DUnsignedMod: PROC [a,b: Number] RETURNS [r: Number] = { [remainder: r] ← DUnsignedDivMod[a,b]; RETURN }; END....