rust_hdl_widgets/
shot.rs

1use rust_hdl_core::prelude::*;
2use std::time::Duration;
3
4use crate::{dff::DFF, dff_setup};
5
6#[derive(Clone, Debug, LogicBlock)]
7pub struct Shot<const N: usize> {
8    pub trigger: Signal<In, Bit>,
9    pub active: Signal<Out, Bit>,
10    pub clock: Signal<In, Clock>,
11    pub fired: Signal<Out, Bit>,
12    duration: Constant<Bits<N>>,
13    counter: DFF<Bits<N>>,
14    state: DFF<Bit>,
15}
16
17impl<const N: usize> Shot<N> {
18    pub fn new(frequency: u64, duration: Duration) -> Self {
19        let duration_nanos = duration.as_nanos() as f64 * NANOS_PER_FEMTO; // duration in femtos
20        let clock_period_nanos = freq_hz_to_period_femto(frequency as f64);
21        let clocks = (duration_nanos / clock_period_nanos).floor() as u64;
22        assert!(clocks < (1_u64 << N));
23        Self {
24            trigger: Signal::default(),
25            active: Signal::new_with_default(false),
26            clock: Signal::default(),
27            fired: Default::default(),
28            duration: Constant::new(clocks.into()),
29            counter: Default::default(),
30            state: Default::default(),
31        }
32    }
33}
34
35impl<const N: usize> Logic for Shot<N> {
36    #[hdl_gen]
37    fn update(&mut self) {
38        dff_setup!(self, clock, counter, state);
39        if self.state.q.val() {
40            self.counter.d.next = self.counter.q.val() + 1;
41        }
42        self.fired.next = false;
43        if self.state.q.val() && (self.counter.q.val() == self.duration.val()) {
44            self.state.d.next = false;
45            self.fired.next = true;
46        }
47        self.active.next = self.state.q.val();
48        if self.trigger.val() {
49            self.state.d.next = true;
50            self.counter.d.next = 0.into();
51        }
52    }
53}