DIRECTORY AMBridge, AMModel, AMModelBridge, AMTypes, Ascii, Atom, Basics, BasicTime, Buttons, Commander, CommandTool, Containers USING [ChildXBound, ChildYBound, Container, Create], Convert, FS, IO, Labels, List, ListerUtils, MessageWindow, OpDebug, PrincOps, PrincOpsUtils, Process, ProcessProps, RESInterpreter, Rope, Rules USING [Create, Rule], SafeStorage, TypeScript, VFonts, ViewerClasses USING [Viewer, ViewerClassRec], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, PaintViewer], ViewerTools USING [GetContents, GetSelectionContents, MakeNewTextViewer, SetContents, SetSelection], WorldVM; RESIInterface: CEDAR MONITOR LOCKS h.LOCK USING h: Handle IMPORTS AMBridge, AMModel, AMModelBridge, AMTypes, Atom, BasicTime, Buttons, Commander, CommandTool, Containers, Convert, IO, Labels, List, MessageWindow, OpDebug, PrincOpsUtils, Process, ProcessProps, RESInterpreter, Rope, Rules, SafeStorage, TypeScript, VFonts, ViewerIO, ViewerOps, ViewerTools, WorldVM EXPORTS RESInterpreter = BEGIN entryHeight: CARDINAL = 15; -- how tall to make each line of items entryVSpace: CARDINAL = 2; -- vertical leading space between lines entryHSpace: CARDINAL = 5; -- horizontal space between items in a line ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; TV: TYPE = AMTypes.TV; Byte: TYPE = Basics.Byte; Machine: TYPE = RESInterpreter.Machine; FinishedExecution: PUBLIC SIGNAL = CODE; Handle: TYPE = REF MyRec; -- a REF to the data for a particular instance of the sample tool; multiple instances can be created. MyRec: TYPE = MONITORED RECORD [ -- the data for a particular tool instance outer: Containers.Container _ NIL, -- handle for the enclosing container height: INT _ 0, -- height measured from the top of the container cmd: CommandViewer, -- the commands busy, ready: BOOL _ FALSE, show2Above, traceOps, countOps, recordXfers, modelCache, flushOnCall, lru: REF BOOL, stopFlag, killCountProcess: BOOL _ FALSE, running, pauseTime: CONDITION, m: Machine, workingDir: Atom.PropList, parent: Commander.Handle, tsIn, tsOut: STREAM, ts: ViewerClasses.Viewer ]; -- the typescript CommandViewer: TYPE = RECORD [ iCount: ViewerClasses.Viewer, cacheLines, cacheQuads, instCaches, dataCaches: ViewerClasses.Viewer, pc: ViewerClasses.Viewer, lf, lfName: ViewerClasses.Viewer, gf, gfName: ViewerClasses.Viewer, nextOp: ViewerClasses.Viewer, stk: ARRAY [0..PrincOps.stackDepth) OF ViewerClasses.Viewer, lcl: ARRAY [0..PrincOps.stackDepth) OF ViewerClasses.Viewer, gfiRange: ViewerClasses.Viewer, breakGF, breakPC: ViewerClasses.Viewer, initialProc, configName: ViewerClasses.Viewer, commandLine: ViewerClasses.Viewer ]; PromptRec: TYPE = RECORD [ handle: Handle, viewer: ViewerClasses.Viewer _ NIL, number: BOOL _ FALSE]; BoolRec: TYPE = RECORD [ handle: Handle, flag: REF BOOL]; PromptHandle: TYPE = REF PromptRec; MakeTool: Commander.CommandProc = TRUSTED BEGIN rule: Rules.Rule; my: Handle _ NEW[MyRec]; cpl: Atom.PropList _ ProcessProps.GetPropList[]; wd: ROPE _ NARROW[List.Assoc[$WorkingDirectory, cpl]]; my.parent _ NARROW[List.Assoc[$CommanderHandle, cpl]]; my.workingDir _ Atom.PutPropOnList[propList: NIL, prop: $WorkingDirectory, val: wd]; my.outer _ Containers.Create[[-- construct the outer container name: "Dragoman", -- name displayed in the caption iconic: TRUE, -- so tool will be iconic (small) when first created column: left, -- initially in the left column scrollable: FALSE ]]; -- inhibit user from scrolling contents MakeCommands[my]; -- build each (sub)viewer in turn rule _ Rules.Create [[parent: my.outer, wy: my.height, ww: my.outer.cw, wh: 2]]; Containers.ChildXBound[my.outer, rule]; my.height _ my.height + entryHeight + 2; -- interline spacing MakeTypescript[my]; ViewerOps.PaintViewer[my.outer, all]; -- reflect above change END; MakeTypescript: PROC [handle: Handle] = BEGIN handle.height _ handle.height + entryVSpace; -- space down from the top of the viewer handle.ts _ TypeScript.Create[ info: [name: "Dragoman.ts", wy: handle.height, parent: handle.outer, border: FALSE ]]; [handle.tsIn, handle.tsOut] _ ViewerIO.CreateViewerStreams [ name: "Dragoman.ts", viewer: handle.ts, backingFile: "Dragoman.ts", editedStream: FALSE]; Containers.ChildXBound[handle.outer, handle.ts]; Containers.ChildYBound[handle.outer, handle.ts]; END; SetValue: PROC [label: ViewerClasses.Viewer, value: ROPE] = { IF label # NIL THEN ViewerTools.SetContents[label, value]}; MakeCommands: PROC [handle: Handle] = BEGIN initialData: Rope.ROPE = NIL; topY: INT = handle.height; stkX, lclblX, lclX, tagX, valX, nameX: INT; trX, opsX, xfrX: INT; wy: INT _ topY; wx: INT _ 0; current: INT = INT.FIRST; At: PROC [x, row: INT _ current] = { IF row # current THEN { wy _ topY + row * (entryHeight + entryVSpace); handle.height _ MAX[handle.height, wy]}; IF x # current THEN wx _ x}; NewLine: PROC = { wy _ wy + entryHeight + entryVSpace; handle.height _ MAX[handle.height, wy]; wx _ entryHSpace}; NamedItem: PROC [label: ROPE, width: INT, data: ROPE _ NIL, number: BOOL _ FALSE] RETURNS [v: ViewerClasses.Viewer] = { ph: PromptHandle _ NEW [PromptRec _ [handle: handle]]; t: Buttons.Button _ Buttons.Create[ info: [ name: Rope.Concat[label, ":"], wy: wy, wh: entryHeight, -- specify rather than defaulting so line is uniform wx: wx, parent: handle.outer, border: FALSE ], proc: Prompt, clientData: ph]; -- this will be passed to our button proc wx _ wx + t.ww + entryHSpace; v _ ViewerTools.MakeNewTextViewer[ [ parent: handle.outer, wx: wx, wy: wy, ww: width*VFonts.CharWidth['0]+12, wh: entryHeight, data: data, scrollable: FALSE, border: FALSE]]; ph.viewer _ v; wx _ wx + v.ww + entryHSpace}; Label: PROC [value: ROPE, width: INT _ 0] RETURNS [v: ViewerClasses.Viewer] = { lw: INT _ MAX[ width*VFonts.CharWidth['0], IF value = NIL THEN 0 ELSE VFonts.StringWidth[value]]+4; v _ Labels.Create[ [ name: value, -- initial contents wx: wx, wy: wy, ww: lw, wh: entryHeight, parent: handle.outer, border: FALSE]]; wx _ wx + v.ww + entryHSpace}; Value: PROC [value: ROPE, width: INT _ 0] RETURNS [v: ViewerClasses.Viewer] = { lw: INT _ MAX[ width*VFonts.CharWidth['0], IF value = NIL THEN 0 ELSE VFonts.StringWidth[value]]+12; v _ ViewerTools.MakeNewTextViewer[ [ data: value, -- initial contents wx: wx, wy: wy, ww: lw, wh: entryHeight, scrollable: FALSE, parent: handle.outer, border: FALSE]]; wx _ wx + v.ww + entryHSpace}; Cmd: PROC [label: ROPE, proc: Buttons.ButtonProc] = { t: Buttons.Button _ Buttons.Create[ info: [ name: Rope.Concat[label, "!"], wx: wx, wy: wy, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: handle.outer, border: FALSE ], proc: proc, clientData: handle]; -- this will be passed to our button proc wx _ wx + t.ww + entryHSpace}; Bool: PROC [label: ROPE, initial: BOOL] RETURNS [flag: REF BOOL] = { t: Buttons.Button; br: REF BoolRec; flag _ NEW[BOOL _ initial]; br _ NEW[BoolRec _ [handle: handle, flag: flag]]; t _ Buttons.Create[ info: [ name: label, wx: wx, wy: wy, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: handle.outer, border: TRUE ], proc: ToggleBool, clientData: br]; -- this will be passed to our button proc Buttons.SetDisplayStyle[ button: t, style: IF initial THEN $WhiteOnBlack ELSE $BlackOnWhite, paint: FALSE]; wx _ wx + t.ww + entryHSpace}; At[row: 0, x: entryHSpace]; Cmd["STOP", StopIt]; Cmd["run", RunProc]; Cmd["step", StepProc]; Cmd["zero", ZeroProc]; [] _ Label["cnt: "]; handle.cmd.iCount _ Value[NIL, 10]; handle.cmd.cacheLines _ NamedItem["lines", 3, "50"]; handle.cmd.cacheQuads _ NamedItem["q/l", 2, "2"]; handle.cmd.instCaches _ NamedItem["inst", 2, "2"]; handle.cmd.dataCaches _ NamedItem["data", 2, "0"]; NewLine[]; [] _ Label["stack: "]; stkX _ wx; handle.cmd.stk[0] _ Value[NIL, 10]; lclblX _ wx; [] _ Label["locals: "]; lclX _wx; handle.cmd.lcl[0] _ Value[NIL, 8]; tagX _ wx; [] _ Label["pc: "]; valX _ wx; handle.cmd.pc _ Value[NIL, 8]; nameX _ wx; handle.modelCache _ Bool["cache", TRUE]; Cmd["reset", ResetCache]; Cmd["print", PrintCache]; NewLine[]; handle.show2Above _ Bool["+2", FALSE]; At[x: lclblX]; [] _ Label["spc"]; At[x: tagX]; [] _ Label["lf:"]; At[x: valX]; handle.cmd.lf _ Value[NIL, 8]; handle.cmd.lfName _ Value[NIL, 20]; Containers.ChildXBound[handle.outer, handle.cmd.lfName]; NewLine[]; handle.flushOnCall _ Bool["flsh", FALSE]; At[x: lclblX]; [] _ Label["ret"]; At[x: tagX]; [] _ Label["gf:"]; At[x: valX]; handle.cmd.gf _ Value[NIL, 8]; At[x: nameX]; handle.cmd.gfName _ Value[NIL, 20]; Containers.ChildXBound[handle.outer, handle.cmd.gfName]; NewLine[]; handle.lru _ Bool["lru", FALSE]; At[x: tagX]; [] _ Label["op:"]; At[x: valX]; handle.cmd.nextOp _ Value[NIL, 20]; Containers.ChildXBound[handle.outer, handle.cmd.nextOp]; NewLine[]; At[x: tagX]; Cmd["init", SetCommandLine]; handle.cmd.commandLine _ NamedItem["cmd", 20]; Containers.ChildXBound[handle.outer, handle.cmd.commandLine]; NewLine[]; At[x: tagX]; [] _ Label["Interpreted gfi's -"]; Cmd["clear", ClearGfiTable]; Cmd["print", PrintGfiTable]; NewLine[]; At[x: tagX]; Cmd["mark", MarkGfiInTable]; handle.cmd.gfiRange _ NamedItem["numbers", 20]; Containers.ChildXBound[handle.outer, handle.cmd.gfiRange]; NewLine[]; At[x: tagX]; handle.cmd.breakGF _ NamedItem["breakGF", 8, "0"]; trX _ wx; handle.traceOps _ Bool["tr", FALSE]; opsX _ wx; handle.countOps _ Bool["ops", FALSE]; xfrX _ wx; handle.recordXfers _ Bool["xfr", FALSE]; NewLine[]; At[x: tagX]; handle.cmd.breakPC _ NamedItem["breakPC", 8, "0"]; At[x: trX]; Cmd["tr", DumpTrace]; At[x: opsX]; Cmd["ops", DumpCounts]; At[x: xfrX]; Cmd["xfr", DumpXferData]; NewLine[]; At[x: tagX]; Cmd["showGfi", ShowGfiRange]; handle.cmd.configName _ NamedItem["of", 20]; Containers.ChildXBound[handle.outer, handle.cmd.configName]; NewLine[]; At[row: 5, x: lclblX]; [] _ Label["L0"]; FOR i: CARDINAL IN [1..PrincOps.stackDepth) DO At[row: i+1, x: stkX]; handle.cmd.stk[i] _ Value[NIL, 9]; At[x: lclX]; handle.cmd.lcl[i] _ Value[NIL, 8]; ENDLOOP; NewLine[]; END; Prompt: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN ph: PromptHandle _ NARROW[clientData]; SELECT mouseButton FROM blue, red => NULL; yellow => { r: ROPE = ViewerTools.GetSelectionContents[]; IF ph.number THEN [] _ Convert.IntFromRope[r ! Convert.Error => GO TO dont]; ViewerTools.SetContents[ph.viewer, r] EXITS dont => NULL; }; ENDCASE; ViewerTools.SetSelection[ph.viewer]; -- force the selection END; ToggleBool: Buttons.ButtonProc = TRUSTED { br: REF BoolRec _ NARROW [clientData]; switch: REF BOOL _ br.flag; switch^ _ ~switch^; Buttons.SetDisplayStyle[ button: NARROW[parent], style: IF switch^ THEN $WhiteOnBlack ELSE $BlackOnWhite]; UpdateDisplay[br.handle]; }; SetCommandLine: Buttons.ButtonProc = TRUSTED { h: Handle _ NARROW [clientData]; commandToolGfi: CARDINAL; gf: PrincOps.GlobalFrameHandle; gf _ PrincOpsUtils.GlobalFrame[CommandTool.DoCommand]; commandToolGfi _ gf.gfi; h.tsOut.PutText["Initializing to run command tool\n"]; Init[h, LOOPHOLE[CallCommandTool]]; -- we're going to push parameters RESInterpreter.Push2[h.m, LOOPHOLE[h]]; MarkInteresting[h.m, commandToolGfi]; UpdateDisplay[h]}; CallCommandTool: PROC [h: Handle] = { line: ROPE _ ViewerTools.GetContents[h.cmd.commandLine]; IF line = NIL OR Rope.Length[line] = 0 THEN RETURN; [] _ CommandTool.DoCommand[line, h.parent]}; GfiRange: PROC [gfi: PrincOps.GFTIndex] RETURNS [first, last: PrincOps.GFTIndex] = TRUSTED { gfItem: PrincOps.GFTItem _ PrincOps.GFT[gfi]; gf: PrincOps.GlobalFrameHandle; code: PrincOps.FrameCodeBase; cb: LONG POINTER TO PrincOps.CSegPrefix; gfItem.epbias _ 0; gf _ gfItem.framePtr; IF gf = NIL THEN RETURN [gfi, gfi]; first _ gf.gfi; code _ gf.code; code.out _ FALSE; cb _ code.longbase; last _ first + cb.header.info.ngfi - 1}; ShowGfiRange: Buttons.ButtonProc = TRUSTED { h: Handle _ NARROW [clientData]; wc, cc: AMModel.Context; NoteMod: PROC [cx: AMModel.Context] RETURNS[stop: BOOL _ FALSE] = TRUSTED { SELECT AMModel.ContextClass[cx] FROM model => [] _ AMModel.ContextChildren[cx, NoteMod]; prog => { tx: TV = AMModelBridge.FrameFromContext[cx]; gf: PrincOps.GlobalFrameHandle = AMBridge.GFHFromTV[tx]; first, last: CARDINAL; [first, last] _ GfiRange[gf.gfi]; min _ MIN[min, first]; max _ MAX[max, last]}; ENDCASE; }; min: CARDINAL _ CARDINAL.LAST; max: CARDINAL _ CARDINAL.FIRST; config: ROPE _ ViewerTools.GetContents[h.cmd.configName]; wc _ AMModel.RootContext[WorldVM.LocalWorld[]]; IF config = NIL THEN RETURN; h.tsOut.PutRope[config]; cc _ AMModel.MostRecentNamedContext[config, wc]; IF cc = NIL THEN {h.tsOut.PutText[" not found\n"]; RETURN}; [] _ NoteMod[cc]; h.tsOut.PutF[" has minGfi: %g, and maxGfi: %g\n", IO.card[min], IO.card[max]]; }; StopIt: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data handle.m.singleStep _ TRUE; END; RunProc: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data RunInContext: SAFE PROC = TRUSTED {RESInterpreter.Execute[handle.m]}; IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; FinishedExecution => {Finalize[handle]; GO TO done}; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; GetParamValues[handle]; handle.m.singleStep _ FALSE; NotifyRunning[handle]; handle.m.startOps _ handle.m.iCount; handle.m.startPulses _ BasicTime.GetClockPulses[]; ProcessProps.AddPropList[handle.workingDir, RunInContext]; PrintSpeed[handle]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; PrintSpeed: PROC [h: Handle] = { et: REAL; et _ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[] - h.m.startPulses]; IO.PutF[h.tsOut, "executed %g instr in %g secs (%g/sec)\n", [cardinal[h.m.iCount - h.m.startOps]], [real[et]], [real[(h.m.iCount - h.m.startOps)/et]]]}; NotifyRunning: ENTRY PROC [h: Handle] = {NOTIFY h.running}; StepProc: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data RunInContext: SAFE PROC = TRUSTED {RESInterpreter.Execute[handle.m]}; IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; FinishedExecution => {Finalize[handle]; GO TO done}; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; GetParamValues[handle]; handle.m.singleStep _ TRUE; ProcessProps.AddPropList[handle.workingDir, RunInContext]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; ViewerValue: PROC [v: ViewerClasses.Viewer, default: INT] RETURNS [n: INT] = { n _ Convert.IntFromRope[ViewerTools.GetContents[v] ! SafeStorage.NarrowFault => {n _ default; GO TO gub}; Convert.Error => { MessageWindow.Append[message: "invalid number", clearFirst: TRUE]; n _ default; GO TO gub}; ]; EXITS gub => NULL; }; GetParamValues: PROC [h: Handle] = { gfc: CARDINAL; lines, quads, instr, data: INT; h.m.breakPC _ ViewerValue[h.cmd.breakPC, 0]; gfc _ ViewerValue[h.cmd.breakGF, 0]; h.m.breakGF _ LOOPHOLE[gfc]; h.m.countOps _ h.countOps^; h.m.traceOps _ h.traceOps^; h.m.flushOnCall _ h.flushOnCall^; h.m.recordXferOut _ h.recordXfers^; lines _ ViewerValue[h.cmd.cacheLines, 100]; quads _ ViewerValue[h.cmd.cacheQuads, 2]; instr _ ViewerValue[h.cmd.instCaches, 2]; data _ ViewerValue[h.cmd.dataCaches, 2]; RESInterpreter.EnableCacheModel[m: h.m, state: h.modelCache^, instr: instr, data: data, lines: lines, quads: quads, lru: h.lru^]}; PrintGfiTable: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN h: Handle _ NARROW[clientData]; -- get our data igft: REF RESInterpreter.BitVector; os: IO.STREAM; inRun, multiple: BOOL; first: BOOL _ TRUE; IF ~EnterTool[h] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[h]; ABORTED => {h.tsOut.PutText[" aborted"]; GO TO done}}; igft _ h.m.interestingGfi; os _ h.tsOut; h.m.singleStep _ FALSE; -- so STOP button will stop printout inRun _ multiple _ FALSE; os.PutRope["\nInteresting gfi's: "]; FOR i: CARDINAL IN [1..PrincOps.GFTIndex.LAST+1] WHILE ~h.m.singleStep DO IF i <= PrincOps.GFTIndex.LAST AND igft[i] THEN IF inRun THEN multiple _ TRUE ELSE { IF first THEN first _ FALSE ELSE os.PutRope[", "]; os.PutF["%g", [cardinal[i]]]; inRun _ TRUE; multiple _ FALSE} ELSE { IF multiple THEN os.PutF["-%g", [cardinal[i-1]]]; inRun _ multiple _ FALSE}; ENDLOOP; os.PutRope["\n~~~~~~~~~~~~~~~\n"]; ExitTool[h]; EXITS done => ExitTool[h]; END; END; ClearGfiTable: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; handle.m.interestingGfi^ _ ALL[FALSE]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; MarkGfiInTable: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN h: Handle _ NARROW[clientData]; -- get our data rangeRope, token: ROPE; gs: IO.STREAM; sepr: ROPE _ "Marking Gfis:"; NumberScan: IO.BreakProc = TRUSTED { RETURN [ SELECT char FROM IN ['0..'9] => other, ',, '- => break, ENDCASE => sepr]}; number, lower, upper: CARDINAL; IF ~EnterTool[h] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[h]; ABORTED => {h.tsOut.PutText[" aborted"]; GO TO done}}; rangeRope _ ViewerTools.GetContents[h.cmd.gfiRange]; gs _ IO.RIS[rangeRope]; DO token _ IO.GetTokenRope[gs, NumberScan !IO.EndOfStream => EXIT].token; number _ Convert.IntFromRope[token ! SafeStorage.NarrowFault, Convert.Error => { MessageWindow.Append[message: "invalid number", clearFirst: TRUE]; EXIT}]; BEGIN -- find separator token _ IO.GetTokenRope[gs, NumberScan !IO.EndOfStream => GO TO single].token; SELECT Rope.Fetch[token, 0] FROM ', => GO TO single; '- => { [lower, ] _ GfiRange[number]; token _ IO.GetTokenRope[gs, NumberScan !IO.EndOfStream => EXIT].token; number _ Convert.IntFromRope[token ! SafeStorage.NarrowFault, Convert.Error => { MessageWindow.Append[message: "invalid number", clearFirst: TRUE]; EXIT}]; [, upper] _ GfiRange[number]; BEGIN -- eat comma token _ IO.GetTokenRope[gs, NumberScan !IO.EndOfStream => GO TO ok].token; IF Rope.Fetch[token, 0] # ', THEN { MessageWindow.Append[message: "missing comma", clearFirst: TRUE]; EXIT}; EXITS ok => NULL; END; }; ENDCASE => { MessageWindow.Append[message: "bad syntax", clearFirst: TRUE]; EXIT}; EXITS single => [lower, upper] _ GfiRange[number]; END; h.tsOut.PutF["%g %g", [rope[sepr]], [integer[lower]]]; sepr _ ","; IF upper # lower THEN h.tsOut.PutF["-%g", [integer[upper]]]; IF upper > PrincOps.GFTIndex.LAST THEN { MessageWindow.Append[message: "out of range", clearFirst: TRUE]; ExitTool[h]; RETURN}; FOR i: CARDINAL IN [lower..upper] DO h.m.interestingGfi[i] _ TRUE; ENDLOOP; ENDLOOP; h.tsOut.PutChar['\n]; ExitTool[h]; EXITS done => ExitTool[h]; END; END; ZeroProc: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; handle.m.iCount _ 0; SetValue[handle.cmd.iCount, "0"]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; ResetCache: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data lines, quads, instr, data: INT; IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; lines _ ViewerValue[handle.cmd.cacheLines, 100]; quads _ ViewerValue[handle.cmd.cacheQuads, 2]; instr _ ViewerValue[handle.cmd.instCaches, 2]; data _ ViewerValue[handle.cmd.dataCaches, 2]; RESInterpreter.ResetCacheModel[m: handle.m, instr: instr, data: data, lines: lines, quads: quads, lru: handle.lru^]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; PrintCache: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data IF ~EnterTool[handle] THEN RETURN; BEGIN ENABLE { UNWIND => ExitTool[handle]; ABORTED => {handle.tsOut.PutText[" aborted"]; GO TO done}}; RESInterpreter.PrintCacheStats[handle.tsOut, handle.m]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; EnterTool: ENTRY PROC [h: Handle] RETURNS [BOOL] = { IF h.busy THEN { MessageWindow.Append[message: "Already running", clearFirst: TRUE]; RETURN[FALSE]}; IF h.m = NIL THEN { MessageWindow.Append[message: "Please initialize", clearFirst: TRUE]; RETURN[FALSE]}; h.busy _ TRUE; RETURN[TRUE]; }; ExitTool: ENTRY PROC [h: Handle] = {UpdateDisplay[h]; h.busy _ FALSE}; Finalize: ENTRY PROC [h: Handle] = { FinalizeInternal[h]; }; FinalizeInternal: INTERNAL PROC [h: Handle] = { h.ready _ FALSE; PrintSpeed[h]; h.killCountProcess _ TRUE; NOTIFY h.running; }; Initialize: PUBLIC PROC [handle: REF ANY, topProc: PROC] = { h: Handle = NARROW[handle]; Init[h, topProc]}; Init: ENTRY PROC [h: Handle, topProc: PROC] = TRUSTED { link: PrincOps.ControlLink = LOOPHOLE[topProc]; IF h.busy THEN { MessageWindow.Append[message: "Stop before reinitializing", clearFirst: TRUE]; RETURN}; IF h.ready THEN FinalizeInternal[h]; IF h.m = NIL THEN h.m _ NEW[RESInterpreter.MachineStateRec _ [ history: NEW [RESInterpreter.OpHistoryRec], opCount: NEW [ARRAY Byte OF INT], interestingGfi: NEW [RESInterpreter.BitVector _ ALL[FALSE]]]] ELSE { oldHistory: RESInterpreter.OpHistory _ h.m.history; oldCounts: REF ARRAY Byte OF INT _ h.m.opCount; oldGfi: REF RESInterpreter.BitVector _ h.m.interestingGfi; h.m^ _ [history: oldHistory, opCount: oldCounts, interestingGfi: oldGfi]}; -- set to default values h.m.opCount^ _ ALL[0]; h.m.history.head _ h.m.history.tail _ 0; MarkInteresting[h.m, link.gfi]; RESInterpreter.Xfer[ m: h.m, dst: link, src: RESInterpreter.MagicReturn, push: FALSE]; h.ready _ TRUE; h.busy _ FALSE; UpdateDisplay[h]; h.killCountProcess _ FALSE; Process.Detach[FORK ShowCount[h]]; }; MarkInteresting: PROC [m: Machine, gfi: PrincOps.GFTIndex] = { first, last: CARDINAL; [first, last] _ GfiRange[gfi]; FOR i: CARDINAL IN [first..last] DO m.interestingGfi[i] _ TRUE; ENDLOOP; }; ShowCount: ENTRY PROC [h: Handle] = { m: Machine = h.m; IF m = NIL THEN RETURN; TRUSTED {Process.InitializeCondition[@h.pauseTime, Process.MsecToTicks[1000]]}; WHILE ~h.killCountProcess DO WHILE (~h.busy OR h.m.singleStep) DO WAIT h.running; IF h.killCountProcess THEN RETURN; ENDLOOP; WAIT h.pauseTime; SetValue[h.cmd.iCount, Convert.RopeFromInt[m.iCount]]; ENDLOOP; }; UpdateDisplay: PROC [handle: Handle] = { m: Machine = handle.m; IF m = NIL THEN RETURN; SetValue[handle.cmd.iCount, Convert.RopeFromInt[m.iCount]]; SetValue[handle.cmd.pc, Convert.RopeFromInt[m.pc, 8]]; DisplayStack[handle]; SetValue[handle.cmd.lf, Convert.RopeFromInt[LOOPHOLE[m.l, CARDINAL], 8]]; DisplayLfName[handle]; SetValue[handle.cmd.gf, Convert.RopeFromInt[LOOPHOLE[m.g, CARDINAL], 8]]; DisplayGfName[handle]; DisplayLocals[handle]; DisplayNextOp[handle]; }; DisplayLfName: PROC [handle: Handle] = TRUSTED { m: Machine = handle.m; name: ROPE; BEGIN ENABLE AMTypes.Error, SafeStorage.NarrowFault => GO TO forgetIt; ftv: TV _ AMBridge.TVForFrame[fh: LOOPHOLE[m.l]]; ptv: TV _ AMTypes.Procedure[ftv]; name _ AMTypes.TVToName[ptv]; EXITS forgetIt => name _ NIL; END; SetValue[handle.cmd.lfName, name]}; DisplayGfName: PROC [handle: Handle] = TRUSTED { m: Machine = handle.m; name: ROPE; BEGIN ENABLE AMTypes.Error, SafeStorage.NarrowFault => GO TO forgetIt; ftv: TV _ AMBridge.TVForGFHReferent[LOOPHOLE[m.g]]; name _ AMTypes.TVToName[ftv]; EXITS forgetIt => name _ NIL; END; SetValue[handle.cmd.gfName, name]}; DisplayStack: PROC [handle: Handle] = { m: Machine = handle.m; i: CARDINAL; FOR i _ 0, i+1 WHILE i < PrincOps.stackDepth AND i < m.sd DO l: ViewerClasses.Viewer = handle.cmd.stk[i]; SetValue[l, Convert.RopeFromInt[m.stack[i], 8]]; ENDLOOP; IF handle.show2Above^ THEN WHILE i < MIN[m.sd+2, PrincOps.stackDepth] DO l: ViewerClasses.Viewer = handle.cmd.stk[i]; SetValue[l, Rope.Cat["<", Convert.RopeFromInt[m.stack[i], 8], ">"]]; i _ i + 1; ENDLOOP; WHILE i < PrincOps.stackDepth DO l: ViewerClasses.Viewer = handle.cmd.stk[i]; SetValue[l, NIL]; i _ i + 1; ENDLOOP; }; DisplayLocals: PROC [handle: Handle] = TRUSTED { m: Machine = handle.m; maxShown: CARDINAL = PrincOps.stackDepth; lSize: CARDINAL; i: CARDINAL; fsi: CARDINAL; local: POINTER TO ARRAY [0..maxShown) OF CARDINAL = LOOPHOLE[m.l]; IF local = NIL OR (LOOPHOLE[local, CARDINAL] MOD 4 # 0) THEN RETURN; fsi _ LOOPHOLE[local-1, POINTER TO CARDINAL]^; lSize _ IF fsi IN PrincOps.FrameSizeIndex THEN PrincOps.FrameVec[fsi] ELSE 0; FOR i _ 0, i+1 WHILE i < maxShown AND i < lSize DO l: Labels.Label = handle.cmd.lcl[i]; SetValue[l, Convert.RopeFromInt[local[i], 8]]; ENDLOOP; WHILE i < maxShown DO l: Labels.Label = handle.cmd.lcl[i]; SetValue[l, NIL]; i _ i + 1; ENDLOOP; }; JumpOp: TYPE = [PrincOps.zJ2..PrincOps.zJIW]; DisplayNextOp: PROC [handle: Handle] = TRUSTED { m: Machine = handle.m; opData: ListerUtils.OpCodeArray _ OpDebug.OpData[]; cb: LONG POINTER TO PACKED ARRAY [0..0) OF Byte = m.cb; op: ARRAY [0..3) OF Byte _ [cb[m.pc], 0, 0]; IF opData # NIL THEN SELECT opData[op[0]].length FROM 2 => op[1] _ cb[m.pc+1]; 3 => {op[2] _ cb[m.pc+2]; op[1] _ cb[m.pc+1]}; ENDCASE; SetValue[handle.cmd.nextOp, OpDebug.RopeForOperation[op, m.pc]]; }; DumpCounts: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN h: Handle _ NARROW[clientData]; -- get our data IF h.m.countOps THEN RESInterpreter.PrintOpCounts[h.tsOut, h.m] ELSE h.tsOut.PutRope["\nOpcodes not being counted\n"]; END; DumpTrace: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN handle: Handle _ NARROW[clientData]; -- get our data PrintHistory[handle.tsOut, handle, TRUE]; UpdateDisplay[handle]; END; DumpXferData: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = TRUSTED BEGIN h: Handle _ NARROW[clientData]; -- get our data IF h.m.recordXferOut THEN RESInterpreter.PrintProcCounts[h.tsOut, h.m] ELSE h.tsOut.PutRope["\nXfers not being counted\n"]; END; PrintHistory: PUBLIC PROC [os: IO.STREAM, h: Handle, modNames: BOOL _ FALSE] = { history: RESInterpreter.OpHistory _ h.m.history; Octal: PROC [n: INT] RETURNS [IO.Value] = { RETURN [[rope[Convert.RopeFromInt[n, 8, n>7]]]]}; ShortOctal: PROC [n: CARDINAL] RETURNS [IO.Value] = { RETURN [[rope[Convert.RopeFromInt[n, 8, n>7]]]]}; PrintItem: PROC [item: RESInterpreter.OpHistoryItem] = TRUSTED { cgf: CARDINAL _ LOOPHOLE[item.gf]; os.PutF["%6g %6g %g", Octal[cgf], Octal[item.pc], [rope[OpDebug.RopeForOperation[item.op, item.pc]]]]; IF item.stkDepth # 0 THEN { os.PutF["\t%g", ShortOctal[item.stk[0]]]; FOR j: CARDINAL IN [1..item.stkDepth) DO os.PutF[", %g", ShortOctal[item.stk[j]]]; ENDLOOP; }; IF modNames THEN { ENABLE AMTypes.Error, SafeStorage.NarrowFault => GO TO forgetIt; ftv: TV _ AMBridge.TVForGFHReferent[item.gf]; name: ROPE _ AMTypes.TVToName[ftv]; os.PutF["\t%g\n", [rope[name]]] EXITS forgetIt => NULL; } ELSE os.PutChar['\n]}; os.PutRope["\n~~~~~~~~~~~~~~~~~~~~~~~~~\n"]; FOR i: CARDINAL _ history.head, (i+1) MOD RESInterpreter.OpHistorySize WHILE i # history.tail DO PrintItem[history.data[i]]; ENDLOOP; RETURN}; Commander.Register[key: "Dragoman", proc: MakeTool, doc: "Run PrincOps code interpretively so that statistics can be taken on memory references" ]; END. @RESIInterface.mesa; Last Edited by: Sweet, March 11, 1985 10:03:59 am PST The Containers interface is used to create an outer envelope or "container" for the different sections below. For uniformity, we define some standard distances between entries in the tool. default the width so that it will be computed for us -- don't use Label, since the text can't be selected. default the width so that it will be computed for us -- default the width so that it will be computed for us -- force the selection into the user input field SetInitialProc: Buttons.ButtonProc = TRUSTED { h: Handle _ NARROW [clientData]; ptv: TV; ptype: AMTypes.Type; noVal: BOOL; cmd, error: ROPE; proc: PROC; IF h.m # NIL THEN GetParamValues[h]; cmd _ ViewerTools.GetContents[h.cmd.initialProc]; IF cmd = NIL THEN { MessageWindow.Append[message: "Enter initial proc name", clearFirst: TRUE]; RETURN}; [result: ptv, errorRope: error, noResult: noVal] _ Interpreter.Evaluate[cmd]; IF error # NIL THEN { MessageWindow.Append[message: "Evaluation problem: ", clearFirst: TRUE]; MessageWindow.Append[message: error, clearFirst: FALSE]; RETURN}; ptype _ AMTypes.TVType[ptv]; IF AMTypes.TypeClass[ptype] # procedure THEN { MessageWindow.Append[message: "Not a procedure", clearFirst: TRUE]; RETURN}; IF AMTypes.Domain[ptype] # SafeStorage.nullType OR AMTypes.Range[ptype] # SafeStorage.nullType THEN { MessageWindow.Append[message: "Must be parameterless", clearFirst: TRUE]; RETURN}; proc _ NARROW[AMBridge.TVToProc[ptv]]; h.tsOut.PutText["Initializing to "]; h.tsOut.PutRope[cmd]; h.tsOut.PutText["\n"]; Init[h, proc]; }; ส(p– "Cedar" style˜Icode– "Cedar" stylešœ™K™5šฯk ˜ K˜ K˜K˜K˜Kšœ˜K˜K˜K˜ Kšœ˜Kšœ ˜ K˜ Kšœ œ/˜?K˜Kšœ˜Kšœ˜K˜K˜K˜ K˜K˜K˜ K˜K˜K˜ K˜Kšœ˜Kšœœ˜K˜ K˜ K˜Kšœœ˜-Kšœ œ˜%Kšœ œ˜,Kšœ œS˜dKšœ˜—š œ œœœœ˜=Kšœsœถ˜ฒKšœ˜—Kš˜Kšœฝ™ฝKšœ œฯc&˜BKšœ œž'˜CKšœ œž+˜GKšœœœ˜Kšœœœœ˜Kšœœ œ˜Kšœœ˜Kšœ œ˜'K˜K˜Kšœ œœ˜(K˜Kšœœœžะckž]˜šœœœž+˜KKšœœž%˜HKšœœž0˜BKšœž˜$Kšœ œœ˜KšœKœœ˜TKšœ œ˜)Kšœ œ˜K˜ Kšœ˜Kšœ˜Kšœ œ˜Kšœž˜.—šœœœ˜Kšœ˜KšœE˜EKšœ˜Kšœ!˜!Kšœ!˜!Kšœ˜Kšœœœ˜Kšœž ˜2Kšœœž4˜CKšœž˜.Kšœ œœž'˜=—Kšœž!˜3KšœP˜PKšœ'˜'Kšœ)ž˜=Kšœ˜Kšœ&ž˜=Kšœ˜—K˜šฯnœœœ˜.Kšœ-ž(˜Ušœ˜KšœMœ˜V—šœ<˜—Kšœ˜—š œœ œ œœœœ˜DK˜Kšœœ ˜Kšœœœ ˜Kšœœ)˜1šœ˜šœ˜Kšœ ˜ K˜Kšœ˜Kšœ7™7Kšœž4˜EKšœ˜Kšœœ˜—Kšœ˜Kšœž(œ˜:—K•StartOfExpansion[]š œ,œ œœœ˜lKšœ˜—K˜K˜0K˜BKšœ/œ˜8Kšœ4˜4K˜1K˜2K˜2K˜K˜K˜ K˜K˜"Kšœœ˜0K˜!Kšœœ˜-K˜Kšœœ˜Kšœ.œ˜5Kšœ3˜3Kšœ ˜ K˜Kšœœ˜&K˜"KšœCœ˜KKšœœ˜#Kšœ8˜8K˜ K˜Kšœ"œ˜)K˜AKšœ#œ˜+Kšœ(œ˜1Kšœ8˜8K˜ K˜Kšœœ˜ KšœGœ˜PKšœ8˜8K˜ K˜K˜)Kšœ.˜.Kšœ=˜=K˜ K˜K˜/K˜9K˜ K˜)Kšœ/˜/Kšœ:˜:K˜ K˜?Kšœ'œ˜.Kšœ)œ˜0Kšœ,œ˜3K˜ K˜K˜K˜?K˜!Kšœ$˜$Kšœ&˜&K˜ K˜K˜K˜*Kšœ,˜,Kšœ<˜Kšœ œ˜K˜Kš œœœœœœ˜HK˜K˜K˜—š  œœœ˜%K˜Kšœœœœ˜KšœH˜Ošœ˜šœ œ˜$Kšœ ˜Kšœœœ˜"Kšœ˜—Kšœ ˜Kšœ6˜6Kšœ˜—K˜—K˜š  œœ˜(K˜Kšœœœœ˜Kšœ;˜;Kšœ6˜6K˜Kšœ,œœ˜IK˜Kšœ,œœ˜IK˜K˜K˜K˜K˜—š  œœœ˜0K˜Kšœœ˜ Kšœœ+œœ ˜FKšœœœ˜1Kšœœ˜!K˜š˜Kšœœ˜—Kšœ˜Kšœ#˜#K˜—š  œœœ˜0K˜Kšœœ˜ Kšœœ+œœ ˜FKšœœœ˜3K˜š˜Kšœœ˜—Kšœ˜Kšœ#˜#K˜—š  œœ˜'K˜Kšœœ˜ šœ œœ ˜