Expand description
A component that adds delay_ticks between receiving anything and sending
it on to its output.
The Delay can be configured such that it will return an error if the
output is ever blocked. Otherwise it will implicitly assert back-pressure on
the input.
§Ports
This component has the following ports:
- One input port:
rx - One output port:
tx
§Function
Fundamentally the Delay’s functionality is to:
loop {
let value = rx.get()?.await;
clock.wait_ticks(delay_ticks).await;
tx.put(value)?.await;
}However, the problem with this is that the input ends up being blocked if the output does not instantly consume the value. Therefore the Delay is actually split into two halves that manage the ports independently.
§Input
A simplified view of how the input side works is:
loop {
// Receive value from input
let value = rx.get()?.await;
// Compute time at which it should leave Delay
let mut tick = clock.tick_now();
tick.set_tick(tick.tick() + delay_ticks as u64);
// Send to the output side
pending.borrow_mut().push_back((value, tick));
// Wake up output if required
pending_changed.notify()?;
}§Output
A simplified view of how the output side works is:
loop {
// Get next value and tick at which to send value
if let Some((value, tick)) = pending.borrow_mut().pop_front() {
// Wait for correct time
let tick_now = clock.tick_now();
clock.wait_ticks(tick.tick() - tick_now.tick()).await;
// Send value
tx.put(value)?.await;
} else {
// Wait to be notified of new data
pending_changed.listen().await;
}
}§Using a Delay
A Delay simply needs to be created with the latency through it and connected between components.
// Create the components
let source = Source::new_and_register(&engine, top, "source", to_send)?;
let delay = Delay::new_and_register(&engine, &clock, top, "delay", delay_ticks)?;
let sink = Sink::new_and_register(&engine, &clock, top, "sink")?;
// Connect the ports
connect_port!(source, tx => delay, rx)?;
connect_port!(delay, tx => sink, rx)?;
run_simulation!(engine);