Add cycle-accurate simulation of sequential networks - #708
Open
marcelwa wants to merge 2 commits into
Open
Conversation
`simulate` evaluates the combinational logic of a network exactly once and has no notion of a register. Handed a `sequential<Ntk>` it assigns the constants, the primary inputs and the gates -- but never the register outputs, which are neither. They keep whatever `node_map` default-constructed them to, so every value in their fanout cone is meaningless: constant 0 for a `bool` simulation, a zero-variable truth table otherwise. Nothing warns about it. `simulate_sequential` runs the network over a number of clock cycles instead. Every register starts at its reset value, the combinational logic is evaluated once per cycle, the primary outputs are recorded, and the register inputs are latched into the register outputs for the next cycle. The simulator concept is unchanged, with one addition: a simulator that provides `compute_pi( index, cycle )` is driven per cycle, so the primary inputs can change from one to the next. `stimulus_simulator` is such a simulator, holding one assignment vector per cycle and repeating its last one for the rest of the run. Everything that works with `simulate` keeps working, holding its assignment for the whole run -- which is what a design with no primary inputs, an LFSR say, wants anyway. A register may declare no reset value at all -- `register_init::dont_care` or `register_init::unknown`, which is what `register_t` defaults to and what an AIGER latch with a nondeterministic reset reads back as. Simulation needs a concrete one, so `simulate_sequential_params::undefined_reset_value` says which. It lives in its own header rather than in `simulation.hpp` because it needs `networks/sequential.hpp`, which pulls in every network implementation. Putting it in `simulation.hpp` would put that cost on every translation unit that simulates anything. The result of a run is a `simulate_sequential_result`, which names both axes of the data instead of returning a bare nested vector: `outputs[cycle][index]` is what primary output `index` emitted in that cycle, `states[cycle][index]` what register `index` held while that cycle was evaluated. The state trace is one entry longer than the output trace, because simulating `n` cycles crosses `n + 1` state boundaries; `reset_state()` is the one the run started from and `final_state()` the one it ended in. Ten test cases: a 4-bit LFSR walking all 15 of its non-zero states and returning to its seed on the sixteenth, a second seed producing the same sequence one step ahead (which only holds if the reset values are honoured), a shift register driven by a per-cycle stimulus, a stimulus shorter than the run, an undefined reset following the parameter both ways, truth-table simulation, a zero-cycle run, the fencepost between the output and state traces, and a register read out one cycle after it was written, where the output of each cycle must equal the state it started in.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #708 +/- ##
==========================================
+ Coverage 84.06% 84.08% +0.02%
==========================================
Files 190 191 +1
Lines 29515 29571 +56
==========================================
+ Hits 24812 24866 +54
- Misses 4703 4705 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
simulateruns a network's combinational logic exactly once and has no notion of a register, so simulating asequential<Ntk>leaves every register output holding whatevernode_mapdefault-constructed it to.simulate_sequentialruns the network over a number of clock cycles instead, seeding each register from its reset value, evaluating the combinational logic once per cycle, and latching the register inputs into the register outputs for the next cycle; a simulator can optionally providecompute_pi( index, cycle )to vary the primary inputs per cycle, andsimulate_sequential_params::undefined_reset_valuefixes a concrete value for registers with no defined reset. It lives in its own header,simulation_sequential.hpp, because it needsnetworks/sequential.hpp, which pulls in every network implementation.