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