Modules & domains
Modules are the building block of a Hover program, and they're flattened at compile time — there's no runtime module overhead, only the nets and logic objects that survive elaboration. Every module belongs to exactly one domain, declared by a prefix keyword, and that domain decides what it may contain and when it runs.
The three domains
| analog module | Allowed: physical primitives, V()/I(), math, if, function calls.Forbidden: state, while. |
| digital module | Allowed: state, if, while, math, function calls.Forbidden: physical primitives. |
| module | Allowed: wire declarations, V()/I() reads, state, function calls, sub-module instantiation.Forbidden: computation, if, while. |
Analog modules model continuous-time device physics. Their state lives in physical elements — capacitors, inductors — managed by the MNA engine, not in software variables. if is permitted for clamping and saturation detection; while is not, because an unbounded loop inside the Newton-Raphson convergence loop is a hang. This is the mechanism for defining your own device models (transistors, diodes, transformers) that stamp into the MNA matrix alongside the built-in primitives.
Digital modules model discrete-time and event-driven behaviour. state variables persist across timesteps, like registers. They can't instantiate hardware — the bridge from a digital output to a physical primitive always runs through a logic port of an analog module, or a driven source in a structural one.
Structural modules (plain module) are wiring harnesses: declare wires, read MNA node voltages, instantiate sub-modules. No computation.
What each domain allows
| analog | digital | module | |
| Physical primitives | ✓ | — | ✓ |
V() / I() |
✓ | ✓ | ✓ |
| Function calls | ✓ | ✓ | ✓ |
| Math / binary expressions | ✓ | ✓ | — |
if statement |
✓ | ✓ | — |
while loop |
— | ✓ | — |
state variables |
— | ✓ | — |
| Standalone assignment | ✓ | ✓ | — |
| Wire declarations | ✓ | ✓ | ✓ |
| Signal declarations | ✓ | ✓ | ✓* |
| Sub-module instantiation | ✓ | ✓ | ✓ |
* Structural module signal initialisers are restricted — see below.
Structural module initialiser rules
Signal declarations inside a plain module are allowed, but the initialiser is restricted to literals, identifiers and function calls. Binary arithmetic isn't accepted — move the computation into a digital or analog sub-module.
Why two computational domains
The split between analog and digital isn't stylistic — it follows from where each one sits relative to the solver.
Analog modules run inside the solver. Their outputs — device currents, conductances — are stamped into the matrix and become part of the system G·x = b. The solver iterates over analog logic within its Newton-Raphson loop, recomputing device currents each iteration until the circuit converges. Analog logic must therefore be purely combinational: the same node voltages must always produce the same currents. A state variable there would accumulate on every iteration instead of once per timestep, corrupting the solution.
Digital modules run outside it. They execute once per accepted timestep, in Phase A, before the matrix is assembled, and their outputs are fixed inputs to the MNA for that step — the solver never re-enters digital logic during iteration. That's exactly what makes state safe there.
In short: analog logic is inside the solver loop, digital logic is outside it. Mixing them would produce wrong answers, which is why the semantic analyser refuses. See Simulation run order for the full picture.
Bracket convention
| < > | Static parameters — compile-time constants |
| ( ) | Logic ports — runtime signals |
| [ ] | Physical ports — electrical wire connections |
Declaration
direction is input or output. Static parameters are evaluated at elaboration time and are available as constants inside the body.
Instantiation
The module instance_name = prefix is mandatory for every module. Physical primitives are the exception — they're written bare. See Wires & components.
Execution order
Each timestep, Phase A executes the three domains in a fixed causal order:
module ⟶ digital ⟶ analog
Structural modules read MNA state first, making voltages and currents available as signals. Digital modules then compute control outputs from those signals. Analog modules run last, computing device currents from the updated node voltages and control signals. Phase B then stamps all driven sources into the matrix before the solve. This ordering is fixed regardless of declaration order in the source file — see Simulation run order.