qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 06/14] fdc: support NEC PC-9821 family
@ 2009-09-09 15:42 武田 俊也
  2009-09-10  7:19 ` Alexander Graf
  0 siblings, 1 reply; 7+ messages in thread
From: 武田 俊也 @ 2009-09-09 15:42 UTC (permalink / raw)
  To: qemu-devel

This patch is to add NEC PC-9821 family i/o to fdc.

diff -ur a/hw/fdc.c b/hw/fdc.c
--- a/hw/fdc.c	Tue Sep  8 21:26:50 2009
+++ b/hw/fdc.c	Wed Sep  9 21:51:23 2009
@@ -85,6 +85,7 @@
     /* Drive status */
     fdrive_type_t drive;
     uint8_t perpendicular;    /* 2.88 MB access mode    */
+    uint8_t seek_result;
     /* Position */
     uint8_t head;
     uint8_t track;
@@ -175,6 +176,7 @@
     drv->head = 0;
     drv->track = 0;
     drv->sect = 1;
+    drv->seek_result = 0;
 }
 
 /* Recognize floppy formats */
@@ -387,6 +389,7 @@
 };
 
 enum {
+    FD_SR0_NOTRDY   = 0x08,
     FD_SR0_EQPMT    = 0x10,
     FD_SR0_SEEK     = 0x20,
     FD_SR0_ABNTERM  = 0x40,
@@ -507,8 +510,10 @@
     uint8_t pwrd;
     /* Sun4m quirks? */
     int sun4m;
+    /* NEC PC-98x1 quirks? */
+    int pc98;
     /* Floppy drives */
-    fdrive_t drives[MAX_FD];
+    fdrive_t drives[4];
     int reset_sensei;
 };
 
@@ -803,7 +808,7 @@
     fdctrl->data_len = 0;
     fdctrl->data_state = 0;
     fdctrl->data_dir = FD_DIR_WRITE;
-    for (i = 0; i < MAX_FD; i++)
+    for (i = 0; i < 4; i++)
         fd_recalibrate(&fdctrl->drives[i]);
     fdctrl_reset_fifo(fdctrl);
     if (do_irq) {
@@ -825,7 +830,6 @@
         return &fdctrl->drives[0];
 }
 
-#if MAX_FD == 4
 static inline fdrive_t *drv2 (fdctrl_t *fdctrl)
 {
     if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
@@ -841,7 +845,6 @@
     else
         return &fdctrl->drives[2];
 }
-#endif
 
 static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
 {
@@ -1603,11 +1606,28 @@
 
 static void fdctrl_handle_recalibrate (fdctrl_t *fdctrl, int direction)
 {
-    fdrive_t *cur_drv;
+    fdrive_t *cur_drv = NULL;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    fd_recalibrate(cur_drv);
+    if (fdctrl->pc98 && (fdctrl->fifo[1] & 3) >= MAX_FD) {
+        switch (fdctrl->fifo[1] & 3) {
+            case 0: cur_drv = drv0(fdctrl); break;
+            case 1: cur_drv = drv1(fdctrl); break;
+            case 2: cur_drv = drv2(fdctrl); break;
+            case 3: cur_drv = drv3(fdctrl); break;
+        }
+        if (cur_drv != NULL) {
+            cur_drv->seek_result = FD_SR0_ABNTERM | FD_SR0_SEEK | FD_SR0_NOTRDY;
+        }
+    } else {
+        SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+        cur_drv = get_cur_drv(fdctrl);
+        fd_recalibrate(cur_drv);
+        if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) {
+            cur_drv->seek_result = 0;
+        } else {
+            cur_drv->seek_result = FD_SR0_ABNTERM | FD_SR0_SEEK | FD_SR0_NOTRDY;
+        }
+    }
     fdctrl_reset_fifo(fdctrl);
     /* Raise Interrupt */
     fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
@@ -1615,39 +1635,72 @@
 
 static void fdctrl_handle_sense_interrupt_status (fdctrl_t *fdctrl, int direction)
 {
-    fdrive_t *cur_drv = get_cur_drv(fdctrl);
-
-    if(fdctrl->reset_sensei > 0) {
-        fdctrl->fifo[0] =
-            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
-        fdctrl->reset_sensei--;
+    if (fdctrl->pc98) {
+        int i;
+        for (i = 0; i < 4; i++) {
+            if (fdctrl->drives[i].seek_result) {
+                fdctrl->fifo[0] = fdctrl->drives[i].seek_result | i;
+                fdctrl->fifo[1] = fdctrl->drives[i].track;
+                fdctrl_set_fifo(fdctrl, 2, 0);
+                fdctrl->drives[i].seek_result = 0;
+                break;
+            }
+        }
+        if (i == 4) {
+            fdctrl->fifo[0] = FD_SR0_INVCMD;
+            fdctrl_set_fifo(fdctrl, 1, 0);
+            fdctrl_reset_irq(fdctrl);
+        }
     } else {
-        /* XXX: status0 handling is broken for read/write
-           commands, so we do this hack. It should be suppressed
-           ASAP */
-        fdctrl->fifo[0] =
-            FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
-    }
+        fdrive_t *cur_drv = get_cur_drv(fdctrl);
 
-    fdctrl->fifo[1] = cur_drv->track;
-    fdctrl_set_fifo(fdctrl, 2, 0);
-    fdctrl_reset_irq(fdctrl);
+        if(fdctrl->reset_sensei > 0) {
+            fdctrl->fifo[0] =
+                FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
+            fdctrl->reset_sensei--;
+        } else {
+            /* XXX: status0 handling is broken for read/write
+               commands, so we do this hack. It should be suppressed
+               ASAP */
+            fdctrl->fifo[0] =
+                FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+        }
+
+        fdctrl->fifo[1] = cur_drv->track;
+        fdctrl_set_fifo(fdctrl, 2, 0);
+        fdctrl_reset_irq(fdctrl);
+    }
     fdctrl->status0 = FD_SR0_RDYCHG;
 }
 
 static void fdctrl_handle_seek (fdctrl_t *fdctrl, int direction)
 {
-    fdrive_t *cur_drv;
+    fdrive_t *cur_drv = NULL;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    fdctrl_reset_fifo(fdctrl);
-    if (fdctrl->fifo[2] > cur_drv->max_track) {
-        fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
+    if (fdctrl->pc98 && (fdctrl->fifo[1] & 3) >= MAX_FD) {
+        switch (fdctrl->fifo[1] & 3) {
+            case 0: cur_drv = drv0(fdctrl); break;
+            case 1: cur_drv = drv1(fdctrl); break;
+            case 2: cur_drv = drv2(fdctrl); break;
+            case 3: cur_drv = drv3(fdctrl); break;
+        }
+        if (cur_drv != NULL) {
+            cur_drv->seek_result = FD_SR0_ABNTERM | FD_SR0_SEEK | FD_SR0_NOTRDY;
+        }
+        /* Raise Interrupt */
+        fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK | FD_SR0_NOTRDY);
     } else {
-        cur_drv->track = fdctrl->fifo[2];
+        SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+        cur_drv = get_cur_drv(fdctrl);
+        fdctrl_reset_fifo(fdctrl);
+        if (fdctrl->fifo[2] > cur_drv->max_track) {
+            cur_drv->seek_result = FD_SR0_ABNTERM | FD_SR0_SEEK;
+        } else {
+            cur_drv->track = fdctrl->fifo[2];
+            cur_drv->seek_result = FD_SR0_SEEK;
+        }
         /* Raise Interrupt */
-        fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
+        fdctrl_raise_irq(fdctrl, cur_drv->seek_result);
     }
 }
 
@@ -1860,6 +1913,92 @@
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
 
+/* NEC PC-98x1 */
+
+/*
+    MEMO: Use fdctrl->pwrd to store access mode flag:
+
+    bit0-3: 1.44MB access mode of drive #0-#3
+    bit5-6: drive select of bit0-3
+    bit7  : 1MB/640KB access mode
+*/
+
+static uint32_t pc98_fdctrl_read_port (void *opaque, uint32_t reg)
+{
+    fdctrl_t *fdctrl = opaque;
+    int bit;
+
+    switch (reg) {
+    case 0x90:
+        return fdctrl_read_main_status(fdctrl);
+    case 0x92:
+        return fdctrl_read_data(fdctrl);
+    case 0x94:
+        return 0x44;
+    case 0xbe:
+        if (fdctrl->pwrd & 0x80) {
+            return 0xff;
+        } else {
+            return 0xfd;
+        }
+    case 0x4be:
+        bit = 1 << ((fdctrl->pwrd >> 5) & 3);
+        if (fdctrl->pwrd & bit) {
+            return 0xff;
+        } else {
+            return 0xfe;
+        }
+    }
+    return 0xff;
+}
+
+static void pc98_fdctrl_write_port (void *opaque, uint32_t reg, uint32_t value)
+{
+    fdctrl_t *fdctrl = opaque;
+
+    switch (reg) {
+    case 0x90:
+        /* read-only */
+        break;
+    case 0x92:
+        fdctrl_write_data(fdctrl, value);
+        break;
+    case 0x94:
+        /* Reset */
+        if (!(value & 0x80)) {
+            if (fdctrl->dor & 0x80) {
+                FLOPPY_DPRINTF("controller enter RESET state\n");
+            }
+        } else {
+            if (!(fdctrl->dor & 0x80)) {
+                FLOPPY_DPRINTF("controller out of RESET state\n");
+                fdctrl_reset(fdctrl, 1);
+                fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+            }
+        }
+        fdctrl->dor = value;
+        break;
+    case 0xbe:
+        if (value & 2) {
+            fdctrl->pwrd |= 0x80;
+        } else {
+            fdctrl->pwrd &= ~0x80;
+        }
+        break;
+    case 0x4be:
+        if (value & 0x10) {
+            int bit = 1 << ((value >> 5) & 3);
+            if (value & 1) {
+                fdctrl->pwrd |= bit;
+            } else {
+                fdctrl->pwrd &= ~bit;
+            }
+        }
+        fdctrl->pwrd = (fdctrl->pwrd & ~0x60) | (value & 0x60);
+        break;
+    }
+}
+
 /* Init functions */
 static void fdctrl_connect_drives(fdctrl_t *fdctrl, BlockDriverState **fds)
 {
@@ -1933,6 +2072,24 @@
     return fdctrl;
 }
 
+fdctrl_t *pc98_fdctrl_init(int isairq, int dma_chann,
+                           uint32_t io_base,
+                           BlockDriverState **fds)
+{
+    fdctrl_t *fdctrl;
+    ISADevice *dev;
+
+    dev = isa_create_simple("pc98-fdc", io_base, 0, isairq, -1);
+    fdctrl = &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
+
+    fdctrl->dma_chann = dma_chann;
+    DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
+
+    fdctrl_connect_drives(fdctrl, fds);
+
+    return fdctrl;
+}
+
 static int fdctrl_init_common(fdctrl_t *fdctrl)
 {
     int i, j;
@@ -2010,6 +2167,27 @@
     return fdctrl_init_common(fdctrl);
 }
 
+static const int pc98_io_base[5] = {0x90, 0x92, 0x94, 0xbe, 0x4be};
+
+static int pc98_fdc_init1(ISADevice *dev)
+{
+    fdctrl_isabus_t *isa = DO_UPCAST(fdctrl_isabus_t, busdev, dev);
+    fdctrl_t *fdctrl = &isa->state;
+    int i;
+    uint32_t io_base = pc98_io_base[0];
+
+    for (i = 0; i < 5; i++) {
+        register_ioport_read(isa->busdev.iobase[0] + pc98_io_base[i] - io_base, 1, 1,
+                             &pc98_fdctrl_read_port, fdctrl);
+        register_ioport_write(isa->busdev.iobase[0] + pc98_io_base[i] - io_base, 1, 1,
+                              &pc98_fdctrl_write_port, fdctrl);
+    }
+    isa_init_irq(&isa->busdev, &fdctrl->irq);
+
+    fdctrl->pc98 = 1;
+    return fdctrl_init_common(fdctrl);
+}
+
 static ISADeviceInfo isa_fdc_info = {
     .init = isabus_fdc_init1,
     .qdev.name  = "isa-fdc",
@@ -2028,11 +2206,18 @@
     .qdev.size  = sizeof(fdctrl_sysbus_t),
 };
 
+static ISADeviceInfo pc98_fdc_info = {
+    .init = pc98_fdc_init1,
+    .qdev.name  = "pc98-fdc",
+    .qdev.size  = sizeof(fdctrl_isabus_t),
+};
+
 static void fdc_register_devices(void)
 {
     isa_qdev_register(&isa_fdc_info);
     sysbus_register_withprop(&sysbus_fdc_info);
     sysbus_register_withprop(&sun4m_fdc_info);
+    isa_qdev_register(&pc98_fdc_info);
 }
 
 device_init(fdc_register_devices)
diff -ur a/hw/fdc.h b/hw/fdc.h
--- a/hw/fdc.h	Tue Sep  8 21:26:50 2009
+++ b/hw/fdc.h	Wed Sep  9 21:51:31 2009
@@ -11,4 +11,7 @@
                              BlockDriverState **fds);
 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
                              BlockDriverState **fds, qemu_irq *fdc_tc);
+fdctrl_t *pc98_fdctrl_init(int isairq, int dma_chann,
+                           uint32_t io_base,
+                           BlockDriverState **fds);
 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 06/14] fdc: support NEC PC-9821 family
  2009-09-09 15:42 [Qemu-devel] [PATCH 06/14] " 武田 俊也
@ 2009-09-10  7:19 ` Alexander Graf
  2009-09-10 16:29   ` [Qemu-devel] " 武田 俊也
  0 siblings, 1 reply; 7+ messages in thread
From: Alexander Graf @ 2009-09-10  7:19 UTC (permalink / raw)
  To: 武田 俊也; +Cc: qemu-devel


On 09.09.2009, at 17:42, 武田 俊也 wrote:

> This patch is to add NEC PC-9821 family i/o to fdc.
>
> diff -ur a/hw/fdc.c b/hw/fdc.c
> --- a/hw/fdc.c	Tue Sep  8 21:26:50 2009
> +++ b/hw/fdc.c	Wed Sep  9 21:51:23 2009
> @@ -85,6 +85,7 @@
>     /* Drive status */
>     fdrive_type_t drive;
>     uint8_t perpendicular;    /* 2.88 MB access mode    */
> +    uint8_t seek_result;
>     /* Position */
>     uint8_t head;
>     uint8_t track;
> @@ -175,6 +176,7 @@
>     drv->head = 0;
>     drv->track = 0;
>     drv->sect = 1;
> +    drv->seek_result = 0;
> }
>
> /* Recognize floppy formats */
> @@ -387,6 +389,7 @@
> };
>
> enum {
> +    FD_SR0_NOTRDY   = 0x08,
>     FD_SR0_EQPMT    = 0x10,
>     FD_SR0_SEEK     = 0x20,
>     FD_SR0_ABNTERM  = 0x40,
> @@ -507,8 +510,10 @@
>     uint8_t pwrd;
>     /* Sun4m quirks? */
>     int sun4m;
> +    /* NEC PC-98x1 quirks? */
> +    int pc98;
>     /* Floppy drives */
> -    fdrive_t drives[MAX_FD];
> +    fdrive_t drives[4];

Just change MAX_FD?

Alex

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Qemu-devel] Re: [PATCH 06/14] fdc: support NEC PC-9821 family
  2009-09-10  7:19 ` Alexander Graf
@ 2009-09-10 16:29   ` 武田 俊也
  0 siblings, 0 replies; 7+ messages in thread
From: 武田 俊也 @ 2009-09-10 16:29 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel

Dear Alex,

>On 09.09.2009, at 17:42, 武田 俊也 wrote:
>
>> This patch is to add NEC PC-9821 family i/o to fdc.
>>
>> diff -ur a/hw/fdc.c b/hw/fdc.c
>> --- a/hw/fdc.c	Tue Sep  8 21:26:50 2009
>> +++ b/hw/fdc.c	Wed Sep  9 21:51:23 2009
>> @@ -85,6 +85,7 @@
>>     /* Drive status */
>>     fdrive_type_t drive;
>>     uint8_t perpendicular;    /* 2.88 MB access mode    */
>> +    uint8_t seek_result;
>>     /* Position */
>>     uint8_t head;
>>     uint8_t track;
>> @@ -175,6 +176,7 @@
>>     drv->head = 0;
>>     drv->track = 0;
>>     drv->sect = 1;
>> +    drv->seek_result = 0;
>> }
>>
>> /* Recognize floppy formats */
>> @@ -387,6 +389,7 @@
>> };
>>
>> enum {
>> +    FD_SR0_NOTRDY   = 0x08,
>>     FD_SR0_EQPMT    = 0x10,
>>     FD_SR0_SEEK     = 0x20,
>>     FD_SR0_ABNTERM  = 0x40,
>> @@ -507,8 +510,10 @@
>>     uint8_t pwrd;
>>     /* Sun4m quirks? */
>>     int sun4m;
>> +    /* NEC PC-98x1 quirks? */
>> +    int pc98;
>>     /* Floppy drives */
>> -    fdrive_t drives[MAX_FD];
>> +    fdrive_t drives[4];
>
>Just change MAX_FD?

Thank you very much for comments.

I tried the patch to support changing the drive number for each machine.
This patch does not includes PC-98x1 features.
If this direction is acceptable, I reimplement PC-98x1 patch based on it.

Now the drive number is initialized to MAX_FD for each machine,
but we need to consider the meaning of MAX_FD.


diff -ur a/hw/fdc.c b/hw/fdc.c
--- a/hw/fdc.c	Thu Sep 10 22:27:13 2009
+++ b/hw/fdc.c	Fri Sep 11 00:54:56 2009
@@ -52,6 +52,8 @@
 /********************************************************/
 /* Floppy drive emulation                               */
 
+#define MAX_FD_BUFFER 4
+
 #define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
 #define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
 
@@ -424,11 +426,6 @@
 };
 
 enum {
-#if MAX_FD == 4
-    FD_DOR_SELMASK  = 0x03,
-#else
-    FD_DOR_SELMASK  = 0x01,
-#endif
     FD_DOR_nRESET   = 0x04,
     FD_DOR_DMAEN    = 0x08,
     FD_DOR_MOTEN0   = 0x10,
@@ -437,13 +434,8 @@
     FD_DOR_MOTEN3   = 0x80,
 };
 
-enum {
-#if MAX_FD == 4
-    FD_TDR_BOOTSEL  = 0x0c,
-#else
-    FD_TDR_BOOTSEL  = 0x04,
-#endif
-};
+#define FD_DOR_SELMASK(fdctrl) (fdctrl->max_fd - 1)
+#define FD_TDR_BOOTSEL(fdctrl) ((fdctrl->max_fd - 1) << 2)
 
 enum {
     FD_DSR_DRATEMASK= 0x03,
@@ -473,6 +465,8 @@
 struct fdctrl_t {
     /* Controller's identification */
     uint8_t version;
+    /* Max drives (must be 2 or 4) */
+    uint8_t max_fd;
     /* HW */
     qemu_irq irq;
     int dma_chann;
@@ -508,7 +502,7 @@
     /* Sun4m quirks? */
     int sun4m;
     /* Floppy drives */
-    fdrive_t drives[MAX_FD];
+    fdrive_t drives[MAX_FD_BUFFER];
     int reset_sensei;
 };
 
@@ -637,7 +631,6 @@
 static void fdc_save (QEMUFile *f, void *opaque)
 {
     fdctrl_t *s = opaque;
-    uint8_t tmp;
     int i;
     uint8_t dor = s->dor | GET_CUR_DRV(s);
 
@@ -666,9 +659,8 @@
     qemu_put_8s(f, &s->lock);
     qemu_put_8s(f, &s->pwrd);
 
-    tmp = MAX_FD;
-    qemu_put_8s(f, &tmp);
-    for (i = 0; i < MAX_FD; i++)
+    qemu_put_8s(f, &s->max_fd);
+    for (i = 0; i < s->max_fd; i++)
         fd_save(f, &s->drives[i]);
 }
 
@@ -694,8 +686,8 @@
     qemu_get_8s(f, &s->sra);
     qemu_get_8s(f, &s->srb);
     qemu_get_8s(f, &s->dor);
-    SET_CUR_DRV(s, s->dor & FD_DOR_SELMASK);
-    s->dor &= ~FD_DOR_SELMASK;
+    SET_CUR_DRV(s, s->dor & FD_DOR_SELMASK(s));
+    s->dor &= ~FD_DOR_SELMASK(s);
     qemu_get_8s(f, &s->tdr);
     qemu_get_8s(f, &s->dsr);
     qemu_get_8s(f, &s->msr);
@@ -718,8 +710,9 @@
     qemu_get_8s(f, &s->pwrd);
     qemu_get_8s(f, &n);
 
-    if (n > MAX_FD)
+    if (n > MAX_FD_BUFFER)
         return -EINVAL;
+    s->max_fd = n;
 
     for (i = 0; i < n; i++) {
         ret = fd_load(f, &s->drives[i]);
@@ -803,7 +796,7 @@
     fdctrl->data_len = 0;
     fdctrl->data_state = 0;
     fdctrl->data_dir = FD_DIR_WRITE;
-    for (i = 0; i < MAX_FD; i++)
+    for (i = 0; i < fdctrl->max_fd; i++)
         fd_recalibrate(&fdctrl->drives[i]);
     fdctrl_reset_fifo(fdctrl);
     if (do_irq) {
@@ -814,21 +807,22 @@
 
 static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
 {
-    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
+    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) >> 2];
 }
 
 static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (1 << 2))
         return &fdctrl->drives[1];
     else
         return &fdctrl->drives[0];
 }
 
-#if MAX_FD == 4
 static inline fdrive_t *drv2 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
+    if (fdctrl->max_fd != 4)
+        return NULL;
+    else if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (2 << 2))
         return &fdctrl->drives[2];
     else
         return &fdctrl->drives[1];
@@ -836,22 +830,21 @@
 
 static inline fdrive_t *drv3 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
+    if (fdctrl->max_fd != 4)
+        return NULL;
+    else if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (3 << 2))
         return &fdctrl->drives[3];
     else
         return &fdctrl->drives[2];
 }
-#endif
 
 static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
 {
     switch (fdctrl->cur_drv) {
         case 0: return drv0(fdctrl);
         case 1: return drv1(fdctrl);
-#if MAX_FD == 4
         case 2: return drv2(fdctrl);
         case 3: return drv3(fdctrl);
-#endif
         default: return NULL;
     }
 }
@@ -921,7 +914,7 @@
         }
     }
     /* Selected drive */
-    fdctrl->cur_drv = value & FD_DOR_SELMASK;
+    fdctrl->cur_drv = value & FD_DOR_SELMASK(fdctrl);
 
     fdctrl->dor = value;
 }
@@ -945,7 +938,7 @@
     }
     FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
     /* Disk boot selection indicator */
-    fdctrl->tdr = value & FD_TDR_BOOTSEL;
+    fdctrl->tdr = value & FD_TDR_BOOTSEL(fdctrl);
     /* Tape indicators: never allow */
 }
 
@@ -1003,10 +996,8 @@
 
     if (fdctrl_media_changed(drv0(fdctrl))
      || fdctrl_media_changed(drv1(fdctrl))
-#if MAX_FD == 4
-     || fdctrl_media_changed(drv2(fdctrl))
-     || fdctrl_media_changed(drv3(fdctrl))
-#endif
+     || (fdctrl->max_fd == 4 && fdctrl_media_changed(drv2(fdctrl)))
+     || (fdctrl->max_fd == 4 && fdctrl_media_changed(drv3(fdctrl)))
         )
         retval |= FD_DIR_DSKCHG;
     if (retval != 0)
@@ -1109,7 +1100,7 @@
     uint8_t kh, kt, ks;
     int did_seek = 0;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     kt = fdctrl->fifo[2];
     kh = fdctrl->fifo[3];
@@ -1379,7 +1370,7 @@
     fdrive_t *cur_drv;
     uint8_t kh, kt, ks;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     kt = fdctrl->fifo[6];
     kh = fdctrl->fifo[7];
@@ -1450,13 +1441,13 @@
     /* Drives position */
     fdctrl->fifo[0] = drv0(fdctrl)->track;
     fdctrl->fifo[1] = drv1(fdctrl)->track;
-#if MAX_FD == 4
-    fdctrl->fifo[2] = drv2(fdctrl)->track;
-    fdctrl->fifo[3] = drv3(fdctrl)->track;
-#else
-    fdctrl->fifo[2] = 0;
-    fdctrl->fifo[3] = 0;
-#endif
+    if (fdctrl->max_fd == 4) {
+        fdctrl->fifo[2] = drv2(fdctrl)->track;
+        fdctrl->fifo[3] = drv3(fdctrl)->track;
+    } else {
+        fdctrl->fifo[2] = 0;
+        fdctrl->fifo[3] = 0;
+    }
     /* timers */
     fdctrl->fifo[4] = fdctrl->timer0;
     fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
@@ -1488,10 +1479,10 @@
     /* Drives position */
     drv0(fdctrl)->track = fdctrl->fifo[3];
     drv1(fdctrl)->track = fdctrl->fifo[4];
-#if MAX_FD == 4
-    drv2(fdctrl)->track = fdctrl->fifo[5];
-    drv3(fdctrl)->track = fdctrl->fifo[6];
-#endif
+    if (fdctrl->max_fd == 4) {
+        drv2(fdctrl)->track = fdctrl->fifo[5];
+        drv3(fdctrl)->track = fdctrl->fifo[6];
+    }
     /* timers */
     fdctrl->timer0 = fdctrl->fifo[7];
     fdctrl->timer1 = fdctrl->fifo[8];
@@ -1513,13 +1504,13 @@
     /* Drives position */
     fdctrl->fifo[2] = drv0(fdctrl)->track;
     fdctrl->fifo[3] = drv1(fdctrl)->track;
-#if MAX_FD == 4
-    fdctrl->fifo[4] = drv2(fdctrl)->track;
-    fdctrl->fifo[5] = drv3(fdctrl)->track;
-#else
-    fdctrl->fifo[4] = 0;
-    fdctrl->fifo[5] = 0;
-#endif
+    if (fdctrl->max_fd == 4) {
+        fdctrl->fifo[4] = drv2(fdctrl)->track;
+        fdctrl->fifo[5] = drv3(fdctrl)->track;
+    } else {
+        fdctrl->fifo[4] = 0;
+        fdctrl->fifo[5] = 0;
+    }
     /* timers */
     fdctrl->fifo[6] = fdctrl->timer0;
     fdctrl->fifo[7] = fdctrl->timer1;
@@ -1548,7 +1539,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fdctrl->data_state |= FD_STATE_FORMAT;
     if (fdctrl->fifo[0] & 0x80)
@@ -1589,7 +1580,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
     /* 1 Byte status back */
@@ -1605,7 +1596,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fd_recalibrate(cur_drv);
     fdctrl_reset_fifo(fdctrl);
@@ -1639,7 +1630,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fdctrl_reset_fifo(fdctrl);
     if (fdctrl->fifo[2] > cur_drv->max_track) {
@@ -1708,7 +1699,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
         cur_drv->track = cur_drv->max_track - 1;
@@ -1724,7 +1715,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     if (fdctrl->fifo[2] > cur_drv->track) {
         cur_drv->track = 0;
@@ -1865,7 +1856,7 @@
 {
     unsigned int i;
 
-    for (i = 0; i < MAX_FD; i++) {
+    for (i = 0; i < fdctrl->max_fd; i++) {
         fd_init(&fdctrl->drives[i], fds[i]);
         fd_revalidate(&fdctrl->drives[i]);
     }
@@ -1881,7 +1872,9 @@
     dev = isa_create_simple("isa-fdc", io_base, 0, isairq, -1);
     fdctrl = &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
 
+    fdctrl->max_fd = MAX_FD;
     fdctrl->dma_chann = dma_chann;
+
     DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
 
     fdctrl_connect_drives(fdctrl, fds);
@@ -1904,7 +1897,9 @@
     sysbus_connect_irq(&sys->busdev, 0, irq);
     sysbus_mmio_map(&sys->busdev, 0, mmio_base);
 
+    fdctrl->max_fd = MAX_FD;
     fdctrl->dma_chann = dma_chann;
+
     DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
     fdctrl_connect_drives(fdctrl, fds);
 
@@ -1926,6 +1921,7 @@
     sysbus_mmio_map(&sys->busdev, 0, io_base);
     *fdc_tc = qdev_get_gpio_in(dev, 0);
 
+    fdctrl->max_fd = MAX_FD;
     fdctrl->dma_chann = -1;
 
     fdctrl_connect_drives(fdctrl, fds);
@@ -1979,6 +1975,8 @@
                           &fdctrl_write_port, fdctrl);
     isa_init_irq(&isa->busdev, &fdctrl->irq);
 
+    fdctrl->max_fd = MAX_FD;
+
     return fdctrl_init_common(fdctrl);
 }
 
@@ -1992,6 +1990,8 @@
     sysbus_init_irq(dev, &fdctrl->irq);
     qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
 
+    fdctrl->max_fd = MAX_FD;
+
     return fdctrl_init_common(fdctrl);
 }
 
@@ -2006,7 +2006,9 @@
     sysbus_init_irq(dev, &fdctrl->irq);
     qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
 
+    fdctrl->max_fd = MAX_FD;
     fdctrl->sun4m = 1;
+
     return fdctrl_init_common(fdctrl);
 }
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Qemu-devel] Re: fdc: support NEC PC-9821 family
       [not found] <m3ocpig2kh.fsf@neno.mitica>
@ 2009-09-11 11:36 ` 武田 俊也
  2009-09-11 20:17   ` Stuart Brady
  0 siblings, 1 reply; 7+ messages in thread
From: 武田 俊也 @ 2009-09-11 11:36 UTC (permalink / raw)
  To: Juan Quintela; +Cc: Alexander Graf, qemu-devel

Dear Juan,

>t-takeda@m1.interq.or.jp (武田 俊也) wrote:
>> Dear Alex,
>>
>>>On 09.09.2009, at 17:42, 武田 俊也 wrote:
>>>
>>>> This patch is to add NEC PC-9821 family i/o to fdc.
>>>>
>>>> diff -ur a/hw/fdc.c b/hw/fdc.c
>>>> --- a/hw/fdc.c	Tue Sep  8 21:26:50 2009
>>>> +++ b/hw/fdc.c	Wed Sep  9 21:51:23 2009
	[snip]
>>>> @@ -507,8 +510,10 @@
>>>>     uint8_t pwrd;
>>>>     /* Sun4m quirks? */
>>>>     int sun4m;
>>>> +    /* NEC PC-98x1 quirks? */
>>>> +    int pc98;
>>>>     /* Floppy drives */
>>>> -    fdrive_t drives[MAX_FD];
>>>> +    fdrive_t drives[4];
>>>
>>>Just change MAX_FD?
>
>Could you just change MAX_FD = 4
>remove your MAX_FD_BUFFER
>and change all remaining users of MAX_FD to 2?
>The only places where MAX_FD is used now is in the init functions.

I modified the patch again.

MAX_FD_BUFFER is removed and MAX_FD is changed to the local definition.

In each machine, MAX_FD is defined for its machine's floppy drive number.
In fdc.c the floppy drive number is given by param of _init() function, 
so each machine can specify its own drive number.

>>      qemu_get_8s(f, &s->srb);
>>      qemu_get_8s(f, &s->dor);
	[snip]
>> @@ -718,8 +710,9 @@
>>      qemu_get_8s(f, &s->pwrd);
>>      qemu_get_8s(f, &n);
>>  
>> -    if (n > MAX_FD)
>> +    if (n > MAX_FD_BUFFER)
>>          return -EINVAL;
>> +    s->max_fd = n;
>
>You also need to check that is was the same than before.
>If you boot with 2 fd's and after load you get 4, things are going to be
>funny.

I modified to check the loaded drive number n == s->max_fd.

This is new patch.

diff -ur a/hw/fdc.c b/hw/fdc.c
--- a/hw/fdc.c	Thu Sep 10 22:27:14 2009
+++ b/hw/fdc.c	Fri Sep 11 18:40:22 2009
@@ -52,6 +52,8 @@
 /********************************************************/
 /* Floppy drive emulation                               */
 
+#define MAX_FD 4
+
 #define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
 #define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
 
@@ -424,11 +426,6 @@
 };
 
 enum {
-#if MAX_FD == 4
-    FD_DOR_SELMASK  = 0x03,
-#else
-    FD_DOR_SELMASK  = 0x01,
-#endif
     FD_DOR_nRESET   = 0x04,
     FD_DOR_DMAEN    = 0x08,
     FD_DOR_MOTEN0   = 0x10,
@@ -437,13 +434,8 @@
     FD_DOR_MOTEN3   = 0x80,
 };
 
-enum {
-#if MAX_FD == 4
-    FD_TDR_BOOTSEL  = 0x0c,
-#else
-    FD_TDR_BOOTSEL  = 0x04,
-#endif
-};
+#define FD_DOR_SELMASK(fdctrl) (fdctrl->max_fd - 1)
+#define FD_TDR_BOOTSEL(fdctrl) ((fdctrl->max_fd - 1) << 2)
 
 enum {
     FD_DSR_DRATEMASK= 0x03,
@@ -473,6 +465,8 @@
 struct fdctrl_t {
     /* Controller's identification */
     uint8_t version;
+    /* Max drives (must be 2 or 4) */
+    uint8_t max_fd;
     /* HW */
     qemu_irq irq;
     int dma_chann;
@@ -637,7 +631,6 @@
 static void fdc_save (QEMUFile *f, void *opaque)
 {
     fdctrl_t *s = opaque;
-    uint8_t tmp;
     int i;
     uint8_t dor = s->dor | GET_CUR_DRV(s);
 
@@ -666,9 +659,8 @@
     qemu_put_8s(f, &s->lock);
     qemu_put_8s(f, &s->pwrd);
 
-    tmp = MAX_FD;
-    qemu_put_8s(f, &tmp);
-    for (i = 0; i < MAX_FD; i++)
+    qemu_put_8s(f, &s->max_fd);
+    for (i = 0; i < s->max_fd; i++)
         fd_save(f, &s->drives[i]);
 }
 
@@ -694,8 +686,8 @@
     qemu_get_8s(f, &s->sra);
     qemu_get_8s(f, &s->srb);
     qemu_get_8s(f, &s->dor);
-    SET_CUR_DRV(s, s->dor & FD_DOR_SELMASK);
-    s->dor &= ~FD_DOR_SELMASK;
+    SET_CUR_DRV(s, s->dor & FD_DOR_SELMASK(s));
+    s->dor &= ~FD_DOR_SELMASK(s);
     qemu_get_8s(f, &s->tdr);
     qemu_get_8s(f, &s->dsr);
     qemu_get_8s(f, &s->msr);
@@ -718,10 +710,10 @@
     qemu_get_8s(f, &s->pwrd);
     qemu_get_8s(f, &n);
 
-    if (n > MAX_FD)
+    if (n > MAX_FD || n != s->max_fd)
         return -EINVAL;
 
-    for (i = 0; i < n; i++) {
+    for (i = 0; i < s->max_fd; i++) {
         ret = fd_load(f, &s->drives[i]);
         if (ret != 0)
             break;
@@ -803,7 +795,7 @@
     fdctrl->data_len = 0;
     fdctrl->data_state = 0;
     fdctrl->data_dir = FD_DIR_WRITE;
-    for (i = 0; i < MAX_FD; i++)
+    for (i = 0; i < fdctrl->max_fd; i++)
         fd_recalibrate(&fdctrl->drives[i]);
     fdctrl_reset_fifo(fdctrl);
     if (do_irq) {
@@ -814,12 +806,12 @@
 
 static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
 {
-    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
+    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) >> 2];
 }
 
 static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (1 << 2))
         return &fdctrl->drives[1];
     else
         return &fdctrl->drives[0];
@@ -828,7 +820,9 @@
 #if MAX_FD == 4
 static inline fdrive_t *drv2 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
+    if (fdctrl->max_fd != 4)
+        return NULL;
+    else if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (2 << 2))
         return &fdctrl->drives[2];
     else
         return &fdctrl->drives[1];
@@ -836,7 +830,9 @@
 
 static inline fdrive_t *drv3 (fdctrl_t *fdctrl)
 {
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
+    if (fdctrl->max_fd != 4)
+        return NULL;
+    else if ((fdctrl->tdr & FD_TDR_BOOTSEL(fdctrl)) < (3 << 2))
         return &fdctrl->drives[3];
     else
         return &fdctrl->drives[2];
@@ -921,7 +917,7 @@
         }
     }
     /* Selected drive */
-    fdctrl->cur_drv = value & FD_DOR_SELMASK;
+    fdctrl->cur_drv = value & FD_DOR_SELMASK(fdctrl);
 
     fdctrl->dor = value;
 }
@@ -945,7 +941,7 @@
     }
     FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
     /* Disk boot selection indicator */
-    fdctrl->tdr = value & FD_TDR_BOOTSEL;
+    fdctrl->tdr = value & FD_TDR_BOOTSEL(fdctrl);
     /* Tape indicators: never allow */
 }
 
@@ -1004,8 +1000,8 @@
     if (fdctrl_media_changed(drv0(fdctrl))
      || fdctrl_media_changed(drv1(fdctrl))
 #if MAX_FD == 4
-     || fdctrl_media_changed(drv2(fdctrl))
-     || fdctrl_media_changed(drv3(fdctrl))
+     || (fdctrl->max_fd == 4 && fdctrl_media_changed(drv2(fdctrl)))
+     || (fdctrl->max_fd == 4 && fdctrl_media_changed(drv3(fdctrl)))
 #endif
         )
         retval |= FD_DIR_DSKCHG;
@@ -1109,7 +1105,7 @@
     uint8_t kh, kt, ks;
     int did_seek = 0;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     kt = fdctrl->fifo[2];
     kh = fdctrl->fifo[3];
@@ -1379,7 +1375,7 @@
     fdrive_t *cur_drv;
     uint8_t kh, kt, ks;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     kt = fdctrl->fifo[6];
     kh = fdctrl->fifo[7];
@@ -1451,11 +1447,15 @@
     fdctrl->fifo[0] = drv0(fdctrl)->track;
     fdctrl->fifo[1] = drv1(fdctrl)->track;
 #if MAX_FD == 4
-    fdctrl->fifo[2] = drv2(fdctrl)->track;
-    fdctrl->fifo[3] = drv3(fdctrl)->track;
+    if (fdctrl->max_fd == 4) {
+        fdctrl->fifo[2] = drv2(fdctrl)->track;
+        fdctrl->fifo[3] = drv3(fdctrl)->track;
+    } else
 #else
-    fdctrl->fifo[2] = 0;
-    fdctrl->fifo[3] = 0;
+    {
+        fdctrl->fifo[2] = 0;
+        fdctrl->fifo[3] = 0;
+    }
 #endif
     /* timers */
     fdctrl->fifo[4] = fdctrl->timer0;
@@ -1489,8 +1489,10 @@
     drv0(fdctrl)->track = fdctrl->fifo[3];
     drv1(fdctrl)->track = fdctrl->fifo[4];
 #if MAX_FD == 4
-    drv2(fdctrl)->track = fdctrl->fifo[5];
-    drv3(fdctrl)->track = fdctrl->fifo[6];
+    if (fdctrl->max_fd == 4) {
+        drv2(fdctrl)->track = fdctrl->fifo[5];
+        drv3(fdctrl)->track = fdctrl->fifo[6];
+    }
 #endif
     /* timers */
     fdctrl->timer0 = fdctrl->fifo[7];
@@ -1514,11 +1516,15 @@
     fdctrl->fifo[2] = drv0(fdctrl)->track;
     fdctrl->fifo[3] = drv1(fdctrl)->track;
 #if MAX_FD == 4
-    fdctrl->fifo[4] = drv2(fdctrl)->track;
-    fdctrl->fifo[5] = drv3(fdctrl)->track;
+    if (fdctrl->max_fd == 4) {
+        fdctrl->fifo[4] = drv2(fdctrl)->track;
+        fdctrl->fifo[5] = drv3(fdctrl)->track;
+    } else
 #else
-    fdctrl->fifo[4] = 0;
-    fdctrl->fifo[5] = 0;
+    {
+        fdctrl->fifo[4] = 0;
+        fdctrl->fifo[5] = 0;
+    }
 #endif
     /* timers */
     fdctrl->fifo[6] = fdctrl->timer0;
@@ -1548,7 +1554,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fdctrl->data_state |= FD_STATE_FORMAT;
     if (fdctrl->fifo[0] & 0x80)
@@ -1589,7 +1595,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
     /* 1 Byte status back */
@@ -1605,7 +1611,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fd_recalibrate(cur_drv);
     fdctrl_reset_fifo(fdctrl);
@@ -1639,7 +1645,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     fdctrl_reset_fifo(fdctrl);
     if (fdctrl->fifo[2] > cur_drv->max_track) {
@@ -1708,7 +1714,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
         cur_drv->track = cur_drv->max_track - 1;
@@ -1724,7 +1730,7 @@
 {
     fdrive_t *cur_drv;
 
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK(fdctrl));
     cur_drv = get_cur_drv(fdctrl);
     if (fdctrl->fifo[2] > cur_drv->track) {
         cur_drv->track = 0;
@@ -1865,7 +1871,7 @@
 {
     unsigned int i;
 
-    for (i = 0; i < MAX_FD; i++) {
+    for (i = 0; i < fdctrl->max_fd; i++) {
         fd_init(&fdctrl->drives[i], fds[i]);
         fd_revalidate(&fdctrl->drives[i]);
     }
@@ -1873,15 +1879,21 @@
 
 fdctrl_t *fdctrl_init_isa(int isairq, int dma_chann,
                           uint32_t io_base,
-                          BlockDriverState **fds)
+                          BlockDriverState **fds, uint8_t max_fd)
 {
     fdctrl_t *fdctrl;
     ISADevice *dev;
 
+    if (max_fd > MAX_FD) {
+        hw_error("fdctrl_init_isa: invalid max_fd");
+    }
+
     dev = isa_create_simple("isa-fdc", io_base, 0, isairq, -1);
     fdctrl = &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
 
     fdctrl->dma_chann = dma_chann;
+    fdctrl->max_fd = max_fd;
+
     DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
 
     fdctrl_connect_drives(fdctrl, fds);
@@ -1891,12 +1903,16 @@
 
 fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                              target_phys_addr_t mmio_base,
-                             BlockDriverState **fds)
+                             BlockDriverState **fds, uint8_t max_fd)
 {
     fdctrl_t *fdctrl;
     DeviceState *dev;
     fdctrl_sysbus_t *sys;
 
+    if (max_fd > MAX_FD) {
+        hw_error("fdctrl_init_sysbus: invalid max_fd");
+    }
+
     dev = qdev_create(NULL, "sysbus-fdc");
     qdev_init(dev);
     sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
@@ -1905,6 +1921,8 @@
     sysbus_mmio_map(&sys->busdev, 0, mmio_base);
 
     fdctrl->dma_chann = dma_chann;
+    fdctrl->max_fd = max_fd;
+
     DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
     fdctrl_connect_drives(fdctrl, fds);
 
@@ -1912,12 +1930,17 @@
 }
 
 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
-                             BlockDriverState **fds, qemu_irq *fdc_tc)
+                             BlockDriverState **fds, uint8_t max_fd,
+                             qemu_irq *fdc_tc)
 {
     DeviceState *dev;
     fdctrl_sysbus_t *sys;
     fdctrl_t *fdctrl;
 
+    if (max_fd > MAX_FD) {
+        hw_error("sun4m_fdctrl_init: invalid max_fd");
+    }
+
     dev = qdev_create(NULL, "SUNW,fdtwo");
     qdev_init(dev);
     sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
@@ -1927,6 +1950,7 @@
     *fdc_tc = qdev_get_gpio_in(dev, 0);
 
     fdctrl->dma_chann = -1;
+    fdctrl->max_fd = max_fd;
 
     fdctrl_connect_drives(fdctrl, fds);
 
diff -ur a/hw/fdc.h b/hw/fdc.h
--- a/hw/fdc.h	Thu Sep 10 22:27:14 2009
+++ b/hw/fdc.h	Fri Sep 11 18:19:56 2009
@@ -1,14 +1,13 @@
 /* fdc.c */
-#define MAX_FD 2
-
 typedef struct fdctrl_t fdctrl_t;
 
 fdctrl_t *fdctrl_init_isa(int isairq, int dma_chann,
                           uint32_t io_base,
-                          BlockDriverState **fds);
+                          BlockDriverState **fds, uint8_t max_fd);
 fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                              target_phys_addr_t mmio_base,
-                             BlockDriverState **fds);
+                             BlockDriverState **fds, uint8_t max_fd);
 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
-                             BlockDriverState **fds, qemu_irq *fdc_tc);
+                             BlockDriverState **fds, uint8_t max_fd,
+                             qemu_irq *fdc_tc);
 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
diff -ur a/hw/mips_jazz.c b/hw/mips_jazz.c
--- a/hw/mips_jazz.c	Thu Sep 10 22:27:14 2009
+++ b/hw/mips_jazz.c	Fri Sep 11 18:49:52 2009
@@ -113,6 +113,8 @@
 #define MAGNUM_BIOS_SIZE_MAX 0x7e000
 #define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
 
+#define MAX_FD 2
+
 static
 void mips_jazz_init (ram_addr_t ram_size,
                      const char *cpu_model,
@@ -238,7 +240,7 @@
         DriveInfo *dinfo = drive_get(IF_FLOPPY, 0, n);
         fds[n] = dinfo ? dinfo->bdrv : NULL;
     }
-    fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
+    fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds, MAX_FD);
 
     /* Real time clock */
     rtc_init(0x70, i8259[8], 1980);
diff -ur a/hw/mips_malta.c b/hw/mips_malta.c
--- a/hw/mips_malta.c	Thu Sep 10 22:27:14 2009
+++ b/hw/mips_malta.c	Fri Sep 11 18:48:16 2009
@@ -55,6 +55,7 @@
 #define ENVP_ENTRY_SIZE	 	256
 
 #define MAX_IDE_BUS 2
+#define MAX_FD 2
 
 typedef struct {
     uint32_t leds;
@@ -932,7 +933,7 @@
         dinfo = drive_get(IF_FLOPPY, 0, i);
         fd[i] = dinfo ? dinfo->bdrv : NULL;
     }
-    floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd);
+    floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd, MAX_FD);
 
     /* Sound card */
 #ifdef HAS_AUDIO
diff -ur a/hw/pc.c b/hw/pc.c
--- a/hw/pc.c	Thu Sep 10 22:27:14 2009
+++ b/hw/pc.c	Fri Sep 11 18:24:52 2009
@@ -58,6 +58,7 @@
 #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
 
 #define MAX_IDE_BUS 2
+#define MAX_FD 2
 
 static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
@@ -1382,7 +1383,7 @@
         dinfo = drive_get(IF_FLOPPY, 0, i);
         fd[i] = dinfo ? dinfo->bdrv : NULL;
     }
-    floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd);
+    floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd, MAX_FD);
 
     cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
 
diff -ur a/hw/ppc_prep.c b/hw/ppc_prep.c
--- a/hw/ppc_prep.c	Thu Sep 10 22:27:14 2009
+++ b/hw/ppc_prep.c	Fri Sep 11 18:46:44 2009
@@ -41,6 +41,7 @@
 #define MAX_CPUS 1
 
 #define MAX_IDE_BUS 2
+#define MAX_FD 2
 
 #define BIOS_SIZE (1024 * 1024)
 #define BIOS_FILENAME "ppc_rom.bin"
@@ -719,7 +720,7 @@
         dinfo = drive_get(IF_FLOPPY, 0, i);
         fd[i] = dinfo ? dinfo->bdrv : NULL;
     }
-    fdctrl_init_isa(6, 2, 0x3f0, fd);
+    fdctrl_init_isa(6, 2, 0x3f0, fd, MAX_FD);
 
     /* Register speaker port */
     register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
diff -ur a/hw/sun4m.c b/hw/sun4m.c
--- a/hw/sun4m.c	Thu Sep 10 22:27:14 2009
+++ b/hw/sun4m.c	Fri Sep 11 18:45:18 2009
@@ -81,6 +81,7 @@
 #define PROM_SIZE_MAX        (1024 * 1024)
 #define PROM_VADDR           0xffd00000
 #define PROM_FILENAME        "openbios-sparc32"
+#define MAX_FD               2
 #define CFG_ADDR             0xd00000510ULL
 #define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00)
 
@@ -827,7 +828,7 @@
         if (dinfo)
             fd[0] = dinfo->bdrv;
 
-        sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
+        sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd, MAX_FD,
                           &fdc_tc);
     }
 
@@ -1611,7 +1612,7 @@
         if (dinfo)
             fd[0] = dinfo->bdrv;
 
-        sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
+        sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd, MAX_FD,
                           &fdc_tc);
     }
 
diff -ur a/hw/sun4u.c b/hw/sun4u.c
--- a/hw/sun4u.c	Thu Sep 10 22:27:14 2009
+++ b/hw/sun4u.c	Fri Sep 11 18:42:18 2009
@@ -55,6 +55,7 @@
 #define PROM_FILENAME        "openbios-sparc64"
 #define NVRAM_SIZE           0x2000
 #define MAX_IDE_BUS          2
+#define MAX_FD               2
 #define BIOS_CFG_IOPORT      0x510
 #define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
 #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
@@ -622,7 +623,7 @@
         dinfo = drive_get(IF_FLOPPY, 0, i);
         fd[i] = dinfo ? dinfo->bdrv : NULL;
     }
-    fdctrl_init_isa(6, 2, 0x3f0, fd);
+    fdctrl_init_isa(6, 2, 0x3f0, fd, MAX_FD);
     /* FIXME: wire up interrupts.  */
     nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] Re: fdc: support NEC PC-9821 family
  2009-09-11 11:36 ` [Qemu-devel] Re: fdc: support NEC PC-9821 family 武田 俊也
@ 2009-09-11 20:17   ` Stuart Brady
  2009-09-12  4:02     ` 武田 俊也
  0 siblings, 1 reply; 7+ messages in thread
From: Stuart Brady @ 2009-09-11 20:17 UTC (permalink / raw)
  To: qemu-devel

On Fri, Sep 11, 2009 at 08:36:02PM +0900, 武田 俊也 wrote:
> This is new patch.

Nice work -- looks a lot closer! :)

I've a few questions, though.

I notice that the 82078 has 'PC AT', 'PS/2' and 'PS/2 Model 30' modes.
QEMU doesn't seem to implement this, but I don't know common each of the
different modes is/was.

Also, I notice that in fdctrl_write_dor(), the DR0 bit (in PS/2 mode)
is set if drives 0 or 2 are selected, which looks like a bug -- I would
expect that it should only be set if drive 0 is selected.

AFAIK, in most IBM PC 'clones' (but not quite all), the FDC can support
four drives, but only up to one/two drives can be physically attached.

It seems that MAX_FD affects emulation of the FDC itself, and doesn't
just determine the number of drives that may be connected.  Surely that
can't be right?  I.e. if MAX_FD == 2, any attempt to select drive 2
results in drive 0 being selected, which should not be the case...

I'm not sure why QEMU limits certain machines to two drives...  Maybe
the reason is that software for systems where only two drives can be
physically connected might react badly to seeing unexpected drives.
Is this the case?  TBH, I'm not sure whether I *really* need more than
a single drive... :)

Also, it seems to me that a floppy controller might have either one,
two, three, four or no drives attached.  (I assume that software can
distinguish between a missing drive and a drive with no disk inserted.)
In that case, it seems to me that QEMU cannot provide emulation of a
system with no drives connected to its FDC.

Cheers,
-- 
Stuart Brady

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] Re: fdc: support NEC PC-9821 family
  2009-09-11 20:17   ` Stuart Brady
@ 2009-09-12  4:02     ` 武田 俊也
  2009-09-15 12:28       ` Natalia Portillo
  0 siblings, 1 reply; 7+ messages in thread
From: 武田 俊也 @ 2009-09-12  4:02 UTC (permalink / raw)
  To: Stuart Brady; +Cc: qemu-devel

Dear Stuart and members,

>On Fri, Sep 11, 2009 at 08:36:02PM +0900, 武田 俊也 wrote:
>> This is new patch.
>
>Nice work -- looks a lot closer! :)
>
>I've a few questions, though.
>
>I notice that the 82078 has 'PC AT', 'PS/2' and 'PS/2 Model 30' modes.
>QEMU doesn't seem to implement this, but I don't know common each of the
>different modes is/was.
>
>Also, I notice that in fdctrl_write_dor(), the DR0 bit (in PS/2 mode)
>is set if drives 0 or 2 are selected, which looks like a bug -- I would
>expect that it should only be set if drive 0 is selected.
>
>AFAIK, in most IBM PC 'clones' (but not quite all), the FDC can support
>four drives, but only up to one/two drives can be physically attached.
>
>It seems that MAX_FD affects emulation of the FDC itself, and doesn't
>just determine the number of drives that may be connected.  Surely that
>can't be right?  I.e. if MAX_FD == 2, any attempt to select drive 2
>results in drive 0 being selected, which should not be the case...
>
>I'm not sure why QEMU limits certain machines to two drives...  Maybe
>the reason is that software for systems where only two drives can be
>physically connected might react badly to seeing unexpected drives.
>Is this the case?  TBH, I'm not sure whether I *really* need more than
>a single drive... :)
>
>Also, it seems to me that a floppy controller might have either one,
>two, three, four or no drives attached.  (I assume that software can
>distinguish between a missing drive and a drive with no disk inserted.)
>In that case, it seems to me that QEMU cannot provide emulation of a
>system with no drives connected to its FDC.
>
>Cheers,
>-- 
>Stuart Brady

I agree.

In PC-98x1 family case (uPD765A is used for fdc), bios checks which drive
the disket is inserted to, by the commands below:
	recalib to drive0
	recalib to drive1
	recalib to drive2
	recalib to drive3
	sence interrupt stat
Yes, if MAX_FD = 2, it is recognized the same drive is connected to
drive0 and drive2, drive1 and drive3.
So I need to change MAX_FD to 4 for PC-98x1 family.

I think we need to divide MAX_FD for 2 meanings,
the number of drives that floppy drive controller can control, is always 4,
and the number of drives that each machine has, is 2 or 4.
For example, MAX_FD used in FD_DOR_SELMASK definition is the former.
MAX_FD in save/load function is the latter.

(Sorry I don't enough about 82078, so I cannot comment about PC/AT and
other mode.)

Thanks,
TAKEDA, toshiya

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] Re: fdc: support NEC PC-9821 family
  2009-09-12  4:02     ` 武田 俊也
@ 2009-09-15 12:28       ` Natalia Portillo
  0 siblings, 0 replies; 7+ messages in thread
From: Natalia Portillo @ 2009-09-15 12:28 UTC (permalink / raw)
  To: 武田 俊也; +Cc: qemu-devel

I can assure you all the Shugart based controlers (NEC FD765 and  
derived like the Intel 82078) do support four drives per controller.

El 12/09/2009, a las 5:02, 武田 俊也 escribió:

> Dear Stuart and members,
>
>> On Fri, Sep 11, 2009 at 08:36:02PM +0900, 武田 俊也 wrote:
>>> This is new patch.
>>
>> Nice work -- looks a lot closer! :)
>>
>> I've a few questions, though.
>>
>> I notice that the 82078 has 'PC AT', 'PS/2' and 'PS/2 Model 30'  
>> modes.
>> QEMU doesn't seem to implement this, but I don't know common each  
>> of the
>> different modes is/was.
>>
>> Also, I notice that in fdctrl_write_dor(), the DR0 bit (in PS/2 mode)
>> is set if drives 0 or 2 are selected, which looks like a bug -- I  
>> would
>> expect that it should only be set if drive 0 is selected.
>>
>> AFAIK, in most IBM PC 'clones' (but not quite all), the FDC can  
>> support
>> four drives, but only up to one/two drives can be physically  
>> attached.
>>
>> It seems that MAX_FD affects emulation of the FDC itself, and doesn't
>> just determine the number of drives that may be connected.  Surely  
>> that
>> can't be right?  I.e. if MAX_FD == 2, any attempt to select drive 2
>> results in drive 0 being selected, which should not be the case...
>>
>> I'm not sure why QEMU limits certain machines to two drives...  Maybe
>> the reason is that software for systems where only two drives can be
>> physically connected might react badly to seeing unexpected drives.
>> Is this the case?  TBH, I'm not sure whether I *really* need more  
>> than
>> a single drive... :)
>>
>> Also, it seems to me that a floppy controller might have either one,
>> two, three, four or no drives attached.  (I assume that software can
>> distinguish between a missing drive and a drive with no disk  
>> inserted.)
>> In that case, it seems to me that QEMU cannot provide emulation of a
>> system with no drives connected to its FDC.
>>
>> Cheers,
>> -- 
>> Stuart Brady
>
> I agree.
>
> In PC-98x1 family case (uPD765A is used for fdc), bios checks which  
> drive
> the disket is inserted to, by the commands below:
> 	recalib to drive0
> 	recalib to drive1
> 	recalib to drive2
> 	recalib to drive3
> 	sence interrupt stat
> Yes, if MAX_FD = 2, it is recognized the same drive is connected to
> drive0 and drive2, drive1 and drive3.
> So I need to change MAX_FD to 4 for PC-98x1 family.
>
> I think we need to divide MAX_FD for 2 meanings,
> the number of drives that floppy drive controller can control, is  
> always 4,
> and the number of drives that each machine has, is 2 or 4.
> For example, MAX_FD used in FD_DOR_SELMASK definition is the former.
> MAX_FD in save/load function is the latter.
>
> (Sorry I don't enough about 82078, so I cannot comment about PC/AT and
> other mode.)
>
> Thanks,
> TAKEDA, toshiya
>
>
>
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-09-15 12:28 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <m3ocpig2kh.fsf@neno.mitica>
2009-09-11 11:36 ` [Qemu-devel] Re: fdc: support NEC PC-9821 family 武田 俊也
2009-09-11 20:17   ` Stuart Brady
2009-09-12  4:02     ` 武田 俊也
2009-09-15 12:28       ` Natalia Portillo
2009-09-09 15:42 [Qemu-devel] [PATCH 06/14] " 武田 俊也
2009-09-10  7:19 ` Alexander Graf
2009-09-10 16:29   ` [Qemu-devel] " 武田 俊也

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).