Sequential simulation
Header: mockturtle/algorithms/simulation_sequential.hpp
simulate evaluates the combinational logic of a network exactly once and has no notion of a register. On a sequential network it never assigns the register outputs at all, so every value in their fanout cone is meaningless.
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.
It returns a simulate_sequential_result, which carries two traces indexed by clock cycle: outputs[cycle][index] is the value primary output index took in that cycle, and states[cycle][index] the value 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.
Examples
A design with no primary inputs runs off its reset state alone. A 4-bit LFSR seeded with 0b0001 walks through all 15 of its non-zero states:
sequential<aig_network> lfsr = ...;
auto const result = simulate_sequential<bool>( lfsr, 15, default_simulator<bool>( std::vector<bool>{} ) );
for ( auto const& outputs : result.outputs )
{
std::cout << outputs[0];
}
The state trace answers what the registers were doing while that happened, and where they ended up:
#include <fmt/ranges.h>
for ( auto const& state : result.states )
{
std::cout << fmt::format( "{}\n", fmt::join( state, "" ) );
}
assert( result.final_state() == result.reset_state() ); // a full period
Primary inputs that change from one cycle to the next are supplied by stimulus_simulator, which holds one assignment vector per cycle and repeats its last one for the rest of the run:
sequential<aig_network> shift_register = ...;
/* a single 1 on the input, then silence */
stimulus_simulator sim( { { true }, { false } } );
auto const result = simulate_sequential<bool>( shift_register, 6, sim );
Any simulator that works with simulate works here too, holding its assignment for the whole run. Truth tables, for instance, give the outputs of each cycle as a function of the primary inputs:
auto const result = simulate_sequential<kitty::dynamic_truth_table>(
ntk, 3, default_simulator<kitty::dynamic_truth_table>( ntk.num_pis() ) );
Result
-
template<class SimulationType>
struct simulate_sequential_result The result of simulating a sequential network.
Both traces are indexed by clock cycle first.
outputs[cycle][index]is the value primary outputindextook in that cycle, andstates[cycle][index]the value registerindexheld while that cycle was evaluated.statesis one entry longer thanoutputs: simulatingncycles crossesn + 1state boundaries.states.front()is the reset state the run started from andstates.back()the state it ended in, so a run of zero cycles still reports the reset state and nothing else.Public Functions
-
inline uint32_t num_cycles() const
Number of clock cycles simulated.
-
inline std::vector<SimulationType> const &reset_state() const
The state the registers were reset to.
-
inline std::vector<SimulationType> const &final_state() const
The state the registers held after the last cycle.
Public Members
-
std::vector<std::vector<SimulationType>> outputs
Primary output values, one vector per clock cycle.
-
std::vector<std::vector<SimulationType>> states
Register values, one vector per state boundary.
-
inline uint32_t num_cycles() const
Parameters
-
struct simulate_sequential_params
Parameters for
simulate_sequential.Public Members
-
bool undefined_reset_value = {false}
Value a register starts at when its reset value is not defined.
A register may declare no reset value at all —
register_init::dont_careorregister_init::unknown, which is whatregister_tdefaults to and what an AIGER latch with a nondeterministic reset reads back as. Simulation needs a concrete value, so this is the one it uses.
-
bool undefined_reset_value = {false}
Simulators
-
class stimulus_simulator
Simulates Boolean assignments that change from cycle to cycle.
A simulator for
simulate_sequentialholding one assignment vector per clock cycle. Cycles past the end of the stimulus repeat its last assignment, so a stimulus shorter than the run holds its final value for the remainder of it.
Algorithm
-
template<class SimulationType, class Ntk, class Simulator = default_simulator<SimulationType>>
simulate_sequential_result<SimulationType> mockturtle::simulate_sequential(Ntk const &ntk, uint32_t num_cycles, Simulator const &sim = Simulator(), simulate_sequential_params const &ps = {}) Simulates a sequential network over a number of clock cycles.
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.
This is what distinguishes it from
simulate, which evaluates the combinational logic exactly once and has no notion of a register: on a sequential networksimulatenever assigns the register outputs at all, and every value in their fanout cone is meaningless.The simulator follows the same concept as for
simulate, with one addition. If it providescompute_pi( index, cycle ), that overload is used and the primary inputs may take a different value in every cycle — seestimulus_simulator. A simulator offering onlycompute_pi( index )holds its assignment for the whole run, which is what a design with no primary inputs, such as an LFSR, wants anyway.A register whose reset value is undefined starts at
simulate_sequential_params::undefined_reset_value.Required network functions:
num_registersregister_atforeach_roforeach_riforeach_piforeach_poforeach_gateforeach_faninfanin_sizeget_constantconstant_valueget_nodeis_complementedcompute
Example
sequential<aig_network> aig = ...; // a 4-bit LFSR, say auto const result = simulate_sequential<bool>( aig, 15, default_simulator<bool>( std::vector<bool>{} ) ); for ( auto const& outputs : result.outputs ) { std::cout << outputs[0]; } // where it ended up auto const& state = result.final_state();
- Parameters:
ntk – The sequential network to simulate
num_cycles – Number of clock cycles to run
sim – The simulator
ps – Parameters
- Returns:
The primary output values and the register values, per clock cycle