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