From 77f1c62aeefdabdef776cd4df20ac5780cd2a757 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 26 May 2025 18:38:53 -0400 Subject: [PATCH] Support for alternate IBM EGA Address (Disabled behind ifdef because while it's a thing, you need a custom BIOS to use it) --- src/include/86box/vid_ega.h | 2 + src/video/vid_ega.c | 120 +++++++++++++++++++++++++++++++++--- 2 files changed, 115 insertions(+), 7 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 0e28820ff..c4c0ea2d7 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -148,6 +148,8 @@ typedef struct ega_t { card should not attempt to display anything. */ void (*render_override)(void *priv); void * priv_parent; + + uint8_t alt_addr; /* 0 for 0x3XX range, 1 for 0x2XX range */ } ega_t; #endif diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index b0d58e0f6..49b29f369 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -72,7 +72,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) uint8_t gdcmask = (ega_type == EGA_SUPEREGA) ? 0xff : 0x0f; uint8_t crtcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x1f; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + if (((((addr & 0xfff0) == 0x3d0) || ((addr & 0xfff0) == 0x2d0)) || (((addr & 0xfff0) == 0x3b0) || ((addr & 0xfff0) == 0x2b0))) && !(ega->miscout & 1)) addr ^= 0x60; switch (addr) { @@ -94,7 +94,9 @@ ega_out(uint16_t addr, uint8_t val, void *priv) } break; + case 0x2c0: case 0x3c0: + case 0x2c1: case 0x3c1: if (atype == EGA_SUPEREGA) val &= 0x7f; /* Bit 7 indicates the flipflop status (read only) */ @@ -139,6 +141,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) } ega->attrff ^= 1; break; + case 0x2c2: case 0x3c2: o = ega->miscout; egaswitchread = (val & 0xc) >> 2; @@ -148,9 +151,15 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->miscout = val; ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : pallook64[ega->attrregs[0x11] & 0x3f]; - io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + + uint16_t base_addr = 0x03a0; +#ifdef EGA_ALT_ADDR_SUPPORT + if (ega->alt_addr == 1) + base_addr = 0x02a0; +#endif + io_removehandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); if (!(val & 1)) - io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); ega_recalctimings(ega); if ((type == EGA_TYPE_COMPAQ) && !(val & 0x02)) mem_mapping_disable(&ega->mapping); @@ -172,9 +181,11 @@ ega_out(uint16_t addr, uint8_t val, void *priv) break; } break; + case 0x2c4: case 0x3c4: ega->seqaddr = val; break; + case 0x2c5: case 0x3c5: o = ega->seqregs[ega->seqaddr & 0xf]; ega->seqregs[ega->seqaddr & 0xf] = val; @@ -201,13 +212,16 @@ ega_out(uint16_t addr, uint8_t val, void *priv) break; } break; + case 0x2c6: case 0x3c6: if (type == EGA_TYPE_COMPAQ) ega->ctl_mode = val; break; + case 0x2ce: case 0x3ce: ega->gdcaddr = val; break; + case 0x2cf: case 0x3cf: ega->gdcreg[ega->gdcaddr & gdcmask] = val; switch (ega->gdcaddr & gdcmask) { @@ -264,14 +278,18 @@ ega_out(uint16_t addr, uint8_t val, void *priv) break; } break; + case 0x2d0: case 0x3d0: + case 0x2d4: case 0x3d4: if (ega->chipset) ega->crtcreg = val & 0x3f; else ega->crtcreg = val; return; + case 0x2d1: case 0x3d1: + case 0x2d5: case 0x3d5: { int idx = ega->crtcreg; @@ -322,7 +340,7 @@ ega_in(uint16_t addr, void *priv) uint8_t gdcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x0f; uint8_t crtcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x1f; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + if (((((addr & 0xfff0) == 0x3d0) || ((addr & 0xfff0) == 0x2d0)) || (((addr & 0xfff0) == 0x3b0) || ((addr & 0xfff0) == 0x2b0))) && !(ega->miscout & 1)) addr ^= 0x60; switch (addr) { @@ -343,7 +361,9 @@ ega_in(uint16_t addr, void *priv) } break; + case 0x2c0: case 0x3c0: + case 0x2c1: case 0x3c1: if (type == EGA_TYPE_OTHER) { int data = (atype == EGA_SUPEREGA) ? (ega->attrff & 1) : (addr & 1); @@ -356,9 +376,11 @@ ega_in(uint16_t addr, void *priv) ret = (ret & 0x3f) | (ega->attrff ? 0x80 : 0x00); } break; + case 0x2c2: case 0x3c2: ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; + case 0x2c4: case 0x3c4: if (type == EGA_TYPE_OTHER) { if (atype == EGA_SUPEREGA) @@ -367,6 +389,7 @@ ega_in(uint16_t addr, void *priv) ret = ega->seqaddr; } break; + case 0x2c5: case 0x3c5: if (type == EGA_TYPE_OTHER) { if ((ega->seqaddr & 0x0f) > 0x04) @@ -375,18 +398,22 @@ ega_in(uint16_t addr, void *priv) ret = ega->seqregs[ega->seqaddr & 0xf]; } break; + case 0x2c6: case 0x3c6: if (type == EGA_TYPE_COMPAQ) ret = ega->ctl_mode; break; + case 0x2c8: case 0x3c8: if (type == EGA_TYPE_OTHER) ret = 2; break; + case 0x2cc: case 0x3cc: if (type == EGA_TYPE_OTHER) ret = ega->miscout; break; + case 0x2ce: case 0x3ce: if (ega_type == EGA_TYPE_OTHER) { ret = ega->gdcaddr; @@ -397,6 +424,7 @@ ega_in(uint16_t addr, void *priv) } } break; + case 0x2cf: case 0x3cf: if (type == EGA_TYPE_OTHER) { switch (ega->gdcaddr & gdcmask) { @@ -421,7 +449,9 @@ ega_in(uint16_t addr, void *priv) } } break; + case 0x2d0: case 0x3d0: + case 0x2d4: case 0x3d4: if (ega_type == EGA_TYPE_OTHER) { ret = ega->crtcreg; @@ -432,7 +462,9 @@ ega_in(uint16_t addr, void *priv) } } break; + case 0x2d1: case 0x3d1: + case 0x2d5: case 0x3d5: switch (ega->crtcreg & crtcmask) { case 0xc: @@ -467,6 +499,7 @@ ega_in(uint16_t addr, void *priv) break; } break; + case 0x2da: case 0x3da: ega->attrff = 0; if (type == EGA_TYPE_COMPAQ) { @@ -1464,7 +1497,12 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) } } - io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + uint16_t base_addr = 0x03a0; +#ifdef EGA_ALT_ADDR_SUPPORT + if (ega->alt_addr == 1) + base_addr = 0x02a0; +#endif + io_sethandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); } else { for (uint16_t c = 0; c < 256; c++) { pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); @@ -1619,7 +1657,15 @@ ega_standalone_init(const device_t *info) mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); if (ega_type == EGA_TYPE_COMPAQ) mem_mapping_disable(&ega->mapping); - io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + uint16_t addr = 0x03c0; +#ifdef EGA_ALT_ADDR_SUPPORT + if (ega_type == EGA_TYPE_IBM) { + addr = device_get_config_hex16("base"); + if (addr == 0x02c0) + ega->alt_addr = 1; + } +#endif + io_sethandler(addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); if (ega->chipset) { io_sethandler(0x01ce, 0x0002, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); @@ -1699,6 +1745,66 @@ ega_speed_changed(void *priv) 0 = Switch closed (ON); 1 = Switch open (OFF). */ +static const device_config_t ega_ibm_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "32 KB", .value = 32 }, + { .description = "64 KB", .value = 64 }, + { .description = "128 KB", .value = 128 }, + { .description = "256 KB", .value = 256 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 9, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Monochrome (5151/MDA) (white)", .value = 0x0B | (DISPLAY_WHITE << 4) }, + { .description = "Monochrome (5151/MDA) (green)", .value = 0x0B | (DISPLAY_GREEN << 4) }, + { .description = "Monochrome (5151/MDA) (amber)", .value = 0x0B | (DISPLAY_AMBER << 4) }, + { .description = "Color 40x25 (5153/CGA)", .value = 0x06 }, + { .description = "Color 80x25 (5153/CGA)", .value = 0x07 }, + { .description = "Enhanced Color - Normal Mode (5154/ECD)", .value = 0x08 }, + { .description = "Enhanced Color - Enhanced Mode (5154/ECD)", .value = 0x09 }, + { .description = "" } + }, + .bios = { { 0 } } + }, +#ifdef EGA_ALT_ADDR_SUPPORT + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x03c0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x3C0", .value = 0x03c0 }, + { .description = "0x2C0", .value = 0x02c0 }, + { .description = "" } + }, + .bios = { { 0 } } + }, +#endif + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + static const device_config_t ega_config[] = { // clang-format off { @@ -1753,7 +1859,7 @@ const device_t ega_device = { .available = ega_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, - .config = ega_config + .config = ega_ibm_config }; const device_t cpqega_device = {