1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28: #include "hw.h"
29: #include "fdc.h"
30: #include "block.h"
31: #include "qemu-timer.h"
32: #include "isa.h"
33:
34:
35:
36:
37:
38: #ifdef DEBUG_FLOPPY
39: #define FLOPPY_DPRINTF(fmt, args...) \
40: do { printf("FLOPPY: " fmt , ##args); } while (0)
41: #else
42: #define FLOPPY_DPRINTF(fmt, args...)
43: #endif
44:
45: #define FLOPPY_ERROR(fmt, args...) \
46: do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
47:
48:
49:
50:
51:
52: #define FD_SECTOR_LEN 512
53: #define FD_SECTOR_SC 2
54:
55:
56: typedef enum fdisk_type_t {
57: FDRIVE_DISK_288 = 0x01,
58: FDRIVE_DISK_144 = 0x02,
59: FDRIVE_DISK_720 = 0x03,
60: FDRIVE_DISK_USER = 0x04,
61: FDRIVE_DISK_NONE = 0x05,
62: } fdisk_type_t;
63:
64: typedef enum fdrive_type_t {
65: FDRIVE_DRV_144 = 0x00,
66: FDRIVE_DRV_288 = 0x01,
67: FDRIVE_DRV_120 = 0x02,
68: FDRIVE_DRV_NONE = 0x03,
69: } fdrive_type_t;
70:
71: typedef enum fdrive_flags_t {
72: FDRIVE_MOTOR_ON = 0x01,
73: } fdrive_flags_t;
74:
75: typedef enum fdisk_flags_t {
76: FDISK_DBL_SIDES = 0x01,
77: } fdisk_flags_t;
78:
79: typedef struct fdrive_t {
80: BlockDriverState *bs;
81:
82: fdrive_type_t drive;
83: fdrive_flags_t drflags;
84: uint8_t perpendicular;
85:
86: uint8_t head;
87: uint8_t track;
88: uint8_t sect;
89:
90: uint8_t dir;
91: uint8_t rw;
92:
93: fdisk_flags_t flags;
94: uint8_t last_sect;
95: uint8_t max_track;
96: uint16_t bps;
97: uint8_t ro;
98: } fdrive_t;
99:
100: static void fd_init (fdrive_t *drv, BlockDriverState *bs)
101: {
102:
103: drv->bs = bs;
104: drv->drive = FDRIVE_DRV_NONE;
105: drv->drflags = 0;
106: drv->perpendicular = 0;
107:
108: drv->last_sect = 0;
109: drv->max_track = 0;
110: }
111:
112: static int _fd_sector (uint8_t head, uint8_t track,
113: uint8_t sect, uint8_t last_sect)
114: {
115: return (((track * 2) + head) * last_sect) + sect - 1;
116: }
117:
118:
119: static int fd_sector (fdrive_t *drv)
120: {
121: return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
122: }
123:
124: static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
125: int enable_seek)
126: {
127: uint32_t sector;
128: int ret;
129:
130: if (track > drv->max_track ||
131: (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
132: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
133: head, track, sect, 1,
134: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
135: drv->max_track, drv->last_sect);
136: return 2;
137: }
138: if (sect > drv->last_sect) {
139: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
140: head, track, sect, 1,
141: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
142: drv->max_track, drv->last_sect);
143: return 3;
144: }
145: sector = _fd_sector(head, track, sect, drv->last_sect);
146: ret = 0;
147: if (sector != fd_sector(drv)) {
148: #if 0
149: if (!enable_seek) {
150: FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
151: head, track, sect, 1, drv->max_track, drv->last_sect);
152: return 4;
153: }
154: #endif
155: drv->head = head;
156: if (drv->track != track)
157: ret = 1;
158: drv->track = track;
159: drv->sect = sect;
160: }
161:
162: return ret;
163: }
164:
165:
166: static void fd_recalibrate (fdrive_t *drv)
167: {
168: FLOPPY_DPRINTF("recalibrate\n");
169: drv->head = 0;
170: drv->track = 0;
171: drv->sect = 1;
172: drv->dir = 1;
173: drv->rw = 0;
174: }
175:
176:
177: typedef struct fd_format_t {
178: fdrive_type_t drive;
179: fdisk_type_t disk;
180: uint8_t last_sect;
181: uint8_t max_track;
182: uint8_t max_head;
183: const char *str;
184: } fd_format_t;
185:
186: static const fd_format_t fd_formats[] = {
187:
188:
189: { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
190: { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", },
191: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
192: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
193: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
194: { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
195: { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
196: { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
197:
198: { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
199: { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
200: { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", },
201: { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
202: { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
203:
204: { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", },
205: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", },
206: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", },
207: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", },
208: { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
209: { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
210:
211: { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", },
212: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
213: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
214: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
215: { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", },
216:
217: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", },
218: { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", },
219:
220: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", },
221: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", },
222: { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", },
223: { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", },
224:
225: { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", },
226: { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", },
227:
228: { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", },
229:
230: { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
231: };
232:
233:
234: static void fd_revalidate (fdrive_t *drv)
235: {
236: const fd_format_t *parse;
237: uint64_t nb_sectors, size;
238: int i, first_match, match;
239: int nb_heads, max_track, last_sect, ro;
240:
241: FLOPPY_DPRINTF("revalidate\n");
242: if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
243: ro = bdrv_is_read_only(drv->bs);
244: bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
245: if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
246: FLOPPY_DPRINTF("User defined disk (%d %d %d)",
247: nb_heads - 1, max_track, last_sect);
248: } else {
249: bdrv_get_geometry(drv->bs, &nb_sectors);
250: match = -1;
251: first_match = -1;
252: for (i = 0;; i++) {
253: parse = &fd_formats[i];
254: if (parse->drive == FDRIVE_DRV_NONE)
255: break;
256: if (drv->drive == parse->drive ||
257: drv->drive == FDRIVE_DRV_NONE) {
258: size = (parse->max_head + 1) * parse->max_track *
259: parse->last_sect;
260: if (nb_sectors == size) {
261: match = i;
262: break;
263: }
264: if (first_match == -1)
265: first_match = i;
266: }
267: }
268: if (match == -1) {
269: if (first_match == -1)
270: match = 1;
271: else
272: match = first_match;
273: parse = &fd_formats[match];
274: }
275: nb_heads = parse->max_head + 1;
276: max_track = parse->max_track;
277: last_sect = parse->last_sect;
278: drv->drive = parse->drive;
279: FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
280: nb_heads, max_track, last_sect, ro ? "ro" : "rw");
281: }
282: if (nb_heads == 1) {
283: drv->flags &= ~FDISK_DBL_SIDES;
284: } else {
285: drv->flags |= FDISK_DBL_SIDES;
286: }
287: drv->max_track = max_track;
288: drv->last_sect = last_sect;
289: drv->ro = ro;
290: } else {
291: FLOPPY_DPRINTF("No disk in drive\n");
292: drv->last_sect = 0;
293: drv->max_track = 0;
294: drv->flags &= ~FDISK_DBL_SIDES;
295: }
296: }
297:
298:
299: static void fd_start (fdrive_t *drv)
300: {
301: drv->drflags |= FDRIVE_MOTOR_ON;
302: }
303:
304: static void fd_stop (fdrive_t *drv)
305: {
306: drv->drflags &= ~FDRIVE_MOTOR_ON;
307: }
308:
309:
310: static void fd_reset (fdrive_t *drv)
311: {
312: fd_stop(drv);
313: fd_recalibrate(drv);
314: }
315:
316:
317:
318:
319: static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
320: static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
321: static int fdctrl_transfer_handler (void *opaque, int nchan,
322: int dma_pos, int dma_len);
323: static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
324: static void fdctrl_result_timer(void *opaque);
325:
326: static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
327: static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
328: static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
329: static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
330: static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
331: static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
332: static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
333: static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
334: static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
335: static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
336:
337: enum {
338: FD_CTRL_ACTIVE = 0x01,
339: FD_CTRL_RESET = 0x02,
340: FD_CTRL_SLEEP = 0x04,
341: FD_CTRL_BUSY = 0x08,
342: FD_CTRL_INTR = 0x10,
343: };
344:
345: enum {
346: FD_DIR_WRITE = 0,
347: FD_DIR_READ = 1,
348: FD_DIR_SCANE = 2,
349: FD_DIR_SCANL = 3,
350: FD_DIR_SCANH = 4,
351: };
352:
353: enum {
354: FD_STATE_CMD = 0x00,
355: FD_STATE_STATUS = 0x01,
356: FD_STATE_DATA = 0x02,
357: FD_STATE_STATE = 0x03,
358: FD_STATE_MULTI = 0x10,
359: FD_STATE_SEEK = 0x20,
360: FD_STATE_FORMAT = 0x40,
361: };
362:
363: #define FD_STATE(state) ((state) & FD_STATE_STATE)
364: #define FD_SET_STATE(state, new_state) \
365: do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
366: #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
367: #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
368: #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
369:
370: struct fdctrl_t {
371: fdctrl_t *fdctrl;
372:
373: uint8_t version;
374:
375: qemu_irq irq;
376: int dma_chann;
377: target_phys_addr_t io_base;
378:
379: QEMUTimer *result_timer;
380: uint8_t state;
381: uint8_t dma_en;
382: uint8_t cur_drv;
383: uint8_t bootsel;
384:
385: uint8_t *fifo;
386: uint32_t data_pos;
387: uint32_t data_len;
388: uint8_t data_state;
389: uint8_t data_dir;
390: uint8_t int_status;
391: uint8_t eot;
392:
393:
394: uint8_t timer0;
395: uint8_t timer1;
396:
397: uint8_t precomp_trk;
398: uint8_t config;
399: uint8_t lock;
400:
401: uint8_t pwrd;
402:
403: int sun4m;
404:
405: fdrive_t drives[2];
406: };
407:
408: static uint32_t fdctrl_read (void *opaque, uint32_t reg)
409: {
410: fdctrl_t *fdctrl = opaque;
411: uint32_t retval;
412:
413: switch (reg & 0x07) {
414: case 0x00:
415: if (fdctrl->sun4m) {
416:
417: retval = fdctrl_read_statusB(fdctrl);
418: } else {
419: retval = (uint32_t)(-1);
420: }
421: break;
422: case 0x01:
423: retval = fdctrl_read_statusB(fdctrl);
424: break;
425: case 0x02:
426: retval = fdctrl_read_dor(fdctrl);
427: break;
428: case 0x03:
429: retval = fdctrl_read_tape(fdctrl);
430: break;
431: case 0x04:
432: retval = fdctrl_read_main_status(fdctrl);
433: break;
434: case 0x05:
435: retval = fdctrl_read_data(fdctrl);
436: break;
437: case 0x07:
438: retval = fdctrl_read_dir(fdctrl);
439: break;
440: default:
441: retval = (uint32_t)(-1);
442: break;
443: }
444: FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
445:
446: return retval;
447: }
448:
449: static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
450: {
451: fdctrl_t *fdctrl = opaque;
452:
453: FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
454:
455: switch (reg & 0x07) {
456: case 0x02:
457: fdctrl_write_dor(fdctrl, value);
458: break;
459: case 0x03:
460: fdctrl_write_tape(fdctrl, value);
461: break;
462: case 0x04:
463: fdctrl_write_rate(fdctrl, value);
464: break;
465: case 0x05:
466: fdctrl_write_data(fdctrl, value);
467: break;
468: default:
469: break;
470: }
471: }
472:
473: static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
474: {
475: return fdctrl_read(opaque, (uint32_t)reg);
476: }
477:
478: static void fdctrl_write_mem (void *opaque,
479: target_phys_addr_t reg, uint32_t value)
480: {
481: fdctrl_write(opaque, (uint32_t)reg, value);
482: }
483:
484: static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
485: fdctrl_read_mem,
486: fdctrl_read_mem,
487: fdctrl_read_mem,
488: };
489:
490: static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
491: fdctrl_write_mem,
492: fdctrl_write_mem,
493: fdctrl_write_mem,
494: };
495:
496: static CPUReadMemoryFunc *fdctrl_mem_read_strict[3] = {
497: fdctrl_read_mem,
498: NULL,
499: NULL,
500: };
501:
502: static CPUWriteMemoryFunc *fdctrl_mem_write_strict[3] = {
503: fdctrl_write_mem,
504: NULL,
505: NULL,
506: };
507:
508: static void fd_save (QEMUFile *f, fdrive_t *fd)
509: {
510: uint8_t tmp;
511:
512: tmp = fd->drflags;
513: qemu_put_8s(f, &tmp);
514: qemu_put_8s(f, &fd->head);
515: qemu_put_8s(f, &fd->track);
516: qemu_put_8s(f, &fd->sect);
517: qemu_put_8s(f, &fd->dir);
518: qemu_put_8s(f, &fd->rw);
519: }
520:
521: static void fdc_save (QEMUFile *f, void *opaque)
522: {
523: fdctrl_t *s = opaque;
524:
525: qemu_put_8s(f, &s->state);
526: qemu_put_8s(f, &s->dma_en);
527: qemu_put_8s(f, &s->cur_drv);
528: qemu_put_8s(f, &s->bootsel);
529: qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
530: qemu_put_be32s(f, &s->data_pos);
531: qemu_put_be32s(f, &s->data_len);
532: qemu_put_8s(f, &s->data_state);
533: qemu_put_8s(f, &s->data_dir);
534: qemu_put_8s(f, &s->int_status);
535: qemu_put_8s(f, &s->eot);
536: qemu_put_8s(f, &s->timer0);
537: qemu_put_8s(f, &s->timer1);
538: qemu_put_8s(f, &s->precomp_trk);
539: qemu_put_8s(f, &s->config);
540: qemu_put_8s(f, &s->lock);
541: qemu_put_8s(f, &s->pwrd);
542: fd_save(f, &s->drives[0]);
543: fd_save(f, &s->drives[1]);
544: }
545:
546: static int fd_load (QEMUFile *f, fdrive_t *fd)
547: {
548: uint8_t tmp;
549:
550: qemu_get_8s(f, &tmp);
551: fd->drflags = tmp;
552: qemu_get_8s(f, &fd->head);
553: qemu_get_8s(f, &fd->track);
554: qemu_get_8s(f, &fd->sect);
555: qemu_get_8s(f, &fd->dir);
556: qemu_get_8s(f, &fd->rw);
557:
558: return 0;
559: }
560:
561: static int fdc_load (QEMUFile *f, void *opaque, int version_id)
562: {
563: fdctrl_t *s = opaque;
564: int ret;
565:
566: if (version_id != 1)
567: return -EINVAL;
568:
569: qemu_get_8s(f, &s->state);
570: qemu_get_8s(f, &s->dma_en);
571: