<> <> <> <> <> DIRECTORY BasicTime USING [GetClockPulses, Now, Pulses, PulsesToSeconds], Buttons USING [Button, Create, ReLabel, SetDisplayStyle], Containers USING [ChildXBound, ChildYBound, Create], Convert USING [Base, CardFromDecimalLiteral, CardFromHexLiteral, CardFromOctalLiteral, Error, IntFromRope], DragOpsCross USING [Byte, FourBytes, IFUStatusRec, Inst, OnesWord, ProcessorRegister, Word, ZerosWord], DragOpsCrossUtils USING [AddDelta, BytePCToWordAddress, IntToWord, WordToCard, WordToInt], HandCodingSupport USING [Area, GetCurrentArea], HandCodingUtil USING [GetInstArray, GetRegArray, NameArray, RegNameArray, ToStream], InputFocus USING [], IO USING [Close, EndOfStream, Error, GetCedarTokenRope, GetIndex, int, PutF, PutFR, PutRope, RIS, RopeFromROS, rope, ROS, STREAM, TokenKind], IOUtils USING [CopyPFProcs, PFCodeProc, PFProcs, SetPFCodeProc, SetPFProcs], Labels USING [Create, Label, Set], LizardCache USING [CacheBase, FlushCache, NewBase, NewCache, SharedBase], LizardHeart USING [ChangeLogger, ChangeLoggerRep, Control, InstDoneProc, InstructionExecute, InstStartProc, IOChangeProc, MemChangeProc, NewProcessor, OutsideEnvelope, Processor, ProcessorStats, RegChangeProc], LizardToolOutput, Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], MessageWindow USING [Append, Blink], NumberLabels USING [CreateNumber, NumberLabel, NumberLabelUpdate], Process USING [Detach, MsecToTicks, priorityBackground, SetPriority, SetTimeout], Real USING [RoundLI], Rope USING [Equal, Fetch, ROPE], SparseMemory USING [Base, Fetch], TypeScript USING [ChangeLooks, Create], VFonts USING [], ViewerClasses USING [Viewer], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, OpenIcon], ViewerTools USING [GetContents, GetSelectionContents, SetContents], VTables USING [Create, Install, SetRowsAndColumns, SetTableEntry, VTable], WriteSparseMemory USING [TestAbort, ToStream]; LizardToolDriver: CEDAR MONITOR LOCKS data USING data: ToolData IMPORTS BasicTime, Buttons, Containers, Convert, DragOpsCrossUtils, HandCodingSupport, IO, IOUtils, Labels, LizardCache, LizardHeart, LizardToolOutput, HandCodingUtil, Menus, MessageWindow, NumberLabels, Process, Real, Rope, SparseMemory, TypeScript, ViewerIO, ViewerOps, ViewerTools, VTables, WriteSparseMemory = BEGIN Area: TYPE = HandCodingSupport.Area; Base: TYPE = SparseMemory.Base; Button: TYPE = Buttons.Button; Byte: TYPE = DragOpsCross.Byte; ChangeLogger: TYPE = LizardHeart.ChangeLogger; ChangeLoggerRep: TYPE = LizardHeart.ChangeLoggerRep; Control: TYPE = LizardHeart.Control; Inst: TYPE = DragOpsCross.Inst; Label: TYPE = Labels.Label; NumberLabel: TYPE = NumberLabels.NumberLabel; Processor: TYPE = LizardHeart.Processor; ProcessorRegister: TYPE = DragOpsCross.ProcessorRegister; ProcessorStats: TYPE = LizardHeart.ProcessorStats; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; TestAbort: TYPE = WriteSparseMemory.TestAbort; Viewer: TYPE = ViewerClasses.Viewer; VTable: TYPE = VTables.VTable; Word: TYPE = DragOpsCross.Word; ZerosWord: Word = DragOpsCross.ZerosWord; OnesWord: Word = DragOpsCross.OnesWord; ToolData: TYPE = REF ToolDataRep; ToolDataRep: TYPE = MONITORED RECORD [ refreshMillis: CARDINAL _ 1000, processors: ProcessorSequence _ NIL, area: Area _ NIL, logger: ChangeLogger _ NIL, logTS: Viewer _ NIL, log: STREAM _ NIL, traceButton, baseButton: Buttons.Button _ NIL, vTab: VTable _ NIL, pauseCondText: Viewer _ NIL, pauseCondTable: PauseCondTable _ NIL, statusLabel: Label _ NIL, refresh: CONDITION, controlChange: CONDITION, internalControl: InternalControl _ pause, initPulses: BasicTime.Pulses _ BasicTime.GetClockPulses[], dumpStart: INT _ 0, dumpWords: INT _ LAST[INT], live: BOOL _ FALSE, requestReset, requestReschedule: BOOL _ FALSE, requestDump: DumpRequest _ none, requestBiasStats: BOOL _ FALSE, stopPrint: BOOL _ FALSE, tracing: BOOL _ FALSE, useHex: BOOL _ TRUE, -- will be inverted at setup time to Octal instTable: InstCountTable _ NIL, lastInstTable: LastInstTable _ NIL, newStats, baseStats: ToolStats _ [], biasStats: LizardToolOutput.StatSnapshot ]; ToolStats: TYPE = RECORD [ samplePulses: BasicTime.Pulses _ 0, pStats: ProcessorStats _ [] ]; ProcessorSequence: TYPE = REF ProcessorSequenceRep; ProcessorSequenceRep: TYPE = RECORD [ SEQUENCE num: NAT OF Processor ]; InternalControl: TYPE = {run, step, pause, stop}; DumpRequest: TYPE = {none, words, bytes, regs, stats, ring}; PauseCondTable: TYPE = REF PauseCondTableRep; PauseCondTableRep: TYPE = RECORD [ instArray: PACKED ARRAY Inst OF BOOL _ ALL[FALSE], pcRanges: LIST OF PCRange _ NIL, instCountStop: LIST OF INT _ NIL ]; InstCountTable: TYPE = REF InstCountTableRep; InstCountTableRep: TYPE = LizardToolOutput.InstCountTableRep; PCRange: TYPE = RECORD [firstPC,lastPC: LONG CARDINAL]; LastInstTable: TYPE = REF LastInstTableRep; LastInstTableRep: TYPE = LizardToolOutput.LastInstTableRep; LastInstMod: NAT = LizardToolOutput.LastInstMod; instCacheLines: NAT _ 64; dataCacheLines: NAT _ 64; <> SampleStats: ENTRY PROC [data: ToolData] RETURNS [ToolStats] = { RETURN [data.newStats]; }; UpdateStats: ENTRY PROC [data: ToolData, stats: ToolStats, updateTime: BOOL _ TRUE] = { IF updateTime THEN stats.samplePulses _ BasicTime.GetClockPulses[]; data.newStats _ stats; }; SetBaseState: ENTRY PROC [data: ToolData] = { data.baseStats _ data.newStats; data.baseStats.samplePulses _ BasicTime.GetClockPulses[]; }; GetDeltaFromBase: ENTRY PROC [data: ToolData] RETURNS [stats: ToolStats] = { stats.pStats.instructions _ data.newStats.pStats.instructions - data.baseStats.pStats.instructions; stats.pStats.cycles _ data.newStats.pStats.cycles - data.baseStats.pStats.cycles; stats.pStats.euFetches _ data.newStats.pStats.euFetches - data.baseStats.pStats.euFetches; stats.pStats.euStores _ data.newStats.pStats.euStores - data.baseStats.pStats.euStores; stats.pStats.instBytes _ data.newStats.pStats.instBytes - data.baseStats.pStats.instBytes; stats.samplePulses _ data.newStats.samplePulses - data.baseStats.samplePulses; }; Start: ENTRY PROC [data: ToolData] = { data.newStats _ [samplePulses: BasicTime.GetClockPulses[]]; data.live _ TRUE; BROADCAST data.refresh; }; Stop: ENTRY PROC [data: ToolData] = { <> vTab: VTables.VTable _ data.vTab; IF vTab # NIL THEN {data.vTab _ NIL; VTables.SetRowsAndColumns[vTab, 0, 0]}; IF data.log # NIL THEN { IO.Close[data.log ! IO.Error => CONTINUE]; data.log _ NIL; data.logTS _ NIL}; data.processors _ NIL; data.vTab _ NIL; data.pauseCondText _ NIL; data.pauseCondTable _ NIL; data.traceButton _ NIL; data.baseButton _ NIL; data.statusLabel _ NIL; data.live _ FALSE; data.instTable _ NIL; }; SetInternalControl: ENTRY PROC [data: ToolData, internalControl: InternalControl] = TRUSTED { data.internalControl _ internalControl; BROADCAST data.controlChange; }; WaitForControlChange: ENTRY PROC [data: ToolData] RETURNS [InternalControl] = TRUSTED { Process.SetTimeout[@data.controlChange, Process.MsecToTicks[data.refreshMillis]]; WAIT data.controlChange; RETURN [data.internalControl]; }; WaitForRefresh: ENTRY PROC [data: ToolData] = TRUSTED { Process.SetTimeout[@data.refresh, Process.MsecToTicks[data.refreshMillis]]; WAIT data.refresh; }; CauseRefresh: ENTRY PROC [data: ToolData] = TRUSTED { BROADCAST data.refresh; }; InvertTracing: ENTRY PROC [data: ToolData] = TRUSTED { data.tracing _ NOT data.tracing; Buttons.SetDisplayStyle[data.traceButton, IF data.tracing THEN $WhiteOnBlack ELSE $BlackOnWhite]; BROADCAST data.refresh; BROADCAST data.controlChange; }; InvertOutputBase: ENTRY PROC [data: ToolData] = TRUSTED { useHex: BOOL _ data.useHex _ NOT data.useHex; SetOutputBaseW[data.log, useHex]; Buttons.ReLabel[data.baseButton, IF useHex THEN " Hex " ELSE "Octal"]; BROADCAST data.refresh; BROADCAST data.controlChange; }; SetOutputBaseW: PROC [st: STREAM, useHex: BOOL] = TRUSTED { pfProcs: IOUtils.PFProcs = IOUtils.CopyPFProcs[st]; [] _ IOUtils.SetPFCodeProc[ pfProcs, 'w, IF useHex THEN CodeWHexProc ELSE CodeWOctalProc]; [] _ IOUtils.SetPFProcs[st, pfProcs]; }; CodeWHexProc: IOUtils.PFCodeProc = { IO.PutF[stream, "%xH", val]; }; CodeWOctalProc: IOUtils.PFCodeProc = { IO.PutF[stream, "%bB", val]; }; <> StopMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> SetInternalControl[NARROW[clientData], stop]; }; PauseMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> SetInternalControl[NARROW[clientData], pause]; }; RunMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; IF shift AND td.tracing THEN InvertTracing[td]; SetInternalControl[td, run]; }; StepMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> SetInternalControl[NARROW[clientData], step]; }; ResetMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestReset _ TRUE; }; ReschedMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestReschedule _ TRUE; }; StopPrintMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.stopPrint _ TRUE; }; DumpMemMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; IF shift THEN td.requestDump _ bytes ELSE td.requestDump _ words; }; DumpRegsMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestDump _ regs; }; DumpStatsMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestDump _ stats; }; DumpRingMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestDump _ ring; }; BiasStatsMenuProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; td.requestBiasStats _ TRUE; }; SamplePauseCondProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> ShowPauseCond[NARROW[clientData]] }; SetPauseCondProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> td: ToolData = NARROW[clientData]; newPauseData: PauseCondTable _ NEW[PauseCondTableRep _ []]; oldPauseData: PauseCondTable = td.pauseCondTable; st: STREAM = IO.RIS[ViewerTools.GetContents[td.pauseCondText]]; buffer: REF TEXT _ NEW[TEXT[64]]; -- buffer for scanning opNameTable: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; startPC: LONG CARDINAL; haveStart: BOOL _ FALSE; haveDots: BOOL _ FALSE; instCount: BOOL _ FALSE; IF shift AND oldPauseData # NIL THEN newPauseData^ _ oldPauseData^; <> DO tokenKind: IO.TokenKind; token: ROPE _ NIL; [tokenKind: tokenKind, token: token] _ IO.GetCedarTokenRope[st ! IO.EndOfStream => {tokenKind _ tokenEOF; CONTINUE}; IO.Error => {tokenKind _ tokenERROR; CONTINUE}]; {endPC: LONG CARDINAL _ startPC; SELECT tokenKind FROM tokenID => { <> IF haveDots THEN GO TO oops; <> FOR inst: Inst IN Inst DO IF Rope.Equal[token, opNameTable[inst]] THEN { newPauseData.instArray[inst] _ TRUE; EXIT; }; ENDLOOP; IF NOT haveStart THEN LOOP; -- No lagging PC to enter }; tokenSINGLE => { <> IF Rope.Fetch[token, 0] = '# THEN instCount _ TRUE; LOOP; }; tokenDOUBLE => { <> IF haveDots OR NOT haveStart THEN GO TO oops; IF NOT Rope.Equal[token, ".."] THEN GO TO oops; haveDots _ TRUE; LOOP; }; tokenDECIMAL, tokenOCTAL, tokenHEX => { <> ENABLE Convert.Error => GO TO oops; thisPC: LONG CARDINAL _ 0; SELECT tokenKind FROM tokenDECIMAL => thisPC _ Convert.CardFromDecimalLiteral[token]; tokenOCTAL => thisPC _ Convert.CardFromOctalLiteral[token]; tokenHEX => thisPC _ Convert.CardFromHexLiteral[token]; ENDCASE => ERROR; SELECT TRUE FROM instCount => { newPauseData.instCountStop _ CONS[thisPC, newPauseData.instCountStop]; instCount _ FALSE; LOOP; }; haveDots => { endPC _ thisPC; }; ENDCASE => { IF haveStart THEN { endPC _ startPC; newPauseData.pcRanges _ CONS[[startPC, endPC], newPauseData.pcRanges]; }; haveStart _ TRUE; startPC _ thisPC; LOOP; }; }; tokenEOF => { IF NOT haveStart THEN EXIT; IF haveDots THEN GO TO oops; haveStart _ FALSE; }; ENDCASE => GO TO oops; <> newPauseData.pcRanges _ CONS[[startPC, endPC], newPauseData.pcRanges]; haveStart _ haveDots _ instCount _ FALSE; EXITS oops => { MessageWindow.Append[ IO.PutFR["near pos %g, scanning error for pause condition", [integer[IO.GetIndex[st]]]], TRUE]; MessageWindow.Blink[]; RETURN; }; }; ENDLOOP; td.pauseCondTable _ newPauseData; ShowPauseCond[td]; }; ShowPauseCond: PROC [td: ToolData] = { oldPauseData: PauseCondTable = td.pauseCondTable; ros: STREAM = IO.ROS[]; opNameTable: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; SetOutputBaseW[ros, td.useHex]; IF oldPauseData # NIL THEN { FOR inst: Inst IN Inst DO IF oldPauseData.instArray[inst] THEN { IO.PutRope[ros, opNameTable[inst]]; IO.PutRope[ros, " "]; }; ENDLOOP; FOR each: LIST OF PCRange _ oldPauseData.pcRanges, each.rest WHILE each # NIL DO pcr: PCRange _ each.first; IF pcr.firstPC # pcr.lastPC THEN IO.PutF[ros, "%w..%w ", [cardinal[pcr.firstPC]], [cardinal[pcr.lastPC]] ] ELSE IO.PutF[ros, "%w ", [cardinal[pcr.firstPC]]]; ENDLOOP; FOR each: LIST OF INT _ oldPauseData.instCountStop, each.rest WHILE each # NIL DO IO.PutF[ros, "#%g ", [cardinal[each.first]]]; ENDLOOP; }; ViewerTools.SetContents[td.pauseCondText, IO.RopeFromROS[ros]]; }; TraceButtonProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> InvertTracing[NARROW[clientData]]; }; BaseButtonProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> InvertOutputBase[NARROW[clientData]]; }; SetDumpStartButtonProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> data: ToolData = NARROW[clientData]; data.dumpStart _ NumberFromSelection[data.dumpStart]; }; SetDumpWordsButtonProc: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> data: ToolData = NARROW[clientData]; data.dumpWords _ NumberFromSelection[data.dumpWords]; }; NumberFromSelection: PROC [default: INT] RETURNS [INT] = { selection: ROPE = ViewerTools.GetSelectionContents[]; RETURN [Convert.IntFromRope[selection ! Convert.Error => CONTINUE]]; MessageWindow.Append["Selection not a number!", TRUE]; MessageWindow.Blink[]; RETURN [default]; }; <> LogRegChange: LizardHeart.RegChangeProc = { <<[data: REF, processor: Processor, reg: ProcessorRegister, old,new: Word]>> td: ToolData = NARROW[data]; IF td.tracing THEN { log: STREAM = td.log; IO.PutRope[log, " "]; IO.PutRope[log, HandCodingUtil.GetRegArray[][reg]]; PutAsBoth[log, ", old: %w (%d)", old]; PutAsBoth[log, ", new: %w (%d)\n", new]; }; }; LogMemChange: LizardHeart.MemChangeProc = { <<[data: REF, processor: Processor, addr: Word, old,new: Word]>> td: ToolData = NARROW[data]; IF td.tracing THEN { log: STREAM = td.log; PutAsCard[log, " word addr: %w", addr]; PutAsBoth[log, ", old: %w (%g)", old]; PutAsBoth[log, ", new: %w (%g)\n", new]; }; }; LogIOChange: LizardHeart.IOChangeProc = { <<[data: REF, processor: Processor, addr: Word, old,new: Word]>> td: ToolData = NARROW[data]; IF td.tracing THEN { log: STREAM = td.log; PutAsCard[log, " IO addr: %w", addr]; PutAsBoth[log, ", old: %w (%g)", old]; PutAsBoth[log, ", new: %w (%g)\n", new]; }; }; LogInstStart: LizardHeart.InstStartProc = { <<[data: REF, processor: Processor, thisPC: Word, inst: Inst, rest: Word]>> td: ToolData = NARROW[data]; thisOne: LONG CARDINAL = DragOpsCrossUtils.WordToCard[thisPC]; instTable: InstCountTable = td.instTable; last: [0..LastInstMod) _ td.lastInstTable.last; td.lastInstTable.last _ last _ IF last = LastInstMod-1 THEN 0 ELSE last + 1; instTable[inst] _ instTable[inst] + 1; td.lastInstTable.pcArray[last] _ thisPC; {pauseTable: PauseCondTable = td.pauseCondTable; IF pauseTable # NIL THEN { <> IF pauseTable.instArray[inst] THEN GO TO setPause; <> FOR each: LIST OF PCRange _ pauseTable.pcRanges, each.rest WHILE each # NIL DO pcr: PCRange _ each.first; IF thisOne IN [pcr.firstPC..pcr.lastPC] THEN GO TO setPause; ENDLOOP; <> FOR each: LIST OF INT _ pauseTable.instCountStop, each.rest WHILE each # NIL DO IF processor.stats.instructions = each.first THEN GO TO setPause; ENDLOOP; }; SELECT inst FROM dTrap, LAST[Inst] => GO TO setPause; ENDCASE; EXITS setPause => { IF NOT td.tracing THEN InvertTracing[td]; SetInternalControl[td, pause]; }; }; IF td.tracing THEN { IO.PutF[td.log, "Inst %g start, cycle: %g, pc: %w, opcode: %w\n ", [integer[processor.stats.instructions]], [integer[processor.stats.cycles]], [cardinal[thisOne]], [cardinal[LOOPHOLE[inst, CARDINAL]]] ]; HandCodingUtil.ToStream[td.log, inst, rest, thisPC]; IO.PutRope[td.log, "\n"]; }; }; LogInstDone: LizardHeart.InstDoneProc = { <<[data: REF, processor: Processor, newPC, rtnPC: Word, control: Control, cycles: INT]>> td: ToolData = NARROW[data]; td.newStats.pStats _ processor.stats; td.newStats.samplePulses _ BasicTime.GetClockPulses[]; IF td.tracing THEN { log: STREAM = td.log; ctrl: ROPE = SELECT control FROM nextInst => "nextInst", doCall => "doCall", doReturn => "doReturn", doSwitch => "doSwitch", doAbort => "doAbort", ENDCASE => "??"; PutAsCard[log, " Inst done. newPC: %w", newPC]; PutAsCard[log, ", rtnPC: %w", rtnPC]; PutAsCard[log, ", regS: %w", processor.regs[ifuS]]; PutAsCard[log, ", regL: %w", processor.regs[ifuL]]; IO.PutF[log, ", control: %g\n\n", [rope[ctrl]] ]; }; }; <> GetInstAndRest: PROC [mem: SparseMemory.Base, pc: Word] RETURNS [inst: Inst, rest: Word] = { <> lastAddr: Word _ ZerosWord; bytes: DragOpsCross.FourBytes _ LOOPHOLE[ZerosWord]; instLen: NAT; word: Word; FetchByte: PROC [offset: NAT] RETURNS [Byte] = { wordAddr: Word; byteIndex: [0..3]; [wordAddr, byteIndex] _ DragOpsCrossUtils.BytePCToWordAddress[[DragOpsCrossUtils.AddDelta[offset, pc]]]; IF lastAddr # wordAddr THEN word _ SparseMemory.Fetch[mem, lastAddr _ wordAddr]; RETURN [LOOPHOLE[word, DragOpsCross.FourBytes][byteIndex]]; }; inst _ LOOPHOLE[FetchByte[0]]; instLen _ LOOPHOLE[inst, CARDINAL] / 64; IF instLen = 0 THEN instLen _ IF LOOPHOLE[inst, CARDINAL] < 40B THEN 1 ELSE 5; SELECT instLen FROM 2 => bytes[3] _ FetchByte[1]; 3 => { bytes[2] _ FetchByte[1]; bytes[3] _ FetchByte[2]; }; 5 => { bytes[0] _ FetchByte[1]; bytes[1] _ FetchByte[2]; bytes[2] _ FetchByte[3]; bytes[3] _ FetchByte[4]; }; ENDCASE; RETURN [inst, LOOPHOLE[bytes]]; }; PutAsBoth: PROC [log: STREAM, format: ROPE, word: Word] = { IO.PutF[log, format, [cardinal[DragOpsCrossUtils.WordToCard[word]]], [integer[DragOpsCrossUtils.WordToInt[word]]]]; }; PutAsCard: PROC [log: STREAM, format: ROPE, word: Word] = { IO.PutF[log, format, [cardinal[DragOpsCrossUtils.WordToCard[word]]]]; }; StandardNumberLabel: PROC [parent: Viewer, chars: NAT] RETURNS [NumberLabel] = { RETURN [NumberLabels.CreateNumber[ info: [parent: parent, border: FALSE], chars: chars, paint: FALSE]]; }; <
> <<>> LizardToolWatcher: PROC [data: ToolData] = { NewMenuEntry: PROC [name: ROPE, proc: Menus.MenuProc, line: INTEGER _ 0] = { Menus.AppendMenuEntry[ menu, Menus.CreateEntry[name: name, proc: proc, clientData: data], line]; }; StandardButton: PROC [name: ROPE, proc: Menus.MenuProc, x,y: INTEGER, w: INTEGER _ 0] RETURNS [button: Buttons.Button] = { button _ Buttons.Create[ info: [parent: topViewer, name: name, border: TRUE, wx: x, wy: y, ww: w], proc: proc, clientData: data, paint: FALSE]; nextX _ button.wx+button.ww-1; nextY _ button.wy+button.wh-1; }; nextX: INTEGER _ 1; nextY: INTEGER _ 1; menu: Menus.Menu = Menus.CreateMenu[2]; topViewer: Viewer = Containers.Create[ info: [name: "LizardTool", iconic: TRUE, column: left, scrollable: FALSE], paint: FALSE]; traceButton: Buttons.Button _ data.traceButton _ StandardButton[ " Trace ", TraceButtonProc, 1, 1]; baseButton: Buttons.Button _ data.baseButton _ StandardButton[ " Octal ", BaseButtonProc, nextX, 1]; setDumpStartButton: Buttons.Button = StandardButton[ " Set Dump Start ", SetDumpStartButtonProc, nextX, 1]; setDumpWordsButton: Buttons.Button = StandardButton[ " Set Dump Words ", SetDumpWordsButtonProc, nextX, 1]; setPauseCondButton: Button = StandardButton[ " SetPauseCond ", SetPauseCondProc, 1, nextY]; samplePauseCondButton: Button = StandardButton[ " Sample ", SamplePauseCondProc, 1, nextY, setPauseCondButton.ww]; pauseCondText: Viewer = ViewerOps.CreateViewer[ flavor: $Text, info: [ wx: nextX, wy: setPauseCondButton.wy, ww: setPauseCondButton.ww, wh: nextY+1 - setPauseCondButton.wy, parent: topViewer], paint: FALSE]; vTab: VTable = VTables.Create[columns: 10, rows: 3, parent: topViewer, x: 1, y: nextY]; statusLabel: Label _ data.statusLabel _ Labels.Create[ info: [name: "Initializing", parent: vTab, border: FALSE], paint: FALSE]; instCountLabel: NumberLabel = StandardNumberLabel[vTab, 10]; instRateLabel: NumberLabel = StandardNumberLabel[vTab, 7]; cycleCountLabel: NumberLabel = StandardNumberLabel[vTab, 10]; cycleRateLabel: NumberLabel = StandardNumberLabel[vTab, 7]; iBytesCountLabel: NumberLabel = StandardNumberLabel[vTab, 10]; iBytesRateLabel: NumberLabel = StandardNumberLabel[vTab, 7]; readCountLabel: NumberLabel = StandardNumberLabel[vTab, 10]; readRateLabel: NumberLabel = StandardNumberLabel[vTab, 7]; writeCountLabel: NumberLabel = StandardNumberLabel[vTab, 10]; writeRateLabel: NumberLabel = StandardNumberLabel[vTab, 7]; DoRefresh: PROC [data: ToolData] = { newStats: ToolStats = SampleStats[data]; deltaStats: ToolStats = GetDeltaFromBase[data]; IF deltaStats.samplePulses # 0 THEN { <> secs: REAL = BasicTime.PulsesToSeconds[deltaStats.samplePulses]; invSecs: REAL = 1/secs; IF deltaStats.pStats.instructions # 0 THEN { NumberLabels.NumberLabelUpdate[instCountLabel, newStats.pStats.instructions]; NumberLabels.NumberLabelUpdate[instRateLabel, Real.RoundLI[(deltaStats.pStats.instructions) * invSecs]]; }; IF deltaStats.pStats.cycles # 0 THEN { NumberLabels.NumberLabelUpdate[cycleCountLabel, newStats.pStats.cycles]; NumberLabels.NumberLabelUpdate[cycleRateLabel, Real.RoundLI[(deltaStats.pStats.cycles) * invSecs]]; }; IF deltaStats.pStats.instBytes # 0 THEN { NumberLabels.NumberLabelUpdate[iBytesCountLabel, newStats.pStats.instBytes]; NumberLabels.NumberLabelUpdate[iBytesRateLabel, Real.RoundLI[(deltaStats.pStats.instBytes) * invSecs]]; }; IF deltaStats.pStats.euFetches # 0 THEN { NumberLabels.NumberLabelUpdate[readCountLabel, newStats.pStats.euFetches]; NumberLabels.NumberLabelUpdate[readRateLabel, Real.RoundLI[(deltaStats.pStats.euFetches) * invSecs]]; }; IF deltaStats.pStats.euStores # 0 THEN { NumberLabels.NumberLabelUpdate[writeCountLabel, newStats.pStats.euStores]; NumberLabels.NumberLabelUpdate[writeRateLabel, Real.RoundLI[(deltaStats.pStats.euStores) * invSecs]]; }; }; }; topViewer.menu _ menu; NewMenuEntry["Stop!", StopMenuProc]; NewMenuEntry["Pause", PauseMenuProc]; NewMenuEntry["Run", RunMenuProc]; NewMenuEntry["Step", StepMenuProc]; NewMenuEntry["Reset", ResetMenuProc]; NewMenuEntry["Resched", ReschedMenuProc]; NewMenuEntry["StopPrint!", StopPrintMenuProc]; NewMenuEntry["DumpMem", DumpMemMenuProc, 1]; NewMenuEntry["DumpRegs", DumpRegsMenuProc, 1]; NewMenuEntry["DumpStats", DumpStatsMenuProc, 1]; NewMenuEntry["DumpRing", DumpRingMenuProc, 1]; NewMenuEntry["BiasStats", BiasStatsMenuProc, 1]; VTables.SetTableEntry[ table: vTab, row: 0, column: 0, flavor: $Viewer, clientData: statusLabel]; VTables.SetTableEntry[table: vTab, row: 1, column: 0, name: "count"]; VTables.SetTableEntry[table: vTab, row: 2, column: 0, name: "rate"]; VTables.SetTableEntry[table: vTab, row: 0, column: 1, name: "inst"]; VTables.SetTableEntry[ table: vTab, row: 1, column: 1, flavor: $Viewer, clientData: instCountLabel]; VTables.SetTableEntry[ table: vTab, row: 2, column: 1, flavor: $Viewer, clientData: instRateLabel]; VTables.SetTableEntry[table: vTab, row: 0, column: 2, name: "cycle"]; VTables.SetTableEntry[ table: vTab, row: 1, column: 2, flavor: $Viewer, clientData: cycleCountLabel]; VTables.SetTableEntry[ table: vTab, row: 2, column: 2, flavor: $Viewer, clientData: cycleRateLabel]; VTables.SetTableEntry[table: vTab, row: 0, column: 3, name: "instBytes"]; VTables.SetTableEntry[ table: vTab, row: 1, column: 3, flavor: $Viewer, clientData: iBytesCountLabel]; VTables.SetTableEntry[ table: vTab, row: 2, column: 3, flavor: $Viewer, clientData: iBytesRateLabel]; VTables.SetTableEntry[table: vTab, row: 0, column: 4, name: "read"]; VTables.SetTableEntry[ table: vTab, row: 1, column: 4, flavor: $Viewer, clientData: readCountLabel]; VTables.SetTableEntry[ table: vTab, row: 2, column: 4, flavor: $Viewer, clientData: readRateLabel]; VTables.SetTableEntry[table: vTab, row: 0, column: 5, name: "write"]; VTables.SetTableEntry[ table: vTab, row: 1, column: 5, flavor: $Viewer, clientData: writeCountLabel]; VTables.SetTableEntry[ table: vTab, row: 2, column: 5, flavor: $Viewer, clientData: writeRateLabel]; VTables.Install[table: vTab, paint: FALSE]; data.logTS _ TypeScript.Create[ info: [parent: topViewer, wx: vTab.wx, wy: vTab.wy+vTab.wh, border: FALSE], paint: FALSE]; TypeScript.ChangeLooks[data.logTS, 'f]; -- fixed width font for alignment TypeScript.ChangeLooks[data.logTS, 's]; -- small for compactness data.vTab _ vTab; data.pauseCondText _ pauseCondText; data.log _ ViewerIO.CreateViewerStreams[ name: "LizardTool.log", viewer: data.logTS, backingFile: "LizardTool.log", editedStream: FALSE].out; Containers.ChildXBound[container: topViewer, child: data.logTS]; Containers.ChildYBound[container: topViewer, child: data.logTS]; Containers.ChildXBound[container: topViewer, child: pauseCondText]; InvertOutputBase[data]; -- forces the initial base to be Octal ViewerOps.OpenIcon[topViewer]; Start[data]; WHILE data.live DO DoRefresh[data]; WaitForRefresh[data]; IF NOT data.live OR topViewer.destroyed THEN EXIT; ENDLOOP; }; ExecBase: PROC [nProcessors: NAT, area: HandCodingSupport.Area] = { data: ToolData = NEW[ToolDataRep]; processors: ProcessorSequence = NEW[ProcessorSequenceRep[nProcessors]]; logger: ChangeLogger = NEW[ChangeLoggerRep _ [ data, LogRegChange, LogMemChange, LogIOChange, LogInstStart, LogInstDone]]; cycles: INT _ 0; processor: Processor _ NIL; lagControl: InternalControl _ run; statusLabel: Label _ NIL; mem: SparseMemory.Base = NARROW[area.data]; shared: LizardCache.SharedBase = LizardCache.NewBase[mem]; instTable: InstCountTable _ NEW[InstCountTableRep _ ALL[0]]; logger.data _ data; data.instTable _ instTable; data.lastInstTable _ NEW[LastInstTableRep]; data.lastInstTable.last _ 0; data.lastInstTable.pcArray _ ALL[ZerosWord]; FOR i: NAT IN [0..nProcessors) DO ifuCache: LizardCache.CacheBase = LizardCache.NewCache[shared, instCacheLines]; euCache: LizardCache.CacheBase = LizardCache.NewCache[shared, dataCacheLines]; processors[i] _ LizardHeart.NewProcessor[ifuCache, euCache, logger]; ENDLOOP; TRUSTED {Process.Detach[FORK LizardToolWatcher[data]]}; <> UNTIL data.live DO WaitForRefresh[data]; ENDLOOP; statusLabel _ data.statusLabel; IO.PutF[data.log, "\nStarting interpreter at %g\n\n", [time[BasicTime.Now[]]] ]; Labels.Set[statusLabel, "Pausing"]; processor _ processors[0]; <> Process.SetPriority[Process.priorityBackground]; <> <> WHILE data.live AND NOT data.vTab.destroyed DO internalControl: InternalControl _ data.internalControl; SELECT TRUE FROM data.requestReset => { processor.resetRequested _ TRUE; IO.PutRope[data.log, "Note: reset requested by user.\n\n"]; data.requestReset _ FALSE; UpdateStats[data, SampleStats[data]]; LOOP; }; data.requestReschedule => { LOOPHOLE[processor.regs[ifuStatus], DragOpsCross.IFUStatusRec].reschedule _ TRUE; IO.PutRope[data.log, "Note: reschedule requested by user.\n\n"]; data.requestReschedule _ FALSE; LOOP; }; data.requestDump # none => { ServiceDumpRequest[data, processor, mem, data.requestDump]; data.requestDump _ none; LOOP; }; data.requestBiasStats => { ServiceBiasStatsRequest[data, processor]; data.requestBiasStats _ FALSE; LOOP; }; ENDCASE; IF internalControl # lagControl THEN { <> SELECT internalControl FROM run => Labels.Set[statusLabel, "Running"]; step => Labels.Set[statusLabel, "Stepping"]; pause => Labels.Set[statusLabel, "Pausing"]; stop => Labels.Set[statusLabel, "Stopping"]; ENDCASE => ERROR; lagControl _ internalControl; SetBaseState[data]; CauseRefresh[data]; }; SELECT internalControl FROM run, step => { }; pause => { UpdateStats[data, SampleStats[data]]; [] _ WaitForControlChange[data]; LOOP}; stop => EXIT; ENDCASE => ERROR; LizardHeart.InstructionExecute[processor ! LizardHeart.OutsideEnvelope => { data.log.PutF["Warning: In instruction %g processor outside defined envelope -\n %g\n\n", IO.int[processor.stats.instructions], IO.rope[explanation]]; internalControl _ step; RESUME } ]; IF internalControl = step THEN { SetInternalControl[data, pause]; CauseRefresh[data]; }; ENDLOOP; IO.PutF[data.log, "\nStopping interpreter at %g\n\n", [time[BasicTime.Now[]]] ! IO.Error => CONTINUE]; Stop[data]; IF NOT statusLabel.destroyed THEN Labels.Set[statusLabel, "Stopped"]; }; ServiceDumpRequest: PROC [data: ToolData, processor: Processor, mem: SparseMemory.Base, kind: DumpRequest] = { regNameArray: HandCodingUtil.RegNameArray = HandCodingUtil.GetRegArray[]; instNameArray: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; log: STREAM = data.log; testAbort: WriteSparseMemory.TestAbort = {RETURN [data.stopPrint]}; data.stopPrint _ FALSE; IO.PutRope[data.log, "Note: start of dump requested by user.\n"]; SELECT kind FROM words, bytes => { useBytes: BOOL = kind = bytes; IO.PutRope[log, "\n"]; LizardCache.FlushCache[processor.euCache]; <> WriteSparseMemory.ToStream[ data.log, mem, DragOpsCrossUtils.IntToWord[data.dumpStart], data.dumpWords, useBytes, useBytes, testAbort]; }; regs => LizardToolOutput.ShowRegisters[log, processor, testAbort]; ring => <> LizardToolOutput.ShowRing[log, data.lastInstTable, mem, LastInstMod, testAbort]; stats => <> LizardToolOutput.ShowStats[log, processor, data.instTable, testAbort]; ENDCASE; IO.PutRope[data.log, "\nNote: end of dump requested by user.\n\n"]; data.stopPrint _ FALSE; }; ServiceBiasStatsRequest: PROC [data: ToolData, processor: LizardHeart.Processor] = { testAbort: WriteSparseMemory.TestAbort = {RETURN [data.stopPrint]}; <> newBias: LizardToolOutput.StatSnapshot _ [pStats: processor.stats, discarded: processor.instBuffer.bytesDiscarded, -- not in stats!!! ifuStats: processor.ifuCache.stats, euStats: processor.euCache.stats, iStats: data.instTable^]; <> LizardToolOutput.ShowBiasedStats[data.log, data.biasStats, newBias]; <> data.biasStats _ newBias; IO.PutRope[data.log, "\nNote: Statistics biased.\n\n"]; }; <> Exec: PROC [nProcessors: NAT _ 1] = TRUSTED { area: HandCodingSupport.Area = HandCodingSupport.GetCurrentArea[]; Process.Detach[FORK ExecBase[nProcessors, area]]; }; Exec1: PROC = { Exec[1]; }; Exec2: PROC = { Exec[2]; }; Exec3: PROC = { Exec[3]; }; Exec4: PROC = { Exec[4]; }; END.