Skip to main content

Module time

Module time 

Source
Expand description

Modules that model time within the simulations.

Clocks are used to control time within a GWR simulation. The engine supports any number of clocks running at different frequencies.

Each clock represents a clock domain. This lets one simulation contain blocks that operate at different frequencies without converting everything into one global tick rate. For example, a platform can model a 1GHz block and a 2GHz block with separate clocks; one tick on the 1GHz clock and two ticks on the 2GHz clock both represent 1.0ns, but each clock domain keeps its own local tick count.

The engine schedules clock waits by absolute simulation time and then by clock phase. Tasks remain event-driven: they only wake when their awaited event, port, or clock wait is ready.

If two clock ticks resolve to exactly the same time and phase the engine does not provide any guarantees about which events will be evaluated first.

§Default Clock

The engine is responsible for managing clocks. Use the default clock when the frequency does not matter (the default is currently 1GHz, but that may change):

let mut engine = Engine::default();
let clock = engine.default_clock();

§Creating a Clock

When a well-defined clock frequency is required, create clocks explicitly. A non-default clock runs at a user-specified frequency and can be created with the engine’s helper functions.

The following two clocks are equivalent:

let mut engine = Engine::default();
let clock_a = engine.clock_ghz(1.0);
let clock_b = engine.clock_mhz(1000.0);

§Advancing Time

Time is advanced by waiting an integer number of ticks on a clock. In the snippet below the println! will be called when the time has advanced to 1.0ns.

let clock = engine.clock_ghz(1.0);
clock.wait_ticks(1).await;
println!("Time now {:.2}", clock.time_now_ns());

§Clock Phases

Clock time is represented using the ClockTick type, made up of a tick count and a phase within that tick. Phases provide deterministic ordering inside a tick.

The two standard phases are:

  • phase::BEGIN: the start of a tick. wait_ticks(...) waits resume in this phase.
  • phase::END: the end of a tick. Components can wait for this phase when they need all same-tick releases or bookkeeping to happen before starting new activity.

Custom u32 phase values can be used between phase::BEGIN and phase::END when a model needs additional deterministic ordering points. A task can use wait_phase(phase) to move later within the current tick, or next_tick_and_phase(phase) to wait until a specific phase in the next tick.

For example, certain models use phase::END before starting new activities in order to guarantee that any completing activities have been processed first:

let clock = engine.clock_ghz(1.0);
clock.wait_phase(phase::END).await;
// Begin activity that should be ordered after same-tick completions.

§Background Tasks

By default a simulation will run until all events have completed. However, sometimes it is useful to create a monitor task like a progress bar that just needs to run as long as the rest of the simulation.

In order to do this the wait_ticks_or_exit function can be called. This lets the engine know that it does not have to keep running if this is the only thread of activity left. For example, the code below will start a thread of activity that prints the current time in ns periodically as long as the simulation is running:

let clock = engine.clock_ghz(1.0);
spawner.spawn(async move {
  loop {
    clock.wait_ticks_or_exit(1000).await;
    println!("Time now {:.2}", clock.time_now_ns());
  }
});

Modules§

clock
This module represents the time during a simulation.
simtime
This module represents the time during a simulation.

Functions§

compute_adjusted_value_and_rate