Skip to main content

hdl_cat_std/
toggle.rs

1//! 1-bit toggle flip-flop.
2//!
3//! The output alternates `false → true → false → …` each cycle,
4//! starting from `false`.
5
6use hdl_cat_circuit::{CircuitUnit, Obj};
7use hdl_cat_error::Error;
8use hdl_cat_ir::{HdlGraphBuilder, Op, WireTy};
9use hdl_cat_kind::BitSeq;
10use hdl_cat_sync::{machine, Sync};
11
12/// A 1-bit toggle flip-flop.
13///
14/// State: `bool` starting at `false`.
15/// Input: [`CircuitUnit`] (no data input).
16/// Output: the current state; next cycle's state is its negation.
17pub type ToggleSync = Sync<Obj<bool>, CircuitUnit, Obj<bool>>;
18
19/// Construct a 1-bit toggle flip-flop.
20///
21/// # Errors
22///
23/// Infallible in practice; propagates any IR builder error.
24pub fn toggle_ff() -> Result<ToggleSync, Error> {
25    let (bld, state) = HdlGraphBuilder::new().with_wire(WireTy::Bit);
26    let (bld, next_state) = bld.with_wire(WireTy::Bit);
27    let bld = bld.with_instruction(Op::Not, vec![state], next_state)?;
28    let graph = bld.build();
29    Ok(machine::from_raw(
30        graph,
31        vec![state],
32        vec![next_state, state],
33        BitSeq::from_iter([false]),
34        1,
35    ))
36}
37
38#[cfg(test)]
39mod tests {
40    use super::toggle_ff;
41
42    #[test]
43    fn toggle_has_one_state_wire() -> Result<(), hdl_cat_error::Error> {
44        let t = toggle_ff()?;
45        assert_eq!(t.state_wire_count(), 1);
46        Ok(())
47    }
48
49    #[test]
50    fn toggle_initial_state_is_false() -> Result<(), hdl_cat_error::Error> {
51        let t = toggle_ff()?;
52        assert_eq!(t.initial_state().len(), 1);
53        assert!(!t.initial_state().bit(0));
54        Ok(())
55    }
56
57    #[test]
58    fn toggle_has_one_not_instruction() -> Result<(), hdl_cat_error::Error> {
59        let t = toggle_ff()?;
60        assert_eq!(t.graph().instructions().len(), 1);
61        Ok(())
62    }
63}