rust_hdl_widgets/i2c/
i2c_test_target.rs

1use 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// Provides a simple read/write memory on an I2C bus
52// The memory is 16 bits wide, and there are 16 addresses.
53#[derive(LogicBlock)]
54pub struct I2CTestTarget {
55    // The I2C data lines must have external pullups.
56    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 internal logic
91        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        // Latch prevention
96        // Wire up the RAM
97        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        // Default controls
106        match self.state.q.val() {
107            State::Idle => {
108                if self.phy.bus_write.val() {
109                    // Check if the address matches
110                    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}