-- XDNubImpl.Mesa Edited by: Bruce on September 24, 1980 3:28 PM -- Sandman on July 21, 1980 11:02 AM 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, RealToBytePC], Runtime USING [CallDebugger], Mopcodes USING [zEXCH, zPOP, zW0, zWBL], Nub USING [badFrame, Sob, Switches], SegmentDefs USING [memConfig], State USING [GetGS, GetString, GSHandle, SetString, WritePrompt], Storage USING [String], String USING [AppendChar, AppendOctal, AppendString, LowerCase]; XDNubImpl: PROGRAM IMPORTS Actions, Commands, DebugOps, DOutput, LoaderOps, MachineDefs, Runtime, Nub, SegmentDefs, State, Storage, String EXPORTS Commands, Nub = BEGIN -- System Signals are converted to these to prevent NubCommand -- from catching user generated signals BadFile: PUBLIC ERROR [badname: STRING, reason: 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 String.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 = {Runtime.CallDebugger["What's up?"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,ReadXD]}; ReadXD: PUBLIC PROCEDURE [p: LONG POINTER] RETURNS [UNSPECIFIED] = {RETURN[p↑]}; 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.RealToBytePC[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 String.AppendString[ext, "bcd"L]; String.AppendChar[name, '.]; String.AppendString[name, ext]; ProcessSwitches[sw]; gf ← LoadNew[name, switches.framelinks ! BadFile => { Commands.WriteError[badFile]; IF ~data.debugging THEN CONTINUE}]; 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; String.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, "unknown Load error!"L]]; cm ← New[bcd, switches.framelinks, FALSE ! BadFile, BadVersion, UNWIND => NULL; VersionMismatch => BEGIN SIGNAL BadVersion[name]; RESUME END; FileNotFound => ERROR BadFile[name, "not found!"L]; BadCode => ERROR BadFile[name, "bad code!"L]; ANY => ERROR BadFile[file, "unknown New error!"L]]; 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 => String.AppendChar[s, c]; ENDLOOP; RETURN END; END.