DIRECTORY Basics, Convert, Core, CoreClasses, CoreFlat, CoreOps, CoreProperties, FS, IO, List, PlotGraph, Ports, Real, RedBlackTree, RefTab, RefText, Rope, Rosemary, RosemaryUser; RosemaryUserBackingImpl: CEDAR MONITOR IMPORTS Basics, Convert, CoreFlat, CoreOps, CoreProperties, FS, IO, List, PlotGraph, Ports, Real, RedBlackTree, RefTab, RefText, Rope, Rosemary, RosemaryUser EXPORTS RosemaryUser ~ BEGIN OPEN RosemaryUser; Sample: TYPE = REF SampleRec; SampleRec: TYPE = RECORD [ next: Sample _ NIL, step: INT _ LAST[INT], -- MosSim step number at which this event occured value: PACKED SEQUENCE size: CARDINAL OF Ports.Level ]; SampleList: TYPE = REF SampleListRec; SampleListRec: TYPE ~ RECORD [ head: Sample, -- the head of the list. The tail is always LogData.current beforeHeadPos: INT, -- the file position of the predecessor of head, <0 => no predecessor inTable: BOOL _ FALSE -- used internally to RBT management, don't modify ... ]; LogData: TYPE = REF LogDataRec; LogDataRec: TYPE = RECORD [ lastFilePos: INT _ -1, -- the file position of the last sample written list: SampleList _ NIL, -- if non-nil, the samples for this object are currently kept in memory previous: Sample _ NIL, -- the previous sample currentTime: INT _ -1, -- time of current sample current: Sample _ NIL -- the sample currently taken, not guaranteed if time=lastUpdateTime ]; LockBackingStore: ENTRY PROC [h: RoseDisplay] = { UNTIL NOT h.psLock DO WAIT h.psWait ENDLOOP; h.psLock _ TRUE; }; UnlockBackingStore: ENTRY PROC [h: RoseDisplay] = { h.psLock _ FALSE; BROADCAST h.psWait; }; WillWrite: PROC [handle: RoseDisplay, nBytes: NAT] ~ { to: REF TEXT = handle.wBuff; IF to.maxLength-nBytes < to.length THEN FlushWBuff[handle, nBytes]; }; FlushWBuff: PROC [handle: RoseDisplay, nBytes: NAT] ~ { IO.PutBlock[handle.ps, handle.wBuff]; IF handle.wBuff.maxLength { -- write single byte PutByte[handle, v.ll]; handle.filePos _ handle.filePos+1; }; { -- write 2 bytes v.lo _ Basics.BITOR[v.lo, 08000H]; PutByte[handle, v.lh]; PutByte[handle, v.ll]; handle.filePos _ handle.filePos+2; }; { -- write 3 bytes v.hi _ Basics.BITOR[v.hi, 000C0H]; PutByte[handle, v.hl]; PutByte[handle, v.lh]; PutByte[handle, v.ll]; handle.filePos _ handle.filePos+3; }; { -- write 4 bytes v.hi _ Basics.BITOR[v.hi, 0E000H]; PutByte[handle, v.hh]; PutByte[handle, v.hl]; PutByte[handle, v.lh]; PutByte[handle, v.ll]; handle.filePos _ handle.filePos+4; }; ENDCASE => ERROR; -- too large }; Read29Bits: PROC [s: IO.STREAM] RETURNS [delta: INT32] ~ { v: Basics.LongNumber; v.lc _ 0; v.ll _ IO.GetByte[s]; SELECT TRUE FROM Basics.BITAND[v.lo, 00080H]=0 => { -- single byte }; Basics.BITAND[v.lo, 00040H]=0 => { -- 2 bytes v.lo _ Basics.BITAND[Basics.BITSHIFT[v.lo, 8], 03F00H]; v.ll _ IO.GetByte[s]; }; Basics.BITAND[v.lo, 00020H]=0 => { -- 3 bytes v.hi _ Basics.BITAND[v.lo, 0001FH]; v.lh _ IO.GetByte[s]; v.ll _ IO.GetByte[s]; }; ENDCASE => { -- 4 bytes v.hi _ Basics.BITAND[Basics.BITSHIFT[v.lo, 8], 01F00H]; v.hl _ IO.GetByte[s]; v.lh _ IO.GetByte[s]; v.ll _ IO.GetByte[s]; }; RETURN [delta: v.li]; }; WriteSample: PROC [handle: RoseDisplay, sample: Sample, prvPos: INT, nextStep: INT] RETURNS [pos: INT] ~ { deltaPos: INT; WillWrite[handle, 8+sample.size]; -- max number of bytes that will be written pos _ handle.filePos; IF prvPos<0 THEN deltaPos _ 0 ELSE { deltaPos _ pos-prvPos; IF deltaPos<=0 THEN ERROR; -- something is very wrong... }; Write29Bits[handle, deltaPos]; Write29Bits[handle, nextStep - sample.step]; -- must be >=0 !!! FOR i: NAT IN [0..sample.size) DO PutByte[handle, ORD[sample.value[i]]]; ENDLOOP; handle.filePos _ handle.filePos+sample.size; }; ReadSample: PROC [s: IO.STREAM, pos: INT, into: Sample, nextStep: INT] RETURNS [prvPos: INT] ~ { deltaPos: INT; IO.SetIndex[s, pos]; deltaPos _ Read29Bits[s]; IF deltaPos=0 THEN prvPos _ -1 ELSE { prvPos _ pos - deltaPos; IF prvPos<0 THEN ERROR; -- inconsistency in file management }; into.step _ nextStep - Read29Bits[s]; FOR i: NAT IN [0..into.size) DO into.value[i] _ VAL[IO.GetByte[s]]; ENDLOOP; }; RBTGetKey: RedBlackTree.GetKey ~ { RETURN [data]; -- keys are same as data... }; RBTCompare: RedBlackTree.Compare ~ { list1: SampleList = NARROW [k]; list2: SampleList = NARROW [data]; RETURN [Basics.CompareInt[list1.beforeHeadPos, list2.beforeHeadPos]]; }; EnterSourceInRBT: PROC [table: RedBlackTree.Table, source: REF ANY, min: INT _ 0] RETURNS [newTable: RedBlackTree.Table] ~ { EnterLogDataInRBT: PROC [data: LogData] ~ { IF data#NIL THEN { -- nothing ever logged for this guy... list: SampleList _ data.list; IF list=NIL THEN { -- must create list head list _ NEW [SampleListRec _ [ head: IF data.previous#NIL THEN data.previous ELSE data.current, beforeHeadPos: data.lastFilePos, inTable: FALSE]]; data.list _ list; }; IF list.beforeHeadPos<0 OR list.head.step<=min THEN RETURN; -- nothing to fetch IF newTable=NIL THEN newTable _ RedBlackTree.Create[RBTGetKey, RBTCompare]; IF NOT list.inTable THEN { -- may not insert twice in a RedBlackTree RedBlackTree.Insert[newTable, list, list]; list.inTable _ TRUE; }; }; }; newTable _ table; WITH source SELECT FROM rvl: Rosemary.RoseValues => UNTIL rvl=NIL DO -- this is for a CoreFlat wire EnterLogDataInRBT[NARROW [rvl.first.roseWire.data]]; rvl _ rvl.rest; -- advance list pointer ENDLOOP; roseInstance: Rosemary.RoseCellInstance => EnterLogDataInRBT[NARROW [roseInstance.data]]; ENDCASE => ERROR; }; ReadSamplesUsingRBT: PROC [handle: RoseDisplay, table: RedBlackTree.Table, min: INT] ~ { stream: IO.STREAM = handle.ps; FlushWBuff[handle, 0]; -- ensure we are really at end of file and the buffer is empty IF table#NIL THEN WHILE RedBlackTree.Size[table]#0 DO list: SampleList _ NARROW [RedBlackTree.LookupLargest[table]]; node: RedBlackTree.Node _ RedBlackTree.Delete[table, list]; sample: Sample _ NEW [SampleRec[list.head.size]]; list.beforeHeadPos _ ReadSample[stream, list.beforeHeadPos, sample, list.head.step]; sample.next _ list.head; list.head _ sample; -- insert as head of list IF sample.step>min AND list.beforeHeadPos>=0 THEN RedBlackTree.InsertNode[table, node, list] -- this one must still go on... ELSE list.inTable _ FALSE; -- it's no more there... ENDLOOP; IO.SetIndex[stream, handle.filePos]; -- go back to end of file }; LogTime: PROC [handle: RoseDisplay, time: INT] ~ { index: NAT _ time/timeBlock; offset: NAT _ time MOD timeBlock; block: TimeSteps _ handle.timeSteps[index]; handle.lastValidTime _ time; IF block=NIL THEN { IF offset#0 THEN ERROR; -- we missed a time value !!! block _ NEW [TimeStepsRep _ ALL[-1]]; handle.timeSteps[index] _ block; }; block[offset] _ handle.simulation.mosSimTime; }; LastStep: PROC [handle: RoseDisplay, time: INT] RETURNS [lastStep: INT] ~ { SELECT TRUE FROM time<0 => lastStep _ 0; time>handle.lastValidTime => lastStep _ handle.simulation.mosSimTime; ENDCASE => { -- normal case index: NAT _ time/timeBlock; offset: NAT _ time MOD timeBlock; lastStep _ handle.timeSteps[index][offset]; }; }; FirstStep: PROC [handle: RoseDisplay, time: INT] RETURNS [firstStep: INT] ~ { time _ time-1; SELECT TRUE FROM time<0 => firstStep _ 0; time>handle.lastValidTime => firstStep _ LAST[INT]; -- get lost ... ENDCASE => { -- normal case index: NAT _ time/timeBlock; offset: NAT _ time MOD timeBlock; firstStep _ handle.timeSteps[index][offset]+1; }; }; LSToSample: PROC [ls: Ports.LevelSequence, sample: Sample] ~ { IF ls.size#sample.size THEN ERROR; -- Client programming error or Rosemary bug FOR i: NAT IN [0.. ls.size) DO sample.value[i] _ ls[i] ENDLOOP; }; NewLogData: PROC [nbits: NAT] RETURNS [data: LogData] ~ { data _ NEW [LogDataRec]; data.lastFilePos _ -1; data.list _ NIL; -- not kept in memory (yet...) data.previous _ NIL; -- no previous sample data.currentTime _ -1; data.current _ NEW[SampleRec[nbits]]; data.current.next _ NIL; data.current.step _ 0; }; InitializeDeltas: PUBLIC PROC [handle: RoseDisplay] = { EraseWireData: RefTab.EachPairAction = { wire: Rosemary.RoseWire _ NARROW[val]; atomic: BOOL = wire.currentValue=NIL; data: LogData _ NewLogData[IF atomic THEN 1 ELSE wire.currentValue.size]; IF atomic THEN data.current.value[0] _ wire.wireLevel ELSE LSToSample[wire.currentValue, data.current]; wire.data _ data; }; EraseInstanceData: RefTab.EachPairAction ~ { roseInstance: Rosemary.RoseCellInstance _ NARROW [val]; ls: Ports.LevelSequence = NARROW [roseInstance.data]; IF ls#NIL THEN { -- make into a LogData data: LogData _ NewLogData[ls.size]; LSToSample[ls, data.current]; roseInstance.data _ data; }; }; LockBackingStore[handle]; -- Don't forget it here... LogTime[handle, 0]; IF handle.wBuff=NIL THEN handle.wBuff _ RefText.New[4096]; handle.wBuff.length _ 0; -- erase the buffer as it may contain garbage IF handle.ps=NIL THEN handle.ps _ FS.StreamOpen["///Temp/RoseBackingStore.bin", $create] ELSE IO.SetLength[handle.ps, 0]; -- completely erase the file if already there... handle.filePos _ 0; [] _ RefTab.Pairs[x: handle.simulation.coreToRoseWires, action: EraseWireData]; [] _ RefTab.Pairs[x: handle.simulation.coreToRoseInstances, action: EraseInstanceData]; UnlockBackingStore[handle]; -- we don't want to hold onto it during plotting ! IF handle.plot#NIL AND handle.plot.data#NIL THEN PlotGraph.RefreshPlot[plot: handle.plot, eraseFirst: TRUE]; }; CollapseSample: PROC [handle: RoseDisplay, data: LogData] ~ { nbits: NAT = data.current.size; DifferSample: PROC [s1, s2: Sample] RETURNS [BOOL] ~ { FOR i: CARDINAL IN [0..s1.size) DO IF s1.value[i]#s2.value[i] THEN RETURN [TRUE] ENDLOOP; RETURN [FALSE]; }; SELECT TRUE FROM data.previous=NIL => { -- this the 1st sample, make it previous & allocate new current data.previous _ data.current; data.current _ NEW[SampleRec[nbits]]; data.previous.next _ data.current; data.current.next _ NIL; -- just to make sure... }; DifferSample[data.previous, data.current] => { -- commit current sample data.lastFilePos _ WriteSample[handle, data.previous, data.lastFilePos, data.current.step]; data.current.next _ IF data.list=NIL THEN data.previous ELSE NEW[SampleRec[nbits]]; data.previous _ data.current; data.current _ data.previous.next; -- update data data.current.next _ NIL; -- necessary if data.previous was reused }; ENDCASE => NULL; -- collapse current with previous }; RecordDelta: PUBLIC PROC [handle: RoseDisplay, wire: Rosemary.RoseWire, time: INT] ~ { IF handle.recordDeltas THEN { -- otherwise, nop... data: LogData = NARROW [wire.data]; nbits: NAT = data.current.size; mosSimTime: INT = handle.simulation.mosSimTime; mustCollapse: BOOL = IF handle.recordSteps THEN mosSimTime#data.current.step ELSE time#data.currentTime; LockBackingStore[handle]; -- let's be paranoid... IF mustCollapse THEN { -- this is a different Eval CollapseSample[handle, data]; data.currentTime _ time; -- this is the new time for the curent sample data.current.step _ mosSimTime; -- this is the new step for the curent sample }; IF wire.currentValue=NIL THEN data.current.value[0] _ wire.wireLevel ELSE LSToSample[wire.currentValue, data.current]; UnlockBackingStore[handle]; }; IF handle.traceChanges THEN { -- debug output wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec _ wire.wire]; UpdateDisplay[handle]; IO.PutF[handle.tsout, "%g_%g ", IO.rope[CoreFlat.WirePathRope[handle.cellType, wireKey^]], IO.rope[Ports.LevelSequenceToRope[Rosemary.WireValue[ handle.simulation, wireKey]]]]; }; }; RecordStateSample: PUBLIC PROC [handle: RoseDisplay, roseInstance: Rosemary.RoseCellInstance, value: Ports.LevelSequence, time: INT] ~ { IF value#NIL AND handle.recordDeltas THEN { data: LogData = NARROW [roseInstance.data]; mosSimTime: INT = handle.simulation.mosSimTime; mustCollapse: BOOL = IF handle.recordSteps THEN mosSimTime#data.current.step ELSE time#data.currentTime; IF data=NIL THEN ERROR; -- InitProc should be returning an LS first !!! LockBackingStore[handle]; -- let's be paranoid... IF mustCollapse THEN { -- this is a different Eval CollapseSample[handle, data]; data.currentTime _ time; -- this is the new time for the curent sample data.current.step _ mosSimTime; -- this is the new step for the curent sample }; LSToSample[value, data.current]; UnlockBackingStore[handle]; }; IF handle.traceChanges THEN { -- cell has changed state UpdateDisplay[handle]; IO.PutF[handle.tsout, "<%g> ", IO.rope[CoreFlat.CellTypePathRope[handle.cellType, roseInstance.instance]]]; }; }; PlotGraphData: TYPE ~ REF PlotGraphDataRec; PlotGraphDataRec: TYPE ~ RECORD [ source: REF ANY _ NIL, -- either RoseValues or RoseCellInstance bits: Ports.LevelSequence _ NIL, -- computed values will go in there clientData: REF ANY _ NIL, -- only for RoseCellInstances ropeProc: StateToRopeProc, -- only if display style is hexaV parts: SEQUENCE size: CARDINAL OF Sample -- basic information for reconstitution ]; roseGraphClass: PlotGraph.GraphClass _ NEW[PlotGraph.GraphClassRec _ [ enumerate: RoseGraphEnumerate]]; NewPlotGraphData: PROC [source: REF ANY, clientData: REF ANY, ropeProc: StateToRopeProc] RETURNS [pgd: PlotGraphData] ~ { partCount: NAT _ 0; bits: Ports.LevelSequence _ NIL; WITH source SELECT FROM rvl: Rosemary.RoseValues => { -- this plot is for a CoreFlat wire bitCount: NAT _ 0; UNTIL rvl=NIL DO val: Rosemary.RoseValue = rvl.first; bitCount _ bitCount+val.fieldWidth; partCount _ partCount + 1; rvl _ rvl.rest; ENDLOOP; bits _ NEW[Ports.LevelSequenceRec[bitCount]]; }; roseInstance: Rosemary.RoseCellInstance => { -- this plot is for an unexpanded cell partCount _ 1; }; ENDCASE => ERROR; -- internal bug, invalid argument pgd _ NEW[PlotGraphDataRec[partCount]]; pgd.source _ source; pgd.clientData _ clientData; pgd.ropeProc _ ropeProc; pgd.bits _ bits; }; InitPlotGraphData: PROC [handle: RoseDisplay, pgd: PlotGraphData, minStep: INT] RETURNS [effectiveStep: INT _ 0] ~ { WITH pgd.source SELECT FROM rvl: Rosemary.RoseValues => { -- this is a wire plot FOR part: NAT IN [0..pgd.size) DO -- go up the sample chain up to minStep data: LogData = NARROW[rvl.first.roseWire.data]; sample: Sample; IF data=NIL OR data.list=NIL THEN RETURN [LAST[INT]]; -- not initialized ! sample _ data.list.head; -- cannot be NIL ! IF sample.step<=minStep THEN { -- try going forwards UNTIL sample.next=NIL OR sample.next.step>minStep DO sample _ sample.next; ENDLOOP; }; effectiveStep _ MAX[effectiveStep, sample.step]; pgd.parts[part] _ sample; rvl _ rvl.rest; ENDLOOP; }; roseInstance: Rosemary.RoseCellInstance => { -- this is a cell state plot data: LogData = NARROW[roseInstance.data]; sample: Sample; IF data=NIL OR data.list=NIL THEN RETURN [LAST[INT]]; -- no info available sample _ data.list.head; -- cannot be NIL ! IF pgd.bits=NIL THEN pgd.bits _ NEW[Ports.LevelSequenceRec[sample.size]]; IF sample.step<=minStep THEN { -- try going forwards UNTIL sample.next=NIL OR sample.next.step>minStep DO sample _ sample.next; ENDLOOP; }; effectiveStep _ sample.step; pgd.parts[0] _ sample; -- there is exactly 1 part in a cell state pgd }; ENDCASE => ERROR; }; AssemblePlotGraphDataBits: PROC [pgd: PlotGraphData] RETURNS [nextStep: INT] ~ { firstFreeBit: NAT _ 0; bits: Ports.LevelSequence _ pgd.bits; nextStep _ LAST[INT]; FOR i: NAT IN [0..pgd.size) DO -- build up the bits sample: Sample = pgd.parts[i]; FOR bit: NAT IN [0..sample.size) DO bits[firstFreeBit+bit] _ sample.value[bit] ENDLOOP; firstFreeBit _ firstFreeBit+sample.size; IF sample.next#NIL THEN nextStep _ MIN[sample.next.step, nextStep]; ENDLOOP; IF nextStep=LAST[INT] THEN RETURN; -- nothing more to do... FOR i: NAT IN [0..pgd.size) DO -- advance samples for nextTime sample: Sample = pgd.parts[i]; IF sample.next#NIL AND sample.next.step=nextStep THEN pgd.parts[i] _ sample.next; ENDLOOP; }; GetValueAt: PROC [handle: RoseDisplay, pgd: PlotGraphData, time: INT] RETURNS [ls: Ports.LevelSequence _ NIL] ~ { atStep: INT _ LastStep[handle, time]; -- convert to step specification possibleStep: INT; LockBackingStore[handle]; -- critical here... possibleStep _ InitPlotGraphData[handle, pgd, atStep]; IF possibleStep>atStep THEN { -- try from disk... table: RedBlackTree.Table _ EnterSourceInRBT[NIL, pgd.source, atStep]; IF table#NIL THEN ReadSamplesUsingRBT[handle, table, atStep]; possibleStep _ InitPlotGraphData[handle, pgd, atStep]; IF possibleStep>atStep THEN RETURN [NIL]; -- we lost the battle... }; IF possibleStep<=atStep THEN { [] _ AssemblePlotGraphDataBits[pgd]; ls _ NEW [Ports.LevelSequenceRec[pgd.bits.size]]; Ports.CopyLS[from: pgd.bits, to: ls]; }; UnlockBackingStore[handle]; -- may now safely release }; WireTimeValue: PUBLIC PROC [handle: RoseDisplay, flatWire: CoreFlat.FlatWire, time: INT] RETURNS [value: Ports.LevelSequence] = { roseValues: Rosemary.RoseValues _ Rosemary.GetValues[handle.simulation, flatWire]; value _ GetValueAt[handle, NewPlotGraphData[roseValues, NIL, NIL], time]; }; StateTimeValue: PUBLIC PROC [handle: RoseDisplay, flatCell: CoreFlat.FlatCellType, time: INT] RETURNS [value: Ports.LevelSequence] = { roseInstance: Rosemary.RoseCellInstance = NARROW [ RefTab.Fetch[handle.simulation.coreToRoseInstances, flatCell].val]; IF roseInstance=NIL THEN ERROR Rosemary.NotInstantiated[]; value _ GetValueAt[handle, NewPlotGraphData[roseInstance, NIL, NIL], time]; }; DisplayPortLeafWires: PUBLIC PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.rootCellType] RETURNS [displayWires: CoreFlat.FlatWires] = { CompareFlatWires: List.CompareProc = { flat1: CoreFlat.FlatWire _ NARROW[ref1]; flat2: CoreFlat.FlatWire _ NARROW[ref2]; IF flat1.flatCell.path.length>flat2.flatCell.path.length THEN RETURN [greater]; IF flat1.flatCell.path.length RETURN [greater]; (NOT one) AND other => RETURN [less]; ENDCASE; ENDLOOP; IF flat1.flatCell.recastCount>flat2.flatCell.recastCount THEN RETURN [greater]; IF flat1.flatCell.recastCount digitVal _ 2*digitVal + 1; L => digitVal _ 2*digitVal; ENDCASE => someX _ TRUE; -- don't care about digitVal now... digitBitCount _ digitBitCount + 1; IF digitBitCount=bitsInDigit THEN { IF someX THEN scratch _ RefText.InlineAppendChar[scratch, 'X] ELSE scratch _ Convert.AppendCard[to: scratch, from: digitVal, base: 16, showRadix: FALSE]; bitsInDigit _ 4; digitBitCount _ 0; someX _ FALSE; digitVal _ 0; }; ENDLOOP; rope _ Rope.FromRefText[scratch]; }; AddGraph: PROC [handle: RoseDisplay, pgd: PlotGraphData, name: ROPE, style: PlotGraph.DrawingStyle, maxChars: NAT _ 8] ~ { plot: PlotGraph.Plot _ handle.plot; graph: PlotGraph.Graph _ NEW[PlotGraph.GraphRec _ [ class: roseGraphClass, data: pgd]]; axis: PlotGraph.Axis _ NEW[PlotGraph.AxisRec _ [ graphs: LIST [graph], bounds: [0.0, 0.0, 10.0, 6.0], name: name, style: style, maxChars: maxChars, axisData: [X: [ticks: 1.0, visible: TRUE], Y: [ticks: 1.0, visible: TRUE]] ]]; IF plot=NIL OR plot.data=NIL THEN { -- don't forget the plot might have been destroyed plot _ handle.plot _ PlotGraph.CreatePlot[handle.name]; PlotGraph.LockPlot[plot]; plot.lowerBounds _ [0.0, 0.0]; plot.upperBounds _ [Real.Float[handle.lastValidTime], 5.0]; plot.data _ handle; } ELSE PlotGraph.LockPlot[plot]; IF plot.axis#NIL THEN axis.bounds _ plot.axis.first.bounds; plot.axis _ CONS[axis, plot.axis]; PlotGraph.UnlockPlot[plot]; PlotGraph.RefreshPlot[plot: plot, eraseFirst: TRUE]; }; AddWireToPlot: PUBLIC PROC [handle: RoseDisplay, wire: CoreFlat.FlatWire] RETURNS [msg: ROPE _ NIL] = { roseValues: Rosemary.RoseValues _ Rosemary.GetValues[handle.simulation, wire ! Rosemary.NotInstantiated => GOTO NoSuchWire]; pgd: PlotGraphData _ NewPlotGraphData[roseValues, NIL, LSToRope]; name: ROPE _ CoreFlat.WirePathRope[handle.cellType, wire^]; IF Rope.Equal[Rope.Substr[name, 0, 7], "public."] THEN name _ Rope.Substr[name, 7]; IF pgd.bits.size=1 THEN AddGraph[handle, pgd, name, analog] ELSE AddGraph[handle, pgd, name, hexaV, (pgd.bits.size+3)/4]; EXITS NoSuchWire => msg _ "Not stored as a Rosemary wire"; }; stateToMaxCharsProcProp: PUBLIC ATOM _ $RoseStateToMaxCharsProc; stateToRopeProcProp: PUBLIC ATOM _ $RoseStateToRopeProc; AddStateToPlot: PUBLIC PROC [handle: RoseDisplay, flatCell: CoreFlat.FlatCellType, data: REF ANY _ NIL] RETURNS [msg: ROPE _ NIL] = { flat: CoreFlat.FlatCellType _ NEW[CoreFlat.FlatCellTypeRec _ flatCell^]; cellType: Core.CellType _ NIL; cellInstance: CoreClasses.CellInstance _ NIL; roseInstance: Rosemary.RoseCellInstance _ NIL; IF CoreFlat.BelowCutSet[handle.cellType, flatCell^, handle.cutSet] THEN RETURN [msg: "Below simulation cutset"]; [,cellInstance, cellType] _ CoreFlat.ResolveFlatCellType[handle.cellType, flat^]; UNTIL CoreFlat.CutSetMemberResolved[flat^, cellInstance, cellType, handle.cutSet] DO cellType _ CoreOps.Recast[cellType]; flat.recastCount _ flat.recastCount + 1; ENDLOOP; roseInstance _ NARROW [ RefTab.Fetch[handle.simulation.coreToRoseInstances, flat].val]; IF roseInstance#NIL THEN { charsProc: REF StateToMaxCharsProc _ NARROW [CoreProperties.InheritCellTypeProp[cellType, stateToMaxCharsProcProp]]; ropeProc: REF StateToRopeProc _ NARROW [CoreProperties.InheritCellTypeProp[cellType, stateToRopeProcProp]]; name: ROPE _ CoreFlat.CellTypePathRope[handle.cellType, flat^]; pgd: PlotGraphData _ NewPlotGraphData[roseInstance, data, IF ropeProc=NIL THEN LSToRope ELSE ropeProc^]; AddGraph[handle, pgd, name, hexaV, IF charsProc=NIL THEN (pgd.bits.size+3)/4 ELSE charsProc^[roseInstance.state, data]]; } ELSE msg _ "Not stored as a Rosemary cell instance"; }; RemoveFromPlot: PROC [handle: RoseDisplay, source: REF ANY, clientData: REF ANY] RETURNS [found: BOOL _ FALSE] ~ { plot: PlotGraph.Plot _ handle.plot; trail: PlotGraph.AxisList _ NIL; IF plot=NIL OR plot.data=NIL THEN RETURN; PlotGraph.LockPlot[plot]; FOR axis: PlotGraph.AxisList _ plot.axis, axis.rest UNTIL axis=NIL DO pgd: PlotGraphData _ NARROW[axis.first.graphs.first.data]; IF pgd.source=source AND pgd.clientData=clientData THEN { IF trail=NIL THEN plot.axis _ axis.rest ELSE trail.rest _ axis.rest; -- excise guilty axis found _ TRUE; EXIT; }; trail _ axis; ENDLOOP; PlotGraph.UnlockPlot[plot]; IF found THEN PlotGraph.RefreshPlot[plot: plot, eraseFirst: TRUE]; }; RemoveWireFromPlot: PUBLIC PROC [handle: RoseDisplay, wire: CoreFlat.FlatWire] RETURNS [found: BOOL _ FALSE] = { roseValues: Rosemary.RoseValues _ Rosemary.GetValues[handle.simulation, wire ! Rosemary.NotInstantiated => GOTO NoSuchWire]; found _ RemoveFromPlot[handle, roseValues, NIL]; EXITS NoSuchWire => NULL; }; RemoveStateFromPlot: PUBLIC PROC [handle: RoseDisplay, flatCell: CoreFlat.FlatCellType, data: REF ANY _ NIL] RETURNS [found: BOOL _ FALSE] = { roseInstance: Rosemary.RoseCellInstance = NARROW [ RefTab.Fetch[handle.simulation.coreToRoseInstances, flatCell].val]; IF roseInstance#NIL THEN found _ RemoveFromPlot[handle, roseInstance, data]; }; DeltaFinished: PUBLIC PROC [handle: RoseDisplay, time: INT] = { plot: PlotGraph.Plot _ handle.plot; LogTime[handle, time]; IF plot#NIL AND plot.data#NIL THEN { -- the plot viewer might have been destroyed ! oldUpper: REAL = plot.upperBounds.x-1.0; newUpper: REAL = Real.Float[time]; plot.upperBounds.x _ newUpper; PlotGraph.RefreshPlot[plot: plot, within: [oldUpper, 0.0, newUpper-oldUpper, 6.0]]; }; }; PGDStepProc: TYPE ~ PROC [pgd: PlotGraphData, rTime: REAL, notLast: BOOL]; EnumeratePGD: PROC [handle: RoseDisplay, pgd: PlotGraphData, from: REAL, to: REAL, eachStep: PGDStepProc, showSteps: BOOL] ~ { firstCur, lastCur, step: INT; -- steps for current time: firstCur<=step<=lastCur, in fromTime firstLogged: INT; -- first time time at which we succeed to get a sample fromTime: INT _ Real.Floor[MAX[from, 0.0]]; -- we should start roughly from here fractional: BOOL; -- TRUE means time is fractional, FALSE time is forced to INT firstCur _ FirstStep[handle, fromTime]; -- first step in fromTime lastCur _ LastStep[handle, fromTime]; -- last step in fromTime step _ firstCur; firstLogged _ InitPlotGraphData[handle, pgd, firstCur]; IF firstLogged>firstCur THEN { -- read more data from disk table: RedBlackTree.Table _ NIL; plot: PlotGraph.Plot = handle.plot; FOR al: PlotGraph.AxisList _ plot.axis, al.rest UNTIL al=NIL DO -- pass over all axis FOR gl: PlotGraph.GraphList _ al.first.graphs, gl.rest UNTIL gl=NIL DO -- and all graphs thisPGD: PlotGraphData = NARROW [gl.first.data]; table _ EnterSourceInRBT[table, thisPGD.source, firstCur]; -- collect source values ENDLOOP; ENDLOOP; IF table#NIL THEN ReadSamplesUsingRBT[handle, table, firstCur]; firstLogged _ InitPlotGraphData[handle, pgd, firstCur]; }; SELECT handle.plotStyle FROM allSteps => {showSteps _ TRUE; fractional _ TRUE}; waveSteps => {fractional _ TRUE}; noSteps => {showSteps _ FALSE; fractional _ FALSE}; ENDCASE => ERROR; IF step<=handle.simulation.mosSimTime THEN DO nextStep: INT = AssemblePlotGraphDataBits[pgd]; rTime: REAL; UNTIL step<=lastCur DO -- advance `fromTime' till it reaches step fromTime _ fromTime+1; firstCur _ lastCur+1; lastCur _ LastStep[handle, fromTime]; ENDLOOP; IF showSteps OR nextStep>lastCur THEN { -- show step, or last of time slot rTime _ Real.Float[fromTime]; IF fractional THEN rTime _ rTime - (lastCur-step)/Real.Float[lastCur-firstCur+1]; IF rTimehandle.simulation.mosSimTime THEN GO TO EndOfWindow; REPEAT EndOfWindow => eachStep[pgd, to, FALSE]; ENDLOOP; }; RoseGraphEnumerate: PlotGraph.GraphEnumerateProc = { ENABLE ABORTED => GOTO Aborted; -- in order to help debug... handle: RoseDisplay _ NARROW [plot.data]; pgd: PlotGraphData _ NARROW [graph.data]; low: REAL = MAX [bounds.x, 0]; high: REAL = handle.lastValidTime+1; -- bounds.w is incorrect in PlotGraph LockBackingStore[handle]; -- critical here... WITH pgd.source SELECT FROM rvl: Rosemary.RoseValues => { -- this plot is for a CoreFlat wire value: REAL; notFirst: BOOL _ FALSE; EachAnalogStep: PGDStepProc ~ { IF notFirst THEN [] _ eachPoint[x: rTime, y: value] ELSE notFirst _ TRUE; IF notLast THEN { value _ SELECT pgd.bits[0] FROM L => 0.0, X => 2.5, H => 5.0, ENDCASE => ERROR; [] _ eachPoint[x: rTime, y: value] }; }; EachWireStep: PGDStepProc ~ { value: ROPE = pgd.ropeProc[NIL, pgd.bits, pgd.clientData]; [] _ eachPoint[x: rTime, y: 0.0, rope: value] }; IF pgd.bits.size=1 THEN EnumeratePGD[handle, pgd, low, high, EachAnalogStep, TRUE] ELSE EnumeratePGD[handle, pgd, low, high, EachWireStep, FALSE]; }; roseInstance: Rosemary.RoseCellInstance => { -- this plot is for an unexpanded cell EachStateStep: PGDStepProc ~ { value: ROPE = pgd.ropeProc[roseInstance.state, pgd.bits, pgd.clientData]; [] _ eachPoint[x: rTime, y: 0.0, rope: value] }; EnumeratePGD[handle, pgd, low, high, EachStateStep, FALSE]; }; ENDCASE => ERROR; UnlockBackingStore[handle]; -- may now safely release EXITS Aborted => UnlockBackingStore[NARROW [plot.data]]; }; Entry: TYPE ~ REF EntryRep; LevelSeen: TYPE ~ RECORD [wasH, wasL: BOOL]; EntryRep: TYPE ~ RECORD [ pos: INT _ -1, roseWire: Rosemary.RoseWire, -- to print the wire name in case of error sample: Sample, -- to read the sample seen: PACKED SEQUENCE size: CARDINAL OF LevelSeen ]; MergeSample: PROC [entry: Entry, sample: Sample] RETURNS [allSeen: BOOL _ TRUE] ~ { FOR i: CARDINAL IN [0..entry.size) DO SELECT sample.value[i] FROM H => { entry.seen[i].wasH _ TRUE; allSeen _ allSeen AND entry.seen[i].wasL; }; L => { entry.seen[i].wasL _ TRUE; allSeen _ allSeen AND entry.seen[i].wasH; }; ENDCASE => allSeen _ allSeen AND entry.seen[i].wasH AND entry.seen[i].wasL; ENDLOOP; }; GetEntryKey: RedBlackTree.GetKey ~ { RETURN [data]; -- keys are same as data... }; CompareEntries: RedBlackTree.Compare ~ { e1: Entry = NARROW [k]; e2: Entry = NARROW [data]; RETURN [Basics.CompareInt[e1.pos, e2.pos]]; }; CheckCoverage: PUBLIC PROC [handle: RoseDisplay] RETURNS [ok: BOOL] ~ { InsertInRBT: RefTab.EachPairAction ~ { wire: Rosemary.RoseWire = NARROW[val]; data: LogData = NARROW [wire.data]; nBits: CARDINAL = data.current.size; entry: Entry _ NEW [EntryRep[nBits]]; entry.pos _ data.lastFilePos; entry.roseWire _ wire; entry.sample _ NEW [SampleRec[nBits]]; FOR i: CARDINAL IN [0..nBits) DO entry.seen[i] _ [FALSE, FALSE] ENDLOOP; IF MergeSample[entry, data.current] THEN RETURN; -- all bits have seen H and L IF data.previous#NIL AND MergeSample[entry, data.previous] THEN RETURN; -- H,L seen SELECT TRUE FROM entry.pos<0 => ReportEntry[entry]; -- we've seen all about it, and it fails RedBlackTree.LookupNode[table, entry]=NIL => RedBlackTree.Insert[table, entry, entry]; ENDCASE => NULL; -- discard the entry, it's already in the RBT somehow ... }; ReportEntry: PROC [entry: Entry] ~ { ReportAtomic: PROC [wire: Core.Wire] ~ { msg: ROPE; h, l: BOOL; [wasH: h, wasL: l] _ entry.seen[bit]; bit _ bit+1; SELECT TRUE FROM h AND l => RETURN; -- good bit h => msg _ "L"; l => msg _ "H"; ENDCASE => msg _ "H nor L"; flatWire.wire _ wire; handle.tsout.PutF["Wire %g does not go through %g\n", IO.rope[CoreFlat.WirePathRope[handle.cellType, flatWire]], IO.rope[msg]]; ok _ FALSE; -- at least one bit in error }; flatWire: CoreFlat.FlatWireRec _ entry.roseWire.wire; wireSize: NAT = CoreOps.WireBits[flatWire.wire]; bit: NAT _ 0; IF entry.roseWire.currentValue=NIL AND entry.roseWire.wireDrive=infinite THEN RETURN; IF wireSize#entry.size THEN ERROR; -- we're in BIG trouble IF wireSize>1 THEN CoreOps.VisitRootAtomics[flatWire.wire, ReportAtomic] ELSE ReportAtomic[flatWire.wire]; }; table: RedBlackTree.Table _ RedBlackTree.Create[GetEntryKey, CompareEntries]; LockBackingStore[handle]; -- the whole procedure assumes the backing store does not change FlushWBuff[handle, 0]; -- ensure we are really at end of file and the buffer is empty ok _ TRUE; -- until proven false ... [] _ RefTab.Pairs[x: handle.simulation.coreToRoseWires, action: InsertInRBT]; -- build RBT WHILE RedBlackTree.Size[table]#0 DO -- Read the backing file backwards entry: Entry _ NARROW [RedBlackTree.LookupLargest[table]]; node: RedBlackTree.Node _ RedBlackTree.Delete[table, entry]; entry.pos _ ReadSample[handle.ps, entry.pos, entry.sample, 0]; -- step is ignored IF MergeSample[entry, entry.sample] THEN LOOP; -- entry has seen H and L, discard IF entry.pos>=0 THEN RedBlackTree.InsertNode[table, node, entry] -- keep entry active ELSE ReportEntry[entry]; -- no more samples, but disagreement ENDLOOP; IO.SetIndex[handle.ps, handle.filePos]; -- go back to end of file UnlockBackingStore[handle]; }; BackingFileStats: PROC [handle: RoseDisplay] RETURNS [nSamples: INT, avgPosLen: REAL, avgStepLen: REAL, avgLSLen: REAL, compression: REAL] ~ { InsertInRBT: RefTab.EachPairAction ~ { wire: Rosemary.RoseWire = NARROW[val]; data: LogData = NARROW [wire.data]; nBits: CARDINAL = data.current.size; sampleList: SampleList _ NEW [SampleListRec _ [head: NEW [SampleRec[nBits]], beforeHeadPos: data.lastFilePos, inTable: FALSE]]; SELECT TRUE FROM data.lastFilePos<0 => NULL; -- nothing stored on file for this entry RedBlackTree.LookupNode[table, sampleList]=NIL => RedBlackTree.Insert[table, sampleList, sampleList]; ENDCASE => NULL; -- discard the entry, it's already in the RBT somehow ... }; Length29: PROC [s: IO.STREAM] RETURNS [size: INT] ~ { b: BYTE _ IO.GetByte[s]; SELECT TRUE FROM Basics.BITAND[b, 00080H]=0 => { -- single byte size _ 1; }; Basics.BITAND[b, 00040H]=0 => { -- 2 bytes size _ 2; [] _ IO.GetByte[s]; }; Basics.BITAND[b, 00020H]=0 => { -- 3 bytes size _ 3; [] _ IO.GetByte[s]; [] _ IO.GetByte[s]; }; ENDCASE => { -- 4 bytes size _ 4; [] _ IO.GetByte[s]; [] _ IO.GetByte[s]; [] _ IO.GetByte[s]; }; }; table: RedBlackTree.Table _ RedBlackTree.Create[RBTGetKey, RBTCompare]; nLSBytes: INT _ 0; nPosBytes: INT _ 0; nStepBytes: INT _ 0; totalBytes: INT; nSamples _ 0; LockBackingStore[handle]; -- the whole procedure assumes the backing store does not change FlushWBuff[handle, 0]; -- ensure we are really at end of file and the buffer is empty totalBytes _ handle.filePos; [] _ RefTab.Pairs[x: handle.simulation.coreToRoseWires, action: InsertInRBT]; -- build RBT WHILE RedBlackTree.Size[table]#0 DO -- Read the backing file backwards sampleList: SampleList _ NARROW [RedBlackTree.LookupLargest[table]]; node: RedBlackTree.Node _ RedBlackTree.Delete[table, sampleList]; IO.SetIndex[handle.ps, sampleList.beforeHeadPos]; nSamples _ nSamples+1; nLSBytes _ nLSBytes+sampleList.head.size; nPosBytes _ nPosBytes+Length29[handle.ps]; nStepBytes _ nStepBytes+Length29[handle.ps]; sampleList.beforeHeadPos _ ReadSample[handle.ps, sampleList.beforeHeadPos, sampleList.head, 0]; -- step is ignored IF sampleList.beforeHeadPos>=0 THEN RedBlackTree.InsertNode[table, node, sampleList]; ENDLOOP; IO.SetIndex[handle.ps, handle.filePos]; -- go back to end of file UnlockBackingStore[handle]; avgPosLen _ Real.Float[nPosBytes]/Real.Float[nSamples]; avgStepLen _ Real.Float[nStepBytes]/Real.Float[nSamples]; avgLSLen _ Real.Float[nLSBytes]/Real.Float[nSamples]; compression _ Real.Float[8*nSamples+nLSBytes]/Real.Float[nPosBytes+nStepBytes+nLSBytes]; IF nPosBytes+nStepBytes+nLSBytes#totalBytes THEN ERROR; -- real strange... }; END. -ΐRosemaryUserBackingImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Jean-Marc Frailong December 28, 1987 1:41:36 pm PST Management of backing storage and plotting functions for RosemaryUser. Backup file management Principles Due to space & time constraints, backup file management is quite messy. The main ideas are: - samples are kept in memory only if needed (i.e. if they are plotted). Samples are time-stamped with the MosSim step number. Relationship between `Eval time' and steps is achieved through an array in the handle that keeps track of the endpoints of each Eval. This permits to support time-logging or step-logging, as well as time-plotting or step-plotting. NOTE: In the current version, samples are never removed from memory. This would be easy it it appears worthwile. - two samples are always kept in memory per wire in order to allow collapsing identical values (c.f. LogData). The information is attached as data field to RoseWires and RoseInstances. - samples on disk are chained backwards through disk pointers to accelerate recovery. Only deltas in file position and time are kept on disk, using a variable length encoding, to reduce storage. The exact format per sample is , , where DPos = file position of sample - file position of previous sample for same object, 0 if this was the 1st sample for the object DStep = step# for next sample - step# for this sample level(s) = value of level, 1 per byte (this could be improved) Both DPos and DStep are represented as 29-bit variable-length numbers (c.f. Write29Bits). The current implementation has the following problems: - It would be real fine to save the drive with which a wire has been driven, in order to distinguish X from Z (driven to garbage from tri-stated). Two problems for that: RoseWires that have LS attached do not carry the drive around (Rick says that can be twiddled around), and PlotGraph does not provide the capacity to display that information. The nice thing is that the cost in storage/disk is very small... Types The object has the specified value in the range [sample.step..sample.next.step) The in-memory representation of a list of samples. The samples back in time may still be on disk, starting at beforeHeadPos. SampleLists are created only when necessary. A LogData is attached to all RoseWires and to RoseInstances that require logging. The following assertions must hold: - current.next = NIL - current.step = value of MosSimStep at last call to Update - current will never be modified once step of Update call > current.step - previous is the sample that was valid just before current. It is necessary to allow collapsing curent with a previous value. previous has not yet been written to disk! - if previous#NIL, then previous.next=current - if list#NIL, then samples are kept in memory. Then, either list.head=previous=NIL, or previous may be reached by following next links from list.head (possibly 0 times!). Backing store physical access -- all procs require backing store lock Warns of the intent of writing a certain number of bytes on file Write current contents of wBuff on file & check there is room enough for nBytes Write a 29-bits integer as 1, 2, 3 or 4 bytes according to size. This a hack to reduce the disk size of backing files... The encoding scheme is (MSB always written first): 0XXXXXXX => delta IN [0..128) 10XXXXXX XXXXXXXX => delta IN [0..16384) 110XXXXX XXXXXXXX XXXXXXXX => delta IN [0..2097152) 111XXXXX XXXXXXXX XXXXXXXX XXXXXXXX => delta IN [0..536870912) IF Basics.BITAND[v.lo, 00080H]#0 THEN ERROR; IF Basics.BITAND[v.lo, 0C000H]#0 THEN ERROR; IF Basics.BITAND[v.lo, 0C000H]#08000H THEN ERROR; IF Basics.BITAND[v.hi, 000E0H]#0 THEN ERROR; IF Basics.BITAND[v.hi, 000E0H]#000C0H THEN ERROR; IF Basics.BITAND[v.hi, 0E000H]#0 THEN ERROR; IF Basics.BITAND[v.hi, 0E000H]#0E000H THEN ERROR; Read a 29-bits integer using the format emitted by Write29Bits IF v.lc>=limit1 THEN ERROR; IF v.lc>=limit2 THEN ERROR; IF v.lc>=limit3 THEN ERROR; IF v.lc>=limit4 THEN ERROR; Write the specified sample at the current file position, using prvPos as backpointer, and return in pos the fileposition at which this sample was read. The initial and final file position are at EOF. Must be called under backing store lock! Read a sample from the specified location on the file. prvPos is the pointer to the previous sample in the chain. prv<0 means this is the 1st sample in chain. Refer to readSample for details. Must be called under backing store lock! Backing store logical access -- all procs require backing store lock Get the key for a SampleList in the RedBlackTree: it's identity... Compare key & data in the RedBlackTree Add the specified roseValues/roseInstance to the table so that they will be fetched from disk up to the required minimum time. Just some sugar on top of EnterLogDataInRBT. min is expressed in steps. Must be called under backing store lock! Read all the samples described in the RBT, going backwards & in order through the file. min is expressed in steps. Must be called under backing store lock! Time management Principles: The timeSteps array (2-level due to stupid 32K array restriction) is a mapping from time value to last step number for that time value. The logic has a deep built-in assumption that time 0 starts at step 0. TimeSteps entries are valid only in the range [0..handle.lastValidTime]. The samples in ]timeSteps[t-1]..timeSteps[t]] are in the time slot t. Only procedures in this section should refer to handle.timeSteps Note time as new lastValidTime & add item to timeSteps array Return the last step number in [time..time+1) Return the first step number in [time..time+1) Sampling Copy the value of the LevelSequence into the sample's data field All is initialized properly except for the bits of data.current. current.time is forced to 0 since NewLogData is called only at Init time. Create the Wire data and initialize it properly... Initializing instance data is tricky since InitializeDeltas is called after Rosemary.Initialize. The technique is to store (a copy) of the returned LS as data field of the RoseCellInstance and to do the conversion here... Must be called under backing store lock ... File pointer is assumed to be at EOF. This procedure is not concerned with time/step stamping. Returns TRUE iff the two samples have different value fields (size must be same!) Maintain the wire data field when the wire is updated. At this point, we assume the file pointer to be at EOF Maintain the wire data field when the rose instance is updated. This looks a lot like RecordDelta... At this point, we assume the file pointer to be at EOF Plotting Types Known misfeatures and how to improve on them: - PlotGraph almost always calls the GraphEnumerateProc with bounds=infinite (on fact, due to a PlotGraph bug, empty). As a result, when a new wire is displayed, it is always read back to the origin of times. It is not possible from the client code to infer the correct bounds (gathering them from the viewer will hamper IP generation). This should be fixed in PlotGraph (anyway, there are other things to be fixed there...). - It would be more efficient to add multiple wires to the plot at once than one at a time because refreshing requires reading the disk. Either have AddWiresToPlot instead of AddWireToPlot, or (better) leave the responsability of refreshing to the client. - It would be faster is InitPlotGraphData could avoid rewinding back to the beginning of times. This could be achieved by adding a "currentTime" field to the pgd, but this raises serious questions when the simulation is re-initialized because we then must invalidate all pgd's. This is the data structure that permits to recompute values of flatwires at each time Value recovery and assembly Create the PlotGraphData with the right sizes for the RoseValues. The contents of parts are left to NIL. The bits field initialization is deferreed for roseInstances to InitPlotGraphData. The bits LS is not setup yet as we don't know the size... It will be setup the 1st time we find a non-NIL sample on the instance... Initialize pgd parts so that a first sample is valid at the required step number. Assumes that the corresponding values have been made resident early enough using EnterSourceInRBT/ReadSamplesUsingRBT. Returns the step at which the value is correct (may be >minStep, LAST[INT] means no value may be established). Must be called under backing store lock! The bits field of pgd is initialized here if we have the information. Assemble the bits for the current step, and position everything for the next step. Returns LAST[INT] if the computed value is the last one. pgd.bits must have been initialized. Must be called under backing store lock! Update the pgd to get a decent value in bits for time, return NIL if it's impossible. Return the value of a wire at a given time. Will return NIL if no value may be established for the required time. Return the value of a wire at a given time. Will return NIL if no value may be established for the required time. Client plotting interface This is restricted version of Ports.LSToRope that does not expand partial X's down to bit level. This is better for plotting as it guarantees that the resulting rope has a constant size. rope _ Ports.LSToRope[value]; bitsInDigit _ IF size MOD 4 = 0 THEN 4 ELSE size MOD 4; Add a graph to the plot For reasons of efficiency, this procedure should NOT refresh the plot because refreshing the plot forces reading the backing store, and the more there is to do at once the better... For reasons of efficiency, this procedure should NOT refresh the plot because refreshing the plot forces reading the backing store, and the more there is to do at once the better... PlotGraph service Enumerate the items in the pgd in the time interval [from..to] (those are the plot bounds), call eachTime for each sample The details shown on the plot are specified by handle.plotStyle: allSteps => everything is shown in full detail, may be unreadable, fractional time waveSteps => show steps only if showSteps is TRUE (waveforms), fractional time noSteps => never show steps, force all display point on integer time boundaries Must be called under backing store lock -- At this point, firstLogged contains the 1st really available point of data. [plot: Plot, graph: Graph, bounds: Rectangle, eachPoint: PointProc, data: REF ANY] Odds and ends Types Coverage checking Add information from sample into entry, return TRUE iff the result has allSeen. Get the key for a SampleList in the RedBlackTree: it's identity... Compare key & data in the RedBlackTree Returns TRUE iff all nodes in the simulation reach the H and L levels. Nodes that do not are printed on the simulation log. All information is recovered from the backing file. The algorithm is: - build an RBT containing all of the simulations roseWires - perform an algorithm similar to ReadSamplesUsingRBT: - when a wire has been both H and L, remove it from RBT - when a wire reaches the starting point and it has not been through both values, log a message & remove it from RBT Report on the Rosemary typescript information about this wire not seing H and L The algorithm to find the correct flat wire for structured wires follows exactly the method used in RosemaryImpl.InitWire. Backing file statistics Compute some statistics on the backing file. Used strictly for debugging & informational purposes. The algorithm is: - build an RBT containing all of the simulations roseWires - Read all samples backwards & compute stats on the fly. The code uses the same data structures (SampleList) as ReadSamplesUsingRBT, but does things by hand to avoid swamping memory. Κ*.˜codešœ™Kšœ<™™>Kšœ œ œJ™YK™——™6K™š——™Kšœœœ ˜šœ œœ˜Kšœœ˜KšœœœœΟc1˜HKšœœœœ ˜4Kšœ˜K™OK™—Kšœ œœ˜%šœœœ˜Kšœ’;˜IKšœœ’E˜YKšœ œœ’6˜LKšœ˜Kšœ©™©K˜—Kšœ œœ ˜šœ œœ˜Kšœ œ’/˜FKšœœ’G˜_Kšœœ’˜.Kšœ œ’˜0Kšœœ’D˜ZJ˜™uJšœ™Jšœ;™;JšœH™HJ™©Jšœœ™-Jšœ œCœX™«———™EšΟnœœœ˜1Kš œœ œœ œ˜,Kšœ œ˜Kšœ˜K˜—š£œœœ˜3Kšœ œ˜Kš œ ˜Kšœ˜K˜—š£ œœœ˜6K™@Kšœœœ˜Kšœ!œ˜CK˜K˜—š£ œœœ˜7K™OKšœ#˜%Kšœœ$˜IK˜K˜K˜—š£œœœœ˜:Kšœ6œ˜AK˜K˜—š£ œœœ˜9Kšœx™xšœœ™2Kšœœ œ ™Kšœœœ œ ™(Kš œœœœ œ ™3Kš œœœœœ œ™>—Kšœœ˜Kšœœ˜Kšœœ ˜Kšœœ˜ Kšœœ˜%Kšœ˜Kšœ ˜ šœ˜šœ ’˜!Kšœœœœ™,Kšœ˜K˜"Kšœ˜—šœ ’˜Kšœœœœ™,Kšœœ˜"Kšœœœœ™1Kšœ˜Kšœ˜K˜"Kšœ˜—šœ ’˜Kšœœœœ™,Kšœœ˜"Kšœœœœ™1Kšœ˜Kšœ˜Kšœ˜K˜"Kšœ˜—šœ ’˜Kšœœœœ™,Kšœœ˜"Kšœœœœ™1Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜"Kšœ˜—Kšœœ’ ˜—K˜K˜—š £ œœœœœ œ˜:K™>Kšœ˜K˜ Kšœœ ˜šœœ˜šœœ’˜1Kšœœœ™Kšœ˜—šœœ’ ˜-Kšœœœ˜7Kšœœ ˜Kšœœœ™Kšœ˜—šœœ’ ˜-Jšœœ˜#Jšœœ ˜Jšœœ ˜Kšœœœ™Kšœ˜—šœ’ ˜Kšœœœ˜7Jšœœ ˜Jšœœ ˜Jšœœ ˜Kšœœœ™Kšœ˜——Kšœ˜K˜K˜—š £ œœ/œ œœœ˜jKšœΓœ™ΗKš‘(™(Kšœ œ˜Kšœ"’+˜MKšœ˜Kšœ œ ˜šœ˜Kšœ˜Kšœ œœ’˜8Kšœ˜—Kšœ˜Kšœ-’˜?šœœœ˜!Kšœœ˜&Kšœ˜—Kšœ,˜,K˜K˜—š£ œœœœœœœ œ˜`KšœΏ™ΏKš‘(™(Kšœ œ˜Kšœ˜Kšœ˜Kšœ œ ˜šœ˜Kšœ˜Kšœ œœ’#˜;Kšœ˜—Kšœ%˜%šœœœ˜Kšœœœ ˜#Kšœ˜—K˜——™Dš£ œ˜"KšœB™BKšœ ’˜*Kšœ˜K˜—š£ œ˜$K™&Kšœœ˜Kšœœ˜"Kšœ?˜EKšœ˜K˜—š £œœ%œœœœ#˜|Kšœ«™«K™Kš‘(™(š£œœ˜+šœœœ’&˜9Kšœ˜šœœœ’˜+šœœ˜Kš œœœœœ˜@Kšœ ˜ Kšœ œ˜—K˜K˜—Kš œœœœ’˜OKšœ œœ7˜Kšœœœ’)˜DKšœ*˜*Kšœœ˜Kšœ˜—Kšœ˜—K˜—Kšœ˜šœ ˜šœœœœ’˜KKšœœ˜4Kšœ’˜'Kšœ˜—Kšœ=œ˜YKšœœ˜—K˜K˜—š£œœ7œ˜XKšœ&œ.™WK™Kš‘(™(Kšœœœ ˜Kšœ’>˜Uš œœœœ˜5Kšœœ%˜>Kšœ;˜;Kšœœ˜1KšœT˜TKšœ-’˜FKšœœœ,’˜|Kšœœ’˜3Kšœ˜—Kšœ#’˜>K˜——™šœ ™ Kšœb‘œW‘œT™—K™Ešœ@™@K™——š£œœœ˜2Kšœ<™Kšœ@™@Kšœœœ’+˜NKš œœœœœ˜?K˜K˜—š£ œœ œœ˜9KšœŠ™ŠKšœœ˜Kšœ˜Kšœ œ’˜/Kšœœ’˜*Kšœ˜Kšœœ˜%Kšœœ˜Kšœ˜K˜K˜—š£œœœ˜7š£ œ˜(K™2Kšœœ˜&Kšœœœ˜%Kšœœœœ˜IKšœœ'˜5Kšœ-˜1Kšœ˜K˜—š£œ˜,KšœF‘œ’™έKšœ*œ˜7Jšœœ˜5šœœœ’˜'Kšœ$˜$Kšœ˜Kšœ˜Kšœ˜—K˜—Kšœ’˜4K˜Kšœœœ"˜:Kšœ’-˜FKšœ œœ œ4˜XKšœœ’0˜QK˜KšœO˜OKšœW˜WKšœ’2˜NKš œ œœœœ6œ˜lK˜K˜—š£œœ)˜=KšœQ™QKšœ‘œ#™8Kšœœ˜š£ œœœœ˜6KšœœE™Qšœœœ ˜"Kšœœœœ˜-Kšœ˜—Kšœœ˜K˜—šœœ˜šœœ’?˜VK˜Kšœœ˜%Kšœ"˜"Kšœœ’˜0Kšœ˜—šœ/’˜GKšœ[˜[Kš œœ œœœœ˜SKšœA’˜OKšœœ’(˜AKšœ˜—Kšœœ’!˜2—K˜K˜—š£ œœœ6œ˜VK™6šœœ’˜2Kšœœ ˜#Kšœœ˜Kšœ œ ˜/Kš œœœœœ˜hKšœ’˜1Kšœ3™6šœœ’˜2Kšœ˜Kšœ’-˜FKšœ ’-˜MKšœ˜—Kšœœœ'˜DKšœ-˜1Kšœ˜K˜—šœœ˜-Kšœœ#˜CKšœ˜Kšœœ9œS˜°Kšœ˜—K˜K˜—š£œœœbœ˜ˆKšœK‘œ™dšœœœœ˜+Kšœœ˜+Kšœ œ ˜/Kš œœœœœ˜hKš œœœœ’/˜GKšœ’˜1Kšœ3™6šœœ’˜2Kšœ˜Kšœ’-˜FKšœ ’-˜MKšœ˜—Kšœ ˜ Kšœ˜Kšœ˜—šœœ’˜7Kšœ˜KšœœJ˜kKšœ˜—K˜———™™™-Kšœΐœf™¨K™ώKšœ•™•K™—Kšœœœ˜+šœœœ˜!Kšœœœœ’(˜?Kšœœ’#˜DKšœ œœœ’˜8Kšœ’!˜K˜Kšœ œœœ˜QKšœ˜—K˜K˜—š £ œœ1œœœ˜qKšœ>œ™UKšœœ’ ˜FKšœœ˜Kšœ’˜-Kšœ6˜6šœœ’˜1Kšœ-œ˜FKšœœœ,˜=Kšœ6˜6Kš œœœœ’˜BK˜—šœœ˜Kšœ$˜$Kšœœ)˜1Kšœ%˜%Kšœ˜—Kšœ’˜5K˜K˜—š £ œœœ:œœ!˜Kšœ8œ6™qKšœR˜RJšœ8œœ ˜IK˜K˜—š £œœœ>œœ!˜†Kšœ8œ6™qKšœ*œF˜vKšœœœœ˜:Jšœ:œœ ˜KK˜——™š£œœœSœ'˜’K˜š£œ˜&Kšœœ˜(Kšœœ˜(Kšœ7œœ ˜OKšœ7œœ˜Lšœœ!˜GKšœœ˜(Kšœœ˜*šœœ˜Kšœœœ œ ˜(Kšœœœ œ˜%Kšœ˜—Kšœ˜—Kšœ7œœ ˜OKšœ7œœ˜LKšœs˜yKšœ˜K˜—š£ œ˜$šœ4œ˜œœœœœœ˜…Kšœ1œ™΅Jšœœ'˜HJšœœ˜Jšœ)œ˜-Kšœ*œ˜.KšœAœœ"˜pJšœQ˜QšœM˜TKšœ$˜$Kšœ(˜(Kšœ˜ —KšœœB˜Wšœœœ˜Jšœ œœI˜tJšœ œœE˜kJšœœ5˜?Kš œ:œ œœ œ ˜hKš œ#œ œœœ'˜xKšœ˜—Kšœ0˜4K˜K˜—š£œœœœœœœ œœ˜rK˜#Kšœœ˜ Jš œœœ œœœ˜)K˜šœ1œœ˜EKšœœ˜:šœœœ˜9Kš œœœœ’˜ZKšœœ˜ Kšœ˜K˜—K˜ Kšœ˜—Kšœ˜Kšœœ/œ˜BK˜K˜—š £œœœ0œ œœ˜pKšœkœ ˜|Kšœ+œ˜0š˜Kšœœ˜—K˜K˜—š£œœœ>œœœœ œœ˜ŽKšœ*œF˜vKšœœœ4˜LK˜K˜——™š£ œœœœ˜?Kšœ#˜#Kšœ˜š œœœ œœ’.˜SKšœ œ˜(Kšœ œ˜"Kšœ˜KšœS˜SK˜—K˜K˜—š œ œœœ œ˜JK˜—š £ œœ1œœ$œ˜~Kšœ&‘œO™y™@K™RKšœN™NK™O—Kš‘'™'Kšœœ’?˜]Kšœ œ’6˜HKšœ œœ’$˜PKšœ œ’=˜OKšœ(’˜AKšœ&’˜>Kšœ˜Kšœ7˜7šœœ’˜:Kšœœ˜ Kšœ#˜#š œ-œœœ’˜Uš œ4œœœ’˜XKšœœ˜0Kšœ;’˜SKšœ˜—Kšœ˜—Kšœœœ.˜?Kšœ7˜7Kšœ˜—Kš’N™Nšœ˜Kšœœœ˜2Kšœœ˜!Kšœœœ˜3Kšœœ˜—šœ$œ˜-Kšœ œ"˜/Kšœœ˜ šœœ’*˜AKšœ˜Kšœ˜Kšœ%˜%Kšœ˜—šœ œœ’"˜JKšœ˜Kšœ œ?˜QKš œ œœœœœ ˜CKšœ˜—K˜Kšœ#œœœ ˜<š˜Kšœ!œ˜(—Kšœ˜—K˜K˜—š£œ"˜4KšœJœœ™RKšœœœ ’˜˜IKšœ-˜-K˜—Kšœ4œ˜;Kšœ˜—Kšœœ˜—Kšœ’˜5š˜Kšœœ˜2—K˜K˜———™ ™Kšœœœ ˜Kšœ œœœ˜,šœ œœ˜Kšœœ˜Kšœ’*˜GKšœ’˜%Jšœœœœ ˜1Kšœ˜——™š £ œœ œ œœ˜SKšœ/œ™Ošœœœ˜%šœ˜šœ˜Kšœœ˜Kšœœ˜)K˜—šœ˜Kšœœ˜Kšœœ˜)K˜—Kšœœœ˜K—Kšœ˜—K˜K˜—š£ œ˜$KšœB™BKšœ ’˜*Kšœ˜K˜—š£œ˜(K™&Kšœ œ˜Kšœ œ˜Kšœ%˜+Kšœ˜K˜—š£ œ œœœ˜GKšœœ£™―™Kšœ œ,™:šœ6™6Kšœ4™7Kšœq™t——š£ œ˜&Kšœœ˜&Kšœœ ˜#Kšœœ˜$Kšœœ˜%Kšœ˜K˜Kšœœ˜&Kšœœœ œœœœ˜HKšœ"œœ’˜NKš œœœ#œœ’ ˜Sšœœ˜Kšœ#’(˜KKšœ&œ-˜VKšœœ’9˜J—K˜—š£ œœ˜$K™OK™zš£ œœ˜(Kšœœ˜ Kšœœ˜ Kšœ%˜%Kšœ ˜ šœœ˜Kšœœœ’ ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ6œ9œ ˜Jšœœ’˜(K˜—Kšœ5˜5Kšœ œ#˜0Kšœœ˜ Kš œœœ#œœ˜UKš œœœ’ Πbc’˜:Kšœ œ6˜HKšœ˜!K˜—KšœM˜MKšœ’@˜ZKšœ’>˜UKšœœ’˜$KšœN’ ˜Zšœœ’"˜FKšœœ%˜:Kšœ<˜˜UKšœ˜KšœN’ ˜Zšœœ’"˜FKšœœ%˜DKšœA˜AKšœ/˜1Kšœ˜Kšœ)˜)Kšœ*˜*Kšœ,˜,Kšœ`’˜rKšœœ2˜UKšœ˜—Kšœ&’˜AKšœ˜Kšœ7˜7Kšœ9˜9Kšœ5˜5KšœX˜XKšœ*œœ’˜JK˜K˜———K˜Kšœ˜—…—†„ήr