Skip to content

sim: correctness fixes — wired parameters, PushButton/Monoflop Reset, InputRef mirroring - #16

Open
discostu105 wants to merge 3 commits into
eisber:mainfrom
discostu105:sim-correctness-fixes
Open

sim: correctness fixes — wired parameters, PushButton/Monoflop Reset, InputRef mirroring#16
discostu105 wants to merge 3 commits into
eisber:mainfrom
discostu105:sim-correctness-fixes

Conversation

@discostu105

Copy link
Copy Markdown

Three independent correctness fixes for lox-sim, found while building lxir's lxir test command, which compiles a test DSL into SimSpec JSON and runs it through lox sim run --json against real configs.

1. Wires into parameter connectors are honored (8d44ffc)

Loxone lets any parameter be driven by a wire instead of a fixed value — Formula Input1Input4, comparator Input2, timer durations. Previously:

  • Graph::add_wire required the sink to be ConnectorDir::Input, so wires into Parameter connectors were refused and degraded to warnings at parse time;
  • both evaluators read parameters straight from the local connector signal, so a wired parameter silently kept its Def= value.

Now the graph accepts any non-Output sink, the interpreter resolves param_sources through wires exactly like input_sources (feedback wires read prev-tick; autodiff duals follow the same resolution), and the JIT compiler's input_source map covers parameter connectors with every EvalStep param index resolved through it.

Observed failure: a VirtualIn wired into a Formula's Input1 evaluated as 0 instead of the injected value.

2. Monoflop Reset; InputRef mirrors its fed side to Q and AQ (1fb350d)

  • Monoflop now honors its Reset input (cancels the running pulse).
  • InputRef mirrors whichever side feeds it to both Q and AQ, matching how downstream blocks consume refs in real configs.

3. PushButton honors Reset and InputDisable (735bc8d)

PushButton/PushButton2 previously ignored their Reset and InputDisable connectors.


All three are test-covered (cargo test -p lox-sim: 498 passing). Reset semantics that could not be validated against a live Miniserver are marked with the existing "WARNING: Assumed behavior" comment convention.

Happy to split this into three PRs if you prefer.

The parser signature for PushButton/PushButton2/PushButton2Sel only mapped
InputTrigger and On, so a wired Reset landed at an input index the eval
never read — a PushButton driven off via Reset stayed on forever.

- parser: add Reset + InputDisable to the PushButton and PushButtonSel
  input signatures (synthesized when absent, so layouts stay stable)
- interpreter: Reset dominates On and forces off; InputDisable gates the
  trigger edge (PushButton and PushButton2; assumed behavior, flagged)
- JIT: same semantics in EvalStep::PushButton (usize::MAX sentinel for
  absent connectors) so interpreter/JIT equivalence holds

Found while simulating the r50 UV-lamp weekday scenario (PushButton with
On: weekday-Or, Reset: Not(weekday-Or)).
…d AQ

- Monoflop: the parser signature lacked Reset, so a wired Reset was never
  read and a running pulse could not be aborted. Reset now clears the
  countdown and blocks retriggering while held (interpreter + JIT;
  assumed behavior, flagged).
- InputRef: the impl forwarded I->Q and AI->AQ separately, but the
  Miniserver mirrors the one fed side onto BOTH outputs — the r50 corpus
  wires 'ref.AI <- mem.AQ' with consumers reading ref.Q. Q is now the
  digital view (non-zero -> 1) and AQ the analog value of whichever side
  is fed.

Found while simulating the r50 alarm chain (Monoflop 'alarm_halten' with
Reset: heimkommen_ref.Q, triggered through an AI-fed InputRef).
Loxone lets any parameter (Formula Input1-Input4, comparator Input2,
timer durations) be driven by a wire instead of a fixed value. The
graph refused such wires (add_wire required dir == Input, degrading
them to warnings), and both evaluators read parameters straight from
the local connector signal, so a wired parameter silently kept its
Def= value.

- graph: add_wire accepts any non-Output sink
- engine: BlockEvalInfo resolves param_sources through wires like
  input_sources (feedback reads prev-tick; autodiff duals follow too)
- compiler (JIT): the input_source map covers parameter connectors and
  every EvalStep param index resolves through it

Found via lxir's pool example: a VirtualIn wired into a Formula's
Input1 evaluated as 0 instead of the injected value.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant