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