1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * A590/A2091/A3000/CDTV SCSI expansion (DMAC/SuperDMAC + WD33C93) emulation
5 * Includes A590 + XT drive emulation.
6 * GVP Series I and II
7 * A2090 SCSI and ST-506
8 *
9 * Copyright 2007-2015 Toni Wilen
10 *
11 */
12
13 #define GVP_S1_DEBUG_IO 0
14 #define GVP_S2_DEBUG_IO 0
15 #define A2091_DEBUG 0
16 #define A2091_DEBUG_IO 0
17 #define XT_DEBUG 0
18 #define A3000_DEBUG 0
19 #define A3000_DEBUG_IO 0
20 #define WD33C93_DEBUG 0
21 #define WD33C93_DEBUG_PIO 0
22
23 #include "sysconfig.h"
24 #include "sysdeps.h"
25
26 #include "options.h"
27 #include "uae.h"
28 #include "uae/memory.h"
29 #include "rommgr.h"
30 #include "custom.h"
31 #include "newcpu.h"
32 #include "debug.h"
33 #include "scsi.h"
34 #include "threaddep/thread.h"
35 #include "a2091.h"
36 #include "blkdev.h"
37 #include "gui.h"
38 #include "zfile.h"
39 #include "filesys.h"
40 #include "autoconf.h"
41 #include "cdtv.h"
42 #include "savestate.h"
43 #include "cpuboard.h"
44
45 #define DMAC_8727_ROM_VECTOR 0x8000
46 #define CDMAC_ROM_VECTOR 0x2000
47 #define CDMAC_ROM_OFFSET 0x2000
48 #define GVP_ROM_OFFSET 0x8000
49 #define GVP_SERIES_I_RAM_OFFSET_1 0x04000
50 #define GVP_SERIES_I_RAM_OFFSET_2 0x04000
51 #define GVP_SERIES_I_RAM_OFFSET_3 0x10000
52 #define GVP_SERIES_I_RAM_MASK_1 (4096 - 1)
53 #define GVP_SERIES_I_RAM_MASK_2 (16384 - 1)
54 #define GVP_SERIES_I_RAM_MASK_3 (16384 - 1)
55
56 /* SuperDMAC CNTR bits. */
57 #define SCNTR_TCEN (1<<5)
58 #define SCNTR_PREST (1<<4)
59 #define SCNTR_PDMD (1<<3)
60 #define SCNTR_INTEN (1<<2)
61 #define SCNTR_DDIR (1<<1)
62 #define SCNTR_IO_DX (1<<0)
63 /* DMAC CNTR bits. */
64 #define CNTR_TCEN (1<<7)
65 #define CNTR_PREST (1<<6)
66 #define CNTR_PDMD (1<<5)
67 #define CNTR_INTEN (1<<4)
68 #define CNTR_DDIR (1<<3)
69 /* ISTR bits. */
70 #define ISTR_INT_F (1<<7) /* Interrupt Follow */
71 #define ISTR_INTS (1<<6) /* SCSI or XT Peripheral Interrupt */
72 #define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */
73 #define ISTR_INT_P (1<<4) /* Interrupt Pending */
74 #define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */
75 #define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */
76 #define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */
77 #define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */
78
79 /* GVP models */
80 #define GVP_GFORCE_040 0x20
81 #define GVP_GFORCE_040_SCSI 0x30
82 #define GVP_A1291_SCSI 0x40
83 #define GVP_GFORCE_030 0xa0
84 #define GVP_GFORCE_030_SCSI 0xb0
85 #define GVP_COMBO_R4 0x60
86 #define GVP_COMBO_R4_SCSI 0x70
87 #define GVP_COMBO_R3 0xe0
88 #define GVP_COMBO_R3_SCSI 0xf0
89 #define GVP_SERIESII 0xf8
90 #define GVP_A530 0xc0
91 #define GVP_A530_SCSI 0xd0
92
93 /* wd register names */
94 #define WD_OWN_ID 0x00
95 #define WD_CONTROL 0x01
96 #define WD_TIMEOUT_PERIOD 0x02
97 #define WD_CDB_1 0x03
98 #define WD_T_SECTORS 0x03
99 #define WD_CDB_2 0x04
100 #define WD_T_HEADS 0x04
101 #define WD_CDB_3 0x05
102 #define WD_T_CYLS_0 0x05
103 #define WD_CDB_4 0x06
104 #define WD_T_CYLS_1 0x06
105 #define WD_CDB_5 0x07
106 #define WD_L_ADDR_0 0x07
107 #define WD_CDB_6 0x08
108 #define WD_L_ADDR_1 0x08
109 #define WD_CDB_7 0x09
110 #define WD_L_ADDR_2 0x09
111 #define WD_CDB_8 0x0a
112 #define WD_L_ADDR_3 0x0a
113 #define WD_CDB_9 0x0b
114 #define WD_SECTOR 0x0b
115 #define WD_CDB_10 0x0c
116 #define WD_HEAD 0x0c
117 #define WD_CDB_11 0x0d
118 #define WD_CYL_0 0x0d
119 #define WD_CDB_12 0x0e
120 #define WD_CYL_1 0x0e
121 #define WD_TARGET_LUN 0x0f
122 #define WD_COMMAND_PHASE 0x10
123 #define WD_SYNCHRONOUS_TRANSFER 0x11
124 #define WD_TRANSFER_COUNT_MSB 0x12
125 #define WD_TRANSFER_COUNT 0x13
126 #define WD_TRANSFER_COUNT_LSB 0x14
127 #define WD_DESTINATION_ID 0x15
128 #define WD_SOURCE_ID 0x16
129 #define WD_SCSI_STATUS 0x17
130 #define WD_COMMAND 0x18
131 #define WD_DATA 0x19
132 #define WD_QUEUE_TAG 0x1a
133 #define WD_AUXILIARY_STATUS 0x1f
134 /* WD commands */
135 #define WD_CMD_RESET 0x00
136 #define WD_CMD_ABORT 0x01
137 #define WD_CMD_ASSERT_ATN 0x02
138 #define WD_CMD_NEGATE_ACK 0x03
139 #define WD_CMD_DISCONNECT 0x04
140 #define WD_CMD_RESELECT 0x05
141 #define WD_CMD_SEL_ATN 0x06
142 #define WD_CMD_SEL 0x07
143 #define WD_CMD_SEL_ATN_XFER 0x08
144 #define WD_CMD_SEL_XFER 0x09
145 #define WD_CMD_RESEL_RECEIVE 0x0a
146 #define WD_CMD_RESEL_SEND 0x0b
147 #define WD_CMD_WAIT_SEL_RECEIVE 0x0c
148 #define WD_CMD_TRANS_ADDR 0x18
149 #define WD_CMD_TRANS_INFO 0x20
150 #define WD_CMD_TRANSFER_PAD 0x21
151 #define WD_CMD_SBT_MODE 0x80
152
153 /* paused or aborted interrupts */
154 #define CSR_MSGIN 0x20
155 #define CSR_SDP 0x21
156 #define CSR_SEL_ABORT 0x22
157 #define CSR_RESEL_ABORT 0x25
158 #define CSR_RESEL_ABORT_AM 0x27
159 #define CSR_ABORT 0x28
160 /* successful completion interrupts */
161 #define CSR_RESELECT 0x10
162 #define CSR_SELECT 0x11
163 #define CSR_TRANS_ADDR 0x15
164 #define CSR_SEL_XFER_DONE 0x16
165 #define CSR_XFER_DONE 0x18
166 /* terminated interrupts */
167 #define CSR_INVALID 0x40
168 #define CSR_UNEXP_DISC 0x41
169 #define CSR_TIMEOUT 0x42
170 #define CSR_PARITY 0x43
171 #define CSR_PARITY_ATN 0x44
172 #define CSR_BAD_STATUS 0x45
173 #define CSR_UNEXP 0x48
174 /* service required interrupts */
175 #define CSR_RESEL 0x80
176 #define CSR_RESEL_AM 0x81
177 #define CSR_DISC 0x85
178 #define CSR_SRV_REQ 0x88
179 /* SCSI Bus Phases */
180 #define PHS_DATA_OUT 0x00
181 #define PHS_DATA_IN 0x01
182 #define PHS_COMMAND 0x02
183 #define PHS_STATUS 0x03
184 #define PHS_MESS_OUT 0x06
185 #define PHS_MESS_IN 0x07
186
187 /* Auxialiry status */
188 #define ASR_INT 0x80 /* Interrupt pending */
189 #define ASR_LCI 0x40 /* Last command ignored */
190 #define ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */
191 #define ASR_CIP 0x10 /* Busy, cmd unavail also */
192 #define ASR_xxx 0x0c
193 #define ASR_PE 0x02 /* Parity error (even) */
194 #define ASR_DBR 0x01 /* Data Buffer Ready */
195 /* Status */
196 #define CSR_CAUSE 0xf0
197 #define CSR_RESET 0x00 /* chip was reset */
198 #define CSR_CMD_DONE 0x10 /* cmd completed */
199 #define CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/
200 #define CSR_CMD_ERR 0x40 /* end with error */
201 #define CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */
202 /* Control */
203 #define CTL_DMA 0x80 /* Single byte dma */
204 #define CTL_DBA_DMA 0x40 /* direct buffer access (bus master) */
205 #define CTL_BURST_DMA 0x20 /* continuous mode (8237) */
206 #define CTL_NO_DMA 0x00 /* Programmed I/O */
207 #define CTL_HHP 0x10 /* Halt on host parity error */
208 #define CTL_EDI 0x08 /* Ending disconnect interrupt */
209 #define CTL_IDI 0x04 /* Intermediate disconnect interrupt*/
210 #define CTL_HA 0x02 /* Halt on ATN */
211 #define CTL_HSP 0x01 /* Halt on SCSI parity error */
212
213 /* SCSI Messages */
214 #define MSG_COMMAND_COMPLETE 0x00
215 #define MSG_SAVE_DATA_POINTER 0x02
216 #define MSG_RESTORE_DATA_POINTERS 0x03
217 #define MSG_NOP 0x08
218 #define MSG_IDENTIFY 0x80
219
220 /* XT hard disk controller registers */
221 #define XD_DATA 0x00 /* data RW register */
222 #define XD_RESET 0x01 /* reset WO register */
223 #define XD_STATUS 0x01 /* status RO register */
224 #define XD_SELECT 0x02 /* select WO register */
225 #define XD_JUMPER 0x02 /* jumper RO register */
226 #define XD_CONTROL 0x03 /* DMAE/INTE WO register */
227 #define XD_RESERVED 0x03 /* reserved */
228
229 /* XT hard disk controller commands (incomplete list) */
230 #define XT_CMD_TESTREADY 0x00 /* test drive ready */
231 #define XT_CMD_RECALIBRATE 0x01 /* recalibrate drive */
232 #define XT_CMD_SENSE 0x03 /* request sense */
233 #define XT_CMD_FORMATDRV 0x04 /* format drive */
234 #define XT_CMD_VERIFY 0x05 /* read verify */
235 #define XT_CMD_FORMATTRK 0x06 /* format track */
236 #define XT_CMD_FORMATBAD 0x07 /* format bad track */
237 #define XT_CMD_READ 0x08 /* read */
238 #define XT_CMD_WRITE 0x0A /* write */
239 #define XT_CMD_SEEK 0x0B /* seek */
240 /* Controller specific commands */
241 #define XT_CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X & CX only?) */
242
243 /* Bits for command status byte */
244 #define XT_CSB_ERROR 0x02 /* error */
245 #define XT_CSB_LUN 0x20 /* logical Unit Number */
246
247 /* XT hard disk controller status bits */
248 #define XT_STAT_READY 0x01 /* controller is ready */
249 #define XT_STAT_INPUT 0x02 /* data flowing from controller to host */
250 #define XT_STAT_COMMAND 0x04 /* controller in command phase */
251 #define XT_STAT_SELECT 0x08 /* controller is selected */
252 #define XT_STAT_REQUEST 0x10 /* controller requesting data */
253 #define XT_STAT_INTERRUPT 0x20 /* controller requesting interrupt */
254
255 /* XT hard disk controller control bits */
256 #define XT_INT 0x02 /* Interrupt enable */
257 #define XT_DMA_MODE 0x01 /* DMA enable */
258
259 #define XT_UNIT 8
260 #define XT_SECTORS 17 /* hardwired */
261
262 #define XT506_UNIT0 8
263 #define XT506_UNIT1 9
264
265 #define MAX_SCSI_UNITS (8 + 2)
266
267 static struct wd_state *wd_a2091[MAX_DUPLICATE_EXPANSION_BOARDS];
268 static struct wd_state *wd_a2090[MAX_DUPLICATE_EXPANSION_BOARDS];
269 static struct wd_state *wd_a3000;
270 static struct wd_state *wd_gvps1[MAX_DUPLICATE_EXPANSION_BOARDS];
271 static struct wd_state *wd_gvps2[MAX_DUPLICATE_EXPANSION_BOARDS];
272 static struct wd_state *wd_gvps2accel;
273 struct wd_state *wd_cdtv;
274
275 static struct wd_state *scsi_units[MAX_SCSI_UNITS + 1];
276
freencrunit(struct wd_state * wd)277 static void freencrunit(struct wd_state *wd)
278 {
279 if (!wd)
280 return;
281 for (int i = 0; i < MAX_SCSI_UNITS; i++) {
282 if (scsi_units[i] == wd) {
283 scsi_units[i] = NULL;
284 }
285 }
286 scsi_freenative(wd->scsis, MAX_SCSI_UNITS);
287 xfree (wd->rom);
288 wd->rom = NULL;
289 if (wd->self_ptr)
290 *wd->self_ptr = NULL;
291 xfree(wd);
292 }
293
allocscsi(struct wd_state ** wd,struct romconfig * rc,int ch)294 static struct wd_state *allocscsi(struct wd_state **wd, struct romconfig *rc, int ch)
295 {
296 struct wd_state *scsi;
297
298 if (ch < 0) {
299 freencrunit(*wd);
300 *wd = NULL;
301 }
302 if ((*wd) == NULL) {
303 scsi = xcalloc(struct wd_state, 1);
304 for (int i = 0; i < MAX_SCSI_UNITS; i++) {
305 if (scsi_units[i] == NULL) {
306 scsi_units[i] = scsi;
307 if (rc)
308 rc->unitdata = scsi;
309 scsi->rc = rc;
310 scsi->self_ptr = wd;
311 *wd = scsi;
312 return scsi;
313 }
314 }
315 }
316 return *wd;
317 }
318
getscsi(struct romconfig * rc)319 static struct wd_state *getscsi(struct romconfig *rc)
320 {
321 if (rc->unitdata)
322 return (struct wd_state*)rc->unitdata;
323 return NULL;
324 }
325
getscsiboard(uaecptr addr)326 static struct wd_state *getscsiboard(uaecptr addr)
327 {
328 for (int i = 0; scsi_units[i]; i++) {
329 if (!scsi_units[i]->baseaddress)
330 return scsi_units[i];
331 if ((addr & ~scsi_units[i]->board_mask) == scsi_units[i]->baseaddress)
332 return scsi_units[i];
333 }
334 return NULL;
335 }
336
reset_dmac(struct wd_state * wd)337 static void reset_dmac(struct wd_state *wd)
338 {
339 switch (wd->dmac_type)
340 {
341 case GVP_DMAC_S1:
342 case GVP_DMAC_S2:
343 wd->gdmac.cntr = 0;
344 wd->gdmac.dma_on = 0;
345 break;
346 case COMMODORE_SDMAC:
347 case COMMODORE_DMAC:
348 case COMMODORE_8727:
349 wd->cdmac.dmac_dma = 0;
350 wd->cdmac.dmac_istr = 0;
351 wd->cdmac.dmac_cntr = 0;
352 break;
353 }
354 }
355
isirq(struct wd_state * wd)356 static bool isirq(struct wd_state *wd)
357 {
358 if (!wd->enabled)
359 return false;
360 switch (wd->dmac_type)
361 {
362 case GVP_DMAC_S1:
363 if ((wd->gdmac.cntr & 0x80) && (wd->wc.auxstatus & ASR_INT))
364 return true;
365 break;
366 case GVP_DMAC_S2:
367 if (wd->wc.auxstatus & ASR_INT)
368 wd->gdmac.cntr |= 2;
369 if ((wd->gdmac.cntr & (2 | 8)) == (2 | 8))
370 return true;
371 break;
372 case COMMODORE_SDMAC:
373 if (wd->wc.auxstatus & ASR_INT)
374 wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F;
375 else
376 wd->cdmac.dmac_istr &= ~ISTR_INT_F;
377 if ((wd->cdmac.dmac_cntr & SCNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT)))
378 return true;
379 break;
380 case COMMODORE_DMAC:
381 if (wd->cdmac.xt_irq)
382 wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F;
383 else if (wd->wc.auxstatus & ASR_INT)
384 wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F;
385 else
386 wd->cdmac.dmac_istr &= ~ISTR_INT_F;
387 if ((wd->cdmac.dmac_cntr & CNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT)))
388 return true;
389 break;
390 case COMMODORE_8727:
391 if (wd->cdmac.xt_irq)
392 wd->cdmac.dmac_istr |= ISTR_INTS;
393 if (wd->wc.auxstatus & ASR_INT)
394 wd->cdmac.dmac_istr |= ISTR_INTS;
395 if ((wd->cdmac.dmac_cntr & CNTR_INTEN) && (wd->cdmac.dmac_istr & ISTR_INTS))
396 return true;
397 break;
398 }
399 return false;
400 }
401
set_dma_done(struct wd_state * wds)402 static void set_dma_done(struct wd_state *wds)
403 {
404 switch (wds->dmac_type)
405 {
406 case GVP_DMAC_S1:
407 case GVP_DMAC_S2:
408 wds->gdmac.dma_on = -1;
409 break;
410 case COMMODORE_SDMAC:
411 case COMMODORE_DMAC:
412 case COMMODORE_8727:
413 wds->cdmac.dmac_dma = -1;
414 break;
415 }
416 }
417
is_dma_enabled(struct wd_state * wds)418 static bool is_dma_enabled(struct wd_state *wds)
419 {
420 switch (wds->dmac_type)
421 {
422 case GVP_DMAC_S1:
423 return true;
424 case GVP_DMAC_S2:
425 return wds->gdmac.dma_on > 0;
426 case COMMODORE_SDMAC:
427 case COMMODORE_DMAC:
428 case COMMODORE_8727:
429 return wds->cdmac.dmac_dma > 0;
430 }
431 return false;
432 }
433
rethink_a2091(void)434 void rethink_a2091 (void)
435 {
436 for (int i = 0; i < MAX_SCSI_UNITS; i++) {
437 if (scsi_units[i] && isirq(scsi_units[i])) {
438 INTREQ_0(0x8000 | 0x0008);
439 #if A2091_DEBUG > 2 || A3000_DEBUG > 2
440 write_log (_T("Interrupt_RETHINK\n"));
441 #endif
442 }
443 }
444 }
445
dmac_scsi_int(struct wd_state * wd)446 static void dmac_scsi_int(struct wd_state *wd)
447 {
448 if (!wd->enabled)
449 return;
450 if (!(wd->wc.auxstatus & ASR_INT))
451 return;
452 rethink_a2091();
453 }
454
dmac_a2091_xt_int(struct wd_state * wd)455 static void dmac_a2091_xt_int(struct wd_state *wd)
456 {
457 if (!wd->enabled)
458 return;
459 wd->cdmac.xt_irq = true;
460 rethink_a2091();
461 }
462
scsi_dmac_a2091_start_dma(struct wd_state * wd)463 void scsi_dmac_a2091_start_dma (struct wd_state *wd)
464 {
465 #if A3000_DEBUG > 0 || A2091_DEBUG > 0
466 write_log (_T("DMAC DMA started, ADDR=%08X, LEN=%08X words\n"), wd->cdmac.dmac_acr, wd->cdmac.dmac_wtc);
467 #endif
468 wd->cdmac.dmac_dma = 1;
469 }
scsi_dmac_a2091_stop_dma(struct wd_state * wd)470 void scsi_dmac_a2091_stop_dma (struct wd_state *wd)
471 {
472 wd->cdmac.dmac_dma = 0;
473 wd->cdmac.dmac_istr &= ~ISTR_E_INT;
474 }
475
dmac_reset(struct wd_state * wd)476 static void dmac_reset (struct wd_state *wd)
477 {
478 #if WD33C93_DEBUG > 0
479 if (wd->dmac_type == COMMODORE_SDMAC)
480 write_log (_T("A3000 %s SCSI reset\n"), WD33C93);
481 else if (wd->dmac_type == COMMODORE_DMAC)
482 write_log (_T("A2091 %s SCSI reset\n"), WD33C93);
483 #endif
484 }
485
incsasr(struct wd_chip_state * wd,int w)486 static void incsasr (struct wd_chip_state *wd, int w)
487 {
488 if (wd->sasr == WD_AUXILIARY_STATUS || wd->sasr == WD_DATA || wd->sasr == WD_COMMAND)
489 return;
490 if (w && wd->sasr == WD_SCSI_STATUS)
491 return;
492 wd->sasr++;
493 wd->sasr &= 0x1f;
494 }
495
dmac_a2091_cint(struct wd_state * wd)496 static void dmac_a2091_cint (struct wd_state *wd)
497 {
498 wd->cdmac.dmac_istr = 0;
499 rethink_a2091 ();
500 }
501
doscsistatus(struct wd_state * wd,uae_u8 status)502 static void doscsistatus(struct wd_state *wd, uae_u8 status)
503 {
504 wd->wc.wdregs[WD_SCSI_STATUS] = status;
505 wd->wc.auxstatus |= ASR_INT;
506 #if WD33C93_DEBUG > 1
507 write_log (_T("%s STATUS=%02X\n"), WD33C93, status);
508 #endif
509 if (!wd->enabled)
510 return;
511 #ifdef CDTV
512 if (wd->cdtv) {
513 cdtv_scsi_int ();
514 return;
515 }
516 #endif
517 dmac_scsi_int(wd);
518 #if WD33C93_DEBUG > 2
519 write_log (_T("Interrupt\n"));
520 #endif
521 }
522
set_status(struct wd_chip_state * wd,uae_u8 status,int delay)523 static void set_status (struct wd_chip_state *wd, uae_u8 status, int delay)
524 {
525 if (wd->queue_index >= WD_STATUS_QUEUE)
526 return;
527 wd->scsidelay_status[wd->queue_index] = status;
528 wd->scsidelay_irq[wd->queue_index] = delay == 0 ? 1 : (delay <= 2 ? 2 : delay);
529 wd->queue_index++;
530 }
531
set_status(struct wd_chip_state * wd,uae_u8 status)532 static void set_status (struct wd_chip_state *wd, uae_u8 status)
533 {
534 set_status (wd, status, 0);
535 }
536
gettc(struct wd_chip_state * wd)537 static uae_u32 gettc (struct wd_chip_state *wd)
538 {
539 return wd->wdregs[WD_TRANSFER_COUNT_LSB] | (wd->wdregs[WD_TRANSFER_COUNT] << 8) | (wd->wdregs[WD_TRANSFER_COUNT_MSB] << 16);
540 }
settc(struct wd_chip_state * wd,uae_u32 tc)541 static void settc (struct wd_chip_state *wd, uae_u32 tc)
542 {
543 wd->wdregs[WD_TRANSFER_COUNT_LSB] = tc & 0xff;
544 wd->wdregs[WD_TRANSFER_COUNT] = (tc >> 8) & 0xff;
545 wd->wdregs[WD_TRANSFER_COUNT_MSB] = (tc >> 16) & 0xff;
546 }
decreasetc(struct wd_chip_state * wd)547 static bool decreasetc(struct wd_chip_state *wd)
548 {
549 uae_u32 tc = gettc (wd);
550 if (!tc)
551 return true;
552 tc--;
553 settc (wd, tc);
554 return tc == 0;
555 }
556
canwddma(struct wd_state * wds)557 static bool canwddma(struct wd_state *wds)
558 {
559 struct wd_chip_state *wd = &wds->wc;
560 uae_u8 mode = wd->wdregs[WD_CONTROL] >> 5;
561 switch(wds->dmac_type)
562 {
563 case COMMODORE_8727:
564 if (mode != 0 && mode != 4) {
565 write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode);
566 }
567 return mode == 4;
568 case COMMODORE_DMAC:
569 case COMMODORE_SDMAC:
570 case GVP_DMAC_S2:
571 if (mode != 0 && mode != 4 && mode != 1) {
572 write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode);
573 }
574 return mode == 4 || mode == 1;
575 case GVP_DMAC_S1:
576 if (mode != 0 && mode != 2) {
577 write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode);
578 }
579 return mode == 2;
580 default:
581 return false;
582 }
583 }
584
585 #if WD33C93_DEBUG > 0
scsitostring(struct wd_chip_state * wd,struct scsi_data * scsi)586 static TCHAR *scsitostring (struct wd_chip_state *wd, struct scsi_data *scsi)
587 {
588 static TCHAR buf[200];
589 TCHAR *p;
590 int i;
591
592 p = buf;
593 p[0] = 0;
594 for (i = 0; i < scsi->offset && i < sizeof wd->wd_data; i++) {
595 if (i > 0) {
596 _tcscat (p, _T("."));
597 p++;
598 }
599 _stprintf (p, _T("%02X"), wd->wd_data[i]);
600 p += _tcslen (p);
601 }
602 return buf;
603 }
604 #endif
605
setphase(struct wd_chip_state * wd,uae_u8 phase)606 static void setphase(struct wd_chip_state *wd, uae_u8 phase)
607 {
608 wd->wdregs[WD_COMMAND_PHASE] = phase;
609 }
610
dmacheck_a2091(struct wd_state * wd)611 static bool dmacheck_a2091 (struct wd_state *wd)
612 {
613 wd->cdmac.dmac_acr++;
614 if (wd->cdmac.old_dmac && (wd->cdmac.dmac_cntr & CNTR_TCEN)) {
615 if (wd->cdmac.dmac_wtc == 0) {
616 wd->cdmac.dmac_istr |= ISTR_E_INT;
617 return true;
618 } else {
619 if ((wd->cdmac.dmac_acr & 1) == 1)
620 wd->cdmac.dmac_wtc--;
621 }
622 }
623 return false;
624 }
625
dmacheck_a2090(struct wd_state * wd)626 static bool dmacheck_a2090 (struct wd_state *wd)
627 {
628 int dir = wd->cdmac.dmac_acr & 0x00800000;
629 wd->cdmac.dmac_acr &= 0x7fffff;
630 wd->cdmac.dmac_acr++;
631 wd->cdmac.dmac_acr &= 0x7fffff;
632 wd->cdmac.dmac_acr |= dir;
633 wd->cdmac.dmac_wtc--;
634 return wd->cdmac.dmac_wtc == 0;
635 }
636
637
do_dma_commodore_8727(struct wd_state * wd,struct scsi_data * scsi)638 static bool do_dma_commodore_8727(struct wd_state *wd, struct scsi_data *scsi)
639 {
640 int dir = wd->cdmac.dmac_acr & 0x00800000;
641
642 if (scsi->direction < 0) {
643 if (dir) {
644 write_log(_T("8727 mismatched direction!\n"));
645 return false;
646 }
647 #if WD33C93_DEBUG > 0
648 uaecptr odmac_acr = wd->cdmac.dmac_acr;
649 #endif
650 for (;;) {
651 uae_u8 v1 = 0, v2 = 0;
652 int status;
653 status = scsi_receive_data (scsi, &v1, true);
654 if (!status)
655 status = scsi_receive_data(scsi, &v2, true);
656 put_word((wd->cdmac.dmac_acr << 1) & 0xffffff, (v1 << 8) | v2);
657 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) {
658 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v1;
659 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v2;
660 }
661 if (decreasetc (&wd->wc))
662 break;
663 if (decreasetc (&wd->wc))
664 break;
665 if (status)
666 break;
667 if (dmacheck_a2090 (wd))
668 break;
669 }
670 #if WD33C93_DEBUG > 0
671 write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, scsi->offset, scsi->data_len, (odmac_acr << 1) & 0xffffff);
672 #endif
673 return true;
674 } else if (scsi->direction > 0) {
675 if (!dir) {
676 write_log(_T("8727 mismatched direction!\n"));
677 return false;
678 }
679 #if WD33C93_DEBUG > 0
680 uaecptr odmac_acr = wd->cdmac.dmac_acr;
681 #endif
682 for (;;) {
683 int status;
684 uae_u16 v = get_word((wd->cdmac.dmac_acr << 1) & 0xffffff);
685 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) {
686 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v >> 8;
687 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
688 }
689 status = scsi_send_data (scsi, v >> 8);
690 if (!status)
691 status = scsi_send_data (scsi, v);
692 if (decreasetc (&wd->wc))
693 break;
694 if (decreasetc (&wd->wc))
695 break;
696 if (status)
697 break;
698 if (dmacheck_a2090 (wd))
699 break;
700 }
701 #if WD33C93_DEBUG > 0
702 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, (odmac_acr << 1) & 0xffffff);
703 #endif
704 return true;
705 }
706 return false;
707 }
708
do_dma_commodore(struct wd_state * wd,struct scsi_data * scsi)709 static bool do_dma_commodore(struct wd_state *wd, struct scsi_data *scsi)
710 {
711 #ifdef CDTV
712 if (wd->cdtv)
713 cdtv_getdmadata(&wd->cdmac.dmac_acr);
714 #endif
715 if (scsi->direction < 0) {
716 #if WD33C93_DEBUG || XT_DEBUG > 0
717 uaecptr odmac_acr = wd->cdmac.dmac_acr;
718 #endif
719 bool run = true;
720 while (run) {
721 uae_u8 v;
722 int status = scsi_receive_data(scsi, &v, true);
723 put_byte(wd->cdmac.dmac_acr, v);
724 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
725 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
726 if (decreasetc (&wd->wc))
727 run = false;
728 if (dmacheck_a2091 (wd))
729 run = false;
730 if (status)
731 run = false;
732 }
733 #if WD33C93_DEBUG || XT_DEBUG > 0
734 write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr);
735 #endif
736 return true;
737 } else if (scsi->direction > 0) {
738 #if WD33C93_DEBUG || XT_DEBUG > 0
739 uaecptr odmac_acr = wd->cdmac.dmac_acr;
740 #endif
741 bool run = true;
742 while (run) {
743 int status;
744 uae_u8 v = get_byte(wd->cdmac.dmac_acr);
745 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
746 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
747 status = scsi_send_data (scsi, v);
748 if (decreasetc (&wd->wc))
749 run = false;
750 if (dmacheck_a2091 (wd))
751 run = false;
752 if (status)
753 run = false;
754 }
755 #if WD33C93_DEBUG || XT_DEBUG > 0
756 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr);
757 #endif
758 return true;
759 }
760 return false;
761 }
762
do_dma_gvp_s1(struct wd_state * wd,struct scsi_data * scsi)763 static bool do_dma_gvp_s1(struct wd_state *wd, struct scsi_data *scsi)
764 {
765 if (scsi->direction < 0) {
766 for (;;) {
767 uae_u8 v;
768 int status = scsi_receive_data(scsi, &v, true);
769 wd->gdmac.buffer[wd->wc.wd_dataoffset++] = v;
770 wd->wc.wd_dataoffset &= wd->gdmac.s1_rammask;
771 if (decreasetc (&wd->wc))
772 break;
773 if (status)
774 break;
775 }
776 #if WD33C93_DEBUG > 0
777 write_log (_T("%s Done DMA from WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len);
778 #endif
779 return true;
780 } else if (scsi->direction > 0) {
781 for (;;) {
782 int status;
783 uae_u8 v = wd->gdmac.buffer[wd->wc.wd_dataoffset++];
784 wd->wc.wd_dataoffset &= wd->gdmac.s1_rammask;
785 status = scsi_send_data (scsi, v);
786 wd->gdmac.addr++;
787 if (decreasetc (&wd->wc))
788 break;
789 if (status)
790 break;
791 }
792 #if WD33C93_DEBUG > 0
793 write_log (_T("%s Done DMA to WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len);
794 #endif
795 return true;
796 }
797 return false;
798 }
799
800
do_dma_gvp_s2(struct wd_state * wd,struct scsi_data * scsi)801 static bool do_dma_gvp_s2(struct wd_state *wd, struct scsi_data *scsi)
802 {
803 #if WD33C93_DEBUG > 0
804 uae_u32 dmaptr = wd->gdmac.addr;
805 #endif
806 if (!is_dma_enabled(wd))
807 return false;
808
809 if (scsi->direction < 0) {
810 if (wd->gdmac.cntr & 0x10) {
811 write_log(_T("GVP DMA: mismatched direction when reading!\n"));
812 return false;
813 }
814 for (;;) {
815 uae_u8 v;
816 int status = scsi_receive_data(scsi, &v, true);
817 put_byte(wd->gdmac.addr, v);
818 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
819 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
820 wd->gdmac.addr++;
821 if (decreasetc (&wd->wc))
822 break;
823 if (status)
824 break;
825 }
826 #if WD33C93_DEBUG > 0
827 write_log (_T("%s Done DMA from WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, dmaptr);
828 #endif
829 return true;
830 } else if (scsi->direction > 0) {
831 if (!(wd->gdmac.cntr & 0x10)) {
832 write_log(_T("GVP DMA: mismatched direction when writing!\n"));
833 return false;
834 }
835 for (;;) {
836 int status;
837 uae_u8 v = get_byte(wd->gdmac.addr);
838 if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
839 wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
840 status = scsi_send_data (scsi, v);
841 wd->gdmac.addr++;
842 if (decreasetc (&wd->wc))
843 break;
844 if (status)
845 break;
846 }
847 #if WD33C93_DEBUG > 0
848 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, dmaptr);
849 #endif
850 return true;
851 }
852 return false;
853 }
854
do_dma(struct wd_state * wd)855 static bool do_dma(struct wd_state *wd)
856 {
857 struct scsi_data *scsi = wd->wc.scsi;
858 wd->wc.wd_data_avail = 0;
859 if (scsi->direction == 0)
860 write_log (_T("%s DMA but no data!?\n"), WD33C93);
861 switch (wd->dmac_type)
862 {
863 case COMMODORE_DMAC:
864 case COMMODORE_SDMAC:
865 return do_dma_commodore(wd, scsi);
866 case COMMODORE_8727:
867 return do_dma_commodore_8727(wd, scsi);
868 case GVP_DMAC_S2:
869 return do_dma_gvp_s2(wd, scsi);
870 case GVP_DMAC_S1:
871 return do_dma_gvp_s1(wd, scsi);
872 }
873 return false;
874 }
875
wd_do_transfer_out(struct wd_chip_state * wd,struct scsi_data * scsi)876 static bool wd_do_transfer_out (struct wd_chip_state *wd, struct scsi_data *scsi)
877 {
878 #if WD33C93_DEBUG > 0
879 write_log (_T("%s SCSI O [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi));
880 #endif
881 if (wd->wdregs[WD_COMMAND_PHASE] < 0x20) {
882 int msg = wd->wd_data[0];
883 /* message was sent */
884 setphase (wd, 0x20);
885 wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND;
886 scsi->status = 0;
887 scsi_start_transfer (scsi);
888 #if WD33C93_DEBUG > 0
889 write_log (_T("%s SCSI got MESSAGE %02X\n"), WD33C93, msg);
890 #endif
891 scsi->message[0] = msg;
892 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) {
893 #if WD33C93_DEBUG > 0
894 write_log (_T("%s SCSI got COMMAND %02X\n"), WD33C93, wd->wd_data[0]);
895 #endif
896 if (scsi->offset < scsi->data_len) {
897 // data missing, ask for more
898 wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND;
899 setphase (wd, 0x30 + scsi->offset);
900 set_status (wd, wd->wd_phase, 1);
901 return false;
902 }
903 settc (wd, 0);
904 scsi_start_transfer (scsi);
905 scsi_emulate_analyze (scsi);
906 if (scsi->direction > 0) {
907 /* if write command, need to wait for data */
908 if (scsi->data_len <= 0 || scsi->direction == 0) {
909 // Status phase if command didn't return anything and don't want anything
910 wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
911 setphase (wd, 0x46);
912 } else {
913 wd->wd_phase = CSR_XFER_DONE | PHS_DATA_OUT;
914 setphase (wd, 0x45);
915 }
916 } else {
917 scsi_emulate_cmd (scsi);
918 if (wd->scsi->data_len <= 0 || scsi->direction == 0) {
919 // Status phase if command didn't return anything and don't want anything
920 wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
921 setphase (wd, 0x46);
922 } else {
923 wd->wd_phase = CSR_XFER_DONE | PHS_DATA_IN;
924 setphase (wd, 0x45); // just skip all reselection and message stuff for now..
925 }
926 }
927 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x45) {
928 if (wd->scsi->offset < scsi->data_len) {
929 // data missing, ask for more
930 wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
931 set_status (wd, wd->wd_phase, 10);
932 return false;
933 }
934 settc (wd, 0);
935 if (scsi->direction > 0) {
936 /* data was sent */
937 scsi_emulate_cmd (scsi);
938 scsi->data_len = 0;
939 wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
940 }
941 scsi_start_transfer (scsi);
942 setphase (wd, 0x47);
943 }
944 wd->wd_dataoffset = 0;
945 set_status (wd, wd->wd_phase, scsi->direction <= 0 ? 0 : 1);
946 wd->wd_busy = 0;
947 return true;
948 }
949
wd_do_transfer_in(struct wd_chip_state * wd,struct scsi_data * scsi,bool message_in_transfer_info)950 static bool wd_do_transfer_in (struct wd_chip_state *wd, struct scsi_data *scsi, bool message_in_transfer_info)
951 {
952 #if WD33C93_DEBUG > 0
953 write_log (_T("%s SCSI I [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi));
954 #endif
955 wd->wd_dataoffset = 0;
956 if (wd->wdregs[WD_COMMAND_PHASE] >= 0x36 && wd->wdregs[WD_COMMAND_PHASE] < 0x46) {
957 if (scsi->offset < scsi->data_len) {
958 // data missing, ask for more
959 wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
960 set_status(wd, wd->wd_phase, 1);
961 return false;
962 }
963 if (gettc (wd) != 0) {
964 wd->wd_phase = CSR_UNEXP | PHS_STATUS;
965 setphase(wd, 0x46);
966 } else {
967 wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
968 setphase(wd, 0x46);
969 }
970 scsi_start_transfer(scsi);
971 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) {
972 setphase(wd, 0x50);
973 wd->wd_phase = CSR_XFER_DONE | PHS_MESS_IN;
974 scsi_start_transfer(scsi);
975 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) {
976 // was TRANSFER INFO with message phase, wait for Negate ACK
977 if (!message_in_transfer_info) {
978 wd->wd_phase = CSR_DISC;
979 wd->wd_selected = false;
980 scsi_start_transfer(scsi);
981 setphase(wd, 0x60);
982 } else {
983 wd->wd_phase = CSR_MSGIN;
984 }
985 }
986 set_status(wd, wd->wd_phase, 1);
987 scsi->direction = 0;
988 return true;
989 }
990
wd_cmd_sel_xfer(struct wd_chip_state * wd,struct wd_state * wds,bool atn)991 static void wd_cmd_sel_xfer (struct wd_chip_state *wd, struct wd_state *wds, bool atn)
992 {
993 int i, tmp_tc;
994 int delay = 0;
995 struct scsi_data *scsi;
996
997 wd->wd_data_avail = 0;
998 tmp_tc = gettc (wd);
999 scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
1000 if (!scsi) {
1001 set_status (wd, CSR_TIMEOUT, 0);
1002 wd->wdregs[WD_COMMAND_PHASE] = 0x00;
1003 #if WD33C93_DEBUG > 0
1004 write_log (_T("* %s select and transfer%s, ID=%d: No device\n"),
1005 WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7);
1006 #endif
1007 return;
1008 }
1009 if (!wd->wd_selected) {
1010 scsi->message[0] = 0x80;
1011 wd->wd_selected = true;
1012 wd->wdregs[WD_COMMAND_PHASE] = 0x10;
1013 }
1014 #if WD33C93_DEBUG > 0
1015 write_log (_T("* %s select and transfer%s, ID=%d PHASE=%02X TC=%d wddma=%d dmac=%d\n"),
1016 WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7, wd->wdregs[WD_COMMAND_PHASE], tmp_tc, wd->wdregs[WD_CONTROL] >> 5, wds->cdmac.dmac_dma);
1017 #endif
1018 if (wd->wdregs[WD_COMMAND_PHASE] <= 0x30) {
1019 scsi->buffer[0] = 0;
1020 scsi->status = 0;
1021 memcpy (scsi->cmd, &wd->wdregs[3], 16);
1022 scsi->data_len = tmp_tc;
1023 scsi_emulate_analyze (scsi);
1024 settc (wd, scsi->cmd_len);
1025 wd->wd_dataoffset = 0;
1026 scsi_start_transfer (scsi);
1027 scsi->direction = 2;
1028 scsi->data_len = scsi->cmd_len;
1029 for (i = 0; i < gettc (wd); i++) {
1030 uae_u8 b = scsi->cmd[i];
1031 wd->wd_data[i] = b;
1032 scsi_send_data (scsi, b);
1033 wd->wd_dataoffset++;
1034 }
1035 // 0x30 = command phase has started
1036 scsi->data_len = tmp_tc;
1037 #if WD33C93_DEBUG > 0
1038 write_log (_T("%s: Got Command %s, datalen=%d\n"), WD33C93, scsitostring (wd, scsi), scsi->data_len);
1039 #endif
1040 if (!scsi_emulate_analyze (scsi)) {
1041 wd->wdregs[WD_COMMAND_PHASE] = 0x46;
1042 goto end;
1043 }
1044 wd->wdregs[WD_COMMAND_PHASE] = 0x30 + gettc (wd);
1045 settc (wd, 0);
1046 if (scsi->direction <= 0) {
1047 scsi_emulate_cmd (scsi);
1048 }
1049 scsi_start_transfer (scsi);
1050 }
1051
1052 if (wd->wdregs[WD_COMMAND_PHASE] <= 0x41) {
1053 wd->wdregs[WD_COMMAND_PHASE] = 0x44;
1054 #if 0
1055 if (wd->wdregs[WD_CONTROL] & CTL_IDI) {
1056 wd->wd_phase = CSR_DISC;
1057 set_status (wd, wd->wd_phase, delay);
1058 wd->wd_phase = CSR_RESEL;
1059 set_status (wd, wd->wd_phase, delay + 10);
1060 return;
1061 }
1062 #endif
1063 wd->wdregs[WD_COMMAND_PHASE] = 0x44;
1064 }
1065
1066 // target replied or start/continue data phase (if data available)
1067 if (wd->wdregs[WD_COMMAND_PHASE] == 0x44) {
1068 wd->wdregs[WD_COMMAND_PHASE] = 0x45;
1069 }
1070
1071 if (wd->wdregs[WD_COMMAND_PHASE] == 0x45) {
1072 settc (wd, tmp_tc);
1073 wd->wd_dataoffset = 0;
1074 setphase (wd, 0x45);
1075
1076 if (gettc (wd) == 0) {
1077 if (scsi->direction != 0) {
1078 // TC = 0 but we may have data
1079 if (scsi->direction < 0) {
1080 if (scsi->data_len == 0 || scsi->offset >= scsi->data_len) {
1081 // no data, continue normally to status phase
1082 setphase (wd, 0x46);
1083 goto end;
1084 }
1085 }
1086 wd->wd_phase = CSR_UNEXP;
1087 if (scsi->direction < 0)
1088 wd->wd_phase |= PHS_DATA_IN;
1089 else
1090 wd->wd_phase |= PHS_DATA_OUT;
1091 set_status (wd, wd->wd_phase, 1);
1092 return;
1093 }
1094 }
1095
1096 if (wd->scsi->direction) {
1097 // wanted data but nothing available?
1098 if (scsi->direction < 0 && scsi->data_len == 0 && gettc(wd)) {
1099 setphase(wd, 0x46);
1100 wd->wd_phase = CSR_UNEXP | PHS_STATUS;
1101 set_status (wd, wd->wd_phase, 1);
1102 return;
1103 }
1104 if (canwddma (wds)) {
1105 if (scsi->direction <= 0) {
1106 do_dma(wds);
1107 if (scsi->offset < scsi->data_len) {
1108 // buffer not completely retrieved?
1109 wd->wd_phase = CSR_UNEXP | PHS_DATA_IN;
1110 set_status (wd, wd->wd_phase, 1);
1111 return;
1112 }
1113 if (gettc (wd) > 0) {
1114 // requested more data than was available.
1115 setphase(wd, 0x46);
1116 wd->wd_phase = CSR_UNEXP | PHS_STATUS;
1117 set_status (wd, wd->wd_phase, 1);
1118 return;
1119 }
1120 setphase (wd, 0x46);
1121 } else {
1122 if (do_dma(wds)) {
1123 setphase (wd, 0x46);
1124 if (scsi->offset < scsi->data_len) {
1125 // not enough data?
1126 wd->wd_phase = CSR_UNEXP | PHS_DATA_OUT;
1127 set_status (wd, wd->wd_phase, 1);
1128 return;
1129 }
1130 // got all data -> execute it
1131 scsi_emulate_cmd (scsi);
1132 }
1133 }
1134 } else {
1135 // no dma = Service Request
1136 wd->wd_phase = CSR_SRV_REQ;
1137 if (scsi->direction < 0)
1138 wd->wd_phase |= PHS_DATA_IN;
1139 else
1140 wd->wd_phase |= PHS_DATA_OUT;
1141 set_status (wd, wd->wd_phase, 1);
1142 return;
1143 }
1144 } else {
1145 // TC > 0 but no data to transfer
1146 if (gettc (wd)) {
1147 wd->wd_phase = CSR_UNEXP | PHS_STATUS;
1148 set_status (wd, wd->wd_phase, 1);
1149 return;
1150 }
1151 setphase(wd, 0x46);
1152 }
1153 }
1154
1155 end:
1156 if (wd->wdregs[WD_COMMAND_PHASE] == 0x46) {
1157 scsi->buffer[0] = 0;
1158 wd->wdregs[WD_COMMAND_PHASE] = 0x50;
1159 wd->wdregs[WD_TARGET_LUN] = scsi->status;
1160 scsi->buffer[0] = scsi->status;
1161 }
1162
1163 // 0x60 = command complete
1164 wd->wdregs[WD_COMMAND_PHASE] = 0x60;
1165 if (!(wd->wdregs[WD_CONTROL] & CTL_EDI)) {
1166 wd->wd_phase = CSR_SEL_XFER_DONE;
1167 delay += 2;
1168 set_status (wd, wd->wd_phase, delay);
1169 delay += 2;
1170 wd->wd_phase = CSR_DISC;
1171 set_status (wd, wd->wd_phase, delay);
1172 } else {
1173 delay += 2;
1174 wd->wd_phase = CSR_SEL_XFER_DONE;
1175 set_status (wd, wd->wd_phase, delay);
1176 }
1177 wd->wd_selected = 0;
1178 }
1179
wd_cmd_trans_info(struct wd_state * wds,struct scsi_data * scsi,bool pad)1180 static void wd_cmd_trans_info (struct wd_state *wds, struct scsi_data *scsi, bool pad)
1181 {
1182 struct wd_chip_state *wd = &wds->wc;
1183 if (wd->wdregs[WD_COMMAND_PHASE] == 0x20) {
1184 wd->wdregs[WD_COMMAND_PHASE] = 0x30;
1185 scsi->status = 0;
1186 }
1187 wd->wd_busy = 1;
1188 if (wd->wdregs[WD_COMMAND] & 0x80)
1189 settc (wd, 1);
1190 if (gettc (wd) == 0)
1191 settc (wd, 1);
1192 wd->wd_dataoffset = 0;
1193
1194 if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) {
1195 scsi->direction = 2; // command
1196 scsi->cmd_len = scsi->data_len = gettc (wd);
1197 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) {
1198 scsi->direction = 1; // message
1199 scsi->data_len = gettc (wd);
1200 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x45) {
1201 scsi_emulate_analyze (scsi);
1202 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) {
1203 scsi->buffer[0] = scsi->status;
1204 wd->wdregs[WD_TARGET_LUN] = scsi->status;
1205 scsi->direction = -1; // status
1206 scsi->data_len = 1;
1207 } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) {
1208 scsi->direction = -1;
1209 scsi->data_len = gettc (wd);
1210 }
1211
1212 if (pad) {
1213 int v;
1214 settc(wd, 0);
1215 if (wd->scsi->direction < 0) {
1216 v = wd_do_transfer_in (wd, wd->scsi, false);
1217 } else if (wd->scsi->direction > 0) {
1218 v = wd_do_transfer_out (wd, wd->scsi);
1219 }
1220 wd->scsi->direction = 0;
1221 wd->wd_data_avail = 0;
1222 } else {
1223 if (canwddma (wds)) {
1224 wd->wd_data_avail = -1;
1225 } else {
1226 wd->wd_data_avail = 1;
1227 }
1228 }
1229
1230 #if WD33C93_DEBUG > 0
1231 write_log (_T("* %s transfer info phase=%02x TC=%d dir=%d data=%d/%d wddma=%d\n"),
1232 WD33C93, wd->wdregs[WD_COMMAND_PHASE], gettc (wd), scsi->direction, scsi->offset, scsi->data_len, wd->wdregs[WD_CONTROL] >> 5);
1233 #endif
1234
1235 }
1236
1237 /* Weird stuff, XT driver (which has nothing to do with SCSI or WD33C93) uses this WD33C93 command! */
wd_cmd_trans_addr(struct wd_chip_state * wd,struct wd_state * wds)1238 static void wd_cmd_trans_addr(struct wd_chip_state *wd, struct wd_state *wds)
1239 {
1240 uae_u32 tcyls = (wd->wdregs[WD_T_CYLS_0] << 8) | wd->wdregs[WD_T_CYLS_1];
1241 uae_u32 theads = wd->wdregs[WD_T_HEADS];
1242 uae_u32 tsectors = wd->wdregs[WD_T_SECTORS];
1243 uae_u32 lba = (wd->wdregs[WD_L_ADDR_0] << 24) | (wd->wdregs[WD_L_ADDR_1] << 16) |
1244 (wd->wdregs[WD_L_ADDR_2] << 8) | (wd->wdregs[WD_L_ADDR_3] << 0);
1245 uae_u32 cyls, heads, sectors;
1246
1247 cyls = lba / (theads * tsectors);
1248 heads = (lba - ((cyls * theads * tsectors))) / tsectors;
1249 sectors = (lba - ((cyls * theads * tsectors))) % tsectors;
1250
1251 write_log(_T("WD TRANS ADDR: LBA=%d TC=%d TH=%d TS=%d -> C=%d H=%d S=%d\n"), lba, tcyls, theads, tsectors, cyls, heads, sectors);
1252
1253 wd->wdregs[WD_CYL_0] = cyls >> 8;
1254 wd->wdregs[WD_CYL_1] = cyls;
1255 wd->wdregs[WD_HEAD] = heads;
1256 wd->wdregs[WD_SECTOR] = sectors;
1257
1258 if (cyls >= tcyls)
1259 set_status(wd, CSR_BAD_STATUS);
1260 else
1261 set_status(wd, CSR_TRANS_ADDR);
1262 }
1263
wd_cmd_sel(struct wd_chip_state * wd,struct wd_state * wds,bool atn)1264 static void wd_cmd_sel (struct wd_chip_state *wd, struct wd_state *wds, bool atn)
1265 {
1266 struct scsi_data *scsi;
1267 #if WD33C93_DEBUG > 0
1268 write_log (_T("* %s select%s, ID=%d\n"), WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7);
1269 #endif
1270 wd->wd_phase = 0;
1271 wd->wdregs[WD_COMMAND_PHASE] = 0;
1272
1273 scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
1274 if (!scsi || (wd->wdregs[WD_DESTINATION_ID] & 7) == 7) {
1275 #if WD33C93_DEBUG > 0
1276 write_log (_T("%s no drive\n"), WD33C93);
1277 #endif
1278 set_status (wd, CSR_TIMEOUT, 1000);
1279 return;
1280 }
1281 scsi_start_transfer (wd->scsi);
1282 wd->wd_selected = true;
1283 scsi->message[0] = 0x80;
1284 set_status (wd, CSR_SELECT, 2);
1285 if (atn) {
1286 wd->wdregs[WD_COMMAND_PHASE] = 0x10;
1287 set_status (wd, CSR_SRV_REQ | PHS_MESS_OUT, 4);
1288 } else {
1289 wd->wdregs[WD_COMMAND_PHASE] = 0x20;
1290 set_status (wd, CSR_SRV_REQ | PHS_COMMAND, 4);
1291 }
1292 }
1293
wd_cmd_reset(struct wd_chip_state * wd,bool irq)1294 static void wd_cmd_reset (struct wd_chip_state *wd, bool irq)
1295 {
1296 int i;
1297
1298 #if WD33C93_DEBUG > 0
1299 if (irq)
1300 write_log (_T("%s reset\n"), WD33C93);
1301 #endif
1302 for (i = 1; i < 0x16; i++)
1303 wd->wdregs[i] = 0;
1304 wd->wdregs[0x18] = 0;
1305 wd->sasr = 0;
1306 wd->wd_selected = false;
1307 wd->scsi = NULL;
1308 wd->scsidelay_irq[0] = 0;
1309 wd->scsidelay_irq[1] = 0;
1310 wd->queue_index = 0;
1311 wd->auxstatus = 0;
1312 wd->wd_data_avail = 0;
1313 if (irq) {
1314 set_status (wd, (wd->wdregs[0] & 0x08) ? 1 : 0, 50);
1315 }
1316 }
1317
wd_master_reset(struct wd_state * wd,bool irq)1318 static void wd_master_reset(struct wd_state *wd, bool irq)
1319 {
1320 memset(wd->wc.wdregs, 0, sizeof wd->wc.wdregs);
1321 wd_cmd_reset(&wd->wc, false);
1322 if (irq)
1323 doscsistatus(wd, 0);
1324 }
1325
wd_cmd_abort(struct wd_chip_state * wd)1326 static void wd_cmd_abort (struct wd_chip_state *wd)
1327 {
1328 #if WD33C93_DEBUG > 0
1329 write_log (_T("%s abort\n"), WD33C93);
1330 #endif
1331 }
1332
1333 static void xt_command_done(struct wd_state *wd);
1334
wd_check_interrupt(struct wd_state * wds,bool checkonly)1335 static void wd_check_interrupt(struct wd_state *wds, bool checkonly)
1336 {
1337 struct wd_chip_state *wd = &wds->wc;
1338 if (wd->auxstatus & ASR_INT)
1339 return;
1340 if (wd->queue_index == 0)
1341 return;
1342 if (wd->scsidelay_irq[0] == 1) {
1343 wd->scsidelay_irq[0] = 0;
1344 doscsistatus(wds, wd->scsidelay_status[0]);
1345 wd->wd_busy = 0;
1346 if (wd->queue_index == 2) {
1347 wd->scsidelay_irq[0] = 1;
1348 wd->scsidelay_status[0] = wd->scsidelay_status[1];
1349 wd->queue_index = 1;
1350 } else {
1351 wd->queue_index = 0;
1352 }
1353 } else if (!checkonly && wd->scsidelay_irq[0] > 1) {
1354 wd->scsidelay_irq[0]--;
1355 }
1356 }
1357
scsi_hsync_check_dma(struct wd_state * wds)1358 static void scsi_hsync_check_dma(struct wd_state *wds)
1359 {
1360 struct wd_chip_state *wd = &wds->wc;
1361 if (wd->wd_data_avail < 0 && is_dma_enabled(wds)) {
1362 bool v;
1363 do_dma(wds);
1364 if (wd->scsi->direction < 0) {
1365 v = wd_do_transfer_in (wd, wd->scsi, false);
1366 } else if (wd->scsi->direction > 0) {
1367 v = wd_do_transfer_out (wd, wd->scsi);
1368 } else {
1369 write_log (_T("%s data transfer attempt without data!\n"), WD33C93);
1370 v = true;
1371 }
1372 if (v) {
1373 wd->scsi->direction = 0;
1374 wd->wd_data_avail = 0;
1375 } else {
1376 set_dma_done(wds);
1377 }
1378 }
1379 }
1380
scsi_hsync2_a2091(struct wd_state * wds)1381 static void scsi_hsync2_a2091 (struct wd_state *wds)
1382 {
1383 struct wd_chip_state *wd = &wds->wc;
1384
1385 if (!wds || !wds->enabled)
1386 return;
1387 scsi_hsync_check_dma(wds);
1388 if (wds->cdmac.dmac_dma > 0 && (wds->cdmac.xt_control & XT_DMA_MODE) && (wds->cdmac.xt_status & (XT_STAT_INPUT | XT_STAT_REQUEST) && !(wds->cdmac.xt_status & XT_STAT_COMMAND))) {
1389 wd->scsi = wds->scsis[XT_UNIT];
1390 if (do_dma(wds)) {
1391 xt_command_done(wds);
1392 }
1393 }
1394 wd_check_interrupt(wds, false);
1395
1396 }
1397
scsi_hsync2_gvp(struct wd_state * wds)1398 static void scsi_hsync2_gvp (struct wd_state *wds)
1399 {
1400 if (!wds || !wds->enabled)
1401 return;
1402 scsi_hsync_check_dma(wds);
1403 wd_check_interrupt(wds, false);
1404 }
1405
scsi_hsync(void)1406 void scsi_hsync (void)
1407 {
1408 for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
1409 scsi_hsync2_a2091(wd_a2091[i]);
1410 scsi_hsync2_a2091(wd_a2090[i]);
1411 scsi_hsync2_gvp(wd_gvps1[i]);
1412 scsi_hsync2_gvp(wd_gvps2[i]);
1413 }
1414 scsi_hsync2_gvp(wd_gvps2accel);
1415 scsi_hsync2_a2091(wd_a3000);
1416 scsi_hsync2_a2091(wd_cdtv);
1417 }
1418
1419
writeonlyreg(int reg)1420 static int writeonlyreg (int reg)
1421 {
1422 if (reg == WD_SCSI_STATUS)
1423 return 1;
1424 return 0;
1425 }
1426
makecmd(struct scsi_data * s,int msg,uae_u8 cmd)1427 static uae_u32 makecmd (struct scsi_data *s, int msg, uae_u8 cmd)
1428 {
1429 uae_u32 v = 0;
1430 if (s)
1431 v |= s->id << 24;
1432 v |= msg << 8;
1433 v |= cmd;
1434 return v;
1435 }
1436
writewdreg(struct wd_chip_state * wd,int sasr,uae_u8 val)1437 static void writewdreg (struct wd_chip_state *wd, int sasr, uae_u8 val)
1438 {
1439 switch (sasr)
1440 {
1441 case WD_OWN_ID:
1442 if (wd->wd33c93_ver == 0)
1443 val &= ~(0x20 | 0x08);
1444 else if (wd->wd33c93_ver == 1)
1445 val &= ~0x20;
1446 break;
1447 }
1448 if (sasr > WD_QUEUE_TAG && sasr < WD_AUXILIARY_STATUS)
1449 return;
1450 // queue tag is B revision only
1451 if (sasr == WD_QUEUE_TAG && wd->wd33c93_ver < 2)
1452 return;
1453 wd->wdregs[sasr] = val;
1454 }
1455
wdscsi_put(struct wd_chip_state * wd,struct wd_state * wds,uae_u8 d)1456 void wdscsi_put (struct wd_chip_state *wd, struct wd_state *wds, uae_u8 d)
1457 {
1458 #if WD33C93_DEBUG > 1
1459 if (WD33C93_DEBUG > 3 || wd->sasr != WD_DATA)
1460 write_log (_T("W %s REG %02X = %02X (%d) PC=%08X\n"), WD33C93, wd->sasr, d, d, M68K_GETPC);
1461 #endif
1462 if (!writeonlyreg (wd->sasr)) {
1463 writewdreg (wd, wd->sasr, d);
1464 }
1465 if (!wd->wd_used) {
1466 wd->wd_used = 1;
1467 write_log (_T("%s %s in use\n"), wds->bank ? wds->bank->name : _T("built-in"), WD33C93);
1468 }
1469 if (wd->sasr == WD_COMMAND_PHASE) {
1470 #if WD33C93_DEBUG > 1
1471 write_log (_T("%s PHASE=%02X\n"), WD33C93, d);
1472 #endif
1473 ;
1474 } else if (wd->sasr == WD_DATA) {
1475 #if WD33C93_DEBUG_PIO
1476 write_log (_T("%s WD_DATA WRITE %02x %d/%d\n"), WD33C93, d, wd->scsi->offset, wd->scsi->data_len);
1477 #endif
1478 if (!wd->wd_data_avail) {
1479 write_log (_T("%s WD_DATA WRITE without data request!?\n"), WD33C93);
1480 return;
1481 }
1482 if (wd->wd_dataoffset < sizeof wd->wd_data)
1483 wd->wd_data[wd->wd_dataoffset] = wd->wdregs[wd->sasr];
1484 wd->wd_dataoffset++;
1485 decreasetc (wd);
1486 wd->wd_data_avail = 1;
1487 if (scsi_send_data (wd->scsi, wd->wdregs[wd->sasr]) || gettc (wd) == 0) {
1488 wd->wd_data_avail = 0;
1489 write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 2, 0), 1);
1490 }
1491 } else if (wd->sasr == WD_COMMAND) {
1492 wd->wd_busy = true;
1493 write_comm_pipe_u32(&wds->requests, makecmd(wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7], 0, d), 1);
1494 if (wd->scsi && wd->scsi->cd_emu_unit >= 0)
1495 gui_flicker_led (LED_CD, wd->scsi->id, 1);
1496 }
1497 incsasr (wd, 1);
1498 }
1499
wdscsi_sasr(struct wd_chip_state * wd,uae_u8 b)1500 void wdscsi_sasr (struct wd_chip_state *wd, uae_u8 b)
1501 {
1502 wd->sasr = b;
1503 }
wdscsi_getauxstatus(struct wd_chip_state * wd)1504 uae_u8 wdscsi_getauxstatus (struct wd_chip_state *wd)
1505 {
1506 return (wd->auxstatus & ASR_INT) | (wd->wd_busy || wd->wd_data_avail < 0 ? ASR_BSY : 0) | (wd->wd_data_avail != 0 ? ASR_DBR : 0);
1507 }
1508
wdscsi_get(struct wd_chip_state * wd,struct wd_state * wds)1509 uae_u8 wdscsi_get (struct wd_chip_state *wd, struct wd_state *wds)
1510 {
1511 uae_u8 v;
1512 #if WD33C93_DEBUG > 1
1513 uae_u8 osasr = wd->sasr;
1514 #endif
1515
1516 v = wd->wdregs[wd->sasr];
1517 if (wd->sasr == WD_DATA) {
1518 if (!wd->wd_data_avail) {
1519 write_log (_T("%s WD_DATA READ without data request!?\n"), WD33C93);
1520 return 0;
1521 }
1522 int status = scsi_receive_data(wd->scsi, &v, true);
1523 #if WD33C93_DEBUG_PIO
1524 write_log (_T("%s WD_DATA READ %02x %d/%d\n"), WD33C93, v, wd->scsi->offset, wd->scsi->data_len);
1525 #endif
1526 if (wd->wd_dataoffset < sizeof wd->wd_data)
1527 wd->wd_data[wd->wd_dataoffset] = v;
1528 wd->wd_dataoffset++;
1529 decreasetc (wd);
1530 wd->wdregs[wd->sasr] = v;
1531 wd->wd_data_avail = 1;
1532 if (status || gettc (wd) == 0) {
1533 wd->wd_data_avail = 0;
1534 write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 3, 0), 1);
1535 }
1536 } else if (wd->sasr == WD_SCSI_STATUS) {
1537 wd->auxstatus &= ~0x80;
1538 #ifdef CDTV
1539 if (wds->cdtv)
1540 cdtv_scsi_clear_int ();
1541 #endif
1542 wds->cdmac.dmac_istr &= ~ISTR_INTS;
1543 wd_check_interrupt(wds, true);
1544 #if 0
1545 if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) {
1546 wd->wdregs[WD_COMMAND_PHASE] = 0x11;
1547 wd->wd_phase = CSR_SRV_REQ | PHS_MESS_OUT;
1548 set_status (wd, wd->wd_phase, 1);
1549 }
1550 #endif
1551 } else if (wd->sasr == WD_AUXILIARY_STATUS) {
1552 v = wdscsi_getauxstatus (wd);
1553 }
1554 incsasr (wd, 0);
1555 #if WD33C93_DEBUG > 1
1556 if (WD33C93_DEBUG > 3 || osasr != WD_DATA)
1557 write_log (_T("R %s REG %02X = %02X (%d) PC=%08X\n"), WD33C93, osasr, v, v, M68K_GETPC);
1558 #endif
1559 return v;
1560 }
1561
1562 /* A590 XT */
1563
xt_default_geometry(struct wd_state * wds)1564 static void xt_default_geometry(struct wd_state *wds)
1565 {
1566 wds->cdmac.xt_cyls = wds->wc.scsi->hfd->cyls > 1023 ? 1023 : wds->wc.scsi->hfd->cyls;
1567 wds->cdmac.xt_heads = wds->wc.scsi->hfd->heads > 31 ? 31 : wds->wc.scsi->hfd->heads;
1568 wds->cdmac.xt_sectors = wds->wc.scsi->hfd->secspertrack;
1569 write_log(_T("XT Default CHS %d %d %d\n"), wds->cdmac.xt_cyls, wds->cdmac.xt_heads, wds->cdmac.xt_sectors);
1570 }
1571
1572
xt_set_status(struct wd_state * wds,uae_u8 state)1573 static void xt_set_status(struct wd_state *wds, uae_u8 state)
1574 {
1575 wds->cdmac.xt_status = state;
1576 wds->cdmac.xt_status |= XT_STAT_SELECT;
1577 wds->cdmac.xt_status |= XT_STAT_READY;
1578 }
1579
xt_reset(struct wd_state * wds)1580 static void xt_reset(struct wd_state *wds)
1581 {
1582 wds->wc.scsi = wds->scsis[XT_UNIT];
1583 if (!wds->wc.scsi)
1584 return;
1585 wds->cdmac.xt_control = 0;
1586 wds->cdmac.xt_datalen = 0;
1587 wds->cdmac.xt_status = 0;
1588 xt_default_geometry(wds);
1589 write_log(_T("XT reset\n"));
1590 }
1591
xt_command_done(struct wd_state * wds)1592 static void xt_command_done(struct wd_state *wds)
1593 {
1594 struct scsi_data *scsi = wds->scsis[XT_UNIT];
1595 if (scsi->direction > 0) {
1596 if (scsi->cmd[0] == 0x0c) {
1597 xt_default_geometry(wds);
1598 int size = wds->cdmac.xt_cyls * wds->cdmac.xt_heads * wds->cdmac.xt_sectors;
1599 wds->cdmac.xt_heads = scsi->buffer[2] & 0x1f;
1600 wds->cdmac.xt_cyls = (scsi->buffer[0] << 8) | scsi->buffer[1];
1601 wds->cdmac.xt_sectors = size / (wds->cdmac.xt_cyls * wds->cdmac.xt_heads);
1602 write_log(_T("XT_SETPARAM: Cyls=%d Heads=%d Sectors=%d\n"), wds->cdmac.xt_cyls, wds->cdmac.xt_heads, wds->cdmac.xt_sectors);
1603 for (int i = 0; i < 8; i++) {
1604 write_log(_T("%02X "), scsi->buffer[i]);
1605 }
1606 write_log(_T("\n"));
1607 } else {
1608 scsi_emulate_cmd(scsi);
1609 }
1610 }
1611
1612 xt_set_status(wds, XT_STAT_INTERRUPT);
1613 if (wds->cdmac.xt_control & XT_INT)
1614 dmac_a2091_xt_int(wds);
1615 wds->cdmac.xt_datalen = 0;
1616 wds->cdmac.xt_statusbyte = 0;
1617 #if XT_DEBUG > 0
1618 write_log(_T("XT command %02x done\n"), wds->cdmac.xt_cmd[0]);
1619 #endif
1620 }
1621
xt_wait_data(struct wd_state * wds,int len)1622 static void xt_wait_data(struct wd_state *wds, int len)
1623 {
1624 xt_set_status(wds, XT_STAT_REQUEST);
1625 wds->cdmac.xt_offset = 0;
1626 wds->cdmac.xt_datalen = len;
1627 }
1628
xt_command(struct wd_state * wds)1629 static void xt_command(struct wd_state *wds)
1630 {
1631 wds->wc.scsi = wds->scsis[XT_UNIT];
1632 struct scsi_data *scsi = wds->scsis[XT_UNIT];
1633 #if XT_DEBUG > 0
1634 write_log(_T("XT command %02x. DMA=%d\n"), wds->cdmac.xt_cmd[0], (wds->cdmac.xt_control & XT_DMA_MODE) ? 1 : 0);
1635 #endif
1636
1637 memcpy(scsi->cmd, wds->cdmac.xt_cmd, 6);
1638 scsi->data_len = -1;
1639 wds->cdmac.xt_offset = 0;
1640 scsi_emulate_analyze(scsi);
1641 scsi_start_transfer(scsi);
1642 if (scsi->direction > 0) {
1643 xt_set_status(wds, XT_STAT_REQUEST);
1644 } else if (scsi->direction < 0) {
1645 scsi_emulate_cmd(scsi);
1646 xt_set_status(wds, XT_STAT_INPUT);
1647 } else {
1648 xt_command_done(wds);
1649 }
1650 wds->cdmac.xt_datalen = scsi->data_len;
1651 settc(&wds->wc, scsi->data_len);
1652 }
1653
read_xt_reg(struct wd_state * wds,int reg)1654 static uae_u8 read_xt_reg(struct wd_state *wds, int reg)
1655 {
1656 uae_u8 v = 0xff;
1657
1658 wds->wc.scsi = wds->scsis[XT_UNIT];
1659 if (!wds->wc.scsi)
1660 return v;
1661
1662 switch(reg)
1663 {
1664 case XD_DATA:
1665 if (wds->cdmac.xt_status & XT_STAT_INPUT) {
1666 v = wds->wc.scsi->buffer[wds->cdmac.xt_offset];
1667 #if XT_DEBUG > 1
1668 write_log(_T("XT data read %02X (%d/%d)\n"), v, wds->cdmac.xt_offset, wds->cdmac.xt_datalen);
1669 #endif
1670 wds->cdmac.xt_offset++;
1671 if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) {
1672 xt_command_done(wds);
1673 }
1674 } else {
1675 v = wds->cdmac.xt_statusbyte;
1676 #if XT_DEBUG > 1
1677 write_log(_T("XT status byte read %02X\n"), v);
1678 #endif
1679 }
1680 break;
1681 case XD_STATUS:
1682 v = wds->cdmac.xt_status;
1683 break;
1684 case XD_JUMPER:
1685 // 20M: 2 40M: 0, xt.device checks it.
1686 v = wds->wc.scsi->hfd->size >= 41615 * 2 * 512 ? 0 : 2;
1687 break;
1688 case XD_RESERVED:
1689 break;
1690 }
1691 #if XT_DEBUG > 2
1692 write_log(_T("XT read %d: %02X\n"), reg, v);
1693 #endif
1694 return v;
1695 }
1696
write_xt_reg(struct wd_state * wds,int reg,uae_u8 v)1697 static void write_xt_reg(struct wd_state *wds, int reg, uae_u8 v)
1698 {
1699 wds->wc.scsi = wds->scsis[XT_UNIT];
1700 if (!wds->wc.scsi)
1701 return;
1702
1703 #if XT_DEBUG > 2
1704 write_log(_T("XT write %d: %02X\n"), reg, v);
1705 #endif
1706
1707 switch (reg)
1708 {
1709 case XD_DATA:
1710 if (!(wds->cdmac.xt_status & XT_STAT_REQUEST)) {
1711 wds->cdmac.xt_offset = 0;
1712 xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST);
1713 }
1714 if (wds->cdmac.xt_status & XT_STAT_REQUEST) {
1715 if (wds->cdmac.xt_status & XT_STAT_COMMAND) {
1716 #if XT_DEBUG > 1
1717 write_log(_T("XT command write %02X (%d/6)\n"), v, wds->cdmac.xt_offset);
1718 #endif
1719 wds->cdmac.xt_cmd[wds->cdmac.xt_offset++] = v;
1720 xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST);
1721 if (wds->cdmac.xt_offset == 6) {
1722 xt_command(wds);
1723 }
1724 } else {
1725 #if XT_DEBUG > 1
1726 write_log(_T("XT data write %02X (%d/6)\n"), v, wds->cdmac.xt_offset, wds->cdmac.xt_datalen);
1727 #endif
1728 wds->wc.scsi->buffer[wds->cdmac.xt_offset] = v;
1729 wds->cdmac.xt_offset++;
1730 if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) {
1731 xt_command_done(wds);
1732 }
1733 }
1734 #if XT_DEBUG > 1
1735 } else {
1736 write_log(_T("XT data write without REQUEST %02X\n"), v);
1737 #endif
1738 }
1739
1740 break;
1741 case XD_RESET:
1742 xt_reset(wds);
1743 break;
1744 case XD_SELECT:
1745 #if XT_DEBUG > 1
1746 write_log(_T("XT select %02X\n"), v);
1747 #endif
1748 xt_set_status(wds, XT_STAT_SELECT);
1749 break;
1750 case XD_CONTROL:
1751 #if XT_DEBUG > 1
1752 if ((v & XT_DMA_MODE) != (wds->cdmac.xt_control & XT_DMA_MODE))
1753 write_log(_T("XT DMA mode=%d\n"), (v & XT_DMA_MODE) ? 1 : 0);
1754 if ((v & XT_INT) != (wds->cdmac.xt_control & XT_INT))
1755 write_log(_T("XT IRQ mode=%d\n"), (v & XT_INT) ? 1 : 0);
1756 #endif
1757 wds->cdmac.xt_control = v;
1758 wds->cdmac.xt_irq = 0;
1759 break;
1760 }
1761 }
1762
1763 /* 8727 DMAC */
1764
dmac8727_read_pcss(struct wd_state * wd)1765 static uae_u8 dmac8727_read_pcss(struct wd_state *wd)
1766 {
1767 uae_u8 v;
1768 v = wd->cdmac.c8727_pcss;
1769 #if A2091_DEBUG_IO > 0
1770 write_log(_T("dmac8727_read_pcss %02x\n"), v);
1771 #endif
1772 return v;
1773 }
1774
dmac8727_write_pcss(struct wd_state * wd,uae_u8 v)1775 static void dmac8727_write_pcss(struct wd_state *wd, uae_u8 v)
1776 {
1777 wd->cdmac.c8727_pcss = v;
1778 #if A2091_DEBUG_IO > 0
1779 write_log(_T("dmac8727_write_pcss %02x\n"), v);
1780 #endif
1781 }
1782
dmac8727_read_pcsd(struct wd_state * wd)1783 static uae_u8 dmac8727_read_pcsd(struct wd_state *wd)
1784 {
1785 struct commodore_dmac *c = &wd->cdmac;
1786 uae_u8 v = 0;
1787 if (!(c->c8727_pcss & 8)) {
1788 // 0xF7 1111 0111
1789 wd->cdmac.dmac_dma = 1;
1790 }
1791 if (!(c->c8727_pcss & 0x10)) {
1792 // 0xEF 1110 1111
1793 // dma complete, no overflow
1794 v = (1 << 7) | (1 << 5);
1795 }
1796 return v;
1797 }
1798
dmac8727_write_pcsd(struct wd_state * wd,uae_u8 v)1799 static void dmac8727_write_pcsd(struct wd_state *wd, uae_u8 v)
1800 {
1801 struct commodore_dmac *c = &wd->cdmac;
1802
1803 if (!(c->c8727_pcss & 4)) {
1804 // 0xFB 1111 1011
1805 c->dmac_acr &= 0xff00ffff;
1806 c->dmac_acr |= v << 16;
1807 }
1808 if (!(c->c8727_pcss & 2)) {
1809 // 0xFD 1111 1101
1810 c->dmac_acr &= 0xffff00ff;
1811 c->dmac_acr |= v << 8;
1812 }
1813 if (!(c->c8727_pcss & 1)) {
1814 // 0xFE 1111 1110
1815 c->dmac_acr &= 0xffffff00;
1816 c->dmac_acr |= v << 0;
1817 c->dmac_wtc = 65535;
1818 }
1819 #if 0
1820 if (!(c->c8727_pcss & 8)) {
1821 // 0xF7 1111 0111
1822 }
1823 #endif
1824 if (!(c->c8727_pcss & 0x80)) {
1825 c->dmac_dma = 0;
1826 }
1827 #if 0
1828 switch (c->c8727_pcss)
1829 {
1830 case 0x7f:
1831 case 0xff:
1832 c->dmac_dma = 0;
1833 break;
1834 }
1835 #endif
1836 }
1837
dmac8727_cbp(struct wd_state * wd)1838 static void dmac8727_cbp(struct wd_state *wd)
1839 {
1840 struct commodore_dmac *c = &wd->cdmac;
1841
1842 c->c8727_st506_cb >>= 8;
1843 c->c8727_st506_cb |= c->c8727_wrcbp << 8;
1844 }
1845
a2090_st506(struct wd_state * wd,uae_u8 b)1846 static void a2090_st506(struct wd_state *wd, uae_u8 b)
1847 {
1848 uae_u8 cb[16];
1849 if (!b) {
1850 wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS);
1851 return;
1852 }
1853 uaecptr cbp = wd->cdmac.c8727_st506_cb << 9;
1854 if (!valid_address(cbp, 16)) {
1855 write_log(_T("Invalid ST-506 command block address %08x\n"), cbp);
1856 return;
1857 }
1858 for (int i = 0; i < sizeof cb; i++) {
1859 cb[i] = get_byte(cbp + i);
1860 }
1861 int unit = (cb[1] >> 5) & 1;
1862 // new command?
1863 if (cb[12] != 0xff)
1864 return;
1865 uaecptr dmaaddr = (cb[6] << 16) | (cb[7] << 8) | cb[8];
1866 memset(cb + 12, 0, 4);
1867 struct scsi_data *scsi = wd->scsis[XT506_UNIT0 + unit];
1868 if (scsi) {
1869 memcpy(scsi->cmd, cb, 6);
1870 // We handle LUN, not SCSI emulation.
1871 scsi->cmd[1] &= ~0x20;
1872 scsi->cmd_len = 6;
1873 scsi_emulate_analyze(scsi);
1874 if (scsi->direction < 0) {
1875 scsi_emulate_cmd(scsi);
1876 for (int i = 0; i < scsi->data_len; i++) {
1877 put_byte(dmaaddr + i, scsi->buffer[i]);
1878 }
1879 } else {
1880 for (int i = 0; i < scsi->data_len; i++) {
1881 scsi->buffer[i] = get_byte(dmaaddr + i);
1882 }
1883 scsi_emulate_cmd(scsi);
1884 }
1885 if (scsi->status && scsi->sense_len) {
1886 memcpy(cb + 12, scsi->sense, 4);
1887 }
1888 } else {
1889 cb[12] = 0x04; // Drive not ready
1890 cb[13] = cb[1];
1891 cb[14] = cb[2];
1892 cb[15] = cb[3];
1893 }
1894 for (int i = 0; i < sizeof cb; i++) {
1895 put_byte(cbp + i, cb[i]);
1896 }
1897 set_dma_done(wd);
1898 wd->cdmac.xt_irq = true;
1899 }
1900
dmac_a2091_read_word(struct wd_state * wd,uaecptr addr)1901 static uae_u32 dmac_a2091_read_word (struct wd_state *wd, uaecptr addr)
1902 {
1903 uae_u32 v = 0;
1904
1905 if (addr < 0x40)
1906 return (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1];
1907
1908 if (wd->dmac_type == COMMODORE_8727) {
1909
1910 if (addr >= CDMAC_ROM_OFFSET) {
1911 if (wd->rom) {
1912 int off = addr & wd->rom_mask;
1913 return (wd->rom[off] << 8) | wd->rom[off + 1];
1914 }
1915 return 0;
1916 }
1917 switch (addr)
1918 {
1919 case 0x40:
1920 v = 0;
1921 if (wd->cdmac.dmac_istr & ISTR_INTS)
1922 v |= (1 << 7) | (1 << 4);
1923 break;
1924 case 0x42:
1925 v = 0;
1926 if (wd->cdmac.dmac_cntr & CNTR_INTEN)
1927 v |= 1 << 4;
1928 v |= wd->cdmac.c8727_ctl & 0x80;
1929 break;
1930 case 0x60:
1931 v = wdscsi_getauxstatus (&wd->wc);
1932 break;
1933 case 0x62:
1934 v = wdscsi_get (&wd->wc, wd);
1935 break;
1936 case 0x64:
1937 v = dmac8727_read_pcss(wd);
1938 break;
1939 case 0x68:
1940 v = dmac8727_read_pcsd(wd);
1941 break;
1942 }
1943 v <<= 8;
1944 return v;
1945
1946 } else if (wd->dmac_type == COMMODORE_DMAC) {
1947 if (addr >= CDMAC_ROM_OFFSET) {
1948 if (wd->rom) {
1949 int off = addr & wd->rom_mask;
1950 if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET)
1951 wd->rombank = (addr & 0x02) >> 1;
1952 off += wd->rombank * wd->rom_size;
1953 return (wd->rom[off] << 8) | wd->rom[off + 1];
1954 }
1955 return 0;
1956 }
1957
1958 addr &= ~1;
1959 switch (addr)
1960 {
1961 case 0x40:
1962 v = wd->cdmac.dmac_istr;
1963 if ((v & (ISTR_E_INT | ISTR_INTS)) && (wd->cdmac.dmac_cntr & CNTR_INTEN))
1964 v |= ISTR_INT_P;
1965 wd->cdmac.dmac_istr &= ~0xf;
1966 break;
1967 case 0x42:
1968 v = wd->cdmac.dmac_cntr;
1969 break;
1970 case 0x80:
1971 if (wd->cdmac.old_dmac)
1972 v = (wd->cdmac.dmac_wtc >> 16) & 0xffff;
1973 break;
1974 case 0x82:
1975 if (wd->cdmac.old_dmac)
1976 v = wd->cdmac.dmac_wtc & 0xffff;
1977 break;
1978 case 0x90:
1979 v = wdscsi_getauxstatus(&wd->wc);
1980 break;
1981 case 0x92:
1982 v = wdscsi_get(&wd->wc, wd);
1983 break;
1984 case 0xc0:
1985 v = 0xf8 | (1 << 0) | (1 << 1) | (1 << 2); // bits 0-2 = dip-switches
1986 break;
1987 case 0xc2:
1988 case 0xc4:
1989 case 0xc6:
1990 v = 0xffff;
1991 break;
1992 case 0xe0:
1993 if (wd->cdmac.dmac_dma <= 0)
1994 scsi_dmac_a2091_start_dma (wd);
1995 break;
1996 case 0xe2:
1997 scsi_dmac_a2091_stop_dma (wd);
1998 break;
1999 case 0xe4:
2000 dmac_a2091_cint (wd);
2001 break;
2002 case 0xe8:
2003 /* FLUSH (new only) */
2004 if (!wd->cdmac.old_dmac && wd->cdmac.dmac_dma > 0)
2005 wd->cdmac.dmac_istr |= ISTR_FE_FLG;
2006 break;
2007 }
2008 }
2009 #if A2091_DEBUG_IO > 0
2010 write_log (_T("dmac_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
2011 #endif
2012 return v;
2013 }
2014
dmac_a2091_read_byte(struct wd_state * wd,uaecptr addr)2015 static uae_u32 dmac_a2091_read_byte (struct wd_state *wd, uaecptr addr)
2016 {
2017 uae_u32 v = 0;
2018
2019 if (addr < 0x40)
2020 return wd->dmacmemory[addr];
2021
2022 if (wd->dmac_type == COMMODORE_8727) {
2023
2024 if (addr >= DMAC_8727_ROM_VECTOR) {
2025 if (wd->rom) {
2026 int off = addr & wd->rom_mask;
2027 return wd->rom[off];
2028 }
2029 return 0;
2030 }
2031 switch (addr)
2032 {
2033 case 0x40:
2034 v = 0;
2035 if (wd->cdmac.dmac_istr & ISTR_INTS)
2036 v |= (1 << 7) | (1 << 4);
2037 break;
2038 case 0x42:
2039 v = 0;
2040 if (wd->cdmac.dmac_cntr & CNTR_INTEN)
2041 v |= 1 << 4;
2042 v |= wd->cdmac.c8727_ctl & 0x80;
2043 break;
2044 case 0x60:
2045 v = wdscsi_getauxstatus (&wd->wc);
2046 break;
2047 case 0x62:
2048 v = wdscsi_get (&wd->wc, wd);
2049 break;
2050 case 0x64:
2051 v = dmac8727_read_pcss(wd);
2052 break;
2053 case 0x68:
2054 v = dmac8727_read_pcsd(wd);
2055 break;
2056 }
2057
2058 } else if (wd->dmac_type == COMMODORE_DMAC) {
2059 if (addr >= CDMAC_ROM_OFFSET) {
2060 if (wd->rom) {
2061 int off = addr & wd->rom_mask;
2062 if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET)
2063 wd->rombank = (addr & 0x02) >> 1;
2064 off += wd->rombank * wd->rom_size;
2065 return wd->rom[off];
2066 }
2067 return 0;
2068 }
2069
2070 switch (addr)
2071 {
2072 case 0x91:
2073 v = wdscsi_getauxstatus (&wd->wc);
2074 break;
2075 case 0x93:
2076 v = wdscsi_get (&wd->wc, wd);
2077 break;
2078 case 0xa1:
2079 case 0xa3:
2080 case 0xa5:
2081 case 0xa7:
2082 v = read_xt_reg(wd, (addr - 0xa0) / 2);
2083 break;
2084 default:
2085 v = dmac_a2091_read_word (wd, addr);
2086 if (!(addr & 1))
2087 v >>= 8;
2088 break;
2089 }
2090 }
2091 #if A2091_DEBUG_IO > 0
2092 write_log (_T("dmac_bget %04X=%02X PC=%08X\n"), addr, v, M68K_GETPC);
2093 #endif
2094 return v;
2095 }
2096
dmac_a2091_write_word(struct wd_state * wd,uaecptr addr,uae_u32 b)2097 static void dmac_a2091_write_word (struct wd_state *wd, uaecptr addr, uae_u32 b)
2098 {
2099 #if A2091_DEBUG_IO > 0
2100 write_log (_T("dmac_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
2101 #endif
2102
2103 if (addr < 0x40)
2104 return;
2105
2106 if (wd->dmac_type == COMMODORE_8727) {
2107
2108 if (addr >= DMAC_8727_ROM_VECTOR)
2109 return;
2110
2111 b >>= 8;
2112 switch(addr)
2113 {
2114 case 0x40:
2115 break;
2116 case 0x42:
2117 wd->cdmac.dmac_cntr &= ~(CNTR_INTEN | CNTR_PDMD);
2118 if (b & (1 << 4))
2119 wd->cdmac.dmac_cntr |= CNTR_INTEN;
2120 wd->cdmac.c8727_ctl = b;
2121 if (b & 0x80)
2122 dmac8727_cbp(wd);
2123 break;
2124 case 0x50:
2125 // clear interrupt
2126 wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS);
2127 wd->cdmac.xt_irq = false;
2128 wd->cdmac.c8727_wrcbp = b;
2129 break;
2130 case 0x52:
2131 a2090_st506(wd, b);
2132 break;
2133 case 0x60:
2134 wdscsi_sasr (&wd->wc, b);
2135 break;
2136 case 0x62:
2137 wdscsi_put (&wd->wc, wd, b);
2138 break;
2139 case 0x64:
2140 dmac8727_write_pcss(wd, b);
2141 break;
2142 case 0x68:
2143 dmac8727_write_pcsd(wd, b);
2144 break;
2145 }
2146
2147
2148 } else if (wd->dmac_type == COMMODORE_DMAC) {
2149
2150 if (addr >= CDMAC_ROM_OFFSET)
2151 return;
2152
2153 addr &= ~1;
2154 switch (addr)
2155 {
2156 case 0x42:
2157 wd->cdmac.dmac_cntr = b;
2158 if (wd->cdmac.dmac_cntr & CNTR_PREST)
2159 dmac_reset (wd);
2160 break;
2161 case 0x80:
2162 wd->cdmac.dmac_wtc &= 0x0000ffff;
2163 wd->cdmac.dmac_wtc |= b << 16;
2164 break;
2165 case 0x82:
2166 wd->cdmac.dmac_wtc &= 0xffff0000;
2167 wd->cdmac.dmac_wtc |= b & 0xffff;
2168 break;
2169 case 0x84:
2170 wd->cdmac.dmac_acr &= 0x0000ffff;
2171 wd->cdmac.dmac_acr |= b << 16;
2172 break;
2173 case 0x86:
2174 wd->cdmac.dmac_acr &= 0xffff0000;
2175 wd->cdmac.dmac_acr |= b & 0xfffe;
2176 if (wd->cdmac.old_dmac)
2177 wd->cdmac.dmac_acr &= ~3;
2178 break;
2179 case 0x8e:
2180 wd->cdmac.dmac_dawr = b;
2181 break;
2182 case 0x90:
2183 wdscsi_sasr (&wd->wc, b);
2184 break;
2185 case 0x92:
2186 wdscsi_put (&wd->wc, wd, b);
2187 break;
2188 case 0xc2:
2189 case 0xc4:
2190 case 0xc6:
2191 break;
2192 case 0xe0:
2193 if (wd->cdmac.dmac_dma <= 0)
2194 scsi_dmac_a2091_start_dma (wd);
2195 break;
2196 case 0xe2:
2197 scsi_dmac_a2091_stop_dma (wd);
2198 break;
2199 case 0xe4:
2200 dmac_a2091_cint (wd);
2201 break;
2202 case 0xe8:
2203 /* FLUSH */
2204 wd->cdmac.dmac_istr |= ISTR_FE_FLG;
2205 break;
2206 }
2207 }
2208 }
2209
dmac_a2091_write_byte(struct wd_state * wd,uaecptr addr,uae_u32 b)2210 static void dmac_a2091_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b)
2211 {
2212 #if A2091_DEBUG_IO > 0
2213 write_log (_T("dmac_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2214 #endif
2215
2216 if (addr < 0x40)
2217 return;
2218
2219 if (wd->dmac_type == COMMODORE_8727) {
2220
2221 if (addr >= DMAC_8727_ROM_VECTOR)
2222 return;
2223
2224 switch(addr)
2225 {
2226 case 0x40:
2227 break;
2228 case 0x42:
2229 wd->cdmac.dmac_cntr &= ~CNTR_INTEN;
2230 if (b & (1 << 4))
2231 wd->cdmac.dmac_cntr |= CNTR_INTEN;
2232 wd->cdmac.c8727_ctl = b;
2233 if (b & 0x80)
2234 dmac8727_cbp(wd);
2235 break;
2236 case 0x50:
2237 // clear interrupt
2238 wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS);
2239 wd->cdmac.xt_irq = false;
2240 wd->cdmac.c8727_wrcbp = b;
2241 break;
2242 case 0x52:
2243 a2090_st506(wd, b);
2244 break;
2245 case 0x60:
2246 wdscsi_sasr (&wd->wc, b);
2247 break;
2248 case 0x62:
2249 wdscsi_put (&wd->wc, wd, b);
2250 break;
2251 case 0x64:
2252 dmac8727_write_pcss(wd, b);
2253 break;
2254 case 0x68:
2255 dmac8727_write_pcsd(wd, b);
2256 break;
2257 }
2258
2259 } else if (wd->dmac_type == COMMODORE_DMAC) {
2260
2261 if (addr >= CDMAC_ROM_OFFSET)
2262 return;
2263
2264 switch (addr)
2265 {
2266 case 0x91:
2267 wdscsi_sasr (&wd->wc, b);
2268 break;
2269 case 0x93:
2270 wdscsi_put (&wd->wc, wd, b);
2271 break;
2272 case 0xa1:
2273 case 0xa3:
2274 case 0xa5:
2275 case 0xa7:
2276 write_xt_reg(wd, (addr - 0xa0) / 2, b);
2277 break;
2278 default:
2279 if (addr & 1)
2280 dmac_a2091_write_word (wd, addr, b);
2281 else
2282 dmac_a2091_write_word (wd, addr, b << 8);
2283 }
2284 }
2285 }
2286
dmac_a2091_lget(struct wd_state * wd,uaecptr addr)2287 static uae_u32 REGPARAM2 dmac_a2091_lget (struct wd_state *wd, uaecptr addr)
2288 {
2289 uae_u32 v;
2290 addr &= 65535;
2291 v = dmac_a2091_read_word(wd, addr) << 16;
2292 v |= dmac_a2091_read_word(wd, addr + 2) & 0xffff;
2293 return v;
2294 }
2295
dmac_a2091_wget(struct wd_state * wd,uaecptr addr)2296 static uae_u32 REGPARAM2 dmac_a2091_wget(struct wd_state *wd, uaecptr addr)
2297 {
2298 uae_u32 v;
2299 addr &= 65535;
2300 v = dmac_a2091_read_word(wd, addr);
2301 return v;
2302 }
2303
dmac_a2091_bget(struct wd_state * wd,uaecptr addr)2304 static uae_u32 REGPARAM2 dmac_a2091_bget(struct wd_state *wd, uaecptr addr)
2305 {
2306 uae_u32 v;
2307 addr &= 65535;
2308 v = dmac_a2091_read_byte(wd, addr);
2309 return v;
2310 }
2311
dmac_a2091_lput(struct wd_state * wd,uaecptr addr,uae_u32 l)2312 static void REGPARAM2 dmac_a2091_lput(struct wd_state *wd, uaecptr addr, uae_u32 l)
2313 {
2314 addr &= 65535;
2315 dmac_a2091_write_word(wd, addr + 0, l >> 16);
2316 dmac_a2091_write_word(wd, addr + 2, l);
2317 }
2318
dmac_a2091_wput(struct wd_state * wd,uaecptr addr,uae_u32 w)2319 static void REGPARAM2 dmac_a2091_wput(struct wd_state *wd, uaecptr addr, uae_u32 w)
2320 {
2321 addr &= 65535;
2322 dmac_a2091_write_word(wd, addr, w);
2323 }
2324
2325 extern addrbank dmaca2091_bank;
2326
dmac_a2091_bput(struct wd_state * wd,uaecptr addr,uae_u32 b)2327 static void REGPARAM2 dmac_a2091_bput(struct wd_state *wd, uaecptr addr, uae_u32 b)
2328 {
2329 b &= 0xff;
2330 addr &= 65535;
2331 if (wd->autoconfig) {
2332 if (addr == 0x48 && !wd->configured) {
2333 map_banks_z2 (wd->bank, b, 0x10000 >> 16);
2334 wd->baseaddress = b << 16;
2335 wd->configured = 1;
2336 expamem_next (wd->bank, NULL);
2337 return;
2338 }
2339 if (addr == 0x4c && !wd->configured) {
2340 wd->configured = 1;
2341 expamem_shutup(wd->bank);
2342 return;
2343 }
2344 if (!wd->configured)
2345 return;
2346 }
2347 dmac_a2091_write_byte(wd, addr, b);
2348 }
2349
dmac_a2091_wgeti(struct wd_state * wd,uaecptr addr)2350 static uae_u32 REGPARAM2 dmac_a2091_wgeti(struct wd_state *wd, uaecptr addr)
2351 {
2352 uae_u32 v = 0xffff;
2353 addr &= 65535;
2354 if (addr >= CDMAC_ROM_OFFSET)
2355 v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask];
2356 else
2357 write_log(_T("Invalid DMAC instruction access %08x\n"), addr);
2358 return v;
2359 }
dmac_a2091_lgeti(struct wd_state * wd,uaecptr addr)2360 static uae_u32 REGPARAM2 dmac_a2091_lgeti(struct wd_state *wd, uaecptr addr)
2361 {
2362 uae_u32 v;
2363 addr &= 65535;
2364 v = dmac_a2091_wgeti(wd, addr) << 16;
2365 v |= dmac_a2091_wgeti(wd, addr + 2);
2366 return v;
2367 }
2368
dmac_a2091_check(struct wd_state * wd,uaecptr addr,uae_u32 size)2369 static int REGPARAM2 dmac_a2091_check(struct wd_state *wd, uaecptr addr, uae_u32 size)
2370 {
2371 return 1;
2372 }
2373
dmac_a2091_xlate(struct wd_state * wd,uaecptr addr)2374 static uae_u8 *REGPARAM2 dmac_a2091_xlate(struct wd_state *wd, uaecptr addr)
2375 {
2376 addr &= 0xffff;
2377 addr += wd->rombank * wd->rom_size;
2378 if (addr >= 0x8000)
2379 addr = 0x8000;
2380 return wd->rom + addr;
2381 }
2382
dmac_a2091_xlate(uaecptr addr)2383 static uae_u8 *REGPARAM2 dmac_a2091_xlate (uaecptr addr)
2384 {
2385 struct wd_state *wd = getscsiboard(addr);
2386 if (wd)
2387 return dmac_a2091_xlate(wd, addr);
2388 return default_xlate(0);
2389 }
dmac_a2091_check(uaecptr addr,uae_u32 size)2390 static int REGPARAM2 dmac_a2091_check (uaecptr addr, uae_u32 size)
2391 {
2392 struct wd_state *wd = getscsiboard(addr);
2393 if (wd)
2394 return dmac_a2091_check(wd, addr, size);
2395 return 0;
2396 }
dmac_a2091_lgeti(uaecptr addr)2397 static uae_u32 REGPARAM2 dmac_a2091_lgeti (uaecptr addr)
2398 {
2399 struct wd_state *wd = getscsiboard(addr);
2400 if (wd)
2401 return dmac_a2091_lgeti(wd, addr);
2402 return 0;
2403 }
dmac_a2091_wgeti(uaecptr addr)2404 static uae_u32 REGPARAM2 dmac_a2091_wgeti (uaecptr addr)
2405 {
2406 struct wd_state *wd = getscsiboard(addr);
2407 if (wd)
2408 return dmac_a2091_wgeti(wd, addr);
2409 return 0;
2410 }
dmac_a2091_bget(uaecptr addr)2411 static uae_u32 REGPARAM2 dmac_a2091_bget (uaecptr addr)
2412 {
2413 struct wd_state *wd = getscsiboard(addr);
2414 if (wd)
2415 return dmac_a2091_bget(wd, addr);
2416 return 0;
2417 }
dmac_a2091_wget(uaecptr addr)2418 static uae_u32 REGPARAM2 dmac_a2091_wget (uaecptr addr)
2419 {
2420 struct wd_state *wd = getscsiboard(addr);
2421 if (wd)
2422 return dmac_a2091_wget(wd, addr);
2423 return 0;
2424 }
dmac_a2091_lget(uaecptr addr)2425 static uae_u32 REGPARAM2 dmac_a2091_lget (uaecptr addr)
2426 {
2427 struct wd_state *wd = getscsiboard(addr);
2428 if (wd)
2429 return dmac_a2091_lget(wd, addr);
2430 return 0;
2431 }
dmac_a2091_bput(uaecptr addr,uae_u32 b)2432 static void REGPARAM2 dmac_a2091_bput (uaecptr addr, uae_u32 b)
2433 {
2434 struct wd_state *wd = getscsiboard(addr);
2435 if (wd)
2436 dmac_a2091_bput(wd, addr, b);
2437 }
dmac_a2091_wput(uaecptr addr,uae_u32 b)2438 static void REGPARAM2 dmac_a2091_wput (uaecptr addr, uae_u32 b)
2439 {
2440 struct wd_state *wd = getscsiboard(addr);
2441 if (wd)
2442 dmac_a2091_wput(wd, addr, b);
2443 }
dmac_a2091_lput(uaecptr addr,uae_u32 b)2444 static void REGPARAM2 dmac_a2091_lput (uaecptr addr, uae_u32 b)
2445 {
2446 struct wd_state *wd = getscsiboard(addr);
2447 if (wd)
2448 dmac_a2091_lput(wd, addr, b);
2449 }
2450
2451 addrbank dmaca2091_bank = {
2452 dmac_a2091_lget, dmac_a2091_wget, dmac_a2091_bget,
2453 dmac_a2091_lput, dmac_a2091_wput, dmac_a2091_bput,
2454 dmac_a2091_xlate, dmac_a2091_check, NULL, NULL, _T("A2090/A2091/A590"),
2455 dmac_a2091_lgeti, dmac_a2091_wgeti,
2456 ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
2457 };
2458
2459
2460 /* GVP Series I and II */
2461
2462 extern addrbank gvp_bank;
2463
dmac_gvp_read_byte(struct wd_state * wd,uaecptr addr)2464 static uae_u32 dmac_gvp_read_byte(struct wd_state *wd, uaecptr addr)
2465 {
2466 uae_u32 v = 0;
2467
2468 addr &= wd->board_mask;
2469 if (addr < 0x3e) {
2470 v = wd->dmacmemory[addr];
2471 } else if ((addr & 0x8000) == GVP_ROM_OFFSET) {
2472 addr &= 0xffff;
2473 if (wd->gdmac.series2) {
2474 if (addr & 1) {
2475 v = wd->gdmac.version;
2476 } else {
2477 if (wd->rom) {
2478 if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET)
2479 wd->rombank = (addr & 0x02) >> 1;
2480 v = wd->rom[(addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384];
2481 }
2482 }
2483 } else {
2484 if ((addr & 1) && wd->gdmac.use_version) {
2485 v = wd->gdmac.version;
2486 } else if (wd->rom) {
2487 v = wd->rom[addr - GVP_ROM_OFFSET];
2488 }
2489 }
2490 } else if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) {
2491 #if GVP_S1_DEBUG_IO > 1
2492 int off = wd->gdmac.bufoffset;
2493 #endif
2494 v = wd->gdmac.buffer[wd->gdmac.bufoffset++];
2495 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2496 #if GVP_S1_DEBUG_IO > 1
2497 write_log(_T("gvp_s1_bget sram %d %04x\n"), off, v);
2498 #endif
2499 } else if (wd->configured) {
2500 if (wd->gdmac.series2) {
2501 switch (addr)
2502 {
2503 case 0x40:
2504 v = wd->gdmac.cntr >> 8;
2505 break;
2506 case 0x41:
2507 v = wd->gdmac.cntr;
2508 break;
2509 case 0x61: // SASR
2510 v = wdscsi_getauxstatus(&wd->wc);
2511 break;
2512 case 0x63: // SCMD
2513 v = wdscsi_get(&wd->wc, wd);
2514 break;
2515 default:
2516 write_log(_T("gvp_s2_bget_unk %04X PC=%08X\n"), addr, M68K_GETPC);
2517 break;
2518 }
2519 } else {
2520 switch (addr)
2521 {
2522 case 0x3e:
2523 v = (wd->wc.auxstatus & ASR_INT) ? 0x80 : 0x00;
2524 break;
2525 case 0x60: // SASR
2526 v = wdscsi_getauxstatus(&wd->wc);
2527 break;
2528 case 0x62: // SCMD
2529 v = wdscsi_get(&wd->wc, wd);
2530 break;
2531 case 0x68:
2532 v = 0;
2533 break;
2534 default:
2535 write_log(_T("gvp_s1_bget_unk %04X PC=%08X\n"), addr, M68K_GETPC);
2536 break;
2537 }
2538 }
2539 } else {
2540 v = 0xff;
2541 }
2542
2543 #if GVP_S2_DEBUG_IO > 0
2544 write_log(_T("gvp_bget %04X=%02X PC=%08X\n"), addr, v, M68K_GETPC);
2545 #endif
2546
2547 return v;
2548 }
2549
dmac_gvp_read_word(struct wd_state * wd,uaecptr addr)2550 static uae_u32 dmac_gvp_read_word(struct wd_state *wd, uaecptr addr)
2551 {
2552 uae_u32 v = 0;
2553
2554 addr &= wd->board_mask;
2555 if (addr < 0x3e) {
2556 v = (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1];
2557 } else if ((addr & 0x8000) == GVP_ROM_OFFSET) {
2558 addr &= 0xffff;
2559 if (wd->gdmac.series2) {
2560 if (wd->rom) {
2561 if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET)
2562 wd->rombank = (addr & 0x02) >> 1;
2563 v = (wd->rom[(addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384] << 8) | wd->gdmac.version;
2564 } else {
2565 v = wd->gdmac.version;
2566 }
2567 } else {
2568 if (wd->rom) {
2569 v = (wd->rom[addr - GVP_ROM_OFFSET] << 8) | (wd->rom[addr - GVP_ROM_OFFSET + 1]);
2570 }
2571 if (wd->gdmac.use_version) {
2572 v &= 0xff00;
2573 v |= wd->gdmac.version;
2574 }
2575 }
2576 } else if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) {
2577 #if GVP_S1_DEBUG_IO > 1
2578 int off = wd->gdmac.bufoffset;
2579 #endif
2580 v = wd->gdmac.buffer[wd->gdmac.bufoffset++] << 8;
2581 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2582 v |= wd->gdmac.buffer[wd->gdmac.bufoffset++] << 0;
2583 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2584 #if GVP_S1_DEBUG_IO > 1
2585 write_log(_T("gvp_s1_wget sram %d %04x\n"), off, v);
2586 #endif
2587 } else if (wd->configured) {
2588 if (wd->gdmac.series2) {
2589 switch (addr)
2590 {
2591 case 0x40:
2592 v = wd->gdmac.cntr;
2593 break;
2594 case 0x68:
2595 v = wd->gdmac.bank;
2596 break;
2597 case 0x70:
2598 v = wd->gdmac.addr >> 16;
2599 break;
2600 case 0x72:
2601 v = wd->gdmac.addr;
2602 break;
2603 default:
2604 write_log(_T("gvp_s2_wget_unk %04X PC=%08X\n"), addr, M68K_GETPC);
2605 break;
2606 }
2607 #if GVP_S2_DEBUG_IO > 0
2608 write_log(_T("gvp_s2_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
2609 #endif
2610 } else {
2611
2612 v = dmac_gvp_read_byte(wd, addr) << 8;
2613 v |= dmac_gvp_read_byte(wd, addr + 1);
2614
2615 #if GVP_S1_DEBUG_IO > 0
2616 write_log(_T("gvp_s1_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
2617 #endif
2618 }
2619 } else {
2620 v = 0xffff;
2621 }
2622
2623 return v;
2624 }
2625
dmac_gvp_write_byte(struct wd_state * wd,uaecptr addr,uae_u32 b)2626 static void dmac_gvp_write_byte(struct wd_state *wd, uaecptr addr, uae_u32 b)
2627 {
2628 addr &= wd->board_mask;
2629
2630 if (addr >= GVP_ROM_OFFSET)
2631 return;
2632
2633 if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) {
2634 #if GVP_S1_DEBUG_IO > 1
2635 int off = wd->gdmac.bufoffset;
2636 #endif
2637 if (!(addr & GVP_ROM_OFFSET)) {
2638 wd->gdmac.buffer[wd->gdmac.bufoffset++] = b;
2639 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2640 }
2641 #if GVP_S1_DEBUG_IO > 1
2642 write_log(_T("gvp_s1_bput sram %d %04x\n"), off, b);
2643 #endif
2644 return;
2645 }
2646
2647 if (wd->gdmac.series2) {
2648 #if GVP_S2_DEBUG_IO > 0
2649 write_log(_T("gvp_s2_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2650 #endif
2651 switch (addr)
2652 {
2653 case 0x40:
2654 wd->gdmac.cntr &= 0x00ff;
2655 wd->gdmac.cntr |= b << 8;
2656 break;
2657 case 0x41:
2658 b &= ~(1 | 2);
2659 wd->gdmac.cntr &= 0xff00;
2660 wd->gdmac.cntr |= b << 0;
2661 break;
2662 case 0x61: // SASR
2663 wdscsi_sasr(&wd->wc, b);
2664 break;
2665 case 0x63: // SCMD
2666 wdscsi_put(&wd->wc, wd, b);
2667 break;
2668
2669 case 0x74: // "secret1"
2670 case 0x75:
2671 case 0x7a: // "secret2"
2672 case 0x7b:
2673 case 0x7c: // "secret3"
2674 case 0x7d:
2675 write_log(_T("gvp_s2_bput_config %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2676 break;
2677 default:
2678 write_log(_T("gvp_s2_bput_unk %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2679 break;
2680 }
2681 } else {
2682 #if GVP_S1_DEBUG_IO > 0
2683 write_log(_T("gvp_s1_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2684 #endif
2685 switch (addr)
2686 {
2687 case 0x60: // SASR
2688 wdscsi_sasr(&wd->wc, b);
2689 break;
2690 case 0x62: // SCMD
2691 wdscsi_put(&wd->wc, wd, b);
2692 break;
2693
2694 // 68:
2695 // 00 CPU SRAM access
2696 // ff WD SRAM access
2697
2698 // 6c:
2699 // 28 0010 startup reset?
2700 // b8 1011 before CPU reading from SRAM
2701 // a8 1100 before CPU writing to SRAM
2702 // e8 1110 before starting WD write DMA
2703 // f8 1111 access done/start WD read DMA
2704 // 08 = intena?
2705
2706 case 0x68:
2707 #if GVP_S1_DEBUG_IO > 0
2708 write_log(_T("gvp_s1_bput_s1 %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2709 #endif
2710 wd->gdmac.bufoffset = 0;
2711 break;
2712 case 0x6c:
2713 #if GVP_S1_DEBUG_IO > 0
2714 write_log(_T("gvp_s1_bput_s1 %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2715 #endif
2716 if (!(wd->gdmac.cntr & 8) && (b & 8))
2717 wd_master_reset(wd, true);
2718 wd->gdmac.cntr = b;
2719 break;
2720
2721 default:
2722 write_log(_T("gvp_s1_bput_unk %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
2723 break;
2724 }
2725 }
2726
2727 }
2728
dmac_gvp_write_word(struct wd_state * wd,uaecptr addr,uae_u32 b)2729 static void dmac_gvp_write_word(struct wd_state *wd, uaecptr addr, uae_u32 b)
2730 {
2731 addr &= wd->board_mask;
2732
2733 if (addr >= GVP_ROM_OFFSET && addr < 65536)
2734 return;
2735
2736 if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) {
2737 #if GVP_S1_DEBUG_IO > 1
2738 int off = wd->gdmac.bufoffset;
2739 #endif
2740 if (!(addr & GVP_ROM_OFFSET)) {
2741 wd->gdmac.buffer[wd->gdmac.bufoffset++] = b >> 8;
2742 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2743 wd->gdmac.buffer[wd->gdmac.bufoffset++] = b;
2744 wd->gdmac.bufoffset &= wd->gdmac.s1_rammask;
2745 }
2746 #if GVP_S1_DEBUG_IO > 1
2747 write_log(_T("gvp_s1_wput sram %d %04x\n"), off, b);
2748 #endif
2749 return;
2750 }
2751
2752 if (wd->gdmac.series2) {
2753 #if GVP_S2_DEBUG_IO > 0
2754 write_log(_T("gvp_s2_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
2755 #endif
2756 switch (addr)
2757 {
2758 case 0x40:
2759 b &= ~(1 | 2);
2760 wd->gdmac.cntr = b;
2761 break;
2762 case 0x68: // bank
2763 if (b != 0)
2764 write_log(_T("bank %02x\n"), b);
2765 break;
2766 case 0x70: // ACR
2767 wd->gdmac.addr &= 0x0000ffff;
2768 wd->gdmac.addr |= (b & 0xff) << 16;
2769 wd->gdmac.addr &= wd->gdmac.addr_mask;
2770 break;
2771 case 0x72: // ACR
2772 wd->gdmac.addr &= 0xffff0000;
2773 wd->gdmac.addr |= b;
2774 wd->gdmac.addr &= wd->gdmac.addr_mask;
2775 break;
2776 case 0x76: // START DMA
2777 wd->gdmac.dma_on = 1;
2778 break;
2779 case 0x78: // STOP DMA
2780 wd->gdmac.dma_on = 0;
2781 break;
2782 case 0x74: // "secret1"
2783 case 0x7a: // "secret2"
2784 case 0x7c: // "secret3"
2785 write_log(_T("gvp_s2_wput_config %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
2786 break;
2787 default:
2788 write_log(_T("gvp_s2_wput_unk %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
2789 break;
2790 }
2791
2792 } else {
2793
2794 dmac_gvp_write_byte(wd, addr, b >> 8);
2795 dmac_gvp_write_byte(wd, addr + 1, b);
2796
2797 #if GVP_S1_DEBUG_IO > 0
2798 write_log(_T("gvp_s1_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
2799 #endif
2800 }
2801 }
2802
dmac_gvp_lget(struct wd_state * wd,uaecptr addr)2803 static uae_u32 REGPARAM2 dmac_gvp_lget(struct wd_state *wd, uaecptr addr)
2804 {
2805 uae_u32 v;
2806 addr &= wd->board_mask;
2807 v = dmac_gvp_read_word(wd, addr) << 16;
2808 v |= dmac_gvp_read_word(wd, addr + 2) & 0xffff;
2809 return v;
2810 }
2811
dmac_gvp_wget(struct wd_state * wd,uaecptr addr)2812 static uae_u32 REGPARAM2 dmac_gvp_wget(struct wd_state *wd, uaecptr addr)
2813 {
2814 uae_u32 v;
2815 addr &= wd->board_mask;
2816 v = dmac_gvp_read_word(wd, addr);
2817 return v;
2818 }
2819
dmac_gvp_bget(struct wd_state * wd,uaecptr addr)2820 static uae_u32 REGPARAM2 dmac_gvp_bget(struct wd_state *wd, uaecptr addr)
2821 {
2822 uae_u32 v;
2823 addr &= wd->board_mask;
2824 v = dmac_gvp_read_byte(wd, addr);
2825 return v;
2826 }
2827
dmac_gvp_lput(struct wd_state * wd,uaecptr addr,uae_u32 l)2828 static void REGPARAM2 dmac_gvp_lput(struct wd_state *wd, uaecptr addr, uae_u32 l)
2829 {
2830 addr &= wd->board_mask;
2831 dmac_gvp_write_word(wd, addr + 0, l >> 16);
2832 dmac_gvp_write_word(wd, addr + 2, l);
2833 }
2834
dmac_gvp_wput(struct wd_state * wd,uaecptr addr,uae_u32 w)2835 static void REGPARAM2 dmac_gvp_wput(struct wd_state *wd, uaecptr addr, uae_u32 w)
2836 {
2837 addr &= wd->board_mask;
2838 dmac_gvp_write_word(wd, addr, w);
2839 }
dmac_gvp_bput(struct wd_state * wd,uaecptr addr,uae_u32 b)2840 static void REGPARAM2 dmac_gvp_bput(struct wd_state *wd, uaecptr addr, uae_u32 b)
2841 {
2842 b &= 0xff;
2843 addr &= wd->board_mask;
2844 if (wd->autoconfig) {
2845 if (addr == 0x48 && !wd->configured) {
2846 map_banks_z2(wd->bank, b, (wd->board_mask + 1) >> 16);
2847 wd->baseaddress = b << 16;
2848 wd->configured = 1;
2849 expamem_next(wd->bank, NULL);
2850 return;
2851 }
2852 if (addr == 0x4c && !wd->configured) {
2853 wd->configured = 1;
2854 expamem_shutup(wd->bank);
2855 return;
2856 }
2857 if (!wd->configured)
2858 return;
2859 }
2860 dmac_gvp_write_byte(wd, addr, b);
2861 }
2862
dmac_gvp_wgeti(struct wd_state * wd,uaecptr addr)2863 static uae_u32 REGPARAM2 dmac_gvp_wgeti(struct wd_state *wd, uaecptr addr)
2864 {
2865 uae_u32 v = 0xffff;
2866 addr &= wd->board_mask;
2867 if (addr >= GVP_ROM_OFFSET) {
2868 addr -= GVP_ROM_OFFSET;
2869 v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask];
2870 } else {
2871 write_log(_T("Invalid GVP instruction access %08x\n"), addr);
2872 }
2873 return v;
2874 }
dmac_gvp_lgeti(struct wd_state * wd,uaecptr addr)2875 static uae_u32 REGPARAM2 dmac_gvp_lgeti(struct wd_state *wd, uaecptr addr)
2876 {
2877 uae_u32 v;
2878 addr &= wd->board_mask;
2879 v = dmac_gvp_wgeti(wd, addr) << 16;
2880 v |= dmac_gvp_wgeti(wd, addr + 2);
2881 return v;
2882 }
2883
dmac_gvp_bput(uaecptr addr,uae_u32 b)2884 static void REGPARAM2 dmac_gvp_bput (uaecptr addr, uae_u32 b)
2885 {
2886 struct wd_state *wd = getscsiboard(addr);
2887 if (wd)
2888 dmac_gvp_bput(wd, addr, b);
2889 }
dmac_gvp_wput(uaecptr addr,uae_u32 b)2890 static void REGPARAM2 dmac_gvp_wput (uaecptr addr, uae_u32 b)
2891 {
2892 struct wd_state *wd = getscsiboard(addr);
2893 if (wd)
2894 dmac_gvp_wput(wd, addr, b);
2895 }
dmac_gvp_lput(uaecptr addr,uae_u32 b)2896 static void REGPARAM2 dmac_gvp_lput (uaecptr addr, uae_u32 b)
2897 {
2898 struct wd_state *wd = getscsiboard(addr);
2899 if (wd)
2900 dmac_gvp_lput(wd, addr, b);
2901 }
dmac_gvp_bget(uaecptr addr)2902 static uae_u32 REGPARAM2 dmac_gvp_bget (uaecptr addr)
2903 {
2904 struct wd_state *wd = getscsiboard(addr);
2905 if (wd)
2906 return dmac_gvp_bget(wd, addr);
2907 return 0;
2908 }
dmac_gvp_wget(uaecptr addr)2909 static uae_u32 REGPARAM2 dmac_gvp_wget (uaecptr addr)
2910 {
2911 struct wd_state *wd = getscsiboard(addr);
2912 if (wd)
2913 return dmac_gvp_wget(wd, addr);
2914 return 0;
2915 }
dmac_gvp_lget(uaecptr addr)2916 static uae_u32 REGPARAM2 dmac_gvp_lget (uaecptr addr)
2917 {
2918 struct wd_state *wd = getscsiboard(addr);
2919 if (wd)
2920 return dmac_gvp_lget(wd, addr);
2921 return 0;
2922 }
dmac_gvp_wgeti(uaecptr addr)2923 static uae_u32 REGPARAM2 dmac_gvp_wgeti (uaecptr addr)
2924 {
2925 struct wd_state *wd = getscsiboard(addr);
2926 if (wd)
2927 return dmac_gvp_wgeti(wd, addr);
2928 return 0;
2929 }
dmac_gvp_lgeti(uaecptr addr)2930 static uae_u32 REGPARAM2 dmac_gvp_lgeti (uaecptr addr)
2931 {
2932 struct wd_state *wd = getscsiboard(addr);
2933 if (wd)
2934 return dmac_gvp_lgeti(wd, addr);
2935 return 0;
2936 }
dmac_gvp_check(uaecptr addr,uae_u32 size)2937 static int REGPARAM2 dmac_gvp_check(uaecptr addr, uae_u32 size)
2938 {
2939 struct wd_state *wd = getscsiboard(addr);
2940 return wd ? 1 : 0;
2941 }
dmac_gvp_xlate(uaecptr addr)2942 static uae_u8 *REGPARAM2 dmac_gvp_xlate(uaecptr addr)
2943 {
2944 struct wd_state *wd = getscsiboard(addr);
2945 if (!wd)
2946 return default_xlate(0);
2947 addr &= 0xffff;
2948 return wd->rom + addr;
2949 }
2950 addrbank gvp_bank = {
2951 dmac_gvp_lget, dmac_gvp_wget, dmac_gvp_bget,
2952 dmac_gvp_lput, dmac_gvp_wput, dmac_gvp_bput,
2953 dmac_gvp_xlate, dmac_gvp_check, NULL, NULL, _T("GVP"),
2954 dmac_gvp_lgeti, dmac_gvp_wgeti,
2955 ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
2956 };
2957
2958 /* SUPERDMAC (A3000 mainboard built-in) */
2959
mbdmac_write_word(struct wd_state * wd,uae_u32 addr,uae_u32 val)2960 static void mbdmac_write_word (struct wd_state *wd, uae_u32 addr, uae_u32 val)
2961 {
2962 #if A3000_DEBUG_IO > 1
2963 write_log (_T("DMAC_WWRITE %08X=%04X PC=%08X\n"), addr, val & 0xffff, M68K_GETPC);
2964 #endif
2965 addr &= 0xfffe;
2966 switch (addr)
2967 {
2968 case 0x02:
2969 wd->cdmac.dmac_dawr = val;
2970 break;
2971 case 0x04:
2972 wd->cdmac.dmac_wtc &= 0x0000ffff;
2973 wd->cdmac.dmac_wtc |= val << 16;
2974 break;
2975 case 0x06:
2976 wd->cdmac.dmac_wtc &= 0xffff0000;
2977 wd->cdmac.dmac_wtc |= val & 0xffff;
2978 break;
2979 case 0x0a:
2980 wd->cdmac.dmac_cntr = val;
2981 if (wd->cdmac.dmac_cntr & SCNTR_PREST)
2982 dmac_reset (wd);
2983 break;
2984 case 0x0c:
2985 wd->cdmac.dmac_acr &= 0x0000ffff;
2986 wd->cdmac.dmac_acr |= val << 16;
2987 break;
2988 case 0x0e:
2989 wd->cdmac.dmac_acr &= 0xffff0000;
2990 wd->cdmac.dmac_acr |= val & 0xfffe;
2991 break;
2992 case 0x12:
2993 if (wd->cdmac.dmac_dma <= 0)
2994 scsi_dmac_a2091_start_dma (wd);
2995 break;
2996 case 0x16:
2997 if (wd->cdmac.dmac_dma) {
2998 /* FLUSH */
2999 wd->cdmac.dmac_istr |= ISTR_FE_FLG;
3000 wd->cdmac.dmac_dma = 0;
3001 }
3002 break;
3003 case 0x1a:
3004 dmac_a2091_cint(wd);
3005 break;
3006 case 0x1e:
3007 /* ISTR */
3008 break;
3009 case 0x3e:
3010 scsi_dmac_a2091_stop_dma (wd);
3011 break;
3012 case 0x40:
3013 case 0x48:
3014 wdscsi_sasr(&wd->wc, val);
3015 break;
3016 case 0x42:
3017 case 0x46:
3018 wdscsi_put(&wd->wc, wd, val);
3019 break;
3020 }
3021 }
3022
mbdmac_write_byte(struct wd_state * wd,uae_u32 addr,uae_u32 val)3023 static void mbdmac_write_byte (struct wd_state *wd, uae_u32 addr, uae_u32 val)
3024 {
3025 #if A3000_DEBUG_IO > 1
3026 write_log (_T("DMAC_BWRITE %08X=%02X PC=%08X\n"), addr, val & 0xff, M68K_GETPC);
3027 #endif
3028 addr &= 0xffff;
3029 switch (addr)
3030 {
3031
3032 case 0x41:
3033 case 0x49:
3034 wdscsi_sasr(&wd->wc, val);
3035 break;
3036 case 0x43:
3037 case 0x47:
3038 wdscsi_put (&wd->wc, wd, val);
3039 break;
3040 default:
3041 if (addr & 1)
3042 mbdmac_write_word (wd, addr, val);
3043 else
3044 mbdmac_write_word (wd, addr, val << 8);
3045 }
3046 }
3047
mbdmac_read_word(struct wd_state * wd,uae_u32 addr)3048 static uae_u32 mbdmac_read_word (struct wd_state *wd, uae_u32 addr)
3049 {
3050 #if A3000_DEBUG_IO > 1
3051 uae_u32 vaddr = addr;
3052 #endif
3053 uae_u32 v = 0xffffffff;
3054
3055 addr &= 0xfffe;
3056 switch (addr)
3057 {
3058 case 0x02:
3059 v = wd->cdmac.dmac_dawr;
3060 break;
3061 case 0x04:
3062 case 0x06:
3063 v = 0xffff;
3064 break;
3065 case 0x0a:
3066 v = wd->cdmac.dmac_cntr;
3067 break;
3068 case 0x0c:
3069 v = wd->cdmac.dmac_acr >> 16;
3070 break;
3071 case 0x0e:
3072 v = wd->cdmac.dmac_acr;
3073 break;
3074 case 0x12:
3075 if (wd->cdmac.dmac_dma <= 0)
3076 scsi_dmac_a2091_start_dma (wd);
3077 v = 0;
3078 break;
3079 case 0x1a:
3080 dmac_a2091_cint (wd);
3081 v = 0;
3082 break;;
3083 case 0x1e:
3084 v = wd->cdmac.dmac_istr;
3085 if (v & ISTR_INTS)
3086 v |= ISTR_INT_P;
3087 wd->cdmac.dmac_istr &= ~15;
3088 if (!wd->cdmac.dmac_dma)
3089 v |= ISTR_FE_FLG;
3090 break;
3091 case 0x3e:
3092 if (wd->cdmac.dmac_dma) {
3093 scsi_dmac_a2091_stop_dma (wd);
3094 wd->cdmac.dmac_istr |= ISTR_FE_FLG;
3095 }
3096 v = 0;
3097 break;
3098 case 0x40:
3099 case 0x48:
3100 v = wdscsi_getauxstatus(&wd->wc);
3101 break;
3102 case 0x42:
3103 case 0x46:
3104 v = wdscsi_get(&wd->wc, wd);
3105 break;
3106 }
3107 #if A3000_DEBUG_IO > 1
3108 write_log (_T("DMAC_WREAD %08X=%04X PC=%X\n"), vaddr, v & 0xffff, M68K_GETPC);
3109 #endif
3110 return v;
3111 }
3112
mbdmac_read_byte(struct wd_state * wd,uae_u32 addr)3113 static uae_u32 mbdmac_read_byte (struct wd_state *wd, uae_u32 addr)
3114 {
3115 #if A3000_DEBUG_IO > 1
3116 uae_u32 vaddr = addr;
3117 #endif
3118 uae_u32 v = 0xffffffff;
3119
3120 addr &= 0xffff;
3121 switch (addr)
3122 {
3123 case 0x41:
3124 case 0x49:
3125 v = wdscsi_getauxstatus (&wd->wc);
3126 break;
3127 case 0x43:
3128 case 0x47:
3129 v = wdscsi_get (&wd->wc, wd);
3130 break;
3131 default:
3132 v = mbdmac_read_word (wd, addr);
3133 if (!(addr & 1))
3134 v >>= 8;
3135 break;
3136 }
3137 #if A3000_DEBUG_IO > 1
3138 write_log (_T("DMAC_BREAD %08X=%02X PC=%X\n"), vaddr, v & 0xff, M68K_GETPC);
3139 #endif
3140 return v;
3141 }
3142
3143
3144 static uae_u32 REGPARAM3 mbdmac_lget (uaecptr) REGPARAM;
3145 static uae_u32 REGPARAM3 mbdmac_wget (uaecptr) REGPARAM;
3146 static uae_u32 REGPARAM3 mbdmac_bget (uaecptr) REGPARAM;
3147 static void REGPARAM3 mbdmac_lput (uaecptr, uae_u32) REGPARAM;
3148 static void REGPARAM3 mbdmac_wput (uaecptr, uae_u32) REGPARAM;
3149 static void REGPARAM3 mbdmac_bput (uaecptr, uae_u32) REGPARAM;
3150
mbdmac_lget(uaecptr addr)3151 static uae_u32 REGPARAM2 mbdmac_lget (uaecptr addr)
3152 {
3153 uae_u32 v;
3154 v = mbdmac_read_word (wd_a3000, addr + 0) << 16;
3155 v |= mbdmac_read_word (wd_a3000, addr + 2) << 0;
3156 return v;
3157 }
mbdmac_wget(uaecptr addr)3158 static uae_u32 REGPARAM2 mbdmac_wget (uaecptr addr)
3159 {
3160 uae_u32 v;
3161 v = mbdmac_read_word (wd_a3000, addr);
3162 return v;
3163 }
mbdmac_bget(uaecptr addr)3164 static uae_u32 REGPARAM2 mbdmac_bget (uaecptr addr)
3165 {
3166 return mbdmac_read_byte (wd_a3000, addr);
3167 }
mbdmac_lput(uaecptr addr,uae_u32 l)3168 static void REGPARAM2 mbdmac_lput (uaecptr addr, uae_u32 l)
3169 {
3170 if ((addr & 0xffff) == 0x40) {
3171 // long write to 0x40 = write byte to SASR
3172 mbdmac_write_byte (wd_a3000, 0x41, l);
3173 } else {
3174 mbdmac_write_word (wd_a3000, addr + 0, l >> 16);
3175 mbdmac_write_word (wd_a3000, addr + 2, l >> 0);
3176 }
3177 }
mbdmac_wput(uaecptr addr,uae_u32 w)3178 static void REGPARAM2 mbdmac_wput (uaecptr addr, uae_u32 w)
3179 {
3180 mbdmac_write_word (wd_a3000, addr + 0, w);
3181 }
mbdmac_bput(uaecptr addr,uae_u32 b)3182 static void REGPARAM2 mbdmac_bput (uaecptr addr, uae_u32 b)
3183 {
3184 mbdmac_write_byte (wd_a3000, addr, b);
3185 }
3186
3187 addrbank mbdmac_a3000_bank = {
3188 mbdmac_lget, mbdmac_wget, mbdmac_bget,
3189 mbdmac_lput, mbdmac_wput, mbdmac_bput,
3190 default_xlate, default_check, NULL, NULL, _T("A3000 DMAC"),
3191 dummy_lgeti, dummy_wgeti,
3192 ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
3193 };
3194
ew(struct wd_state * wd,int addr,uae_u32 value)3195 static void ew (struct wd_state *wd, int addr, uae_u32 value)
3196 {
3197 addr &= 0xffff;
3198 if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
3199 wd->dmacmemory[addr] = (value & 0xf0);
3200 wd->dmacmemory[addr + 2] = (value & 0x0f) << 4;
3201 } else {
3202 wd->dmacmemory[addr] = ~(value & 0xf0);
3203 wd->dmacmemory[addr + 2] = ~((value & 0x0f) << 4);
3204 }
3205 }
3206
scsi_thread(void * wdv)3207 static void *scsi_thread (void *wdv)
3208 {
3209 struct wd_state *wds = (struct wd_state*)wdv;
3210 struct wd_chip_state *wd = &wds->wc;
3211 for (;;) {
3212 uae_u32 v = read_comm_pipe_u32_blocking (&wds->requests);
3213 if (wds->scsi_thread_running == 0 || v == 0xfffffff)
3214 break;
3215 int cmd = v & 0x7f;
3216 int msg = (v >> 8) & 0xff;
3217 int unit = (v >> 24) & 0xff;
3218 wd->scsi = wds->scsis[unit];
3219 //write_log (_T("scsi_thread got msg=%d cmd=%d\n"), msg, cmd);
3220 if (msg == 0) {
3221 if (WD33C93_DEBUG > 0)
3222 write_log (_T("%s command %02X\n"), WD33C93, cmd);
3223 switch (cmd)
3224 {
3225 case WD_CMD_RESET:
3226 wd_cmd_reset(wd, true);
3227 break;
3228 case WD_CMD_ABORT:
3229 wd_cmd_abort (wd);
3230 break;
3231 case WD_CMD_SEL:
3232 wd_cmd_sel (wd, wds, false);
3233 break;
3234 case WD_CMD_SEL_ATN:
3235 wd_cmd_sel (wd, wds, true);
3236 break;
3237 case WD_CMD_SEL_ATN_XFER:
3238 wd_cmd_sel_xfer (wd, wds, true);
3239 break;
3240 case WD_CMD_SEL_XFER:
3241 wd_cmd_sel_xfer (wd, wds, false);
3242 break;
3243 case WD_CMD_TRANS_INFO:
3244 wd_cmd_trans_info (wds, wd->scsi, false);
3245 break;
3246 case WD_CMD_TRANS_ADDR:
3247 wd_cmd_trans_addr(wd, wds);
3248 break;
3249 case WD_CMD_NEGATE_ACK:
3250 if (wd->wd_phase == CSR_MSGIN && wd->wd_selected)
3251 wd_do_transfer_in(wd, wd->scsi, false);
3252 break;
3253 case WD_CMD_TRANSFER_PAD:
3254 wd_cmd_trans_info (wds, wd->scsi, true);
3255 break;
3256 default:
3257 wd->wd_busy = false;
3258 write_log (_T("%s unimplemented/unknown command %02X\n"), WD33C93, cmd);
3259 set_status (wd, CSR_INVALID, 10);
3260 break;
3261 }
3262 } else if (msg == 1) {
3263 wd_do_transfer_in (wd, wd->scsi, false);
3264 } else if (msg == 2) {
3265 wd_do_transfer_out (wd, wd->scsi);
3266 } else if (msg == 3) {
3267 wd_do_transfer_in (wd, wd->scsi, true);
3268 }
3269 }
3270 wds->scsi_thread_running = -1;
3271 return 0;
3272 }
3273
init_wd_scsi(struct wd_state * wd)3274 void init_wd_scsi (struct wd_state *wd)
3275 {
3276 wd->configured = 0;
3277 wd->enabled = true;
3278 wd->wc.wd_used = 0;
3279 wd->wc.wd33c93_ver = 1;
3280 wd->baseaddress = 0;
3281 if (wd == wd_cdtv) {
3282 wd->cdtv = true;
3283 }
3284 if (!wd->scsi_thread_running) {
3285 wd->scsi_thread_running = 1;
3286 init_comm_pipe (&wd->requests, 100, 1);
3287 uae_start_thread (_T("scsi"), scsi_thread, wd, NULL);
3288 }
3289 }
3290
a3000_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3291 void a3000_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3292 {
3293 struct wd_state *wd = allocscsi(&wd_a3000, rc, ch);
3294 if (!wd || ch < 0)
3295 return;
3296 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3297 }
3298
a3000scsi_reset(void)3299 void a3000scsi_reset (void)
3300 {
3301 struct wd_state *wd = wd_a3000;
3302 if (!wd)
3303 return;
3304 init_wd_scsi (wd);
3305 wd->enabled = true;
3306 wd->configured = -1;
3307 wd->dmac_type = COMMODORE_SDMAC;
3308 map_banks(&mbdmac_a3000_bank, 0xDD, 1, 0);
3309 wd_cmd_reset (&wd->wc, false);
3310 reset_dmac(wd);
3311 }
3312
a3000scsi_free(void)3313 void a3000scsi_free (void)
3314 {
3315 struct wd_state *wd = wd_a3000;
3316 if (!wd)
3317 return;
3318 freencrunit(wd);
3319 if (wd->scsi_thread_running > 0) {
3320 wd->scsi_thread_running = 0;
3321 write_comm_pipe_u32 (&wd->requests, 0xffffffff, 1);
3322 while(wd->scsi_thread_running == 0)
3323 sleep_millis (10);
3324 wd->scsi_thread_running = 0;
3325 }
3326 }
3327
a2090_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3328 void a2090_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3329 {
3330 struct wd_state *wd = allocscsi(&wd_a2090[ci->controller_type_unit], rc, ch);
3331 if (!wd || ch < 0)
3332 return;
3333 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3334 }
3335
a2091_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3336 void a2091_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3337 {
3338 struct wd_state *wd = allocscsi(&wd_a2091[ci->controller_type_unit], rc, ch);
3339 if (!wd || ch < 0)
3340 return;
3341 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3342 }
3343
gvp_s1_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3344 void gvp_s1_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3345 {
3346 struct wd_state *wd = allocscsi(&wd_gvps1[ci->controller_type_unit], rc, ch);
3347 if (!wd || ch < 0)
3348 return;
3349 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3350 }
3351
gvp_s2_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3352 void gvp_s2_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3353 {
3354 struct wd_state *wd = allocscsi(&wd_gvps2[ci->controller_type_unit], rc, ch);
3355 if (!wd || ch < 0)
3356 return;
3357 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3358 }
3359
gvp_s2_add_accelerator_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3360 void gvp_s2_add_accelerator_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3361 {
3362 struct wd_state *wd = allocscsi(&wd_gvps2accel, rc, ch);
3363 if (!wd || ch < 0)
3364 return;
3365 add_scsi_device(&wd->scsis[ch], ch, ci, rc);
3366 }
3367
a2091_free_device(struct wd_state * wd)3368 static void a2091_free_device (struct wd_state *wd)
3369 {
3370 freencrunit(wd);
3371 }
3372
a2091_free(void)3373 void a2091_free (void)
3374 {
3375 for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
3376 a2091_free_device(wd_a2091[i]);
3377 a2091_free_device(wd_a2090[i]);
3378 }
3379 }
3380
a2091_reset_device(struct wd_state * wd)3381 static void a2091_reset_device(struct wd_state *wd)
3382 {
3383 if (!wd)
3384 return;
3385 wd->configured = 0;
3386 wd->wc.wd_used = 0;
3387 wd->wc.wd33c93_ver = 1;
3388 wd->dmac_type = COMMODORE_DMAC;
3389 wd->cdmac.old_dmac = 0;
3390 if (currprefs.scsi == 2)
3391 scsi_addnative(wd->scsis);
3392 wd_cmd_reset (&wd->wc, false);
3393 reset_dmac(wd);
3394 xt_reset(wd);
3395 }
3396
a2090_reset_device(struct wd_state * wd)3397 static void a2090_reset_device(struct wd_state *wd)
3398 {
3399 if (!wd)
3400 return;
3401 wd->configured = 0;
3402 wd->wc.wd_used = 0;
3403 wd->wc.wd33c93_ver = 1;
3404 wd->dmac_type = COMMODORE_8727;
3405 wd->cdmac.old_dmac = 0;
3406 wd_cmd_reset (&wd->wc, false);
3407 reset_dmac(wd);
3408 }
3409
a2091_reset(void)3410 void a2091_reset (void)
3411 {
3412 for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
3413 a2091_reset_device(wd_a2091[i]);
3414 a2090_reset_device(wd_a2090[i]);
3415 }
3416 }
3417
a2091_init(struct romconfig * rc)3418 addrbank *a2091_init (struct romconfig *rc)
3419 {
3420 struct wd_state *wd = getscsi(rc);
3421 int slotsize;
3422
3423 if (!wd)
3424 return &expamem_null;
3425
3426 init_wd_scsi(wd);
3427
3428 wd->cdmac.old_dmac = rc->subtype == 0;
3429 wd->configured = 0;
3430 wd->autoconfig = true;
3431 wd->board_mask = 65535;
3432 wd->bank = &dmaca2091_bank;
3433 memset (wd->dmacmemory, 0xff, sizeof wd->dmacmemory);
3434 ew(wd, 0x00, 0xc0 | 0x01 | 0x10 | (expansion_is_next_board_fastram() ? 0x08 : 0x00));
3435 /* A590/A2091 hardware id */
3436 ew(wd, 0x04, wd->cdmac.old_dmac ? 0x02 : 0x03);
3437 /* commodore's manufacturer id */
3438 ew (wd, 0x10, 0x02);
3439 ew (wd, 0x14, 0x02);
3440 /* rom vector */
3441 ew (wd, 0x28, CDMAC_ROM_VECTOR >> 8);
3442 ew (wd, 0x2c, CDMAC_ROM_VECTOR);
3443
3444 ew (wd, 0x18, 0x00); /* ser.no. Byte 0 */
3445 ew (wd, 0x1c, 0x00); /* ser.no. Byte 1 */
3446 ew (wd, 0x20, 0x00); /* ser.no. Byte 2 */
3447 ew (wd, 0x24, 0x00); /* ser.no. Byte 3 */
3448
3449 wd->rombankswitcher = 0;
3450 wd->rombank = 0;
3451 slotsize = 65536;
3452 wd->rom = xcalloc (uae_u8, slotsize);
3453 memset(wd->rom, 0xff, slotsize);
3454 wd->rom_size = 16384;
3455 wd->rom_mask = wd->rom_size - 1;
3456 if (!rc->autoboot_disabled) {
3457 struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_A2091);
3458 if (z) {
3459 wd->rom_size = zfile_size (z);
3460 zfile_fread (wd->rom, wd->rom_size, 1, z);
3461 zfile_fclose (z);
3462 if (wd->rom_size == 32768) {
3463 wd->rombankswitcher = 1;
3464 for (int i = wd->rom_size - 1; i >= 0; i--) {
3465 wd->rom[i * 2 + 0] = wd->rom[i];
3466 wd->rom[i * 2 + 1] = 0xff;
3467 }
3468 } else {
3469 for (int i = 1; i < slotsize / wd->rom_size; i++)
3470 memcpy (wd->rom + i * wd->rom_size, wd->rom, wd->rom_size);
3471 }
3472 wd->rom_mask = wd->rom_size - 1;
3473 }
3474 }
3475 return wd->bank;
3476 }
3477
a2090_init(struct romconfig * rc)3478 addrbank *a2090_init (struct romconfig *rc)
3479 {
3480 struct wd_state *wd = getscsi(rc);
3481 int slotsize;
3482
3483 if (!wd)
3484 return &expamem_null;
3485
3486 init_wd_scsi(wd);
3487
3488 wd->configured = 0;
3489 wd->autoconfig = true;
3490 wd->board_mask = 65535;
3491 wd->bank = &dmaca2091_bank;
3492 memset (wd->dmacmemory, 0xff, sizeof wd->dmacmemory);
3493 ew (wd, 0x00, 0xc0 | 0x01 | 0x10);
3494 /* A590/A2091 hardware id */
3495 ew(wd, 0x04, rc->subtype ? 0x02 : 0x01);
3496 /* commodore's manufacturer id */
3497 ew (wd, 0x10, 0x02);
3498 ew (wd, 0x14, 0x02);
3499 /* rom vector */
3500 ew (wd, 0x28, DMAC_8727_ROM_VECTOR >> 8);
3501 ew (wd, 0x2c, DMAC_8727_ROM_VECTOR);
3502
3503 ew (wd, 0x18, 0x00); /* ser.no. Byte 0 */
3504 ew (wd, 0x1c, 0x00); /* ser.no. Byte 1 */
3505 ew (wd, 0x20, 0x00); /* ser.no. Byte 2 */
3506 ew (wd, 0x24, 0x00); /* ser.no. Byte 3 */
3507
3508 //ew(wd, 0x30, 0x80); // SCSI only flag
3509
3510 wd->rombankswitcher = 0;
3511 wd->rombank = 0;
3512 slotsize = 65536;
3513 wd->rom = xcalloc (uae_u8, slotsize);
3514 memset(wd->rom, 0xff, slotsize);
3515 wd->rom_size = 16384;
3516 wd->rom_mask = wd->rom_size - 1;
3517 if (!rc->autoboot_disabled) {
3518 struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_A2090);
3519 if (z) {
3520 wd->rom_size = zfile_size (z);
3521 zfile_fread (wd->rom, wd->rom_size, 1, z);
3522 zfile_fclose (z);
3523 for (int i = 1; i < slotsize / wd->rom_size; i++) {
3524 memcpy (wd->rom + i * wd->rom_size, wd->rom, wd->rom_size);
3525 }
3526 wd->rom_mask = wd->rom_size - 1;
3527 }
3528 }
3529 return wd->bank;
3530 }
3531
gvp_free_device(struct wd_state * wd)3532 static void gvp_free_device (struct wd_state *wd)
3533 {
3534 freencrunit(wd);
3535 }
3536
gvp_free(void)3537 void gvp_free (void)
3538 {
3539 for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
3540 gvp_free_device(wd_gvps1[i]);
3541 gvp_free_device(wd_gvps2[i]);
3542 }
3543 gvp_free_device(wd_gvps2accel);
3544 }
3545
gvp_reset_device(struct wd_state * wd)3546 static void gvp_reset_device(struct wd_state *wd)
3547 {
3548 if (!wd)
3549 return;
3550 wd->configured = 0;
3551 wd->wc.wd_used = 0;
3552 wd->wc.wd33c93_ver = 1;
3553 wd->dmac_type = wd->gdmac.series2 ? GVP_DMAC_S2 : GVP_DMAC_S1;
3554 if (currprefs.scsi == 2)
3555 scsi_addnative(wd->scsis);
3556 wd_cmd_reset (&wd->wc, false);
3557 reset_dmac(wd);
3558 }
3559
gvp_reset(void)3560 void gvp_reset (void)
3561 {
3562 for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
3563 gvp_reset_device(wd_gvps1[i]);
3564 gvp_reset_device(wd_gvps2[i]);
3565 }
3566 gvp_reset_device(wd_gvps2accel);
3567 }
3568
3569 static const uae_u8 gvp_scsi_i_autoconfig_1[16] = { 0xd1, 0x01, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
3570 static const uae_u8 gvp_scsi_i_autoconfig_2[16] = { 0xd1, 0x02, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
3571 static const uae_u8 gvp_scsi_i_autoconfig_3[16] = { 0xd2, 0x03, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
3572 static const uae_u8 gvp_scsi_ii_autoconfig[16] = { 0xd1, 0x0b, 0x00, 0x00, 0x07, 0xe1, 0xee, 0xee, 0xee, 0xee, 0x80, 0x00 };
3573
is_gvp_accelerator(void)3574 static bool is_gvp_accelerator(void)
3575 {
3576 return ISCPUBOARD(BOARD_GVP, -1);
3577 }
3578
gvp_init(struct romconfig * rc,bool series2,bool accel)3579 static addrbank *gvp_init(struct romconfig *rc, bool series2, bool accel)
3580 {
3581 struct wd_state *wd = getscsi(rc);
3582 bool isscsi = true;
3583 const uae_u8 *ac;
3584 int romtype;
3585
3586 if (!accel) {
3587 romtype = series2 ? ROMTYPE_GVPS2 : ROMTYPE_GVPS1;
3588 } else {
3589 romtype = ROMTYPE_CPUBOARD;
3590 }
3591
3592 if (!wd)
3593 return &expamem_null;
3594
3595 init_wd_scsi(wd);
3596 wd->configured = 0;
3597 wd->bank = &gvp_bank;
3598 wd->autoconfig = true;
3599 wd->rombankswitcher = 0;
3600 memset(wd->dmacmemory, 0xff, sizeof wd->dmacmemory);
3601 wd->gdmac.series2 = series2;
3602 wd->gdmac.use_version = series2;
3603 wd->board_mask = 65535;
3604
3605 wd->rom_size = 32768;
3606 wd->rom = xcalloc(uae_u8, 2 * wd->rom_size);
3607 memset(wd->rom, 0xff, 2 * wd->rom_size);
3608 wd->rom_mask = 32768 - 1;
3609 wd->gdmac.s1_subtype = 0;
3610 ac = gvp_scsi_ii_autoconfig;
3611
3612 ac = gvp_scsi_ii_autoconfig;
3613 if (!series2) {
3614 ac = gvp_scsi_i_autoconfig_1;
3615 wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_1;
3616 wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_1;
3617 if (rc->subtype == 1) {
3618 ac = gvp_scsi_i_autoconfig_2;
3619 wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_2;
3620 wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_2;
3621 } else if (rc->subtype == 2) {
3622 ac = gvp_scsi_i_autoconfig_3;
3623 wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_3;
3624 wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_3;
3625 wd->board_mask = 131071;
3626 }
3627 wd->gdmac.s1_subtype = rc->subtype;
3628 }
3629 xfree(wd->gdmac.buffer);
3630 wd->gdmac.buffer = xcalloc(uae_u8, 16384);
3631 if (!rc->autoboot_disabled) {
3632 struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_GVPS2);
3633 if (z) {
3634 int size = zfile_size(z);
3635 if (series2) {
3636 int total = 0;
3637 int seekpos = 0;
3638 int size = zfile_size(z);
3639 if (size > 16384 + 4096) {
3640 zfile_fread(wd->rom, 64, 1, z);
3641 zfile_fseek(z, 16384, SEEK_SET);
3642 zfile_fread(wd->rom + 64, 64, 1, z);
3643 if (!memcmp(wd->rom, wd->rom + 64, 64))
3644 wd->rombankswitcher = true;
3645 else
3646 seekpos = 16384;
3647 }
3648 while (total < 32768 - 4096) {
3649 int prevtotal = total;
3650 zfile_fseek(z, seekpos, SEEK_SET);
3651 total += zfile_fread(wd->rom + total, 1, wd->rom_size - total >= wd->rom_size ? wd->rom_size : wd->rom_size - total, z);
3652 if (prevtotal == total)
3653 break;
3654 }
3655 } else {
3656 int j = 0;
3657 bool oddonly = false;
3658 for (int i = 0; i < 16384; i++) {
3659 uae_u8 b;
3660 zfile_fread(&b, 1, 1, z);
3661 wd->rom[j + 16384] = b;
3662 wd->rom[j++] = b;
3663 if (i == 0 && (b & 0xc0) != 0x80) {
3664 // was not wordwide
3665 oddonly = true;
3666 wd->gdmac.use_version = true;
3667 }
3668 if (oddonly) {
3669 wd->rom[j + 16384] = 0xff;
3670 wd->rom[j++] = 0xff;
3671 }
3672 }
3673 }
3674 zfile_fclose(z);
3675 } else {
3676 isscsi = false;
3677 }
3678 }
3679
3680 if (series2) {
3681 wd->gdmac.version = GVP_SERIESII;
3682 wd->gdmac.addr_mask = 0x00ffffff;
3683 if (ISCPUBOARD(BOARD_GVP, BOARD_GVP_SUB_A530)) {
3684 wd->gdmac.version = isscsi ? GVP_A530_SCSI : GVP_A530;
3685 wd->gdmac.addr_mask = 0x01ffffff;
3686 } else if (ISCPUBOARD(BOARD_GVP, BOARD_GVP_SUB_GFORCE030)) {
3687 wd->gdmac.version = isscsi ? GVP_GFORCE_030_SCSI : GVP_GFORCE_030;
3688 wd->gdmac.addr_mask = 0x01ffffff;
3689 }
3690 } else {
3691 wd->gdmac.version = 0x00;
3692 }
3693
3694 for (int i = 0; i < 16; i++) {
3695 uae_u8 b = ac[i];
3696 ew(wd, i * 4, b);
3697 }
3698 gvp_reset_device(wd);
3699 return wd->bank;
3700 }
3701
gvp_init_s1(struct romconfig * rc)3702 addrbank *gvp_init_s1(struct romconfig *rc)
3703 {
3704 return gvp_init(rc, false, false);
3705 }
gvp_init_s2(struct romconfig * rc)3706 addrbank *gvp_init_s2(struct romconfig *rc)
3707 {
3708 return gvp_init(rc, true, false);
3709 }
gvp_init_accelerator(struct romconfig * rc)3710 addrbank *gvp_init_accelerator(struct romconfig *rc)
3711 {
3712 return gvp_init(rc, true, true);
3713 }
3714
3715 #ifdef CDTV
cdtv_add_scsi_unit(int ch,struct uaedev_config_info * ci,struct romconfig * rc)3716 void cdtv_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc)
3717 {
3718 struct wd_state *wd = allocscsi(&wd_cdtv, rc, ch);
3719 if (!wd || ch < 0)
3720 return;
3721 add_scsi_device(&wd_cdtv->scsis[ch], ch, ci, rc);
3722 }
3723 #endif
3724
3725
3726 #if 0
3727 uae_u8 *save_scsi_dmac (int wdtype, int *len, uae_u8 *dstptr)
3728 {
3729 struct wd_state *wd = wdscsi[wdtype];
3730 uae_u8 *dstbak, *dst;
3731
3732 if (!wd->enabled)
3733 return NULL;
3734 if (dstptr)
3735 dstbak = dst = dstptr;
3736 else
3737 dstbak = dst = xmalloc (uae_u8, 1000);
3738
3739 // model (0=original,1=rev2,2=superdmac)
3740 save_u32 (currprefs.cs_mbdmac == 1 ? 2 : 1);
3741 save_u32 (0); // reserved flags
3742 save_u8(wd->cdmac.dmac_istr);
3743 save_u8(wd->cdmac.dmac_cntr);
3744 save_u32(wd->cdmac.dmac_wtc);
3745 save_u32(wd->cdmac.dmac_acr);
3746 save_u16(wd->cdmac.dmac_dawr);
3747 save_u32(wd->cdmac.dmac_dma ? 1 : 0);
3748 save_u8 (wd->configured);
3749 *len = dst - dstbak;
3750 return dstbak;
3751 }
3752
3753 uae_u8 *restore_scsi_dmac (int wdtype, uae_u8 *src)
3754 {
3755 struct wd_state *wd = wdscsi[wdtype];
3756 restore_u32 ();
3757 restore_u32 ();
3758 wd->cdmac.dmac_istr = restore_u8();
3759 wd->cdmac.dmac_cntr = restore_u8();
3760 wd->cdmac.dmac_wtc = restore_u32();
3761 wd->cdmac.dmac_acr = restore_u32();
3762 wd->cdmac.dmac_dawr = restore_u16();
3763 restore_u32 ();
3764 wd->configured = restore_u8 ();
3765 return src;
3766 }
3767
3768 uae_u8 *save_scsi_device (int wdtype, int num, int *len, uae_u8 *dstptr)
3769 {
3770 uae_u8 *dstbak, *dst;
3771 struct scsi_data *s;
3772 struct wd_state *wd = wdscsi[wdtype];
3773
3774 if (!wd->enabled)
3775 return NULL;
3776 s = wd->scsis[num];
3777 if (!s)
3778 return NULL;
3779 if (dstptr)
3780 dstbak = dst = dstptr;
3781 else
3782 dstbak = dst = xmalloc (uae_u8, 1000);
3783 save_u32 (num);
3784 save_u32 (s->device_type); // flags
3785 switch (s->device_type)
3786 {
3787 case UAEDEV_HDF:
3788 case 0:
3789 save_u64 (s->hfd->size);
3790 save_string (s->hfd->hfd.ci.rootdir);
3791 save_u32 (s->hfd->hfd.ci.blocksize);
3792 save_u32 (s->hfd->hfd.ci.readonly);
3793 save_u32 (s->hfd->cyls);
3794 save_u32 (s->hfd->heads);
3795 save_u32 (s->hfd->secspertrack);
3796 save_u64 (s->hfd->hfd.virtual_size);
3797 save_u32 (s->hfd->hfd.ci.sectors);
3798 save_u32 (s->hfd->hfd.ci.surfaces);
3799 save_u32 (s->hfd->hfd.ci.reserved);
3800 save_u32 (s->hfd->hfd.ci.bootpri);
3801 save_u32 (s->hfd->ansi_version);
3802 if (num == 7) {
3803 save_u16(wd->cdmac.xt_cyls);
3804 save_u16(wd->cdmac.xt_heads);
3805 save_u16(wd->cdmac.xt_sectors);
3806 save_u8(wd->cdmac.xt_status);
3807 save_u8(wd->cdmac.xt_control);
3808 }
3809 break;
3810 case UAEDEV_CD:
3811 save_u32 (s->cd_emu_unit);
3812 break;
3813 case UAEDEV_TAPE:
3814 save_u32 (s->cd_emu_unit);
3815 save_u32 (s->tape->blocksize);
3816 save_u32 (s->tape->wp);
3817 save_string (s->tape->tape_dir);
3818 break;
3819 }
3820 *len = dst - dstbak;
3821 return dstbak;
3822 }
3823
3824 uae_u8 *restore_scsi_device (int wdtype, uae_u8 *src)
3825 {
3826 struct wd_state *wd = wdscsi[wdtype];
3827 int num, num2;
3828 struct hd_hardfiledata *hfd;
3829 struct scsi_data *s;
3830 uae_u64 size;
3831 uae_u32 flags;
3832 int blocksize, readonly;
3833 TCHAR *path;
3834
3835 num = restore_u32 ();
3836
3837 flags = restore_u32 ();
3838 switch (flags & 15)
3839 {
3840 case UAEDEV_HDF:
3841 case 0:
3842 hfd = xcalloc (struct hd_hardfiledata, 1);
3843 s = wd->scsis[num] = scsi_alloc_hd (num, hfd);
3844 size = restore_u64 ();
3845 path = restore_string ();
3846 _tcscpy (s->hfd->hfd.ci.rootdir, path);
3847 blocksize = restore_u32 ();
3848 readonly = restore_u32 ();
3849 s->hfd->cyls = restore_u32 ();
3850 s->hfd->heads = restore_u32 ();
3851 s->hfd->secspertrack = restore_u32 ();
3852 s->hfd->hfd.virtual_size = restore_u64 ();
3853 s->hfd->hfd.ci.sectors = restore_u32 ();
3854 s->hfd->hfd.ci.surfaces = restore_u32 ();
3855 s->hfd->hfd.ci.reserved = restore_u32 ();
3856 s->hfd->hfd.ci.bootpri = restore_u32 ();
3857 s->hfd->ansi_version = restore_u32 ();
3858 s->hfd->hfd.ci.blocksize = blocksize;
3859 if (num == 7) {
3860 wd->cdmac.xt_cyls = restore_u16();
3861 wd->cdmac.xt_heads = restore_u8();
3862 wd->cdmac.xt_sectors = restore_u8();
3863 wd->cdmac.xt_status = restore_u8();
3864 wd->cdmac.xt_control = restore_u8();
3865 }
3866 if (size)
3867 add_scsi_hd (&wd->scsis[num], num, hfd, NULL, s->hfd->ansi_version);
3868 xfree (path);
3869 break;
3870 case UAEDEV_CD:
3871 num2 = restore_u32 ();
3872 add_scsi_cd (wd->scsis, num, num2);
3873 break;
3874 case UAEDEV_TAPE:
3875 num2 = restore_u32 ();
3876 blocksize = restore_u32 ();
3877 readonly = restore_u32 ();
3878 path = restore_string ();
3879 add_scsi_tape (&wd->scsis[num], num, path, readonly != 0);
3880 xfree (path);
3881 break;
3882 }
3883 return src;
3884 }
3885 #endif
3886