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