|
|
1.1.1.2 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.2 root 3: *
1.1 root 4: * Floppy disk emulation
5: *
1.1.1.11 root 6: * Copyright 1995 Hannu Rummukainen
7: * Copyright 1995-2001 Bernd Schmidt
8: * Copyright 2000, 2001 Toni Wilen
9: *
10: * High Density Drive Handling by Dr. Adil Temel (C) 2001 [[email protected]]
11: *
1.1 root 12: */
13:
1.1.1.2 root 14: #include <stdio.h>
15:
1.1 root 16: #include "sysconfig.h"
17: #include "sysdeps.h"
18:
19: #include "config.h"
20: #include "options.h"
1.1.1.12! root 21: #include "threaddep/thread.h"
1.1 root 22: #include "memory.h"
23: #include "events.h"
24: #include "custom.h"
25: #include "ersatz.h"
26: #include "disk.h"
27: #include "gui.h"
28: #include "zfile.h"
1.1.1.2 root 29: #include "autoconf.h"
30: #include "newcpu.h"
31: #include "xwin.h"
32: #include "osemu.h"
33: #include "execlib.h"
1.1.1.11 root 34: #include "savestate.h"
1.1.1.2 root 35:
1.1.1.3 root 36: #define FLOPPY_GAP_LEN 360
1.1.1.7 root 37: /* writable track length with normal 2us bitcell/300RPM motor */
38: #define FLOPPY_WRITE_LEN 6250
39: /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */
40: #define NORMAL_FLOPPY_SPEED 1830
41:
42: static int floppy_speed = NORMAL_FLOPPY_SPEED;
43:
44: #undef DISK_DEBUG
1.1.1.11 root 45: #undef DEBUG_DRIVE_ID
1.1.1.7 root 46:
47: /* UAE-1ADF (ADF_EXT2)
48: * W reserved
49: * W number of tracks (default 2*80=160)
50: *
51: * W reserved
52: * W type, 0=normal AmigaDOS track, 1 = raw MFM
53: * L available space for track in bytes
54: * L track length in bits
55: */
1.1 root 56:
1.1.1.11 root 57: static int side, direction, writing;
1.1.1.12! root 58: static uae_u8 selected = 15, disabled;
1.1 root 59:
1.1.1.11 root 60: static uae_u8 *writebuffer[544 * 22];
1.1.1.7 root 61:
62: typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype;
1.1 root 63: typedef struct {
1.1.1.3 root 64: uae_u16 len;
65: uae_u32 offs;
1.1.1.7 root 66: int bitlen;
67: unsigned int sync;
68: image_tracktype type;
1.1 root 69: } trackid;
70:
1.1.1.2 root 71: #define MAX_TRACKS 328
72:
1.1.1.11 root 73: #define DRIVE_ID_NONE 0xFFFFFFFF
74: #define DRIVE_ID_35DD 0x00000000
75: #define DRIVE_ID_35HD 0xAAAAAAAA
76: #define DRIVE_ID_525DD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */
77:
1.1.1.7 root 78: typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2 } drive_filetype;
1.1 root 79: typedef struct {
80: FILE *diskfile;
81: drive_filetype filetype;
1.1.1.2 root 82: trackid trackdata[MAX_TRACKS];
1.1.1.7 root 83: int buffered_cyl, buffered_side;
84: int cyl;
1.1 root 85: int motoroff;
1.1.1.7 root 86: int state;
1.1 root 87: int wrprot;
1.1.1.11 root 88: uae_u16 bigmfmbuf[0x8000];
1.1 root 89: int mfmpos;
1.1.1.7 root 90: int tracklen;
91: int trackspeed;
92: int dmalen;
93: int num_tracks, num_secs;
1.1.1.3 root 94: int dskchange;
95: int dskchange_time;
1.1.1.10 root 96: int dskready;
97: int dskready_time;
1.1.1.11 root 98: int steplimit;
99: int ddhd; /* 1=DD 2=HD */
100: int drive_id_scnt; /* drive id shift counter */
101: unsigned long drive_id; /* drive id to be reported */
1.1.1.12! root 102: char newname[256]; /* storage space for new filename during eject delay */
1.1 root 103: } drive;
104:
1.1.1.11 root 105: static drive floppy[4];
106:
107: /* Keeps track of whether the Amiga program seems to be using the data coming
108: in from the disk; if this remains 0 for several seconds, we stop calling
109: disk_doupdate_read, even if the motor is still on. This is a rather large
110: performance win. This contains the number of frames since we last accessed
111: the disk. */
112: static int disk_data_used;
113:
114: #ifdef DEBUG_DRIVE_ID
115: static char *drive_id_name(drive *drv)
116: {
117: switch(drv->drive_id)
118: {
119: case DRIVE_ID_35HD : return "3.5HD";
120: case DRIVE_ID_525DD: return "5.25DD";
121: case DRIVE_ID_35DD : return "3.5DD";
122: }
123: return "UNKNOWN";
124: }
125: #endif
126:
127: /* Simulate exact behaviour of an A3000T 3.5 HD disk drive.
128: * The drive reports to be a 3.5 DD drive whenever there is no
129: * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported
130: * when a real 3.5 HD disk is inserted. -Adil
131: */
132: static void drive_settype_id(drive *drv)
133: {
134: if (!drv->diskfile || drv->num_secs == 11) {
135: /* Double density */
136: drv->drive_id = DRIVE_ID_35DD;
137: drv->ddhd = 1;
138: } else {
139: /* High density */
140: drv->drive_id = DRIVE_ID_35HD;
141: drv->ddhd = 2;
142: }
143: drv->drive_id_scnt = 0;
144: #ifdef DEBUG_DRIVE_ID
145: write_log("drive_settype_id: DF%d: set to %s\n",drv-floppy, drive_id_name(drv));
146: #endif
147: }
1.1 root 148:
1.1.1.7 root 149: /* code for track display */
1.1.1.8 root 150: static void update_drive_gui (int num)
1.1.1.7 root 151: {
1.1.1.8 root 152: drive *drv = floppy + num;
153:
1.1.1.7 root 154: if (drv->state == gui_data.drive_motor[num]
155: && drv->cyl == gui_data.drive_track[num]
156: && ((writing && gui_data.drive_writing[num])
157: || (!writing && !gui_data.drive_writing[num]))) {
158: return;
159: }
160: gui_data.drive_motor[num] = drv->state;
161: gui_data.drive_track[num] = drv->cyl;
162: if (!gui_data.drive_writing[num])
163: gui_data.drive_writing[num] = writing;
1.1.1.8 root 164: gui_ledstate &= ~(2 << num);
165: if (drv->state)
166: gui_ledstate |= 2 << num;
1.1.1.7 root 167: gui_led (num + 1, gui_data.drive_motor[num]);
168: }
169:
170: static void drive_fill_bigbuf (drive * drv);
1.1 root 171:
1.1.1.3 root 172: FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
1.1 root 173: {
1.1.1.4 root 174: FILE *f = zfile_open (fname, "r+b");
1.1.1.3 root 175: if (f) {
176: if (wrprot)
177: *wrprot = 0;
1.1 root 178: } else {
1.1.1.3 root 179: if (wrprot)
180: *wrprot = 1;
1.1.1.4 root 181: f = zfile_open (fname, "rb");
1.1 root 182: }
1.1.1.3 root 183: if (!leave_open)
1.1.1.4 root 184: zfile_close (f);
1.1.1.3 root 185: return f;
186: }
187:
1.1.1.7 root 188: static int drive_insert (drive * drv, int dnum, const char *fname)
1.1.1.3 root 189: {
1.1.1.7 root 190: unsigned char buffer[2 + 2 + 4 + 4];
191: trackid *tid;
1.1.1.3 root 192:
193: drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
1.1.1.6 root 194: if (drv->diskfile == 0) {
1.1.1.7 root 195: drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
196: drv->trackspeed = floppy_speed;
1.1.1.3 root 197: return 0;
1.1.1.6 root 198: }
1.1.1.3 root 199: strncpy (currprefs.df[dnum], fname, 255);
200: currprefs.df[dnum][255] = 0;
201: strncpy (changed_prefs.df[dnum], fname, 255);
202: changed_prefs.df[dnum][255] = 0;
1.1.1.7 root 203: gui_filename (dnum, fname);
1.1.1.3 root 204:
1.1.1.7 root 205: fread (buffer, sizeof (char), 8, drv->diskfile);
206: if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
207: int offs;
208: int i;
209:
210: fread (buffer, 1, 4, drv->diskfile);
211: drv->num_tracks = buffer[2] * 256 + buffer[3];
212: drv->filetype = ADF_EXT2;
213: drv->num_secs = 11;
1.1.1.10 root 214: offs = 8 + 2 + 2 + drv->num_tracks * (2 + 2 + 4 + 4);
1.1.1.7 root 215:
216: for (i = 0; i < drv->num_tracks; i++) {
217: tid = &drv->trackdata[i];
218: fread (buffer, 2 + 2 + 4 + 4, 1, drv->diskfile);
219: tid->type = buffer[2] * 256 + buffer[3];
220: tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
221: tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
222: tid->offs = offs;
223: if (tid->type == TRACK_AMIGADOS) {
224: if (tid->len > 20000)
225: drv->num_secs = 22;
226: }
227: offs += tid->len;
228: }
229: } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
230: int offs = 160 * 4 + 8;
1.1 root 231: int i;
1.1.1.3 root 232:
233: drv->filetype = ADF_EXT1;
1.1.1.2 root 234: drv->num_tracks = 160;
235: drv->num_secs = 11;
1.1.1.3 root 236:
1.1.1.7 root 237: drv->wrprot = 1; /* write to adf_ext1 not implemented */
238: for (i = 0; i < 160; i++) {
239: tid = &drv->trackdata[i];
240: fread (buffer, 4, 1, drv->diskfile);
241: tid->sync = buffer[0] * 256 + buffer[1];
242: tid->len = buffer[2] * 256 + buffer[3];
243: tid->offs = offs;
244: if (tid->sync == 0) {
245: tid->type = TRACK_AMIGADOS;
246: tid->bitlen = 0;
247: } else {
248: tid->type = TRACK_RAW1;
249: tid->bitlen = tid->len * 8;
250: }
251: offs += tid->len;
1.1 root 252: }
253: } else {
1.1.1.7 root 254: int i;
1.1.1.3 root 255:
256: drv->filetype = ADF_NORMAL;
1.1.1.2 root 257:
1.1.1.7 root 258: fseek (drv->diskfile, 0, SEEK_END);
1.1.1.4 root 259: i = ftell (drv->diskfile);
1.1.1.7 root 260: fseek (drv->diskfile, 0, SEEK_SET);
1.1.1.3 root 261:
1.1.1.2 root 262: /* High-density disk? */
1.1.1.7 root 263: if (i >= 160 * 22 * 512)
264: drv->num_tracks = i / (512 * (drv->num_secs = 22));
1.1.1.2 root 265: else
1.1.1.7 root 266: drv->num_tracks = i / (512 * (drv->num_secs = 11));
1.1.1.3 root 267:
1.1.1.2 root 268: if (drv->num_tracks > MAX_TRACKS)
1.1.1.3 root 269: write_log ("Your diskfile is too big!\n");
1.1.1.7 root 270: for (i = 0; i < drv->num_tracks; i++) {
271: tid = &drv->trackdata[i];
272: tid->type = TRACK_AMIGADOS;
273: tid->len = 512 * drv->num_secs;
274: tid->bitlen = 0;
275: tid->offs = i * 512 * drv->num_secs;
1.1 root 276: }
277: }
1.1.1.11 root 278: drive_settype_id(drv); /* Set DD or HD drive */
1.1.1.7 root 279: drv->buffered_side = 2; /* will force read */
1.1.1.6 root 280: drive_fill_bigbuf (drv);
1.1.1.3 root 281: return 1;
1.1 root 282: }
283:
1.1.1.7 root 284: static int drive_empty (drive * drv)
1.1.1.2 root 285: {
1.1.1.3 root 286: return drv->diskfile == 0;
1.1.1.2 root 287: }
288:
1.1.1.7 root 289: static void drive_step (drive * drv)
1.1 root 290: {
1.1.1.11 root 291: if (drv->steplimit)
292: return;
293: /* A1200's floppy drive needs at least 30 raster lines between steps
294: * but we'll use very small value for better compatibility with faster CPU emulation
295: * (stupid trackloaders with CPU delay loops)
296: */
297: drv->steplimit = 2;
1.1.1.12! root 298: if (!drive_empty (drv))
! 299: drv->dskchange = 0;
1.1 root 300: if (direction) {
1.1.1.7 root 301: if (drv->cyl)
302: drv->cyl--;
1.1.1.11 root 303: /* else
304: write_log("program tried to step beyond track zero\n");
305: "no-click" programs does that
306: */
307: } else {
1.1.1.7 root 308: if (drv->cyl < 83)
309: drv->cyl++;
1.1.1.11 root 310: else
311: write_log("program tried to step over track 83\n");
1.1 root 312: }
313:
1.1.1.7 root 314: #if 0 && defined DISK_DEBUG
315: write_log ("track %d\n", drv->cyl);
316: #endif
317: }
1.1 root 318:
1.1.1.7 root 319: static int drive_track0 (drive * drv)
1.1 root 320: {
1.1.1.3 root 321: return drv->cyl == 0;
1.1 root 322: }
323:
1.1.1.7 root 324: static int drive_writeprotected (drive * drv)
1.1 root 325: {
1.1.1.3 root 326: return drv->wrprot || drv->diskfile == NULL;
1.1 root 327: }
328:
1.1.1.7 root 329: static int drive_running (drive * drv)
1.1 root 330: {
1.1.1.3 root 331: return !drv->motoroff;
1.1 root 332: }
333:
1.1.1.7 root 334: static void drive_motor (drive * drv, int off)
1.1 root 335: {
1.1.1.12! root 336: /* A value of 5 works out to a guaranteed delay of 1/2 of a second
1.1.1.10 root 337: Higher values are dangerous, e.g. a value of 8 breaks the RSI
338: demo. */
1.1.1.11 root 339: if (drv->motoroff && !off) {
1.1.1.12! root 340: drv->dskready_time = 5;
1.1.1.11 root 341: disk_data_used = 0;
342: drv->drive_id_scnt = 0; /* Reset id shift reg counter */
343: #ifdef DEBUG_DRIVE_ID
344: write_log("drive_motor: Selected DF%d: reset id shift reg.\n",drv-floppy);
345: #endif
346: }
1.1 root 347: drv->motoroff = off;
1.1.1.10 root 348: if (drv->motoroff) {
349: drv->dskready = 0;
350: drv->dskready_time = 0;
351: }
1.1 root 352: }
353:
1.1.1.7 root 354: static void read_floppy_data (drive * drv, int track, int offset, unsigned char *dst, int len)
355: {
356: trackid *ti;
357:
358: ti = &drv->trackdata[track];
359: fseek (drv->diskfile, ti->offs + offset, SEEK_SET);
360: fread (dst, 1, len, drv->diskfile);
361: }
362:
363: /* Megalomania does not like zero MFM words... */
364: static void mfmcode (uae_u16 * mfm, int words)
365: {
1.1.1.8 root 366: uae_u32 lastword = 0;
1.1.1.7 root 367:
368: while (words--) {
1.1.1.8 root 369: uae_u32 v = *mfm;
370: uae_u32 lv = (lastword << 16) | v;
371: uae_u32 nlv = 0x55555555 & ~lv;
372: uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
373:
374: *mfm++ = v | mfmbits;
375: lastword = v;
1.1.1.7 root 376: }
377: }
378:
379: static void drive_fill_bigbuf (drive * drv)
1.1 root 380: {
1.1.1.7 root 381: int tr = drv->cyl * 2 + side;
382: trackid *ti = drv->trackdata + tr;
1.1.1.3 root 383:
1.1.1.7 root 384: if (!drv->diskfile || tr >= drv->num_tracks) {
1.1.1.11 root 385: drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8;
1.1.1.7 root 386: drv->trackspeed = floppy_speed;
1.1.1.11 root 387: memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2 * drv->ddhd);
1.1.1.2 root 388: return;
389: }
1.1.1.3 root 390: if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
391: return;
392:
1.1.1.7 root 393: if (ti->type == TRACK_AMIGADOS) {
1.1 root 394: /* Normal AmigaDOS format track */
1.1.1.7 root 395: int sec;
396: drv->tracklen = (drv->num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
397: memset (drv->bigmfmbuf, 0xaa, FLOPPY_GAP_LEN * 2);
1.1.1.2 root 398:
399: for (sec = 0; sec < drv->num_secs; sec++) {
1.1.1.3 root 400: uae_u8 secbuf[544];
1.1 root 401: int i;
1.1.1.7 root 402: uae_u16 *mfmbuf = drv->bigmfmbuf + 544 * sec + FLOPPY_GAP_LEN;
403: uae_u32 deven, dodd;
404: uae_u32 hck = 0, dck = 0;
1.1.1.3 root 405:
1.1 root 406: secbuf[0] = secbuf[1] = 0x00;
407: secbuf[2] = secbuf[3] = 0xa1;
408: secbuf[4] = 0xff;
409: secbuf[5] = tr;
410: secbuf[6] = sec;
1.1.1.7 root 411: secbuf[7] = drv->num_secs - sec;
1.1 root 412:
1.1.1.7 root 413: for (i = 8; i < 24; i++)
1.1 root 414: secbuf[i] = 0;
1.1.1.3 root 415:
1.1.1.7 root 416: read_floppy_data (drv, tr, sec * 512, &secbuf[32], 512);
1.1.1.3 root 417:
1.1 root 418: mfmbuf[0] = mfmbuf[1] = 0xaaaa;
419: mfmbuf[2] = mfmbuf[3] = 0x4489;
1.1.1.3 root 420:
421: deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
1.1 root 422: | (secbuf[6] << 8) | (secbuf[7]));
423: dodd = deven >> 1;
1.1.1.7 root 424: deven &= 0x55555555;
425: dodd &= 0x55555555;
1.1.1.3 root 426:
1.1 root 427: mfmbuf[4] = dodd >> 16;
428: mfmbuf[5] = dodd;
1.1.1.7 root 429: mfmbuf[6] = deven >> 16;
1.1 root 430: mfmbuf[7] = deven;
1.1.1.3 root 431:
1.1 root 432: for (i = 8; i < 48; i++)
1.1.1.6 root 433: mfmbuf[i] = 0xaaaa;
1.1.1.7 root 434: for (i = 0; i < 512; i += 4) {
435: deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
436: | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
1.1 root 437: dodd = deven >> 1;
1.1.1.7 root 438: deven &= 0x55555555;
439: dodd &= 0x55555555;
440: mfmbuf[(i >> 1) + 32] = dodd >> 16;
441: mfmbuf[(i >> 1) + 33] = dodd;
442: mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
443: mfmbuf[(i >> 1) + 256 + 33] = deven;
444: }
445:
446: for (i = 4; i < 24; i += 2)
447: hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
448:
449: deven = dodd = hck;
450: dodd >>= 1;
451: mfmbuf[24] = dodd >> 16;
452: mfmbuf[25] = dodd;
453: mfmbuf[26] = deven >> 16;
454: mfmbuf[27] = deven;
455:
456: for (i = 32; i < 544; i += 2)
457: dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
458:
459: deven = dodd = dck;
460: dodd >>= 1;
461: mfmbuf[28] = dodd >> 16;
462: mfmbuf[29] = dodd;
463: mfmbuf[30] = deven >> 16;
464: mfmbuf[31] = deven;
465: mfmcode (mfmbuf + 4, 544 - 4);
1.1 root 466: }
1.1.1.7 root 467: #ifdef DISK_DEBUG
468: write_log ("amigados read track %d\n", tr);
469: #endif
1.1 root 470: } else {
471: int i;
1.1.1.7 root 472: int base_offset = ti->type == TRACK_RAW ? 0 : 1;
473: drv->tracklen = ti->bitlen + 16 * base_offset;
474: drv->bigmfmbuf[0] = ti->sync;
1.1.1.10 root 475: read_floppy_data (drv, tr, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8);
476: for (i = base_offset; i < (drv->tracklen + 15) / 16; i++) {
1.1.1.7 root 477: uae_u16 *mfm = drv->bigmfmbuf + i;
478: uae_u8 *data = (uae_u8 *) mfm;
479: *mfm = 256 * *data + *(data + 1);
1.1 root 480: }
1.1.1.7 root 481: #if 0 && defined DISK_DEBUG
482: write_log ("rawtrack %d\n", tr);
483: #endif
1.1 root 484: }
1.1.1.3 root 485: drv->buffered_side = side;
486: drv->buffered_cyl = drv->cyl;
1.1.1.7 root 487: drv->trackspeed = floppy_speed * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN);
1.1 root 488: }
489:
1.1.1.7 root 490: /* Update ADF_EXT2 track header */
491: static void diskfile_update (drive * drv, int len, uae_u8 type)
1.1 root 492: {
1.1.1.7 root 493: trackid *ti;
494: int track;
495: uae_u8 buf[2 + 2 + 4 + 4], *zerobuf;
1.1.1.3 root 496:
1.1.1.7 root 497: if (drv->filetype != ADF_EXT2)
498: return;
1.1.1.6 root 499:
1.1.1.7 root 500: track = drv->cyl * 2 + side;
501: ti = &drv->trackdata[track];
502: ti->bitlen = len;
503: fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET);
504: memset (buf, 0, sizeof buf);
505: ti->type = type;
506: buf[3] = ti->type;
507: do_put_mem_long ((uae_u32 *) (buf + 4), ti->len);
508: do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen);
509: fwrite (buf, sizeof (buf), 1, drv->diskfile);
510: if (ti->len > (len + 7) / 8) {
511: zerobuf = malloc (ti->len);
512: memset (zerobuf, 0, ti->len);
513: fseek (drv->diskfile, ti->offs, SEEK_SET);
514: fwrite (zerobuf, 1, ti->len, drv->diskfile);
515: free (zerobuf);
516: }
517: #ifdef DISK_DEBUG
518: write_log ("track %d, raw track length %d written (total size %d)\n", track, (ti->bitlen + 7) / 8, ti->len);
519: #endif
1.1 root 520: }
521:
522: #define MFMMASK 0x55555555
1.1.1.7 root 523: static uae_u32 getmfmlong (uae_u16 * mbuf)
1.1 root 524: {
525: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
526: }
527:
1.1.1.7 root 528: static int drive_write_adf_amigados (drive * drv)
1.1 root 529: {
530: int i, secwritten = 0;
1.1.1.11 root 531: int fwlen = FLOPPY_WRITE_LEN * drv->ddhd;
532: int length = 2 * fwlen;
533: int drvsec= drv->num_secs;
1.1.1.3 root 534: uae_u32 odd, even, chksum, id, dlong;
1.1.1.7 root 535: uae_u8 *secdata;
1.1.1.3 root 536: uae_u8 secbuf[544];
1.1.1.7 root 537: uae_u16 *mbuf = drv->bigmfmbuf;
1.1.1.3 root 538: uae_u16 *mend = mbuf + length;
1.1.1.11 root 539: char sectable[22];
1.1.1.7 root 540: memset (sectable, 0, sizeof (sectable));
1.1.1.11 root 541: memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
1.1 root 542: mend -= (4 + 16 + 8 + 512);
1.1.1.11 root 543: while (secwritten < drvsec) {
1.1 root 544: int trackoffs;
1.1.1.3 root 545:
1.1 root 546: do {
547: while (*mbuf++ != 0x4489) {
1.1.1.4 root 548: if (mbuf >= mend)
1.1.1.7 root 549: return 1;
1.1 root 550: }
551: } while (*mbuf++ != 0x4489);
1.1.1.3 root 552:
1.1.1.4 root 553: odd = getmfmlong (mbuf);
554: even = getmfmlong (mbuf + 2);
1.1.1.3 root 555: mbuf += 4;
1.1 root 556: id = (odd << 1) | even;
1.1.1.3 root 557:
1.1 root 558: trackoffs = (id & 0xff00) >> 8;
1.1.1.11 root 559: if (trackoffs + 1 > drvsec) {
1.1.1.7 root 560: if (drv->filetype == ADF_EXT2)
561: return 2;
1.1.1.5 root 562: write_log ("Disk write: weird sector number %d\n", trackoffs);
1.1 root 563: continue;
564: }
565: chksum = odd ^ even;
1.1.1.4 root 566: for (i = 0; i < 4; i++) {
1.1.1.7 root 567: odd = getmfmlong (mbuf);
568: even = getmfmlong (mbuf + 8);
1.1 root 569: mbuf += 2;
1.1.1.3 root 570:
1.1 root 571: dlong = (odd << 1) | even;
1.1.1.7 root 572: if (dlong) {
573: if (drv->filetype == ADF_EXT2)
574: return 6;
1.1.1.4 root 575: secwritten = -200;
1.1.1.7 root 576: }
1.1 root 577: chksum ^= odd ^ even;
1.1.1.7 root 578: } /* could check here if the label is nonstandard */
1.1 root 579: mbuf += 8;
1.1.1.7 root 580: odd = getmfmlong (mbuf);
581: even = getmfmlong (mbuf + 2);
582: mbuf += 4;
583: if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) {
584: if (drv->filetype == ADF_EXT2)
585: return 3;
586: write_log ("Disk write: checksum error on sector %d header\n", trackoffs);
1.1 root 587: continue;
588: }
1.1.1.7 root 589: odd = getmfmlong (mbuf);
590: even = getmfmlong (mbuf + 2);
591: mbuf += 4;
1.1 root 592: chksum = (odd << 1) | even;
593: secdata = secbuf + 32;
1.1.1.7 root 594: for (i = 0; i < 128; i++) {
595: odd = getmfmlong (mbuf);
596: even = getmfmlong (mbuf + 256);
597: mbuf += 2;
1.1 root 598: dlong = (odd << 1) | even;
1.1.1.7 root 599: *secdata++ = dlong >> 24;
600: *secdata++ = dlong >> 16;
601: *secdata++ = dlong >> 8;
602: *secdata++ = dlong;
1.1 root 603: chksum ^= odd ^ even;
604: }
605: mbuf += 256;
606: if (chksum) {
1.1.1.7 root 607: if (drv->filetype == ADF_EXT2)
608: return 4;
609: write_log ("Disk write: sector %d, data checksum error\n", trackoffs);
1.1 root 610: continue;
611: }
1.1.1.7 root 612: sectable[trackoffs] = 1;
1.1 root 613: secwritten++;
1.1.1.7 root 614: memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
1.1 root 615: }
1.1.1.7 root 616: if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
617: return 5;
1.1.1.3 root 618: if (secwritten == 0)
619: write_log ("Disk write in unsupported format\n");
1.1 root 620: if (secwritten < 0)
1.1.1.3 root 621: write_log ("Disk write: sector labels ignored\n");
1.1.1.7 root 622:
1.1.1.11 root 623: diskfile_update (drv, drvsec * 512 * 8, TRACK_AMIGADOS);
624: for (i = 0; i < drvsec; i++) {
1.1.1.7 root 625: fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET);
626: fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile);
627: }
628:
629: return 0;
1.1 root 630: }
631:
1.1.1.7 root 632: /* write raw track to disk file */
633: static int drive_write_ext2 (drive * drv)
634: {
635: trackid *ti;
636: int len, track, i;
1.1 root 637:
1.1.1.7 root 638: track = drv->cyl * 2 + side;
639: ti = &drv->trackdata[track];
640: len = (drv->tracklen + 7) / 8;
641: if (len > ti->len) {
642: write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", track, ti->len, len);
643: return 0;
644: }
645: diskfile_update (drv, drv->tracklen, TRACK_RAW);
646: for (i = 0; i < drv->trackdata[track].len / 2; i++) {
647: uae_u16 *mfm = drv->bigmfmbuf + i;
648: uae_u8 *data = (uae_u8 *) mfm;
649: *mfm = 256 * *data + *(data + 1);
650: }
651: fseek (drv->diskfile, ti->offs, SEEK_SET);
652: fwrite (drv->bigmfmbuf, 1, len, drv->diskfile);
653: return 1;
654: }
655:
656: static void drive_write_data (drive * drv)
1.1 root 657: {
1.1.1.7 root 658: int ret;
659: if (drive_writeprotected (drv))
660: return;
661: switch (drv->filetype) {
662: case ADF_NORMAL:
663: drive_write_adf_amigados (drv);
664: break;
665: case ADF_EXT1:
666: write_log ("writing to ADF_EXT1 not supported\n");
667: return;
668: case ADF_EXT2:
669: ret = drive_write_adf_amigados (drv);
670: if (ret) {
671: /*write_log("not an amigados track (error %d), writing as raw track\n",ret); */
672: drive_write_ext2 (drv);
673: }
674: break;
675: }
676: drv->buffered_side = 2; /* will force read */
677: }
678:
679: static void drive_eject (drive * drv)
680: {
681: if (!drive_empty (drv))
1.1.1.4 root 682: zfile_close (drv->diskfile);
1.1 root 683: drv->diskfile = 0;
1.1.1.12! root 684: drv->dskchange = 1;
1.1.1.11 root 685: drive_settype_id(drv); /* Back to 35 DD */
1.1.1.12! root 686: #ifdef DISK_DEBUG
! 687: write_log ("eject drive %d\n", drv - &floppy[0]);
! 688: #endif
1.1 root 689: }
690:
1.1.1.3 root 691: /* We use this function if we have no Kickstart ROM.
1.1 root 692: * No error checking - we trust our luck. */
1.1.1.3 root 693: void DISK_ersatz_read (int tr, int sec, uaecptr dest)
1.1 root 694: {
1.1.1.7 root 695: uae_u8 *dptr = get_real_address (dest);
696: fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET);
1.1.1.3 root 697: fread (dptr, 1, 512, floppy[0].diskfile);
1.1 root 698: }
699:
1.1.1.4 root 700: void disk_eject (int num)
1.1 root 701: {
1.1.1.7 root 702: gui_filename (num, "");
703: drive_eject (floppy + num);
1.1.1.3 root 704: *currprefs.df[num] = *changed_prefs.df[num] = 0;
1.1.1.12! root 705: floppy[num].newname[0] = 0;
1.1 root 706: }
707:
1.1.1.4 root 708: void disk_insert (int num, const char *name)
1.1 root 709: {
1.1.1.12! root 710: drive *drv = floppy + num;
! 711: if (name[0] == 0) {
! 712: disk_eject (num);
! 713: } else if (!drive_empty(drv) || drv->dskchange_time > 0) {
! 714: drive_eject (drv);
! 715: /* set dskchange_time, disk_insert() will be
! 716: * called from DISK_check_change() after 1 second delay
! 717: * this makes sure that all programs detect disk change correctly
! 718: */
! 719: strcpy (drv->newname, name);
! 720: drv->dskchange_time = 10; /* 1 second disk change delay */
! 721: } else {
! 722: /* no delayed insert if drive is already empty */
! 723: drive_insert (drv, num, name);
! 724: }
1.1 root 725: }
726:
1.1.1.3 root 727: void DISK_check_change (void)
728: {
729: int i;
730:
731: for (i = 0; i < 4; i++) {
1.1.1.12! root 732: drive *drv = floppy + i;
! 733: if (strcmp (currprefs.df[i], changed_prefs.df[i])) {
! 734: strcpy (currprefs.df[i], changed_prefs.df[i]);
! 735: disk_insert (i, currprefs.df[i]);
! 736: }
! 737: /* emulate drive motor turn on time */
! 738: if (drv->dskready_time) {
! 739: drv->dskready_time--;
! 740: if (drv->dskready_time == 0)
! 741: drv->dskready = 1;
! 742: }
! 743: /* delay until new disk image is inserted */
! 744: if (drv->dskchange_time) {
! 745: drv->dskchange_time--;
! 746: if (drv->dskchange_time == 0) {
! 747: drive_insert (drv, i, drv->newname);
! 748: #ifdef DISK_DEBUG
! 749: write_log ("delayed insert, drive %d, image '%s'\n", i, drv->newname);
! 750: #endif
! 751: drv->newname[0] = 0;
1.1.1.3 root 752: }
753: }
754: }
755: }
756:
1.1.1.4 root 757: int disk_empty (int num)
1.1 root 758: {
1.1.1.4 root 759: return drive_empty (floppy + num);
1.1 root 760: }
761:
1.1.1.11 root 762: static int step;
1.1.1.10 root 763:
1.1.1.4 root 764: void DISK_select (uae_u8 data)
1.1 root 765: {
1.1.1.11 root 766: int step_pulse, lastselected;
1.1 root 767: int dr;
1.1.1.11 root 768: static uae_u8 prevdata;
1.1.1.3 root 769:
1.1.1.10 root 770: lastselected = selected;
1.1 root 771: selected = (data >> 3) & 15;
1.1.1.12! root 772: selected |= disabled;
! 773: if (selected != lastselected)
! 774: disk_data_used = 1;
1.1.1.3 root 775: side = 1 - ((data >> 2) & 1);
776:
1.1 root 777: direction = (data >> 1) & 1;
778: step_pulse = data & 1;
779: if (step != step_pulse) {
780: step = step_pulse;
1.1.1.11 root 781: if (step) {
1.1.1.7 root 782: for (dr = 0; dr < 4; dr++) {
1.1 root 783: if (!(selected & (1 << dr))) {
1.1.1.4 root 784: drive_step (floppy + dr);
1.1 root 785: }
786: }
787: }
788: }
1.1.1.7 root 789: for (dr = 0; dr < 4; dr++) {
1.1.1.11 root 790: /* motor on/off workings tested with small assembler code on real Amiga 1200. */
791: /* motor flipflop is set only when drive select goes from high to low */
792: if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) {
793: if (floppy[dr].motoroff) {
1.1.1.12! root 794: /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */
1.1.1.11 root 795: if ((prevdata & 0x80) == 0 || (data & 0x80) == 0)
796: drive_motor (floppy + dr, 0);
797: } else {
798: /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect)
799: -> turn motor off */
800: if (prevdata & 0x80)
801: drive_motor (floppy + dr, 1);
802: }
1.1 root 803: }
804: }
805: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 806: floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
1.1.1.8 root 807: update_drive_gui (dr);
1.1 root 808: }
1.1.1.11 root 809: prevdata = data;
1.1 root 810: }
811:
1.1.1.4 root 812: uae_u8 DISK_status (void)
1.1 root 813: {
1.1.1.3 root 814: uae_u8 st = 0x3c;
1.1 root 815: int dr;
1.1.1.3 root 816:
1.1.1.7 root 817: for (dr = 0; dr < 4; dr++) {
1.1.1.3 root 818: drive *drv = floppy + dr;
1.1 root 819: if (!(selected & (1 << dr))) {
1.1.1.7 root 820: if (drive_running (drv)) {
1.1.1.11 root 821: if (drv->dskready)
1.1.1.7 root 822: st &= ~0x20;
1.1.1.12! root 823: } else {
1.1.1.11 root 824: /* report drive ID */
825: if (drv->drive_id & (1L << (31 - drv->drive_id_scnt)))
826: st |= 0x20;
827: else
828: st &= ~0x20;
829: #ifdef DEBUG_DRIVE_ID
830: write_log("DISK_status: sel %d id %s [0x%08lx, bit #%02d: %d]\n",
831: dr,drive_id_name(drv), drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, st & 0x20 ? 1:0);
1.1.1.12! root 832: #endif
1.1.1.11 root 833: /* Left shift id reg bit should be done with each LH transition of drv_sel */
834: drv->drive_id_scnt++;
835: drv->drive_id_scnt &= 31;
1.1 root 836: }
1.1.1.12! root 837: if (drive_track0 (drv))
1.1.1.7 root 838: st &= ~0x10;
1.1.1.12! root 839: if (drive_writeprotected (drv))
1.1.1.7 root 840: st &= ~8;
1.1.1.12! root 841: if (drv->dskchange)
! 842: st &= ~4;
! 843: }
1.1 root 844: }
845: return st;
846: }
847:
1.1.1.7 root 848: #define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */
849:
850: #define DISK_INDEXSYNC 1
851: #define DISK_WORDSYNC 2
852:
853: static uae_u16 dskbytr_tab[MAX_DISK_WORDS_PER_LINE * 2 + 1];
854: static uae_u8 dskbytr_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
1.1.1.11 root 855: static short wordsync_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
1.1.1.7 root 856: static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
857: static uae_u8 disk_sync[MAXHPOS];
858: static int disk_sync_cycle;
859: static int dskdmaen, dsklength;
860: static uae_u16 dsksync;
861: static uae_u32 dskpt;
862:
863: static void disk_dmafinished (void)
864: {
865: INTREQ (0x8002);
1.1.1.12! root 866: dskdmaen = 1; /* surprise, it isn't set to zero! */
1.1.1.11 root 867: #ifdef DISK_DEBUG
1.1.1.12! root 868: write_log("disk dma finished %08.8X\n", dskpt);
1.1.1.11 root 869: #endif
870: }
1.1.1.7 root 871:
872: static void disk_events (int last)
873: {
874: eventtab[ev_disk].active = 0;
1.1.1.11 root 875: for (disk_sync_cycle = last; disk_sync_cycle < maxhpos; disk_sync_cycle++) {
1.1.1.7 root 876: if (disk_sync[disk_sync_cycle]) {
1.1.1.10 root 877: eventtab[ev_disk].oldcycles = get_cycles ();
878: eventtab[ev_disk].evtime = get_cycles () + (disk_sync_cycle - last) * CYCLE_UNIT;
1.1.1.7 root 879: eventtab[ev_disk].active = 1;
880: events_schedule ();
881: return;
1.1 root 882: }
883: }
884: }
885:
1.1.1.7 root 886: extern void cia_diskindex (void);
1.1.1.3 root 887:
1.1.1.7 root 888: void DISK_handler (void)
889: {
890: eventtab[ev_disk].active = 0;
1.1.1.11 root 891: if (disk_sync[disk_sync_cycle] & DISK_WORDSYNC)
1.1.1.7 root 892: INTREQ (0x9000);
1.1.1.11 root 893: if (disk_sync[disk_sync_cycle] & DISK_INDEXSYNC)
1.1.1.7 root 894: cia_diskindex ();
895: disk_sync[disk_sync_cycle] = 0;
896: disk_events (disk_sync_cycle);
897: }
1.1.1.3 root 898:
1.1.1.12! root 899: static int dma_enable, bitoffset;
! 900: static uae_u32 word;
1.1 root 901:
1.1.1.7 root 902: /* Always carried through to the next line. */
903: static int disk_hpos;
1.1.1.2 root 904:
1.1.1.7 root 905: /* emulate disk write dma for full horizontal line */
906: static void disk_doupdate_write (drive * drv)
907: {
908: int hpos = disk_hpos;
1.1.1.11 root 909: while (hpos < (maxhpos << 8)) {
1.1.1.7 root 910: drv->mfmpos++;
911: drv->mfmpos %= drv->tracklen;
912: if (!drv->mfmpos) {
913: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
914: disk_events (0);
915: }
916: if ((dmacon & 0x210) == 0x210 && dskdmaen == 3) {
917: bitoffset++;
918: bitoffset &= 15;
919: if (!bitoffset) {
920: drv->bigmfmbuf[drv->mfmpos >> 4] = get_word (dskpt);
921: dskpt += 2;
922: dsklength--;
923: if (dsklength == 0) {
924: disk_dmafinished ();
925: drive_write_data (drv);
926: }
1.1 root 927: }
928: }
1.1.1.7 root 929: hpos += drv->trackspeed;
1.1 root 930: }
1.1.1.11 root 931: disk_hpos = hpos - (maxhpos << 8);
1.1 root 932: }
933:
1.1.1.7 root 934: /* get one bit from MFM bit stream */
1.1.1.12! root 935: static uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u32 word)
1.1 root 936: {
1.1.1.7 root 937: uae_u16 *buf;
1.1 root 938:
1.1.1.7 root 939: buf = &mfmbuf[mfmpos >> 4];
940: word <<= 1;
941: word |= (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
942: return word;
1.1 root 943: }
944:
1.1.1.11 root 945: #define WORDSYNC_CYCLES 7 /* (~7 * 280ns = 2us) */
946:
1.1.1.7 root 947: /* emulate disk read dma for full horizontal line */
948: static void disk_doupdate_read (drive * drv)
949: {
950: int hpos = disk_hpos;
1.1.1.12! root 951: int is_sync = 0;
1.1.1.11 root 952: int j = 0, k = 1, l = 0;
1.1.1.12! root 953: uae_u16 synccheck;
1.1.1.11 root 954: static int dskbytr_last = 0, wordsync_last = -1;
1.1.1.7 root 955:
1.1.1.11 root 956: dskbytr_tab[0] = dskbytr_tab[dskbytr_last];
957:
958: if (wordsync_last >= 0 && maxhpos - wordsync_cycle[wordsync_last] < WORDSYNC_CYCLES)
959: wordsync_cycle[l++] = (maxhpos - wordsync_cycle[wordsync_last]) - WORDSYNC_CYCLES;
960: wordsync_last = -1;
961:
962: while (hpos < (maxhpos << 8)) {
963: if (drv->dskready)
964: word = getonebit (drv->bigmfmbuf, drv->mfmpos, word);
965: else
966: word <<= 1;
1.1.1.7 root 967: drv->mfmpos++;
968: drv->mfmpos %= drv->tracklen;
1.1.1.12! root 969: if (!drv->mfmpos) {
1.1.1.7 root 970: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
971: is_sync = 1;
972: }
1.1.1.12! root 973: if (bitoffset == 31 && dma_enable) {
! 974: dma_tab[j++] = (word >> 16) & 0xffff;
1.1.1.7 root 975: if (j == MAX_DISK_WORDS_PER_LINE - 1) {
976: write_log ("Bug: Disk DMA buffer overflow!\n");
977: j--;
978: }
979: }
1.1.1.12! root 980: if (bitoffset == 15 || bitoffset == 23 || bitoffset == 31) {
! 981: dskbytr_tab[k] = (word >> 8) & 0xff;
1.1.1.11 root 982: dskbytr_tab[k] |= 0x8000;
983: dskbytr_last = k;
1.1.1.7 root 984: dskbytr_cycle[k++] = hpos >> 8;
985: }
1.1.1.12! root 986: synccheck = (word >> 8) & 0xffff;
! 987: if (synccheck == dsksync) {
! 988: if (adkcon & 0x400) {
! 989: if (bitoffset != 23 || !dma_enable)
! 990: bitoffset = 7;
! 991: dma_enable = 1;
! 992: }
! 993: wordsync_last = l;
! 994: wordsync_cycle[l++] = hpos >> 8;
! 995: disk_sync[hpos >> 8] |= DISK_WORDSYNC;
! 996: is_sync = 1;
! 997: }
1.1.1.11 root 998: bitoffset++;
1.1.1.12! root 999: if (bitoffset == 32) bitoffset = 16;
1.1.1.7 root 1000: hpos += drv->trackspeed;
1001: }
1002: dma_tab[j] = 0xffffffff;
1.1.1.11 root 1003: dskbytr_cycle[k] = 255;
1004: wordsync_cycle[l] = 255;
1.1.1.7 root 1005: if (is_sync)
1006: disk_events (0);
1007:
1.1.1.11 root 1008: disk_hpos = hpos - (maxhpos << 8);
1.1.1.7 root 1009: }
1010:
1011: /* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
1012: (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
1013: data at cycle 0. I don't think any program cares about this small difference.
1.1.1.12! root 1014:
! 1015: We must handle dsklength = 0 because some copy protections use it to detect
! 1016: wordsync without transferring any data.
1.1.1.7 root 1017: */
1018: static void dodmafetch (void)
1.1 root 1019: {
1.1.1.7 root 1020: int i;
1021:
1022: i = 0;
1023: while (dma_tab[i] != 0xffffffff && dskdmaen == 2 && (dmacon & 0x210) == 0x210) {
1.1.1.12! root 1024: if (dsklength > 0) {
! 1025: put_word (dskpt, dma_tab[i++]);
! 1026: dskpt += 2;
! 1027: dsklength--;
! 1028: }
1.1.1.7 root 1029: if (dsklength == 0) {
1030: disk_dmafinished ();
1031: break;
1032: }
1033: }
1034: dma_tab[0] = 0xffffffff;
1.1 root 1035: }
1036:
1.1.1.7 root 1037: static void DISK_start (void)
1.1.1.6 root 1038: {
1039: int dr;
1.1.1.7 root 1040:
1.1.1.6 root 1041: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 1042: drive *drv = &floppy[dr];
1043: if (!(selected & (1 << dr))) {
1044: int tr = drv->cyl * 2 + side;
1045: trackid *ti = drv->trackdata + tr;
1046:
1047: if (dskdmaen == 3) {
1.1.1.11 root 1048: drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 8 * 2;
1.1.1.7 root 1049: drv->trackspeed = floppy_speed;
1050: }
1051: /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read
1052: from the start. */
1053: if (ti->type == TRACK_RAW1)
1.1.1.12! root 1054: drv->mfmpos = 0;
1.1.1.6 root 1055: }
1056: }
1.1.1.12! root 1057: dma_enable = (adkcon & 0x400) ? 0 : 1;
1.1.1.7 root 1058: word = 0;
1059: bitoffset = 0;
1060: dma_tab[0] = 0xffffffff;
1.1.1.6 root 1061: }
1062:
1.1.1.7 root 1063: static int linecounter;
1064:
1065: void DISK_update (void)
1.1 root 1066: {
1067: int dr;
1.1.1.7 root 1068:
1.1.1.6 root 1069: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 1070: drive *drv = &floppy[dr];
1.1.1.11 root 1071: if (drv->steplimit)
1072: drv->steplimit--;
1.1.1.7 root 1073: }
1074: if (linecounter) {
1075: linecounter--;
1076: if (! linecounter)
1077: disk_dmafinished ();
1078: return;
1079: }
1080:
1081: dodmafetch ();
1082:
1083: for (dr = 0; dr < 4; dr++) {
1084: drive *drv = &floppy[dr];
1085: if (drv->motoroff)
1086: continue;
1087: if (selected & (1 << dr)) {
1.1.1.11 root 1088: drv->mfmpos += (maxhpos << 8) / drv->trackspeed;
1.1.1.7 root 1089: drv->mfmpos %= drv->tracklen;
1090: continue;
1.1 root 1091: }
1.1.1.11 root 1092: drive_fill_bigbuf (drv);
1093: drv->mfmpos %= drv->tracklen;
1094: if (dskdmaen > 1)
1095: disk_data_used = 0;
1096:
1.1.1.7 root 1097: if (dskdmaen == 3)
1098: disk_doupdate_write (drv);
1.1.1.12! root 1099: else if (1 || disk_data_used < MAXVPOS * 50 * 2) {
1.1.1.11 root 1100: disk_data_used++;
1.1.1.7 root 1101: disk_doupdate_read (drv);
1.1.1.11 root 1102: }
1.1.1.7 root 1103: return;
1.1 root 1104: }
1105: }
1.1.1.6 root 1106:
1.1.1.7 root 1107: void DSKLEN (uae_u16 v, int hpos)
1.1.1.6 root 1108: {
1.1.1.7 root 1109: if (v & 0x8000) {
1110: dskdmaen = dskdmaen == 1 ? 2 : 1;
1111: } else {
1112: /* Megalomania does this */
1113: #if 0
1114: if (dskdmaen == 2)
1115: write_log ("warning: Disk read DMA aborted, %d words left\n", dsklength);
1116: #endif
1117: if (dskdmaen == 3)
1118: write_log ("warning: Disk write DMA aborted, %d words left\n", dsklength);
1119: dskdmaen = 0;
1120: }
1.1.1.12! root 1121: dsklength = v & 0x3ffe;
1.1.1.7 root 1122: if (dskdmaen <= 1)
1123: return;
1124: if (v & 0x4000)
1125: dskdmaen = 3;
1126: #ifdef DISK_DEBUG
1127: {
1128: int dr;
1129: for (dr = 0; dr < 4; dr++) {
1130: drive *drv = &floppy[dr];
1131: if (drv->motoroff)
1132: continue;
1133: if ((selected & (1 << dr)) == 0)
1134: break;
1135: }
1136: if (dr == 4)
1137: write_log ("disk DMA started, but no drive ready!\n");
1138: else
1139: write_log ("disk %s DMA started for %d words (%08.8X) sync=%04.4X track %d\n",
1140: dskdmaen == 3 ? "write" : "read", dsklength, dskpt,
1141: (adkcon & 0x400) ? dsksync : 0xffff,
1142: floppy[dr].cyl * 2 + side);
1143: }
1144: #endif
1145: /* Megalomania does not work if DSKLEN write is delayed to next horizontal line,
1146: also it seems some copy protections require this fix */
1147: DISK_start ();
1.1.1.6 root 1148:
1.1.1.7 root 1149: /* Try to make floppy access from Kickstart faster. */
1150: if (dskdmaen != 2)
1151: return;
1152: {
1153: int dr;
1154: uaecptr pc = m68k_getpc ();
1155: if ((pc & 0xF80000) != 0xF80000)
1156: return;
1157: for (dr = 0; dr < 4; dr++) {
1158: drive *drv = &floppy[dr];
1159: if (drv->motoroff)
1160: continue;
1161: if ((selected & (1 << dr)) == 0) {
1162: int pos = drv->mfmpos & ~15;
1163: int i;
1164:
1.1.1.11 root 1165: drive_fill_bigbuf (drv);
1.1.1.7 root 1166: if (adkcon & 0x400) {
1167: for (i = 0; i < drv->tracklen; i += 16) {
1168: pos += 16;
1169: pos %= drv->tracklen;
1.1.1.11 root 1170: if (drv->bigmfmbuf[pos >> 4] == dsksync) {
1171: /* must skip first disk sync marker */
1.1.1.12! root 1172: pos += 16;
1.1.1.11 root 1173: pos %= drv->tracklen;
1.1.1.7 root 1174: break;
1.1.1.11 root 1175: }
1.1.1.7 root 1176: }
1177: if (i >= drv->tracklen)
1178: return;
1179: }
1180: while (dsklength-- > 0) {
1181: put_word (dskpt, drv->bigmfmbuf[pos >> 4]);
1182: dskpt += 2;
1183: pos += 16;
1184: pos %= drv->tracklen;
1.1.1.6 root 1185: }
1.1.1.7 root 1186: INTREQ (0x9000);
1187: linecounter = 2;
1188: dskdmaen = 0;
1189: return;
1.1.1.6 root 1190: }
1191: }
1.1.1.7 root 1192: }
1.1.1.6 root 1193: }
1194:
1.1.1.11 root 1195: /* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */
1.1.1.7 root 1196:
1197: uae_u16 DSKBYTR (int hpos)
1.1.1.6 root 1198: {
1.1.1.7 root 1199: uae_u16 v;
1200: int i;
1201:
1202: i = 0;
1.1.1.11 root 1203: while (hpos > dskbytr_cycle[i + 1])
1.1.1.7 root 1204: i++;
1205: v = dskbytr_tab[i];
1206: dskbytr_tab[i] &= ~0x8000;
1.1.1.11 root 1207: if (wordsync_cycle[0] != 255) {
1208: i = 0;
1.1.1.12! root 1209: while (hpos < wordsync_cycle[i])
! 1210: i++;
! 1211: if (hpos - wordsync_cycle[i] <= WORDSYNC_CYCLES)
1.1.1.11 root 1212: v |= 0x1000;
1213: }
1.1.1.7 root 1214: if (dskdmaen && (dmacon & 0x210) == 0x210)
1215: v |= 0x4000;
1216: if (dskdmaen == 3)
1217: v |= 0x2000;
1.1.1.11 root 1218:
1219: disk_data_used = 0;
1220:
1.1.1.7 root 1221: return v;
1222: }
1223:
1.1.1.11 root 1224: /* not a real hardware register */
1.1.1.7 root 1225: uae_u16 DSKDATR (int hpos)
1226: {
1.1.1.11 root 1227: return 0;
1.1.1.7 root 1228: }
1229:
1230: void DSKSYNC (uae_u16 v)
1231: {
1232: dsksync = v;
1233: }
1234:
1235: void DSKDAT (uae_u16 v)
1236: {
1237: static int count = 0;
1238: if (count < 5) {
1239: count++;
1240: write_log ("DSKDAT written. Not good.");
1241: if (count == 5)
1242: write_log ("(further messages suppressed)");
1243:
1244: write_log ("\n");
1.1.1.6 root 1245: }
1246: }
1.1.1.7 root 1247: void DSKPTH (uae_u16 v)
1248: {
1249: dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16);
1250: }
1.1.1.6 root 1251:
1.1.1.7 root 1252: void DSKPTL (uae_u16 v)
1.1.1.6 root 1253: {
1.1.1.7 root 1254: dskpt = (dskpt & ~0xffff) | (v);
1.1.1.6 root 1255: }
1256:
1.1.1.7 root 1257: void DISK_init (void)
1258: {
1.1.1.11 root 1259: int dr;
1.1.1.7 root 1260:
1261: dma_tab[0] = 0xffffffff;
1.1.1.11 root 1262: dskbytr_cycle[0] = 0;
1263: dskbytr_cycle[1] = 255;
1264: wordsync_cycle[0] = 255;
1.1.1.7 root 1265:
1.1.1.11 root 1266: for (dr = 0; dr < 4; dr++) {
1267: drive *drv = &floppy[dr];
1.1.1.12! root 1268: /* reset all drive types to 3.5 DD */
1.1.1.11 root 1269: drive_settype_id (drv);
1270: if (!drive_insert (drv, dr, currprefs.df[dr]))
1271: disk_eject (dr);
1.1.1.8 root 1272: }
1.1.1.7 root 1273: if (disk_empty (0))
1274: write_log ("No disk in drive 0.\n");
1275: }
1276:
1.1.1.8 root 1277: void DISK_reset (void)
1278: {
1279: int i;
1280: disk_hpos = 0;
1.1.1.11 root 1281: disk_data_used = 0;
1.1.1.12! root 1282: disabled = 0;
1.1.1.8 root 1283: for (i = 0; i < 4; i++) {
1.1.1.12! root 1284: if (i >= currprefs.nr_floppies) {
! 1285: disabled |= 1 << i;
! 1286: floppy[i].motoroff = 1;
! 1287: }
1.1.1.8 root 1288: }
1289: }
1290:
1.1.1.7 root 1291: void dumpdisk (void)
1292: {
1293: int i;
1294: for (i = 0; i < 4; i++) {
1295: drive *drv = &floppy[i];
1296: printf ("Drive %d: motor %s cylinder %2d selected %d\n", i, drv->motoroff ? "off" : " on", drv->cyl, selected & (1 << i));
1297: }
1298: }
1.1.1.11 root 1299:
1300: /* Disk save/restore code */
1301:
1302: void DISK_save_custom (uae_u32 *pdskpt, uae_u16 *pdsklength, uae_u16 *pdsksync, uae_u16 *pdskdatr, uae_u16 *pdskbytr)
1303: {
1304: if(pdskpt) *pdskpt = dskpt;
1305: if(pdsklength) *pdsklength = dsklength;
1306: if(pdsksync) *pdsksync = dsksync;
1307: if(pdskdatr) *pdskdatr = 0;
1308: if(pdskbytr) *pdskbytr = dskbytr_tab[0];
1309: }
1310:
1311: void DISK_restore_custom (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskdatr, uae_u16 pdskbytr)
1312: {
1313: dskpt = pdskpt;
1314: dsklength = pdsklength;
1315: dskbytr_tab[0] = pdskbytr;
1316: }
1317:
1318: uae_u8 *restore_disk(int num,uae_u8 *src)
1319: {
1320: drive *drv;
1321:
1322: drv = &floppy[num];
1323: drv->drive_id = restore_u32 ();
1324: drv->motoroff = restore_u8 () ? 0 : 1;
1325: drv->cyl = restore_u8 ();
1326: drv->dskready = restore_u8 ();
1327: drv->drive_id_scnt = restore_u8 ();
1328: drv->mfmpos = restore_u32 ();
1329: restore_u32 ();
1330: strncpy(currprefs.df[num],src,255);
1331: src+=strlen(src)+1;
1332:
1333: return src;
1334: }
1335:
1336: uae_u8 *save_disk(int num,int *len)
1337: {
1338: uae_u8 *dstbak,*dst;
1339: drive *drv;
1340:
1341: drv = &floppy[num];
1342: dstbak = dst = malloc (2+1+1+1+1+4+4+256);
1343: save_u32 (drv->drive_id); /* drive type ID */
1344: save_u8 (drv->motoroff ? 0:1); /* motor state */
1345: save_u8 (drv->cyl); /* cylinder */
1346: save_u8 (drv->dskready); /* dskready */
1347: save_u8 (drv->drive_id_scnt); /* id mode position */
1348: save_u32 (drv->mfmpos); /* disk position */
1349: save_u32 (0); /* CRC of disk image */
1350: strcpy (dst, currprefs.df[num]);/* image name */
1351: dst += strlen(dst) + 1;
1352:
1353: *len = dst - dstbak;
1354: return dstbak;
1355: }
1356:
1357: /* internal floppy controller variables */
1358:
1359: uae_u8 *restore_floppy(uae_u8 *src)
1360: {
1361: word = restore_u16();
1362: bitoffset = restore_u8();
1.1.1.12! root 1363: dma_enable = restore_u8();
1.1.1.11 root 1364: disk_hpos = restore_u8();
1365: dskdmaen = restore_u8();
1.1.1.12! root 1366: word |= restore_u16() << 16;
1.1.1.11 root 1367:
1368: return src;
1369: }
1370:
1371: uae_u8 *save_floppy(int *len)
1372: {
1373: uae_u8 *dstbak, *dst;
1374:
1375: /* flush dma buffer before saving */
1376: dodmafetch();
1377:
1.1.1.12! root 1378: dstbak = dst = malloc(2+1+1+1+1+2);
! 1379: save_u16 (word); /* current fifo (low word) */
1.1.1.11 root 1380: save_u8 (bitoffset); /* dma bit offset */
1.1.1.12! root 1381: save_u8 (dma_enable); /* disk sync found */
1.1.1.11 root 1382: save_u8 (disk_hpos); /* next bit read position */
1383: save_u8 (dskdmaen); /* dma status */
1.1.1.12! root 1384: save_u16 (word >> 16); /* current fifo (high word) */
1.1.1.11 root 1385:
1386: *len = dst - dstbak;
1387: return dstbak;
1388: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.