]> git.sesse.net Git - pistorm/commitdiff
IDE updates, fix mouse hook hotkey
authorbeeanyew <beeanyew@gmail.com>
Fri, 15 Jan 2021 03:30:52 +0000 (04:30 +0100)
committerbeeanyew <beeanyew@gmail.com>
Fri, 15 Jan 2021 03:30:52 +0000 (04:30 +0100)
Added support for headerless (RDSK) HDD images, and fixed the IDE controller emulation to not keep separate LBA1-4 values for each hard drive.
This may look strange at first glance, but the Amiga would regularly write the CHS values for drive access ahead of actually switching to the drive it wanted, so I assume this is how it's actually supposed to work.
The second drive still doesn't mount automatically on boot, but I believe that some currently unsupported register write or read is causing this.

default.cfg
emulator.c
gpio/gpio.c
gpio/gpio.h
platforms/amiga/Gayle.c
platforms/amiga/amiga-platform.c
platforms/amiga/gayle-ide/ide.c
platforms/amiga/gayle-ide/ide.h

index aa07b9f25d6ef865e03beb5a86708dac2726447f..fe75e7a5cecb02aee6604606ddce2bee0072f9e6 100644 (file)
@@ -26,8 +26,13 @@ loopcycles 300
 platform amiga
 # Uncomment to let reads/writes through from/to the RTC memory range
 #setvar enable_rtc_emulation 0
-# Uncomment to set a custom HD image file for ide0
+# Uncomment to set a custom HD image file for ide0 drive 0/1
 #setvar hdd0 snakes.img
+#setvar hdd1 snakes2.img
+# Uncomment to enable RTG
+#setvar rtg
+# Uncomment to enable CDTV mode (not working, requires Kickstart 1.3+CDTV extended ROM)
+#setvar cdtv
 
 # Forward mouse events to host system, defaults to off unless toggle key is pressed on the Pi.
 # Syntax is mouse [device] [toggle key]
index bb93c585cb5aaa5c1d664c8ce6049a15e94b33a0..ce516f3bbd474abd2a85cbe1739ed7401dd71e9d 100644 (file)
@@ -69,8 +69,8 @@ void *iplThread(void *args) {
       irq = 0;
 
     if (gayle_emulation_enabled) {
-      if (((gayle_int & 0x80) || gayle_a4k_int) && get_ide(0)->drive->intrq) {
-        //get_ide(0)->drive->intrq = 0;
+      if (((gayle_int & 0x80) || gayle_a4k_int) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
+        //get_ide(0)->drive[0].intrq = 0;
         gayleirq = 1;
         m68k_end_timeslice();
       }
@@ -291,7 +291,7 @@ disasm_run:;
       }
 
       if (!kb_hook_enabled && c_type) {
-        if (c == cfg->mouse_toggle_key) {
+        if (c && c == cfg->mouse_toggle_key) {
           mouse_hook_enabled ^= 1;
           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
           mouse_dx = mouse_dy = mouse_buttons = 0;
index 5eb11d9667c23bdcaca85cea76e23c6f64327185..ed388c4b8d079dd0ad1f0fb11c5c665ef25dd70e 100644 (file)
@@ -377,7 +377,7 @@ inline void gpio_handle_irq() {
     srdata = read_reg();
     m68k_set_irq((srdata >> 13) & 0xff);
   } else {
-    if ((gayle_int & 0x80) && get_ide(0)->drive->intrq) {
+    if ((gayle_int & 0x80) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
       write16(0xdff09c, 0x8008);
       m68k_set_irq(2);
     }
index 5ad470afc7c21880bcce309356242482820dcd89..43521ceed5cba995983b631ac4b8b6ac57629426 100644 (file)
@@ -76,7 +76,7 @@
     srdata = read_reg(); \
     m68k_set_irq((srdata >> 13) & 0xff); \
   } else { \
-    if ((gayle_int & 0x80) && get_ide(0)->drive->intrq) { \
+    if ((gayle_int & 0x80) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) { \
       write16(0xdff09c, 0x8008); \
       m68k_set_irq(2); \
     } \
index 6e38ffa35006a177a86622ca142ac61e74d82cee..044b27e14428740cc702c4fa6bd22c66e2b5fb51 100644 (file)
@@ -80,21 +80,34 @@ void InitGayle(void) {
   }
 
   ide0 = ide_allocate("cf");
-  fd = open(hdd_image_file[0], O_RDWR);
-  if (fd == -1) {
-    printf("HDD Image %s failed open\n", hdd_image_file[0]);
-  } else {
-    ide_attach(ide0, 0, fd);
-    ide_reset_begin(ide0);
-    printf("HDD Image %s attached\n", hdd_image_file[0]);
+
+  for (int i = 0; i < GAYLE_MAX_HARDFILES; i++) {
+    if (hdd_image_file[i]) {
+      fd = open(hdd_image_file[i], O_RDWR);
+      if (fd == -1) {
+        printf("[HDD%d] HDD Image %s failed open\n", i, hdd_image_file[i]);
+      } else {
+        printf("[HDD%d] Attaching HDD image %s.\n", i, hdd_image_file[i]);
+        if (strcmp(hdd_image_file[i] + (strlen(hdd_image_file[i]) - 3), "img") != 0) {
+          printf("No header present on HDD image %s.\n", hdd_image_file[i]);
+          ide_attach_hdf(ide0, i, fd);
+        }
+        else {
+          printf("Attaching HDD image with header.\n");
+          ide_attach(ide0, i, fd);
+        }
+        printf("[HDD%d] HDD Image %s attached\n", i, hdd_image_file[i]);
+      }
+    }
   }
+  ide_reset_begin(ide0);
 }
 
 uint8_t CheckIrq(void) {
   uint8_t irq;
 
   if (gayle_int & (1 << 7)) {
-    irq = ide0->drive->intrq;
+    irq = ide0->drive[0].intrq || ide0->drive[1].intrq;
     // if (irq==0)
     // printf("IDE IRQ: %x\n",irq);
     return irq;
@@ -108,9 +121,11 @@ void writeGayleB(unsigned int address, unsigned int value) {
   if (address >= gayle_ide_base) {
     switch ((address - gayle_ide_base) - gayle_ide_adj) {
       case GFEAT_OFFSET:
+        printf("Write to GFEAT: %.2X.\n", value);
         ide_action = ide_feature_w;
         goto idewrite8;
       case GCMD_OFFSET:
+        //printf("Write to GCMD: %.2X.\n", value);
         ide_action = ide_command_w;
         goto idewrite8;
       case GSECTCOUNT_OFFSET:
@@ -126,9 +141,11 @@ void writeGayleB(unsigned int address, unsigned int value) {
         ide_action = ide_cyl_hi;
         goto idewrite8;
       case GDEVHEAD_OFFSET:
+        printf("Write to GDEVHEAD: %.2X.\n", value);
         ide_action = ide_dev_head;
         goto idewrite8;
       case GCTRL_OFFSET:
+        printf("Write to GCTRL: %.2X.\n", value);
         ide_action = ide_devctrl_w;
         goto idewrite8;
       case GIRQ_4000_OFFSET:
@@ -150,9 +167,11 @@ skip_idewrite8:;
       gayle_a4k = value;
       return;*/
     case GIDENT:
+      printf("Write to GIDENT: %d\n", value);
       counter = 0;
       return;
     case GCONF:
+      printf("Write to GCONF: %d\n", gayle_cfg);
       gayle_cfg = value;
       return;
     case RAMSEY_REG:
@@ -165,6 +184,8 @@ skip_idewrite8:;
       gayle_cs_mask = value & ~3;
       gayle_cs &= ~3;
       gayle_cs |= value & 3;
+      printf("Write to GCS: %d\n", gayle_cs);
+      //ide0->selected = gayle_cs;
       return;
   }
 
@@ -233,7 +254,7 @@ void writeGayleL(unsigned int address, unsigned int value) {
 }
 
 uint8_t readGayleB(unsigned int address) {
-  uint8_t ide_action = 0;
+  uint8_t ide_action = 0, ide_val = 0;
 
   if (address >= gayle_ide_base) {
     switch ((address - gayle_ide_base) - gayle_ide_adj) {
@@ -268,6 +289,9 @@ uint8_t readGayleB(unsigned int address) {
     }
     goto skip_ideread8;
 ideread8:;
+    ide_val = ide_read8(ide0, ide_action);
+    if (((address - gayle_ide_base) - gayle_ide_adj) == GDEVHEAD_OFFSET)
+      printf("Read from GDEVHEAD: %.2X\n", ide_val);
     return ide_read8(ide0, ide_action);
 skip_ideread8:;
   }
@@ -281,15 +305,18 @@ skip_ideread8:;
         val = 0x00;
       }
       counter++;
+      printf("Read from GIDENT: %.2X.\n", val);
       return val;
     }
     case GINT:
       return gayle_int;
     case GCONF:
+      printf("Read from GCONF: %d\n", gayle_cfg & 0x0F);
       return gayle_cfg & 0x0f;
     case GCS: {
       uint8_t v;
       v = gayle_cs_mask | gayle_cs;
+      printf("Read from GCS: %d\n", v);
       return v;
     }
     // This seems incorrect, GARY_REG3 is the same as GIDENT, and the A4000
index 292989d07f8281d6743c561d28953a54c7c3e36d..264b1d96565941d9e3aecfeb149b679ee164281b 100644 (file)
@@ -278,6 +278,10 @@ void setvar_amiga(struct emulator_config *cfg, char *var, char *val) {
         if (val && strlen(val) != 0)
             set_hard_drive_image_file_amiga(0, val);
     }
+    if (strcmp(var, "hdd1") == 0) {
+        if (val && strlen(val) != 0)
+            set_hard_drive_image_file_amiga(1, val);
+    }
     if (strcmp(var, "cdtv") == 0) {
         printf("[AMIGA] CDTV mode enabled.\n");
         cdtv_mode = 1;
index f82dfb53a1da6b29154bb2de791b5bf047acc55c..765bb139ff0cecc9aa9cd1ed54ba9553a7b62376 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <time.h>
 #include <arpa/inet.h>
+#include "../../../config_file/config_file.h"
 
 #include "ide.h"
 
@@ -139,29 +140,34 @@ static off_t xlate_block(struct ide_taskfile *t)
   struct ide_drive *d = t->drive;
   uint16_t cyl;
 
-  if (t->lba4 & DEVH_LBA) {
+  if (d->controller->lba4 & DEVH_LBA) {
 /*    fprintf(stderr, "XLATE LBA %02X:%02X:%02X:%02X\n", 
       t->lba4, t->lba3, t->lba2, t->lba1);*/
     if (d->lba)
-      return 2 + (((t->lba4 & DEVH_HEAD) << 24) | (t->lba3 << 16) | (t->lba2 << 8) | t->lba1);
+      return ((d->header_present) ? 2 : 0) + (((t->drive->controller->lba4 & DEVH_HEAD) << 24) | (t->drive->controller->lba3 << 16) | (t->drive->controller->lba2 << 8) | t->drive->controller->lba1);
     ide_fault(d, "LBA on non LBA drive");
   }
 
   /* Some well known software asks for 0/0/0 when it means 0/0/1. Drives appear
      to interpret sector 0 as sector 1 */
-  if (t->lba1 == 0) {
+  if (t->drive->controller->lba1 == 0) {
     fprintf(stderr, "[Bug: request for sector offset 0].\n");
-    t->lba1 = 1;
+    t->drive->controller->lba1 = 1;
   }
-  cyl = (t->lba3 << 8) | t->lba2;
+  cyl = (t->drive->controller->lba3 << 8) | t->drive->controller->lba2;
   /* fprintf(stderr, "(H %d C %d S %d)\n", t->lba4 & DEVH_HEAD, cyl, t->lba1); */
-  if (t->lba1 == 0 || t->lba1 > d->sectors || t->lba4 >= d->heads || cyl >= d->cylinders) {
+  if (t->drive->controller->lba1 == 0 || t->drive->controller->lba1 > d->sectors || t->drive->controller->lba4 >= d->heads || cyl >= d->cylinders) {
     return -1;
   }
   /* Sector 1 is first */
   /* Images generally go cylinder/head/sector. This also matters if we ever
      implement more advanced geometry setting */
-  return 1 + ((cyl * d->heads) + (t->lba4 & DEVH_HEAD)) * d->sectors + t->lba1;
+  //off_t ret = ((d->header_present) ? 1 : -1) + ((cyl * d->heads) + (t->drive->controller->lba4 & DEVH_HEAD)) * d->sectors + t->drive->controller->lba1;
+  //printf("Non-LBA xlate block %lX.\n", ret);
+  //printf("Cyl: %d Heads: %d Sectors: %d\n", cyl, d->heads, d->sectors);
+  //printf("LBA1: %.2X LBA2: %.2X LBA3: %.2X LBA4: %.2X\n", t->drive->controller->lba1, t->drive->controller->lba2, t->drive->controller->lba3, t->drive->controller->lba4);
+
+  return ((d->header_present) ? 1 : -1) + ((cyl * d->heads) + (t->drive->controller->lba4 & DEVH_HEAD)) * d->sectors + t->drive->controller->lba1;
 }
 
 /* Indicate the drive is ready */
@@ -211,10 +217,10 @@ static void data_out_state(struct ide_taskfile *tf)
 static void edd_setup(struct ide_taskfile *tf)
 {
   tf->error = 0x01;            /* All good */
-  tf->lba1 = 0x01;             /* EDD always updates drive 0 */
-  tf->lba2 = 0x00;
-  tf->lba3 = 0x00;
-  tf->lba4 = 0x00;
+  tf->drive->controller->lba1 = 0x01;          /* EDD always updates drive 0 */
+  tf->drive->controller->lba2 = 0x00;
+  tf->drive->controller->lba3 = 0x00;
+  tf->drive->controller->lba4 = 0x00;
   tf->count = 0x01;
   ready(tf);
 }
@@ -233,6 +239,8 @@ void ide_reset(struct ide_controller *c)
     c->drive[1].taskfile.status = ST_DRDY;
     c->drive[1].eightbit = 0;
   }
+  if (c->selected != 0) {
+  }
   c->selected = 0;
 }
 
@@ -286,7 +294,7 @@ static void cmd_initparam_complete(struct ide_taskfile *tf)
 {
   struct ide_drive *d = tf->drive;
   /* We only support the current mapping */
-  if (tf->count != d->sectors || (tf->lba4 & DEVH_HEAD) + 1 != d->heads) {
+  if (tf->count != d->sectors || (tf->drive->controller->lba4 & DEVH_HEAD) + 1 != d->heads) {
     tf->status |= ST_ERR;
     tf->error |= ERR_ABRT;
     tf->drive->failed = 1;             /* Report ID NF until fixed */
@@ -426,20 +434,20 @@ static void cmd_writesectors_complete(struct ide_taskfile *tf)
 
 static void ide_set_error(struct ide_drive *d)
 {
-  d->taskfile.lba4 &= ~DEVH_HEAD;
+  d->controller->lba4 &= ~DEVH_HEAD;
 
-  if (d->taskfile.lba4 & DEVH_LBA) {
-    d->taskfile.lba1 = d->offset & 0xFF;
-    d->taskfile.lba2 = (d->offset >> 8) & 0xFF;
-    d->taskfile.lba3 = (d->offset >> 16) & 0xFF;
-    d->taskfile.lba4 |= (d->offset >> 24) & DEVH_HEAD;
+  if (d->controller->lba4 & DEVH_LBA) {
+    d->controller->lba1 = d->offset & 0xFF;
+    d->controller->lba2 = (d->offset >> 8) & 0xFF;
+    d->controller->lba3 = (d->offset >> 16) & 0xFF;
+    d->controller->lba4 |= (d->offset >> 24) & DEVH_HEAD;
   } else {
-    d->taskfile.lba1 = d->offset % d->sectors + 1;
+    d->controller->lba1 = d->offset % d->sectors + 1;
     d->offset /= d->sectors;
-    d->taskfile.lba4 |= d->offset / (d->cylinders * d->sectors);
+    d->controller->lba4 |= d->offset / (d->cylinders * d->sectors);
     d->offset %= (d->cylinders * d->sectors);
-    d->taskfile.lba2 = d->offset & 0xFF;
-    d->taskfile.lba3 = (d->offset >> 8) & 0xFF;
+    d->controller->lba2 = d->offset & 0xFF;
+    d->controller->lba3 = (d->offset >> 8) & 0xFF;
   }
   d->taskfile.count = d->length;
   d->taskfile.status |= ST_ERR;
@@ -607,13 +615,13 @@ uint8_t ide_read8(struct ide_controller *c, uint8_t r)
     case ide_sec_count:
       return t->count;
     case ide_lba_low:
-      return t->lba1;
+      return c->lba1;
     case ide_lba_mid:
-      return t->lba2;
+      return c->lba2;
     case ide_lba_hi:
-      return t->lba3;
+      return c->lba3;
     case ide_lba_top:
-      return t->lba4;
+      return c->lba4 | ((c->selected) ? 0x10 : 0x00);
     case ide_status_r:
       d->intrq = 0;            /* Acked */
     case ide_altst_r:
@@ -641,6 +649,8 @@ void ide_write8(struct ide_controller *c, uint8_t r, uint8_t v)
     }
   }
 
+  uint8_t ve;
+
   switch(r) {
     case ide_data:
       ide_data_out(d, v, 1);
@@ -652,17 +662,17 @@ void ide_write8(struct ide_controller *c, uint8_t r, uint8_t v)
       t->count = v;
       break;
     case ide_lba_low:
-      t->lba1 = v;
+      c->lba1 = v;
       break;
     case ide_lba_mid:
-      t->lba2 = v;
+      c->lba2 = v;
       break;
     case ide_lba_hi:
-      t->lba3 = v;
+      c->lba3 = v;
       break;
     case ide_lba_top:
       c->selected = (v & DEVH_DEV) ? 1 : 0;
-      c->drive[c->selected].taskfile.lba4 = v & (DEVH_HEAD|DEVH_DEV|DEVH_LBA);
+      c->lba4 = v & (DEVH_HEAD|/*DEVH_DEV|*/DEVH_LBA);
       break;
     case ide_command_w:
       t->command = v; 
@@ -755,6 +765,7 @@ int ide_attach(struct ide_controller *c, int drive, int fd)
   d->heads = d->identify[3];
   d->sectors = d->identify[6];
   d->cylinders = le16(d->identify[1]);
+  d->header_present = 1;
   if (d->identify[49] & le16(1 << 9))
     d->lba = 1;
   else
@@ -762,6 +773,52 @@ int ide_attach(struct ide_controller *c, int drive, int fd)
   return 0;
 }
 
+// Attach a headerless HDD image to the controller
+int ide_attach_hdf(struct ide_controller *c, int drive, int fd)
+{
+  struct ide_drive *d = &c->drive[drive];
+  if (d->present) {
+    printf("[IDE/HDL] Drive already attached.\n");
+    return -1;
+  }
+
+  d->fd = fd;
+  d->present = 1;
+  d->lba = 0;
+
+  d->heads = 255;
+  d->sectors = 63;
+  d->header_present = 0;
+
+  uint64_t file_size = lseek(fd, 0, SEEK_END);
+  lseek(fd, 1024, SEEK_SET);
+
+  if (file_size < 500 * SIZE_MEGA) {
+    d->heads = 16;
+  }
+  else if (file_size < 1000 * SIZE_MEGA) {
+    d->heads = 32;
+  }
+  else if (file_size < 2000 * SIZE_MEGA) {
+    d->heads = 64;
+  }
+  else if (file_size < (uint64_t)4000 * SIZE_MEGA) {
+    d->heads = 128;
+  }
+
+  d->cylinders = (file_size / 512) / (d->sectors * d->heads);
+
+  printf("[IDE/HDL] Cylinders: %d Heads: %d Sectors: %d\n", d->cylinders, d->heads, d->sectors);
+
+  if (file_size >= 4 * 1000 * 1000) {
+    d->lba = 1;
+  }
+
+  ide_make_ident(d->cylinders, d->heads, d->sectors, "PISTORM HDD IMAGE v0.1", d->identify);
+
+  return 0;
+}
+
 /*
  *     Detach an IDE device from the interface (not hot pluggable)
  */
@@ -837,6 +894,40 @@ static void make_serial(uint16_t *p)
   make_ascii(p, buf, 20);
 }
 
+int ide_make_ident(uint16_t c, uint8_t h, uint8_t s, char *name, uint16_t *target)
+{
+  uint16_t *ident = target;
+  uint32_t sectors;
+
+  memset(ident, 0, 512);
+  memcpy(ident, ide_magic, 8);
+
+  memset(ident, 0, 8);
+  ident[0] = le16((1 << 15) | (1 << 6));       /* Non removable */
+  make_serial(ident + 10);
+  ident[47] = 0; /* no read multi for now */
+  ident[51] = le16(240 /* PIO2 */ << 8);       /* PIO cycle time */
+  ident[53] = le16(1);         /* Geometry words are valid */
+
+  make_ascii(ident + 23, "A001.001", 8);
+  make_ascii(ident + 27, name, 40);
+  ident[49] = le16(1 << 9); /* LBA */
+
+  ident[1] = le16(c);
+  ident[3] = le16(h);
+  ident[6] = le16(s);
+  ident[54] = ident[1];
+  ident[55] = ident[3];
+  ident[56] = ident[6];
+  sectors = c * h * s;
+  ident[57] = le16(sectors & 0xFFFF);
+  ident[58] = le16(sectors >> 16);
+  ident[60] = ident[57];
+  ident[61] = ident[58];
+
+  return 0;
+}
+
 int ide_make_drive(uint8_t type, int fd)
 {
   uint8_t s, h;
index 900c3cd1f646066ff85781f04e4a05b29b9ca06e..29598ec29b34b1495db480cf7416ea757d71e68b 100644 (file)
@@ -19,7 +19,7 @@
 #define                ide_lba_mid     4
 #define                ide_cyl_hi      5
 #define                ide_lba_hi      5
-#define                ide_dev_head    6
+#define                ide_dev_head 6
 #define                ide_lba_top     6
 #define                ide_status_r    7
 #define                ide_command_w   7
@@ -32,10 +32,6 @@ struct ide_taskfile {
   uint8_t error;
   uint8_t feature;
   uint8_t count;
-  uint8_t lba1;
-  uint8_t lba2;
-  uint8_t lba3;
-  uint8_t lba4;
   uint8_t status;
   uint8_t command;
   uint8_t devctrl;
@@ -55,6 +51,7 @@ struct ide_drive {
   int fd;
   off_t offset;
   int length;
+  uint8_t header_present;
 };
 
 struct ide_controller {
@@ -62,6 +59,10 @@ struct ide_controller {
   int selected;
   const char *name;
   uint16_t data_latch;
+  uint8_t lba1;
+  uint8_t lba2;
+  uint8_t lba3;
+  uint8_t lba4;
 };
 
 //extern ide_controller idectrl;
@@ -77,6 +78,8 @@ void ide_write_latched(struct ide_controller *c, uint8_t r, uint8_t v);
 
 struct ide_controller *ide_allocate(const char *name);
 int ide_attach(struct ide_controller *c, int drive, int fd);
+int ide_attach_hdf(struct ide_controller *c, int drive, int fd);
+int ide_make_ident(uint16_t c, uint8_t h, uint8_t s, char *name, uint16_t *target);
 void ide_detach(struct ide_drive *d);
 void ide_free(struct ide_controller *c);