|
|
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.4 root 6: * Copyright 1995 Bernd Schmidt, Hannu Rummukainen
1.1 root 7: */
8:
1.1.1.2 root 9: #include <stdio.h>
10:
1.1 root 11: #include "sysconfig.h"
12: #include "sysdeps.h"
13:
14: #include "config.h"
15: #include "options.h"
1.1.1.3 root 16: #include "threaddep/penguin.h"
1.1 root 17: #include "memory.h"
18: #include "events.h"
19: #include "custom.h"
20: #include "ersatz.h"
21: #include "disk.h"
22: #include "gui.h"
23: #include "zfile.h"
1.1.1.2 root 24: #include "autoconf.h"
25: #include "newcpu.h"
26: #include "xwin.h"
27: #include "osemu.h"
28: #include "execlib.h"
29:
1.1.1.3 root 30: #define FLOPPY_GAP_LEN 360
1.1.1.7 root 31: /* writable track length with normal 2us bitcell/300RPM motor */
32: #define FLOPPY_WRITE_LEN 6250
33: /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */
34: #define NORMAL_FLOPPY_SPEED 1830
35:
36: static int floppy_speed = NORMAL_FLOPPY_SPEED;
37:
38: #undef DISK_DEBUG
39:
40: /* UAE-1ADF (ADF_EXT2)
41: * W reserved
42: * W number of tracks (default 2*80=160)
43: *
44: * W reserved
45: * W type, 0=normal AmigaDOS track, 1 = raw MFM
46: * L available space for track in bytes
47: * L track length in bits
48: */
1.1 root 49:
1.1.1.7 root 50: static int side, direction, step, writing;
1.1.1.3 root 51: static uae_u8 selected = 15;
1.1 root 52: static int dskready;
53:
1.1.1.7 root 54: static uae_u8 *writebuffer[544 * 11];
55:
56: typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype;
1.1 root 57: typedef struct {
1.1.1.3 root 58: uae_u16 len;
59: uae_u32 offs;
1.1.1.7 root 60: int bitlen;
61: unsigned int sync;
62: image_tracktype type;
1.1 root 63: } trackid;
64:
1.1.1.2 root 65: #define MAX_TRACKS 328
66:
1.1.1.7 root 67: typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2 } drive_filetype;
1.1 root 68: typedef struct {
69: FILE *diskfile;
70: drive_filetype filetype;
1.1.1.2 root 71: trackid trackdata[MAX_TRACKS];
1.1.1.7 root 72: int buffered_cyl, buffered_side;
73: int cyl;
1.1 root 74: int motoroff;
1.1.1.7 root 75: int state;
76: int disabled;
1.1 root 77: int wrprot;
1.1.1.3 root 78: uae_u16 bigmfmbuf[0x4000];
1.1 root 79: int mfmpos;
1.1.1.7 root 80: int mfmpos_hsync;
81: int tracklen;
82: int trackspeed;
83: int dmalen;
84: int num_tracks, num_secs;
1.1.1.3 root 85: /* dskchange is set to a small number when a disk is removed. At a step
86: * impulse, it is reset if there is a new disk in the drive or counted
87: * down to 1 if the drive contains a disk. DISK_check_change will only
88: * insert a new disk when dskchange is 1, or if the dskchange_time timer
89: * expires. The last condition can happen if AmigaOS isn't running and a
90: * game/demo doesn't use the step motor to check for a new disk.
91: */
92: int dskchange;
93: int dskchange_time;
1.1 root 94: } drive;
95:
96: drive floppy[4];
97:
1.1.1.7 root 98: /* code for track display */
1.1.1.8 root 99: static void update_drive_gui (int num)
1.1.1.7 root 100: {
1.1.1.8 root 101: drive *drv = floppy + num;
102:
1.1.1.7 root 103: if (drv->state == gui_data.drive_motor[num]
104: && drv->cyl == gui_data.drive_track[num]
105: && ((writing && gui_data.drive_writing[num])
106: || (!writing && !gui_data.drive_writing[num]))) {
107: return;
108: }
109: gui_data.drive_motor[num] = drv->state;
110: gui_data.drive_track[num] = drv->cyl;
111: if (!gui_data.drive_writing[num])
112: gui_data.drive_writing[num] = writing;
1.1.1.8 root 113: gui_ledstate &= ~(2 << num);
114: if (drv->state)
115: gui_ledstate |= 2 << num;
1.1.1.7 root 116: gui_led (num + 1, gui_data.drive_motor[num]);
117: }
118:
119: static void drive_fill_bigbuf (drive * drv);
1.1 root 120:
1.1.1.3 root 121: FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
1.1 root 122: {
1.1.1.4 root 123: FILE *f = zfile_open (fname, "r+b");
1.1.1.3 root 124: if (f) {
125: if (wrprot)
126: *wrprot = 0;
1.1 root 127: } else {
1.1.1.3 root 128: if (wrprot)
129: *wrprot = 1;
1.1.1.4 root 130: f = zfile_open (fname, "rb");
1.1 root 131: }
1.1.1.3 root 132: if (!leave_open)
1.1.1.4 root 133: zfile_close (f);
1.1.1.3 root 134: return f;
135: }
136:
1.1.1.7 root 137: static int drive_insert (drive * drv, int dnum, const char *fname)
1.1.1.3 root 138: {
1.1.1.7 root 139: unsigned char buffer[2 + 2 + 4 + 4];
140: trackid *tid;
1.1.1.3 root 141:
142: drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
1.1.1.6 root 143: if (drv->diskfile == 0) {
1.1.1.7 root 144: drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
145: drv->trackspeed = floppy_speed;
1.1.1.3 root 146: return 0;
1.1.1.6 root 147: }
1.1.1.3 root 148: strncpy (currprefs.df[dnum], fname, 255);
149: currprefs.df[dnum][255] = 0;
150: strncpy (changed_prefs.df[dnum], fname, 255);
151: changed_prefs.df[dnum][255] = 0;
1.1.1.7 root 152: gui_filename (dnum, fname);
1.1.1.3 root 153:
1.1.1.7 root 154: fread (buffer, sizeof (char), 8, drv->diskfile);
155: if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
156: int offs;
157: int i;
158:
159: fread (buffer, 1, 4, drv->diskfile);
160: drv->num_tracks = buffer[2] * 256 + buffer[3];
161: drv->filetype = ADF_EXT2;
162: drv->num_secs = 11;
163: offs = 8 + drv->num_tracks * (2 + 2 + 4 + 4);
164:
165: for (i = 0; i < drv->num_tracks; i++) {
166: tid = &drv->trackdata[i];
167: fread (buffer, 2 + 2 + 4 + 4, 1, drv->diskfile);
168: tid->type = buffer[2] * 256 + buffer[3];
169: tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
170: tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
171: tid->offs = offs;
172: if (tid->type == TRACK_AMIGADOS) {
173: if (tid->len > 20000)
174: drv->num_secs = 22;
175: }
176: offs += tid->len;
177: }
178: } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
179: int offs = 160 * 4 + 8;
1.1 root 180: int i;
1.1.1.3 root 181:
182: drv->filetype = ADF_EXT1;
1.1.1.2 root 183: drv->num_tracks = 160;
184: drv->num_secs = 11;
1.1.1.3 root 185:
1.1.1.7 root 186: drv->wrprot = 1; /* write to adf_ext1 not implemented */
187: for (i = 0; i < 160; i++) {
188: tid = &drv->trackdata[i];
189: fread (buffer, 4, 1, drv->diskfile);
190: tid->sync = buffer[0] * 256 + buffer[1];
191: tid->len = buffer[2] * 256 + buffer[3];
192: tid->offs = offs;
193: if (tid->sync == 0) {
194: tid->type = TRACK_AMIGADOS;
195: tid->bitlen = 0;
196: } else {
197: tid->type = TRACK_RAW1;
198: tid->bitlen = tid->len * 8;
199: }
200: offs += tid->len;
1.1 root 201: }
202: } else {
1.1.1.7 root 203: int i;
1.1.1.3 root 204:
205: drv->filetype = ADF_NORMAL;
1.1.1.2 root 206:
1.1.1.7 root 207: fseek (drv->diskfile, 0, SEEK_END);
1.1.1.4 root 208: i = ftell (drv->diskfile);
1.1.1.7 root 209: fseek (drv->diskfile, 0, SEEK_SET);
1.1.1.3 root 210:
1.1.1.2 root 211: /* High-density disk? */
1.1.1.7 root 212: if (i >= 160 * 22 * 512)
213: drv->num_tracks = i / (512 * (drv->num_secs = 22));
1.1.1.2 root 214: else
1.1.1.7 root 215: drv->num_tracks = i / (512 * (drv->num_secs = 11));
1.1.1.3 root 216:
1.1.1.2 root 217: if (drv->num_tracks > MAX_TRACKS)
1.1.1.3 root 218: write_log ("Your diskfile is too big!\n");
1.1.1.7 root 219: for (i = 0; i < drv->num_tracks; i++) {
220: tid = &drv->trackdata[i];
221: tid->type = TRACK_AMIGADOS;
222: tid->len = 512 * drv->num_secs;
223: tid->bitlen = 0;
224: tid->offs = i * 512 * drv->num_secs;
1.1 root 225: }
226: }
1.1.1.7 root 227: drv->buffered_side = 2; /* will force read */
1.1.1.6 root 228: drive_fill_bigbuf (drv);
1.1.1.3 root 229: return 1;
1.1 root 230: }
231:
1.1.1.7 root 232: static int drive_empty (drive * drv)
1.1.1.2 root 233: {
1.1.1.3 root 234: return drv->diskfile == 0;
1.1.1.2 root 235: }
236:
1.1.1.7 root 237: static void drive_step (drive * drv)
1.1 root 238: {
1.1.1.7 root 239: if (!drive_empty (drv))
1.1.1.3 root 240: drv->dskchange = 0;
241: else if (drv->dskchange > 1) {
242: /* printf("Stepping...\n");
243: drv->dskchange--;*/
244: }
1.1 root 245: if (direction) {
1.1.1.7 root 246: if (drv->cyl)
247: drv->cyl--;
1.1 root 248: } else {
1.1.1.7 root 249: if (drv->cyl < 83)
250: drv->cyl++;
1.1 root 251: }
252:
1.1.1.7 root 253: #if 0 && defined DISK_DEBUG
254: write_log ("track %d\n", drv->cyl);
255: #endif
256: }
1.1 root 257:
1.1.1.7 root 258: static int drive_track0 (drive * drv)
1.1 root 259: {
1.1.1.3 root 260: return drv->cyl == 0;
1.1 root 261: }
262:
1.1.1.7 root 263: static int drive_writeprotected (drive * drv)
1.1 root 264: {
1.1.1.3 root 265: return drv->wrprot || drv->diskfile == NULL;
1.1 root 266: }
267:
1.1.1.7 root 268: static int drive_running (drive * drv)
1.1 root 269: {
1.1.1.3 root 270: return !drv->motoroff;
1.1 root 271: }
272:
1.1.1.7 root 273: static void drive_motor (drive * drv, int off)
1.1 root 274: {
275: drv->motoroff = off;
276: }
277:
1.1.1.7 root 278: static void read_floppy_data (drive * drv, int track, int offset, unsigned char *dst, int len)
279: {
280: trackid *ti;
281:
282: ti = &drv->trackdata[track];
283: fseek (drv->diskfile, ti->offs + offset, SEEK_SET);
284: fread (dst, 1, len, drv->diskfile);
285: }
286:
287: /* Megalomania does not like zero MFM words... */
288: static void mfmcode (uae_u16 * mfm, int words)
289: {
1.1.1.8 root 290: uae_u32 lastword = 0;
1.1.1.7 root 291:
292: while (words--) {
1.1.1.8 root 293: uae_u32 v = *mfm;
294: uae_u32 lv = (lastword << 16) | v;
295: uae_u32 nlv = 0x55555555 & ~lv;
296: uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
297:
298: *mfm++ = v | mfmbits;
299: lastword = v;
1.1.1.7 root 300: }
301: }
302:
303: static void drive_fill_bigbuf (drive * drv)
1.1 root 304: {
1.1.1.7 root 305: int tr = drv->cyl * 2 + side;
306: trackid *ti = drv->trackdata + tr;
1.1.1.3 root 307:
1.1.1.7 root 308: if (!drv->diskfile || tr >= drv->num_tracks) {
309: drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
310: drv->trackspeed = floppy_speed;
311: memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2);
1.1.1.2 root 312: return;
313: }
1.1.1.3 root 314: if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
315: return;
316:
1.1.1.7 root 317: if (ti->type == TRACK_AMIGADOS) {
1.1 root 318: /* Normal AmigaDOS format track */
1.1.1.7 root 319: int sec;
320: drv->tracklen = (drv->num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
321: memset (drv->bigmfmbuf, 0xaa, FLOPPY_GAP_LEN * 2);
1.1.1.2 root 322:
323: for (sec = 0; sec < drv->num_secs; sec++) {
1.1.1.3 root 324: uae_u8 secbuf[544];
1.1 root 325: int i;
1.1.1.7 root 326: uae_u16 *mfmbuf = drv->bigmfmbuf + 544 * sec + FLOPPY_GAP_LEN;
327: uae_u32 deven, dodd;
328: uae_u32 hck = 0, dck = 0;
1.1.1.3 root 329:
1.1 root 330: secbuf[0] = secbuf[1] = 0x00;
331: secbuf[2] = secbuf[3] = 0xa1;
332: secbuf[4] = 0xff;
333: secbuf[5] = tr;
334: secbuf[6] = sec;
1.1.1.7 root 335: secbuf[7] = drv->num_secs - sec;
1.1 root 336:
1.1.1.7 root 337: for (i = 8; i < 24; i++)
1.1 root 338: secbuf[i] = 0;
1.1.1.3 root 339:
1.1.1.7 root 340: read_floppy_data (drv, tr, sec * 512, &secbuf[32], 512);
1.1.1.3 root 341:
1.1 root 342: mfmbuf[0] = mfmbuf[1] = 0xaaaa;
343: mfmbuf[2] = mfmbuf[3] = 0x4489;
1.1.1.3 root 344:
345: deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
1.1 root 346: | (secbuf[6] << 8) | (secbuf[7]));
347: dodd = deven >> 1;
1.1.1.7 root 348: deven &= 0x55555555;
349: dodd &= 0x55555555;
1.1.1.3 root 350:
1.1 root 351: mfmbuf[4] = dodd >> 16;
352: mfmbuf[5] = dodd;
1.1.1.7 root 353: mfmbuf[6] = deven >> 16;
1.1 root 354: mfmbuf[7] = deven;
1.1.1.3 root 355:
1.1 root 356: for (i = 8; i < 48; i++)
1.1.1.6 root 357: mfmbuf[i] = 0xaaaa;
1.1.1.7 root 358: for (i = 0; i < 512; i += 4) {
359: deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
360: | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
1.1 root 361: dodd = deven >> 1;
1.1.1.7 root 362: deven &= 0x55555555;
363: dodd &= 0x55555555;
364: mfmbuf[(i >> 1) + 32] = dodd >> 16;
365: mfmbuf[(i >> 1) + 33] = dodd;
366: mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
367: mfmbuf[(i >> 1) + 256 + 33] = deven;
368: }
369:
370: for (i = 4; i < 24; i += 2)
371: hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
372:
373: deven = dodd = hck;
374: dodd >>= 1;
375: mfmbuf[24] = dodd >> 16;
376: mfmbuf[25] = dodd;
377: mfmbuf[26] = deven >> 16;
378: mfmbuf[27] = deven;
379:
380: for (i = 32; i < 544; i += 2)
381: dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
382:
383: deven = dodd = dck;
384: dodd >>= 1;
385: mfmbuf[28] = dodd >> 16;
386: mfmbuf[29] = dodd;
387: mfmbuf[30] = deven >> 16;
388: mfmbuf[31] = deven;
389: mfmcode (mfmbuf + 4, 544 - 4);
1.1 root 390: }
1.1.1.7 root 391: #ifdef DISK_DEBUG
392: write_log ("amigados read track %d\n", tr);
393: #endif
1.1 root 394: } else {
395: int i;
1.1.1.7 root 396: int base_offset = ti->type == TRACK_RAW ? 0 : 1;
397: drv->tracklen = ti->bitlen + 16 * base_offset;
398: read_floppy_data (drv, tr, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8);
399: drv->bigmfmbuf[0] = ti->sync;
400: for (i = base_offset; i < drv->tracklen / 16; i++) {
401: uae_u16 *mfm = drv->bigmfmbuf + i;
402: uae_u8 *data = (uae_u8 *) mfm;
403: *mfm = 256 * *data + *(data + 1);
1.1 root 404: }
1.1.1.7 root 405: #if 0 && defined DISK_DEBUG
406: write_log ("rawtrack %d\n", tr);
407: #endif
1.1 root 408: }
1.1.1.3 root 409: drv->buffered_side = side;
410: drv->buffered_cyl = drv->cyl;
1.1.1.7 root 411: drv->trackspeed = floppy_speed * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN);
1.1 root 412: }
413:
1.1.1.7 root 414: /* Update ADF_EXT2 track header */
415: static void diskfile_update (drive * drv, int len, uae_u8 type)
1.1 root 416: {
1.1.1.7 root 417: trackid *ti;
418: int track;
419: uae_u8 buf[2 + 2 + 4 + 4], *zerobuf;
1.1.1.3 root 420:
1.1.1.7 root 421: if (drv->filetype != ADF_EXT2)
422: return;
1.1.1.6 root 423:
1.1.1.7 root 424: track = drv->cyl * 2 + side;
425: ti = &drv->trackdata[track];
426: ti->bitlen = len;
427: fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET);
428: memset (buf, 0, sizeof buf);
429: ti->type = type;
430: buf[3] = ti->type;
431: do_put_mem_long ((uae_u32 *) (buf + 4), ti->len);
432: do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen);
433: fwrite (buf, sizeof (buf), 1, drv->diskfile);
434: if (ti->len > (len + 7) / 8) {
435: zerobuf = malloc (ti->len);
436: memset (zerobuf, 0, ti->len);
437: fseek (drv->diskfile, ti->offs, SEEK_SET);
438: fwrite (zerobuf, 1, ti->len, drv->diskfile);
439: free (zerobuf);
440: }
441: #ifdef DISK_DEBUG
442: write_log ("track %d, raw track length %d written (total size %d)\n", track, (ti->bitlen + 7) / 8, ti->len);
443: #endif
1.1 root 444: }
445:
446: #define MFMMASK 0x55555555
1.1.1.7 root 447: static uae_u32 getmfmlong (uae_u16 * mbuf)
1.1 root 448: {
449: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
450: }
451:
1.1.1.7 root 452: static int drive_write_adf_amigados (drive * drv)
1.1 root 453: {
454: int i, secwritten = 0;
1.1.1.7 root 455: int length = 2 * FLOPPY_WRITE_LEN;
1.1.1.3 root 456: uae_u32 odd, even, chksum, id, dlong;
1.1.1.7 root 457: uae_u8 *secdata;
1.1.1.3 root 458: uae_u8 secbuf[544];
1.1.1.7 root 459: uae_u16 *mbuf = drv->bigmfmbuf;
1.1.1.3 root 460: uae_u16 *mend = mbuf + length;
1.1.1.7 root 461: char sectable[11];
1.1.1.3 root 462:
1.1.1.7 root 463: memset (sectable, 0, sizeof (sectable));
464: memcpy (mbuf + FLOPPY_WRITE_LEN, mbuf, FLOPPY_WRITE_LEN * sizeof (uae_u16));
1.1 root 465: mend -= (4 + 16 + 8 + 512);
1.1.1.7 root 466: while (secwritten < 11) {
1.1 root 467: int trackoffs;
1.1.1.3 root 468:
1.1 root 469: do {
470: while (*mbuf++ != 0x4489) {
1.1.1.4 root 471: if (mbuf >= mend)
1.1.1.7 root 472: return 1;
1.1 root 473: }
474: } while (*mbuf++ != 0x4489);
1.1.1.3 root 475:
1.1.1.4 root 476: odd = getmfmlong (mbuf);
477: even = getmfmlong (mbuf + 2);
1.1.1.3 root 478: mbuf += 4;
1.1 root 479: id = (odd << 1) | even;
1.1.1.3 root 480:
1.1 root 481: trackoffs = (id & 0xff00) >> 8;
482: if (trackoffs > 10) {
1.1.1.7 root 483: if (drv->filetype == ADF_EXT2)
484: return 2;
1.1.1.5 root 485: write_log ("Disk write: weird sector number %d\n", trackoffs);
1.1 root 486: continue;
487: }
488: chksum = odd ^ even;
1.1.1.4 root 489: for (i = 0; i < 4; i++) {
1.1.1.7 root 490: odd = getmfmlong (mbuf);
491: even = getmfmlong (mbuf + 8);
1.1 root 492: mbuf += 2;
1.1.1.3 root 493:
1.1 root 494: dlong = (odd << 1) | even;
1.1.1.7 root 495: if (dlong) {
496: if (drv->filetype == ADF_EXT2)
497: return 6;
1.1.1.4 root 498: secwritten = -200;
1.1.1.7 root 499: }
1.1 root 500: chksum ^= odd ^ even;
1.1.1.7 root 501: } /* could check here if the label is nonstandard */
1.1 root 502: mbuf += 8;
1.1.1.7 root 503: odd = getmfmlong (mbuf);
504: even = getmfmlong (mbuf + 2);
505: mbuf += 4;
506: if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) {
507: if (drv->filetype == ADF_EXT2)
508: return 3;
509: write_log ("Disk write: checksum error on sector %d header\n", trackoffs);
1.1 root 510: continue;
511: }
1.1.1.7 root 512: odd = getmfmlong (mbuf);
513: even = getmfmlong (mbuf + 2);
514: mbuf += 4;
1.1 root 515: chksum = (odd << 1) | even;
516: secdata = secbuf + 32;
1.1.1.7 root 517: for (i = 0; i < 128; i++) {
518: odd = getmfmlong (mbuf);
519: even = getmfmlong (mbuf + 256);
520: mbuf += 2;
1.1 root 521: dlong = (odd << 1) | even;
1.1.1.7 root 522: *secdata++ = dlong >> 24;
523: *secdata++ = dlong >> 16;
524: *secdata++ = dlong >> 8;
525: *secdata++ = dlong;
1.1 root 526: chksum ^= odd ^ even;
527: }
528: mbuf += 256;
529: if (chksum) {
1.1.1.7 root 530: if (drv->filetype == ADF_EXT2)
531: return 4;
532: write_log ("Disk write: sector %d, data checksum error\n", trackoffs);
1.1 root 533: continue;
534: }
1.1.1.7 root 535: sectable[trackoffs] = 1;
1.1 root 536: secwritten++;
1.1.1.7 root 537: memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
1.1 root 538: }
1.1.1.7 root 539: if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
540: return 5;
1.1.1.3 root 541: if (secwritten == 0)
542: write_log ("Disk write in unsupported format\n");
1.1 root 543: if (secwritten < 0)
1.1.1.3 root 544: write_log ("Disk write: sector labels ignored\n");
1.1.1.7 root 545:
546: diskfile_update (drv, 11 * 512 * 8, TRACK_AMIGADOS);
547: for (i = 0; i < 11; i++) {
548: fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET);
549: fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile);
550: }
551:
552: return 0;
1.1 root 553: }
554:
1.1.1.7 root 555: /* write raw track to disk file */
556: static int drive_write_ext2 (drive * drv)
557: {
558: trackid *ti;
559: int len, track, i;
1.1 root 560:
1.1.1.7 root 561: track = drv->cyl * 2 + side;
562: ti = &drv->trackdata[track];
563: len = (drv->tracklen + 7) / 8;
564: if (len > ti->len) {
565: write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", track, ti->len, len);
566: return 0;
567: }
568: diskfile_update (drv, drv->tracklen, TRACK_RAW);
569: for (i = 0; i < drv->trackdata[track].len / 2; i++) {
570: uae_u16 *mfm = drv->bigmfmbuf + i;
571: uae_u8 *data = (uae_u8 *) mfm;
572: *mfm = 256 * *data + *(data + 1);
573: }
574: fseek (drv->diskfile, ti->offs, SEEK_SET);
575: fwrite (drv->bigmfmbuf, 1, len, drv->diskfile);
576: return 1;
577: }
578:
579: static void drive_write_data (drive * drv)
1.1 root 580: {
1.1.1.7 root 581: int ret;
582: if (drive_writeprotected (drv))
583: return;
584: switch (drv->filetype) {
585: case ADF_NORMAL:
586: drive_write_adf_amigados (drv);
587: break;
588: case ADF_EXT1:
589: write_log ("writing to ADF_EXT1 not supported\n");
590: return;
591: case ADF_EXT2:
592: ret = drive_write_adf_amigados (drv);
593: if (ret) {
594: /*write_log("not an amigados track (error %d), writing as raw track\n",ret); */
595: drive_write_ext2 (drv);
596: }
597: break;
598: }
599: drv->buffered_side = 2; /* will force read */
600: }
601:
602: static void drive_eject (drive * drv)
603: {
604: if (!drive_empty (drv))
1.1.1.4 root 605: zfile_close (drv->diskfile);
1.1.1.3 root 606:
607: drv->dskchange = 4;
608: drv->dskchange_time = 20;
609: /* printf("setting changed bit %d\n", drv-floppy);*/
1.1 root 610: drv->diskfile = 0;
611: }
612:
1.1.1.3 root 613: /* We use this function if we have no Kickstart ROM.
1.1 root 614: * No error checking - we trust our luck. */
1.1.1.3 root 615: void DISK_ersatz_read (int tr, int sec, uaecptr dest)
1.1 root 616: {
1.1.1.7 root 617: uae_u8 *dptr = get_real_address (dest);
618: fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET);
1.1.1.3 root 619: fread (dptr, 1, 512, floppy[0].diskfile);
1.1 root 620: }
621:
1.1.1.4 root 622: void disk_eject (int num)
1.1 root 623: {
1.1.1.7 root 624: gui_filename (num, "");
625: drive_eject (floppy + num);
1.1.1.3 root 626: *currprefs.df[num] = *changed_prefs.df[num] = 0;
1.1 root 627: }
628:
1.1.1.4 root 629: void disk_insert (int num, const char *name)
1.1 root 630: {
631: /* just to be sure */
1.1.1.4 root 632: drive_eject (floppy + num);
633: drive_insert (floppy + num, num, name);
1.1 root 634: }
635:
1.1.1.3 root 636: void DISK_check_change (void)
637: {
638: int i;
639: static int count = 0;
640: count++;
641:
642: for (i = 0; i < 4; i++) {
643: if (strcmp (currprefs.df[i], changed_prefs.df[i]) != 0) {
644: if (currprefs.df[i][0] != '\0') {
1.1.1.7 root 645: drive_eject (floppy + i);
1.1.1.3 root 646: currprefs.df[i][0] = '\0';
1.1.1.7 root 647: gui_filename (i, "");
1.1.1.3 root 648: } else if (floppy[i].dskchange == 1) {
649: /* In theory, it should work without the dskchange test.
650: * In practice, it doesn't. */
651: drive_insert (floppy + i, i, changed_prefs.df[i]);
652: } else if (floppy[i].dskchange > 1 && floppy[i].dskchange_time > 0) {
653: /* Force the dskchange bit to go to 1 after a given timeout */
654: if (--floppy[i].dskchange_time == 0) {
655: floppy[i].dskchange = 1;
656: }
657: }
658: }
659: }
660: }
661:
1.1.1.4 root 662: int disk_empty (int num)
1.1 root 663: {
1.1.1.4 root 664: return drive_empty (floppy + num);
1.1 root 665: }
666:
1.1.1.4 root 667: void DISK_select (uae_u8 data)
1.1 root 668: {
669: int step_pulse;
670: int dr;
1.1.1.3 root 671:
672: if (selected != ((data >> 3) & 15))
1.1 root 673: dskready = 0;
674: selected = (data >> 3) & 15;
1.1.1.3 root 675: side = 1 - ((data >> 2) & 1);
676:
1.1 root 677: direction = (data >> 1) & 1;
678: step_pulse = data & 1;
679: if (step != step_pulse) {
680: step = step_pulse;
1.1.1.7 root 681: if (step == 0) {
682: for (dr = 0; dr < 4; dr++) {
1.1 root 683: if (!(selected & (1 << dr))) {
1.1.1.4 root 684: drive_step (floppy + dr);
1.1 root 685: }
686: }
687: }
688: }
1.1.1.7 root 689: for (dr = 0; dr < 4; dr++) {
690: if (!(selected & (1 << dr))) {
691: drive_motor (floppy + dr, data >> 7);
1.1 root 692: }
693: }
694: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 695: floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
1.1.1.8 root 696: update_drive_gui (dr);
1.1 root 697: }
698: }
699:
1.1.1.4 root 700: uae_u8 DISK_status (void)
1.1 root 701: {
1.1.1.3 root 702: uae_u8 st = 0x3c;
1.1 root 703: int dr;
1.1.1.3 root 704:
1.1.1.7 root 705: for (dr = 0; dr < 4; dr++) {
1.1.1.3 root 706: drive *drv = floppy + dr;
1.1 root 707: if (!(selected & (1 << dr))) {
1.1.1.7 root 708: if (drive_running (drv)) {
709: if (dskready)
710: st &= ~0x20;
1.1 root 711: dskready = 1;
1.1.1.7 root 712: } else if (!drv->disabled) {
713: st &= ~0x20; /* report drive ID */
1.1 root 714: }
1.1.1.3 root 715:
1.1.1.7 root 716: if (drive_track0 (drv)) {
717: st &= ~0x10;
718: }
719: if (drive_writeprotected (drv)) {
720: st &= ~8;
721: }
1.1.1.3 root 722: if (drv->dskchange) {
723: /*printf("changed bit set: %d\n",dr); */
724: st &= ~0x4;
725: if (drv->dskchange > 1)
726: drv->dskchange--;
727: }
1.1 root 728: }
729: }
730: return st;
731: }
732:
1.1.1.7 root 733: #define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */
734:
735: #define DISK_INDEXSYNC 1
736: #define DISK_WORDSYNC 2
737:
738: static uae_u16 dskbytr_tab[MAX_DISK_WORDS_PER_LINE * 2 + 1];
739: static uae_u8 dskbytr_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
740: static uae_u16 dskdatr_tab[MAX_DISK_WORDS_PER_LINE + 1];
741: static uae_u8 dskdatr_cycle[MAX_DISK_WORDS_PER_LINE + 1];
742: static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
743: static uae_u8 disk_sync[MAXHPOS];
744: static int disk_sync_cycle;
745: static int indexsync_last_cycle;
746: static int dskdmaen, dsklength;
747: static uae_u16 dsksync;
748: static uae_u32 dskpt;
749:
750: static void disk_dmafinished (void)
751: {
752: INTREQ (0x8002);
753: dskdmaen = 0;
754: }
755:
756: static void disk_events (int last)
757: {
758: eventtab[ev_disk].active = 0;
759: for (disk_sync_cycle = last; disk_sync_cycle < MAXHPOS; disk_sync_cycle++) {
760: if (disk_sync[disk_sync_cycle]) {
761: eventtab[ev_disk].oldcycles = cycles;
762: eventtab[ev_disk].evtime = cycles + (disk_sync_cycle - last);
763: eventtab[ev_disk].active = 1;
764: events_schedule ();
765: return;
1.1 root 766: }
767: }
768: }
769:
1.1.1.7 root 770: extern void cia_diskindex (void);
1.1.1.3 root 771:
1.1.1.7 root 772: void DISK_handler (void)
773: {
774: eventtab[ev_disk].active = 0;
775: if (disk_sync[disk_sync_cycle] & DISK_WORDSYNC) {
776: INTREQ (0x9000);
777: indexsync_last_cycle = disk_sync_cycle + ((floppy_speed + 255) >> 8);
778: }
779: if (disk_sync[disk_sync_cycle] & DISK_INDEXSYNC) {
780: cia_diskindex ();
781: }
782: disk_sync[disk_sync_cycle] = 0;
783: disk_events (disk_sync_cycle);
784: }
1.1.1.3 root 785:
1.1.1.7 root 786: static int syncfound, dmaon, word, bitoffset;
1.1 root 787:
1.1.1.7 root 788: /* Always carried through to the next line. */
789: static int disk_hpos;
1.1.1.2 root 790:
1.1.1.7 root 791: /* emulate disk write dma for full horizontal line */
792: static void disk_doupdate_write (drive * drv)
793: {
794: int hpos = disk_hpos;
795: while (hpos < (MAXHPOS << 8)) {
796: drv->mfmpos++;
797: drv->mfmpos %= drv->tracklen;
798: if (!drv->mfmpos) {
799: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
800: disk_events (0);
801: }
802: if ((dmacon & 0x210) == 0x210 && dskdmaen == 3) {
803: bitoffset++;
804: bitoffset &= 15;
805: if (!bitoffset) {
806: drv->bigmfmbuf[drv->mfmpos >> 4] = get_word (dskpt);
807: dskpt += 2;
808: dsklength--;
809: if (dsklength == 0) {
810: disk_dmafinished ();
811: drive_write_data (drv);
812: }
1.1 root 813: }
814: }
1.1.1.7 root 815: hpos += drv->trackspeed;
1.1 root 816: }
1.1.1.7 root 817: disk_hpos = hpos - (MAXHPOS << 8);
1.1 root 818: }
819:
1.1.1.7 root 820: /* get one bit from MFM bit stream */
821: static uae_u16 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u16 word)
1.1 root 822: {
1.1.1.7 root 823: uae_u16 *buf;
1.1 root 824:
1.1.1.7 root 825: buf = &mfmbuf[mfmpos >> 4];
826: word <<= 1;
827: word |= (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
828: return word;
1.1 root 829: }
830:
1.1.1.7 root 831: /* emulate disk read dma for full horizontal line */
832: static void disk_doupdate_read (drive * drv)
833: {
834: int hpos = disk_hpos;
835: int is_sync = 0, dmaon;
836: int j = 0, l = 0, k = 0;
837:
838: while (hpos < (MAXHPOS << 8)) {
839: word = getonebit (drv->bigmfmbuf, drv->mfmpos, word);
840: drv->mfmpos++;
841: drv->mfmpos %= drv->tracklen;
842: if (!drv->mfmpos) {
843: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
844: is_sync = 1;
845: }
846: bitoffset++;
847: bitoffset &= 15;
848: if (bitoffset == 0 && (!(adkcon & 0x400) || syncfound))
849: dmaon = 1;
850: else
851: dmaon = 0;
852: if (word == dsksync) {
853: if ((adkcon & 0x400) == 0x400 && ! syncfound) {
854: syncfound = 1;
855: bitoffset = 0;
856: }
857: disk_sync[hpos >> 8] |= DISK_WORDSYNC;
858: is_sync = 1;
859: }
860: if (dmaon) {
861: dma_tab[j++] = word;
862: if (j == MAX_DISK_WORDS_PER_LINE - 1) {
863: write_log ("Bug: Disk DMA buffer overflow!\n");
864: j--;
865: }
866: }
867: if (bitoffset == 0 || bitoffset == 8) {
868: dskbytr_tab[k] = (word & 0xff) | 0x8000;
869: dskbytr_cycle[k++] = hpos >> 8;
870: if (bitoffset == 0) {
871: dskdatr_tab[l] = word;
872: dskdatr_cycle[l++] = hpos >> 8;
873: }
874: }
875: hpos += drv->trackspeed;
876: }
877: dma_tab[j] = 0xffffffff;
878: if (is_sync)
879: disk_events (0);
880: dskbytr_cycle[k] = 255;
881: dskdatr_cycle[l] = 255;
882:
883: disk_hpos = hpos - (MAXHPOS << 8);
884: }
885:
886: /* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
887: (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
888: data at cycle 0. I don't think any program cares about this small difference.
889: */
890: static void dodmafetch (void)
1.1 root 891: {
1.1.1.7 root 892: int i;
893:
894: i = 0;
895: while (dma_tab[i] != 0xffffffff && dskdmaen == 2 && (dmacon & 0x210) == 0x210) {
896: put_word (dskpt, dma_tab[i]);
897: dskpt += 2;
898: dsklength--;
899: if (dsklength == 0) {
900: disk_dmafinished ();
901: break;
902: }
903: i++;
904: }
905: dma_tab[0] = 0xffffffff;
1.1 root 906: }
907:
1.1.1.7 root 908: static void DISK_start (void)
1.1.1.6 root 909: {
910: int dr;
1.1.1.7 root 911:
1.1.1.6 root 912: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 913: drive *drv = &floppy[dr];
914: if (!(selected & (1 << dr))) {
915: int tr = drv->cyl * 2 + side;
916: trackid *ti = drv->trackdata + tr;
917:
918: drive_fill_bigbuf (drv);
919: if (dskdmaen == 3) {
920: drv->tracklen = FLOPPY_WRITE_LEN * 8 * 2;
921: drv->trackspeed = floppy_speed;
922: }
923: /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read
924: from the start. */
925: if (ti->type == TRACK_RAW1)
926: drv->mfmpos = 0;
927: drv->mfmpos %= drv->tracklen;
1.1.1.6 root 928: }
929: }
1.1.1.7 root 930: syncfound = 0;
931: dmaon = 0;
932: word = 0;
933: bitoffset = 0;
934: dma_tab[0] = 0xffffffff;
1.1.1.6 root 935: }
936:
1.1.1.7 root 937: static int linecounter;
938:
939: void DISK_update (void)
1.1 root 940: {
941: int dr;
1.1.1.7 root 942:
1.1.1.6 root 943: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 944: drive *drv = &floppy[dr];
945: drv->mfmpos_hsync = drv->mfmpos;
946: }
947: if (linecounter) {
948: linecounter--;
949: if (! linecounter)
950: disk_dmafinished ();
951: return;
952: }
953:
954: dodmafetch ();
955: indexsync_last_cycle = -1;
956:
957: for (dr = 0; dr < 4; dr++) {
958: drive *drv = &floppy[dr];
959: if (drv->motoroff)
960: continue;
961: if (selected & (1 << dr)) {
962: drv->mfmpos += (MAXHPOS << 8) / drv->trackspeed;
963: drv->mfmpos %= drv->tracklen;
964: continue;
1.1 root 965: }
1.1.1.7 root 966: if (dskdmaen == 3)
967: disk_doupdate_write (drv);
968: else
969: disk_doupdate_read (drv);
970: return;
1.1 root 971: }
972: }
1.1.1.6 root 973:
1.1.1.7 root 974: void DSKLEN (uae_u16 v, int hpos)
1.1.1.6 root 975: {
1.1.1.7 root 976: if (v & 0x8000) {
977: dskdmaen = dskdmaen == 1 ? 2 : 1;
978: } else {
979: /* Megalomania does this */
980: #if 0
981: if (dskdmaen == 2)
982: write_log ("warning: Disk read DMA aborted, %d words left\n", dsklength);
983: #endif
984: if (dskdmaen == 3)
985: write_log ("warning: Disk write DMA aborted, %d words left\n", dsklength);
986: dskdmaen = 0;
987: }
988: dsklength = v & 0x3fff;
989: if (dskdmaen <= 1)
990: return;
991: if (v & 0x4000)
992: dskdmaen = 3;
993: #ifdef DISK_DEBUG
994: {
995: int dr;
996: for (dr = 0; dr < 4; dr++) {
997: drive *drv = &floppy[dr];
998: if (drv->motoroff)
999: continue;
1000: if ((selected & (1 << dr)) == 0)
1001: break;
1002: }
1003: if (dr == 4)
1004: write_log ("disk DMA started, but no drive ready!\n");
1005: else
1006: write_log ("disk %s DMA started for %d words (%08.8X) sync=%04.4X track %d\n",
1007: dskdmaen == 3 ? "write" : "read", dsklength, dskpt,
1008: (adkcon & 0x400) ? dsksync : 0xffff,
1009: floppy[dr].cyl * 2 + side);
1010: }
1011: #endif
1012: /* Megalomania does not work if DSKLEN write is delayed to next horizontal line,
1013: also it seems some copy protections require this fix */
1014: DISK_start ();
1.1.1.6 root 1015:
1.1.1.7 root 1016: /* Try to make floppy access from Kickstart faster. */
1017: if (dskdmaen != 2)
1018: return;
1019: {
1020: int dr;
1021: uaecptr pc = m68k_getpc ();
1022: if ((pc & 0xF80000) != 0xF80000)
1023: return;
1024: for (dr = 0; dr < 4; dr++) {
1025: drive *drv = &floppy[dr];
1026: if (drv->motoroff)
1027: continue;
1028: if ((selected & (1 << dr)) == 0) {
1029: int pos = drv->mfmpos & ~15;
1030: int i;
1031:
1032: if (adkcon & 0x400) {
1033: for (i = 0; i < drv->tracklen; i += 16) {
1034: pos += 16;
1035: pos %= drv->tracklen;
1036: if (drv->bigmfmbuf[pos >> 4] == dsksync)
1037: break;
1038: }
1039: if (i >= drv->tracklen)
1040: return;
1041: }
1042: while (dsklength-- > 0) {
1043: put_word (dskpt, drv->bigmfmbuf[pos >> 4]);
1044: dskpt += 2;
1045: pos += 16;
1046: pos %= drv->tracklen;
1.1.1.6 root 1047: }
1.1.1.7 root 1048: INTREQ (0x9000);
1049: linecounter = 2;
1050: dskdmaen = 0;
1051: return;
1.1.1.6 root 1052: }
1053: }
1.1.1.7 root 1054: }
1.1.1.6 root 1055: }
1056:
1.1.1.7 root 1057: /* this unoptimized code should be enough (DSKBYTR and DSKDATR are used very rarely) */
1058:
1059: uae_u16 DSKBYTR (int hpos)
1.1.1.6 root 1060: {
1.1.1.7 root 1061: uae_u16 v;
1062: int i;
1063:
1064: i = 0;
1065: while (hpos > dskbytr_cycle[i])
1066: i++;
1067: v = dskbytr_tab[i];
1068: if (indexsync_last_cycle >= 0 && indexsync_last_cycle <= hpos)
1069: v |= 0x1000;
1070: dskbytr_tab[i] &= ~0x8000;
1071: if (dskdmaen && (dmacon & 0x210) == 0x210)
1072: v |= 0x4000;
1073: if (dskdmaen == 3)
1074: v |= 0x2000;
1075: return v;
1076: }
1077:
1078: uae_u16 DSKDATR (int hpos)
1079: {
1080: int i;
1081:
1082: i = 0;
1083: while (hpos > dskdatr_cycle[i])
1084: i++;
1085: return dskdatr_tab[i];
1086: }
1087:
1088: void DSKSYNC (uae_u16 v)
1089: {
1090: dsksync = v;
1091: }
1092:
1093: void DSKDAT (uae_u16 v)
1094: {
1095: static int count = 0;
1096: if (count < 5) {
1097: count++;
1098: write_log ("DSKDAT written. Not good.");
1099: if (count == 5)
1100: write_log ("(further messages suppressed)");
1101:
1102: write_log ("\n");
1.1.1.6 root 1103: }
1104: }
1.1.1.7 root 1105: void DSKPTH (uae_u16 v)
1106: {
1107: dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16);
1108: }
1.1.1.6 root 1109:
1.1.1.7 root 1110: void DSKPTL (uae_u16 v)
1.1.1.6 root 1111: {
1.1.1.7 root 1112: dskpt = (dskpt & ~0xffff) | (v);
1.1.1.6 root 1113: }
1114:
1.1.1.7 root 1115: void DISK_init (void)
1116: {
1117: int i;
1118:
1119: dma_tab[0] = 0xffffffff;
1120: dskbytr_cycle[0] = 255;
1121: dskdatr_cycle[0] = 255;
1122: indexsync_last_cycle = -1;
1123:
1.1.1.8 root 1124: for (i = 0; i < 4; i++) {
1.1.1.7 root 1125: if (!drive_insert (floppy + i, i, currprefs.df[i]))
1126: disk_eject (i);
1.1.1.8 root 1127: }
1.1.1.7 root 1128: if (disk_empty (0))
1129: write_log ("No disk in drive 0.\n");
1130: }
1131:
1.1.1.8 root 1132: void DISK_reset (void)
1133: {
1134: int i;
1135: disk_hpos = 0;
1136: for (i = 0; i < 4; i++) {
1137: floppy[i].disabled = 0;
1138: if (i >= currprefs.nr_floppies)
1139: floppy[i].disabled = 1;
1140: }
1141: }
1142:
1.1.1.7 root 1143: void dumpdisk (void)
1144: {
1145: int i;
1146: for (i = 0; i < 4; i++) {
1147: drive *drv = &floppy[i];
1148: printf ("Drive %d: motor %s cylinder %2d selected %d\n", i, drv->motoroff ? "off" : " on", drv->cyl, selected & (1 << i));
1149: }
1150: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.