1use crate::edge_detector::EdgeDetector;
2use crate::spi::master::{SPIConfig, SPIWiresSlave};
3use crate::synchronizer::BitSynchronizer;
4use crate::{dff::DFF, dff_setup};
5use rust_hdl_core::prelude::*;
6
7#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
8enum SPISlaveState {
9 Boot,
10 Idle,
11 Armed,
12 Capture,
13 Hold,
14 Update,
15 Settle,
16 Waiting,
17 Hangup,
18 Disabled,
19}
20
21#[derive(LogicBlock)]
26pub struct SPISlave<const N: usize> {
27 pub clock: Signal<In, Clock>,
29 pub wires: SPIWiresSlave,
31 pub disabled: Signal<In, Bit>,
33 pub busy: Signal<Out, Bit>,
35 pub data_inbound: Signal<Out, Bits<N>>,
37 pub start_send: Signal<In, Bit>,
40 pub data_outbound: Signal<In, Bits<N>>,
42 pub bits: Signal<In, Bits<16>>,
44 pub continued_transaction: Signal<In, Bit>,
46 pub transfer_done: Signal<Out, Bit>,
48 miso_flop: DFF<Bit>,
49 done_flop: DFF<Bit>,
50 register_out: DFF<Bits<N>>,
51 register_in: DFF<Bits<N>>,
52 state: DFF<SPISlaveState>,
53 pointer: DFF<Bits<16>>,
54 bits_saved: DFF<Bits<16>>,
55 continued_saved: DFF<Bit>,
56 capture_detector: EdgeDetector,
57 advance_detector: EdgeDetector,
58 edge_detector: EdgeDetector,
59 mclk_synchronizer: BitSynchronizer,
60 csel_synchronizer: BitSynchronizer,
61 escape: DFF<Bits<16>>,
62 clocks_per_baud: Constant<Bits<16>>,
63 cpha: Constant<Bit>,
64 cs_off: Constant<Bit>,
65 boot_delay: DFF<Bits<4>>,
66}
67
68impl<const N: usize> SPISlave<N> {
83 pub fn new(config: SPIConfig) -> Self {
95 assert!(config.cpha | (config.clock_speed >= 40 * config.speed_hz));
99 Self {
100 clock: Default::default(),
101 wires: Default::default(),
102 disabled: Default::default(),
103 busy: Default::default(),
104 data_inbound: Default::default(),
105 start_send: Default::default(),
106 data_outbound: Default::default(),
107 bits: Default::default(),
108 continued_transaction: Default::default(),
109 transfer_done: Default::default(),
110 miso_flop: Default::default(),
111 done_flop: Default::default(),
112 register_out: Default::default(),
113 register_in: Default::default(),
114 state: Default::default(),
115 pointer: Default::default(),
116 bits_saved: Default::default(),
117 continued_saved: Default::default(),
118 capture_detector: EdgeDetector::new(!(config.cpol ^ config.cpha)),
119 advance_detector: EdgeDetector::new(config.cpol ^ config.cpha),
120 edge_detector: EdgeDetector::new(!config.cs_off),
121 mclk_synchronizer: BitSynchronizer::default(),
122 csel_synchronizer: BitSynchronizer::default(),
123 escape: Default::default(),
124 clocks_per_baud: Constant::new((2 * config.clock_speed / config.speed_hz).into()),
125 cpha: Constant::new(config.cpha),
126 cs_off: Constant::new(config.cs_off),
127 boot_delay: Default::default(),
128 }
129 }
130}
131
132impl<const N: usize> Logic for SPISlave<N> {
133 #[hdl_gen]
134 fn update(&mut self) {
135 dff_setup!(
136 self,
137 clock,
138 miso_flop,
139 done_flop,
140 register_out,
141 register_in,
142 state,
143 pointer,
144 bits_saved,
145 continued_saved,
146 escape,
147 boot_delay
148 );
149 clock!(
150 self,
151 clock,
152 capture_detector,
153 advance_detector,
154 edge_detector,
155 mclk_synchronizer,
156 csel_synchronizer
157 );
158 self.capture_detector.input_signal.next = self.mclk_synchronizer.sig_out.val();
160 self.advance_detector.input_signal.next = self.mclk_synchronizer.sig_out.val();
161 self.edge_detector.input_signal.next = self.csel_synchronizer.sig_out.val();
162 self.mclk_synchronizer.sig_in.next = self.wires.mclk.val();
164 self.csel_synchronizer.sig_in.next = self.wires.msel.val();
165 self.busy.next = (self.state.q.val() != SPISlaveState::Idle)
167 | (self.csel_synchronizer.sig_out.val() != self.cs_off.val());
168 if self.state.q.val() != SPISlaveState::Disabled {
169 self.wires.miso.next = self.miso_flop.q.val();
170 } else {
171 self.wires.miso.next = true;
172 }
173 self.data_inbound.next = self.register_in.q.val();
174 self.transfer_done.next = self.done_flop.q.val();
175 self.done_flop.d.next = false;
176 self.miso_flop.d.next = self
177 .register_out
178 .q
179 .val()
180 .get_bit(self.pointer.q.val().index());
181 self.boot_delay.d.next = self.boot_delay.q.val() + 1;
182 match self.state.q.val() {
183 SPISlaveState::Boot => {
184 if self.boot_delay.q.val() == 8 {
185 self.state.d.next = SPISlaveState::Idle;
186 }
187 }
188 SPISlaveState::Idle => {
189 if self.edge_detector.edge_signal.val() {
190 self.register_in.d.next = 0.into();
191 self.state.d.next = SPISlaveState::Waiting;
192 self.pointer.d.next = 0.into();
193 self.escape.d.next = 0.into();
194 } else if self.start_send.val() {
195 self.register_out.d.next = self.data_outbound.val();
196 self.bits_saved.d.next = self.bits.val();
197 self.continued_saved.d.next = self.continued_transaction.val();
198 self.pointer.d.next = self.bits.val() - 1;
199 self.register_in.d.next = 0.into();
200 self.state.d.next = SPISlaveState::Armed;
201 } else if self.disabled.val() {
202 self.state.d.next = SPISlaveState::Disabled;
203 }
204 }
205 SPISlaveState::Armed => {
206 if self.csel_synchronizer.sig_out.val() != self.cs_off.val() {
207 if self.cpha.val() & !self.continued_saved.q.val() {
208 self.state.d.next = SPISlaveState::Waiting;
209 } else {
210 self.state.d.next = SPISlaveState::Settle;
211 }
212 }
213 }
214 SPISlaveState::Waiting => {
215 if self.advance_detector.edge_signal.val() {
216 self.state.d.next = SPISlaveState::Settle;
217 }
218 if self.cpha.val()
220 & !self.continued_saved.q.val()
221 & (self.csel_synchronizer.sig_out.val() == self.cs_off.val())
222 {
223 self.state.d.next = SPISlaveState::Idle;
224 }
225 if !self.cpha.val() & (self.csel_synchronizer.sig_out.val() == self.cs_off.val()) {
226 self.escape.d.next = self.escape.q.val() + 1;
227 if self.escape.q.val().all() {
228 self.state.d.next = SPISlaveState::Idle;
229 }
230 }
231 }
232 SPISlaveState::Settle => {
233 if self.capture_detector.edge_signal.val() {
234 self.state.d.next = SPISlaveState::Capture;
235 }
236 if self.csel_synchronizer.sig_out.val() == self.cs_off.val() {
238 self.state.d.next = SPISlaveState::Idle;
239 }
240 }
241 SPISlaveState::Capture => {
242 self.register_in.d.next = (self.register_in.q.val() << 1)
243 | bit_cast::<N, 1>(self.wires.mosi.val().into());
244 self.state.d.next = SPISlaveState::Hold;
245 }
246 SPISlaveState::Hold => {
247 if self.advance_detector.edge_signal.val() {
248 if self.pointer.q.val().any() {
249 self.state.d.next = SPISlaveState::Update;
250 } else {
251 if self.continued_saved.q.val() {
252 self.done_flop.d.next = true;
253 self.state.d.next = SPISlaveState::Idle;
254 } else {
255 self.state.d.next = SPISlaveState::Hangup;
256 }
257 }
258 self.escape.d.next = 0.into();
259 } else if self.csel_synchronizer.sig_out.val() == self.cs_off.val() {
260 self.done_flop.d.next = true;
261 self.state.d.next = SPISlaveState::Idle;
262 } else {
263 self.escape.d.next = self.escape.q.val() + 1;
264 }
265 if self.escape.q.val() == self.clocks_per_baud.val() {
266 self.done_flop.d.next = true;
267 self.state.d.next = SPISlaveState::Idle;
268 }
269 }
270 SPISlaveState::Update => {
271 if self.pointer.q.val().any() {
272 self.pointer.d.next = self.pointer.q.val() - 1;
273 }
274 self.state.d.next = SPISlaveState::Settle;
275 }
276 SPISlaveState::Hangup => {
277 if self.csel_synchronizer.sig_out.val() == self.cs_off.val() {
278 self.done_flop.d.next = true;
279 self.state.d.next = SPISlaveState::Idle;
280 }
281 if self.disabled.val() {
282 self.state.d.next = SPISlaveState::Disabled;
283 }
284 }
285 SPISlaveState::Disabled => {
286 if !self.disabled.val() {
287 self.state.d.next = SPISlaveState::Idle;
288 self.register_out.d.next = 0.into();
289 }
290 }
291 _ => {
292 self.state.d.next = SPISlaveState::Boot;
293 }
294 }
295 }
296}
297
298#[test]
299fn test_spi_slave_synthesizes() {
300 let config = SPIConfig {
301 clock_speed: 48_000_000,
302 cs_off: true,
303 mosi_off: false,
304 speed_hz: 1_000_000,
305 cpha: true,
306 cpol: false,
307 };
308 let mut uut: SPISlave<64> = SPISlave::new(config);
309 uut.connect_all();
310 yosys_validate("spi_slave", &generate_verilog(&uut)).unwrap();
311}