diff --git a/default.cfg b/default.cfg index aa07b9f..fe75e7a 100644 --- a/default.cfg +++ b/default.cfg @@ -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] diff --git a/emulator.c b/emulator.c index bb93c58..ce516f3 100644 --- a/emulator.c +++ b/emulator.c @@ -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; diff --git a/gpio/gpio.c b/gpio/gpio.c index 5eb11d9..ed388c4 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -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); } diff --git a/gpio/gpio.h b/gpio/gpio.h index 5ad470a..43521ce 100644 --- a/gpio/gpio.h +++ b/gpio/gpio.h @@ -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); \ } \ diff --git a/platforms/amiga/Gayle.c b/platforms/amiga/Gayle.c index 6e38ffa..044b27e 100644 --- a/platforms/amiga/Gayle.c +++ b/platforms/amiga/Gayle.c @@ -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 diff --git a/platforms/amiga/amiga-platform.c b/platforms/amiga/amiga-platform.c index 292989d..264b1d9 100644 --- a/platforms/amiga/amiga-platform.c +++ b/platforms/amiga/amiga-platform.c @@ -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; diff --git a/platforms/amiga/gayle-ide/ide.c b/platforms/amiga/gayle-ide/ide.c index f82dfb5..765bb13 100644 --- a/platforms/amiga/gayle-ide/ide.c +++ b/platforms/amiga/gayle-ide/ide.c @@ -25,6 +25,7 @@ #include #include #include +#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; diff --git a/platforms/amiga/gayle-ide/ide.h b/platforms/amiga/gayle-ide/ide.h index 900c3cd..29598ec 100644 --- a/platforms/amiga/gayle-ide/ide.h +++ b/platforms/amiga/gayle-ide/ide.h @@ -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);