1use hdl_cat_bits::Bits;
7use hdl_cat_circuit::Obj;
8use hdl_cat_error::{Error, Width};
9use hdl_cat_ir::{HdlGraphBuilder, Op, WireTy};
10use hdl_cat_kind::BitSeq;
11use hdl_cat_sync::{machine, Sync};
12
13pub type ShiftRegisterLeftSync<const N: usize> = Sync<Obj<Bits<N>>, Obj<bool>, Obj<Bits<N>>>;
19
20pub fn shift_register_left<const N: usize>() -> Result<ShiftRegisterLeftSync<N>, Error> {
27 (N >= 2)
28 .then_some(())
29 .ok_or_else(|| Error::WidthMismatch {
30 expected: Width::new(2),
31 actual: Width::new(u32::try_from(N).unwrap_or(u32::MAX)),
32 })?;
33
34 let width_n = u32::try_from(N).map_err(|_| Error::Overflow {
35 width: Width::new(u32::MAX),
36 })?;
37 let width_n_minus_1 = width_n - 1;
38
39 let (bld, state) = HdlGraphBuilder::new().with_wire(WireTy::Bits(width_n));
40 let (bld, new_bit) = bld.with_wire(WireTy::Bit);
41 let (bld, low_part) = bld.with_wire(WireTy::Bits(width_n_minus_1));
42 let (bld, next_state) = bld.with_wire(WireTy::Bits(width_n));
43
44 let bld = bld.with_instruction(
46 Op::Slice {
47 lo: 0,
48 hi: width_n_minus_1,
49 },
50 vec![state],
51 low_part,
52 )?;
53 let bld = bld.with_instruction(
55 Op::Concat {
56 low_width: 1,
57 high_width: width_n_minus_1,
58 },
59 vec![new_bit, low_part],
60 next_state,
61 )?;
62
63 let graph = bld.build();
64 let initial_state: BitSeq = (0..N).map(|_| false).collect();
65 Ok(machine::from_raw(
66 graph,
67 vec![state, new_bit],
68 vec![next_state, state],
69 initial_state,
70 1,
71 ))
72}
73
74#[cfg(test)]
75mod tests {
76 use super::shift_register_left;
77
78 #[test]
79 fn shift_register_rejects_width_below_two() {
80 assert!(shift_register_left::<1>().is_err());
81 assert!(shift_register_left::<0>().is_err());
82 }
83
84 #[test]
85 fn shift_register_has_two_instructions() -> Result<(), hdl_cat_error::Error> {
86 let s = shift_register_left::<8>()?;
87 assert_eq!(s.graph().instructions().len(), 2);
88 Ok(())
89 }
90
91 #[test]
92 fn shift_register_state_is_n_bits() -> Result<(), hdl_cat_error::Error> {
93 let s = shift_register_left::<4>()?;
94 assert_eq!(s.initial_state().len(), 4);
95 Ok(())
96 }
97}