1use hdl_cat_bits::Bits;
8use hdl_cat_circuit::{CircuitUnit, Obj};
9use hdl_cat_error::{Error, Width};
10use hdl_cat_ir::{BinOp, HdlGraphBuilder, Op, WireTy};
11use hdl_cat_kind::BitSeq;
12use hdl_cat_sync::{machine, Sync};
13
14pub type CounterSync<const N: usize> = Sync<Obj<Bits<N>>, CircuitUnit, Obj<Bits<N>>>;
20
21pub fn counter<const N: usize>() -> Result<CounterSync<N>, Error> {
38 let width = u32::try_from(N).map_err(|_| Error::Overflow {
39 width: Width::new(u32::MAX),
40 })?;
41 let ty = WireTy::Bits(width);
42
43 let (bld, state) = HdlGraphBuilder::new().with_wire(ty.clone());
44 let (bld, one) = bld.with_wire(ty.clone());
45 let (bld, next_state) = bld.with_wire(ty.clone());
46
47 let bld = bld.with_instruction(
48 Op::Const {
49 bits: one_bitseq(N),
50 ty: ty.clone(),
51 },
52 vec![],
53 one,
54 )?;
55 let bld = bld.with_instruction(Op::Bin(BinOp::Add), vec![state, one], next_state)?;
56
57 let graph = bld.build();
58 let initial_state = zero_bitseq(N);
59
60 Ok(machine::from_raw(
64 graph,
65 vec![state],
66 vec![next_state, state],
67 initial_state,
68 1,
69 ))
70}
71
72fn zero_bitseq(n: usize) -> BitSeq {
73 (0..n).map(|_| false).collect()
74}
75
76fn one_bitseq(n: usize) -> BitSeq {
77 (0..n).map(|i| i == 0).collect()
78}
79
80#[cfg(test)]
81mod tests {
82 use super::counter;
83
84 #[test]
85 fn counter_has_one_state_wire() -> Result<(), hdl_cat_error::Error> {
86 let c = counter::<8>()?;
87 assert_eq!(c.state_wire_count(), 1);
88 Ok(())
89 }
90
91 #[test]
92 fn counter_initial_state_is_zero() -> Result<(), hdl_cat_error::Error> {
93 let c = counter::<8>()?;
94 assert_eq!(c.initial_state().len(), 8);
95 assert!(c.initial_state().as_slice().iter().all(|b| !*b));
96 Ok(())
97 }
98
99 #[test]
100 fn counter_has_two_instructions() -> Result<(), hdl_cat_error::Error> {
101 let c = counter::<4>()?;
102 assert_eq!(c.graph().instructions().len(), 2);
104 Ok(())
105 }
106}