]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
DraCo Amiga HD disk support, PC disk write/format support, keyboard repeat support.
authorToni Wilen <twilen@winuae.net>
Sun, 14 Jan 2024 13:43:50 +0000 (15:43 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 14 Jan 2024 13:43:50 +0000 (15:43 +0200)
draco.cpp
include/draco.h
inputdevice.cpp
inputevents.def
od-win32/winuae_msvc15/keyboard_at_draco.cpp
x86.cpp

index 9514dfcebfa88a3a174ac06deb6e113a3de4df13..aadb3d7d07c79dd7714824583a046f314e2faaad 100644 (file)
--- a/draco.cpp
+++ b/draco.cpp
@@ -20,6 +20,7 @@
 #include "zfile.h"
 #include "keybuf.h"
 #include "rommgr.h"
+#include "disk.h"
 
 static int maxcnt = 100;
 
@@ -650,43 +651,56 @@ static void draco_1wire_reset(void)
 #endif
 }
 
+static uae_u16 draco_floppy_data;
+static int draco_floppy_bits, draco_floppy_rate;
+
 // draco reads amiga disks by polling register
 // that returns time since last flux change.
 static uae_u8 draco_floppy_get_data(void)
 {
-       static uae_u16 data;
-       static int bits;
-       if (bits < 8) {
-               uae_u16 t = floppy_get_raw_data();
-               data |= (t & 0xff) << (8 - bits);
-               bits += 8;
+       if (draco_floppy_bits < 8) {
+               uae_u16 t = floppy_get_raw_data(&draco_floppy_rate);
+               draco_floppy_data |= (t & 0xff) << (8 - draco_floppy_bits);
+               draco_floppy_bits += 8;
        }
-       int bit1 = (data & 0x8000);
-       int bit2 = (data & 0x4000);
-       int bit3 = (data & 0x2000);
-       int bit4 = (data & 0x1000);
+       int bit1 = (draco_floppy_data & 0x8000);
+       int bit2 = (draco_floppy_data & 0x4000);
+       int bit3 = (draco_floppy_data & 0x2000);
+       int bit4 = (draco_floppy_data & 0x1000);
+       int v = 0;
 
        if (bit1) {
-               data <<= 1;
-               bits--;
-               return 8;
-       }
-       if (bit2) {
-               data <<= 2;
-               bits -= 2;
-               return 24;
+               draco_floppy_data <<= 1;
+               draco_floppy_bits--;
+               v = 8;
+       } else if (bit2) {
+               draco_floppy_data <<= 2;
+               draco_floppy_bits -= 2;
+               v = 24;
+       } else if (bit3) {
+               draco_floppy_data <<= 3;
+               draco_floppy_bits -= 3;
+               v = 40;
+       } else if (bit4) {
+               draco_floppy_data <<= 4;
+               draco_floppy_bits -= 4;
+               v = 56;
        }
-       if (bit3) {
-               data <<= 3;
-               bits -= 3;
-               return 40;
-       }
-       if (bit4) {
-               data <<= 4;
-               bits -= 4;
-               return 56;
+       switch (draco_floppy_rate) {
+               case FLOPPY_RATE_250K:
+                       // above values are in 250Kbs
+                       break;
+               case FLOPPY_RATE_500K:
+                       v /= 2;
+                       break;
+               case FLOPPY_RATE_300K:
+                       v = v * 30 / 25;
+                       break;
+               case FLOPPY_RATE_1M:
+                       v /= 4;
+                       break;
        }
-       return 0;
+       return v;
 }
 
 static void vmotion_write(uaecptr addr, uae_u8 v)
@@ -1184,7 +1198,7 @@ void draco_ext_interrupt(bool i6)
        draco_irq();
 }
 
-void draco_keycode(uae_u8 scancode, uae_u8 state)
+void draco_keycode(uae_u16 scancode, uae_u8 state)
 {
        if (currprefs.cs_compatible == CP_DRACO && (currprefs.cpuboard_settings & 0x10)) {
                if (draco_kbd_buffer_len == 0 && !(draco_reg[3] & DRSTAT_KBDRECV)) {
@@ -1300,6 +1314,8 @@ void draco_reset(int hardreset)
        draco_superio_cfg[6] = 0xff;
        draco_superio_cfg[13] = 0x65;
        draco_superio_cfg[14] = 1;
+       draco_floppy_data = 0;
+       draco_floppy_bits = 0;
        memset(draco_reg, 0, sizeof(draco_reg));
        draco_reg[1] = DRCNTRL_FDCINTENA | DRCNTRL_KBDINTENA;
        draco_reg[5] = 0xff;
index ce98ffa005025c2fa1f48feb973122e64c26a1cc..58e709b74ccc1ff15bf161a841e30a79e7daae85 100644 (file)
@@ -6,4 +6,4 @@ void draco_free(void);
 bool draco_mouse(int port, int x, int y, int z, int b);
 void draco_bustimeout(uaecptr addr);
 void draco_ext_interrupt(bool);
-void draco_keycode(uae_u8 scancode, uae_u8 state);
+void draco_keycode(uae_u16 scancode, uae_u8 state);
index 2a0430cbfafd9dcca4dbaf09c959a359720fa7a0..7d3a052526c4f5c7ca616897b868dae43f874c5a 100644 (file)
@@ -199,6 +199,9 @@ static int temp_uid_cnt[IDTYPE_MAX];
 static int gp_swappeddevices[MAX_INPUT_DEVICES][IDTYPE_MAX];
 static int osk_state;
 
+extern int draco_keyboard_get_rate(void);
+static int draco_keybord_repeat_cnt, draco_keybord_repeat_code;
+
 bool osk_status(void)
 {
        return osk_state != 0;
@@ -4382,6 +4385,17 @@ void inputdevice_hsync (bool forceread)
                        maybe_read_input();
                }
        }
+       if (draco_keybord_repeat_cnt > 0) {
+               draco_keybord_repeat_cnt--;
+               if (draco_keybord_repeat_cnt == 0) {
+                       int rate = draco_keyboard_get_rate();
+                       int b = (rate >> 3) & 3;
+                       int d = (rate >> 0) & 7;
+                       float r = ((1 << b) * (d + 8) / 240.0f) * 1000.0f;
+                       draco_keybord_repeat_cnt = (int)(vblank_hz * maxvpos * r / 1000);
+                       draco_keycode(draco_keybord_repeat_code, 1);
+               }
+       }
 }
 
 static uae_u16 POTDAT (int joy)
@@ -5800,6 +5814,7 @@ void inputdevice_reset (void)
        lightpen_trigger2 = 0;
        cubo_flag = 0;
        alg_flag &= 1;
+       draco_keybord_repeat_cnt = 0;
 }
 
 static int getoldport (struct uae_input_device *id)
@@ -10458,9 +10473,18 @@ void inputdevice_draco_key(int kc)
                if (events[i].data == kc && events[i].data2 && events[i].allow_mask == AM_K) {
                        int code = events[i].data2;
                        if ((code & 0xff00) == 0xe000) {
-                               draco_keycode((code & 0xff) | 0x100, state);
+                               code = (code & 0xff) | 0x100;
+                       } else {
+                               code &= 0xff;
+                       }
+                       draco_keycode(code, state);
+                       if (state) {
+                               int rate = draco_keyboard_get_rate();
+                               int init = ((rate >> 5) & 3) * 250 + 250;
+                               draco_keybord_repeat_cnt = (int)(vblank_hz * maxvpos * init / 1000);
+                               draco_keybord_repeat_code = code;
                        } else {
-                               draco_keycode(code & 0xff, state);
+                               draco_keybord_repeat_code = 0;
                        }
                }
        }
index 2efefe5eee856b231280fd08f5055d3429789359..6d82f849b417854631eaa3d95eaa2c0729f155a9 100644 (file)
@@ -196,7 +196,7 @@ DEFEVENTKB(KEY_ALT_LEFT,_T("Left Alt"),AM_K,AK_LALT,0x38)
 DEFEVENTKB(KEY_AMIGA_LEFT,_T("Left Amiga"),AM_K,AK_LAMI,0xe05b)
 DEFEVENTKB(KEY_AMIGA_RIGHT,_T("Right Amiga"),AM_K,AK_RAMI,0xe05c)
 DEFEVENTKB(KEY_ALT_RIGHT,_T("Right Alt"),AM_K,AK_RALT,0xe038)
-DEFEVENTKB(KEY_SHIFT_RIGHT,_T("Right Shift"),AM_K,AK_RSH,0x59)
+DEFEVENTKB(KEY_SHIFT_RIGHT,_T("Right Shift"),AM_K,AK_RSH,0x36)
 DEFEVENTKB(KEY_SPACE,_T("Space"),AM_K,AK_SPC,0x39)
 DEFEVENTKB(KEY_CURSOR_UP,_T("Cursor Up"),AM_K,AK_UP,0xe048)
 DEFEVENTKB(KEY_CURSOR_DOWN,_T("Cursor Down"),AM_K,AK_DN,0xe050)
index 176ef7623fe4152f562e7ea8c2494ddd2b0df6f9..f9db91e6f0ec8e9e5212df3728d24e17f809d312 100644 (file)
@@ -25,6 +25,8 @@
     Bits 0 - 1 = scan code set. */
 uint8_t keyboard_mode = 0x02;
 
+extern void write_log(const char *, ...);
+
 void draco_kdb_queue_add(void *d, uint8_t val, int state);
 
 void kbc_at_dev_reset(void *d, int r)
@@ -32,6 +34,12 @@ void kbc_at_dev_reset(void *d, int r)
 }
 void keyboard_at_log(const char *txt, ...)
 {
+    char buffer[256];
+    va_list parms;
+    va_start(parms, txt);
+    vsprintf(buffer, txt, parms);
+    write_log(buffer);
+    va_end(parms);
 }
 void fatalx(const char *txt, ...)
 {
@@ -1155,6 +1163,13 @@ draco_key_process(uint16_t scan, int down)
 void *draco_keyboard_init(void)
 {
     draco_kbd.type = 10;
+    draco_kbd.name = "draco";
     memset(oldkey, 0, sizeof(oldkey));
+    keyboard_at_set_defaults(&draco_kbd);
     return &draco_kbd;
 }
+
+int draco_keyboard_get_rate(void)
+{
+    return draco_kbd.rate;
+}
diff --git a/x86.cpp b/x86.cpp
index 92d945981245b684a3a80e8bfb99b420feceeb07..49cdaa5440a53daebcd4d6b1ad104289f74ab654 100644 (file)
--- a/x86.cpp
+++ b/x86.cpp
@@ -573,7 +573,7 @@ static bool floppy_did_reset;
 static bool floppy_irq;
 static bool floppy_specify_pio;
 static uae_u8 *floppy_pio_buffer;
-static int floppy_pio_len, floppy_pio_cnt;
+static int floppy_pio_len, floppy_pio_cnt, floppy_pio_active;
 static uae_s8 floppy_rate;
 
 #define PC_SEEK_DELAY 50
@@ -750,6 +750,201 @@ static bool floppy_valid_rate(struct floppy_reserved *fr)
        return fr->rate == floppy_rate || floppy_rate < 0;
 }
 
+static void floppy_format(struct x86_bridge *xb, bool real)
+{
+       uae_u8 cmd = floppy_cmd[0];
+       struct pc_floppy *pcf = &floppy_pc[floppy_num];
+       struct floppy_reserved fr = { 0 };
+       bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
+
+#if FLOPPY_DEBUG
+       write_log(_T("Floppy%d %s format MF=%d N=%d:SC=%d:GPL=%d:D=%d\n"),
+               floppy_num, real ? _T("real") : _T("sim"), (floppy_cmd[0] & 0x40) ? 1 : 0,
+               floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5]);
+       write_log(_T("DMA addr %08x len %04x\n"), dma[2].page | dma[2].ac, dma[2].cb);
+       write_log(_T("IMG: Secs=%d Heads=%d\n"), fr.secs, fr.heads);
+#endif
+       int secs = floppy_cmd[3];
+       int sector = pcf->sector;
+       int head = pcf->head;
+       int cyl = pcf->cyl;
+       if (valid_floppy && fr.img) {
+               // TODO: CHRN values totally ignored
+               pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
+               uae_u8 buf[512];
+               memset(buf, floppy_cmd[5], sizeof buf);
+               uae_u8 *pioptr = floppy_pio_buffer;
+               for (int i = 0; i < secs && i < fr.secs && !fr.wrprot; i++) {
+                       uae_u8 cx = 0, hx = 0, rx = 0, nx = 0;
+                       if (floppy_specify_pio) {
+                               if (real) {
+                                       cx = *pioptr++;
+                                       hx = *pioptr++;
+                                       rx = *pioptr++;
+                                       nx = *pioptr++;
+                                       floppy_pio_cnt += 4;
+                               } else {
+                                       floppy_pio_len += 4;
+                               }
+                       } else {
+                               if (real) {
+                                       cx = dma_channel_read(2);
+                                       hx = dma_channel_read(2);
+                                       rx = dma_channel_read(2);
+                                       nx = dma_channel_read(2);
+                               }
+                       }
+                       pcf->sector = rx - 1;
+#if FLOPPY_DEBUG
+                       write_log(_T("Floppy%d %d/%d: C=%d H=%d R=%d N=%d\n"), floppy_num, i, fr.secs, cx, hx, rx, nx);
+#endif
+                       if (real) {
+                               zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
+                               zfile_fwrite(buf, 1, 512, fr.img);
+                       }
+                       pcf->sector++;
+               }
+       } else {
+               floppy_status[0] |= 0x40; // abnormal termination
+               floppy_status[0] |= 0x10; // equipment check
+       }
+       floppy_cmd_len = 7;
+       if (fr.wrprot) {
+               floppy_status[0] |= 0x40; // abnormal termination
+               floppy_status[1] |= 0x02; // not writable
+       }
+       floppy_result[0] = floppy_status[0];
+       floppy_result[1] = floppy_status[1];
+       floppy_result[2] = floppy_status[2];
+       floppy_result[3] = pcf->cyl;
+       floppy_result[4] = pcf->head;
+       floppy_result[5] = pcf->sector + 1;
+       floppy_result[6] = floppy_cmd[2];
+       if (real) {
+               floppy_delay_hsync = 10;
+               disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
+       } else {
+               pcf->cyl = cyl;
+               pcf->sector = sector;
+               pcf->head = head;
+       }
+}
+
+static void floppy_write(struct x86_bridge *xb, bool real)
+{
+       uae_u8 cmd = floppy_cmd[0];
+       struct pc_floppy *pcf = &floppy_pc[floppy_num];
+       struct floppy_reserved fr = { 0 };
+       bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
+
+#if FLOPPY_DEBUG
+       write_log(_T("Floppy%d %s write MT=%d MF=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"),
+               floppy_num, real ? _T("real") : _T("sim"), (floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0,
+               floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5],
+               floppy_cmd[6], floppy_cmd[7], floppy_cmd[8]);
+       write_log(_T("DMA addr %08x len %04x\n"), dma[2].page | dma[2].ac, dma[2].ab);
+#endif
+       floppy_delay_hsync = 50;
+       int eot = floppy_cmd[6];
+       bool mt = (floppy_cmd[0] & 0x80) != 0;
+       int sector = pcf->sector;
+       int head = pcf->head;
+       int cyl = pcf->cyl;
+       if (valid_floppy) {
+               if (fr.img && pcf->cyl != floppy_cmd[2]) {
+                       floppy_status[0] |= 0x40; // abnormal termination
+                       floppy_status[2] |= 0x20; // wrong cylinder
+               } else if (fr.img) {
+                       int end = 0;
+                       pcf->sector = floppy_cmd[4] - 1;
+                       pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
+                       uae_u8 *pioptr = floppy_pio_buffer;
+                       while (!end && !fr.wrprot) {
+                               int len = 128 << floppy_cmd[5];
+                               uae_u8 buf[512] = { 0 };
+                               if (floppy_specify_pio) {
+                                       for (int i = 0; i < 512 && i < len; i++) {
+                                               if (real) {
+                                                       if (floppy_pio_cnt >= floppy_pio_len) {
+                                                               end = 1;
+                                                               break;
+                                                       }
+                                                       int v = *pioptr++;
+                                                       buf[i] = v;
+                                                       floppy_pio_cnt++;
+                                               } else {
+                                                       floppy_pio_len++;
+                                               }
+                                       }
+                               } else {
+                                       for (int i = 0; i < 512 && i < len; i++) {
+                                               if (real) {
+                                                       int v = dma_channel_read(2);
+                                                       if (v < 0) {
+                                                               end = -1;
+                                                               break;
+                                                       }
+                                                       buf[i] = v;
+                                                       if (v >= 0x10000) {
+                                                               end = 1;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+#if FLOPPY_DEBUG
+                               write_log(_T("LEN=%d END=%d C=%d H=%d S=%d. IMG S=%d H=%d\n"), len, end, pcf->cyl, pcf->head, pcf->sector, fr.secs, fr.heads);
+#endif
+                               if (end < 0)
+                                       break;
+                               if (real) {
+                                       zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
+                                       zfile_fwrite(buf, 1, 512, fr.img);
+                               }
+                               pcf->sector++;
+                               if (pcf->sector == eot) {
+                                       if (mt) {
+                                               pcf->sector = 0;
+                                               if (pcf->head)
+                                                       pcf->cyl++;
+                                               pcf->head ^= 1;
+                                       } else {
+                                               break;
+                                       }
+                               }
+                               if (pcf->sector >= fr.secs) {
+                                       pcf->sector = 0;
+                                       pcf->head ^= 1;
+                                       break;
+                               }
+                       }
+                       floppy_result[3] = cyl;
+                       floppy_result[4] = pcf->head;
+                       floppy_result[5] = pcf->sector + 1;
+                       floppy_result[6] = floppy_cmd[5];
+               } else {
+                       floppy_status[0] |= 0x40; // abnormal termination
+                       floppy_status[0] |= 0x10; // equipment check
+               }
+       }
+       floppy_cmd_len = 7;
+       if (fr.wrprot) {
+               floppy_status[0] |= 0x40; // abnormal termination
+               floppy_status[1] |= 0x02; // not writable
+       }
+       floppy_result[0] = floppy_status[0];
+       floppy_result[1] = floppy_status[1];
+       floppy_result[2] = floppy_status[2];
+       if (real) {
+               floppy_delay_hsync = 10;
+               disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
+       } else {
+               pcf->cyl = cyl;
+               pcf->sector = sector;
+               pcf->head = head;
+       }
+}
+
 static void floppy_do_cmd(struct x86_bridge *xb)
 {
        uae_u8 cmd = floppy_cmd[0];
@@ -834,87 +1029,7 @@ static void floppy_do_cmd(struct x86_bridge *xb)
 
                case 5:
                {
-#if FLOPPY_DEBUG
-                       write_log(_T("Floppy%d write MT=%d MF=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"),
-                               floppy_num, (floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0,
-                               floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5],
-                               floppy_cmd[6], floppy_cmd[7], floppy_cmd[8]);
-                       write_log(_T("DMA addr %08x len %04x\n"), dma[2].page | dma[2].ac, dma[2].ab);
-#endif
-                       floppy_delay_hsync = 50;
-                       int eot = floppy_cmd[6];
-                       bool mt = (floppy_cmd[0] & 0x80) != 0;
-                       int cyl = pcf->cyl;
-                       if (valid_floppy) {
-                               if (fr.img && pcf->cyl != floppy_cmd[2]) {
-                                       floppy_status[0] |= 0x40; // abnormal termination
-                                       floppy_status[2] |= 0x20; // wrong cylinder
-                               } else if (fr.img) {
-                                       int end = 0;
-                                       pcf->sector = floppy_cmd[4] - 1;
-                                       pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
-                                       while (!end && !fr.wrprot) {
-                                               int len = 128 << floppy_cmd[5];
-                                               uae_u8 buf[512] = { 0 };
-                                               if (floppy_specify_pio) {
-                                                       end = -1;
-                                               } else {
-                                                       for (int i = 0; i < 512 && i < len; i++) {
-                                                               int v = dma_channel_read(2);
-                                                               if (v < 0) {
-                                                                       end = -1;
-                                                                       break;
-                                                               }
-                                                               buf[i] = v;
-                                                               if (v >= 0x10000) {
-                                                                       end = 1;
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-#if FLOPPY_DEBUG
-                                               write_log(_T("LEN=%d END=%d C=%d H=%d S=%d. IMG S=%d H=%d\n"), len, end, pcf->cyl, pcf->head, pcf->sector, fr.secs, fr.heads);
-#endif
-                                               if (end < 0)
-                                                       break;
-                                               zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
-                                               zfile_fwrite(buf, 1, 512, fr.img);
-                                               pcf->sector++;
-                                               if (pcf->sector == eot) {
-                                                       if (mt) {
-                                                               pcf->sector = 0;
-                                                               if (pcf->head)
-                                                                       pcf->cyl++;
-                                                               pcf->head ^= 1;
-                                                       } else {
-                                                               break;
-                                                       }
-                                               }
-                                               if (pcf->sector >= fr.secs) {
-                                                       pcf->sector = 0;
-                                                       pcf->head ^= 1;
-                                                       break;
-                                               }
-                                       }
-                                       floppy_result[3] = cyl;
-                                       floppy_result[4] = pcf->head;
-                                       floppy_result[5] = pcf->sector + 1;
-                                       floppy_result[6] = floppy_cmd[5];
-                               } else {
-                                       floppy_status[0] |= 0x40; // abnormal termination
-                                       floppy_status[0] |= 0x10; // equipment check
-                               }
-                       }
-                       floppy_cmd_len = 7;
-                       if (fr.wrprot) {
-                               floppy_status[0] |= 0x40; // abnormal termination
-                               floppy_status[1] |= 0x02; // not writable
-                       }
-                       floppy_result[0] = floppy_status[0];
-                       floppy_result[1] = floppy_status[1];
-                       floppy_result[2] = floppy_status[2];
-                       floppy_delay_hsync = 10;
-                       disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
+                       floppy_write(xb, true);
                }
                break;
 
@@ -957,6 +1072,7 @@ static void floppy_do_cmd(struct x86_bridge *xb)
                                                        memcpy(pioptr, buf, 512);
                                                        pioptr += 512;
                                                        floppy_pio_len += 512;
+                                                       floppy_pio_active = 1;
                                                } else {
                                                        for (int i = 0; i < 512 && i < len; i++) {
                                                                int v = dma_channel_write(2, buf[i]);
@@ -1036,56 +1152,13 @@ static void floppy_do_cmd(struct x86_bridge *xb)
                        pcf->sector %= fr.secs;
                }
 
-               floppy_delay_hsync = 10;
+               floppy_delay_hsync = maxvpos * 20;
                disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
                break;
 
                case 13:
                {
-#if FLOPPY_DEBUG
-                       write_log(_T("Floppy%d format MF=%d N=%d:SC=%d:GPL=%d:D=%d\n"),
-                               floppy_num, (floppy_cmd[0] & 0x40) ? 1 : 0,
-                               floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5]);
-                       write_log(_T("DMA addr %08x len %04x\n"), dma[2].page | dma[2].ac, dma[2].cb);
-                       write_log(_T("IMG: Secs=%d Heads=%d\n"), fr.secs, fr.heads);
-#endif
-                       int secs = floppy_cmd[3];
-                       if (valid_floppy && fr.img) {
-                               // TODO: CHRN values totally ignored
-                               pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
-                               uae_u8 buf[512];
-                               memset(buf, floppy_cmd[5], sizeof buf);
-                               for (int i = 0; i < secs && i < fr.secs && !fr.wrprot; i++) {
-                                       uae_u8 cx = dma_channel_read(2);
-                                       uae_u8 hx = dma_channel_read(2);
-                                       uae_u8 rx = dma_channel_read(2);
-                                       uae_u8 nx = dma_channel_read(2);
-                                       pcf->sector = rx - 1;
-#if FLOPPY_DEBUG
-                                       write_log(_T("Floppy%d %d/%d: C=%d H=%d R=%d N=%d\n"), floppy_num, i, fr.secs, cx, hx, rx, nx);
-#endif
-                                       zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
-                                       zfile_fwrite(buf, 1, 512, fr.img);
-                                       pcf->sector++;
-                               }
-                       } else {
-                               floppy_status[0] |= 0x40; // abnormal termination
-                               floppy_status[0] |= 0x10; // equipment check
-                       }
-                       floppy_cmd_len = 7;
-                       if (fr.wrprot) {
-                               floppy_status[0] |= 0x40; // abnormal termination
-                               floppy_status[1] |= 0x02; // not writable
-                       }
-                       floppy_result[0] = floppy_status[0];
-                       floppy_result[1] = floppy_status[1];
-                       floppy_result[2] = floppy_status[2];
-                       floppy_result[3] = pcf->cyl;
-                       floppy_result[4] = pcf->head;
-                       floppy_result[5] = pcf->sector + 1;
-                       floppy_result[6] = floppy_cmd[2];
-                       floppy_delay_hsync = 10;
-                       disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
+                       floppy_format(xb, true);
                }
                break;
 
@@ -1169,63 +1242,97 @@ static void outfloppy(struct x86_bridge *xb, int portnum, uae_u8 v)
                }
                break;
                case 0x3f5: // data reg
-               floppy_cmd[floppy_idx] = v;
-               if (floppy_idx == 0) {
-                       floppy_cmd_len = -1;
-                       switch(v & 31)
-                       {
-                               case 3: // specify
-                               floppy_cmd_len = 3;
-                               break;
-                               case 4: // sense drive status
-                               floppy_cmd_len = 2;
-                               break;
-                               case 5: // write data
-                               floppy_cmd_len = 9;
-                               break;
-                               case 6: // read data
-                               floppy_cmd_len = 9;
-                               break;
-                               case 7: // recalibrate
-                               floppy_cmd_len = 2;
-                               break;
-                               case 8: // sense interrupt status
-                               floppy_cmd_len = 1;
-                               break;
-                               case 10: // read id
-                               floppy_cmd_len = 2;
-                               break;
-                               case 12: // perpendiculaor mode
-                               if (xb->type < 0) {
+               if (floppy_pio_len > 0 && floppy_pio_cnt < floppy_pio_len && floppy_pio_active) {
+                       floppy_pio_buffer[floppy_pio_cnt++] = v;
+                       if (floppy_pio_cnt >= floppy_pio_len) {
+                               floppy_pio_cnt = 0;
+                               floppy_pio_active = 0;
+                               floppy_clear_irq();
+                               floppy_do_cmd(xb);
+                               floppy_pio_cnt = 0;
+                               floppy_pio_len = 0;
+                       }
+               } else {
+                       floppy_cmd[floppy_idx] = v;
+                       if (floppy_idx == 0) {
+                               floppy_cmd_len = -1;
+                               switch(v & 31)
+                               {
+                                       case 3: // specify
+                                       floppy_cmd_len = 3;
+                                       break;
+                                       case 4: // sense drive status
                                        floppy_cmd_len = 2;
-                               }
-                               break;
-                               case 13: // format track
-                               floppy_cmd_len = 6;
-                               break;
-                               case 15: // seek
-                               floppy_cmd_len = 3;
-                               break;
-                               case 16: // get versionm
-                               if (xb->type < 0) {
+                                       break;
+                                       case 5: // write data
+                                       floppy_cmd_len = 9;
+                                       break;
+                                       case 6: // read data
+                                       floppy_cmd_len = 9;
+                                       break;
+                                       case 7: // recalibrate
+                                       floppy_cmd_len = 2;
+                                       break;
+                                       case 8: // sense interrupt status
                                        floppy_cmd_len = 1;
+                                       break;
+                                       case 10: // read id
+                                       floppy_cmd_len = 2;
+                                       break;
+                                       case 12: // perpendiculaor mode
+                                       if (xb->type < 0) {
+                                               floppy_cmd_len = 2;
+                                       }
+                                       break;
+                                       case 13: // format track
+                                       floppy_cmd_len = 6;
+                                       break;
+                                       case 15: // seek
+                                       floppy_cmd_len = 3;
+                                       break;
+                                       case 16: // get versionm
+                                       if (xb->type < 0) {
+                                               floppy_cmd_len = 1;
+                                       }
+                                       break;
+                                       case 19: // configure
+                                       if (xb->type < 0) {
+                                               floppy_cmd_len = 4;
+                                       }
+                                       break;
                                }
-                               break;
-                               case 19: // configure
-                               if (xb->type < 0) {
-                                       floppy_cmd_len = 4;
+                               if (floppy_cmd_len < 0) {
+                                       write_log(_T("Floppy unimplemented command %02x\n"), v);
+                                       floppy_cmd_len = 1;
                                }
-                               break;
                        }
-                       if (floppy_cmd_len < 0) {
-                               write_log(_T("Floppy unimplemented command %02x\n"), v);
-                               floppy_cmd_len = 1;
+                       floppy_idx++;
+                       if (floppy_idx >= floppy_cmd_len) {
+                               if (floppy_specify_pio && (floppy_cmd[0] & 31) == 5) {
+                                       floppy_write(xb, false);
+                                       floppy_pio_cnt = 0;
+                                       floppy_pio_active = 0;
+                                       if (floppy_pio_len > 0) {
+                                               floppy_delay_hsync = 10;
+                                               floppy_pio_active = 1;
+                                       } else {
+                                               floppy_write(xb, true);
+                                       }
+                               } else if (floppy_specify_pio && (floppy_cmd[0] & 31) == 13) {
+                                       floppy_format(xb, false);
+                                       floppy_pio_cnt = 0;
+                                       floppy_pio_active = 0;
+                                       if (floppy_pio_len > 0) {
+                                               floppy_delay_hsync = 10;
+                                               floppy_pio_active = 1;
+                                       } else {
+                                               floppy_format(xb, true);
+                                       }
+                               } else {
+                                       floppy_do_cmd(xb);
+                               }
                        }
                }
-               floppy_idx++;
-               if (floppy_idx >= floppy_cmd_len) {
-                       floppy_do_cmd(xb);
-               }
                break;
                case 0x3f7: // configuration control
                if (xb->type >= TYPE_2286) {
@@ -1276,9 +1383,9 @@ static uae_u8 infloppy(struct x86_bridge *xb, int portnum)
                v = 0;
                if (!floppy_delay_hsync && (floppy_dpc & 4))
                        v |= 0x80;
-               if (floppy_idx || floppy_delay_hsync || floppy_pio_len) {
+               if (floppy_idx || floppy_delay_hsync || floppy_pio_active) {
                        v |= 0x10;
-                       if (floppy_pio_len)
+                       if (floppy_pio_active)
                                v |= 0x20;
                }
                if ((v & 0x80) && floppy_dir)
@@ -1293,6 +1400,7 @@ static uae_u8 infloppy(struct x86_bridge *xb, int portnum)
                        v = floppy_pio_buffer[floppy_pio_cnt++];
                        if (floppy_pio_cnt >= floppy_pio_len) {
                                floppy_pio_len = 0;
+                               floppy_pio_active = 0;
                                floppy_clear_irq();
                                floppy_delay_hsync = 50;
                        }
@@ -1335,10 +1443,11 @@ static uae_u8 infloppy(struct x86_bridge *xb, int portnum)
        return v;
 }
 
-uae_u16 floppy_get_raw_data(void)
+uae_u16 floppy_get_raw_data(int *rate)
 {
        struct floppy_reserved fr = { 0 };
        bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
+       *rate = fr.rate;
        if (valid_floppy) {
                return DSKBYTR_fake(fr.num);
        }