From 6eb05e14d5f0842e66838580a69337ed43970e3c Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 18 Dec 2023 23:43:37 +0100 Subject: [PATCH] ATI EGA Wonder 800+ and 18800 refactoring: 1. Proper cleanup of the code. 2. Migrate the card in question to the VGA class list as it's actually a rebadged VGA Edge (thus 18800). 3. Some VGA only features are not supported on this card and are documented in the recalctimings. --- src/include/86box/vid_ega.h | 3 - src/include/86box/video.h | 1 + src/video/vid_ati18800.c | 176 ++++++++++++++++++++++++++++-------- src/video/vid_ega.c | 105 +-------------------- src/video/vid_table.c | 2 +- 5 files changed, 142 insertions(+), 145 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 180803c8a..ec13de928 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -132,8 +132,6 @@ typedef struct ega_t { double dot_clock; - void * eeprom; - uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr); void (*render)(struct ega_t *svga); } ega_t; @@ -143,7 +141,6 @@ typedef struct ega_t { extern const device_t ega_device; extern const device_t cpqega_device; extern const device_t sega_device; -extern const device_t atiega_device; extern const device_t iskra_ega_device; extern const device_t et2000_device; #endif diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 396b39124..de27fcbb1 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -322,6 +322,7 @@ extern const device_t ati18800_wonder_device; # endif extern const device_t ati18800_vga88_device; extern const device_t ati18800_device; +extern const device_t ati18800_egawonder800plus_device; /* ATi 28800 */ extern const device_t ati28800_device; diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 5847faa39..fd658eacf 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -35,17 +35,20 @@ #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) # define BIOS_ROM_PATH_WONDER "roms/video/ati18800/VGA_Wonder_V3-1.02.bin" #endif -#define BIOS_ROM_PATH_VGA88 "roms/video/ati18800/vga88.bin" -#define BIOS_ROM_PATH_EDGE16 "roms/video/ati18800/vgaedge16.vbi" +#define BIOS_ROM_PATH_VGA88 "roms/video/ati18800/vga88.bin" +#define BIOS_ROM_PATH_EDGE16 "roms/video/ati18800/vgaedge16.vbi" +#define BIOS_ROM_PATH_ATIEGAPLUS "roms/video/ati18800/ATI EGA Wonder 800+ N1.00.BIN" enum { #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) ATI18800_WONDER = 0, ATI18800_VGA88, - ATI18800_EDGE16 + ATI18800_EDGE16, + ATI18800_EGAWONDER800PLUS #else ATI18800_VGA88 = 0, - ATI18800_EDGE16 + ATI18800_EDGE16, + ATI18800_EGAWONDER800PLUS #endif }; @@ -57,6 +60,8 @@ typedef struct ati18800_t { uint8_t regs[256]; int index; + int type; + uint32_t memory; } ati18800_t; static video_timings_t timing_ati18800 = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; @@ -76,19 +81,20 @@ ati18800_out(uint16_t addr, uint8_t val, void *priv) ati18800->index = val; break; case 0x1cf: + old = ati18800->regs[ati18800->index]; ati18800->regs[ati18800->index] = val; switch (ati18800->index) { case 0xb0: - svga_recalctimings(svga); + if ((old ^ val) & 6) + svga_recalctimings(svga); break; case 0xb2: case 0xbe: - if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ - { - svga->read_bank = ((ati18800->regs[0xb2] >> 5) & 7) * 0x10000; - svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + if (ati18800->regs[0xbe] & 8) { /*Read/write bank mode*/ + svga->read_bank = ((ati18800->regs[0xb2] & 0xe0) >> 5) * 0x10000; + svga->write_bank = ((ati18800->regs[0xb2] & 0x0e) >> 1) * 0x10000; } else /*Single bank mode*/ - svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] & 0x0e) >> 1) * 0x10000; break; case 0xb3: ati_eeprom_write(&ati18800->eeprom, val & 8, val & 2, val & 1); @@ -172,21 +178,91 @@ static void ati18800_recalctimings(svga_t *svga) { const ati18800_t *ati18800 = (ati18800_t *) svga->priv; + int clock_sel; - if (svga->crtc[0x17] & 4) { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; + clock_sel = ((svga->miscout >> 2) & 3) | ((ati18800->regs[0xbe] & 0x10) >> 1) | ((ati18800->regs[0xb9] & 2) << 1); + + if (ati18800->type == ATI18800_EGAWONDER800PLUS) { + svga->crtc[5] &= ~0x60; /*Not supported by the EGA Wonder 800+*/ + svga->crtc[0x0b] &= ~0x60; /*Not supported by the EGA Wonder 800+*/ + + svga->hdisp_time = svga->hdisp; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]); + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + + if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) { /*40 column*/ + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + /* Character clock is off by 1 now in 40-line modes, on all cards. */ + svga->ma_latch--; + svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; + } else { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + } + } } - if (!svga->scrblank && ((ati18800->regs[0xb0] & 0x02) || (ati18800->regs[0xb0] & 0x04))) /*Extended 256 colour modes*/ - { - svga->render = svga_render_8bpp_highres; - svga->bpp = 8; + if (ati18800->regs[0xb6] & 0x10) { + svga->hdisp <<= 1; + svga->htotal <<= 1; svga->rowoffset <<= 1; - svga->ma <<= 1; + svga->gdcreg[5] &= ~0x40; + } + + if (ati18800->regs[0xb0] & 6) + svga->gdcreg[5] |= 0x40; + + if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: + case 0x60: /*256+ colours*/ + switch (svga->bpp) { + default: + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + } + break; + } + break; + + default: + break; + } + } } } @@ -198,6 +274,8 @@ ati18800_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati18800); + ati18800->type = info->local; + switch (info->local) { default: #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) @@ -207,32 +285,36 @@ ati18800_init(const device_t *info) #endif case ATI18800_VGA88: rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_VGA88, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + ati18800->memory = 256; break; case ATI18800_EDGE16: rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_EDGE16, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + ati18800->memory = 512; + break; + case ATI18800_EGAWONDER800PLUS: + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_ATIEGAPLUS, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + ati18800->memory = 256; break; } - if (info->local == ATI18800_EDGE16) { - svga_init(info, &ati18800->svga, ati18800, 1 << 18, /*256kb*/ - ati18800_recalctimings, - ati18800_in, ati18800_out, - NULL, - NULL); - } else { - svga_init(info, &ati18800->svga, ati18800, 1 << 19, /*512kb*/ - ati18800_recalctimings, - ati18800_in, ati18800_out, - NULL, - NULL); - } + svga_init(info, &ati18800->svga, ati18800, ati18800->memory << 10, + ati18800_recalctimings, + ati18800_in, ati18800_out, + NULL, + NULL); + ati18800->svga.clock_gen = device_add(&ati18810_device); + ati18800->svga.getclock = ics2494_getclock; io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); io_sethandler(0x03c0, 0x0020, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); ati18800->svga.miscout = 1; + ati18800->svga.bpp = 8; - ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); + if (info->local == ATI18800_EGAWONDER800PLUS) + ati_eeprom_load(&ati18800->eeprom, "egawonder800.nvr", 0); + else + ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); return ati18800; } @@ -257,6 +339,12 @@ ati18800_available(void) return rom_present(BIOS_ROM_PATH_EDGE16); } +static int +ati18800_egawonder800plus_available(void) +{ + return rom_present(BIOS_ROM_PATH_ATIEGAPLUS); +} + static void ati18800_close(void *priv) { @@ -300,7 +388,7 @@ const device_t ati18800_wonder_device = { #endif const device_t ati18800_vga88_device = { - .name = "ATI-18800-1", + .name = "ATI 18800-1", .internal_name = "ati18800v", .flags = DEVICE_ISA, .local = ATI18800_VGA88, @@ -314,7 +402,7 @@ const device_t ati18800_vga88_device = { }; const device_t ati18800_device = { - .name = "ATI-18800-5", + .name = "ATI VGA Edge 16", .internal_name = "ati18800", .flags = DEVICE_ISA, .local = ATI18800_EDGE16, @@ -326,3 +414,17 @@ const device_t ati18800_device = { .force_redraw = ati18800_force_redraw, .config = NULL }; + +const device_t ati18800_egawonder800plus_device = { + .name = "ATI EGA Wonder 800+", + .internal_name = "egawonder800", + .flags = DEVICE_ISA, + .local = ATI18800_EGAWONDER800PLUS, + .init = ati18800_init, + .close = ati18800_close, + .reset = NULL, + { .available = ati18800_egawonder800plus_available }, + .speed_changed = ati18800_speed_changed, + .force_redraw = ati18800_force_redraw, + .config = NULL +}; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index d4abebb39..626ddeca9 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -41,7 +41,6 @@ void ega_doblit(int wx, int wy, ega_t *ega); #define BIOS_IBM_PATH "roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" #define BIOS_CPQ_PATH "roms/video/ega/108281-001.bin" #define BIOS_SEGA_PATH "roms/video/ega/lega.vbi" -#define BIOS_ATIEGA_PATH "roms/video/ega/ATI EGA Wonder 800+ N1.00.BIN" #define BIOS_ISKRA_PATH "roms/video/ega/143-02.bin", "roms/video/ega/143-03.bin" #define BIOS_TSENG_PATH "roms/video/ega/EGA ET2000.BIN" @@ -49,7 +48,6 @@ enum { EGA_IBM = 0, EGA_COMPAQ, EGA_SUPEREGA, - EGA_ATI, EGA_ISKRA, EGA_TSENG }; @@ -80,34 +78,6 @@ ega_out(uint16_t addr, uint8_t val, void *priv) addr ^= 0x60; switch (addr) { - case 0x1ce: - ega->index = val; - break; - case 0x1cf: - ega->regs[ega->index] = val; - switch (ega->index) { - case 0xb0: - ega_recalctimings(ega); - break; - case 0xb2: - case 0xbe: -#if 0 - if (ega->regs[0xbe] & 8) { /*Read/write bank mode*/ - svga->read_bank = ((ega->regs[0xb2] >> 5) & 7) * 0x10000; - svga->write_bank = ((ega->regs[0xb2] >> 1) & 7) * 0x10000; - } else /*Single bank mode*/ - svga->read_bank = svga->write_bank = ((ega->regs[0xb2] >> 1) & 7) * 0x10000; -#endif - break; - case 0xb3: - ati_eeprom_write((ati_eeprom_t *) ega->eeprom, val & 8, val & 2, val & 1); - break; - - default: - break; - } - break; - case 0x3c0: case 0x3c1: if (!ega->attrff) { @@ -276,23 +246,6 @@ ega_in(uint16_t addr, void *priv) addr ^= 0x60; switch (addr) { - case 0x1ce: - ret = ega->index; - break; - case 0x1cf: - switch (ega->index) { - case 0xb7: - ret = ega->regs[ega->index] & ~8; - if (ati_eeprom_read((ati_eeprom_t *) ega->eeprom)) - ret |= 8; - break; - - default: - ret = ega->regs[ega->index]; - break; - } - break; - case 0x3c0: if (ega_type) ret = ega->attraddr | ega->attr_palette_enable; @@ -476,31 +429,6 @@ ega_recalctimings(ega_t *ega) crtcconst *= 9.0; else crtcconst *= 8.0; - } else if (ega->eeprom) { - clksel = ((ega->miscout & 0xc) >> 2) | ((ega->regs[0xbe] & 0x10) ? 4 : 0); - - switch (clksel) { - case 0: - crtcconst = (cpuclock / 25175000.0 * (double) (1ULL << 32)); - break; - case 1: - crtcconst = (cpuclock / 28322000.0 * (double) (1ULL << 32)); - break; - case 4: - crtcconst = (cpuclock / 14318181.0 * (double) (1ULL << 32)); - break; - case 5: - crtcconst = (cpuclock / 16257000.0 * (double) (1ULL << 32)); - break; - case 7: - default: - crtcconst = (cpuclock / 36000000.0 * (double) (1ULL << 32)); - break; - } - if (!(ega->seqregs[1] & 1)) - crtcconst *= 9.0; - else - crtcconst *= 8.0; } else { if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); @@ -1414,10 +1342,6 @@ ega_standalone_init(const device_t *info) rom_init(&ega->bios_rom, BIOS_SEGA_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); break; - case EGA_ATI: - rom_init(&ega->bios_rom, BIOS_ATIEGA_PATH, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - break; case EGA_ISKRA: rom_init_interleaved(&ega->bios_rom, BIOS_ISKRA_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -1445,12 +1369,7 @@ 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); io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - if (info->local == EGA_ATI) { - io_sethandler(0x01ce, 0x0002, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - ega->eeprom = malloc(sizeof(ati_eeprom_t)); - memset(ega->eeprom, 0, sizeof(ati_eeprom_t)); - ati_eeprom_load((ati_eeprom_t *) ega->eeprom, "egawonder800.nvr", 0); - } else if (info->local == EGA_COMPAQ) { + if (info->local == EGA_COMPAQ) { io_sethandler(0x0084, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); io_sethandler(0x07c6, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); io_sethandler(0x0bc6, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); @@ -1478,12 +1397,6 @@ sega_standalone_available(void) return rom_present(BIOS_SEGA_PATH); } -static int -atiega_standalone_available(void) -{ - return rom_present(BIOS_ATIEGA_PATH); -} - static int iskra_ega_standalone_available(void) { @@ -1501,8 +1414,6 @@ ega_close(void *priv) { ega_t *ega = (ega_t *) priv; - if (ega->eeprom) - free(ega->eeprom); free(ega->vram); free(ega); } @@ -1640,20 +1551,6 @@ const device_t sega_device = { .config = ega_config }; -const device_t atiega_device = { - .name = "ATI EGA Wonder 800+", - .internal_name = "egawonder800", - .flags = DEVICE_ISA, - .local = EGA_ATI, - .init = ega_standalone_init, - .close = ega_close, - .reset = NULL, - { .available = atiega_standalone_available }, - .speed_changed = ega_speed_changed, - .force_redraw = NULL, - .config = ega_config -}; - const device_t iskra_ega_device = { .name = "Iskra EGA (Cyrillic ROM)", .internal_name = "iskra_ega", diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 6317fb5a3..f7f377888 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -79,7 +79,7 @@ video_cards[] = { // clang-format off { &vid_none_device }, { &vid_internal_device }, - { &atiega_device }, + { &ati18800_egawonder800plus_device }, { &mach8_isa_device, VIDEO_FLAG_TYPE_8514 }, { &mach32_isa_device, VIDEO_FLAG_TYPE_8514 }, { &mach64gx_isa_device },