1use crate::{Block, Error, Result, FRAME_COUNT, FRAME_SIZE};
28use core::borrow::BorrowMut;
29use psx_io::controller_port::{ExchangeError, Port, Transport};
30use psx_io::periph::ControllerPort;
31
32const CARD_SELECT: u8 = 0x81;
34const CMD_READ: u8 = 0x52;
35const CMD_WRITE: u8 = 0x57;
36const ID1: u8 = 0x5A;
37const ACK1: u8 = 0x5C;
38const END_GOOD: u8 = 0x47;
39const FIRST_COMMAND_SETTLE_SPINS: u32 = 1_024;
42const POST_WRITE_SETTLE_SPINS: u32 = 400_000;
46
47pub type Slot = Port;
49
50#[derive(Copy, Clone, Debug, PartialEq, Eq)]
52pub enum TransportFault {
53 None,
55 TxTimeout,
57 RxTimeout,
59 AckTimeout,
61 AckReleaseTimeout,
63}
64
65#[derive(Copy, Clone, Debug, PartialEq, Eq)]
67pub struct TransportTrace {
68 pub exchanges: u16,
70 pub acknowledgements: u16,
72 pub fault: TransportFault,
74 pub fault_exchange: u16,
76 pub response_prefix: [u8; 10],
78}
79
80impl TransportTrace {
81 const fn new() -> Self {
82 Self {
83 exchanges: 0,
84 acknowledgements: 0,
85 fault: TransportFault::None,
86 fault_exchange: u16::MAX,
87 response_prefix: [0xff; 10],
88 }
89 }
90}
91
92#[derive(Copy, Clone, Debug)]
94pub struct Timing {
95 pub setup_spins: u32,
97 pub byte_spins: u32,
99 pub ack_spins: u32,
101}
102
103impl Default for Timing {
104 fn default() -> Self {
105 let card = psx_io::controller_port::Timing::CARD;
106 Timing {
107 setup_spins: card.setup_spins,
108 byte_spins: card.byte_spins,
109 ack_spins: card.ack_spins,
110 }
111 }
112}
113
114impl Timing {
115 fn link(self) -> psx_io::controller_port::Timing {
116 psx_io::controller_port::Timing {
117 setup_spins: self.setup_spins,
118 byte_spins: self.byte_spins,
119 ack_spins: self.ack_spins,
120 }
121 }
122}
123
124pub struct HardwareCard<P = ControllerPort> {
143 port: P,
144 slot: Slot,
145 timing: Timing,
146 trace: TransportTrace,
147}
148
149impl HardwareCard<ControllerPort> {
150 #[deprecated(note = "use `HardwareCard::on_port` with the `ControllerPort` token")]
152 pub fn new(slot: Slot) -> Self {
153 Self::on_port(steal_port(), slot)
154 }
155}
156
157fn steal_port() -> ControllerPort {
159 unsafe { ControllerPort::steal() }
162}
163
164impl<P: BorrowMut<ControllerPort>> HardwareCard<P> {
165 pub fn on_port(port: P, slot: Slot) -> Self {
168 Self::on_port_with_timing(port, slot, Timing::default())
169 }
170
171 pub fn on_port_with_timing(port: P, slot: Slot, timing: Timing) -> Self {
174 HardwareCard {
175 port,
176 slot,
177 timing,
178 trace: TransportTrace::new(),
179 }
180 }
181
182 pub fn release(self) -> P {
185 self.port
186 }
187
188 pub fn last_trace(&self) -> TransportTrace {
190 self.trace
191 }
192
193 pub fn controller_port(&mut self) -> &mut ControllerPort {
197 self.port.borrow_mut()
198 }
199}
200
201struct Link<'a, T> {
204 bus: &'a mut T,
205 slot: Slot,
206 timing: Timing,
207 trace: TransportTrace,
208}
209
210impl<T: Transport> Link<'_, T> {
211 fn select(&mut self) {
212 if !self.bus.begin(self.slot, self.timing.link()) {
213 self.record_fault(TransportFault::AckReleaseTimeout, 0);
216 }
217 }
218
219 fn record_fault(&mut self, fault: TransportFault, exchange: u16) {
220 if self.trace.fault == TransportFault::None {
221 self.trace.fault = fault;
222 self.trace.fault_exchange = exchange;
223 }
224 }
225
226 fn note_reply(&mut self, exchange: u16, reply: u8) {
227 if (exchange as usize) < self.trace.response_prefix.len() {
228 self.trace.response_prefix[exchange as usize] = reply;
229 }
230 self.trace.exchanges = exchange + 1;
231 }
232
233 fn xfer(&mut self, tx: u8, wait_ack: bool) -> u8 {
237 if self.trace.fault != TransportFault::None {
238 return 0xff;
239 }
240 let exchange = self.trace.exchanges;
241 match self.bus.exchange(tx, !wait_ack, self.timing.link()) {
242 Ok(reply) => {
243 self.note_reply(exchange, reply);
244 if wait_ack {
245 self.trace.acknowledgements += 1;
246 }
247 reply
248 }
249 Err(ExchangeError::TxTimeout) => {
250 self.record_fault(TransportFault::TxTimeout, exchange);
251 0xff
252 }
253 Err(ExchangeError::RxTimeout) => {
254 self.record_fault(TransportFault::RxTimeout, exchange);
255 0xff
256 }
257 Err(ExchangeError::AckTimeout { reply }) => {
258 self.note_reply(exchange, reply);
259 self.record_fault(TransportFault::AckTimeout, exchange);
260 reply
261 }
262 Err(ExchangeError::AckStuck { reply }) => {
263 self.note_reply(exchange, reply);
264 self.trace.acknowledgements += 1;
265 self.record_fault(TransportFault::AckReleaseTimeout, exchange);
266 reply
267 }
268 }
269 }
270
271 fn end(&mut self) {
272 let clean = self.trace.fault == TransportFault::None;
273 self.bus.finish(clean);
274 }
275
276 fn read_frame(&mut self, frame: u16, out: &mut [u8; FRAME_SIZE]) -> Result<()> {
277 let msb = (frame >> 8) as u8;
278 let lsb = frame as u8;
279
280 self.select();
281 self.xfer(CARD_SELECT, true); self.bus.delay(FIRST_COMMAND_SETTLE_SPINS);
283 let flags = self.xfer(CMD_READ, true);
284 let id1 = self.xfer(0x00, true); let _id2 = self.xfer(0x00, true); let _ = self.xfer(msb, true); let _ = self.xfer(lsb, true); let ack1 = self.xfer(0x00, true); let _ack2 = self.xfer(0x00, true); let emsb = self.xfer(0x00, true); let elsb = self.xfer(0x00, true); for b in out.iter_mut() {
293 *b = self.xfer(0x00, true);
294 }
295 let chk = self.xfer(0x00, true);
296 let end = self.xfer(0x00, false); self.end();
298
299 if id1 == 0xFF {
300 return Err(Error::NoCard);
301 }
302 if flags & 0x04 != 0
304 || id1 != ID1
305 || ack1 != ACK1
306 || emsb != msb
307 || elsb != lsb
308 || end != END_GOOD
309 {
310 return Err(Error::Protocol);
311 }
312 let mut want = msb ^ lsb;
313 for &b in out.iter() {
314 want ^= b;
315 }
316 if want != chk {
317 return Err(Error::BadChecksum);
318 }
319 Ok(())
320 }
321
322 fn write_frame(&mut self, frame: u16, data: &[u8; FRAME_SIZE]) -> Result<()> {
323 let msb = (frame >> 8) as u8;
324 let lsb = frame as u8;
325 let mut chk = msb ^ lsb;
326 for &b in data.iter() {
327 chk ^= b;
328 }
329
330 self.select();
331 self.xfer(CARD_SELECT, true); self.bus.delay(FIRST_COMMAND_SETTLE_SPINS);
333 self.xfer(CMD_WRITE, true);
334 let id1 = self.xfer(0x00, true); let _id2 = self.xfer(0x00, true); let _ = self.xfer(msb, true); let _ = self.xfer(lsb, true); for &b in data.iter() {
339 self.xfer(b, true);
340 }
341 self.xfer(chk, true); let ack1 = self.xfer(0x00, true); let _ack2 = self.xfer(0x00, true); let end = self.xfer(0x00, false); self.end();
346
347 self.bus.delay(POST_WRITE_SETTLE_SPINS);
351
352 if id1 == 0xFF {
353 return Err(Error::NoCard);
354 }
355 if id1 != ID1 || ack1 != ACK1 {
356 return Err(Error::Protocol);
357 }
358 if end != END_GOOD {
359 return Err(Error::Protocol);
361 }
362 Ok(())
363 }
364}
365
366fn transact<T: Transport, R>(
368 bus: &mut T,
369 slot: Slot,
370 timing: Timing,
371 trace: &mut TransportTrace,
372 run: impl FnOnce(&mut Link<'_, T>) -> R,
373) -> R {
374 let mut link = Link {
375 bus,
376 slot,
377 timing,
378 trace: TransportTrace::new(),
379 };
380 let result = run(&mut link);
381 *trace = link.trace;
382 result
383}
384
385fn check_range(frame: u16) -> Result<()> {
386 if (frame as usize) < FRAME_COUNT {
387 Ok(())
388 } else {
389 Err(Error::OutOfRange)
390 }
391}
392
393impl<P: BorrowMut<ControllerPort>> Block for HardwareCard<P> {
394 fn read_frame(&mut self, frame: u16, out: &mut [u8; FRAME_SIZE]) -> Result<()> {
395 check_range(frame)?;
396 let (slot, timing) = (self.slot, self.timing);
397 transact(
398 self.port.borrow_mut(),
399 slot,
400 timing,
401 &mut self.trace,
402 |link| link.read_frame(frame, out),
403 )
404 }
405
406 fn write_frame(&mut self, frame: u16, data: &[u8; FRAME_SIZE]) -> Result<()> {
407 check_range(frame)?;
408 let (slot, timing) = (self.slot, self.timing);
409 transact(
410 self.port.borrow_mut(),
411 slot,
412 timing,
413 &mut self.trace,
414 |link| link.write_frame(frame, data),
415 )
416 }
417}
418
419#[cfg(test)]
420mod tests;