Improve IRQ handler responsiveness
[SCSI2SD-V6.git] / src / firmware / scsiPhy.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #ifdef STM32F2xx\r
19 #include "stm32f2xx.h"\r
20 #include "stm32f2xx_hal.h"\r
21 #include "stm32f2xx_hal_dma.h"\r
22 #endif\r
23 \r
24 #ifdef STM32F4xx\r
25 #include "stm32f4xx.h"\r
26 #include "stm32f4xx_hal.h"\r
27 #include "stm32f4xx_hal_dma.h"\r
28 #endif\r
29 \r
30 #include "gpio.h"\r
31 \r
32 #include "scsi.h"\r
33 #include "scsiPhy.h"\r
34 #include "time.h"\r
35 #include "fpga.h"\r
36 #include "led.h"\r
37 \r
38 #include <string.h>\r
39 \r
40 #define SCSI_ASYNC_15 0\r
41 #define SCSI_ASYNC_33 1\r
42 #define SCSI_ASYNC_50 2\r
43 #define SCSI_ASYNC_SAFE 3\r
44 #define SCSI_ASYNC_TURBO 4\r
45 \r
46 #ifdef STM32F2xx\r
47 #include "scsiPhyTiming108MHz.h"\r
48 #endif\r
49 \r
50 #ifdef STM32F4xx\r
51 #include "scsiPhyTiming90MHz.h"\r
52 #endif\r
53 \r
54 // Private DMA variables.\r
55 static int dmaInProgress = 0;\r
56 \r
57 static DMA_HandleTypeDef memToFSMC;\r
58 static DMA_HandleTypeDef fsmcToMem;\r
59 \r
60 \r
61 volatile uint8_t scsiRxDMAComplete;\r
62 volatile uint8_t scsiTxDMAComplete;\r
63 \r
64 // scsi IRQ handler is initialised by the STM32 HAL. Connected to\r
65 // PE4\r
66 // Note: naming is important to ensure this function is listed in the\r
67 // vector table.\r
68 void EXTI4_IRQHandler()\r
69 {\r
70         // Make sure that interrupt flag is set\r
71         if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET) {\r
72 \r
73                 // Clear interrupt flag\r
74                 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);\r
75 \r
76                 uint8_t statusFlags = *SCSI_STS_SCSI;\r
77 \r
78                 scsiDev.resetFlag = scsiDev.resetFlag || (statusFlags & 0x04);\r
79 \r
80                 // selFlag is required for Philips P2000C which releases it after 600ns\r
81                 // without waiting for BSY.\r
82                 // Also required for some early Mac Plus roms\r
83                 if (statusFlags & 0x08) // Check SEL flag\r
84                 {\r
85                         scsiDev.selFlag = *SCSI_STS_SELECTED;\r
86                 }\r
87         }\r
88 }\r
89 \r
90 void\r
91 scsiSetDataCount(uint32_t count)\r
92 {\r
93         *SCSI_DATA_CNT_HI = (count >> 16) & 0xff;\r
94         *SCSI_DATA_CNT_MID = (count >> 8) & 0xff;\r
95         *SCSI_DATA_CNT_LO = count & 0xff;\r
96         *SCSI_DATA_CNT_SET = 1;\r
97 \r
98 #ifdef STM32F4xx\r
99         __NOP();\r
100         __NOP();\r
101 #endif\r
102 }\r
103 \r
104 int scsiFifoReady(void)\r
105 {\r
106         __NOP();\r
107 #ifdef STM32F4xx\r
108         __NOP();\r
109 #endif\r
110         HAL_GPIO_ReadPin(GPIOE, FPGA_GPIO3_Pin);\r
111         __NOP();\r
112 #ifdef STM32F4xx\r
113         __NOP();\r
114         __NOP();\r
115         __NOP();\r
116 #endif\r
117         return HAL_GPIO_ReadPin(GPIOE, FPGA_GPIO3_Pin) != 0;\r
118 }\r
119 \r
120 uint8_t\r
121 scsiReadByte(void)\r
122 {\r
123         scsiSetDataCount(1);\r
124 \r
125         // Ready immediately. setDataCount resets fifos\r
126 \r
127         __disable_irq();\r
128         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
129         {\r
130                 __WFI(); // Wait for interrupt\r
131         }\r
132         __enable_irq();\r
133 \r
134         uint8_t val = scsiPhyRx();\r
135         // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
136 \r
137         return val;\r
138 }\r
139 \r
140 \r
141 void\r
142 scsiReadPIO(uint8_t* data, uint32_t count, int* parityError)\r
143 {\r
144         uint16_t* fifoData = (uint16_t*)data;\r
145         uint32_t count16 = (count + 1) / 2;\r
146 \r
147         int i = 0;\r
148         while ((i  < count16) && likely(!scsiDev.resetFlag))\r
149         {\r
150                 // Wait until FIFO is full (or complete)\r
151                 while (!scsiFifoReady() && likely(!scsiDev.resetFlag))\r
152                 {\r
153                         // spin\r
154                 }\r
155 \r
156                 if (count16 - i >= SCSI_FIFO_DEPTH16)\r
157                 {\r
158                         uint32_t chunk16 = SCSI_FIFO_DEPTH16;\r
159 \r
160                         // Let gcc unroll the loop as much as possible.\r
161                         for (uint32_t k = 0; k + 128 <= chunk16; k += 128)\r
162                         {\r
163                                 fifoData[i + k] = scsiPhyRx();\r
164                                 fifoData[i + k + 1] = scsiPhyRx();\r
165                                 fifoData[i + k + 2] = scsiPhyRx();\r
166                                 fifoData[i + k + 3] = scsiPhyRx();\r
167                                 fifoData[i + k + 4] = scsiPhyRx();\r
168                                 fifoData[i + k + 5] = scsiPhyRx();\r
169                                 fifoData[i + k + 6] = scsiPhyRx();\r
170                                 fifoData[i + k + 7] = scsiPhyRx();\r
171                                 fifoData[i + k + 8] = scsiPhyRx();\r
172                                 fifoData[i + k + 9] = scsiPhyRx();\r
173                                 fifoData[i + k + 10] = scsiPhyRx();\r
174                                 fifoData[i + k + 11] = scsiPhyRx();\r
175                                 fifoData[i + k + 12] = scsiPhyRx();\r
176                                 fifoData[i + k + 13] = scsiPhyRx();\r
177                                 fifoData[i + k + 14] = scsiPhyRx();\r
178                                 fifoData[i + k + 15] = scsiPhyRx();\r
179                                 fifoData[i + k + 16] = scsiPhyRx();\r
180                                 fifoData[i + k + 17] = scsiPhyRx();\r
181                                 fifoData[i + k + 18] = scsiPhyRx();\r
182                                 fifoData[i + k + 19] = scsiPhyRx();\r
183                                 fifoData[i + k + 20] = scsiPhyRx();\r
184                                 fifoData[i + k + 21] = scsiPhyRx();\r
185                                 fifoData[i + k + 22] = scsiPhyRx();\r
186                                 fifoData[i + k + 23] = scsiPhyRx();\r
187                                 fifoData[i + k + 24] = scsiPhyRx();\r
188                                 fifoData[i + k + 25] = scsiPhyRx();\r
189                                 fifoData[i + k + 26] = scsiPhyRx();\r
190                                 fifoData[i + k + 27] = scsiPhyRx();\r
191                                 fifoData[i + k + 28] = scsiPhyRx();\r
192                                 fifoData[i + k + 29] = scsiPhyRx();\r
193                                 fifoData[i + k + 30] = scsiPhyRx();\r
194                                 fifoData[i + k + 31] = scsiPhyRx();\r
195                                 fifoData[i + k + 32] = scsiPhyRx();\r
196                                 fifoData[i + k + 33] = scsiPhyRx();\r
197                                 fifoData[i + k + 34] = scsiPhyRx();\r
198                                 fifoData[i + k + 35] = scsiPhyRx();\r
199                                 fifoData[i + k + 36] = scsiPhyRx();\r
200                                 fifoData[i + k + 37] = scsiPhyRx();\r
201                                 fifoData[i + k + 38] = scsiPhyRx();\r
202                                 fifoData[i + k + 39] = scsiPhyRx();\r
203                                 fifoData[i + k + 40] = scsiPhyRx();\r
204                                 fifoData[i + k + 41] = scsiPhyRx();\r
205                                 fifoData[i + k + 42] = scsiPhyRx();\r
206                                 fifoData[i + k + 43] = scsiPhyRx();\r
207                                 fifoData[i + k + 44] = scsiPhyRx();\r
208                                 fifoData[i + k + 45] = scsiPhyRx();\r
209                                 fifoData[i + k + 46] = scsiPhyRx();\r
210                                 fifoData[i + k + 47] = scsiPhyRx();\r
211                                 fifoData[i + k + 48] = scsiPhyRx();\r
212                                 fifoData[i + k + 49] = scsiPhyRx();\r
213                                 fifoData[i + k + 50] = scsiPhyRx();\r
214                                 fifoData[i + k + 51] = scsiPhyRx();\r
215                                 fifoData[i + k + 52] = scsiPhyRx();\r
216                                 fifoData[i + k + 53] = scsiPhyRx();\r
217                                 fifoData[i + k + 54] = scsiPhyRx();\r
218                                 fifoData[i + k + 55] = scsiPhyRx();\r
219                                 fifoData[i + k + 56] = scsiPhyRx();\r
220                                 fifoData[i + k + 57] = scsiPhyRx();\r
221                                 fifoData[i + k + 58] = scsiPhyRx();\r
222                                 fifoData[i + k + 59] = scsiPhyRx();\r
223                                 fifoData[i + k + 60] = scsiPhyRx();\r
224                                 fifoData[i + k + 61] = scsiPhyRx();\r
225                                 fifoData[i + k + 62] = scsiPhyRx();\r
226                                 fifoData[i + k + 63] = scsiPhyRx();\r
227                                 fifoData[i + k + 64] = scsiPhyRx();\r
228                                 fifoData[i + k + 65] = scsiPhyRx();\r
229                                 fifoData[i + k + 66] = scsiPhyRx();\r
230                                 fifoData[i + k + 67] = scsiPhyRx();\r
231                                 fifoData[i + k + 68] = scsiPhyRx();\r
232                                 fifoData[i + k + 69] = scsiPhyRx();\r
233                                 fifoData[i + k + 70] = scsiPhyRx();\r
234                                 fifoData[i + k + 71] = scsiPhyRx();\r
235                                 fifoData[i + k + 72] = scsiPhyRx();\r
236                                 fifoData[i + k + 73] = scsiPhyRx();\r
237                                 fifoData[i + k + 74] = scsiPhyRx();\r
238                                 fifoData[i + k + 75] = scsiPhyRx();\r
239                                 fifoData[i + k + 76] = scsiPhyRx();\r
240                                 fifoData[i + k + 77] = scsiPhyRx();\r
241                                 fifoData[i + k + 78] = scsiPhyRx();\r
242                                 fifoData[i + k + 79] = scsiPhyRx();\r
243                                 fifoData[i + k + 80] = scsiPhyRx();\r
244                                 fifoData[i + k + 81] = scsiPhyRx();\r
245                                 fifoData[i + k + 82] = scsiPhyRx();\r
246                                 fifoData[i + k + 83] = scsiPhyRx();\r
247                                 fifoData[i + k + 84] = scsiPhyRx();\r
248                                 fifoData[i + k + 85] = scsiPhyRx();\r
249                                 fifoData[i + k + 86] = scsiPhyRx();\r
250                                 fifoData[i + k + 87] = scsiPhyRx();\r
251                                 fifoData[i + k + 88] = scsiPhyRx();\r
252                                 fifoData[i + k + 89] = scsiPhyRx();\r
253                                 fifoData[i + k + 90] = scsiPhyRx();\r
254                                 fifoData[i + k + 91] = scsiPhyRx();\r
255                                 fifoData[i + k + 92] = scsiPhyRx();\r
256                                 fifoData[i + k + 93] = scsiPhyRx();\r
257                                 fifoData[i + k + 94] = scsiPhyRx();\r
258                                 fifoData[i + k + 95] = scsiPhyRx();\r
259                                 fifoData[i + k + 96] = scsiPhyRx();\r
260                                 fifoData[i + k + 97] = scsiPhyRx();\r
261                                 fifoData[i + k + 98] = scsiPhyRx();\r
262                                 fifoData[i + k + 99] = scsiPhyRx();\r
263                                 fifoData[i + k + 100] = scsiPhyRx();\r
264                                 fifoData[i + k + 101] = scsiPhyRx();\r
265                                 fifoData[i + k + 102] = scsiPhyRx();\r
266                                 fifoData[i + k + 103] = scsiPhyRx();\r
267                                 fifoData[i + k + 104] = scsiPhyRx();\r
268                                 fifoData[i + k + 105] = scsiPhyRx();\r
269                                 fifoData[i + k + 106] = scsiPhyRx();\r
270                                 fifoData[i + k + 107] = scsiPhyRx();\r
271                                 fifoData[i + k + 108] = scsiPhyRx();\r
272                                 fifoData[i + k + 109] = scsiPhyRx();\r
273                                 fifoData[i + k + 110] = scsiPhyRx();\r
274                                 fifoData[i + k + 111] = scsiPhyRx();\r
275                                 fifoData[i + k + 112] = scsiPhyRx();\r
276                                 fifoData[i + k + 113] = scsiPhyRx();\r
277                                 fifoData[i + k + 114] = scsiPhyRx();\r
278                                 fifoData[i + k + 115] = scsiPhyRx();\r
279                                 fifoData[i + k + 116] = scsiPhyRx();\r
280                                 fifoData[i + k + 117] = scsiPhyRx();\r
281                                 fifoData[i + k + 118] = scsiPhyRx();\r
282                                 fifoData[i + k + 119] = scsiPhyRx();\r
283                                 fifoData[i + k + 120] = scsiPhyRx();\r
284                                 fifoData[i + k + 121] = scsiPhyRx();\r
285                                 fifoData[i + k + 122] = scsiPhyRx();\r
286                                 fifoData[i + k + 123] = scsiPhyRx();\r
287                                 fifoData[i + k + 124] = scsiPhyRx();\r
288                                 fifoData[i + k + 125] = scsiPhyRx();\r
289                                 fifoData[i + k + 126] = scsiPhyRx();\r
290                                 fifoData[i + k + 127] = scsiPhyRx();\r
291                         }\r
292 \r
293                         i += chunk16;\r
294                 }\r
295                 else\r
296                 {\r
297                         uint32_t chunk16 = count16 - i;\r
298 \r
299                         uint32_t k = 0;\r
300                         for (; k + 4 <= chunk16; k += 4)\r
301                         {\r
302                                 fifoData[i + k] = scsiPhyRx();\r
303                                 fifoData[i + 1 + k] = scsiPhyRx();\r
304                                 fifoData[i + 2 + k] = scsiPhyRx();\r
305                                 fifoData[i + 3 + k] = scsiPhyRx();\r
306                         }\r
307                         for (; k < chunk16; ++k)\r
308                         {\r
309                                 fifoData[i + k] = scsiPhyRx();\r
310                         }\r
311                         i += chunk16;\r
312                 }\r
313         }\r
314 \r
315         *parityError |= scsiParityError();\r
316 }\r
317 \r
318 void\r
319 scsiRead(uint8_t* data, uint32_t count, int* parityError)\r
320 {\r
321         int i = 0;\r
322         *parityError = 0;\r
323 \r
324         while (i < count && likely(!scsiDev.resetFlag))\r
325         {\r
326                 uint32_t chunk = ((count - i) > SCSI_XFER_MAX)\r
327                         ? SCSI_XFER_MAX : (count - i);\r
328                 scsiSetDataCount(chunk);\r
329 \r
330                 scsiReadPIO(data + i, chunk, parityError);\r
331 \r
332                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
333                 {\r
334                     __disable_irq();\r
335             if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
336             {\r
337                         __WFI();\r
338             }\r
339                     __enable_irq();\r
340                 }\r
341 \r
342                 i += chunk;\r
343         }\r
344 }\r
345 \r
346 void\r
347 scsiWriteByte(uint8_t value)\r
348 {\r
349         scsiSetDataCount(1);\r
350         scsiPhyTx(value);\r
351 \r
352         __disable_irq();\r
353         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
354         {\r
355                 __WFI();\r
356         }\r
357         __enable_irq();\r
358 }\r
359 \r
360 void\r
361 scsiWritePIO(const uint8_t* data, uint32_t count)\r
362 {\r
363         uint16_t* fifoData = (uint16_t*)data;\r
364         uint32_t count16 = (count + 1) / 2;\r
365 \r
366         int i = 0;\r
367         while ((i  < count16) && likely(!scsiDev.resetFlag))\r
368         {\r
369                 while (!scsiFifoReady() && likely(!scsiDev.resetFlag))\r
370                 {\r
371                         // Spin\r
372                 }\r
373 \r
374                 if (count16 - i >= SCSI_FIFO_DEPTH16)\r
375                 {\r
376                         uint32_t chunk16 = SCSI_FIFO_DEPTH16;\r
377 \r
378                         // Let gcc unroll the loop as much as possible.\r
379                         for (uint32_t k = 0; k + 128 <= chunk16; k += 128)\r
380                         {\r
381                                 scsiPhyTx32(fifoData[i + k], fifoData[i + k + 1]);\r
382                                 scsiPhyTx32(fifoData[i + 2 + k], fifoData[i + k + 3]);\r
383                                 scsiPhyTx32(fifoData[i + 4 + k], fifoData[i + k + 5]);\r
384                                 scsiPhyTx32(fifoData[i + 6 + k], fifoData[i + k + 7]);\r
385                                 scsiPhyTx32(fifoData[i + 8 + k], fifoData[i + k + 9]);\r
386                                 scsiPhyTx32(fifoData[i + 10 + k], fifoData[i + k + 11]);\r
387                                 scsiPhyTx32(fifoData[i + 12 + k], fifoData[i + k + 13]);\r
388                                 scsiPhyTx32(fifoData[i + 14 + k], fifoData[i + k + 15]);\r
389                                 scsiPhyTx32(fifoData[i + 16 + k], fifoData[i + k + 17]);\r
390                                 scsiPhyTx32(fifoData[i + 18 + k], fifoData[i + k + 19]);\r
391                                 scsiPhyTx32(fifoData[i + 20 + k], fifoData[i + k + 21]);\r
392                                 scsiPhyTx32(fifoData[i + 22 + k], fifoData[i + k + 23]);\r
393                                 scsiPhyTx32(fifoData[i + 24 + k], fifoData[i + k + 25]);\r
394                                 scsiPhyTx32(fifoData[i + 26 + k], fifoData[i + k + 27]);\r
395                                 scsiPhyTx32(fifoData[i + 28 + k], fifoData[i + k + 29]);\r
396                                 scsiPhyTx32(fifoData[i + 30 + k], fifoData[i + k + 31]);\r
397 \r
398                                 scsiPhyTx32(fifoData[i + 32 + k], fifoData[i + k + 33]);\r
399                                 scsiPhyTx32(fifoData[i + 34 + k], fifoData[i + k + 35]);\r
400                                 scsiPhyTx32(fifoData[i + 36 + k], fifoData[i + k + 37]);\r
401                                 scsiPhyTx32(fifoData[i + 38 + k], fifoData[i + k + 39]);\r
402                                 scsiPhyTx32(fifoData[i + 40 + k], fifoData[i + k + 41]);\r
403                                 scsiPhyTx32(fifoData[i + 42 + k], fifoData[i + k + 43]);\r
404                                 scsiPhyTx32(fifoData[i + 44 + k], fifoData[i + k + 45]);\r
405                                 scsiPhyTx32(fifoData[i + 46 + k], fifoData[i + k + 47]);\r
406                                 scsiPhyTx32(fifoData[i + 48 + k], fifoData[i + k + 49]);\r
407                                 scsiPhyTx32(fifoData[i + 50 + k], fifoData[i + k + 51]);\r
408                                 scsiPhyTx32(fifoData[i + 52 + k], fifoData[i + k + 53]);\r
409                                 scsiPhyTx32(fifoData[i + 54 + k], fifoData[i + k + 55]);\r
410                                 scsiPhyTx32(fifoData[i + 56 + k], fifoData[i + k + 57]);\r
411                                 scsiPhyTx32(fifoData[i + 58 + k], fifoData[i + k + 59]);\r
412                                 scsiPhyTx32(fifoData[i + 60 + k], fifoData[i + k + 61]);\r
413                                 scsiPhyTx32(fifoData[i + 62 + k], fifoData[i + k + 63]);\r
414 \r
415                                 scsiPhyTx32(fifoData[i + 64 + k], fifoData[i + k + 65]);\r
416                                 scsiPhyTx32(fifoData[i + 66 + k], fifoData[i + k + 67]);\r
417                                 scsiPhyTx32(fifoData[i + 68 + k], fifoData[i + k + 69]);\r
418                                 scsiPhyTx32(fifoData[i + 70 + k], fifoData[i + k + 71]);\r
419                                 scsiPhyTx32(fifoData[i + 72 + k], fifoData[i + k + 73]);\r
420                                 scsiPhyTx32(fifoData[i + 74 + k], fifoData[i + k + 75]);\r
421                                 scsiPhyTx32(fifoData[i + 76 + k], fifoData[i + k + 77]);\r
422                                 scsiPhyTx32(fifoData[i + 78 + k], fifoData[i + k + 79]);\r
423                                 scsiPhyTx32(fifoData[i + 80 + k], fifoData[i + k + 81]);\r
424                                 scsiPhyTx32(fifoData[i + 82 + k], fifoData[i + k + 83]);\r
425                                 scsiPhyTx32(fifoData[i + 84 + k], fifoData[i + k + 85]);\r
426                                 scsiPhyTx32(fifoData[i + 86 + k], fifoData[i + k + 87]);\r
427                                 scsiPhyTx32(fifoData[i + 88 + k], fifoData[i + k + 89]);\r
428                                 scsiPhyTx32(fifoData[i + 90 + k], fifoData[i + k + 91]);\r
429                                 scsiPhyTx32(fifoData[i + 92 + k], fifoData[i + k + 93]);\r
430                                 scsiPhyTx32(fifoData[i + 94 + k], fifoData[i + k + 95]);\r
431 \r
432                                 scsiPhyTx32(fifoData[i + 96 + k], fifoData[i + k + 97]);\r
433                                 scsiPhyTx32(fifoData[i + 98 + k], fifoData[i + k + 99]);\r
434                                 scsiPhyTx32(fifoData[i + 100 + k], fifoData[i + k + 101]);\r
435                                 scsiPhyTx32(fifoData[i + 102 + k], fifoData[i + k + 103]);\r
436                                 scsiPhyTx32(fifoData[i + 104 + k], fifoData[i + k + 105]);\r
437                                 scsiPhyTx32(fifoData[i + 106 + k], fifoData[i + k + 107]);\r
438                                 scsiPhyTx32(fifoData[i + 108 + k], fifoData[i + k + 109]);\r
439                                 scsiPhyTx32(fifoData[i + 110 + k], fifoData[i + k + 111]);\r
440                                 scsiPhyTx32(fifoData[i + 112 + k], fifoData[i + k + 113]);\r
441                                 scsiPhyTx32(fifoData[i + 114 + k], fifoData[i + k + 115]);\r
442                                 scsiPhyTx32(fifoData[i + 116 + k], fifoData[i + k + 117]);\r
443                                 scsiPhyTx32(fifoData[i + 118 + k], fifoData[i + k + 119]);\r
444                                 scsiPhyTx32(fifoData[i + 120 + k], fifoData[i + k + 121]);\r
445                                 scsiPhyTx32(fifoData[i + 122 + k], fifoData[i + k + 123]);\r
446                                 scsiPhyTx32(fifoData[i + 124 + k], fifoData[i + k + 125]);\r
447                                 scsiPhyTx32(fifoData[i + 126 + k], fifoData[i + k + 127]);\r
448 \r
449                         }\r
450 \r
451                         i += chunk16;\r
452                 }\r
453                 else\r
454                 {\r
455                         uint32_t chunk16 = count16 - i;\r
456 \r
457                         uint32_t k = 0;\r
458                         for (; k + 4 <= chunk16; k += 4)\r
459                         {\r
460                                 scsiPhyTx32(fifoData[i + k], fifoData[i + k + 1]);\r
461                                 scsiPhyTx32(fifoData[i + k + 2], fifoData[i + k + 3]);\r
462                         }\r
463                         for (; k < chunk16; ++k)\r
464                         {\r
465                                 scsiPhyTx(fifoData[i + k]);\r
466                         }\r
467                         i += chunk16;\r
468                 }\r
469         }\r
470 }\r
471 \r
472 \r
473 void\r
474 scsiWrite(const uint8_t* data, uint32_t count)\r
475 {\r
476         int i = 0;\r
477         while (i < count && likely(!scsiDev.resetFlag))\r
478         {\r
479                 uint32_t chunk = ((count - i) > SCSI_XFER_MAX)\r
480                         ? SCSI_XFER_MAX : (count - i);\r
481                 scsiSetDataCount(chunk);\r
482 \r
483                 scsiWritePIO(data + i, chunk);\r
484 \r
485                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
486                 {\r
487                     __disable_irq();\r
488                     if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
489             {\r
490                         __WFI();\r
491             }\r
492                     __enable_irq();\r
493                 }\r
494 \r
495                 i += chunk;\r
496         }\r
497 }\r
498 \r
499 static inline void busSettleDelay(void)\r
500 {\r
501         // Data Release time (switching IO) = 400ns\r
502         // + Bus Settle time (switching phase) = 400ns.\r
503         s2s_delay_us(1); // Close enough.\r
504 }\r
505 \r
506 void scsiEnterBusFree()\r
507 {\r
508         *SCSI_CTRL_BSY = 0x00;\r
509         // We now have a Bus Clear Delay of 800ns to release remaining signals.\r
510         *SCSI_CTRL_PHASE = 0;\r
511 }\r
512 \r
513 static void\r
514 scsiSetTiming(\r
515         uint8_t assertClocks,\r
516         uint8_t deskew,\r
517         uint8_t hold,\r
518         uint8_t glitch)\r
519 {\r
520         *SCSI_CTRL_DESKEW = ((hold & 7) << 5) | (deskew & 0x1F);\r
521         *SCSI_CTRL_TIMING = (assertClocks & 0x3F);\r
522         *SCSI_CTRL_TIMING3 = (glitch & 0xF);\r
523 }\r
524 \r
525 static void\r
526 scsiSetDefaultTiming()\r
527 {\r
528         const uint8_t* asyncTiming = asyncTimings[0];\r
529         scsiSetTiming(\r
530                 asyncTiming[0],\r
531                 asyncTiming[1],\r
532                 asyncTiming[2],\r
533                 asyncTiming[3]);\r
534 }\r
535 \r
536 void scsiEnterPhase(int newPhase)\r
537 {\r
538         uint32_t delay = scsiEnterPhaseImmediate(newPhase);\r
539         if (delay > 0)\r
540         {\r
541                 s2s_delay_us(delay);\r
542         }\r
543 }\r
544 \r
545 // Returns microsecond delay\r
546 uint32_t scsiEnterPhaseImmediate(int newPhase)\r
547 {\r
548         // ANSI INCITS 362-2002 SPI-3 10.7.1:\r
549         // Phase changes are not allowed while REQ or ACK is asserted.\r
550         while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}\r
551 \r
552         int oldPhase = *SCSI_CTRL_PHASE;\r
553 \r
554         if (newPhase != oldPhase)\r
555         {\r
556                 if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&\r
557                         scsiDev.target->syncOffset)\r
558                 {\r
559                         if (scsiDev.target->syncPeriod < 23)\r
560                         {\r
561                                 scsiSetTiming(SCSI_FAST20_ASSERT, SCSI_FAST20_DESKEW, SCSI_FAST20_HOLD, 1);\r
562                         }\r
563                         else if (scsiDev.target->syncPeriod <= 25)\r
564                         {\r
565                                 if (newPhase == DATA_IN)\r
566                                 {\r
567                                         scsiSetTiming(SCSI_FAST10_WRITE_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);\r
568                                 }\r
569                                 else\r
570                                 {\r
571                                         scsiSetTiming(SCSI_FAST10_READ_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);\r
572                                 }\r
573                         }\r
574                         else\r
575                         {\r
576                                 // Amiga A3000 OS3.9 sets period to 35 and fails with\r
577                                 // glitch == 1.\r
578                                 int glitch =\r
579                                         scsiDev.target->syncPeriod < 35 ? 1 :\r
580                                                 (scsiDev.target->syncPeriod < 45 ? 2 : 5);\r
581                                 int deskew = syncDeskew(scsiDev.target->syncPeriod);\r
582                                 int assertion;\r
583                                 if (newPhase == DATA_IN)\r
584                                 {\r
585                                         assertion = syncAssertionWrite(scsiDev.target->syncPeriod, deskew);\r
586                                 }\r
587                                 else\r
588                                 {\r
589                                         assertion = syncAssertionRead(scsiDev.target->syncPeriod);\r
590                                 }\r
591                                 scsiSetTiming(\r
592                                         assertion,\r
593                                         deskew,\r
594                                         syncHold(scsiDev.target->syncPeriod),\r
595                                         glitch);\r
596                         }\r
597 \r
598                         *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;\r
599                 }\r
600                 else if (newPhase >= 0)\r
601                 {\r
602 \r
603                         *SCSI_CTRL_SYNC_OFFSET = 0;\r
604                         const uint8_t* asyncTiming;\r
605 \r
606                         if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit)\r
607                         {\r
608                                 asyncTiming = asyncTimings[SCSI_ASYNC_SAFE];\r
609                         }\r
610                         else if (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_TURBO)\r
611                         {\r
612                                 asyncTiming = asyncTimings[SCSI_ASYNC_TURBO];\r
613                         }\r
614                         else if (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_ASYNC_50)\r
615                         {\r
616                                 asyncTiming = asyncTimings[SCSI_ASYNC_50];\r
617                         } else if (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_ASYNC_33) {\r
618 \r
619                                 asyncTiming = asyncTimings[SCSI_ASYNC_33];\r
620 \r
621                         } else {\r
622                                 asyncTiming = asyncTimings[SCSI_ASYNC_15];\r
623                         }\r
624                         scsiSetTiming(\r
625                                 asyncTiming[0],\r
626                                 asyncTiming[1],\r
627                                 asyncTiming[2],\r
628                                 asyncTiming[3]);\r
629                 }\r
630 \r
631                 uint32_t delayUs = 0;\r
632                 if (newPhase >= 0)\r
633                 {\r
634                         *SCSI_CTRL_PHASE = newPhase;\r
635                         delayUs += 1; // busSettleDelay\r
636 \r
637                         if (scsiDev.compatMode < COMPAT_SCSI2)\r
638                         {\r
639                                 // EMU EMAX needs 100uS ! 10uS is not enough.\r
640                                 delayUs += 100;\r
641                         }\r
642                 }\r
643                 else\r
644                 {\r
645                         *SCSI_CTRL_PHASE = 0;\r
646                 }\r
647 \r
648                 return delayUs;\r
649         }\r
650 \r
651         return 0; // No change\r
652 }\r
653 \r
654 // Returns a "safe" estimate of the host SCSI speed of\r
655 // theoretical speed / 2\r
656 uint32_t s2s_getScsiRateKBs()\r
657 {\r
658         if (scsiDev.target->syncOffset)\r
659         {\r
660                 if (scsiDev.target->syncPeriod < 23)\r
661                 {\r
662                         return 20 / 2;\r
663                 }\r
664                 else if (scsiDev.target->syncPeriod <= 25)\r
665                 {\r
666                         return 10 / 2;\r
667                 }\r
668                 else\r
669                 {\r
670                         // 1000000000 / (scsiDev.target->syncPeriod * 4) bytes per second\r
671                         // (1000000000 / (scsiDev.target->syncPeriod * 4)) / 1000  kB/s\r
672                         return (1000000 / (scsiDev.target->syncPeriod * 4)) / 2;\r
673                 }\r
674         }\r
675         else\r
676         {\r
677                 return 0;\r
678         }\r
679 }\r
680 \r
681 void scsiPhyReset()\r
682 {\r
683         if (dmaInProgress)\r
684         {\r
685                 HAL_DMA_Abort(&memToFSMC);\r
686                 HAL_DMA_Abort(&fsmcToMem);\r
687 \r
688                 dmaInProgress = 0;\r
689         }\r
690 \r
691         s2s_fpgaReset(); // Clears fifos etc.\r
692 \r
693         *SCSI_CTRL_PHASE = 0x00;\r
694         *SCSI_CTRL_BSY = 0x00;\r
695         *SCSI_CTRL_DBX = 0;\r
696 \r
697         *SCSI_CTRL_SYNC_OFFSET = 0;\r
698         scsiSetDefaultTiming();\r
699 \r
700         // DMA Benchmark code\r
701         // Currently 14.9MB/s.\r
702         #ifdef DMA_BENCHMARK\r
703         while(1)\r
704         {\r
705                 s2s_ledOn();\r
706                 // 100MB\r
707                 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)\r
708                 {\r
709                         HAL_DMA_Start(\r
710                                 &memToFSMC,\r
711                                 (uint32_t) &scsiDev.data[0],\r
712                                 (uint32_t) SCSI_FIFO_DATA,\r
713                                 SCSI_FIFO_DEPTH / 4);\r
714 \r
715                         HAL_DMA_PollForTransfer(\r
716                                 &memToFSMC,\r
717                                 HAL_DMA_FULL_TRANSFER,\r
718                                 0xffffffff);\r
719 \r
720                         s2s_fpgaReset();\r
721                 }\r
722                 s2s_ledOff();\r
723 \r
724                 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);\r
725         }\r
726         #endif\r
727 \r
728         // PIO Benchmark code\r
729         // Currently 16.7MB/s.\r
730         //#define PIO_BENCHMARK 1\r
731         #ifdef PIO_BENCHMARK\r
732         while(1)\r
733         {\r
734                 s2s_ledOn();\r
735 \r
736                 scsiEnterPhase(DATA_IN); // Need IO flag set for fifo ready flag\r
737 \r
738                 // 100MB\r
739                 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)\r
740                 {\r
741                         scsiSetDataCount(1); // Resets fifos.\r
742 \r
743                         // Shouldn't block\r
744                         scsiDev.resetFlag = 0;\r
745                         scsiWritePIO(&scsiDev.data[0], SCSI_FIFO_DEPTH);\r
746                 }\r
747                 s2s_ledOff();\r
748 \r
749                 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);\r
750         }\r
751         #endif\r
752 \r
753         #ifdef SCSI_FREQ_TEST\r
754         while(1)\r
755         {\r
756                 *SCSI_CTRL_DBX = 0xAA;\r
757                 *SCSI_CTRL_DBX = 0x55;\r
758         }\r
759         #endif\r
760 \r
761 }\r
762 \r
763 static void scsiPhyInitDMA()\r
764 {\r
765         // One-time init only.\r
766         static uint8_t init = 0;\r
767         if (init == 0)\r
768         {\r
769                 init = 1;\r
770 \r
771                 // Memory to memory transfers can only be done using DMA2\r
772                 __DMA2_CLK_ENABLE();\r
773 \r
774                 // Transmit SCSI data. The source data is treated as the\r
775                 // peripheral (even though this is memory-to-memory)\r
776                 memToFSMC.Instance = DMA2_Stream0;\r
777                 memToFSMC.Init.Channel = DMA_CHANNEL_0;\r
778                 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
779                 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;\r
780                 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;\r
781                 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;\r
782                 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;\r
783                 memToFSMC.Init.Mode = DMA_NORMAL;\r
784                 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;\r
785                 // FIFO mode is needed to allow conversion from 32bit words to the\r
786                 // 16bit FSMC interface.\r
787                 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
788 \r
789                 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's\r
790                 // better to let the DMA fifo fill up then do burst transfers, but\r
791                 // bursting out the FSMC interface will be very slow and may starve\r
792                 // other (faster) transfers. We don't want to risk the SDIO transfers\r
793                 // from overrun/underrun conditions.\r
794                 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
795                 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;\r
796                 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
797                 HAL_DMA_Init(&memToFSMC);\r
798 \r
799                 // Receive SCSI data. The source data (fsmc) is treated as the\r
800                 // peripheral (even though this is memory-to-memory)\r
801                 fsmcToMem.Instance = DMA2_Stream1;\r
802                 fsmcToMem.Init.Channel = DMA_CHANNEL_0;\r
803                 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
804                 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;\r
805                 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;\r
806                 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;\r
807                 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;\r
808                 fsmcToMem.Init.Mode = DMA_NORMAL;\r
809                 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;\r
810                 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
811                 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
812                 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;\r
813                 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
814                 HAL_DMA_Init(&fsmcToMem);\r
815 \r
816                 // TODO configure IRQs\r
817         }\r
818 }\r
819 \r
820 \r
821 void scsiPhyInit()\r
822 {\r
823         scsiPhyInitDMA();\r
824 \r
825         *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig\r
826         *SCSI_CTRL_PHASE = 0x00;\r
827         *SCSI_CTRL_BSY = 0x00;\r
828         *SCSI_CTRL_DBX = 0;\r
829 \r
830         *SCSI_CTRL_SYNC_OFFSET = 0;\r
831         scsiSetDefaultTiming();\r
832 \r
833         *SCSI_CTRL_SEL_TIMING = SCSI_DEFAULT_SELECTION;\r
834 \r
835 }\r
836 \r
837 void scsiPhyConfig()\r
838 {\r
839         if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)\r
840         {\r
841                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);\r
842         }\r
843         else\r
844         {\r
845                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);\r
846         }\r
847 \r
848 \r
849         uint8_t idMask = 0;\r
850         for (int i = 0; i < 8; ++i)\r
851         {\r
852                 const S2S_TargetCfg* cfg = s2s_getConfigById(i);\r
853                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))\r
854                 {\r
855                         idMask |= (1 << i);\r
856                 }\r
857         }\r
858         *SCSI_CTRL_IDMASK = idMask;\r
859 \r
860         *SCSI_CTRL_FLAGS =\r
861                 ((scsiDev.boardCfg.flags & S2S_CFG_DISABLE_GLITCH) ?\r
862                         SCSI_CTRL_FLAGS_DISABLE_GLITCH : 0) |\r
863                 ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY) ?\r
864                         SCSI_CTRL_FLAGS_ENABLE_PARITY : 0);\r
865 \r
866         *SCSI_CTRL_SEL_TIMING =\r
867                 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH) ?\r
868                         SCSI_FAST_SELECTION : SCSI_DEFAULT_SELECTION;\r
869 }\r
870 \r
871 \r
872 // 1 = DBx error\r
873 // 2 = Parity error\r
874 // 4 = MSG error\r
875 // 8 = CD error\r
876 // 16 = IO error\r
877 // 32 = other error\r
878 // 64 = fpga comms error\r
879 int scsiSelfTest()\r
880 {\r
881         if (scsiDev.phase != BUS_FREE)\r
882         {\r
883                 return 32;\r
884         }\r
885 \r
886         // Acquire the SCSI bus.\r
887         for (int i = 0; i < 100; ++i)\r
888         {\r
889                 if (scsiStatusBSY())\r
890                 {\r
891                         s2s_delay_ms(1);\r
892                 }\r
893         }\r
894         if (scsiStatusBSY())\r
895         {\r
896                 // Error, couldn't acquire scsi bus\r
897                 return 32;\r
898         }\r
899         *SCSI_CTRL_BSY = 1;\r
900         s2s_delay_ms(1);\r
901         if (! scsiStatusBSY())\r
902         {\r
903                 *SCSI_CTRL_BSY = 0;\r
904 \r
905                 // Error, BSY doesn't work.\r
906                 return 32;\r
907         }\r
908 \r
909         // Should be safe to use the bus now.\r
910 \r
911         int result = 0;\r
912 \r
913         *SCSI_CTRL_DBX = 0;\r
914         busSettleDelay();\r
915         if ((*SCSI_STS_DBX & 0xff) != 0)\r
916         {\r
917                 result = 1;\r
918         }\r
919 \r
920         *SCSI_CTRL_BSY = 0;\r
921 \r
922         return result;\r
923 }\r
924 \r