Fixed fsmc timing some more so it's stable
[SCSI2SD-V6.git] / src / firmware / scsiPhy.c
1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
2 //
3 // This file is part of SCSI2SD.
4 //
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "stm32f2xx.h"
19 #include "stm32f2xx_hal.h"
20 #include "stm32f2xx_hal_dma.h"
21
22 #include "scsi.h"
23 #include "scsiPhy.h"
24 #include "trace.h"
25 #include "time.h"
26 #include "fpga.h"
27 #include "led.h"
28
29 #include <string.h>
30
31 // 5MB/s
32 // Assumes a 96MHz fpga clock.
33 // 2:0 Deskew count, 55ns
34 // 6:4 Hold count, 53ns
35 // 3:0 Assertion count, 80ns
36 #define SCSI_DEFAULT_DESKEW 0x6
37 #define SCSI_DEFAULT_TIMING ((0x5 << 4) | 0x8)
38
39 // 10MB/s
40 // 2:0 Deskew count, 25ns
41 // 6:4 Hold count, 33ns
42 // 3:0 Assertion count, 30ns
43 #define SCSI_FAST10_DESKEW 3
44 #define SCSI_FAST10_TIMING ((0x3 << 4) | 0x3)
45
46 // 20MB/s
47 // 2:0 Deskew count, 12ns
48 // 6:4 Hold count, 17ns
49 // 3:0 Assertion count, 15ns
50 #define SCSI_FAST20_DESKEW 2
51 #define SCSI_FAST20_TIMING ((0x2 << 4) | 0x2)
52
53 // Private DMA variables.
54 static int dmaInProgress = 0;
55
56 static DMA_HandleTypeDef memToFSMC;
57 static DMA_HandleTypeDef fsmcToMem;
58
59
60 volatile uint8_t scsiRxDMAComplete;
61 volatile uint8_t scsiTxDMAComplete;
62
63 #if 0
64 CY_ISR_PROTO(scsiRxCompleteISR);
65 CY_ISR(scsiRxCompleteISR)
66 {
67 traceIrq(trace_scsiRxCompleteISR);
68 scsiRxDMAComplete = 1;
69 }
70
71 CY_ISR_PROTO(scsiTxCompleteISR);
72 CY_ISR(scsiTxCompleteISR)
73 {
74 traceIrq(trace_scsiTxCompleteISR);
75 scsiTxDMAComplete = 1;
76 }
77 #endif
78
79 uint8_t scsiPhyFifoSel = 0; // global
80
81 // scsi IRQ handler is initialised by the STM32 HAL. Connected to
82 // PE4
83 // Note: naming is important to ensure this function is listed in the
84 // vector table.
85 void EXTI4_IRQHandler()
86 {
87 traceIrq(trace_scsiResetISR);
88
89 // Make sure that interrupt flag is set
90 if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET) {
91
92 // Clear interrupt flag
93 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
94
95 scsiDev.resetFlag = scsiDev.resetFlag || scsiStatusRST();
96 // TODO grab SEL status as well
97
98 }
99 }
100
101 static void assertFail()
102 {
103 while (1)
104 {
105 s2s_ledOn();
106 s2s_delay_ms(100);
107 s2s_ledOff();
108 s2s_delay_ms(100);
109 }
110 }
111
112 void
113 scsiSetDataCount(uint32_t count)
114 {
115 *SCSI_DATA_CNT_HI = count >> 8;
116 *SCSI_DATA_CNT_LO = count & 0xff;
117 *SCSI_DATA_CNT_SET = 1;
118 }
119
120 uint8_t
121 scsiReadByte(void)
122 {
123 #if FIFODEBUG
124 if (!scsiPhyFifoAltEmpty()) {
125 // Force a lock-up.
126 assertFail();
127 }
128 #endif
129 scsiSetDataCount(1);
130
131 trace(trace_spinPhyRxFifo);
132 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
133 scsiPhyFifoFlip();
134 uint8_t val = scsiPhyRx();
135 // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
136
137 #if FIFODEBUG
138 if (!scsiPhyFifoEmpty()) {
139 int j = 0;
140 uint8_t k __attribute((unused));
141 while (!scsiPhyFifoEmpty()) { k = scsiPhyRx(); ++j; }
142
143 // Force a lock-up.
144 assertFail();
145 }
146 #endif
147 return val;
148 }
149
150
151 static void
152 scsiReadPIO(uint8_t* data, uint32_t count)
153 {
154 uint16_t* fifoData = (uint16_t*)data;
155 for (int i = 0; i < (count + 1) / 2; ++i)
156 {
157 fifoData[i] = scsiPhyRx(); // TODO ASSUMES LITTLE ENDIAN
158 }
159 // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
160 }
161
162 void
163 scsiReadDMA(uint8_t* data, uint32_t count)
164 {
165 // Prepare DMA transfer
166 dmaInProgress = 1;
167 trace(trace_doRxSingleDMA);
168
169 scsiTxDMAComplete = 1; // TODO not used much
170 scsiRxDMAComplete = 0; // TODO not used much
171
172 HAL_DMA_Start(
173 &fsmcToMem,
174 (uint32_t) SCSI_FIFO_DATA,
175 (uint32_t) data,
176 (count + 1) / 2);
177 }
178
179 int
180 scsiReadDMAPoll()
181 {
182 int complete = __HAL_DMA_GET_COUNTER(&fsmcToMem) == 0;
183 complete = complete && (HAL_DMA_PollForTransfer(&fsmcToMem, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
184 if (complete)
185 {
186 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
187 scsiRxDMAComplete = 1;
188
189 dmaInProgress = 0;
190 #if 0
191 // TODO MM scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
192 #endif
193 return 1;
194
195 }
196 else
197 {
198 return 0;
199 }
200 }
201
202 void
203 scsiRead(uint8_t* data, uint32_t count)
204 {
205 int i = 0;
206
207
208 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
209 ? SCSI_FIFO_DEPTH : (count - i);
210 #ifdef SCSI_FSMC_DMA
211 if (chunk >= 16)
212 {
213 // DMA is doing 32bit transfers.
214 chunk = chunk & 0xFFFFFFF8;
215 }
216 #endif
217 scsiSetDataCount(chunk);
218
219 while (i < count && likely(!scsiDev.resetFlag))
220 {
221 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
222 scsiPhyFifoFlip();
223
224 uint32_t nextChunk = ((count - i - chunk) > SCSI_FIFO_DEPTH)
225 ? SCSI_FIFO_DEPTH : (count - i - chunk);
226 #ifdef SCSI_FSMC_DMA
227 if (nextChunk >= 16)
228 {
229 nextChunk = nextChunk & 0xFFFFFFF8;
230 }
231 #endif
232 if (nextChunk > 0)
233 {
234 scsiSetDataCount(nextChunk);
235 }
236
237 #ifdef SCSI_FSMC_DMA
238 if (chunk < 16)
239 #endif
240 {
241 scsiReadPIO(data + i, chunk);
242 }
243 #ifdef SCSI_FSMC_DMA
244 else
245 {
246 scsiReadDMA(data + i, chunk);
247
248 trace(trace_spinReadDMAPoll);
249
250 while (!scsiReadDMAPoll() && likely(!scsiDev.resetFlag))
251 {
252 };
253 }
254 #endif
255
256
257 i += chunk;
258 chunk = nextChunk;
259 }
260 #if FIFODEBUG
261 if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {
262 int j = 0;
263 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }
264 scsiPhyFifoFlip();
265 int k = 0;
266 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }
267 // Force a lock-up.
268 assertFail();
269 }
270 #endif
271 }
272
273 void
274 scsiWriteByte(uint8_t value)
275 {
276 #if FIFODEBUG
277 if (!scsiPhyFifoEmpty()) {
278 // Force a lock-up.
279 assertFail();
280 }
281 #endif
282 trace(trace_spinPhyTxFifo);
283 scsiPhyTx(value);
284 scsiPhyFifoFlip();
285
286 scsiSetDataCount(1);
287
288 trace(trace_spinTxComplete);
289 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
290
291 #if FIFODEBUG
292 if (!scsiPhyFifoAltEmpty()) {
293 // Force a lock-up.
294 assertFail();
295 }
296 #endif
297 }
298
299 static void
300 scsiWritePIO(const uint8_t* data, uint32_t count)
301 {
302 uint16_t* fifoData = (uint16_t*)data;
303 for (int i = 0; i < (count + 1) / 2; ++i)
304 {
305 scsiPhyTx(fifoData[i]);
306 }
307 }
308
309 void
310 scsiWriteDMA(const uint8_t* data, uint32_t count)
311 {
312 // Prepare DMA transfer
313 dmaInProgress = 1;
314 trace(trace_doTxSingleDMA);
315
316 scsiTxDMAComplete = 0;
317 scsiRxDMAComplete = 1;
318
319 HAL_DMA_Start(
320 &memToFSMC,
321 (uint32_t) data,
322 (uint32_t) SCSI_FIFO_DATA,
323 count / 4);
324 }
325
326 int
327 scsiWriteDMAPoll()
328 {
329 int complete = __HAL_DMA_GET_COUNTER(&memToFSMC) == 0;
330 complete = complete && (HAL_DMA_PollForTransfer(&memToFSMC, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
331 if (complete)
332 {
333 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
334 scsiRxDMAComplete = 1;
335
336 dmaInProgress = 0;
337 return 1;
338 }
339 else
340 {
341 return 0;
342 }
343 }
344
345 void
346 scsiWrite(const uint8_t* data, uint32_t count)
347 {
348 int i = 0;
349 while (i < count && likely(!scsiDev.resetFlag))
350 {
351 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
352 ? SCSI_FIFO_DEPTH : (count - i);
353
354 #if FIFODEBUG
355 if (!scsiPhyFifoEmpty()) {
356 // Force a lock-up.
357 assertFail();
358 }
359 #endif
360
361 #ifdef SCSI_FSMC_DMA
362 if (chunk < 16)
363 #endif
364 {
365 scsiWritePIO(data + i, chunk);
366 }
367 #ifdef SCSI_FSMC_DMA
368 else
369 {
370 // DMA is doing 32bit transfers.
371 chunk = chunk & 0xFFFFFFF8;
372 scsiWriteDMA(data + i, chunk);
373
374 trace(trace_spinReadDMAPoll);
375
376 while (!scsiWriteDMAPoll() && likely(!scsiDev.resetFlag))
377 {
378 }
379 }
380 #endif
381
382 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
383 {
384 }
385
386 #if FIFODEBUG
387 if (!scsiPhyFifoAltEmpty()) {
388 // Force a lock-up.
389 assertFail();
390 }
391 #endif
392
393 scsiPhyFifoFlip();
394 scsiSetDataCount(chunk);
395 i += chunk;
396 }
397 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
398 {
399 }
400
401 #if FIFODEBUG
402 if (!scsiPhyFifoAltEmpty()) {
403 // Force a lock-up.
404 assertFail();
405 }
406 #endif
407 }
408
409 static inline void busSettleDelay(void)
410 {
411 // Data Release time (switching IO) = 400ns
412 // + Bus Settle time (switching phase) = 400ns.
413 s2s_delay_us(1); // Close enough.
414 }
415
416 void scsiEnterBusFree()
417 {
418 *SCSI_CTRL_BSY = 0x00;
419 // We now have a Bus Clear Delay of 800ns to release remaining signals.
420 *SCSI_CTRL_PHASE = 0;
421 }
422
423 void scsiEnterPhase(int phase)
424 {
425 // ANSI INCITS 362-2002 SPI-3 10.7.1:
426 // Phase changes are not allowed while REQ or ACK is asserted.
427 while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}
428
429 int newPhase = phase > 0 ? phase : 0;
430 int oldPhase = *SCSI_CTRL_PHASE;
431
432 if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {
433 // Force a lock-up.
434 assertFail();
435 }
436 if (newPhase != oldPhase)
437 {
438 if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&
439 scsiDev.target->syncOffset)
440 {
441 if (scsiDev.target->syncPeriod == 12)
442 {
443 // SCSI2 FAST-20 Timing. 20MB/s.
444 *SCSI_CTRL_TIMING = SCSI_FAST20_DESKEW;
445 *SCSI_CTRL_TIMING2 = SCSI_FAST20_TIMING;
446 }
447 else if (scsiDev.target->syncPeriod == 25)
448 {
449 // SCSI2 FAST Timing. 10MB/s.
450 *SCSI_CTRL_TIMING = SCSI_FAST10_DESKEW;
451 *SCSI_CTRL_TIMING2 = SCSI_FAST10_TIMING;
452 } else {
453 // 5MB/s Timing
454 *SCSI_CTRL_TIMING = SCSI_DEFAULT_DESKEW;
455 *SCSI_CTRL_TIMING2 = SCSI_DEFAULT_TIMING;
456 }
457 *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
458 } else {
459 *SCSI_CTRL_SYNC_OFFSET = 0;
460 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
461 }
462
463 *SCSI_CTRL_PHASE = newPhase;
464 busSettleDelay();
465
466 if (scsiDev.compatMode < COMPAT_SCSI2)
467 {
468 s2s_delay_us(100);
469 }
470
471 }
472 }
473
474 void scsiPhyReset()
475 {
476 trace(trace_scsiPhyReset);
477 if (dmaInProgress)
478 {
479 trace(trace_spinDMAReset);
480 HAL_DMA_Abort(&memToFSMC);
481 HAL_DMA_Abort(&fsmcToMem);
482
483 dmaInProgress = 0;
484 }
485
486 *SCSI_CTRL_PHASE = 0x00;
487 *SCSI_CTRL_BSY = 0x00;
488 s2s_fpgaReset(); // Clears fifos etc.
489
490 scsiPhyFifoSel = 0;
491 *SCSI_FIFO_SEL = 0;
492 *SCSI_CTRL_DBX = 0;
493
494 *SCSI_CTRL_SYNC_OFFSET = 0;
495 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
496
497 // DMA Benchmark code
498 // Currently 11MB/s.
499 #ifdef DMA_BENCHMARK
500 while(1)
501 {
502 s2s_ledOn();
503 // 100MB
504 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)
505 {
506 HAL_DMA_Start(
507 &memToFSMC,
508 (uint32_t) &scsiDev.data[0],
509 (uint32_t) SCSI_FIFO_DATA,
510 SCSI_FIFO_DEPTH / 4);
511
512 HAL_DMA_PollForTransfer(
513 &memToFSMC,
514 HAL_DMA_FULL_TRANSFER,
515 0xffffffff);
516
517 s2s_fpgaReset();
518 }
519 s2s_ledOff();
520
521 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);
522 }
523 #endif
524
525 // FPGA comms test code
526 #ifdef FPGA_TEST
527 while(1)
528 {
529 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
530 {
531 scsiDev.data[j] = j;
532 }
533
534 if (!scsiPhyFifoEmpty())
535 {
536 assertFail();
537 }
538
539 *SCSI_CTRL_PHASE = DATA_IN;
540 HAL_DMA_Start(
541 &memToFSMC,
542 (uint32_t) &scsiDev.data[0],
543 (uint32_t) SCSI_FIFO_DATA,
544 SCSI_FIFO_DEPTH / 4);
545
546 HAL_DMA_PollForTransfer(
547 &memToFSMC,
548 HAL_DMA_FULL_TRANSFER,
549 0xffffffff);
550
551 if (!scsiPhyFifoFull())
552 {
553 assertFail();
554 }
555
556 memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH);
557
558 *SCSI_CTRL_PHASE = DATA_OUT;
559 HAL_DMA_Start(
560 &fsmcToMem,
561 (uint32_t) SCSI_FIFO_DATA,
562 (uint32_t) &scsiDev.data[0],
563 SCSI_FIFO_DEPTH / 2);
564
565 HAL_DMA_PollForTransfer(
566 &fsmcToMem,
567 HAL_DMA_FULL_TRANSFER,
568 0xffffffff);
569
570 if (!scsiPhyFifoEmpty())
571 {
572 assertFail();
573 }
574
575
576 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
577 {
578 if (scsiDev.data[j] != (uint8_t) j)
579 {
580 assertFail();
581 }
582 }
583
584 s2s_fpgaReset();
585
586 }
587 #endif
588
589 }
590
591 static void scsiPhyInitDMA()
592 {
593 // One-time init only.
594 static uint8_t init = 0;
595 if (init == 0)
596 {
597 init = 1;
598
599 // Memory to memory transfers can only be done using DMA2
600 __DMA2_CLK_ENABLE();
601
602 // Transmit SCSI data. The source data is treated as the
603 // peripheral (even though this is memory-to-memory)
604 memToFSMC.Instance = DMA2_Stream0;
605 memToFSMC.Init.Channel = DMA_CHANNEL_0;
606 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;
607 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;
608 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;
609 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
610 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
611 memToFSMC.Init.Mode = DMA_NORMAL;
612 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;
613 // FIFO mode is needed to allow conversion from 32bit words to the
614 // 16bit FSMC interface.
615 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
616
617 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's
618 // better to let the DMA fifo fill up then do burst transfers, but
619 // bursting out the FSMC interface will be very slow and may starve
620 // other (faster) transfers. We don't want to risk the SDIO transfers
621 // from overrun/underrun conditions.
622 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
623 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;
624 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;
625 HAL_DMA_Init(&memToFSMC);
626
627 // Receive SCSI data. The source data (fsmc) is treated as the
628 // peripheral (even though this is memory-to-memory)
629 fsmcToMem.Instance = DMA2_Stream1;
630 fsmcToMem.Init.Channel = DMA_CHANNEL_0;
631 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;
632 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;
633 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;
634 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
635 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
636 fsmcToMem.Init.Mode = DMA_NORMAL;
637 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;
638 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
639 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
640 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;
641 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;
642 HAL_DMA_Init(&fsmcToMem);
643
644 // TODO configure IRQs
645 }
646 }
647
648
649 void scsiPhyInit()
650 {
651 scsiPhyInitDMA();
652
653 *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig
654 *SCSI_CTRL_PHASE = 0x00;
655 *SCSI_CTRL_BSY = 0x00;
656 scsiPhyFifoSel = 0;
657 *SCSI_FIFO_SEL = 0;
658 *SCSI_CTRL_DBX = 0;
659
660 *SCSI_CTRL_SYNC_OFFSET = 0;
661 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
662
663 }
664
665 void scsiPhyConfig()
666 {
667 if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)
668 {
669 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);
670 }
671 else
672 {
673 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);
674 }
675
676
677 uint8_t idMask = 0;
678 for (int i = 0; i < 8; ++i)
679 {
680 const S2S_TargetCfg* cfg = s2s_getConfigById(i);
681 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
682 {
683 idMask |= (1 << i);
684 }
685 }
686 *SCSI_CTRL_IDMASK = idMask;
687 }
688
689
690 // 1 = DBx error
691 // 2 = Parity error
692 // 4 = MSG error
693 // 8 = CD error
694 // 16 = IO error
695 // 32 = other error
696 int scsiSelfTest()
697 {
698 if (scsiDev.phase != BUS_FREE)
699 {
700 return 32;
701 }
702
703 // Acquire the SCSI bus.
704 for (int i = 0; i < 100; ++i)
705 {
706 if (scsiStatusBSY())
707 {
708 s2s_delay_ms(1);
709 }
710 }
711 if (scsiStatusBSY())
712 {
713 // Error, couldn't acquire scsi bus
714 return 32;
715 }
716 *SCSI_CTRL_BSY = 1;
717 if (! scsiStatusBSY())
718 {
719 // Error, BSY doesn't work.
720 return 32;
721 }
722
723 // Should be safe to use the bus now.
724
725 int result = 0;
726
727 // TEST DBx
728 // TODO test DBp
729 int i;
730 for (i = 0; i < 256; ++i)
731 {
732 *SCSI_CTRL_DBX = i;
733 busSettleDelay();
734 if (*SCSI_STS_DBX != (i & 0xff))
735 {
736 result |= 1;
737 }
738 /*if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))
739 {
740 result |= 2;
741 }*/
742 }
743 *SCSI_CTRL_DBX = 0;
744
745 // TEST MSG, CD, IO
746 /* TODO
747 for (i = 0; i < 8; ++i)
748 {
749 SCSI_CTL_PHASE_Write(i);
750 scsiDeskewDelay();
751
752 if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))
753 {
754 result |= 4;
755 }
756 if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))
757 {
758 result |= 8;
759 }
760 if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))
761 {
762 result |= 16;
763 }
764 }
765 SCSI_CTL_PHASE_Write(0);
766
767 uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };
768 uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };
769
770 for (i = 0; i < 4; ++i)
771 {
772 SCSI_SetPin(signalsOut[i]);
773 scsiDeskewDelay();
774
775 int j;
776 for (j = 0; j < 4; ++j)
777 {
778 if (i == j)
779 {
780 if (! SCSI_ReadFilt(signalsIn[j]))
781 {
782 result |= 32;
783 }
784 }
785 else
786 {
787 if (SCSI_ReadFilt(signalsIn[j]))
788 {
789 result |= 32;
790 }
791 }
792 }
793 SCSI_ClearPin(signalsOut[i]);
794 }
795 */
796
797 *SCSI_CTRL_BSY = 0;
798 return result;
799 }
800