1use crate::periph::ControllerPort;
23use crate::{read_u32, read_u8, write_u16, write_u8};
24use psx_hw::sio::sio0;
25
26#[derive(Copy, Clone, Debug, PartialEq, Eq)]
28pub enum Port {
29 One,
31 Two,
33}
34
35impl Port {
36 #[inline(always)]
38 pub const fn is_two(self) -> bool {
39 matches!(self, Port::Two)
40 }
41}
42
43#[derive(Copy, Clone, Debug, PartialEq, Eq)]
46pub struct Timing {
47 pub setup_spins: u32,
50 pub byte_spins: u32,
52 pub ack_spins: u32,
55}
56
57impl Timing {
58 pub const PAD: Timing = Timing {
62 setup_spins: 1_024,
63 byte_spins: 32_768,
64 ack_spins: 2_048,
65 };
66
67 pub const CARD: Timing = Timing {
71 setup_spins: 1_024,
72 byte_spins: 32_768,
73 ack_spins: 200_000,
74 };
75}
76
77#[derive(Copy, Clone, Debug, PartialEq, Eq)]
79pub enum ExchangeError {
80 TxTimeout,
82 RxTimeout,
84 AckTimeout {
87 reply: u8,
89 },
90 AckStuck {
92 reply: u8,
94 },
95}
96
97pub trait Transport {
104 fn status(&mut self) -> u32;
106 fn receive(&mut self) -> u8;
108 fn transmit(&mut self, byte: u8);
110 fn set_mode(&mut self, value: u16);
112 fn set_baud(&mut self, value: u16);
114 fn set_control(&mut self, value: u16);
116
117 fn select(&mut self, port: Port) {
123 self.select_with(port, false);
124 }
125
126 fn select_with(&mut self, port: Port, arm_ack_irq: bool) {
130 self.set_mode(sio0::MODE_8N1);
131 self.set_baud(sio0::BAUD_250KHZ);
132 self.set_control(sio0::ctrl::ACK);
135 self.set_control(sio0::selected_ctrl(port.is_two(), arm_ack_irq));
136 }
137
138 fn deselect(&mut self) {
140 self.set_control(0);
141 }
142
143 fn reset(&mut self) {
146 self.set_control(sio0::ctrl::RESET);
147 }
148
149 fn drain_receive(&mut self) {
153 let mut popped = 0;
154 while self.status() & sio0::stat::RX_NOT_EMPTY != 0 && popped < 16 {
155 let _ = self.receive();
156 popped += 1;
157 }
158 }
159
160 fn delay(&mut self, spins: u32) {
162 let mut remaining = spins;
163 while remaining > 0 {
164 let _ = self.status();
165 remaining -= 1;
166 core::hint::spin_loop();
167 }
168 }
169
170 fn wait_status_set(&mut self, mask: u32, spins: u32) -> bool {
173 let mut remaining = spins;
174 while self.status() & mask == 0 {
175 if remaining == 0 {
176 return false;
177 }
178 remaining -= 1;
179 core::hint::spin_loop();
180 }
181 true
182 }
183
184 fn wait_status_clear(&mut self, mask: u32, spins: u32) -> bool {
187 let mut remaining = spins;
188 while self.status() & mask != 0 {
189 if remaining == 0 {
190 return false;
191 }
192 remaining -= 1;
193 core::hint::spin_loop();
194 }
195 true
196 }
197
198 fn begin(&mut self, port: Port, timing: Timing) -> bool {
205 self.select(port);
206 self.delay(timing.setup_spins);
207 self.drain_receive();
208 self.wait_status_clear(sio0::stat::DSR_LEVEL, timing.ack_spins)
209 }
210
211 fn finish(&mut self, succeeded: bool) {
214 self.deselect();
215 if !succeeded {
216 self.reset();
217 }
218 }
219
220 fn exchange(&mut self, byte: u8, is_last: bool, timing: Timing) -> Result<u8, ExchangeError> {
231 if !self.wait_status_set(sio0::stat::TX_READY, timing.byte_spins) {
232 return Err(ExchangeError::TxTimeout);
233 }
234 self.transmit(byte);
235 let mut ack_seen = false;
236 let mut remaining = timing.byte_spins;
237 loop {
238 let status = self.status();
239 ack_seen |= status & sio0::stat::DSR_LEVEL != 0;
240 if status & sio0::stat::RX_NOT_EMPTY != 0 {
241 break;
242 }
243 if remaining == 0 {
244 return Err(ExchangeError::RxTimeout);
245 }
246 remaining -= 1;
247 core::hint::spin_loop();
248 }
249 let reply = self.receive();
250 if !is_last {
251 if !ack_seen && !self.wait_status_set(sio0::stat::DSR_LEVEL, timing.ack_spins) {
252 return Err(ExchangeError::AckTimeout { reply });
253 }
254 if !self.wait_status_clear(sio0::stat::DSR_LEVEL, timing.ack_spins) {
255 return Err(ExchangeError::AckStuck { reply });
256 }
257 }
258 Ok(reply)
259 }
260}
261
262impl Transport for ControllerPort {
263 #[inline(always)]
264 fn status(&mut self) -> u32 {
265 unsafe { read_u32(sio0::STAT) }
269 }
270
271 #[inline(always)]
272 fn receive(&mut self) -> u8 {
273 unsafe { read_u8(sio0::DATA) }
275 }
276
277 #[inline(always)]
278 fn transmit(&mut self, byte: u8) {
279 unsafe { write_u8(sio0::DATA, byte) }
281 }
282
283 #[inline(always)]
284 fn set_mode(&mut self, value: u16) {
285 unsafe { write_u16(sio0::MODE, value) }
287 }
288
289 #[inline(always)]
290 fn set_baud(&mut self, value: u16) {
291 unsafe { write_u16(sio0::BAUD, value) }
293 }
294
295 #[inline(always)]
296 fn set_control(&mut self, value: u16) {
297 unsafe { write_u16(sio0::CTRL, value) }
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 extern crate std;
306
307 use super::*;
308 use std::vec::Vec;
309
310 #[derive(Default)]
313 struct Script {
314 status: Vec<u32>,
315 reads: usize,
316 received: Vec<u8>,
317 sent: Vec<u8>,
318 control: Vec<u16>,
319 }
320
321 impl Script {
322 fn with_status(words: &[u32]) -> Self {
323 Script {
324 status: words.to_vec(),
325 ..Script::default()
326 }
327 }
328 }
329
330 impl Transport for Script {
331 fn status(&mut self) -> u32 {
332 let word = self
334 .status
335 .get(self.reads)
336 .or(self.status.last())
337 .copied()
338 .unwrap_or(0);
339 self.reads += 1;
340 word
341 }
342 fn receive(&mut self) -> u8 {
343 self.received.pop().unwrap_or(0xFF)
344 }
345 fn transmit(&mut self, byte: u8) {
346 self.sent.push(byte);
347 }
348 fn set_mode(&mut self, _value: u16) {}
349 fn set_baud(&mut self, _value: u16) {}
350 fn set_control(&mut self, value: u16) {
351 self.control.push(value);
352 }
353 }
354
355 const TX: u32 = sio0::stat::TX_READY;
356 const RX: u32 = sio0::stat::RX_NOT_EMPTY;
357 const DSR: u32 = sio0::stat::DSR_LEVEL;
358 const TIMING: Timing = Timing {
359 setup_spins: 2,
360 byte_spins: 4,
361 ack_spins: 4,
362 };
363
364 #[test]
365 fn the_token_is_the_only_way_to_a_port_that_implements_the_transport() {
366 fn takes_transport<T: Transport>(_: &mut T) {}
367 let mut port = unsafe { ControllerPort::steal() };
369 takes_transport(&mut port);
370 assert_eq!(core::mem::size_of::<ControllerPort>(), 0);
371 }
372
373 #[test]
374 fn select_clears_the_latch_then_asserts_the_port_without_arming_the_ack_interrupt() {
375 for (port, selected) in [(Port::One, 0x0003), (Port::Two, 0x2003)] {
376 let mut bus = Script::default();
377 bus.select(port);
378 assert_eq!(bus.control, [sio0::ctrl::ACK, selected]);
379 assert_eq!(selected & sio0::ctrl::ACK_IRQ_EN, 0);
380 }
381 }
382
383 #[test]
384 fn a_failed_transaction_resets_the_uart_and_a_clean_one_only_releases_the_port() {
385 let mut bus = Script::default();
386 bus.finish(true);
387 assert_eq!(bus.control, [0]);
388 let mut bus = Script::default();
389 bus.finish(false);
390 assert_eq!(bus.control, [0, sio0::ctrl::RESET]);
391 }
392
393 #[test]
394 fn begin_drops_stale_bytes_and_waits_for_a_held_ack_to_release() {
395 let mut bus = Script::with_status(&[0, 0, RX, 0, DSR, DSR, 0]);
398 bus.received.push(0x55);
399 assert!(bus.begin(Port::One, TIMING));
400 assert!(bus.received.is_empty());
401
402 let mut stuck = Script::with_status(&[DSR]);
403 assert!(!stuck.begin(Port::One, TIMING));
404 }
405
406 #[test]
407 fn an_acknowledged_byte_waits_for_ack_to_assert_and_release() {
408 let mut bus = Script::with_status(&[TX, RX, DSR, 0]);
410 bus.received.push(0x41);
411 assert_eq!(bus.exchange(0x42, false, TIMING), Ok(0x41));
412 assert_eq!(bus.sent, [0x42]);
413 assert!(bus.control.is_empty());
415 }
416
417 #[test]
418 fn an_ack_seen_while_the_reply_shifts_in_is_not_waited_for_again() {
419 let mut bus = Script::with_status(&[TX, DSR, RX, 0]);
422 bus.received.push(0x5A);
423 assert_eq!(bus.exchange(0x00, false, TIMING), Ok(0x5A));
424 }
425
426 #[test]
427 fn the_last_byte_of_a_packet_is_never_waited_on() {
428 let mut bus = Script::with_status(&[TX, RX]);
429 bus.received.push(0x80);
430 assert_eq!(bus.exchange(0x00, true, TIMING), Ok(0x80));
431 assert_eq!(bus.reads, 2);
433 }
434
435 #[test]
436 fn each_failure_is_reported_with_its_stage() {
437 let mut bus = Script::with_status(&[0]);
438 assert_eq!(
439 bus.exchange(0x01, false, TIMING),
440 Err(ExchangeError::TxTimeout)
441 );
442 assert!(bus.sent.is_empty());
443
444 let mut bus = Script::with_status(&[TX, 0]);
445 assert_eq!(
446 bus.exchange(0x01, false, TIMING),
447 Err(ExchangeError::RxTimeout)
448 );
449
450 let mut bus = Script::with_status(&[TX, RX, 0]);
451 bus.received.push(0xFF);
452 assert_eq!(
453 bus.exchange(0x01, false, TIMING),
454 Err(ExchangeError::AckTimeout { reply: 0xFF })
455 );
456
457 let mut bus = Script::with_status(&[TX, RX | DSR, DSR]);
458 bus.received.push(0x41);
459 assert_eq!(
460 bus.exchange(0x01, false, TIMING),
461 Err(ExchangeError::AckStuck { reply: 0x41 })
462 );
463 }
464
465 #[test]
466 fn the_pad_and_card_budgets_differ_only_in_the_ack_wait() {
467 assert_eq!(
468 Timing {
469 ack_spins: Timing::PAD.ack_spins,
470 ..Timing::CARD
471 },
472 Timing::PAD
473 );
474 const { assert!(Timing::CARD.ack_spins > Timing::PAD.ack_spins) };
475 }
476}