rust_hdl_widgets/i2c/
i2c_test_target.rs1use array_init::array_init;
2
3use crate::prelude::*;
4use rust_hdl_core::prelude::*;
5
6#[derive(LogicBlock)]
7pub struct I2CTestBus<const N: usize> {
8 pub endpoints: [I2CBusReceiver; N],
9 pub sda_state: Signal<Local, Bit>,
10 pub scl_state: Signal<Local, Bit>,
11}
12
13impl<const N: usize> Default for I2CTestBus<N> {
14 fn default() -> Self {
15 Self {
16 endpoints: array_init(|_| Default::default()),
17 sda_state: Default::default(),
18 scl_state: Default::default(),
19 }
20 }
21}
22
23impl<const N: usize> Logic for I2CTestBus<N> {
24 #[hdl_gen]
25 fn update(&mut self) {
26 self.sda_state.next = true;
27 self.scl_state.next = true;
28 for ndx in 0..N {
29 self.sda_state.next = self.sda_state.val() & !self.endpoints[ndx].sda.drive_low.val();
30 self.scl_state.next = self.scl_state.val() & !self.endpoints[ndx].scl.drive_low.val();
31 }
32 for ndx in 0..N {
33 self.endpoints[ndx].sda.line_state.next = self.sda_state.val();
34 self.endpoints[ndx].scl.line_state.next = self.scl_state.val();
35 }
36 }
37}
38
39#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
40enum State {
41 Idle,
42 GetPointer,
43 GetMSB,
44 GetLSB,
45 WriteMSB,
46 WriteLSB,
47 CheckMSBAck,
48 CheckLSBAck,
49}
50
51#[derive(LogicBlock)]
54pub struct I2CTestTarget {
55 pub i2c: I2CBusDriver,
57 pub clock: Signal<In, Clock>,
58 phy: I2CTarget,
59 mem: RAM<Bits<16>, 4>,
60 ptr: DFF<Bits<4>>,
61 address: Constant<Bits<7>>,
62 outgoing: DFF<Bits<8>>,
63 save: DFF<Bits<8>>,
64 state: DFF<State>,
65 active: DFF<Bit>,
66}
67
68impl I2CTestTarget {
69 pub fn new(address: u8) -> Self {
70 assert_eq!(address & 0x80, 0, "I2C addresses must be 7 bits");
71 Self {
72 i2c: Default::default(),
73 clock: Default::default(),
74 phy: Default::default(),
75 mem: Default::default(),
76 ptr: Default::default(),
77 address: Constant::new(address.to_bits()),
78 outgoing: Default::default(),
79 save: Default::default(),
80 state: Default::default(),
81 active: Default::default(),
82 }
83 }
84}
85
86impl Logic for I2CTestTarget {
87 #[hdl_gen]
88 fn update(&mut self) {
89 I2CBusDriver::link(&mut self.i2c, &mut self.phy.i2c);
90 clock!(self, clock, phy);
92 self.mem.read_clock.next = self.clock.val();
93 self.mem.write_clock.next = self.clock.val();
94 dff_setup!(self, clock, ptr, outgoing, save, state, active);
95 self.mem.write_data.next =
98 bit_cast::<16, 8>(self.save.q.val()) << 8 | bit_cast::<16, 8>(self.phy.from_bus.val());
99 self.mem.write_enable.next = false;
100 self.mem.write_address.next = self.ptr.q.val();
101 self.mem.read_address.next = self.ptr.q.val();
102 self.phy.active.next = self.active.q.val();
103 self.phy.to_bus.next = 0.into();
104 self.phy.write_enable.next = false;
105 match self.state.q.val() {
107 State::Idle => {
108 if self.phy.bus_write.val() {
109 if self.phy.from_bus.val().get_bits::<7>(1) == self.address.val() {
111 self.active.d.next = true;
112 if !self.phy.from_bus.val().get_bit(0) {
113 self.state.d.next = State::GetPointer;
114 } else {
115 self.state.d.next = State::WriteMSB;
116 }
117 } else {
118 self.active.d.next = false;
119 }
120 }
121 }
122 State::GetPointer => {
123 if self.phy.bus_write.val() {
124 self.ptr.d.next = self.phy.from_bus.val().get_bits::<4>(0);
125 self.state.d.next = State::GetMSB;
126 }
127 }
128 State::GetMSB => {
129 if self.phy.bus_write.val() {
130 self.save.d.next = self.phy.from_bus.val();
131 self.state.d.next = State::GetLSB;
132 }
133 }
134 State::GetLSB => {
135 self.mem.write_enable.next = self.phy.bus_write.val();
136 if self.phy.bus_write.val() {
137 self.state.d.next = State::Idle;
138 }
139 }
140 State::WriteMSB => {
141 if self.phy.write_ok.val() {
142 self.phy.to_bus.next = self.mem.read_data.val().get_bits::<8>(8);
143 self.phy.write_enable.next = true;
144 self.state.d.next = State::CheckMSBAck;
145 }
146 }
147 State::CheckMSBAck => {
148 if self.phy.ack.val() {
149 self.state.d.next = State::WriteLSB;
150 }
151 if self.phy.nack.val() {
152 self.state.d.next = State::Idle;
153 }
154 }
155 State::WriteLSB => {
156 if self.phy.write_ok.val() {
157 self.phy.to_bus.next = self.mem.read_data.val().get_bits::<8>(0);
158 self.phy.write_enable.next = true;
159 self.state.d.next = State::CheckLSBAck;
160 }
161 }
162 State::CheckLSBAck => {
163 if self.phy.ack.val() {
164 self.state.d.next = State::Idle;
165 }
166 if self.phy.nack.val() {
167 self.state.d.next = State::Idle;
168 }
169 }
170 _ => {
171 self.state.d.next = State::Idle;
172 }
173 }
174 if self.phy.stop.val() {
175 self.state.d.next = State::Idle;
176 self.active.d.next = false;
177 }
178 }
179}
180
181#[test]
182fn test_i2c_test_target_synthesizable() {
183 let mut uut = I2CTestTarget::new(0x53);
184 uut.connect_all();
185 let vlog = generate_verilog(&uut);
186 yosys_validate("i2c_test_target", &vlog).unwrap()
187}