|
|
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.