|
|
1.1 root 1: /*
2: * Hatari - NCR 5380 SCSI controller emulation
3: *
4: * Based on scsi.ccp from WinUAE:
5: *
6: * Copyright 2007-2015 Toni Wilen
7: *
8: * Adaptions to Hatari:
9: *
10: * Copyright 2018 Thomas Huth
11: *
12: * This file is distributed under the GNU General Public License, version 2
13: * or at your option any later version. Read the file gpl.txt for details.
14: */
15: const char NCR5380_fileid[] = "Hatari ncr5380.c";
16:
17: #include "main.h"
18: #include "configuration.h"
19: #include "cycInt.h"
20: #include "file.h"
21: #include "fdc.h"
22: #include "hdc.h"
23: #include "hatari-glue.h"
24: #include "ioMem.h"
25: #include "log.h"
26: #include "memorySnapShot.h"
27: #include "mfp.h"
28: #include "ncr5380.h"
29: #include "stMemory.h"
30: #include "newcpu.h"
31:
32: #define WITH_NCR5380 1
33:
34: static SCSI_CTRLR ScsiBus;
35:
36: #define MAX_TOTAL_SCSI_DEVICES 8
37:
38: #define RAW_SCSI_DEBUG 2
39: #define NCR5380_DEBUG 1
40: #define NCR5380_DEBUG_IRQ 0
41:
42: #ifndef _T
43: #define _T(x) x
44: #endif
45:
46: // raw scsi
47:
48: #define SCSI_IO_BUSY 0x80
49: #define SCSI_IO_ATN 0x40
50: #define SCSI_IO_SEL 0x20
51: #define SCSI_IO_REQ 0x10
52: #define SCSI_IO_DIRECTION 0x01
53: #define SCSI_IO_COMMAND 0x02
54: #define SCSI_IO_MESSAGE 0x04
55:
56: #define SCSI_SIGNAL_PHASE_FREE -1
57: #define SCSI_SIGNAL_PHASE_ARBIT -2
58: #define SCSI_SIGNAL_PHASE_SELECT_1 -3
59: #define SCSI_SIGNAL_PHASE_SELECT_2 -4
60:
61: #define SCSI_SIGNAL_PHASE_DATA_OUT 0
62: #define SCSI_SIGNAL_PHASE_DATA_IN 1
63: #define SCSI_SIGNAL_PHASE_COMMAND 2
64: #define SCSI_SIGNAL_PHASE_STATUS 3
65: #define SCSI_SIGNAL_PHASE_MESSAGE_OUT 6
66: #define SCSI_SIGNAL_PHASE_MESSAGE_IN 7
67:
68: #define SCSI_STATUS_GOOD 0x00
69: #define SCSI_STATUS_CHECK_CONDITION 0x02
70: #define SCSI_STATUS_CONDITION_MET 0x04
71: #define SCSI_STATUS_BUSY 0x08
72: #define SCSI_STATUS_INTERMEDIATE 0x10
73: #define SCSI_STATUS_ICM 0x14 /* intermediate condition met */
74: #define SCSI_STATUS_RESERVATION_CONFLICT 0x18
75: #define SCSI_STATUS_COMMAND_TERMINATED 0x22
76: #define SCSI_STATUS_QUEUE_FULL 0x28
77: #define SCSI_STATUS_ACA_ACTIVE 0x30
78:
79: struct raw_scsi
80: {
81: int io;
82: int bus_phase;
83: bool atn;
84: bool ack;
85: uae_u8 data_write;
86: uae_u8 status;
87: bool databusoutput;
88: int initiator_id, target_id;
89: struct scsi_data *device[MAX_TOTAL_SCSI_DEVICES];
90: struct scsi_data *target;
91: int msglun;
92: };
93:
94: struct soft_scsi
95: {
96: uae_u8 regs[9];
97: struct raw_scsi rscsi;
98: bool irq;
99:
100: int dma_direction;
101: bool dma_active;
102: bool dma_started;
103: bool dma_controller;
104: bool dma_drq;
105:
106: int dmac_direction;
107: int dmac_active;
108: };
109:
110: struct soft_scsi ncr_soft_scsi;
111:
112: static const uae_s16 outcmd[] = { 0x04, 0x0a, 0x0c, 0x11, 0x2a, 0xaa, 0x15, 0x55, 0x0f, -1 };
113: static const uae_s16 incmd[] = { 0x01, 0x03, 0x08, 0x0e, 0x12, 0x1a, 0x5a, 0x25, 0x28, 0x34, 0x37, 0x42, 0x43, 0xa8, 0x51, 0x52, 0xb9, 0xbd, 0xd8, 0xd9, 0xbe, -1 };
114: static const uae_s16 nonecmd[] = { 0x00, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x10, 0x16, 0x17, 0x19, 0x1b, 0x1d, 0x1e, 0x2b, 0x35, 0x45, 0x47, 0x48, 0x49, 0x4b, 0x4e, 0xa5, 0xa9, 0xba, 0xbc, 0xe0, 0xe3, 0xe4, -1 };
115: static const uae_s16 scsicmdsizes[] = { 6, 10, 10, 12, 16, 12, 10, 6 };
116:
117: static uae_u8 ncr5380_bget(struct soft_scsi *scsi, int reg);
118: void ncr5380_bput(struct soft_scsi *scsi, int reg, uae_u8 v);
119:
120: static int scsi_data_dir(struct scsi_data *sd)
121: {
122: int i;
123: uae_u8 cmd;
124:
125: cmd = sd->cmd[0];
126: for (i = 0; outcmd[i] >= 0; i++) {
127: if (cmd == outcmd[i]) {
128: return 1;
129: }
130: }
131: for (i = 0; incmd[i] >= 0; i++) {
132: if (cmd == incmd[i]) {
133: return -1;
134: }
135: }
136: for (i = 0; nonecmd[i] >= 0; i++) {
137: if (cmd == nonecmd[i]) {
138: return 0;
139: }
140: }
141: write_log (_T("SCSI command %02X, no direction specified!\n"), cmd);
142: return 0;
143: }
144:
145: static void scsi_start_transfer(struct scsi_data *sd)
146: {
147: // sd->offset = 0;
148: ScsiBus.offset = 0;
149: }
150:
151: static int scsi_send_data(struct scsi_data *sd, uae_u8 b)
152: {
153: if (ScsiBus.offset < 0) {
154: write_log(_T("SCSI data offset is negative!\n"));
155: return 0;
156: }
157: if (sd->direction == 1) {
158: if (ScsiBus.offset >= ScsiBus.buffer_size) {
159: write_log (_T("SCSI data buffer overflow!\n"));
160: return 0;
161: }
162: ScsiBus.buffer[ScsiBus.offset++] = b;
163: } else if (sd->direction == 2) {
164: if (ScsiBus.offset >= 16) {
165: write_log (_T("SCSI command buffer overflow!\n"));
166: return 0;
167: }
168: sd->cmd[ScsiBus.offset++] = b;
169: if (ScsiBus.offset == sd->cmd_len)
170: return 1;
171: } else {
172: write_log (_T("scsi_send_data() without direction! (%02X)\n"), b);
173: return 0;
174: }
175: if (ScsiBus.offset == ScsiBus.data_len)
176: return 1;
177: return 0;
178: }
179:
180: static int scsi_receive_data(struct scsi_data *sd, uae_u8 *b, bool next)
181: {
182: if (!ScsiBus.data_len) {
183: fprintf(stderr, "scsi_receive_data without length!\n");
184: return -1;
185: }
186: *b = ScsiBus.buffer[ScsiBus.offset];
187: // fprintf(stderr,"scsi_receive_data %i <-> %i (%i)\n",
188: // ScsiBus.offset, ScsiBus.data_len, next);
189: if (next) {
190: ScsiBus.offset++;
191: if (ScsiBus.offset == ScsiBus.data_len)
192: return 1; // requested length got
193: }
194: return 0;
195: }
196:
197: static void bus_free(struct raw_scsi *rs)
198: {
199: // fprintf(stderr, "BUS FREE!\n");
200: rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
201: rs->io = 0;
202: }
203:
204: static int getbit(uae_u8 v)
205: {
206: int i;
207:
208: for (i = 7; i >= 0; i--) {
209: if ((1 << i) & v)
210: return i;
211: }
212: return -1;
213: }
214:
215: static int countbits(uae_u8 v)
216: {
217: int i, cnt = 0;
218:
219: for (i = 7; i >= 0; i--) {
220: if ((1 << i) & v)
221: cnt++;
222: }
223: return cnt;
224: }
225:
226: static void raw_scsi_reset_bus(struct soft_scsi *scsi)
227: {
228: //struct raw_scsi *r = &scsi->rscsi;
229: #if RAW_SCSI_DEBUG
230: write_log(_T("SCSI BUS reset\n"));
231: #endif
232: #if 0 /* FIXME */
233: for (int i = 0; i < 8; i++) {
234: scsi_emulate_reset_device(r->device[i]);
235: }
236: #endif
237: }
238:
239:
240: static void raw_scsi_set_databus(struct raw_scsi *rs, bool databusoutput)
241: {
242: rs->databusoutput = databusoutput;
243: }
244:
245: static void raw_scsi_set_signal_phase(struct raw_scsi *rs, bool busy, bool select, bool atn)
246: {
247: // fprintf(stderr,"raw_scsi_set_signal_phase busy=%i sel=%i atn=%i phase=%i\n",
248: // busy, select, atn, rs->bus_phase);
249: switch (rs->bus_phase)
250: {
251: case SCSI_SIGNAL_PHASE_FREE:
252: if (busy && !select && !rs->databusoutput) {
253: if (countbits(rs->data_write) != 1) {
254: #if RAW_SCSI_DEBUG
255: write_log(_T("raw_scsi: invalid arbitration scsi id mask! (%02x)\n"), rs->data_write);
256: #endif
257: return;
258: }
259: rs->bus_phase = SCSI_SIGNAL_PHASE_ARBIT;
260: rs->initiator_id = getbit(rs->data_write);
261: #if RAW_SCSI_DEBUG
262: write_log(_T("raw_scsi: arbitration initiator id %d (%02x)\n"), rs->initiator_id, rs->data_write);
263: #endif
264: } else if (!busy && select) {
265: if (countbits(rs->data_write) > 2 || rs->data_write == 0) {
266: #if RAW_SCSI_DEBUG
267: write_log(_T("raw_scsi: invalid scsi id selected mask (%02x)\n"), rs->data_write);
268: #endif
269: return;
270: }
271: rs->initiator_id = -1;
272: rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
273: #if RAW_SCSI_DEBUG
274: write_log(_T("raw_scsi: selected scsi id mask (%02x)\n"), rs->data_write);
275: #endif
276: raw_scsi_set_signal_phase(rs, busy, select, atn);
277: }
278: break;
279: case SCSI_SIGNAL_PHASE_ARBIT:
280: rs->target_id = -1;
281: rs->target = NULL;
282: ScsiBus.target = -1;
283: if (busy && select) {
284: rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
285: }
286: break;
287: case SCSI_SIGNAL_PHASE_SELECT_1:
288: rs->atn = atn;
289: rs->msglun = -1;
290: rs->target_id = -1;
291: ScsiBus.target = -1;
292: if (!busy) {
293: int i;
294: for (i = 0; i < 8; i++) {
295: if (i == rs->initiator_id)
296: continue;
297: if ((rs->data_write & (1 << i)) && rs->device[i]) {
298: rs->target_id = i;
299: rs->target = rs->device[rs->target_id];
300: ScsiBus.target = i;
301: #if RAW_SCSI_DEBUG
302: write_log(_T("raw_scsi: selected id %d\n"), rs->target_id);
303: #endif
304: rs->io |= SCSI_IO_BUSY;
305: }
306: }
307: #if RAW_SCSI_DEBUG
308: if (rs->target_id < 0) {
309: int i;
310: for (i = 0; i < 8; i++) {
311: if (i == rs->initiator_id)
312: continue;
313: if ((rs->data_write & (1 << i)) && !rs->device[i]) {
314: write_log(_T("raw_scsi: selected non-existing id %d\n"), i);
315: }
316: }
317: }
318: #endif
319: if (rs->target_id >= 0) {
320: rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_2;
321: } else {
322: if (!select) {
323: rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
324: }
325: }
326: }
327: break;
328: case SCSI_SIGNAL_PHASE_SELECT_2:
329: if (!select) {
330: scsi_start_transfer(rs->target);
331: rs->bus_phase = rs->atn ? SCSI_SIGNAL_PHASE_MESSAGE_OUT : SCSI_SIGNAL_PHASE_COMMAND;
332: rs->io = SCSI_IO_BUSY | SCSI_IO_REQ;
333: }
334: break;
335: }
336: }
337:
338: static uae_u8 raw_scsi_get_signal_phase(struct raw_scsi *rs)
339: {
340: uae_u8 v = rs->io;
341: if (rs->bus_phase >= 0)
342: v |= rs->bus_phase;
343: if (rs->ack)
344: v &= ~SCSI_IO_REQ;
345: return v;
346: }
347:
348: static uae_u8 raw_scsi_get_data_2(struct raw_scsi *rs, bool next, bool nodebug)
349: {
350: struct scsi_data *sd = rs->target;
351: uae_u8 v = 0;
352:
353: switch (rs->bus_phase)
354: {
355: case SCSI_SIGNAL_PHASE_FREE:
356: v = 0;
357: break;
358: case SCSI_SIGNAL_PHASE_ARBIT:
359: #if RAW_SCSI_DEBUG
360: write_log(_T("raw_scsi: arbitration\n"));
361: #endif
362: v = rs->data_write;
363: break;
364: case SCSI_SIGNAL_PHASE_DATA_IN:
365: #if RAW_SCSI_DEBUG > 2
366: scsi_receive_data(sd, &v, false);
367: write_log(_T("raw_scsi: read data byte %02x (%d/%d)\n"), v, ScsiBus.offset, ScsiBus.data_len);
368: #endif
369: if (scsi_receive_data(sd, &v, next)) {
370: #if RAW_SCSI_DEBUG
371: write_log(_T("raw_scsi: data in finished, %d bytes: status phase\n"), ScsiBus.offset);
372: #endif
373: rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
374: }
375: break;
376: case SCSI_SIGNAL_PHASE_STATUS:
377: #if RAW_SCSI_DEBUG
378: if (!nodebug || next)
379: write_log(_T("raw_scsi: status byte read %02x. Next=%d\n"), ScsiBus.status, next);
380: #endif
381: v = ScsiBus.status; // sd->status;
382: if (next) {
383: ScsiBus.status = 0; // sd->status = 0;
384: rs->bus_phase = SCSI_SIGNAL_PHASE_MESSAGE_IN;
385: }
386: break;
387: case SCSI_SIGNAL_PHASE_MESSAGE_IN:
388: #if RAW_SCSI_DEBUG
389: if (!nodebug || next)
390: write_log(_T("raw_scsi: message byte read %02x. Next=%d\n"), ScsiBus.status, next);
391: #endif
392: v = ScsiBus.status; // sd->status;
393: rs->status = v;
394: if (next) {
395: bus_free(rs);
396: }
397: break;
398: default:
399: #if RAW_SCSI_DEBUG
400: write_log(_T("raw_scsi_get_data but bus phase is %d!\n"), rs->bus_phase);
401: #endif
402: break;
403: }
404:
405: return v;
406: }
407:
408: static uae_u8 raw_scsi_get_data(struct raw_scsi *rs, bool next)
409: {
410: return raw_scsi_get_data_2(rs, next, true);
411: }
412:
413: static int getmsglen(uae_u8 *msgp, int len)
414: {
415: uae_u8 msg = msgp[0];
416: if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) || msg >= 0x80)
417: return 1;
418: if (msg >= 0x20 && msg <= 0x2f)
419: return 2;
420: // extended message, at least 3 bytes
421: if (len < 2)
422: return 3;
423: return msgp[1];
424: }
425:
426: static bool scsi_emulate_analyze (struct scsi_data *sd)
427: {
428: int cmd_len, data_len;
429:
430: data_len = ScsiBus.data_len;
431: cmd_len = scsicmdsizes[sd->cmd[0] >> 5];
432: sd->cmd_len = cmd_len;
433: switch (sd->cmd[0])
434: {
435: case 0x04: // FORMAT UNIT
436: // FmtData set?
437: if (sd->cmd[1] & 0x10) {
438: // int cl = (sd->cmd[1] & 8) != 0;
439: // int dlf = sd->cmd[1] & 7;
440: //data_len2 = 4;
441: } else {
442: sd->direction = 0;
443: ScsiBus.data_len = 0;
444: return true;
445: }
446: break;
447: case 0x06: // FORMAT TRACK
448: case 0x07: // FORMAT BAD TRACK
449: sd->direction = 0;
450: ScsiBus.data_len = 0;
451: return true;
452: case 0x0c: // INITIALIZE DRIVE CHARACTERICS (SASI)
453: data_len = 8;
454: break;
455: case 0x08: // READ(6)
456: break;
457: case 0x11: // ASSIGN ALTERNATE TRACK (SASI)
458: data_len = 4;
459: break;
460: case 0x28: // READ(10)
461: break;
462: case 0xa8: // READ(12)
463: break;
464: case 0x0f: // WRITE SECTOR BUFFER
465: data_len = 512; //sd->blocksize;
466: break;
467: case 0x0a: // WRITE(6)
468: data_len = (sd->cmd[4] == 0 ? 256 : sd->cmd[4]) * 512; //sd->blocksize;
469: break;
470: case 0x2a: // WRITE(10)
471: data_len = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * 512; //sd->blocksize;
472: break;
473: /*
474: case 0xaa: // WRITE(12)
475: data_len = ((sd->cmd[6] << 24) | (sd->cmd[7] << 16) | (sd->cmd[8] << 8) | (sd->cmd[9] << 0)) * 512; //sd->blocksize;
476: break;
477: */
478: case 0x2f: // VERIFY
479: if (sd->cmd[1] & 2) {
480: ScsiBus.data_len = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * 512; // sd->blocksize;
481: sd->direction = 1;
482: } else {
483: ScsiBus.data_len = 0;
484: sd->direction = 0;
485: }
486: return true;
487: }
488: if (data_len < 0) {
489: if (cmd_len == 6) {
490: ScsiBus.data_len = sd->cmd[4];
491: } else {
492: ScsiBus.data_len = (sd->cmd[7] << 8) | sd->cmd[8];
493: }
494: } else {
495: ScsiBus.data_len = data_len;
496: }
497: sd->direction = scsi_data_dir(sd);
498: if (sd->direction > 0 && ScsiBus.data_len == 0) {
499: sd->direction = 0;
500: }
501: return true;
502: }
503:
504: static void scsi_emulate_cmd(struct scsi_data *sd)
505: {
506: int i;
507:
508: // fprintf(stderr,"scsi_emulate_cmd cmdlen=%i offset=%i\n", sd->cmd_len, ScsiBus.offset);
509: ScsiBus.byteCount = 0;
510: for (i = 0; i < sd->cmd_len; i++)
511: {
512: HDC_WriteCommandPacket(&ScsiBus, sd->cmd[i]);
513: }
514: }
515:
516: static void raw_scsi_write_data(struct raw_scsi *rs, uae_u8 data)
517: {
518: struct scsi_data *sd = rs->target;
519: int len;
520:
521: switch (rs->bus_phase)
522: {
523: case SCSI_SIGNAL_PHASE_SELECT_1:
524: case SCSI_SIGNAL_PHASE_FREE:
525: break;
526: case SCSI_SIGNAL_PHASE_COMMAND:
527: sd->cmd[ScsiBus.offset++] = data;
528: len = scsicmdsizes[sd->cmd[0] >> 5];
529: #if RAW_SCSI_DEBUG > 1
530: write_log(_T("raw_scsi: got command byte %02x (%d/%d)\n"), data, ScsiBus.offset, len);
531: #endif
532: if (ScsiBus.offset >= len) {
533: if (rs->msglun >= 0) {
534: sd->cmd[1] &= ~(0x80 | 0x40 | 0x20);
535: sd->cmd[1] |= rs->msglun << 5;
536: }
537: scsi_emulate_analyze(rs->target);
538: if (sd->direction > 0) {
539: #if RAW_SCSI_DEBUG
540: write_log(_T("raw_scsi: data out %d bytes required\n"), ScsiBus.data_len);
541: #endif
542: scsi_emulate_cmd(sd); /* Hatari only */
543: scsi_start_transfer(sd);
544: rs->bus_phase = SCSI_SIGNAL_PHASE_DATA_OUT;
545: } else if (sd->direction <= 0) {
546: scsi_emulate_cmd(sd);
547: scsi_start_transfer(sd);
548: if (!ScsiBus.status && ScsiBus.data_len > 0) {
549: #if RAW_SCSI_DEBUG
550: write_log(_T("raw_scsi: data in %d bytes waiting\n"), ScsiBus.data_len);
551: #endif
552: rs->bus_phase = SCSI_SIGNAL_PHASE_DATA_IN;
553: } else {
554: #if RAW_SCSI_DEBUG
555: write_log(_T("raw_scsi: no data, status = %d\n"), ScsiBus.status);
556: #endif
557: rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
558: }
559: }
560: }
561: break;
562: case SCSI_SIGNAL_PHASE_DATA_OUT:
563: #if RAW_SCSI_DEBUG > 2
564: write_log(_T("raw_scsi: write data byte %02x (%d/%d)\n"), data, ScsiBus.offset, ScsiBus.data_len);
565: #endif
566: if (scsi_send_data(sd, data)) {
567: #if RAW_SCSI_DEBUG
568: write_log(_T("raw_scsi: data out finished, %d bytes\n"), ScsiBus.data_len);
569: #endif
570: if (ScsiBus.dmawrite_to_fh)
571: {
572: int r;
573: r = fwrite(ScsiBus.buffer, 1, ScsiBus.data_len, ScsiBus.dmawrite_to_fh);
574: if (r != ScsiBus.data_len)
575: {
576: Log_Printf(LOG_ERROR, "Could not write bytes to HD image (%d/%d).\n",
577: r, ScsiBus.data_len);
578: ScsiBus.status = HD_STATUS_ERROR;
579: }
580: ScsiBus.dmawrite_to_fh = NULL;
581: }
582:
583: rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
584: }
585: break;
586: case SCSI_SIGNAL_PHASE_MESSAGE_OUT:
587: sd->msgout[ScsiBus.offset++] = data;
588: len = getmsglen(sd->msgout, ScsiBus.offset);
589: #if RAW_SCSI_DEBUG
590: write_log(_T("raw_scsi_put_data got message %02x (%d/%d)\n"), data, ScsiBus.offset, len);
591: #endif
592: if (ScsiBus.offset >= len) {
593: #if RAW_SCSI_DEBUG
594: write_log(_T("raw_scsi_put_data got message %02x (%d bytes)\n"), sd->msgout[0], len);
595: #endif
596: if ((sd->msgout[0] & (0x80 | 0x20)) == 0x80)
597: rs->msglun = sd->msgout[0] & 7;
598: scsi_start_transfer(sd);
599: rs->bus_phase = SCSI_SIGNAL_PHASE_COMMAND;
600: }
601: break;
602: default:
603: #if RAW_SCSI_DEBUG
604: write_log(_T("raw_scsi_put_data but bus phase is %d!\n"), rs->bus_phase);
605: #endif
606: break;
607: }
608: }
609:
610: static void raw_scsi_put_data(struct raw_scsi *rs, uae_u8 data, bool databusoutput)
611: {
612: rs->data_write = data;
613: if (!databusoutput)
614: return;
615: raw_scsi_write_data(rs, data);
616: }
617:
618: static void raw_scsi_set_ack(struct raw_scsi *rs, bool ack)
619: {
620: if (rs->ack != ack) {
621: rs->ack = ack;
622: if (!ack)
623: return;
624: if (rs->bus_phase < 0)
625: return;
626: if (!(rs->bus_phase & SCSI_IO_DIRECTION)) {
627: if (rs->databusoutput) {
628: raw_scsi_write_data(rs, rs->data_write);
629: }
630: } else {
631: raw_scsi_get_data_2(rs, true, false);
632: }
633: }
634: }
635:
636: static void Ncr5380_UpdateDmaAddrAndLen(uint32_t nDmaAddr, uint32_t nDataLen)
637: {
638: uint32_t nNewAddr = nDmaAddr + nDataLen;
639: uint32_t nNewLen;
640:
641: if (Config_IsMachineFalcon())
642: {
643: FDC_WriteDMAAddress(nNewAddr);
644: }
645: else
646: {
647: IoMem[0xff8701] = nNewAddr >> 24;
648: IoMem[0xff8703] = nNewAddr >> 16;
649: IoMem[0xff8705] = nNewAddr >> 8;
650: IoMem[0xff8707] = nNewAddr;
651:
652: nNewLen = (Uint32)IoMem[0xff8709] << 24 | IoMem[0xff870b] << 16
653: | IoMem[0xff870d] << 8 | IoMem[0xff870f];
654: assert(nDataLen <= nNewLen);
655: nNewLen -= nDataLen;
656: IoMem[0xff8709] = nNewLen >> 24;
657: IoMem[0xff870b] = nNewLen >> 16;
658: IoMem[0xff870d] = nNewLen >> 8;
659: IoMem[0xff870f] = nNewLen;
660: }
661: }
662:
663: static void dma_check(struct soft_scsi *ncr)
664: {
665: int i, nDataLen;
666: uint32_t nDmaAddr;
667:
668: // fprintf(stderr, "dma_check: dma_direction=%i data_len=%i/%i phase=%i %i active=%i \n",
669: // ncr->dma_direction, ScsiBus.offset, ScsiBus.data_len, ncr->rscsi.bus_phase, ncr->regs[3] & 7, ncr->dma_active);
670:
671: /* Don't do anything if nothing to transfer */
672: if (ScsiBus.data_len - ScsiBus.offset == 0 || !ncr->dma_active || !ncr->dma_direction)
673: return;
674:
675: if (Config_IsMachineFalcon())
676: {
677: /* Is DMA really active? */
678: if ((FDC_DMA_GetMode() & 0xc0) != 0x00)
679: return;
680: nDmaAddr = FDC_GetDMAAddress();
681: nDataLen = FDC_DMA_GetSectorCount() * 512;
682: }
683: else
684: {
685: if ((IoMem[0xff8715] & 2) == 0)
686: return;
687: nDmaAddr = (Uint32)IoMem[0xff8701] << 24 | IoMem[0xff8703] << 16
688: | IoMem[0xff8705] << 8 | IoMem[0xff8707];
689: nDataLen = (Uint32)IoMem[0xff8709] << 24 | IoMem[0xff870b] << 16
690: | IoMem[0xff870d] << 8 | IoMem[0xff870f];
691: }
692:
693: if (nDataLen > ScsiBus.data_len - ScsiBus.offset)
694: nDataLen = ScsiBus.data_len - ScsiBus.offset;
695:
696: if (ncr_soft_scsi.dma_direction < 0)
697: {
698: if (STMemory_CheckAreaType(nDmaAddr, nDataLen, ABFLAG_RAM | ABFLAG_ROM))
699: {
700: for (i = 0; i < nDataLen; i++)
701: {
702: uint8_t val = ncr5380_bget(ncr, 8);
703: STMemory_WriteByte(nDmaAddr + i, val);
704: }
705: ScsiBus.bDmaError = false;
706: }
707: else
708: {
709: ScsiBus.bDmaError = true;
710: ScsiBus.status = HD_STATUS_ERROR;
711: }
712:
713: if (Config_IsMachineFalcon())
714: {
715: /* Note that the Falcon's DMA chip seems to report an
716: * end address that is 16 bytes too high if the DATA IN
717: * phase was interrupted by a different phase, but the
718: * address is correct if there was no interruption. */
719: if (ScsiBus.offset < ScsiBus.data_len)
720: Ncr5380_UpdateDmaAddrAndLen(nDmaAddr, nDataLen + 16);
721: else
722: Ncr5380_UpdateDmaAddrAndLen(nDmaAddr, nDataLen);
723: }
724: else
725: {
726: int nRemainingBytes = IoMem[0xff8707] & 3;
727: Ncr5380_UpdateDmaAddrAndLen(nDmaAddr, nDataLen);
728: for (i = 0; i < nRemainingBytes; i++)
729: {
730: /* For more precise emulation, we should not
731: * pre-write the bytes to the STRam ... */
732: const Uint32 addr = nDmaAddr + nDataLen - nRemainingBytes;
733: IoMem[0xff8710 + i] = STMemory_ReadByte(addr + i);
734: }
735: }
736: }
737: else if (ncr_soft_scsi.dma_direction > 0 && ScsiBus.dmawrite_to_fh)
738: {
739: /* write - if allowed */
740: if (STMemory_CheckAreaType(nDmaAddr, nDataLen, ABFLAG_RAM | ABFLAG_ROM))
741: {
742: for (i = 0; i < nDataLen; i++)
743: {
744: uint8_t val = STMemory_ReadByte(nDmaAddr + i);
745: ncr5380_bput(ncr, 8, val);
746: }
747: }
748: else
749: {
750: Log_Printf(LOG_WARN, "SCSI DMA write uses invalid RAM range 0x%x+%i\n",
751: nDmaAddr, nDataLen);
752: ScsiBus.bDmaError = true;
753: ScsiBus.status = HD_STATUS_ERROR;
754: }
755: Ncr5380_UpdateDmaAddrAndLen(nDmaAddr, nDataLen);
756: }
757:
758: if (Config_IsMachineFalcon())
759: {
760: FDC_SetDMAStatus(ScsiBus.bDmaError); /* Mark DMA error */
761: FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
762: }
763: else
764: {
765: ncr->irq = true;
766: }
767:
768: if (ScsiBus.offset == ScsiBus.data_len)
769: {
770: ncr->dmac_active = 0;
771: ncr->dma_active = 0;
772: }
773: }
774:
775: static void ncr5380_set_irq(struct soft_scsi *scsi)
776: {
777: if (scsi->irq)
778: return;
779: scsi->irq = true;
780: #if 0 /* FIXME */
781: devices_rethink_all(ncr80_rethink);
782: if (scsi->delayed_irq)
783: x_do_cycles(2 * CYCLE_UNIT);
784: #endif
785: #if NCR5380_DEBUG_IRQ
786: write_log(_T("IRQ\n"));
787: #endif
788:
789: if (Config_IsMachineFalcon())
790: FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
791: }
792:
793: static void ncr5380_databusoutput(struct soft_scsi *scsi)
794: {
795: bool databusoutput = (scsi->regs[1] & 1) != 0;
796: struct raw_scsi *r = &scsi->rscsi;
797:
798: if (r->bus_phase >= 0 && (r->bus_phase & SCSI_IO_DIRECTION))
799: databusoutput = false;
800: raw_scsi_set_databus(r, databusoutput);
801: }
802:
803: static void ncr5380_check(struct soft_scsi *scsi)
804: {
805: ncr5380_databusoutput(scsi);
806: }
807:
808: static void ncr5380_check_phase(struct soft_scsi *scsi)
809: {
810: if (!(scsi->regs[2] & 2))
811: return;
812: if (scsi->regs[2] & 0x40)
813: return;
814: if (scsi->rscsi.bus_phase != (scsi->regs[3] & 7)) {
815: if (scsi->dma_controller) {
816: scsi->regs[5] |= 0x80; // end of dma
817: scsi->regs[3] |= 0x80; // last byte sent
818: }
819: ncr5380_set_irq(scsi);
820: }
821: }
822:
823: static void ncr5380_reset(struct soft_scsi *scsi)
824: {
825: memset(scsi->regs, 0, sizeof scsi->regs);
826: raw_scsi_reset_bus(scsi);
827: scsi->regs[1] = 0x80;
828: ncr5380_set_irq(scsi);
829: }
830:
831: static uae_u8 ncr5380_bget(struct soft_scsi *scsi, int reg)
832: {
833: if (reg > 8)
834: return 0;
835: uae_u8 v = scsi->regs[reg];
836: struct raw_scsi *r = &scsi->rscsi;
837: switch(reg)
838: {
839: case 1:
840: break;
841: case 4:
842: {
843: uae_u8 t = raw_scsi_get_signal_phase(r);
844: v = 0;
845: if (t & SCSI_IO_BUSY)
846: v |= 1 << 6;
847: if (t & SCSI_IO_REQ)
848: v |= 1 << 5;
849: if (t & SCSI_IO_SEL)
850: v |= 1 << 1;
851: if (r->bus_phase >= 0)
852: v |= r->bus_phase << 2;
853: if (scsi->regs[1] & 0x80)
854: v |= 0x80;
855: }
856: break;
857: case 5:
858: {
859: uae_u8 t = raw_scsi_get_signal_phase(r);
860: v &= (0x80 | 0x40 | 0x20 | 0x04);
861: if (t & SCSI_IO_ATN)
862: v |= 1 << 1;
863: if (r->bus_phase == (scsi->regs[3] & 7)) {
864: v |= 1 << 3;
865: }
866: if (scsi->irq) {
867: v |= 1 << 4;
868: }
869: if (scsi->dma_drq || (scsi->dma_active && !scsi->dma_controller && r->bus_phase == (scsi->regs[3] & 7))) {
870: scsi->dma_drq = true;
871: v |= 1 << 6;
872: }
873: if (scsi->regs[2] & 4) {
874: // monitor busy
875: if (r->bus_phase == SCSI_SIGNAL_PHASE_FREE) {
876: // any loss of busy = Busy error
877: // not just "unexpected" loss of busy
878: v |= 1 << 2;
879: scsi->dmac_active = false;
880: }
881: }
882: }
883: break;
884: case 0:
885: v = raw_scsi_get_data(r, false);
886: break;
887: case 6:
888: v = raw_scsi_get_data(r, scsi->dma_active);
889: ncr5380_check_phase(scsi);
890: break;
891: case 7:
892: scsi->irq = false;
893: if (Config_IsMachineFalcon())
894: FDC_ClearIRQ();
895: break;
896: case 8: // fake dma port
897: v = raw_scsi_get_data(r, true);
898: ncr5380_check_phase(scsi);
899: break;
900: }
901: ncr5380_check(scsi);
902: return v;
903: }
904:
905: void ncr5380_bput(struct soft_scsi *scsi, int reg, uae_u8 v)
906: {
907: if (reg > 8)
908: return;
909: bool dataoutput = (scsi->regs[1] & 1) != 0;
910: struct raw_scsi *r = &scsi->rscsi;
911: uae_u8 old = scsi->regs[reg];
912: scsi->regs[reg] = v;
913: switch(reg)
914: {
915: case 0:
916: {
917: r->data_write = v;
918: // assert data bus can be only active if direction is out
919: // and bus phase matches
920: if (r->databusoutput) {
921: if (((scsi->regs[2] & 2) && scsi->dma_active) || r->bus_phase < 0) {
922: raw_scsi_write_data(r, v);
923: ncr5380_check_phase(scsi);
924: }
925: }
926: }
927: break;
928: case 1:
929: {
930: scsi->regs[reg] &= ~((1 << 5) | (1 << 6));
931: scsi->regs[reg] |= old & ((1 << 5) | (1 << 6)); // AIP, LA
932: if (!(v & 0x80)) {
933: bool init = r->bus_phase < 0;
934: ncr5380_databusoutput(scsi);
935: if (init && !dataoutput && (v & 1) && (scsi->regs[2] & 1)) {
936: r->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
937: }
938: raw_scsi_set_signal_phase(r,
939: (v & (1 << 3)) != 0,
940: (v & (1 << 2)) != 0,
941: (v & (1 << 1)) != 0);
942: if (!(scsi->regs[2] & 2))
943: raw_scsi_set_ack(r, (v & (1 << 4)) != 0);
944: }
945: if (v & 0x80) { // RST
946: ncr5380_reset(scsi);
947: }
948: }
949: break;
950: case 2:
951: if ((v & 1) && !(old & 1)) { // Arbitrate
952: r->databusoutput = false;
953: raw_scsi_set_signal_phase(r, true, false, false);
954: scsi->regs[1] |= 1 << 6; // AIP
955: scsi->regs[1] &= ~(1 << 5); // LA
956: } else if (!(v & 1) && (old & 1)) {
957: scsi->regs[1] &= ~(1 << 6);
958: }
959: if (!(v & 2)) {
960: // end of dma and dma request
961: scsi->regs[5] &= ~(0x80 | 0x40);
962: scsi->dma_direction = 0;
963: scsi->dma_active = false;
964: scsi->dma_drq = false;
965: }
966: break;
967: case 5:
968: scsi->regs[reg] = old;
969: if (scsi->regs[2] & 2) {
970: scsi->dma_direction = 1;
971: scsi->dma_active = true;
972: dma_check(scsi);
973: }
974: #if NCR5380_DEBUG
975: write_log(_T("DMA send PC=%08x\n"), M68K_GETPC);
976: #endif
977: break;
978: case 6:
979: if (scsi->regs[2] & 2) {
980: scsi->dma_direction = 1;
981: scsi->dma_active = true;
982: scsi->dma_started = true;
983: dma_check(scsi);
984: }
985: #if NCR5380_DEBUG
986: write_log(_T("DMA target recv PC=%08x\n"), M68K_GETPC);
987: #endif
988: break;
989: case 7:
990: if (scsi->regs[2] & 2) {
991: scsi->dma_direction = -1;
992: scsi->dma_active = true;
993: scsi->dma_started = true;
994: dma_check(scsi);
995: }
996: #if NCR5380_DEBUG
997: write_log(_T("DMA initiator recv PC=%08x\n"), M68K_GETPC);
998: #endif
999: break;
1000: case 8: // fake dma port
1001: if (r->bus_phase == (scsi->regs[3] & 7)) {
1002: raw_scsi_put_data(r, v, true);
1003: }
1004: ncr5380_check_phase(scsi);
1005: break;
1006: }
1007: ncr5380_check(scsi);
1008: }
1009:
1010: /* ***** Hatari glue code below ***** */
1011:
1012: /**
1013: * return number of identified partitions on existing SCSI images
1014: */
1015: int Ncr5380_Init(void)
1016: {
1017: #if WITH_NCR5380
1018: int i, partitions = 0;
1019:
1020: memset(&ScsiBus, 0, sizeof(ScsiBus));
1021: ScsiBus.typestr = "SCSI";
1022: ScsiBus.buffer_size = 512;
1023: ScsiBus.buffer = malloc(ScsiBus.buffer_size);
1024: if (!ScsiBus.buffer)
1025: {
1026: perror("Ncr5380_Init");
1027: return 0;
1028: }
1029: for (i = 0; i < MAX_SCSI_DEVS; i++)
1030: {
1031: if (!ConfigureParams.Scsi[i].bUseDevice)
1032: continue;
1033: if (HDC_InitDevice(&ScsiBus.devs[i], ConfigureParams.Scsi[i].sDeviceFile, ConfigureParams.Scsi[i].nBlockSize) == 0)
1034: partitions += HDC_PartitionCount(ScsiBus.devs[i].image_file, TRACE_SCSI_CMD, NULL);
1035: }
1036: return partitions;
1037: #else
1038: return 0;
1039: #endif
1040: }
1041:
1042: void Ncr5380_UnInit(void)
1043: {
1044: #if WITH_NCR5380
1045: int i;
1046:
1047: for (i = 0; i < MAX_SCSI_DEVS; i++)
1048: {
1049: if (!ScsiBus.devs[i].enabled)
1050: continue;
1051: File_UnLock(ScsiBus.devs[i].image_file);
1052: fclose(ScsiBus.devs[i].image_file);
1053: ScsiBus.devs[i].image_file = NULL;
1054: ScsiBus.devs[i].enabled = false;
1055: }
1056: free(ScsiBus.buffer);
1057: ScsiBus.buffer = NULL;
1058: #endif
1059: }
1060:
1061: /**
1062: * Emulate external reset "pin": Clear registers etc.
1063: */
1064: void Ncr5380_Reset(void)
1065: {
1066: #if WITH_NCR5380
1067: int i;
1068:
1069: ncr5380_reset(&ncr_soft_scsi);
1070: bus_free(&ncr_soft_scsi.rscsi);
1071:
1072: for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1073: if (ScsiBus.devs[i].enabled) {
1074: ncr_soft_scsi.rscsi.device[i] = &ScsiBus.devs[i];
1075: // fprintf(stderr, "SCSI #%i enabled\n", i);
1076: }
1077: else
1078: {
1079: ncr_soft_scsi.rscsi.device[i] = NULL;
1080: }
1081: }
1082: #endif
1083: }
1084:
1085: /**
1086: * Write a command byte to the NCR 5380 SCSI controller
1087: */
1088: void Ncr5380_WriteByte(int addr, Uint8 byte)
1089: {
1090: #if WITH_NCR5380
1091: ncr5380_bput(&ncr_soft_scsi, addr, byte);
1092: #endif
1093: }
1094:
1095: /**
1096: * Read a command byte from the NCR 5380 SCSI controller
1097: */
1098: Uint8 Ncr5380_ReadByte(int addr)
1099: {
1100: #if WITH_NCR5380
1101: return ncr5380_bget(&ncr_soft_scsi, addr);
1102: #else
1103: return 0;
1104: #endif
1105: }
1106:
1107:
1108: void Ncr5380_DmaTransfer_Falcon(void)
1109: {
1110: dma_check(&ncr_soft_scsi);
1111: }
1112:
1113:
1114: void Ncr5380_IoMemTT_WriteByte(void)
1115: {
1116: while (nIoMemAccessSize > 0)
1117: {
1118: if (IoAccessBaseAddress & 1)
1119: {
1120: int addr = IoAccessBaseAddress / 2 & 0x7;
1121: Ncr5380_WriteByte(addr, IoMem[IoAccessBaseAddress]);
1122: }
1123: IoAccessBaseAddress++;
1124: nIoMemAccessSize--;
1125: }
1126: }
1127:
1128:
1129: void Ncr5380_IoMemTT_ReadByte(void)
1130: {
1131: while (nIoMemAccessSize > 0)
1132: {
1133: if (IoAccessBaseAddress & 1)
1134: {
1135: int addr = IoAccessBaseAddress / 2 & 0x7;
1136: IoMem[IoAccessBaseAddress] = Ncr5380_ReadByte(addr);
1137: }
1138: IoAccessBaseAddress++;
1139: nIoMemAccessSize--;
1140: }
1141: }
1142:
1143:
1144: void Ncr5380_TT_DMA_Ctrl_WriteWord(void)
1145: {
1146: if (IoMem[0xff8715] & 2)
1147: dma_check(&ncr_soft_scsi);
1148: }
1149:
1150:
1151: /**
1152: * This is a temporary hack until we've got proper emulation of the
1153: * 2nd MFP in the TT
1154: */
1155: void Ncr5380_TT_GPIP_ReadByte(void)
1156: {
1157: Uint8 val = 0x7f;
1158:
1159: if (ncr_soft_scsi.irq)
1160: val |= 0x80;
1161:
1162: IoMem[0xfffa81] = val;
1163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.