X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=platforms%2Famiga%2FGayle.c;h=bdfaaa72be46ca614ff6af9b400789b173a8db4a;hb=3ea3c81c4d0500adef7edfd96f0089f428619d42;hp=1bbba361bb929f6af15b3290170f067d405f4cde;hpb=ef9d05f9de811eb674657e8832bb6070f1f7e1ee;p=pistorm diff --git a/platforms/amiga/Gayle.c b/platforms/amiga/Gayle.c index 1bbba36..bdfaaa7 100644 --- a/platforms/amiga/Gayle.c +++ b/platforms/amiga/Gayle.c @@ -1,15 +1,12 @@ +// SPDX-License-Identifier: MIT + // // Gayle.c -// Omega -// -// Created by Matt Parsons on 06/03/2019. +// Originally based on Omega's Gayle emulation, +// created by Matt Parsons on 06/03/2019. // Copyright © 2019 Matt Parsons. All rights reserved. // -// Write Byte to Gayle Space 0xda9000 (0x0000c3) -// Read Byte From Gayle Space 0xda9000 -// Read Byte From Gayle Space 0xdaa000 - #include "Gayle.h" #include #include @@ -19,83 +16,57 @@ #include #include -#include "../shared/rtc.h" -#include "../../config_file/config_file.h" +#include "platforms/shared/rtc.h" +#include "config_file/config_file.h" -#include "gayle-ide/ide.h" #include "amiga-registers.h" -//#define GSTATUS 0xda201c -//#define GCLOW 0xda2010 -//#define GDH 0xda2018 - -// Gayle Addresses - -// Gayle IDE Reads -#define GERROR 0xda2004 // Error -#define GSTATUS 0xda201c // Status -// Gayle IDE Writes -#define GFEAT 0xda2004 // Write : Feature -#define GCMD 0xda201c // Write : Command -// Gayle IDE RW -#define GDATA 0xda2000 // Data -#define GSECTCNT 0xda2008 // SectorCount -#define GSECTNUM 0xda200c // SectorNumber -#define GCYLLOW 0xda2010 // CylinderLow -#define GCYLHIGH 0xda2014 // CylinderHigh -#define GDEVHEAD 0xda2018 // Device/Head -#define GCTRL 0xda3018 // Control -// Gayle Ident -#define GIDENT 0xDE1000 - -// Gayle IRQ/CC -#define GCS 0xDA8000 // Card Control -#define GIRQ 0xDA9000 // IRQ -#define GINT 0xDAA000 // Int enable -#define GCONF 0xDAB000 // Gayle Config - -/* DA8000 */ -#define GAYLE_CS_IDE 0x80 /* IDE int status */ -#define GAYLE_CS_CCDET 0x40 /* credit card detect */ -#define GAYLE_CS_BVD1 0x20 /* battery voltage detect 1 */ -#define GAYLE_CS_SC 0x20 /* credit card status change */ -#define GAYLE_CS_BVD2 0x10 /* battery voltage detect 2 */ -#define GAYLE_CS_DA 0x10 /* digital audio */ -#define GAYLE_CS_WR 0x08 /* write enable (1 == enabled) */ -#define GAYLE_CS_BSY 0x04 /* credit card busy */ -#define GAYLE_CS_IRQ 0x04 /* interrupt request */ -#define GAYLE_CS_DAEN 0x02 /* enable digital audio */ -#define GAYLE_CS_DIS 0x01 /* disable PCMCIA slot */ - -/* DA9000 */ -#define GAYLE_IRQ_IDE 0x80 -#define GAYLE_IRQ_CCDET 0x40 /* credit card detect */ -#define GAYLE_IRQ_BVD1 0x20 /* battery voltage detect 1 */ -#define GAYLE_IRQ_SC 0x20 /* credit card status change */ -#define GAYLE_IRQ_BVD2 0x10 /* battery voltage detect 2 */ -#define GAYLE_IRQ_DA 0x10 /* digital audio */ -#define GAYLE_IRQ_WR 0x08 /* write enable (1 == enabled) */ -#define GAYLE_IRQ_BSY 0x04 /* credit card busy */ -#define GAYLE_IRQ_IRQ 0x04 /* interrupt request */ -#define GAYLE_IRQ_RESET 0x02 /* reset machine after CCDET change */ -#define GAYLE_IRQ_BERR 0x01 /* generate bus error after CCDET change */ - -/* DAA000 */ -#define GAYLE_INT_IDE 0x80 /* IDE interrupt enable */ -#define GAYLE_INT_CCDET 0x40 /* credit card detect change enable */ -#define GAYLE_INT_BVD1 0x20 /* battery voltage detect 1 change enable */ -#define GAYLE_INT_SC 0x20 /* credit card status change enable */ -#define GAYLE_INT_BVD2 0x10 /* battery voltage detect 2 change enable */ -#define GAYLE_INT_DA 0x10 /* digital audio change enable */ -#define GAYLE_INT_WR 0x08 /* write enable change enabled */ -#define GAYLE_INT_BSY 0x04 /* credit card busy */ -#define GAYLE_INT_IRQ 0x04 /* credit card interrupt request */ -#define GAYLE_INT_BVD_LEV 0x02 /* BVD int level, 0=lev2,1=lev6 */ -#define GAYLE_INT_BSY_LEV 0x01 /* BSY int level, 0=lev2,1=lev6 */ +//#define DEBUG_GAYLE +#ifdef DEBUG_GAYLE +#define DEBUG printf +#else +#define DEBUG(...) +#endif + +#define IDE_DUMMY + +#ifdef IDE_DUMMY +uint8_t *ide0 = NULL; + +uint8_t ide_feature_w = 0, ide_command_w = 0, ide_sec_count = 0, ide_sec_num = 0, idewrite8 = 0, ide_cyl_hi = 0, ide_dev_head = 0; +uint8_t ide_devctrl_w = 0, ide_cyl_low = 0, ide_error_r = 0, ide_status_r = 0, ide_altst_r = 0, ide_data = 0; + +uint8_t ide_read8(uint8_t *dummy, uint8_t ide_action) { if (dummy || ide_action) {}; return 0; } +uint16_t ide_read16(uint8_t *dummy, uint8_t ide_action) { if (dummy || ide_action) {}; return 0; } + +void ide_write8(uint8_t *dummy, uint8_t ide_action, uint8_t value) { if (dummy || ide_action || value) {}; } +void ide_write16(uint8_t *dummy, uint8_t ide_action, uint16_t value) { if (dummy || ide_action || value) {}; } +void ide_reset_begin(uint8_t *dummy) { if (dummy) {}; } + +uint8_t *ide_allocate(const char *name) { if (name) {}; return NULL; } + +void ide_attach_hdf(uint8_t *dummy, uint32_t idx, uint32_t fd) { + if (dummy || idx || fd) {}; + printf("[!!!IDE] No IDE emulation layer available, HDF image not attached.\n"); + return; +} + +void ide_attach(uint8_t *dummy, uint32_t idx, uint32_t fd) { + if (dummy || idx || fd) {}; + printf("[!!!IDE] No IDE emulation layer available, image not mounted.\n"); + return; +} +#else +static struct ide_controller *ide0 = NULL; +#endif + +uint8_t gary_cfg[8]; + +uint8_t ramsey_cfg = 0x08; +static uint8_t ramsey_id = RAMSEY_REV7; int counter; static uint8_t gayle_irq, gayle_cs, gayle_cs_mask, gayle_cfg; -static struct ide_controller *ide0; int fd; uint8_t rtc_type = RTC_TYPE_RICOH; @@ -105,11 +76,24 @@ char *hdd_image_file[GAYLE_MAX_HARDFILES]; uint8_t cdtv_mode = 0; unsigned char cdtv_sram[32 * SIZE_KILO]; -uint8_t gayle_int; +uint8_t gayle_a4k = 0xA0; +uint16_t gayle_a4k_irq = 0; +uint8_t gayle_a4k_int = 0; +uint8_t gayle_int = 0; + +uint32_t gayle_ide_mask = ~GDATA; +uint32_t gayle_ide_base = GDATA; +uint8_t gayle_ide_enabled = 1; +uint8_t gayle_emulation_enabled = 1; +uint8_t gayle_ide_adj = 0; + +void adjust_gayle_4000() { + gayle_ide_base = GAYLE_IDE_BASE_A4000; + gayle_ide_adj = 2; + gayle_a4k_int = 1; +} -struct ide_controller *get_ide(int index) { - //if (index) {} - return ide0; +void adjust_gayle_1200() { } void set_hard_drive_image_file_amiga(uint8_t index, char *filename) { @@ -120,99 +104,119 @@ void set_hard_drive_image_file_amiga(uint8_t index, char *filename) { } void InitGayle(void) { - if (!hdd_image_file[0]) { - hdd_image_file[0] = calloc(1, 64); - sprintf(hdd_image_file[0], "hd0.img"); - } + uint8_t num_ide_drives = 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) { + if (!ide0) + ide0 = ide_allocate("cf"); + } - 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); + 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); + num_ide_drives++; + } + else { + printf("Attaching HDD image with header.\n"); + ide_attach(ide0, i, fd); + num_ide_drives++; + } + printf("[HDD%d] HDD Image %s attached\n", i, hdd_image_file[i]); + } + } + } + if (ide0) ide_reset_begin(ide0); - printf("HDD Image %s attached\n", hdd_image_file[0]); + + if (num_ide_drives == 0) { + // No IDE drives mounted, disable IDE component of Gayle + printf("No IDE drives mounted, disabling Gayle IDE component.\n"); + gayle_ide_enabled = 0; } } -uint8_t CheckIrq(void) { - uint8_t irq; - - if (gayle_int & (1 << 7)) { - irq = ide0->drive->intrq; - // if (irq==0) - // printf("IDE IRQ: %x\n",irq); - return irq; - }; - return 0; -} +static uint8_t ide_action = 0; void writeGayleB(unsigned int address, unsigned int value) { - if (address == GFEAT) { - ide_write8(ide0, ide_feature_w, value); - return; - } - if (address == GCMD) { - ide_write8(ide0, ide_command_w, value); - return; - } - if (address == GSECTCNT) { - ide_write8(ide0, ide_sec_count, value); - return; - } - if (address == GSECTNUM) { - ide_write8(ide0, ide_sec_num, value); - return; - } - if (address == GCYLLOW) { - ide_write8(ide0, ide_cyl_low, value); - return; - } - if (address == GCYLHIGH) { - ide_write8(ide0, ide_cyl_hi, value); - return; - } - if (address == GDEVHEAD) { - ide_write8(ide0, ide_dev_head, value); - return; - } - if (address == GCTRL) { - ide_write8(ide0, ide_devctrl_w, value); - return; - } - - if (address == GIDENT) { - counter = 0; - // printf("Write Byte to Gayle Ident 0x%06x (0x%06x)\n",address,value); - return; - } - - if (address == GIRQ) { - // printf("Write Byte to Gayle GIRQ 0x%06x (0x%06x)\n",address,value); - gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)); - - return; - } - - if (address == GCS) { - printf("Write Byte to Gayle GCS 0x%06x (0x%06x)\n", address, value); - gayle_cs_mask = value & ~3; - gayle_cs &= ~3; - gayle_cs |= value & 3; - return; - } - - if (address == GINT) { - printf("Write Byte to Gayle GINT 0x%06x (0x%06x)\n", address, value); - gayle_int = value; - return; + if (ide0) { + 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: + ide_action = ide_sec_count; + goto idewrite8; + case GSECTNUM_OFFSET: + ide_action = ide_sec_num; + goto idewrite8; + case GCYLLOW_OFFSET: + ide_action = ide_cyl_low; + goto idewrite8; + case GCYLHIGH_OFFSET: + 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: + gayle_a4k_irq = value; + // Fallthrough + case GIRQ_OFFSET: + gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)); + return; + } + goto skip_idewrite8; +idewrite8:; + ide_write8(ide0, ide_action, value); + return; +skip_idewrite8:; + } } - if (address == GCONF) { - printf("Write Byte to Gayle GCONF 0x%06x (0x%06x)\n", address, value); - gayle_cfg = value; - return; + switch (address) { + /*case 0xDD203A: + printf("Write bye to A4000 Gayle: %.2X\n", value); + 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: + ramsey_cfg = value & 0x0F; + return; + case GINT: + gayle_int = value; + return; + case GCS: + 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; } if ((address & GAYLEMASK) == CLOCKBASE) { @@ -228,13 +232,20 @@ void writeGayleB(unsigned int address, unsigned int value) { return; } - printf("Write Byte to Gayle Space 0x%06x (0x%06x)\n", address, value); + DEBUG("Write Byte to Gayle Space 0x%06x (0x%06x)\n", address, value); } void writeGayle(unsigned int address, unsigned int value) { - if (address == GDATA) { - ide_write16(ide0, ide_data, value); - return; + if (ide0) { + if (address - gayle_ide_base == GDATA_OFFSET) { + ide_write16(ide0, ide_data, value); + return; + } + + if (address == GIRQ_A4000) { + gayle_a4k_irq = value; + return; + } } if ((address & GAYLEMASK) == CLOCKBASE) { @@ -251,7 +262,7 @@ void writeGayle(unsigned int address, unsigned int value) { return; } - printf("Write Word to Gayle Space 0x%06x (0x%06x)\n", address, value); + DEBUG("Write Word to Gayle Space 0x%06x (0x%06x)\n", address, value); } void writeGayleL(unsigned int address, unsigned int value) { @@ -271,39 +282,104 @@ void writeGayleL(unsigned int address, unsigned int value) { return; } - printf("Write Long to Gayle Space 0x%06x (0x%06x)\n", address, value); + DEBUG("Write Long to Gayle Space 0x%06x (0x%06x)\n", address, value); } uint8_t readGayleB(unsigned int address) { - if (address == GERROR) { - return ide_read8(ide0, ide_error_r); - } - if (address == GSTATUS) { - return ide_read8(ide0, ide_status_r); - } - - if (address == GSECTCNT) { - return ide_read8(ide0, ide_sec_count); - } - - if (address == GSECTNUM) { - return ide_read8(ide0, ide_sec_num); - } - - if (address == GCYLLOW) { - return ide_read8(ide0, ide_cyl_low); - } - - if (address == GCYLHIGH) { - return ide_read8(ide0, ide_cyl_hi); - } - - if (address == GDEVHEAD) { - return ide_read8(ide0, ide_dev_head); - } + if (ide0) { + uint8_t ide_action = 0, ide_val = 0; + + if (address >= gayle_ide_base) { + switch ((address - gayle_ide_base) - gayle_ide_adj) { + case GERROR_OFFSET: + ide_action = ide_error_r; + goto ideread8; + case GSTATUS_OFFSET: + ide_action = ide_status_r; + goto ideread8; + case GSECTCOUNT_OFFSET: + ide_action = ide_sec_count; + goto ideread8; + case GSECTNUM_OFFSET: + ide_action = ide_sec_num; + goto ideread8; + case GCYLLOW_OFFSET: + ide_action = ide_cyl_low; + goto ideread8; + case GCYLHIGH_OFFSET: + ide_action = ide_cyl_hi; + goto ideread8; + case GDEVHEAD_OFFSET: + ide_action = ide_dev_head; + goto ideread8; + case GCTRL_OFFSET: + ide_action = ide_altst_r; + goto ideread8; + case GIRQ_4000_OFFSET: + case GIRQ_OFFSET: + return 0x80; + //gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)); + } + goto skip_ideread8; +ideread8:; + ide_val = ide_read8(ide0, ide_action); + return ide_val; +skip_ideread8:; + } - if (address == GCTRL) { - return ide_read8(ide0, ide_altst_r); + switch (address) { + case GIDENT: { + uint8_t val; + if (counter == 0 || counter == 1 || counter == 3) { + val = 0x80; // 80; to enable gayle + } else { + 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 + // service manual says that Gary is accessible in the address range $DFC000 to $DFFFFF. + case GARY_REG0: + case GARY_REG1: + case GARY_REG2: + return gary_cfg[address - GARY_REG0]; + break; + //case GARY_REG3: + case GARY_REG4: + //case GARY_REG5: + return gary_cfg[address - GARY_REG4]; + case RAMSEY_ID: + return ramsey_id; + case RAMSEY_REG: + return ramsey_cfg; + case GARY_REG5: { // This makes no sense. + uint8_t val; + if (counter == 0 || counter == 1 || counter == 3) { + val = 0x80; // 80; to enable GARY + } else { + val = 0x00; + } + counter++; + return val; + } + //case 0xDD203A: + // This can't be correct, as this is the same address as GDEVHEAD on the A4000 Gayle. + //printf("Read Byte from Gayle A4k: %.2X\n", gayle_a4k); + //return gayle_a4k; + } } if ((address & GAYLEMASK) == CLOCKBASE) { @@ -318,62 +394,23 @@ uint8_t readGayleB(unsigned int address) { return get_rtc_byte(address, rtc_type); } - if (address == GIDENT) { - uint8_t val; - // printf("Read Byte from Gayle Ident 0x%06x (0x%06x)\n",address,counter); - if (counter == 0 || counter == 1 || counter == 3) { - val = 0x80; // 80; to enable gayle - } else { - val = 0x00; - } - counter++; - return val; - } - - if (address == GIRQ) { - // printf("Read Byte From GIRQ Space 0x%06x\n",gayle_irq); - - return 0x80;//gayle_irq; -/* - uint8_t irq; - irq = ide0->drive->intrq; - - if (irq == 1) { - // printf("IDE IRQ: %x\n",irq); - return 0x80; // gayle_irq; - } - - return 0; -*/ - } - - if (address == GCS) { - printf("Read Byte From GCS Space 0x%06x\n", 0x1234); - uint8_t v; - v = gayle_cs_mask | gayle_cs; - return v; - } - - if (address == GINT) { - // printf("Read Byte From GINT Space 0x%06x\n",gayle_int); - return gayle_int; - } - - if (address == GCONF) { - printf("Read Byte From GCONF Space 0x%06x\n", gayle_cfg & 0x0f); - return gayle_cfg & 0x0f; - } - - printf("Read Byte From Gayle Space 0x%06x\n", address); + DEBUG("Read Byte From Gayle Space 0x%06x\n", address); return 0xFF; } uint16_t readGayle(unsigned int address) { - if (address == GDATA) { - uint16_t value; - value = ide_read16(ide0, ide_data); - // value = (value << 8) | (value >> 8); - return value; + if (ide0) { + if (address - gayle_ide_base == GDATA_OFFSET) { + uint16_t value; + value = ide_read16(ide0, ide_data); + // value = (value << 8) | (value >> 8); + return value; + } + + if (address == GIRQ_A4000) { + gayle_a4k_irq = 0x8000; + return 0x8000; + } } if ((address & GAYLEMASK) == CLOCKBASE) { @@ -388,7 +425,7 @@ uint16_t readGayle(unsigned int address) { return ((get_rtc_byte(address, rtc_type) << 8) | (get_rtc_byte(address + 1, rtc_type))); } - printf("Read Word From Gayle Space 0x%06x\n", address); + DEBUG("Read Word From Gayle Space 0x%06x\n", address); return 0x8000; } @@ -405,6 +442,6 @@ uint32_t readGayleL(unsigned int address) { return ((get_rtc_byte(address, rtc_type) << 24) | (get_rtc_byte(address + 1, rtc_type) << 16) | (get_rtc_byte(address + 2, rtc_type) << 8) | (get_rtc_byte(address + 3, rtc_type))); } - printf("Read Long From Gayle Space 0x%06x\n", address); + DEBUG("Read Long From Gayle Space 0x%06x\n", address); return 0x8000; }