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