|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * Floppy disk emulation ! 5: * ! 6: * (c) 1995 Bernd Schmidt, Hannu Rummukainen ! 7: */ ! 8: ! 9: #include "sysconfig.h" ! 10: #include "sysdeps.h" ! 11: ! 12: #include "config.h" ! 13: #include "options.h" ! 14: #include "memory.h" ! 15: #include "events.h" ! 16: #include "custom.h" ! 17: #include "ersatz.h" ! 18: #include "disk.h" ! 19: #include "gui.h" ! 20: #include "zfile.h" ! 21: ! 22: #define FLOPPY_SPEED 5 ! 23: ! 24: UWORD* mfmwrite; ! 25: static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */ ! 26: ! 27: static int side, direction, step; ! 28: static UBYTE selected = 15; ! 29: static int dskready; ! 30: static int need_read = 0; ! 31: ! 32: typedef struct { ! 33: UWORD sync; ! 34: UWORD len; ! 35: ULONG offs; ! 36: } trackid; ! 37: ! 38: typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype; ! 39: typedef struct { ! 40: FILE *diskfile; ! 41: drive_filetype filetype; ! 42: trackid trackdata[164]; ! 43: unsigned int track; ! 44: int motoroff; ! 45: int wrprot; ! 46: UWORD bigmfmbuf[0x2000]; ! 47: int tracklen; ! 48: unsigned long last_cycles; ! 49: int mfmpos; ! 50: } drive; ! 51: ! 52: drive floppy[4]; ! 53: ! 54: static void drive_fill_bigbuf(drive *drv); ! 55: ! 56: static void drive_insert(drive *drv, int dnum, char *fname) ! 57: { ! 58: unsigned char buffer[10]; ! 59: ! 60: drv->diskfile = zfile_open(fname,"r+b"); ! 61: if (drv->diskfile) { ! 62: drv->wrprot = 0; ! 63: } else { ! 64: drv->wrprot = 1; ! 65: drv->diskfile = zfile_open(fname, "rb"); ! 66: if (!drv->diskfile) { ! 67: gui_filename(dnum, ""); ! 68: return; ! 69: } ! 70: } ! 71: switch (dnum) { ! 72: case 0: strcpy((char *)df0, fname); break; ! 73: case 1: strcpy((char *)df1, fname); break; ! 74: case 2: strcpy((char *)df2, fname); break; ! 75: case 3: strcpy((char *)df3, fname); break; ! 76: case 4: break; ! 77: } ! 78: gui_filename(dnum, fname); ! 79: fread(buffer,sizeof(char),8,drv->diskfile); ! 80: if (strncmp((char *)buffer,"UAE--ADF",8) == 0) { ! 81: int offs = 160*4+8; ! 82: int i; ! 83: ! 84: drv->filetype = ADF_EXT1; ! 85: drv->wrprot = 1; /* write to adf_ext1 not implemented */ ! 86: for(i=0; i<160; i++) { ! 87: fread(buffer, 4, 1, drv->diskfile); ! 88: drv->trackdata[i].sync = buffer[0]*256 + buffer[1]; ! 89: drv->trackdata[i].len = buffer[2]*256 + buffer[3]; ! 90: drv->trackdata[i].offs = offs; ! 91: offs += drv->trackdata[i].len; ! 92: } ! 93: } else { ! 94: int i; ! 95: drv->filetype = ADF_NORMAL; ! 96: for(i=0; i<160; i++) { ! 97: drv->trackdata[i].len = 512 * 11; ! 98: drv->trackdata[i].sync = 0; ! 99: drv->trackdata[i].offs = i*512*11; ! 100: } ! 101: } ! 102: drive_fill_bigbuf(drv); ! 103: } ! 104: ! 105: static void drive_step(drive *drv) ! 106: { ! 107: if (direction) { ! 108: if (drv->track) drv->track--; ! 109: } else { ! 110: if (drv->track < 85) drv->track++; ! 111: } ! 112: drive_fill_bigbuf(drv); ! 113: } ! 114: ! 115: ! 116: static int drive_track0(drive *drv) ! 117: { ! 118: return drv->track == 0; ! 119: } ! 120: ! 121: static int drive_writeprotected(drive *drv) ! 122: { ! 123: return drv->wrprot || drv->diskfile == NULL; ! 124: } ! 125: ! 126: static int drive_empty(drive *drv) ! 127: { ! 128: return drv->diskfile == 0; ! 129: } ! 130: ! 131: static int drive_running(drive *drv) ! 132: { ! 133: return !drv->motoroff; ! 134: } ! 135: ! 136: static void drive_motor(drive *drv, int off) ! 137: { ! 138: if (drv->motoroff && !off) { ! 139: drv->last_cycles = cycles; ! 140: drv->mfmpos = 0; ! 141: eventtab[ev_diskindex].active = 1; ! 142: if (drv->tracklen) ! 143: eventtab[ev_diskindex].evtime = FLOPPY_SPEED * drv->tracklen + cycles; ! 144: else ! 145: eventtab[ev_diskindex].evtime = cycles + 1000; ! 146: eventtab[ev_diskindex].oldcycles = cycles; ! 147: } else if (off) ! 148: eventtab[ev_diskindex].active = 0; ! 149: drv->motoroff = off; ! 150: events_schedule(); ! 151: ! 152: } ! 153: ! 154: static void drive_fill_bigbuf(drive *drv) ! 155: { ! 156: int tr = drv->track*2 + side; ! 157: ! 158: if (!drv->diskfile) return; ! 159: ! 160: if (drv->trackdata[tr].sync == 0) { ! 161: /* Normal AmigaDOS format track */ ! 162: int sec; ! 163: drv->tracklen = 11*544 + 300; ! 164: memset(drv->bigmfmbuf,0xaa,300*2); ! 165: ! 166: for (sec = 0; sec < 11; sec++) { ! 167: UBYTE secbuf[544]; ! 168: int i; ! 169: UWORD *mfmbuf = drv->bigmfmbuf + 544*sec + 300; ! 170: ULONG deven,dodd; ! 171: ULONG hck=0,dck=0; ! 172: ! 173: secbuf[0] = secbuf[1] = 0x00; ! 174: secbuf[2] = secbuf[3] = 0xa1; ! 175: secbuf[4] = 0xff; ! 176: secbuf[5] = tr; ! 177: secbuf[6] = sec; ! 178: secbuf[7] = 11-sec; ! 179: ! 180: for(i = 8; i < 24; i++) ! 181: secbuf[i] = 0; ! 182: ! 183: fseek(drv->diskfile, ! 184: drv->trackdata[tr].offs + sec*512, ! 185: SEEK_SET); ! 186: fread(&secbuf[32],1,512,drv->diskfile); ! 187: ! 188: mfmbuf[0] = mfmbuf[1] = 0xaaaa; ! 189: mfmbuf[2] = mfmbuf[3] = 0x4489; ! 190: ! 191: deven = ((secbuf[4] << 24) | (secbuf[5] << 16) ! 192: | (secbuf[6] << 8) | (secbuf[7])); ! 193: dodd = deven >> 1; ! 194: deven &= 0x55555555; dodd &= 0x55555555; ! 195: ! 196: mfmbuf[4] = dodd >> 16; ! 197: mfmbuf[5] = dodd; ! 198: mfmbuf[6] = deven>> 16; ! 199: mfmbuf[7] = deven; ! 200: ! 201: for (i = 8; i < 48; i++) ! 202: mfmbuf[i] = 0; ! 203: for (i = 0; i < 512; i += 4){ ! 204: deven = ((secbuf[i+32] << 24) | (secbuf[i+33] << 16) ! 205: | (secbuf[i+34] << 8) | (secbuf[i+35])); ! 206: dodd = deven >> 1; ! 207: deven &= 0x55555555; dodd &= 0x55555555; ! 208: mfmbuf[(i>>1)+32] = dodd >> 16; ! 209: mfmbuf[(i>>1)+33] = dodd; ! 210: mfmbuf[(i>>1)+256+32] = deven >> 16; ! 211: mfmbuf[(i>>1)+256+33] = deven; ! 212: } ! 213: ! 214: for(i = 4; i < 24; i += 2) ! 215: hck ^= (mfmbuf[i] << 16) | mfmbuf[i+1]; ! 216: ! 217: deven = dodd = hck; dodd >>= 1; ! 218: mfmbuf[24] = dodd >> 16; mfmbuf[25] = dodd; ! 219: mfmbuf[26] = deven>> 16; mfmbuf[27] = deven; ! 220: ! 221: for(i = 32; i < 544; i += 2) ! 222: dck ^= (mfmbuf[i] << 16) | mfmbuf[i+1]; ! 223: ! 224: deven = dodd = dck; dodd >>= 1; ! 225: mfmbuf[28] = dodd >> 16; mfmbuf[29] = dodd; ! 226: mfmbuf[30] = deven>> 16; mfmbuf[31] = deven; ! 227: } ! 228: } else { ! 229: int i; ! 230: drv->tracklen = drv->trackdata[tr].len/2 + 1; ! 231: drv->bigmfmbuf[0] = drv->trackdata[tr].sync; ! 232: fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET); ! 233: fread(drv->bigmfmbuf+1, 1, drv->trackdata[tr].len, drv->diskfile); ! 234: for (i = 0; i < drv->trackdata[tr].len/2; i++) { ! 235: UWORD *mfm = drv->bigmfmbuf + i + 1; ! 236: UBYTE *data = (UBYTE *)mfm; ! 237: ! 238: *mfm = 256 * *data + *(data+1); ! 239: } ! 240: } ! 241: need_read = 0; ! 242: drv->last_cycles = cycles; ! 243: drv->mfmpos = 0; ! 244: } ! 245: ! 246: static int drive_get_data(drive *drv, UWORD *mfm, UWORD *byt) ! 247: { ! 248: int offset,mfmpos; ! 249: if (need_read) { ! 250: drive_fill_bigbuf(drv); ! 251: } ! 252: offset = (cycles - drv->last_cycles) / FLOPPY_SPEED; ! 253: mfmpos = (drv->mfmpos + offset) % drv->tracklen; ! 254: drv->last_cycles += offset*FLOPPY_SPEED; ! 255: drv->mfmpos = mfmpos; ! 256: *mfm = drv->bigmfmbuf[mfmpos]; ! 257: return offset > 0; ! 258: } ! 259: ! 260: #define MFMMASK 0x55555555 ! 261: static __inline__ ULONG getmfmlong(UWORD* mbuf) ! 262: { ! 263: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK; ! 264: } ! 265: ! 266: static void drive_write_data(drive *drv, UWORD *mbuf, int length) ! 267: { ! 268: int i, secwritten = 0; ! 269: ULONG odd, even, chksum, id, dlong; ! 270: UBYTE* secdata; ! 271: UBYTE secbuf[544]; ! 272: UWORD *mend = mbuf + length; ! 273: ! 274: if (drive_writeprotected(drv)) return; ! 275: mend -= (4 + 16 + 8 + 512); ! 276: while (length > 0) { ! 277: int trackoffs; ! 278: ! 279: do { ! 280: while (*mbuf++ != 0x4489) { ! 281: if (mbuf >= mend) return; ! 282: } ! 283: } while (*mbuf++ != 0x4489); ! 284: ! 285: odd = getmfmlong(mbuf); ! 286: even = getmfmlong(mbuf+2); ! 287: mbuf += 4; ! 288: id = (odd << 1) | even; ! 289: ! 290: trackoffs = (id & 0xff00) >> 8; ! 291: if (trackoffs > 10) { ! 292: printf("Disk write: weird sector number %d\n", trackoffs); ! 293: continue; ! 294: } ! 295: chksum = odd ^ even; ! 296: for (i=0; i<4; i++) { ! 297: odd = getmfmlong(mbuf); ! 298: even = getmfmlong(mbuf+8); ! 299: mbuf += 2; ! 300: ! 301: dlong = (odd << 1) | even; ! 302: if (dlong) secwritten = -200; ! 303: chksum ^= odd ^ even; ! 304: } /* could check here if the label is nonstandard */ ! 305: mbuf += 8; ! 306: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; ! 307: if ((((odd << 1) | even) != chksum) || ! 308: (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) { ! 309: printf("Disk write: checksum error on sector header\n"); ! 310: continue; ! 311: } ! 312: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; ! 313: chksum = (odd << 1) | even; ! 314: secdata = secbuf + 32; ! 315: for (i=0; i<128; i++) { ! 316: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2; ! 317: dlong = (odd << 1) | even; ! 318: *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff; ! 319: *secdata++ = dlong >> 8; *secdata++ = dlong; ! 320: chksum ^= odd ^ even; ! 321: } ! 322: mbuf += 256; ! 323: if (chksum) { ! 324: printf("Disk write: data checksum error\n"); ! 325: continue; ! 326: } ! 327: secwritten++; ! 328: fseek(drv->diskfile, ! 329: drv->trackdata[drv->track*2 + side].offs + trackoffs*512, ! 330: SEEK_SET); ! 331: fwrite(secbuf+32, sizeof(UBYTE), 512, drv->diskfile); ! 332: } ! 333: need_read = 1; ! 334: ! 335: if (secwritten == 0) ! 336: printf("Disk write in unsupported format\n"); ! 337: if (secwritten < 0) ! 338: printf("Disk write: sector labels ignored\n"); ! 339: } ! 340: ! 341: ! 342: static void drive_eject(drive *drv) ! 343: { ! 344: if (!drive_empty(drv)) zfile_close(drv->diskfile); ! 345: drv->diskfile = 0; ! 346: } ! 347: ! 348: /* We use this function if we have no Kickstart ROM. ! 349: * No error checking - we trust our luck. */ ! 350: void DISK_ersatz_read (int tr, int sec, CPTR dest) ! 351: { ! 352: int i; ! 353: UBYTE *dptr = get_real_address(dest); ! 354: fseek(floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec*512, SEEK_SET); ! 355: fread(dptr,1,512,floppy[0].diskfile); ! 356: } ! 357: ! 358: void disk_eject(int num) ! 359: { ! 360: gui_filename(num, ""); ! 361: drive_eject(floppy + num); ! 362: } ! 363: ! 364: void disk_insert(int num, char *name) ! 365: { ! 366: /* just to be sure */ ! 367: drive_eject(floppy + num); ! 368: drive_insert(floppy + num, num, name); ! 369: } ! 370: ! 371: int disk_empty(int num) ! 372: { ! 373: return drive_empty(floppy + num); ! 374: } ! 375: ! 376: void DISK_init() ! 377: { ! 378: drive_insert(floppy, 0, df0); ! 379: if (disk_empty(0)) ! 380: fprintf(stderr, "No floppy in drive 0.\n"); ! 381: drive_insert(floppy + 1, 1, df1); ! 382: drive_insert(floppy + 2, 2, df2); ! 383: drive_insert(floppy + 3, 3, df3); ! 384: } ! 385: ! 386: static int ledstate[] = { 0,0,0,0 }; ! 387: ! 388: void DISK_select(UBYTE data) ! 389: { ! 390: int step_pulse; ! 391: int dr; ! 392: ! 393: if (selected != ((data >> 3) & 15)) ! 394: dskready = 0; ! 395: selected = (data >> 3) & 15; ! 396: if (side != 1 - ((data >> 2) & 1)) { ! 397: side = 1 - ((data >> 2) & 1); ! 398: need_read = 1; ! 399: } ! 400: direction = (data >> 1) & 1; ! 401: step_pulse = data & 1; ! 402: if (step != step_pulse) { ! 403: step = step_pulse; ! 404: if (step == 0){ ! 405: for (dr = 0; dr < 4; dr++){ ! 406: if (!(selected & (1 << dr))) { ! 407: drive_step(floppy + dr); ! 408: } ! 409: } ! 410: } ! 411: } ! 412: for (dr = 0; dr < 4; dr++){ ! 413: if (!(selected & (1<<dr))) { ! 414: drive_motor(floppy + dr, data >> 7); ! 415: } ! 416: } ! 417: for (dr = 0; dr < 4; dr++) { ! 418: int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff; ! 419: if (state != ledstate[dr]) ! 420: gui_led (dr+1, state); ! 421: ledstate[dr] = state; ! 422: } ! 423: } ! 424: ! 425: UBYTE DISK_status() ! 426: { ! 427: UBYTE st = 0x3c; ! 428: int dr; ! 429: ! 430: for (dr = 0; dr < 4; dr++){ ! 431: if (!(selected & (1 << dr))) { ! 432: if (drive_running(floppy + dr)){ ! 433: if (dskready) st &= ~0x20; ! 434: dskready = 1; ! 435: } else { ! 436: st &= ~0x20; /* report drive ID */ ! 437: } ! 438: ! 439: if (drive_track0(floppy + dr)) { st &= ~0x10; } ! 440: if (drive_writeprotected(floppy + dr)) { st &= ~8; } ! 441: if (drive_empty(floppy + dr)) { st &= ~0x4; } ! 442: } ! 443: } ! 444: return st; ! 445: } ! 446: ! 447: int DISK_GetData(UWORD *mfm,UWORD *byt) ! 448: { ! 449: int dr; ! 450: for (dr = 0; dr < 4; dr++){ ! 451: if (!(selected & (1<<dr))) { ! 452: return drive_get_data (floppy + dr, mfm, byt); ! 453: } ! 454: } ! 455: return 0; ! 456: } ! 457: ! 458: static UWORD mfm_read_buffer[0x4000]; ! 459: static int mfm_read_length; ! 460: ! 461: int DISK_PrepareReadMFM(int length, UWORD sync, int use_sync) ! 462: { ! 463: int dr; ! 464: ! 465: mfm_read_length = 0; ! 466: ! 467: for (dr = 0; dr < 4; dr++) { ! 468: if (!(selected & (1<<dr))) { ! 469: int time = 0; ! 470: UWORD *mfmp = mfm_read_buffer; ! 471: drive *drv = floppy + dr; ! 472: int offset,mfmpos; ! 473: ! 474: if (need_read) { ! 475: drive_fill_bigbuf(drv); ! 476: } ! 477: ! 478: offset = (cycles - drv->last_cycles) / FLOPPY_SPEED; ! 479: mfmpos = (drv->mfmpos + offset) % drv->tracklen; ! 480: drv->last_cycles += offset*FLOPPY_SPEED; ! 481: drv->mfmpos = mfmpos; ! 482: mfmpos++; mfmpos %= drv->tracklen; ! 483: while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync) ! 484: mfmpos = (mfmpos + 1) % drv->tracklen, time++; ! 485: ! 486: if (drv->bigmfmbuf[mfmpos] != sync && use_sync) { ! 487: fprintf(stderr, "warning: sync not found on disk read\n"); ! 488: return 0; ! 489: } else ! 490: mfmpos++; ! 491: ! 492: mfm_read_length = length; ! 493: ! 494: while (length--) { ! 495: *mfmp++ = drv->bigmfmbuf[mfmpos]; ! 496: mfmpos = (mfmpos + 1) % drv->tracklen; ! 497: time++; ! 498: } ! 499: ! 500: return time*FLOPPY_SPEED; ! 501: } ! 502: } ! 503: return 0; ! 504: } ! 505: ! 506: int DISK_ReadMFM(CPTR target) ! 507: { ! 508: int i; ! 509: UBYTE *mfmp = get_real_address(target); ! 510: ! 511: if (!chipmem_bank.check(target, mfm_read_length * 2)) { ! 512: fprintf(stderr, "warning: Bad disk DMA read pointer\n"); ! 513: return 0; ! 514: } ! 515: ! 516: for (i = 0; i < mfm_read_length; i++) { ! 517: *mfmp++ = mfm_read_buffer[i] >> 8; ! 518: *mfmp++ = mfm_read_buffer[i]; ! 519: } ! 520: return 1; ! 521: } ! 522: ! 523: void DISK_InitWrite() ! 524: { ! 525: mfmwrite = mfmwrbuffer; ! 526: } ! 527: ! 528: void DISK_WriteData(int length) ! 529: { ! 530: int dr; ! 531: for (dr=0;dr<4;dr++){ ! 532: if (!(selected & (1<<dr))) { ! 533: drive_write_data(floppy + dr, mfmwrbuffer, length); ! 534: } ! 535: } ! 536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.