-- NubImpl.Mesa Edited by: Bruce on July 9, 1980 7:09 PM
-- Hayes on July 10, 1980 3:13 PM
DIRECTORY
Actions USING [Read, Write],
Ascii USING [ControlS, ControlT, CR, NUL, SP],
BcdOps USING [BcdBase],
CommandList USING [Command],
Commands USING [Command, Confirm, GetString, GetToken, GetTwoStrings, WriteCommand, WriteError],
ControlDefs USING [ControlModule, GFT, NullFrame],
DebugOps USING [Abort, Proceed, Quit, StringExpToOctal],
DOutput USING [Char, Decimal, EOL, Octal, Text],
LoaderOps USING [BadCode, FileNotFound, Load, New, VersionMismatch],
MachineDefs USING [FHandle, GFHandle, NullGF, WordToBytePC],
MiscDefs USING [CallDebugger],
Mopcodes USING [zEXCH, zPOP, zW0, zWBL],
Nub USING [badFrame, ReadXD, Sob, Switches],
SegmentDefs USING [memConfig],
State USING [GetGS, GetString, GSHandle, SetString, WritePrompt],
Storage USING [String],
StringDefs USING [AppendChar, AppendOctal, AppendString, LowerCase];
NubImpl: PROGRAM
IMPORTS Actions, Commands, DebugOps, DOutput, LoaderOps,
MachineDefs, MiscDefs, Nub, SegmentDefs, State, Storage, StringDefs
EXPORTS Commands, Nub =
BEGIN
-- System Signals are converted to these to prevent NubCommand
-- from catching user generated signals
BadFile: PUBLIC ERROR [badname: STRING] = CODE; -- nee FileNameError
BadVersion: PUBLIC SIGNAL [badname: STRING] = CODE; -- nee VersionMismatch
data: State.GSHandle ← State.GetGS[];
DoCommand: PUBLIC PROCEDURE [char: CHARACTER] =
BEGIN OPEN Commands;
SELECT StringDefs.LowerCase[char] FROM
'n => GetString[[prompt: name, sId: nubModule], LoadIt, nubNew];
's => GetString[[prompt: nubFrame, sId: nubFrame], StartIt, nubStart];
't => DisplayNubStack[Nub.badFrame];
'd => Confirm[nubDebug, CallIDebug];
'q => Confirm[quit, SignalQuit];
'p => Confirm[proceed, SignalProceed];
'r => GetTwoStrings[[prompt: at, sId: nubRAddr, resetPrompt: FALSE], [
prompt: n10, sId: nubRCount, resetPrompt: FALSE], ReadIt, read];
'w => GetTwoStrings[[prompt: at, sId: nubWAddr, resetPrompt: FALSE], [
prompt: gets, sId: nubRhs, colon: FALSE, resetPrompt: FALSE],
WriteIt, write];
'? =>
BEGIN
DOutput.Text["Commands are: "L];
FOR nubIndex: CommandList.Command IN [nubNew..nubStack) DO
WriteCommand[nubIndex]; DOutput.Text[", "L] ENDLOOP;
WriteCommand[nubStack];
State.WritePrompt[];
END;
Ascii.CR, Ascii.SP => State.WritePrompt[];
ENDCASE => BEGIN DOutput.Char['?]; State.WritePrompt[]; END;
RETURN
END;
CallIDebug: PROCEDURE = {MiscDefs.CallDebugger["What's up Garbo?"L]};
LoadIt: PROCEDURE [file: STRING] = BEGIN [] ← LoadFile[file] END;
StartIt: PROCEDURE [frame: STRING] =
BEGIN
gframe: MachineDefs.GFHandle ← LOOPHOLE[DebugOps.StringExpToOctal[frame]];
StartProg[gframe];
END;
ReadIt: PROCEDURE [start, cnt: STRING] = {Actions.Read[start,cnt,Nub.ReadXD]};
DisplayNubStack: PROCEDURE [f: MachineDefs.FHandle] =
BEGIN
Commands.WriteCommand[nubStack];
IF f#ControlDefs.NullFrame THEN f ← f.returnlink.frame;
THROUGH [0..25) WHILE f#ControlDefs.NullFrame DO
DOutput.EOL[];
DOutput.Text["L: "L];
DOutput.Octal[f];
DOutput.Text[", G: "L];
DOutput.Octal[f.accesslink];
DOutput.Text[", PC: "L];
DOutput.Octal[MachineDefs.WordToBytePC[f.pc]];
DOutput.Text[", Locals: "L];
FOR i: CARDINAL IN [0..3) DO
DOutput.Octal[f.local[i]];
DOutput.Text[", "L];
ENDLOOP;
DOutput.Octal[f.local[3]];
f ← f.returnlink.frame;
ENDLOOP;
IF f#ControlDefs.NullFrame THEN
BEGIN
DOutput.EOL[];
FOR i: INTEGER IN [0..1000) DO
IF f=ControlDefs.NullFrame THEN {DOutput.Decimal[i]; EXIT};
f ← f.returnlink.frame;
REPEAT
FINISHED => DOutput.Text["> 1000"L];
ENDLOOP;
DOutput.Text[" more..."L];
END;
DOutput.EOL[];
State.WritePrompt[];
END;
WriteXD: PUBLIC PROC [p: LONG POINTER, v: UNSPECIFIED] =
BEGIN
WBL: PROC [UNSPECIFIED, LONG POINTER] =
MACHINE CODE BEGIN Mopcodes.zWBL, 0 END;
WriteMem: PROCEDURE [LONG POINTER, UNSPECIFIED] =
MACHINE CODE BEGIN Mopcodes.zPOP; Mopcodes.zEXCH; Mopcodes.zW0 END;
IF SegmentDefs.memConfig.xmMicroCode THEN WBL[v, p] ELSE WriteMem[p,v]
END;
WriteIt: PROCEDURE [loc, rhs: STRING] = {Actions.Write[loc,rhs,WriteXD]};
SignalProceed: PUBLIC PROCEDURE =
BEGIN SIGNAL DebugOps.Proceed; RETURN END;
SignalQuit: PUBLIC PROCEDURE =
BEGIN SIGNAL DebugOps.Quit; RETURN END;
LoadFile: PUBLIC PROCEDURE [file: STRING] RETURNS [gf: MachineDefs.GFHandle] =
BEGIN
ext: STRING ← [10];
sw: STRING ← [10];
name: STRING ← [40];
i: CARDINAL ← 0;
get: PROCEDURE RETURNS [c:CHARACTER] =
BEGIN
IF i = file.length THEN RETURN [Ascii.NUL];
c ← file[i];
i ← i+1;
RETURN[c];
END;
gf ← MachineDefs.NullGF;
Commands.GetToken[get, name, ext, sw];
IF ext.length = 0 THEN StringDefs.AppendString[ext, "bcd"L];
StringDefs.AppendChar[name, '.];
StringDefs.AppendString[name, ext];
ProcessSwitches[sw];
gf ← LoadNew[name, switches.framelinks !BadFile =>
BEGIN Commands.WriteError[badFile]; CONTINUE END];
IF gf # MachineDefs.NullGF THEN
BEGIN frame: STRING ← State.GetString[nubFrame];
data.nubFrame ← gf;
IF frame = NIL THEN
BEGIN frame ← Storage.String[7]; State.SetString[nubFrame, frame] END
ELSE frame.length ← 0;
StringDefs.AppendOctal[frame, gf];
END;
RETURN
END;
LoadNew: PUBLIC PROCEDURE [file: STRING, framelinks: BOOLEAN ← TRUE]
RETURNS [MachineDefs.GFHandle] =
BEGIN OPEN LoaderOps;
bcd: BcdOps.BcdBase;
cm: ControlDefs.ControlModule;
bcd ← Load[file! BadFile, UNWIND => NULL; ANY => ERROR BadFile[file]];
cm ← New[bcd, switches.framelinks, FALSE
! BadFile, BadVersion, UNWIND => NULL;
VersionMismatch => BEGIN SIGNAL BadVersion[name]; RESUME END;
FileNotFound, BadCode => ERROR BadFile[name];
ANY => ERROR BadFile[file]];
DOutput.Text[" -- "L];
DOutput.Octal[cm];
DOutput.EOL[];
RETURN[cm.frame]
END;
StartProg: PUBLIC PROCEDURE [gf: MachineDefs.GFHandle] =
BEGIN
p: PROCESS;
IF ControlDefs.GFT[gf.gfi].frame # gf THEN
BEGIN
DOutput.Text[" not a global frame: "L];
SIGNAL DebugOps.Abort
END;
IF gf # MachineDefs.NullGF THEN
BEGIN
data.nubFrame ← gf;
p ← FORK StartModule[LOOPHOLE[gf]];
JOIN p;
END;
RETURN
END;
StartModule: PROCEDURE [f: PROGRAM] =
BEGIN ENABLE ABORTED, DebugOps.Abort => CONTINUE;
IF ~LOOPHOLE[f, MachineDefs.GFHandle].started THEN START f ELSE RESTART f;
END;
switches: Nub.Sob;
InitSwitches: PUBLIC PROCEDURE RETURNS [Nub.Switches] =
BEGIN
switches ← [command: FALSE, internalInstall: FALSE, install: FALSE,
framelinks: TRUE, start: TRUE, search: FALSE, trees: FALSE,
display: FALSE, spare1: FALSE, spare2: FALSE];
RETURN [@switches]
END;
ProcessSwitches: PUBLIC PROCEDURE [s: STRING] =
BEGIN OPEN switches;
i: CARDINAL;
inverse: BOOLEAN ← FALSE;
FOR i IN [0..s.length) DO
SELECT s[i] FROM
'c, 'C => BEGIN inverse ← FALSE; command ← TRUE END;
'i, 'I => BEGIN inverse ← FALSE; install ← TRUE END;
'x, 'X => BEGIN inverse ← FALSE; internalInstall ← TRUE END;
's, 'S => IF inverse THEN inverse ← start ← FALSE ELSE start ← TRUE;
'l, 'L => BEGIN inverse ← FALSE; framelinks ← FALSE END;
'b, 'B =>
IF inverse THEN inverse ← display ← FALSE ELSE display ← TRUE;
Ascii.ControlS =>
IF inverse THEN inverse ← display ← FALSE ELSE search ← TRUE;
Ascii.ControlT =>
IF inverse THEN inverse ← display ← FALSE ELSE trees ← TRUE;
'- => inverse ← TRUE;
ENDCASE => inverse ← FALSE;
ENDLOOP;
END;
GetToken: PUBLIC PROCEDURE [
get: PROCEDURE RETURNS [CHARACTER], token, ext, switches: STRING] =
BEGIN OPEN Ascii;
s: STRING;
c: CHARACTER;
token.length ← ext.length ← switches.length ← 0;
s ← token;
WHILE (c ← get[]) # NUL DO
SELECT c FROM
SP, CR =>
IF token.length # 0 OR ext.length # 0 OR switches.length # 0 THEN RETURN;
'. => s ← ext;
'/ => s ← switches;
ENDCASE => StringDefs.AppendChar[s, c];
ENDLOOP;
RETURN
END;
END.