ba71f6594e2bfd7a60d974b36c9890fb8d5997d5
[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 static void
113 startScsiRx(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 startScsiRx(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 for (int i = 0; i < count; ++i)
155 {
156 data[i] = scsiPhyRx();
157 }
158 // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
159 }
160
161 void
162 scsiReadDMA(uint8_t* data, uint32_t count)
163 {
164 // Prepare DMA transfer
165 dmaInProgress = 1;
166 trace(trace_doRxSingleDMA);
167
168 scsiTxDMAComplete = 1; // TODO not used much
169 scsiRxDMAComplete = 0; // TODO not used much
170
171 HAL_DMA_Start(&fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) data, count);
172 }
173
174 int
175 scsiReadDMAPoll()
176 {
177 int complete = __HAL_DMA_GET_COUNTER(&fsmcToMem) == 0;
178 complete = complete && (HAL_DMA_PollForTransfer(&fsmcToMem, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
179 if (complete)
180 {
181 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
182 scsiRxDMAComplete = 1;
183
184 dmaInProgress = 0;
185 #if 0
186 // TODO MM scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
187 #endif
188 return 1;
189
190 }
191 else
192 {
193 return 0;
194 }
195 }
196
197 void
198 scsiRead(uint8_t* data, uint32_t count)
199 {
200 int i = 0;
201
202
203 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
204 ? SCSI_FIFO_DEPTH : (count - i);
205 #ifdef SCSI_FSMC_DMA
206 if (chunk >= 16)
207 {
208 // DMA is doing 32bit transfers.
209 chunk = chunk & 0xFFFFFFF8;
210 }
211 #endif
212 startScsiRx(chunk);
213
214 while (i < count && likely(!scsiDev.resetFlag))
215 {
216 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
217 scsiPhyFifoFlip();
218
219 uint32_t nextChunk = ((count - i - chunk) > SCSI_FIFO_DEPTH)
220 ? SCSI_FIFO_DEPTH : (count - i - chunk);
221 #ifdef SCSI_FSMC_DMA
222 if (nextChunk >= 16)
223 {
224 nextChunk = nextChunk & 0xFFFFFFF8;
225 }
226 #endif
227 if (nextChunk > 0)
228 {
229 startScsiRx(nextChunk);
230 }
231
232 #ifdef SCSI_FSMC_DMA
233 if (chunk < 16)
234 #endif
235 {
236 scsiReadPIO(data + i, chunk);
237 }
238 #ifdef SCSI_FSMC_DMA
239 else
240 {
241 scsiReadDMA(data + i, chunk);
242
243 trace(trace_spinReadDMAPoll);
244
245 while (!scsiReadDMAPoll() && likely(!scsiDev.resetFlag))
246 {
247 };
248 }
249 #endif
250
251
252 i += chunk;
253 chunk = nextChunk;
254 }
255 #if FIFODEBUG
256 if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {
257 int j = 0;
258 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }
259 scsiPhyFifoFlip();
260 int k = 0;
261 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }
262 // Force a lock-up.
263 assertFail();
264 }
265 #endif
266 }
267
268 void
269 scsiWriteByte(uint8_t value)
270 {
271 #if FIFODEBUG
272 if (!scsiPhyFifoEmpty()) {
273 // Force a lock-up.
274 assertFail();
275 }
276 #endif
277 trace(trace_spinPhyTxFifo);
278 scsiPhyTx(value);
279 scsiPhyFifoFlip();
280
281 trace(trace_spinTxComplete);
282 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
283
284 #if FIFODEBUG
285 if (!scsiPhyFifoAltEmpty()) {
286 // Force a lock-up.
287 assertFail();
288 }
289 #endif
290 }
291
292 static void
293 scsiWritePIO(const uint8_t* data, uint32_t count)
294 {
295 for (int i = 0; i < count; ++i)
296 {
297 scsiPhyTx(data[i]);
298 }
299 }
300
301 void
302 scsiWriteDMA(const uint8_t* data, uint32_t count)
303 {
304 // Prepare DMA transfer
305 dmaInProgress = 1;
306 trace(trace_doTxSingleDMA);
307
308 scsiTxDMAComplete = 0;
309 scsiRxDMAComplete = 1;
310
311 HAL_DMA_Start(
312 &memToFSMC,
313 (uint32_t) data,
314 (uint32_t) SCSI_FIFO_DATA,
315 count / 4);
316 }
317
318 int
319 scsiWriteDMAPoll()
320 {
321 int complete = __HAL_DMA_GET_COUNTER(&memToFSMC) == 0;
322 complete = complete && (HAL_DMA_PollForTransfer(&memToFSMC, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
323 if (complete)
324 {
325 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
326 scsiRxDMAComplete = 1;
327
328 dmaInProgress = 0;
329 return 1;
330 }
331 else
332 {
333 return 0;
334 }
335 }
336
337 void
338 scsiWrite(const uint8_t* data, uint32_t count)
339 {
340 int i = 0;
341 while (i < count && likely(!scsiDev.resetFlag))
342 {
343 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
344 ? SCSI_FIFO_DEPTH : (count - i);
345
346 #if FIFODEBUG
347 if (!scsiPhyFifoEmpty()) {
348 // Force a lock-up.
349 assertFail();
350 }
351 #endif
352
353 #ifdef SCSI_FSMC_DMA
354 if (chunk < 16)
355 #endif
356 {
357 scsiWritePIO(data + i, chunk);
358 }
359 #ifdef SCSI_FSMC_DMA
360 else
361 {
362 // DMA is doing 32bit transfers.
363 chunk = chunk & 0xFFFFFFF8;
364 scsiWriteDMA(data + i, chunk);
365
366 trace(trace_spinReadDMAPoll);
367
368 while (!scsiWriteDMAPoll() && likely(!scsiDev.resetFlag))
369 {
370 }
371 }
372 #endif
373
374 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
375 {
376 }
377
378 #if FIFODEBUG
379 if (!scsiPhyFifoAltEmpty()) {
380 // Force a lock-up.
381 assertFail();
382 }
383 #endif
384
385 scsiPhyFifoFlip();
386 i += chunk;
387 }
388 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
389 {
390 }
391
392 #if FIFODEBUG
393 if (!scsiPhyFifoAltEmpty()) {
394 // Force a lock-up.
395 assertFail();
396 }
397 #endif
398 }
399
400 static inline void busSettleDelay(void)
401 {
402 // Data Release time (switching IO) = 400ns
403 // + Bus Settle time (switching phase) = 400ns.
404 s2s_delay_us(1); // Close enough.
405 }
406
407 void scsiEnterBusFree()
408 {
409 *SCSI_CTRL_BSY = 0x00;
410 // We now have a Bus Clear Delay of 800ns to release remaining signals.
411 *SCSI_CTRL_PHASE = 0;
412 }
413
414 void scsiEnterPhase(int phase)
415 {
416 // ANSI INCITS 362-2002 SPI-3 10.7.1:
417 // Phase changes are not allowed while REQ or ACK is asserted.
418 while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}
419
420 int newPhase = phase > 0 ? phase : 0;
421 int oldPhase = *SCSI_CTRL_PHASE;
422
423 if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {
424 // Force a lock-up.
425 assertFail();
426 }
427 if (newPhase != oldPhase)
428 {
429 if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&
430 scsiDev.target->syncOffset)
431 {
432 if (scsiDev.target->syncPeriod == 12)
433 {
434 // SCSI2 FAST-20 Timing. 20MB/s.
435 *SCSI_CTRL_TIMING = SCSI_FAST20_DESKEW;
436 *SCSI_CTRL_TIMING2 = SCSI_FAST20_TIMING;
437 }
438 else if (scsiDev.target->syncPeriod == 25)
439 {
440 // SCSI2 FAST Timing. 10MB/s.
441 *SCSI_CTRL_TIMING = SCSI_FAST10_DESKEW;
442 *SCSI_CTRL_TIMING2 = SCSI_FAST10_TIMING;
443 } else {
444 // 5MB/s Timing
445 *SCSI_CTRL_TIMING = SCSI_DEFAULT_DESKEW;
446 *SCSI_CTRL_TIMING2 = SCSI_DEFAULT_TIMING;
447 }
448 *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
449 } else {
450 *SCSI_CTRL_SYNC_OFFSET = 0;
451 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
452 }
453
454 *SCSI_CTRL_PHASE = newPhase;
455 busSettleDelay();
456
457 if (scsiDev.compatMode < COMPAT_SCSI2)
458 {
459 s2s_delay_us(100);
460 }
461
462 }
463 }
464
465 void scsiPhyReset()
466 {
467 trace(trace_scsiPhyReset);
468 if (dmaInProgress)
469 {
470 trace(trace_spinDMAReset);
471 HAL_DMA_Abort(&memToFSMC);
472 HAL_DMA_Abort(&fsmcToMem);
473
474 dmaInProgress = 0;
475 }
476
477 *SCSI_CTRL_PHASE = 0x00;
478 *SCSI_CTRL_BSY = 0x00;
479 s2s_fpgaReset(); // Clears fifos etc.
480
481 scsiPhyFifoSel = 0;
482 *SCSI_FIFO_SEL = 0;
483 *SCSI_CTRL_DBX = 0;
484
485 *SCSI_CTRL_SYNC_OFFSET = 0;
486 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
487
488 // DMA Benchmark code
489 // Currently 6.6MB/s. Assume 13MB/s is achievable with 16 bits
490 #ifdef DMA_BENCHMARK
491 while(1)
492 {
493 s2s_ledOn();
494 // 100MB
495 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)
496 {
497 HAL_DMA_Start(
498 &memToFSMC,
499 (uint32_t) &scsiDev.data[0],
500 (uint32_t) SCSI_FIFO_DATA,
501 SCSI_FIFO_DEPTH / 4);
502
503 HAL_DMA_PollForTransfer(
504 &memToFSMC,
505 HAL_DMA_FULL_TRANSFER,
506 0xffffffff);
507
508 s2s_fpgaReset();
509 }
510 s2s_ledOff();
511
512 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);
513 }
514 #endif
515
516 // FPGA comms test code
517 #ifdef FPGA_TEST
518 while(1)
519 {
520 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
521 {
522 scsiDev.data[j] = j;
523 }
524
525 if (!scsiPhyFifoEmpty())
526 {
527 assertFail();
528 }
529
530 *SCSI_CTRL_PHASE = DATA_IN;
531 HAL_DMA_Start(
532 &memToFSMC,
533 (uint32_t) &scsiDev.data[0],
534 (uint32_t) SCSI_FIFO_DATA,
535 SCSI_FIFO_DEPTH / 4);
536
537 HAL_DMA_PollForTransfer(
538 &memToFSMC,
539 HAL_DMA_FULL_TRANSFER,
540 0xffffffff);
541
542 if (!scsiPhyFifoFull())
543 {
544 assertFail();
545 }
546
547 memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH);
548
549 *SCSI_CTRL_PHASE = DATA_OUT;
550 HAL_DMA_Start(
551 &fsmcToMem,
552 (uint32_t) SCSI_FIFO_DATA,
553 (uint32_t) &scsiDev.data[0],
554 SCSI_FIFO_DEPTH);
555
556 HAL_DMA_PollForTransfer(
557 &fsmcToMem,
558 HAL_DMA_FULL_TRANSFER,
559 0xffffffff);
560
561 if (!scsiPhyFifoEmpty())
562 {
563 assertFail();
564 }
565
566
567 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
568 {
569 if (scsiDev.data[j] != (uint8_t) j)
570 {
571 assertFail();
572 }
573 }
574
575 s2s_fpgaReset();
576
577 }
578 #endif
579
580 }
581
582 static void scsiPhyInitDMA()
583 {
584 // One-time init only.
585 static uint8_t init = 0;
586 if (init == 0)
587 {
588 init = 1;
589
590 // Memory to memory transfers can only be done using DMA2
591 __DMA2_CLK_ENABLE();
592
593 // Transmit SCSI data. The source data is treated as the
594 // peripheral (even though this is memory-to-memory)
595 memToFSMC.Instance = DMA2_Stream0;
596 memToFSMC.Init.Channel = DMA_CHANNEL_0;
597 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;
598 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;
599 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;
600 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
601 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
602 memToFSMC.Init.Mode = DMA_NORMAL;
603 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;
604 // FIFO mode is needed to allow conversion from 32bit words to the
605 // 8bit FSMC interface.
606 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
607
608 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's
609 // better to let the DMA fifo fill up then do burst transfers, but
610 // bursting out the FSMC interface will be very slow and may starve
611 // other (faster) transfers. We don't want to risk the SDIO transfers
612 // from overrun/underrun conditions.
613 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
614 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;
615 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;
616 HAL_DMA_Init(&memToFSMC);
617
618 // Receive SCSI data. The source data (fsmc) is treated as the
619 // peripheral (even though this is memory-to-memory)
620 fsmcToMem.Instance = DMA2_Stream1;
621 fsmcToMem.Init.Channel = DMA_CHANNEL_0;
622 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;
623 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;
624 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;
625 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
626 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
627 fsmcToMem.Init.Mode = DMA_NORMAL;
628 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;
629 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
630 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
631 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;
632 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;
633 HAL_DMA_Init(&fsmcToMem);
634
635 // TODO configure IRQs
636 }
637 }
638
639
640 void scsiPhyInit()
641 {
642 scsiPhyInitDMA();
643
644 *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig
645 *SCSI_CTRL_PHASE = 0x00;
646 *SCSI_CTRL_BSY = 0x00;
647 scsiPhyFifoSel = 0;
648 *SCSI_FIFO_SEL = 0;
649 *SCSI_CTRL_DBX = 0;
650
651 *SCSI_CTRL_SYNC_OFFSET = 0;
652 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
653
654 }
655
656 void scsiPhyConfig()
657 {
658 if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)
659 {
660 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);
661 }
662 else
663 {
664 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);
665 }
666
667
668 uint8_t idMask = 0;
669 for (int i = 0; i < 8; ++i)
670 {
671 const S2S_TargetCfg* cfg = s2s_getConfigById(i);
672 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
673 {
674 idMask |= (1 << i);
675 }
676 }
677 *SCSI_CTRL_IDMASK = idMask;
678 }
679
680
681 // 1 = DBx error
682 // 2 = Parity error
683 // 4 = MSG error
684 // 8 = CD error
685 // 16 = IO error
686 // 32 = other error
687 int scsiSelfTest()
688 {
689 if (scsiDev.phase != BUS_FREE)
690 {
691 return 32;
692 }
693
694 // Acquire the SCSI bus.
695 for (int i = 0; i < 100; ++i)
696 {
697 if (scsiStatusBSY())
698 {
699 s2s_delay_ms(1);
700 }
701 }
702 if (scsiStatusBSY())
703 {
704 // Error, couldn't acquire scsi bus
705 return 32;
706 }
707 *SCSI_CTRL_BSY = 1;
708 if (! scsiStatusBSY())
709 {
710 // Error, BSY doesn't work.
711 return 32;
712 }
713
714 // Should be safe to use the bus now.
715
716 int result = 0;
717
718 // TEST DBx
719 // TODO test DBp
720 int i;
721 for (i = 0; i < 256; ++i)
722 {
723 *SCSI_CTRL_DBX = i;
724 busSettleDelay();
725 if (*SCSI_STS_DBX != (i & 0xff))
726 {
727 result |= 1;
728 }
729 /*if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))
730 {
731 result |= 2;
732 }*/
733 }
734 *SCSI_CTRL_DBX = 0;
735
736 // TEST MSG, CD, IO
737 /* TODO
738 for (i = 0; i < 8; ++i)
739 {
740 SCSI_CTL_PHASE_Write(i);
741 scsiDeskewDelay();
742
743 if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))
744 {
745 result |= 4;
746 }
747 if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))
748 {
749 result |= 8;
750 }
751 if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))
752 {
753 result |= 16;
754 }
755 }
756 SCSI_CTL_PHASE_Write(0);
757
758 uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };
759 uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };
760
761 for (i = 0; i < 4; ++i)
762 {
763 SCSI_SetPin(signalsOut[i]);
764 scsiDeskewDelay();
765
766 int j;
767 for (j = 0; j < 4; ++j)
768 {
769 if (i == j)
770 {
771 if (! SCSI_ReadFilt(signalsIn[j]))
772 {
773 result |= 32;
774 }
775 }
776 else
777 {
778 if (SCSI_ReadFilt(signalsIn[j]))
779 {
780 result |= 32;
781 }
782 }
783 }
784 SCSI_ClearPin(signalsOut[i]);
785 }
786 */
787
788 *SCSI_CTRL_BSY = 0;
789 return result;
790 }
791