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