1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
use crate::core::prelude::*;
use crate::widgets::prelude::*;
#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
enum State {
    Idle,
    Start,
    Reading,
    Waiting,
    Flag,
    Ack,
    AckHold,
    WaitEndTransaction,
    CheckStop,
    Writing,
    WaitSCLHigh,
    WaitSCLLow,
    WaitSCLHighAck,
    CollectAck,
}
#[derive(LogicBlock, Default)]
pub struct I2CTarget {
    pub i2c: I2CBusDriver,
    pub clock: Signal<In, Clock>,
    pub from_bus: Signal<Out, Bits<8>>,
    pub bus_write: Signal<Out, Bit>,
    pub active: Signal<In, Bit>,
    pub stop: Signal<Out, Bit>,
    pub to_bus: Signal<In, Bits<8>>,
    pub write_enable: Signal<In, Bit>,
    pub ack: Signal<Out, Bit>,
    pub nack: Signal<Out, Bit>,
    pub write_ok: Signal<Out, Bit>,
    state: DFF<State>,
    scl_is_high: Signal<Local, Bit>,
    sda_is_high: Signal<Local, Bit>,
    sda_flop: DFF<Bit>,
    clear_sda: Signal<Local, Bit>,
    set_sda: Signal<Local, Bit>,
    read_bit: DFF<Bit>,
    count: DFF<Bits<4>>,
    accum: DFF<Bits<8>>,
}
impl Logic for I2CTarget {
    #[hdl_gen]
    fn update(&mut self) {
        dff_setup!(self, clock, state, sda_flop, read_bit, count, accum);
        self.i2c.scl.drive_low.next = false;
        self.i2c.sda.drive_low.next = self.sda_flop.q.val();
        self.sda_is_high.next = self.i2c.sda.line_state.val();
        self.scl_is_high.next = self.i2c.scl.line_state.val();
        self.set_sda.next = false;
        self.clear_sda.next = false;
        self.from_bus.next = self.accum.q.val();
        self.bus_write.next = false;
        self.stop.next = false;
        self.ack.next = false;
        self.nack.next = false;
        self.write_ok.next = false;
        match self.state.q.val() {
            State::Idle => {
                self.set_sda.next = true;
                self.count.d.next = 0.into();
                if !self.sda_is_high.val() & self.scl_is_high.val() {
                    self.state.d.next = State::Start;
                }
            }
            State::Start => {
                if self.sda_is_high.val() {
                    self.state.d.next = State::Idle;
                } else if !self.sda_is_high.val() & !self.scl_is_high.val() {
                    self.state.d.next = State::Reading;
                }
            }
            State::Writing => {
                if self.accum.q.val().get_bit(7) {
                    self.set_sda.next = true;
                } else {
                    self.clear_sda.next = true;
                }
                self.count.d.next = self.count.q.val() + 1;
                self.accum.d.next = self.accum.q.val() << 1;
                self.state.d.next = State::WaitSCLHigh;
                if self.count.q.val() == 8 {
                    self.state.d.next = State::WaitSCLHighAck;
                }
            }
            State::WaitSCLHighAck => {
                if self.scl_is_high.val() {
                    self.set_sda.next = true;
                    self.state.d.next = State::CollectAck;
                }
            }
            State::CollectAck => {
                if !self.scl_is_high.val() {
                    if self.sda_is_high.val() {
                        self.nack.next = true;
                    } else {
                        self.ack.next = true;
                    }
                    self.state.d.next = State::Reading;
                }
            }
            State::WaitSCLHigh => {
                if self.scl_is_high.val() {
                    self.state.d.next = State::WaitSCLLow;
                }
            }
            State::WaitSCLLow => {
                if !self.scl_is_high.val() {
                    self.state.d.next = State::Writing;
                }
            }
            State::Reading => {
                self.write_ok.next = true;
                if self.write_enable.val() {
                    self.accum.d.next = self.to_bus.val();
                    self.count.d.next = 0.into();
                    self.state.d.next = State::Writing;
                }
                if self.scl_is_high.val() {
                    self.read_bit.d.next = self.sda_is_high.val();
                    self.state.d.next = State::Waiting;
                }
            }
            State::Waiting => {
                if !self.scl_is_high.val() {
                    self.accum.d.next =
                        (self.accum.q.val() << 1) | bit_cast::<8, 1>(self.read_bit.q.val().into());
                    self.count.d.next = self.count.q.val() + 1;
                    if self.count.q.val() == 7 {
                        self.state.d.next = State::Flag;
                    } else {
                        self.state.d.next = State::Reading;
                    }
                }
                if !self.read_bit.q.val() & self.sda_is_high.val() & self.scl_is_high.val() {
                    self.stop.next = true;
                    self.state.d.next = State::Idle;
                }
                if self.read_bit.q.val() & !self.sda_is_high.val() & self.scl_is_high.val() {
                    self.stop.next = true;
                    self.state.d.next = State::Idle;
                }
            }
            State::Flag => {
                self.bus_write.next = true;
                self.accum.d.next = 0.into();
                self.count.d.next = 0.into();
                self.state.d.next = State::Ack;
            }
            State::Ack => {
                self.clear_sda.next = self.active.val();
                if !self.active.val() {
                    self.state.d.next = State::WaitEndTransaction;
                }
                if self.scl_is_high.val() {
                    self.state.d.next = State::AckHold;
                }
            }
            State::AckHold => {
                if !self.scl_is_high.val() {
                    self.set_sda.next = true;
                    self.state.d.next = State::Reading;
                }
            }
            State::WaitEndTransaction => {
                if self.scl_is_high.val() & !self.sda_is_high.val() {
                    self.state.d.next = State::CheckStop;
                }
            }
            State::CheckStop => {
                if self.scl_is_high.val() & self.sda_is_high.val() {
                    self.state.d.next = State::Idle;
                    self.stop.next = true;
                }
            }
            _ => {
                self.state.d.next = State::Idle;
            }
        }
        if self.set_sda.val() {
            self.sda_flop.d.next = false;
        }
        if self.clear_sda.val() {
            self.sda_flop.d.next = true;
        }
    }
}