<> <> <<>> DIRECTORY AMBridge, AMModel, AMModelBridge, AMTypes, Ascii, AssociativeCache, Atom, Basics, BasicTime, Buttons, CacheModels, Commander, CommandTool, Containers USING [ChildXBound, ChildYBound, Container, Create], Convert, DirectMapCache, Dragoman, DragomanOpDebug, DragomanPrivate, FS, IO, Labels, List, ListerUtils, MessageWindow, PrincOps, PrincOpsUtils, Process, ProcessProps, Rope, Rules USING [Create, Rule], SafeStorage, TypeScript, VFonts, ViewerClasses USING [Viewer, ViewerClassRec], ViewerIO USING [CreateViewerStreams], ViewerOps USING [PaintViewer], ViewerTools USING [GetContents, GetSelectionContents, MakeNewTextViewer, SetContents, SetSelection], WorldVM; DragomanDebug: CEDAR MONITOR LOCKS h.LOCK USING h: Handle IMPORTS AMBridge, AMModel, AMModelBridge, AMTypes, AssociativeCache, Atom, BasicTime, Buttons, Commander, CommandTool, Containers, Convert, DirectMapCache, DragomanOpDebug, DragomanPrivate, IO, Labels, List, MessageWindow, PrincOpsUtils, Process, ProcessProps, Rope, Rules, SafeStorage, TypeScript, VFonts, ViewerIO, ViewerOps, ViewerTools, WorldVM = 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 = DragomanPrivate.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: REF BOOL, stopFlag, killCountProcess: BOOL _ FALSE, running, pauseTime: CONDITION, m: DragomanPrivate.Machine, workingDir: Atom.PropList, parent: Commander.Handle, rc, mc: CacheModels.Cache, 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]; myCache: DragomanPrivate.CacheInfo; 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]; my.rc _ DirectMapCache.NewCache[lines: 512, quadsPerLine: 8]; -- real cache my.mc _ AssociativeCache.NewCache[lines: 256, quadsPerLine: 4, wordsPerQuad: 1]; -- map cache myCache _ NEW [DragomanPrivate.CacheInfoRec _ [iCaches: 1, dCaches: 1]]; myCache.iCache[0] _ AssociativeCache.NewCache[lines: 100, wordsPerQuad: 4, quadsPerLine: 1, lru: FALSE, realCache: my.rc, mapCache: my.mc]; myCache.dCache[0] _ AssociativeCache.NewCache[lines: 100, wordsPerQuad: 4, quadsPerLine: 1, lru: FALSE, realCache: my.rc, mapCache: my.mc]; my.m _ NEW[DragomanPrivate.MachineStateRec _ [ cacheData: myCache, history: NEW [DragomanPrivate.OpHistoryRec], opCount: NEW [ARRAY Byte OF INT], interestingGfi: NEW [DragomanPrivate.BitVector _ ALL[FALSE]]]]; 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["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[]; 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[LOOPHOLE[CommandTool.DoCommand]]; commandToolGfi _ gf.gfi; h.tsOut.PutText["Initializing to run command tool\n"]; Init[h, LOOPHOLE[CallCommandTool]]; -- we're going to push parameters DragomanPrivate.Push2[h.m, LOOPHOLE[h]]; MarkInteresting[h.m, commandToolGfi]; UpdateDisplay[h]}; <> <> <> <> <> <> <> <> <> <> <> <> <<[result: ptv, errorRope: error, noResult: noVal] _ Interpreter.Evaluate[cmd];>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> CallCommandTool: PROC [handle: Handle] = { parent: Commander.Handle _ NEW[Commander.CommandObject _ [ in: IO.noInputStream, out: handle.tsOut, err: IO.noWhereStream]]; line: ROPE _ ViewerTools.GetContents[handle.cmd.commandLine]; prompt: ROPE _ "%l%% %l"; directory: ROPE _ "///Commands/"; IF Rope.Length[line] = 0 THEN RETURN; parent.propertyList _ List.PutAssoc[ key: $ErrorInputStream, val: IO.noInputStream, aList: parent.propertyList]; parent.propertyList _ List.PutAssoc[ key: $Prompt, val: prompt, aList: parent.propertyList]; parent.propertyList _ List.PutAssoc[ key: $SearchRules, val: LIST[directory], aList: parent.propertyList]; [] _ CommandTool.DoCommand[line, parent]; }; 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}}; DragomanPrivate.PrintCacheStats[handle.tsOut, handle.m]; handle.rc.print[handle.rc, handle.tsOut, "Real cache"]; handle.mc.print[handle.mc, handle.tsOut, "Map cache"]; ExitTool[handle]; EXITS done => ExitTool[handle]; END; END; 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]]; }; 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}; 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 {DragomanPrivate.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 {DragomanPrivate.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; <> 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^; DragomanPrivate.EnableCaches[m: h.m, state: h.modelCache^]; h.m.flushOnCall _ h.flushOnCall^; h.m.recordXferOut _ h.recordXfers^}; 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 DragomanPrivate.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; MarkGfiByNumber: 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; MarkGFIByName: PROC [handle: Handle, name: ROPE] = { 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: AMTypes.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; TRUSTED {wc _ AMModel.RootContext[WorldVM.LocalWorld[]]}; IF name = NIL THEN RETURN; TRUSTED {cc _ AMModel.MostRecentNamedContext[name, wc]}; IF cc = NIL THEN {Output[handle, "*** MarkGFI: ", name, " not found\n"]; RETURN}; [] _ NoteMod[cc]; Output[handle, "MarkGFI: ", name, " gfi's are marked (", Convert.RopeFromInt[min], "-", Convert.RopeFromInt[max], ")\n"]; FOR i: CARDINAL IN [min..max] DO handle.m.interestingGfi[i] _ TRUE; ENDLOOP; }; 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; 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]; ResetMachine[h.m]; h.m.opCount^ _ ALL[0]; h.m.history.head _ h.m.history.tail _ 0; MarkInteresting[h.m, link.gfi]; DragomanPrivate.Xfer[ m: h.m, dst: link, src: DragomanPrivate.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; }; ResetMachine: PROC [m: Machine] = { m.sd _ 0; m.stack _ ALL[[0]]; m.l _ NIL; m.g _ NIL; m.cb _ NIL; m.pc _ 0; m.iCount _ 0; m.outCalls _ 0; m.singleStep _ FALSE; m.breakGF _ NIL; m.breakPC _ 0; m.traceOps _ FALSE; m.recordXferOut _ FALSE; m.xferData _ NIL; m.countOps _ FALSE; m.flushOnCall _ FALSE; m.startPulses _ 0; m.startOps _ 0}; 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:"; TokenScan: IO.BreakProc = TRUSTED { RETURN [ SELECT char FROM IN ['0..'9], IN ['A..'Z], IN ['a..'z] => 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, TokenScan !IO.EndOfStream => EXIT].token; SELECT Rope.Fetch[token, 0] FROM IN ['0..'9] => number _ Convert.IntFromRope[token ! SafeStorage.NarrowFault, Convert.Error => { MessageWindow.Append[message: "invalid number", clearFirst: TRUE]; EXIT}]; IN ['A..'Z], IN ['a..'z] => { MarkGFIByName[h, token]; token _ IO.GetTokenRope[gs, TokenScan !IO.EndOfStream => EXIT].token; IF Rope.Fetch[token, 0] # ', THEN { MessageWindow.Append[message: "bad syntax", clearFirst: TRUE]; EXIT}; LOOP}; ENDCASE; BEGIN -- find separator token _ IO.GetTokenRope[gs, TokenScan !IO.EndOfStream => GO TO single].token; SELECT Rope.Fetch[token, 0] FROM ', => GO TO single; '- => { [lower, ] _ GfiRange[number]; token _ IO.GetTokenRope[gs, TokenScan !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, TokenScan !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; 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 _ DragomanOpDebug.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, DragomanOpDebug.RopeForOperation[op, m.pc]]; }; Output: PUBLIC PROC [handle: Handle, r1, r2, r3, r4, r5, r6, r7, r8: ROPE _ NIL] = { PR: PROC [r: ROPE] = INLINE {IF r # NIL THEN IO.PutRope[handle.tsOut, r]}; PR[r1]; PR[r2]; PR[r3]; PR[r4]; PR[r5]; PR[r6]; PR[r7]; PR[r8]}; 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 DragomanPrivate.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 DragomanPrivate.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] = { history: DragomanPrivate.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: DragomanPrivate.OpHistoryItem] = TRUSTED { cgf: CARDINAL _ LOOPHOLE[item.gf]; os.PutF["%6g %6g %g", Octal[cgf], Octal[item.pc], [rope[DragomanOpDebug.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: AMTypes.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 DragomanPrivate.OpHistorySize WHILE i # history.tail DO PrintItem[history.data[i]]; ENDLOOP; RETURN}; Commander.Register[key: "DragomanDebug", proc: MakeTool, doc: "Create a window interface for Dragoman" ]; END.