-- MMDebug.mesa; edited by Sandman June 19, 1979 9:43 AM -- Edited by Forrest July 15, 1980 2:21 PM -- Edited by Gobbel November 3, 1980 11:43 PM DIRECTORY BcplOps USING [BcplJSR], ControlDefs USING [FrameHandle, GlobalFrameHandle, StateVector, SVPointer], DiskDefs USING [DS], FrameDefs USING [UnNew], FrameOps USING [GetReturnFrame, GetReturnLink, MyLocalFrame], ImageDefs USING [ AbortMesa, CleanupItem, CleanupMask, CleanupProcedure, PuntMesa, StopMesa], InlineDefs USING [BITAND], MMInit USING [MakeBootFile, MMMakeBoot, MMStart], MMOps USING [BootNetExec, etherBooted, FakeModulesCode, MMEtherBoot], Mopcodes USING [zSTARTIO], OsStaticDefs USING [OsStatics], ProcessDefs USING [DisableInterrupts, EnableInterrupts], SDDefs USING [ sCallDebugger, SD, sInterrupt, sProcessBreakpoint, sUncaughtSignal], SystemDefs USING [FreePages]; MMDebug: PROGRAM [user: PROGRAM] IMPORTS BcplOps, FrameDefs, FrameOps, ImageDefs, InlineDefs, MMInit, MMOps, ProcessDefs, SystemDefs EXPORTS ImageDefs, MMInit, MMOps SHARES DiskDefs = BEGIN OPEN ControlDefs; debugState: SVPointer; reason: {uncaughtsignal, interrupt, breakpoint, explicitcall} ← explicitcall; etherBooted: PUBLIC BOOLEAN ← FALSE; ProcessBreakpoint: PROCEDURE [s: SVPointer] = BEGIN reason ← breakpoint; debugState ← s; Swap[]; RETURN END; Interrupt: PROCEDURE = BEGIN -- called by BRK trap handler in resident code state: ControlDefs.StateVector; state ← STATE; state.dest ← FrameOps.MyLocalFrame[]; reason ← interrupt; debugState ← @state; Swap[]; END; Catcher: PROCEDURE [msg, signal: UNSPECIFIED, frame: FrameHandle] = BEGIN OPEN ControlDefs; state: StateVector; state.stk[0] ← msg; state.stk[1] ← signal; state.stkptr ← 0; state.dest ← FrameOps.GetReturnFrame[]; reason ← uncaughtsignal; debugState ← @state; Swap[]; RETURN END; CallDebugger: PROCEDURE [s: STRING] = BEGIN -- user's entry point to debugger state: ControlDefs.StateVector; state ← STATE; state.stk[0] ← s; state.stkptr ← 1; state.dest ← FrameOps.GetReturnLink[]; reason ← explicitcall; debugState ← @state; Swap[]; RETURN END; SetSD: PROCEDURE = BEGIN OPEN SDDefs; sd: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD; sd[sProcessBreakpoint] ← ProcessBreakpoint; sd[sUncaughtSignal] ← Catcher; sd[sInterrupt] ← Interrupt; sd[sCallDebugger] ← CallDebugger; END; Swap: PROCEDURE = BEGIN break: RECORD[a,b: WORD] ← [77400B, 1400B]; DiskStatus: POINTER TO DiskDefs.DS = LOOPHOLE[522B]; IF DiskStatus.notReady # 0 THEN NetDebug[] ELSE [] ← BcplOps.BcplJSR[JSR, @break, 0]; RETURN END; TypeStore: UNSPECIFIED = 200B; TypeFetch: UNSPECIFIED = 201B; TypeProceed: UNSPECIFIED = 202B; TypeProceedReply: UNSPECIFIED = 203B; TypeAck: UNSPECIFIED = 204B; TeleDebugSocket: CARDINAL = 60B; -- these types for clarity Byte: TYPE = [0..255]; ByteCount, WordCount: TYPE = CARDINAL; MachineAddress: TYPE = MACHINE DEPENDENT RECORD [ net, host: Byte]; Pair: TYPE = MACHINE DEPENDENT RECORD [a,b: CARDINAL]; Port: TYPE = MACHINE DEPENDENT RECORD [ machine: MachineAddress, socket: Pair]; PacketTypePup: CARDINAL = 1000B; SocDebugger: Pair = [0,TeleDebugSocket]; DPup:TYPE= MACHINE DEPENDENT RECORD [ -- the Ethernet encapsulation eDest, eSource: Byte, eWord2: CARDINAL, -- Pup starts here pupLength: ByteCount, transportControl, pupType: Byte, pupID: Pair, destPort: Port, sourcePort: Port, data: Data, xSum: CARDINAL]; PacketSize: WordCount = SIZE[DPup]; PupSize: ByteCount = (PacketSize-2)*2; Data: TYPE = MACHINE DEPENDENT RECORD [ SELECT OVERLAID * FROM short => [ sAddress: POINTER, sValue: UNSPECIFIED, lenChunk: CARDINAL], long => [ lAddress: LONG POINTER, lValue: UNSPECIFIED], ENDCASE]; NoChecksum: CARDINAL = 177777B; EthernetDeviceBlock: TYPE = MACHINE DEPENDENT RECORD [ EPLocMicrocodeStatus, EPLocHardwareStatus: Byte, EBLocInterruptBit: WORD, EELocInputFinishCount: INTEGER, ELLocCollisionMagic: WORD, EILocInputCount: INTEGER, EILocInputPointer: POINTER, EOLocOutputCount: INTEGER, EOLocOutputPointer: POINTER]; EtherDevice: POINTER TO EthernetDeviceBlock = LOOPHOLE[600B]; EtherCommand: --MACHINE DEPENDENT-- TYPE = {null, output, input, reset}; Ether: PROCEDURE [EtherCommand] = MACHINE CODE BEGIN Mopcodes.zSTARTIO END; rtClock: POINTER TO INTEGER = LOOPHOLE[430B]; TicksPerSec: CARDINAL = 26; TenSec: CARDINAL = 10 * TicksPerSec; delayCount: CARDINAL ← 200; TeleSwatCursor: ARRAY [0..16) OF WORD = [ 0, 73507B, 22104B, 23507B, 22104B, 23567B, 0, 0, 65227B, 105252B, 45252B, 25272B, 142452B, 0, 0, 0]; NetDebug: PROCEDURE = BEGIN myHost: Byte ← OsStaticDefs.OsStatics.SerialNumber; d0: BOOLEAN = OsStaticDefs.OsStatics.AltoVersion.engineeringnumber = 4; debugger: Port; device: POINTER TO EthernetDeviceBlock ← LOOPHOLE[600B]; cursor: POINTER TO ARRAY [0..16) OF WORD ← LOOPHOLE[431B]; saveCursor: ARRAY [0..16) OF WORD ← cursor↑; xpup: DPup; dpup: POINTER TO DPup = @xpup; proceedTime: INTEGER ← 0; cursor↑ ← TeleSwatCursor; device.EBLocInterruptBit ← 0; Ether[reset]; device.EILocInputPointer ← device.EOLocOutputPointer ← dpup; device.EILocInputCount ← device.EOLocOutputCount ← PacketSize; UNTIL proceedTime # 0 AND proceedTime-rtClock↑ <= 0 DO Ether[reset]; device.EPLocMicrocodeStatus ← 0; device.EPLocHardwareStatus ← 0; device.ELLocCollisionMagic ← 0; Ether[input]; DO IF device.EPLocHardwareStatus#0 THEN BEGIN IF device.EPLocMicrocodeStatus = 0 AND dpup.eWord2 = PacketTypePup AND dpup.destPort.socket = SocDebugger THEN BEGIN IF dpup.pupType # TypeProceedReply THEN proceedTime ← 0; SELECT dpup.pupType FROM TypeFetch => BEGIN dpup.data.sValue ← dpup.data.sAddress↑; dpup.data.lenChunk ← 0; END; TypeStore => BEGIN dpup.data.sAddress↑ ← dpup.data.sValue; dpup.data.lenChunk ← 0; END; TypeProceed => proceedTime ← rtClock↑ + TenSec; TypeProceedReply => IF proceedTime # 0 THEN BEGIN cursor↑ ← saveCursor; RETURN END; ENDCASE => EXIT; END ELSE EXIT; dpup.eDest ← dpup.eSource; dpup.eSource ← myHost; debugger ← dpup.sourcePort; dpup.sourcePort ← dpup.destPort; dpup.destPort ← debugger; dpup.pupType ← TypeAck; dpup.pupLength ← PupSize; dpup.transportControl ← 0; dpup.xSum ← NoChecksum; device.EPLocMicrocodeStatus ← 0; device.EPLocHardwareStatus ← 0; device.ELLocCollisionMagic ← 0; -- delay before sending ack THROUGH [0..delayCount) DO NULL ENDLOOP; Ether[output]; EXIT; END; ENDLOOP; UNTIL device.EPLocHardwareStatus#0 DO NULL ENDLOOP; ENDLOOP; cursor↑ ← saveCursor; RETURN END; BootViaNet: PUBLIC PROCEDURE [bootIndex: CARDINAL, host: WORD ← 0] = BEGIN StartLoader: ARRAY [0..8] OF UNSPECIFIED ← [ 20406B, -- lda 0 lvBootLoaderPacket ; Get pointer to loader 101400B, -- inc 0 0 ; Compute page0image-1 24405B, -- lda 1 k400 ; Last destination address 34405B, -- lda 3 lblt ; Negative of number of words 61005B, -- blt ; Move loader into page 0 6B, -- jmp boot0-page0image+page0origin ; Dive into loader 0B, -- lvBootLoaderPacket: bootLoaderPacket 400B, -- k400: 400 177402B]; -- lblt: -401+page0origin BootFileNumberIndex: CARDINAL = 74B; HostIndex: CARDINAL = 67B; EtherCodeStartIndex: CARDINAL = 31B; etherBootCode: POINTER TO ARRAY [0..0) OF WORD ← MMOps.FakeModulesCode[MMOps.MMEtherBoot]; ProcessDefs.DisableInterrupts[]; etherBootCode[BootFileNumberIndex] ← bootIndex; etherBootCode[HostIndex] ← host*400B; StartLoader[6B] ← @etherBootCode[EtherCodeStartIndex]; [] ← BcplOps.BcplJSR[JSR,@StartLoader[0B],NIL]; -- bye bye END; MakeBoot: PUBLIC PROCEDURE = BEGIN MMInit.MakeBootFile[]; FrameDefs.UnNew[LOOPHOLE[MMInit.MMMakeBoot]]; RETURN END; UserCleanupList: POINTER TO ImageDefs.CleanupItem ← NIL; AddCleanupProcedure: PUBLIC PROCEDURE [item: POINTER TO ImageDefs.CleanupItem] = BEGIN ProcessDefs.DisableInterrupts[]; RemoveCleanupProcedure[item]; item.link ← UserCleanupList; UserCleanupList ← item; ProcessDefs.EnableInterrupts[]; END; RemoveCleanupProcedure: PUBLIC PROCEDURE [item: POINTER TO ImageDefs.CleanupItem] = BEGIN prev, this: POINTER TO ImageDefs.CleanupItem; IF UserCleanupList = NIL THEN RETURN; ProcessDefs.DisableInterrupts[]; prev ← this ← UserCleanupList; IF this = item THEN UserCleanupList ← this.link ELSE UNTIL (this ← this.link) = NIL DO IF this = item THEN BEGIN prev.link ← this.link; EXIT END; prev ← this; ENDLOOP; ProcessDefs.EnableInterrupts[]; END; UserCleanupProc: PUBLIC ImageDefs.CleanupProcedure = BEGIN OPEN ImageDefs, MMOps; -- all interrupts off if why = finish or abort this, next: POINTER TO ImageDefs.CleanupItem; this ← UserCleanupList; UserCleanupList ← NIL; WHILE this # NIL DO next ← this.link; IF InlineDefs.BITAND[ImageDefs.CleanupMask[why], this.mask] # 0 THEN this.proc[why ! ANY => IF why = Abort OR why = Finish THEN CONTINUE]; AddCleanupProcedure[this]; this ← next; ENDLOOP; SELECT why FROM Finish => IF ~etherBooted THEN StopMesa[] ELSE BootNetExec[]; Abort => IF ~etherBooted THEN AbortMesa[] ELSE BootNetExec[]; ENDCASE; END; -- Main body STOP; BEGIN ENABLE ANY => ImageDefs.PuntMesa; SetSD[]; SystemDefs.FreePages[LOOPHOLE[MMInit.MMStart, GlobalFrameHandle].code.handle]; FrameDefs.UnNew[LOOPHOLE[MMInit.MMStart]]; END; START user; ImageDefs.StopMesa[]; END...