# OSDI Files

`OsdiFile` (`osdifile.h`/`osdifile.cpp`) represents one loaded OSDI shared library - a compiled Verilog-A module, opened via [`dynload.h`](libplatform.md) - and is the layer that turns its raw C ABI exports into simulator-friendly, name-indexed lookups. An OSDI file can contain several device descriptors (several Verilog-A modules compiled into one shared library), each exposed as one entry addressed by `OsdiDeviceIndex`.

## Loading and version checking

The constructor reads a fixed set of well-known exported symbols directly by name via `dynamicLibrarySymbol()` - `OSDI_DESCRIPTORS`, `OSDI_NUM_DESCRIPTORS`, `OSDI_VERSION_MAJOR`/`MINOR`, `OSDI_ATTRIBUTES`, `OSDI_NATURES`/`_LEN`, `OSDI_DISCIPLINES`/`_LEN`, `OSDI_DESCRIPTOR_SIZE`, `OSDI_LIM_TABLE`/`_LEN` - the raw C ABI OSDI defines for a compiled module. It rejects a library with no descriptors or an unsupported interface version (`>= 0.4` required) with a located [`Status`](status.md) error, and wires the library's own `OSDI_LIM_TABLE` entries to the simulator's limiting-function implementations by matching name and argument count against `limitFunctionTable` (see [OSDI Callbacks](osdicallback.md)) - an unmatched or arity-mismatched limiting function is itself a load error.

A static per-process registry (`registry`, keyed by dynamic-library handle and owning the `OsdiFile` via `unique_ptr`; `nameToFile`, keyed by path; `fileOrder`, insertion order) means opening the same `.osdi` file twice returns the same loaded `OsdiFile`, not a second copy.

## Per-device translation tables

For each device descriptor in the file, `OsdiFile` builds, once at load time, the tables that make later lookups O(1) instead of re-scanning the raw OSDI descriptor arrays every time:

- Name-to-OSDI-id maps for parameters/output variables (`paramOsdiIdTranslators`) and noise sources (`noiseSourceNameTranslators`), and for terminal/internal node names (`nodeMaps`).
- OSDI-id-to-simulator-`ParameterIndex` translation (`osdiIdSimInstIdLists`/`osdiIdSimModIdLists`), separating a device's parameters into the simulator's own independent instance-parameter and model-parameter numbering (an OSDI parameter can be marked as either or both, via `PARA_KIND_INST`/`PARA_KIND_MODEL`/`PARA_KIND_OPVAR` flags - `instanceParameterIndex()`/`modelParameterIndex()`/`outvarIndex()` each check the parameter's kind before returning a hit).
- Lists of OSDI ids that own heap-allocated storage (`instParAllocatedOsdiId`/`modParAllocatedOsdiId`) - used to free string/vector-valued parameters when an instance or model is destroyed, since OSDI parameter storage lives inside the opaque per-instance/per-model blob (see [OSDI Instances](osdiinstance.md)) and isn't cleaned up automatically.
- Nonzero-entry index lists (`nonzeroResistiveJacNdx`/`nonzeroReactiveJacNdx`/`nonzeroResistiveResNdx`/`nonzeroReactiveResNdx`) used when allocating and binding the sparse KLU matrix structure (`klumatrix.h`, not documented separately here) for a device.

## Natures, disciplines, and tolerances

`processNaturesAndDisciplines()` walks the file's `OSDI_NATURES`/`OSDI_DISCIPLINES` tables and registers each with [`NatureRegistry`](natures.md), collecting the absolute-tolerance values associated with each nature and its time-integral ("idt") counterpart. `natrefTolerances()` resolves one `OsdiNatureRef` (OSDI's own tagged reference to either a bare nature or a discipline's flow/potential nature) into a `(NatureTolerance, NatureTolerance)` pair for the quantity and its time integral; `tolerances(deviceIndex, node)` combines a device's per-node unknown and residual natures into the four-way `(unknown, unknown idt, residual, residual idt)` tuple `OsdiDevice`/`OsdiInstance` use to register tolerances with the simulator's tolerance-checking machinery (see [Natures](natures.md)).

## Creating devices

`open()` is the factory entry point (parses the file and returns an `OsdiFile*`, or reports failure via `Status`); `createDevice()` (by index or by name) constructs an [`OsdiDevice`](osdidevice.md) for one descriptor within the file - the actual `Device` a `model` statement can then bind to.
