ModelHelpers Module
Types and nested modules
| Type/Module | Description |
Functions and values
| Function or value | Description |
|
|
|
|
|
The complete drawing state, serialised with the same library that writes .dgm files. SimpleJson round-trips F# maps - including the ones keyed by a record or a single-case DU, which it writes as an array of [key, value] pairs rather than as a JSON object - along with sets, options and bigints. So there is no need to reduce anything by hand: this is every symbol, wire, port and port map exactly as the model holds it. BusWireT.Model is the largest part of the model that contains no functions at all. SheetT.Model above it holds PopupViewFunc and a ChildProcess, and its undo and redo lists are whole models, which would multiply the dump by the undo depth. Returns a message rather than throwing if serialisation fails, so that a type SimpleJson cannot represent degrades to a readable error instead of breaking the caller. Fable only: SimpleJson's reflection does not work under .NET, which does not matter for renderer debug code.
|
Full Usage:
circuitCheckIsNeeded model (arg2, arg3)
Parameters:
Model
arg1 : Component list
arg2 : Connection list
Returns: bool
|
Should the Simulation tab ask for a new verdict? True when the stored one is missing or no longer describes the design, and no check is already on its way. The CheckPending test comes first, and not only to save the comparison: this is asked while rendering, and a render that asked again for a check already scheduled would be answered with another render, and so on without ever reaching the check.
|
Full Usage:
clampSelection index entries
Parameters:
int
entries : 'a list
Returns: int
|
|
|
Has the open sheet changed since it was last saved? Asked freshly rather than read off Model.SavedSheetIsOutOfDate, which is only RECOMPUTED on draw block messages: a change made by anything else - the Properties pane setting a sheet's array settings or its parameters - leaves that flag saying what was true before it. Switching sheets saves the sheet being left, and reading a stale flag there drops the change. Two things count as changed, and the first is why the canvas alone will not do: a sheet is more than what is drawn on it. LoadedComponentIsOutOfDate is what says the rest of it moved.
|
Full Usage:
designOf project (arg2, arg3)
Parameters:
Project
arg1 : Component list
arg2 : Connection list
Returns: LoadedComponent list
|
The design as the simulator sees it: the open sheet as it is on the canvas now, and every other sheet as the project holds it. The same list prepareSimulationMemoized compares against, so a verdict and a simulation go stale together. canvasState is passed in rather than taken from model.Sheet: extracting it walks every symbol and wire on the sheet, and the caller that runs per render already holds the one MainView extracted for this frame.
|
Full Usage:
designStepCost model simSheet
Parameters:
Model
simSheet : string
Returns: Result<StepCost, SimulationError>
|
The per-cycle memory cost of wave-simulating the open design: what the waveform configuration dialog's size message and its OK gating need, and nothing more. This exists because the dialog used to get the same number by building a complete 10-cycle simulation - every FastComponent, every step array - and reading one field off the result: 49 seconds of frozen dialog on a 480,000-component design, and the waveform simulation cache evicted on the way. The cost is a fact about the design's merged graph, so this stops there: check the circuit, price its graph, allocate nothing - not even the flattening, which stepCostOfGraph no longer needs. The per-cycle cost of one sheet of the open design. `waveSimStepCost` below is this for the sheet the waveform simulator is on; the step simulator asks for the open one, to decide how many cycles of history it can afford (SimulationView.stepSimArraySize). One memo entry, keyed by sheet: two callers asking about different sheets re-price rather than share, which costs a graph walk. That is the right trade - the dialog asks per keystroke about one sheet, and the step simulator asks once per build.
|
Full Usage:
designWithSheet project sheet (arg3, arg4)
Parameters:
Project
sheet : string
arg2 : Component list
arg3 : Connection list
Returns: LoadedComponent list
|
The design with one sheet's canvas replaced by the state given, and every other sheet as the project holds it. Which sheet is a parameter because saving names it: a save writes the canvas of the sheet being saved, and until it finishes the project's own copy of that sheet is the version BEFORE the edit. Walking the stale copy is how a component renamed on the canvas would be saved under the name it no longer has. The whole list goes in, INCLUDING the sheet being replaced: addStateToLoadedComponents replaces it itself, and everything about the sheet that its canvas does not say - its parameters, whether it is the top sheet, and whether it is an array component - it can only carry forward from the copy already there. Filtering first left an array component looking like an ordinary sheet for as long as it was the sheet being edited, so its ports came out wrong and it was never expanded.
|
|
|
|
|
|
Everything the model believes about the .NET simulator's session, forgotten together. These fields are one fact between them - there is a session, this is how far it has run, this is what has been asked of it and what the last completed fetch was for - and a path that drops some of them leaves the rest describing a simulation that is not there. That is not hypothetical: the End Simulation button released the port slices and left the session behind, so the model went on naming a build whose slices it no longer had, with `FetchedData` still claiming the caches were serving it. Ending a simulation is the only thing that does this. Nothing is told to the SIDECAR: it drops its own session when the first sheet of the next design arrives, which is what makes a design upload safe (docs/dev/sidecarInvariants.md, section E).
|
|
|
|
|
|
|
Full Usage:
getSavedWaveInfo ldcs topSheet wsModel
Parameters:
LoadedComponent list
topSheet : string
wsModel : WaveSimModel
Returns: SavedWaveInfo
|
Get saveable record of WaveSimModel. The selection is written as label paths rather than as the ids the model holds, so that it survives being read back against a design whose ids have been reallocated or whose sheets have been edited - see WavePath.fs. `topSheet` is the sheet this wave sim simulates, which the paths are rooted at, and `ldcs` is the design they are walked through. A wave whose component the design no longer holds is dropped here rather than written as a path to nothing. That can only happen if the design changed under a live wave sim, which is when the selection is stale anyway.
|
|
|
|
|
|
|
Full Usage:
inputBigint props placeholder locs isValid dispatch model
Parameters:
IHTMLProp list
placeholder : string
locs : ModelLocations
isValid : bigint -> Model -> bool
dispatch : Msg -> unit
model : Model
Returns: ReactElement
|
|
|
|
Full Usage:
loadWSModelFromSavedWaveInfo ldcs topSheet swInfo
Parameters:
LoadedComponent list
topSheet : string
swInfo : SavedWaveInfo
Returns: WaveSimModel
|
Setup current WaveSimModel from saved record. The inverse of getSavedWaveInfo: each saved label path is resolved against the design as loaded. A path naming a component that has since been renamed or deleted resolves to nothing and its wave is simply not selected - which is the whole reason the selection is saved as labels. SavedWaveInfo's shape can now be changed without a legacy reader: a file this version cannot parse loses its selection and keeps its sheet (Helpers.jsonStringToState).
|
Full Usage:
mapFst mapFn (model, cmd)
Parameters:
'a -> 'b
model : 'a
cmd : 'c
Returns: 'b * 'c
|
|
|
|
Full Usage:
memoryWidthsInDesign model compId mem
Parameters:
Model
compId : ComponentId
mem : Memory1
Returns: (int * int) list
|
The address and data widths one memory component of the open sheet has ACROSS ITS DESIGN: one pair per set of parameter values the sheet is used at, never empty. Contents are one map shared by every instance of the sheet, so data offered to a memory - typed into the editor, or read from a .ram file it is linked to - has to fit every one of these, not merely the shape the sheet happens to be drawn at. Where nothing is parameterised there is one pair and this says what it always said.
|
|
|
|
|
|
|
Full Usage:
pinDrawBlock pinned model
Parameters:
PinnedCanvas
model : Model
Returns: Model
|
|
|
|
|
Write the pinned state back over the live draw block, so that nothing which would be saved can change while a library sheet is being viewed. This is the whole of read-only enforcement. It restores rather than refuses because there are too many ways to edit to block them one at a time and be sure: 58 mutating cases across the three draw block Msg types, half a dozen places that write model.Sheet directly through Optic.map without reaching any update function, and UpdateModel, which carries an arbitrary Model -> Model and cannot be inspected at all. Undoing the change afterwards catches every one of those, and goes on catching messages added later. Everything the user can reach that would be reverted is separately disabled, so nothing appears to work and then springs back. Called after every message, so it first asks whether anything it pins was touched at all: the maps are persistent, so an untouched one is still the same object and the usual case costs seven reference comparisons and no allocation.
|
|
The draw block state to hold a read-only sheet at. Taken once the sheet has settled, never while it loads: loading recomputes symbol sizes, reroutes wires whose ports have moved and centres the circuit, all of which are changes the pin would otherwise undo one by one until the sheet never finished opening.
|
Full Usage:
readProjectBrowserFolder folder selected
Parameters:
string
selected : int
Returns: ProjectBrowserState
|
Read a folder for the project browser: what is in it, or why it cannot be shown. Done here, from the update function, rather than while rendering. A popup body runs on every message, so a view that read the disk would read it continuously - and the keyboard needs the number of rows before it can move between them.
|
|
|
|
|
|
For reasons of space efficiency, ensure that no non-empty unused FastSimulation records are kept. A FastSimulation holds a step array per net and a SimulationGraph node per component instance, so a large design's is hundreds of MB: one left behind slows every later edit, because each major GC must trace all of it. Call this before building a new simulation. CurrentStepSimulationStep is the only field of the model holding one. Every WaveSim entry is released as well - see releaseWaveSimData - which covers the sheet the caller is about to resimulate (its WaveDetails is rebuilt by the refresh), the sheets left behind by switching the waveform simulator between sheets, and the entry EndWaveSim is about to mark Ended. The truth table's TableSimData is deliberately left alone: it is what regenerates the table when a constraint changes, so it is in use rather than stale.
|
|
|
|
|
|
|
|
|
Full Usage:
setWSModel wsModel model
Parameters:
WaveSimModel
model : Model
Returns: Model
|
|
|
Whether a fetch of waveform data is running. Read off the in-flight table, like everything else about what the simulator is doing. It was a bool on the WaveSimModel, set where the fetch started and cleared where it landed - a second place saying what the table says, which could disagree with it and which nothing outside the waveform simulator could see.
|
|
Whether a build of the design on the .NET simulator is running. Read off the in-flight table rather than kept beside it, so there is one thing that says so. An answer arriving removes the entry, which is the same moment the session appears - there is no window in which both are true, and none in which neither is.
|
|
|
|
|
|
|
Full Usage:
simulateModel localBuild isWaveSim simulatedSheet simulationArraySize (arg5, arg6) model
Parameters:
bool
isWaveSim : bool
simulatedSheet : string option
simulationArraySize : int
arg4 : Component list
arg5 : Connection list
model : Model
Returns: Result<SimulationData, SimulationError> * CanvasState
|
|
Full Usage:
simulationHeapEstimate simulatedSheet (arg2, arg3) model
Parameters:
string option
arg1 : Component list
arg2 : Connection list
model : Model
Returns: float
|
Start simulating the current Diagram. Return SimulationData that can be used to extend the simulation as needed, or error if simulation fails. Note that simulation is only redone if current canvas changes. What the design a simulation of this sheet would expand to costs in heap, worked out the way GraphMerger refuses on and from the same pair of canvas and project the simulation itself is assembled from.
|
|
|
|
Which simulator a button is about to start, or is running, for its label - development builds only, where it is the empty string. The two backends are meant to be indistinguishable, and are checked against each other for exactly that. The cost is that when they are NOT - a difference in a waveform, a simulation that is slow, a fetch that fails - nothing on screen says which one is being looked at, and the Development menu that switches them does not say either. The button that starts a simulation is where the question is asked, so it is where the answer goes.
|
|
|
|
|
|
|
|
|
|
|
Full Usage:
spMess msg
Parameters:
'a
Returns: string
|
|
Full Usage:
spOpt f thingOpt
Parameters:
'a -> string
thingOpt : 'a option
Returns: string
|
|
|
|
Full Usage:
spState (arg1, arg2)
Parameters:
Component list
arg1 : Connection list
Returns: string
|
|
Full Usage:
startingLastClock configured heapEstimate
Parameters:
int
heapEstimate : float
Returns: int
|
The clock cycle a waveform simulation should start at, given what its expanded design will cost in heap and what it was configured for. A big design costs minutes to start, not seconds: main6 of the largeTest project is 480,000 components, and at the configured 2000 cycles it spent three minutes building 6GB of step arrays and another two building 835,000 wave records - all before showing anything. Started short it is seconds, and the configuration is still there to raise once the user has seen the design work. This only ever lowers what was asked for. Only the UNTOUCHED DEFAULT of a design past bigDesignHeapShare is lowered: a value anyone has set in the configuration dialog is honoured exactly, however big the design. The dialog already refuses what will not fit in memory (FastCreate.maxLastClockFor), so an explicit value is one the user has been told the cost of - and overriding it made the configuration a lie: main6 of largeTest, configured to 4000 cycles well inside its stated limit, was silently started at 200 with no way to raise it, since the dialog is closed to a running simulation. The overwrite even outlived the session, because WSConfig is saved in the sheet. (An earlier version also tapered the allowed cycles as 40/share below the threshold, which capped a 350-component CPU at 75,000 of its configured 1,000,000 cycles.)
|
|
How many cycles of history the step simulator may build for a design costing this much, or None when it may not be simulated at all. The waveform simulator gets its bound from a configuration dialog that prices the design and refuses a last clock that will not fit. The step simulator has no dialog - it just picks a length - so the same budget has to bind on that one number. `wanted` is what it would like; this lowers it to what the design can afford, and refuses below `minStepArraySize`, where there is not enough past to step back through. Measured against maxCyclesFor, which is the budget WITHOUT the runtime headroom checkSimulationFits allows itself. Deliberately the stricter of the two: a size chosen here is then certain to pass the build's own check, so this decides the outcome rather than moving a refusal to somewhere that explains it worse.
|
Full Usage:
syncArrayTextFor ldc model
Parameters:
LoadedComponent
model : Model
Returns: Model
|
The drawn symbols of `ldc` brought into line with what it says: on an ARRAY COMPONENT a join draws the channel EXPRESSION it is on and an Output draws the loop variable, and neither is anywhere on the canvas - a join's channel is a parameter slot of the sheet, and the loop variable is in its array settings. See SymbolUpdate.syncArrayText, which is where the rule is. Takes the sheet rather than reading the open one, because the caller that matters most is opening a sheet: the project's idea of which sheet is open changes around that, and passing the one being loaded says which is meant without depending on when.
|
|
|
|
|
Full Usage:
updateLdComps name changeFun ldComps
Parameters:
string
changeFun : LoadedComponent -> LoadedComponent
ldComps : LoadedComponent list
Returns: LoadedComponent list
|
|
Full Usage:
updateLdCompsWithCompOpt newCompOpt ldComps
Parameters:
LoadedComponent option
ldComps : LoadedComponent list
Returns: LoadedComponent list
|
|
Full Usage:
updateWSModel updateFn model
Parameters:
WaveSimModel -> WaveSimModel
model : Model
Returns: Model
|
|
Full Usage:
updateWSModelOfSheet sheet updateFn model
Parameters:
string
updateFn : WaveSimModel -> WaveSimModel
model : Model
Returns: Model
|
|
|
|
|
|
Full Usage:
waveSimStepCost model
Parameters:
Model
Returns: Result<StepCost, SimulationError>
|
|