@@ -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);
}