diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index 4f7dbae3e..97da08822 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -14,11 +14,13 @@ * * Copyright 2016-2018 Miran Grca. */ -#include +#include #include +#include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/mca.h> @@ -40,7 +42,12 @@ typedef struct { rom_t bios_rom; + uint8_t pel_wd; uint8_t banking; + uint8_t reg_3d8; + uint8_t reg_3bf; + uint8_t tries; + uint8_t ext_enable; } et3000_t; static video_timings_t timing_et3000_isa = { VIDEO_ISA, 3, 3, 6, 5, 5, 10 }; @@ -48,30 +55,130 @@ static video_timings_t timing_et3000_isa = { VIDEO_ISA, 3, 3, 6, 5, 5, 10 }; static uint8_t et3000_in(uint16_t addr, void *priv); static void et3000_out(uint16_t addr, uint8_t val, void *priv); +#ifdef ENABLE_ET3000_LOG +int svga_do_log = ENABLE_ET3000_LOG; + +static void +et3000_log(const char *fmt, ...) +{ + va_list ap; + + if (et3000_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define et3000_log(fmt, ...) +#endif + static uint8_t et3000_in(uint16_t addr, void *priv) { et3000_t *dev = (et3000_t *) priv; svga_t *svga = &dev->svga; + uint8_t ret = 0xff; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; + if ((addr >= 0x03b0) && (addr < 0x03bc) && (svga->miscout & 1)) + return 0xff; + + if ((addr >= 0x03d0) && (addr < 0x03dc) && !(svga->miscout & 1)) + return 0xff; switch (addr) { - case 0x3cd: /*Banking*/ - return dev->banking; - - case 0x3d4: - return svga->crtcreg; - - case 0x3d5: - return svga->crtc[svga->crtcreg]; - default: + ret = svga_in(addr, svga); + +#ifdef ENABLE_ET3000_LOG + if (addr != 0x03da) + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); +#endif + break; + + case 0x3c1: + /* It appears the extended attribute registers are **NOT** + protected by key on the ET3000AX, as the BIOS attempts to + write to attribute register 16h without the key. */ + ret = svga_in(addr, svga); + et3000_log("[%04X:%08X] [R] %04X: %02X = %02X (%i)\n", CS, cpu_state.pc, + addr, svga->attraddr, ret, dev->ext_enable); + break; + + case 0x3c5: + if ((svga->seqaddr >= 6) && !dev->ext_enable) + ret = 0xff; + else + ret = svga_in(addr, svga); + et3000_log("[%04X:%08X] [R] %04X: %02X = %02X (%i)\n", CS, cpu_state.pc, + addr, svga->seqaddr, ret, dev->ext_enable); + break; + + case 0x3cf: + if ((svga->gdcaddr >= 0x0d) && !dev->ext_enable) + ret = 0xff; + else + ret = svga_in(addr, svga); + et3000_log("[%04X:%08X] [R] %04X: %02X = %02X (%i)\n", CS, cpu_state.pc, + addr, svga->gdcaddr & 15, ret, dev->ext_enable); + break; + + case 0x3cb: /*PEL Address/Data Wd*/ + ret = dev->pel_wd; + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + break; + + case 0x3cd: /*Banking*/ + ret = dev->banking; + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + break; + + case 0x3b4: + case 0x3d4: + ret = svga->crtcreg; + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + break; + + case 0x3b5: + case 0x3d5: + if ((svga->crtcreg >= 0x18) && (svga->crtcreg < 0x23) && !dev->ext_enable) + ret = 0xff; + else if (svga->crtcreg > 0x25) + ret = 0xff; + else + ret = svga->crtc[svga->crtcreg]; + et3000_log("[%04X:%08X] [R] %04X: %02X = %02X\n", CS, cpu_state.pc, + addr, svga->crtcreg, ret); + break; + + case 0x3b8: + case 0x3d8: + ret = dev->reg_3d8; + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + break; + + case 0x3ba: + case 0x3da: + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + + ret = svga->cgastat; + + if ((svga->fcr & 0x08) && svga->dispon) + ret |= 0x08; + break; + + case 0x3bf: + ret = dev->reg_3bf; + et3000_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); break; } - return svga_in(addr, svga); + return ret; } static void @@ -80,47 +187,119 @@ et3000_out(uint16_t addr, uint8_t val, void *priv) et3000_t *dev = (et3000_t *) priv; svga_t *svga = &dev->svga; uint8_t old; + uint8_t index; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; + et3000_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); + + if ((addr >= 0x03b0) && (addr < 0x03bc) && (svga->miscout & 1)) + return; + + if ((addr >= 0x03d0) && (addr < 0x03dc) && !(svga->miscout & 1)) + return; switch (addr) { case 0x3c0: - case 0x3c1: + /* It appears the extended attribute registers are **NOT** + protected by key on the ET3000AX, as the BIOS attempts to + write to attribute register 16h without the key. */ + if (svga->attrff && (svga->attraddr == 0x11) && (svga->attrregs[0x16] & 0x01)) + val = (val & 0xf0) | (svga->attrregs[0x11] & 0x0f); +#ifdef ENABLE_ET3000_LOG + if (svga->attrff && (svga->attraddr > 0x14)) + et3000_log("3C1: %02X = %02X\n", svga->attraddr, val); +#endif if (svga->attrff && (svga->attraddr == 0x16)) { svga->attrregs[0x16] = val; svga->chain4 &= ~0x10; if (svga->gdcreg[5] & 0x40) svga->chain4 |= (svga->attrregs[0x16] & 0x10); svga_recalctimings(svga); + return; } break; + case 0x3c1: + return; + case 0x3c2: + svga->miscout = val; + svga->vidclock = val & 4; + svga_recalctimings(svga); + return; + + case 0x3c4: + svga->seqaddr = val & 0x07; + return; case 0x3c5: + if ((svga->seqaddr >= 6) && !dev->ext_enable) + return; + if (svga->seqaddr == 4) { svga->seqregs[4] = val; svga->chain2_write = !(val & 4); svga->chain4 = (svga->chain4 & ~8) | (val & 8); - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); + et3000_log("CHAIN2 = %i, CHAIN4 = %i\n", svga->chain2_write, svga->chain4); + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4 && + !(svga->adv_flags & FLAG_ADDR_BY8); return; } +#ifdef ENABLE_ET3000_LOG + else if (svga->seqaddr > 4) + et3000_log("3C5: %02X = %02X\n", svga->seqaddr, val); +#endif break; - case 0x3cf: - if ((svga->gdcaddr & 15) == 5) { - svga->chain4 &= ~0x10; - if (val & 0x40) - svga->chain4 |= (svga->attrregs[0x16] & 0x10); + case 0x3c9: + if (svga->adv_flags & FLAG_RAMDAC_SHIFT) + val <<= 2; + svga->fullchange = svga->monitor->mon_changeframecount; + switch (svga->dac_pos) { + case 0: + if (!(svga->attrregs[0x16] & 0x02) && !(svga->attrregs[0x17] & 0x80)) + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + if (!(svga->attrregs[0x16] & 0x02) && !(svga->attrregs[0x17] & 0x80)) + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + index = svga->dac_addr & 255; + if (!(svga->attrregs[0x16] & 0x02) && !(svga->attrregs[0x17] & 0x80)) { + svga->dac_b = val; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = svga->dac_b; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, + svga->vgapal[index].b); + else + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], + video_6to8[svga->vgapal[index].g & 0x3f], + video_6to8[svga->vgapal[index].b & 0x3f]); + } + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 255; + break; + + default: + break; } + return; + + case 0x3cb: /*PEL Address/Data Wd*/ + et3000_log("3CB = %02X\n", val); + dev->pel_wd = val; break; case 0x3cd: /*Banking*/ - dev->banking = val; + et3000_log("3CD = %02X\n", val); if (!(svga->crtc[0x23] & 0x80) && !(svga->gdcreg[6] & 0x08)) { switch ((val >> 6) & 3) { case 0: /*128K segments*/ - svga->write_bank = (val & 7) << 17; + svga->write_bank = ((val >> 0) & 7) << 17; svga->read_bank = ((val >> 3) & 7) << 17; break; case 1: /*64K segments*/ @@ -132,13 +311,68 @@ et3000_out(uint16_t addr, uint8_t val, void *priv) break; } } + dev->banking = val; return; + case 0x3ce: + svga->gdcaddr = val & 0x0f; + return; + case 0x3cf: + if ((svga->gdcaddr >= 0x0d) && !dev->ext_enable) + return; + + if ((svga->gdcaddr & 15) == 5) { + svga->chain4 &= ~0x10; + if (val & 0x40) + svga->chain4 |= (svga->attrregs[0x16] & 0x10); + } else if ((svga->gdcaddr & 15) == 6) { + if (!(svga->crtc[0x23] & 0x80) && !(val & 0x08)) { + switch ((dev->banking >> 6) & 3) { + case 0: /*128K segments*/ + svga->write_bank = ((dev->banking >> 0) & 7) << 17; + svga->read_bank = ((dev->banking >> 3) & 7) << 17; + break; + case 1: /*64K segments*/ + svga->write_bank = (dev->banking & 7) << 16; + svga->read_bank = ((dev->banking >> 3) & 7) << 16; + break; + + default: + break; + } + } else + svga->write_bank = svga->read_bank = 0; + + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) { + /* Override mask - ET3000 supports linear 128k at A0000. */ + svga->banked_mask = 0x1ffff; + } + return; + } +#ifdef ENABLE_ET3000_LOG + else if ((svga->gdcaddr & 15) > 8) + et3000_log("3CF: %02X = %02X\n", (svga->gdcaddr & 15), val); +#endif + break; + + case 0x3b4: case 0x3d4: svga->crtcreg = val & 0x3f; return; + case 0x3b5: case 0x3d5: + if ((svga->crtcreg >= 0x18) && (svga->crtcreg < 0x23) && !dev->ext_enable) + return; + else if (svga->crtcreg > 0x25) + return; + + /* Unlike the ET4000AX, which protects all bits of the + overflow high register (0x35 there, 0x25 here) except for + bits 4 and 7, if bit 7 of CRTC 11h is set, the ET3000AX + does not to that. */ if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -146,6 +380,11 @@ et3000_out(uint16_t addr, uint8_t val, void *priv) old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; +#ifdef ENABLE_ET3000_LOG + if (svga->crtcreg > 0x18) + et3000_log("3D5: %02X = %02X\n", svga->crtcreg, val); +#endif + if (old != val) { if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) { svga->fullchange = changeframecount; @@ -154,6 +393,27 @@ et3000_out(uint16_t addr, uint8_t val, void *priv) } break; + case 0x3b8: + case 0x3d8: + et3000_log("%04X = %02X\n", addr, val); + dev->reg_3d8 = val; + if ((val == 0xa0) && (dev->tries == 1)) { + dev->ext_enable = 1; + dev->tries = 0; + } else if (val == 0x29) + dev->tries = 1; + return; + + case 0x3bf: + et3000_log("%04X = %02X\n", addr, val); + dev->reg_3bf = val; + if ((val == 0x01) && (dev->tries == 1)) { + dev->ext_enable = 0; + dev->tries = 0; + } else if (val == 0x03) + dev->tries = 1; + return; + default: break; } @@ -199,10 +459,8 @@ et3000_recalctimings(svga_t *svga) } } -#if 0 - pclog("HDISP = %i, HTOTAL = %i, ROWOFFSET = %i, INTERLACE = %i\n", - svga->hdisp, svga->htotal, svga->rowoffset, svga->interlace); -#endif + et3000_log("HDISP = %i, HTOTAL = %i, ROWOFFSET = %i, INTERLACE = %i\n", + svga->hdisp, svga->htotal, svga->rowoffset, svga->interlace); switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x24] << 1) & 4)) { case 0: @@ -238,7 +496,7 @@ et3000_init(const device_t *info) svga_init(info, &dev->svga, dev, device_get_config_int("memory") << 10, et3000_recalctimings, et3000_in, et3000_out, NULL, NULL); - io_sethandler(0x03c0, 32, + io_sethandler(0x03b0, 48, et3000_in, NULL, NULL, et3000_out, NULL, NULL, dev); break; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 984071ade..f5f9ad813 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -244,11 +244,61 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) et4000_t *dev = (et4000_t *) priv; svga_t *svga = &dev->svga; uint8_t old; + uint8_t pal4to16[16] = { 0, 7, 0x38, 0x3f, 0, 3, 4, 0x3f, 0, 2, 4, 0x3e, 0, 3, 5, 0x3f }; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 0x1f; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val)) + svga->fullchange = svga->monitor->mon_changeframecount; + old = svga->attrregs[svga->attraddr & 0x1f]; + svga->attrregs[svga->attraddr & 0x1f] = val; + if (svga->attraddr < 0x10) + svga->fullchange = svga->monitor->mon_changeframecount; + + if ((svga->attraddr == 0x10) || (svga->attraddr == 0x14) || (svga->attraddr < 0x10)) { + for (int c = 0; c < 0x10; c++) { + if (svga->attrregs[0x10] & 0x80) + svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else if (svga->ati_4color) + svga->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)]; + else + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + svga->fullchange = svga->monitor->mon_changeframecount; + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + svga->chain4 &= ~0x02; + if ((val & 0x40) && (svga->attrregs[0x10] & 0x40)) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + if (old != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (old != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = svga->monitor->mon_changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c5: if (svga->seqaddr == 4) { svga->seqregs[4] = val; @@ -260,7 +310,7 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) } else if (svga->seqaddr == 0x0e) { svga->seqregs[0x0e] = val; svga->chain4 &= ~0x02; - if (svga->gdcreg[5] & 0x40) + if ((svga->gdcreg[5] & 0x40) && svga->lowres) svga->chain4 |= (svga->seqregs[0x0e] & 0x02); svga_recalctimings(svga); return; @@ -286,7 +336,11 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) return; case 0x3cf: - if ((svga->gdcaddr & 15) == 6) { + if ((svga->gdcaddr & 15) == 5) { + svga->chain4 &= ~0x02; + if ((val & 0x40) && svga->lowres) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + } else if ((svga->gdcaddr & 15) == 6) { if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { svga->write_bank = (dev->banking & 0x0f) * 0x10000; svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; @@ -663,13 +717,6 @@ et4000_recalctimings(svga_t *svga) } } - if (dev->type == ET4000_TYPE_TC6058AF) { - if (svga->render == svga_render_8bpp_lowres) - svga->render = svga_render_8bpp_tseng_lowres; - else if (svga->render == svga_render_8bpp_highres) - svga->render = svga_render_8bpp_tseng_highres; - } - if ((svga->bpp == 8) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { svga->map8 = svga->pallook; if (svga->lowres) @@ -677,6 +724,19 @@ et4000_recalctimings(svga_t *svga) else svga->render = svga_render_8bpp_highres; } + + if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40) && svga->lowres) { + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + svga->render = svga_render_8bpp_highres; + } + + if (dev->type == ET4000_TYPE_TC6058AF) { + if (svga->render == svga_render_8bpp_lowres) + svga->render = svga_render_8bpp_tseng_lowres; + else if (svga->render == svga_render_8bpp_highres) + svga->render = svga_render_8bpp_tseng_highres; + } } static void