diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index ec13de928c..ec241d613a 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -109,6 +109,8 @@ typedef struct ega_t { int bpp; int index; int remap_required; + int actual_type; + int chipset; uint32_t charseta; uint32_t charsetb; @@ -132,6 +134,8 @@ 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; @@ -141,6 +145,7 @@ 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 atiega800p_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 de27fcbb1f..396b391241 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -322,7 +322,6 @@ 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 fd658eacfb..f9dc8821ec 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -37,18 +37,15 @@ #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_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_EGAWONDER800PLUS + ATI18800_EDGE16 #else ATI18800_VGA88 = 0, - ATI18800_EDGE16, - ATI18800_EGAWONDER800PLUS + ATI18800_EDGE16 #endif }; @@ -71,6 +68,7 @@ ati18800_out(uint16_t addr, uint8_t val, void *priv) { ati18800_t *ati18800 = (ati18800_t *) priv; svga_t *svga = &ati18800->svga; + uint8_t o; uint8_t old; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -182,40 +180,6 @@ ati18800_recalctimings(svga_t *svga) 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 (ati18800->regs[0xb6] & 0x10) { svga->hdisp <<= 1; svga->htotal <<= 1; @@ -291,10 +255,6 @@ ati18800_init(const device_t *info) 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; } svga_init(info, &ati18800->svga, ati18800, ati18800->memory << 10, @@ -311,10 +271,7 @@ ati18800_init(const device_t *info) ati18800->svga.miscout = 1; ati18800->svga.bpp = 8; - if (info->local == ATI18800_EGAWONDER800PLUS) - ati_eeprom_load(&ati18800->eeprom, "egawonder800.nvr", 0); - else - ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); + ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); return ati18800; } @@ -339,12 +296,6 @@ 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) { @@ -414,17 +365,3 @@ 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 626ddeca95..da77449b0b 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -41,6 +41,7 @@ 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_ATIEGA800P_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" @@ -48,6 +49,7 @@ enum { EGA_IBM = 0, EGA_COMPAQ, EGA_SUPEREGA, + EGA_ATI800P, EGA_ISKRA, EGA_TSENG }; @@ -78,6 +80,24 @@ 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 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) { @@ -126,8 +146,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) io_removehandler(0x03a0, 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); - if ((o ^ val) & 0x80) - ega_recalctimings(ega); + ega_recalctimings(ega); break; case 0x3c4: ega->seqaddr = val; @@ -208,14 +227,24 @@ ega_out(uint16_t addr, uint8_t val, void *priv) break; case 0x3d0: case 0x3d4: - ega->crtcreg = val & 31; + if (ega->chipset) + ega->crtcreg = val & 0x3f; + else + ega->crtcreg = val & 0x1f; return; case 0x3d1: case 0x3d5: - if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80)) - return; - if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80)) - val = (ega->crtc[7] & ~0x10) | (val & 0x10); + if (ega->chipset) { + if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80)) + return; + if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80)) + val = (ega->crtc[7] & ~0x10) | (val & 0x10); + } else { + if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80)) + return; + if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80)) + val = (ega->crtc[7] & ~0x10) | (val & 0x10); + } old = ega->crtc[ega->crtcreg]; ega->crtc[ega->crtcreg] = val; if (old != val) { @@ -246,6 +275,23 @@ 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; @@ -255,8 +301,8 @@ ega_in(uint16_t addr, void *priv) ret = ega->attrregs[ega->attraddr]; break; case 0x3c2: - ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; - break; + ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; + break; case 0x3c4: if (ega_type) ret = ega->seqaddr; @@ -310,6 +356,7 @@ ega_in(uint16_t addr, void *priv) default: if (ega_type) ret = ega->crtc[ega->crtcreg]; + break; } break; case 0x3da: @@ -429,6 +476,31 @@ 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)); @@ -460,6 +532,15 @@ ega_recalctimings(ega_t *ega) } } + if (ega->chipset) { + if (ega->hdisp > 640) { + ega->dispend <<= 1; + ega->vtotal <<= 1; + ega->split <<= 1; + ega->vsyncstart <<= 1; + } + } + if (enable_overscan) { overscan_y = (ega->rowcount + 1) << 1; @@ -663,8 +744,18 @@ ega_poll(void *priv) if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) ega->stat &= ~8; ega->vslines++; - if (ega->displine > 500) - ega->displine = 0; + if (ega->chipset) { + if (ega->hdisp > 640) { + if (ega->displine > 2000) + ega->displine = 0; + } else { + if (ega->displine > 500) + ega->displine = 0; + } + } else { + if (ega->displine > 500) + ega->displine = 0; + } } else { timer_advance_u64(&ega->timer, ega->dispontime); @@ -700,7 +791,13 @@ ega_poll(void *priv) } } ega->vc++; - ega->vc &= 511; + if (ega->chipset) { + if (ega->hdisp > 640) + ega->vc &= 1023; + else + ega->vc &= 511; + } else + ega->vc &= 511; if (ega->vc == ega->split) { // TODO: Implement the hardware bug where the first scanline is drawn twice when the split happens if (ega->interlace && ega->oddeven) @@ -1327,6 +1424,9 @@ ega_standalone_init(const device_t *info) else ega_type = 1; + ega->actual_type = info->local; + ega->chipset = 0; + switch (info->local) { default: case EGA_IBM: @@ -1342,6 +1442,11 @@ 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_ATI800P: + rom_init(&ega->bios_rom, BIOS_ATIEGA800P_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + ega->chipset = 1; + break; case EGA_ISKRA: rom_init_interleaved(&ega->bios_rom, BIOS_ISKRA_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -1369,7 +1474,12 @@ 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_COMPAQ) { + if (ega->chipset) { + 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, "egawonder800p.nvr", 0); + } else 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); @@ -1397,6 +1507,12 @@ sega_standalone_available(void) return rom_present(BIOS_SEGA_PATH); } +static int +atiega800p_standalone_available(void) +{ + return rom_present(BIOS_ATIEGA800P_PATH); +} + static int iskra_ega_standalone_available(void) { @@ -1414,6 +1530,8 @@ ega_close(void *priv) { ega_t *ega = (ega_t *) priv; + if (ega->eeprom) + free(ega->eeprom); free(ega->vram); free(ega); } @@ -1551,6 +1669,20 @@ const device_t sega_device = { .config = ega_config }; +const device_t atiega800p_device = { + .name = "ATI EGA Wonder 800+", + .internal_name = "egawonder800p", + .flags = DEVICE_ISA, + .local = EGA_ATI800P, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = atiega800p_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 f7f377888b..0131fa3a44 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 }, - { &ati18800_egawonder800plus_device }, + { &atiega800p_device }, { &mach8_isa_device, VIDEO_FLAG_TYPE_8514 }, { &mach32_isa_device, VIDEO_FLAG_TYPE_8514 }, { &mach64gx_isa_device },