Issie logo Issie

PortView Module

 The ports of one elaborated sheet instance that a waveform can be taken of.

 **This is the narrow question the renderer should be asking a simulator**, and the one
 `SimInterface` describes: not "give me every wave in the design" - which is proportional to the
 expansion and is what a remote simulator exists to keep out of the renderer - but "which ports
 does THIS instance offer", asked of the handful of instances on screen.

 Everything here that a design could answer is answered from the design instead; what is left is
 what only an elaborated simulation knows. That is two things, and they are the reason this
 cannot be a design-time query:

   the WIDTH of a port, because parameters are resolved when a design is elaborated, so two
   instances of one sheet are meant to differ;

   where the port's data LIES - its driver and its step array - which is a fact about one build
   and is invalidated by the next.

 Below the UI for the same reason `RamView` and `WaveNames` are: the .NET sidecar has a
 FastSimulation of its own and must answer this from exactly this code, or the two agree until
 they do not.

Types

Type Description

ComponentSlots

Every port of one component of one instance, positionally: array index = port number, which is the design's own numbering (a Component's port lists are position-numbered).

InstancePort

One port of one instance, with everything a waveform needs that the design cannot supply. The field names are prefixed because a record field resolves to the last type declaring one, and the wave simulator is full of ports, widths and names.

InstanceView

What one instance offers, with the facts that are about the INSTANCE rather than about any one of its ports worked out once. Both were being recomputed per wave, and each walks the instance path - which made reconciling a hundred waves quadratic in the depth of the design for no reason at all.

PortSlot

The width and driver index of one port: what a wave needs from the BUILD, and nothing else. Two ints, because this is what travels when the simulator is in another process. Everything else a selector shows - names, labels, which ports carry a wave at all - is a fact about the design, which the renderer holds; only elaboration facts need the simulation, and these are they. The driver index doubles as the build's read handle: `SimRead` accepts it for as long as this build lives, and the next build invalidates it wholesale.

Functions and values

Function or value Description

drawnComponentOf design waveId

Full Usage: drawnComponentOf design waveId

Parameters:
Returns: ComponentId

The component a wave should take the user TO, which is not always the one it comes from. A wave on one of an array component's copies comes from a component the EXPANSION made - the copy, which is a custom component on a sheet nobody drew - so there is no symbol anywhere to go to, and the waveform viewer's "show me this" button did nothing at all. What the user means by it is the join, or the input or output, that this port IS: that is drawn on the array component's own sheet, and the body sheet keeps the ids of what is drawn there, so the body's IO component for this port is the drawn one. Found by port NUMBER and not by label. A copy's port labels are the channels that copy is joined by, which is the whole point of them, and those are not the body's labels - see ArrayElaborate's copyPortNames.

design : SimulatedDesign
waveId : WaveIndexT
Returns: ComponentId

nameOfPort fs wi

Full Usage: nameOfPort fs wi

Parameters:
Returns: string

The raw name of one port of one instance - component label, port name, bit limits, uncased - which is what the probe label prints beside a value. The selector's rows use the cased `PortDisplayName` instead.

fs : FastSimulation
wi : WaveIndexT
Returns: string

ofInstance fs instance

Full Usage: ofInstance fs instance

Parameters:
Returns: InstanceView

The ports of one instance that carry a waveform, from the simulation in this process. The DERIVATION is `ofSlice`'s - the design plus two ints a port - and this is only the local composition of it with the local slice. A renderer whose simulator is in another process runs the same `ofSlice` over a slice that arrived on the wire, and the two must be the same function or the two modes drift; that is why there is no second derivation here.

fs : FastSimulation
instance : InstancePath
Returns: InstanceView

ofInstanceCached fs instance

Full Usage: ofInstanceCached fs instance

Parameters:
Returns: InstanceView
fs : FastSimulation
instance : InstancePath
Returns: InstanceView

ofSlice design instance slice

Full Usage: ofSlice design instance slice

Parameters:
Returns: InstanceView

two ints a port, and it merely happens that a .NET simulator computed the ints.

design : SimulatedDesign
instance : InstancePath
slice : ComponentSlots list
Returns: InstanceView

sheetSliceOf fs instance

Full Usage: sheetSliceOf fs instance

Parameters:
Returns: ComponentSlots list

Width and driver of every port of every component on one instance's sheet. ALL ports, positionally - not the wave-carrying subset. Filtering would mean naming what was kept, which costs more than the entries it saves, and the rule for what carries a wave is a design fact the caller already has - the IOLabel election included, which is read off the design's connections (see `ofSlice`). A group's members share their arrays here, so the DATA is the same whichever member is asked about. A width of 0 is a port with no signal: an unconnected input, still holding the dummy array it was created with. This is the sidecar's answer to "what does this instance offer" and the renderer's local answer to the same question, from one body of code - which is the point.

fs : FastSimulation
instance : InstancePath
Returns: ComponentSlots list

sliceSource

Full Usage: sliceSource

Returns: (FastSimulation -> InstancePath -> ComponentSlots list option) option

Where wire-fetched slices are read from, when the simulation is NOT in this process. Installed ONCE, at startup, by the renderer's PortData - and never under .NET, where it stays None and every slice is computed locally. It is consulted only for a CARRIER build, and it answers from what has arrived for exactly that build: None means "this instance is not described YET" - a different thing from an empty slice, and the distinction is what lets a selection loaded before the wire answers pass through unresolved instead of being dropped. A hook rather than a parameter because slices are read from view code through the memo below, at call sites that have no business knowing which process simulates. Which build the hook is asked about travels WITH the ask - the same fs the caller holds - so there is no lifecycle here: nothing activates it, nothing clears it, and a stale answer is impossible because the store inside keys what it holds by the build it holds it for.

Returns: (FastSimulation -> InstancePath -> ComponentSlots list option) option

tryOfInstanceCached

Full Usage: tryOfInstanceCached

Returns: FastSimulation -> InstancePath -> InstanceView option

The ports of an instance, remembered for as long as the simulation is. `ofInstance` costs one sheet. That is the right cost to pay once for an instance and the wrong cost to pay per selected wave: reconciling a hundred waves walked their sheet a hundred times, and the test suite went from 27 seconds to 43 when it started to. Only instances actually asked about are held - the ones the selector is showing, and the ones selected waves are in - so what this holds is bounded by what the UI touches rather than by the expansion. Keyed on the simulation, which is rebuilt rather than mutated, so a new one is the signal that all of it is stale; emptied when a simulation ends, by Helpers.clearIdentityMemos. None while the sidecar simulates and this instance's slice has not arrived - the case every display site answers with nothing-yet, and reconciliation answers by keeping the wave unresolved. A described instance is memoised; an undescribed one is asked again, because the answer changes when the slice lands.

Returns: FastSimulation -> InstancePath -> InstanceView option

waveIndexOf instance port

Full Usage: waveIndexOf instance port

Parameters:
Returns: WaveIndexT

The wave index of a port: how the rest of Issie names one, and what a selection is made of.

instance : InstancePath
port : InstancePort
Returns: WaveIndexT

waveIndicesOfDesign design instance

Full Usage: waveIndicesOfDesign design instance

Parameters:
Returns: WaveIndexT list

The wave-carrying ports of one instance, from the DESIGN alone - no simulation, no slices. Every wave comes back UNRESOLVED (SimArrayIndex = DriverIndex -1): where its data lies is a build fact this deliberately does not know. Reconciliation resolves them against whichever simulator runs - which is what makes this enumeration mode-agnostic, and what the dev harness selects with. Port counts and numbering are the design's own; the carries-a-wave rule is the same one ofSlice applies, election by connection included. The one thing a slice adds - dropping an unconnected input's width-0 port - is left to resolution, where the fetch already records such a wave as having no driver.

design : SimulatedDesign
instance : InstancePath
Returns: WaveIndexT list

Type something to start searching.