PowerPC system emulation fixes (Jocelyn Mayer)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/hw/fdc.c b/hw/fdc.c
index 7d7837b..0de5578 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -83,7 +83,6 @@
     uint8_t dir;              /* Direction              */
     uint8_t rw;               /* Read/write             */
     /* Media */
-    fdisk_type_t disk;        /* Disk type              */
     fdisk_flags_t flags;
     uint8_t last_sect;        /* Nb sector per track    */
     uint8_t max_track;        /* Nb of tracks           */
@@ -102,7 +101,6 @@
     drv->drflags = 0;
     drv->perpendicular = 0;
     /* Disk */
-    drv->disk = FDRIVE_DISK_NONE;
     drv->last_sect = 0;
     drv->max_track = 0;
 }
@@ -171,26 +169,113 @@
     drv->rw = 0;
 }
 
+/* Recognize floppy formats */
+typedef struct fd_format_t {
+    fdrive_type_t drive;
+    fdisk_type_t  disk;
+    uint8_t last_sect;
+    uint8_t max_track;
+    uint8_t max_head;
+    const unsigned char *str;
+} fd_format_t;
+
+static fd_format_t fd_formats[] = {
+    /* First entry is default format */
+    /* 1.44 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1,  "1.6 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
+    /* 2.88 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
+    { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
+    { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1,  "3.2 MB 3\"1/2", },
+    { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
+    { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
+    /* 720 kB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 1,  "720 kB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1,  "800 kB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1,  "820 kB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1,  "830 kB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
+    { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
+    /* 1.2 MB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1,  "1.2 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1,  "1.6 MB 5\"1/4", },
+    /* 720 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 80, 1,  "720 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1,  "880 kB 5\"1/4", },
+    /* 360 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 1,  "360 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 0,  "180 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1,  "410 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1,  "420 kB 5\"1/4", },
+    /* 320 kB 5"1/4 floppy disks */ 
+    { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 1,  "320 kB 5\"1/4", },
+    { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 0,  "160 kB 5\"1/4", },
+    /* 360 kB must match 5"1/4 better than 3"1/2... */
+    { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 0,  "360 kB 3\"1/2", },
+    /* end */
+    { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
+};
+
 /* Revalidate a disk drive after a disk change */
 static void fd_revalidate (fdrive_t *drv)
 {
-    int64_t nb_sectors;
+    fd_format_t *parse;
+    int64_t nb_sectors, size;
+    int i, first_match, match;
     int nb_heads, max_track, last_sect, ro;
 
     FLOPPY_DPRINTF("revalidate\n");
     drv->drflags &= ~FDRIVE_REVALIDATE;
-
-    /* if no drive present, cannot do more */
-    if (!drv->bs)
-        return;
-
-    if (bdrv_is_inserted(drv->bs)) {
+    if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
 	ro = bdrv_is_read_only(drv->bs);
-	bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect);
+	bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
 	if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
-	    drv->disk = FDRIVE_DISK_USER;
 	    printf("User defined disk (%d %d %d)",
 		   nb_heads - 1, max_track, last_sect);
+	} else {
+	    bdrv_get_geometry(drv->bs, &nb_sectors);
+	    match = -1;
+	    first_match = -1;
+	    for (i = 0;; i++) {
+		parse = &fd_formats[i];
+		if (parse->drive == FDRIVE_DRV_NONE)
+		    break;
+		if (drv->drive == parse->drive ||
+		    drv->drive == FDRIVE_DRV_NONE) {
+		    size = (parse->max_head + 1) * parse->max_track *
+			parse->last_sect;
+		    if (nb_sectors == size) {
+			match = i;
+			break;
+		    }
+		    if (first_match == -1)
+			first_match = i;
+		}
+	    }
+	    if (match == -1) {
+		if (first_match == -1)
+		    match = 1;
+		else
+		    match = first_match;
+		parse = &fd_formats[match];
+	    }
+	    nb_heads = parse->max_head + 1;
+	    max_track = parse->max_track;
+	    last_sect = parse->last_sect;
+	    drv->drive = parse->drive;
+	    printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
+		   nb_heads, max_track, last_sect, ro ? "ro" : "rw");
+	}
 	    if (nb_heads == 1) {
 		drv->flags &= ~FDISK_DBL_SIDES;
 	    } else {
@@ -198,236 +283,9 @@
 	    }
 	    drv->max_track = max_track;
 	    drv->last_sect = last_sect;
-	} else {
-        bdrv_get_geometry(drv->bs, &nb_sectors);
-	    switch (nb_sectors) {
-            /* 2.88 MB 3"1/2 drive disks */
-	    case 7680:
-		printf("3.84 Mb 3\"1/2 disk (1 80 48)");
-		drv->drive = FDRIVE_DRV_288;
-		drv->disk = FDRIVE_DISK_288;
-		drv->last_sect = 48;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 7040:
-		printf("3.52 Mb 3\"1/2 disk (1 80 44)");
-		drv->drive = FDRIVE_DRV_288;
-		drv->disk = FDRIVE_DISK_288;
-		drv->last_sect = 44;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 6400:
-		printf("3.2 Mb 3\"1/2 disk (1 80 40)");
-		drv->drive = FDRIVE_DRV_288;
-		drv->disk = FDRIVE_DISK_288;
-		drv->last_sect = 40;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 6240:
-		printf("3.12 Mb 3\"1/2 disk (1 80 39)");
-		drv->drive = FDRIVE_DRV_288;
-		drv->disk = FDRIVE_DISK_288;
-		drv->last_sect = 39;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 5760:
-		printf("2.88 Mb 3\"1/2 disk (1 80 36)");
-		drv->drive = FDRIVE_DRV_288;
-            drv->disk = FDRIVE_DISK_288;
-            drv->last_sect = 36;
-            drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-
-            /* 1.44 MB 3"1/2 drive disks */
-	    case 3840:
-		printf("1.92 Mb 3\"1/2 disk (1 80 24)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 24;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3680:
-		printf("1.84 Mb 3\"1/2 disk (1 80 23)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 23;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3520:
-		printf("1.76 Mb 3\"1/2 disk (1 80 22)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 22;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3486:
-		printf("1.74 Mb 3\"1/2 disk (1 83 21)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 21;
-		drv->max_track = 83;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3444:
-		printf("1.72 Mb 3\"1/2 disk (1 82 21)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 21;
-		drv->max_track = 82;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3360:
-		printf("1.68 Mb 3\"1/2 disk (1 80 21)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 21;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 3200:
-		printf("1.6 Mb 3\"1/2 disk (1 80 20)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_144;
-		drv->last_sect = 20;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 2880:
-	    default:
-		printf("1.44 Mb 3\"1/2 disk (1 80 18)");
-		drv->drive = FDRIVE_DRV_144;
-            drv->disk = FDRIVE_DISK_144;
-            drv->last_sect = 18;
-            drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-
-            /* 720 kB 3"1/2 drive disks */
-	    case 2240:
-		printf("1.12 Mb 3\"1/2 disk (1 80 14)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_720;
-		drv->last_sect = 14;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 2080:
-		printf("1.04 Mb 3\"1/2 disk (1 80 13)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_720;
-		drv->last_sect = 13;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 1660:
-		printf("830 kb 3\"1/2 disk (1 83 10)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_720;
-		drv->last_sect = 10;
-		drv->max_track = 83;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 1640:
-		printf("820 kb 3\"1/2 disk (1 82 10)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_720;
-		drv->last_sect = 10;
-		drv->max_track = 82;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 1600:
-		printf("800 kb 3\"1/2 disk (1 80 10)");
-		drv->drive = FDRIVE_DRV_144;
-		drv->disk = FDRIVE_DISK_720;
-		drv->last_sect = 10;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 1440:
-		printf("720 kb 3\"1/2 disk (1 80 9)");
-		drv->drive = FDRIVE_DRV_144;
-            drv->disk = FDRIVE_DISK_720;
-            drv->last_sect = 9;
-            drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-
-	    /* 1.2 MB 5"1/4 drive disks */
-	    case 2988:
-		printf("1.49 Mb 5\"1/4 disk (1 83 18)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 18;
-		drv->max_track = 83;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 2952:
-		printf("1.48 Mb 5\"1/4 disk (1 82 18)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 18;
-		drv->max_track = 82;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-	    case 2400:
-		printf("1.2 Mb 5\"1/4 disk (1 80 15)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 15;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-
-	    case 1760:
-		printf("880 kb 5\"1/4 disk (1 80 11)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 11;
-		drv->max_track = 80;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-
-	    /* 360 kB 5"1/4 drive disks */
-	    case 840:
-		/* 420 kB 5"1/4 disk */
-		printf("420 kb 5\"1/4 disk (1 42 10)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 10;
-		drv->max_track = 42;
-		drv->flags |= FDISK_DBL_SIDES;
-	    case 820:
-		/* 410 kB 5"1/4 disk */
-		printf("410 kb 5\"1/4 disk (1 41 10)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 10;
-		drv->max_track = 41;
-		drv->flags |= FDISK_DBL_SIDES;
-	    case 720:
-		/* 360 kB 5"1/4 disk */
-		printf("360 kb 5\"1/4 disk (1 40 9)");
-		drv->drive = FDRIVE_DRV_120;
-		drv->disk = FDRIVE_DISK_144; /* ? */
-		drv->last_sect = 9;
-		drv->max_track = 40;
-		drv->flags |= FDISK_DBL_SIDES;
-		break;
-        }
-	    printf(" %s\n", ro == 0 ? "rw" : "ro");
-	}
 	drv->ro = ro;
     } else {
 	printf("No disk in drive\n");
-        drv->disk = FDRIVE_DISK_NONE;
         drv->last_sect = 0;
 	drv->max_track = 0;
 	drv->flags &= ~FDISK_DBL_SIDES;
@@ -544,20 +402,29 @@
     fdctrl_t *fdctrl = opaque;
     uint32_t retval;
 
-    if (reg == fdctrl->io_base + 0x01)
+    switch (reg & 0x07) {
+    case 0x01:
 	retval = fdctrl_read_statusB(fdctrl);
-    else if (reg == fdctrl->io_base + 0x02)
+	break;
+    case 0x02:
 	retval = fdctrl_read_dor(fdctrl);
-    else if (reg == fdctrl->io_base + 0x03)
+	break;
+    case 0x03:
         retval = fdctrl_read_tape(fdctrl);
-    else if (reg == fdctrl->io_base + 0x04)
+	break;
+    case 0x04:
         retval = fdctrl_read_main_status(fdctrl);
-    else if (reg == fdctrl->io_base + 0x05)
+	break;
+    case 0x05:
         retval = fdctrl_read_data(fdctrl);
-    else if (reg == fdctrl->io_base + 0x07)
+	break;
+    case 0x07:
         retval = fdctrl_read_dir(fdctrl);
-    else 
+	break;
+    default:
 	retval = (uint32_t)(-1);
+	break;
+    }
 
     return retval;
 }
@@ -566,14 +433,22 @@
 {
     fdctrl_t *fdctrl = opaque;
 
-    if (reg == fdctrl->io_base + 0x02)
+    switch (reg & 0x07) {
+    case 0x02:
 	fdctrl_write_dor(fdctrl, value);
-    else if (reg == fdctrl->io_base + 0x03)
+	break;
+    case 0x03:
         fdctrl_write_tape(fdctrl, value);
-    else if (reg == fdctrl->io_base + 0x04)
+	break;
+    case 0x04:
         fdctrl_write_rate(fdctrl, value);
-    else if (reg == fdctrl->io_base + 0x05)
+	break;
+    case 0x05:
         fdctrl_write_data(fdctrl, value);
+	break;
+    default:
+	break;
+    }
 }
 
 static void fd_change_cb (void *opaque)
@@ -581,7 +456,6 @@
     fdrive_t *drv = opaque;
 
     FLOPPY_DPRINTF("disk change\n");
-    /* TODO: use command-line parameters to force geometry */
     fd_revalidate(drv);
 #if 0
     fd_recalibrate(drv);
@@ -606,7 +480,7 @@
     fdctrl->irq_lvl = irq_lvl;
     fdctrl->dma_chann = dma_chann;
     fdctrl->io_base = io_base;
-    fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */
+    fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
     if (fdctrl->dma_chann != -1) {
         fdctrl->dma_en = 1;
         DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
@@ -634,9 +508,10 @@
         register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
         register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
     }
-    for (i = 0; i < MAX_FD; i++) {
+    for (i = 0; i < 2; i++) {
         fd_revalidate(&fdctrl->drives[i]);
     }
+
     return fdctrl;
 }