From 01ffb60df89a16544d7f6e894b1b0ec72abcbfc2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 6 Aug 2023 20:29:39 -0400 Subject: [PATCH 01/11] SVGA hskew --- src/video/vid_cl54xx.c | 22 ++++++ src/video/vid_et4000.c | 139 ++++++++++++++++++++++++++++++++---- src/video/vid_et4000w32.c | 8 +++ src/video/vid_s3.c | 34 +++++++-- src/video/vid_svga.c | 117 ++++++++++++++++++++++++++---- src/video/vid_svga_render.c | 17 ++++- src/video/vid_table.c | 1 + 7 files changed, 306 insertions(+), 32 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 225810974..74af8b4a1 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -1828,6 +1828,28 @@ gd54xx_recalctimings(svga_t *svga) } svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; + + pclog("svga->crtc[0x1a] = %02X\n", svga->crtc[0x1a]); + pclog("svga->crtc[0x1b] = %02X\n", svga->crtc[0x1b]); + pclog("svga->crtc[0x1c] = %02X\n", svga->crtc[0x1c]); + + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) + svga->htotal += ((svga->crtc[0x1c] >> 3) & 0x07); + + if (svga->crtc[0x1b] & ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5424) ? 0xa0 : 0x20)) { + /* Special blanking mode: the blank start and end become components of the window generator, + and the actual blanking comes from the display enable signal. */ + /* Start blanking at the first character clock after the last active one. */ + svga->hblankstart = svga->crtc[1] + 1; + svga->hblank_end_val = (svga->htotal + 6) & 0x3f; + /* In this mode, the dots per clock are always 8 or 16, never 9 or 18. */ + if (!svga->scrblank && svga->attr_palette_enable) + svga->dots_per_clock = (svga->seqregs[1] & 8) ? 16 : 8; + /* No overscan in this mode. */ + svga->hblank_overscan = 0; + /* Also make sure vertical blanking starts on display end. */ + svga->vblankstart = svga->dispend; + } } static void diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index a97d65cdb..b7362dd00 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -55,17 +55,19 @@ #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#define ET4000_TYPE_TC6058AF 0 /* ISA ET4000AX (TC6058AF) */ #define ET4000_TYPE_ISA 1 /* ISA ET4000AX */ #define ET4000_TYPE_MCA 2 /* MCA ET4000AX */ #define ET4000_TYPE_KOREAN 3 /* Korean ET4000 */ #define ET4000_TYPE_TRIGEM 4 /* Trigem 286M ET4000 */ #define ET4000_TYPE_KASAN 5 /* Kasan ET4000 */ -#define BIOS_ROM_PATH "roms/video/et4000/ET4000.BIN" -#define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" -#define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" -#define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" -#define KASAN_FONT_ROM_PATH "roms/video/et4000/kasan_ksc5601.rom" +#define BIOS_ROM_PATH "roms/video/et4000/ET4000.BIN" +#define TC6058AF_BIOS_ROM_PATH "roms/video/et4000/Tseng_Labs_VGA-4000_BIOS_V1.1.bin" +#define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" +#define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" +#define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" +#define KASAN_FONT_ROM_PATH "roms/video/et4000/kasan_ksc5601.rom" typedef struct { const char *name; @@ -115,6 +117,7 @@ et4000_in(uint16_t addr, void *priv) { et4000_t *dev = (et4000_t *) priv; svga_t *svga = &dev->svga; + uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -138,7 +141,8 @@ et4000_in(uint16_t addr, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - return sc1502x_ramdac_in(addr, svga->ramdac, svga); + if (dev->type >= ET4000_TYPE_ISA) + return sc1502x_ramdac_in(addr, svga->ramdac, svga); case 0x3cd: /*Banking*/ return dev->banking; @@ -149,6 +153,26 @@ et4000_in(uint16_t addr, void *priv) case 0x3d5: return svga->crtc[svga->crtcreg]; + 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; + + if (ret & 0x08) + ret &= 0x7f; + else + ret |= 0x80; + + return ret; + default: break; } @@ -225,12 +249,33 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) addr ^= 0x60; switch (addr) { + case 0x3c5: + 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); + return; + } else if (svga->seqaddr == 0x0e) { + svga->seqregs[0x0e] = val; + svga->chain4 &= ~0x02; + if (svga->gdcreg[5] & 0x40) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + svga_recalctimings(svga); + return; + } + break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: - sc1502x_ramdac_out(addr, val, svga->ramdac, svga); - return; + if (dev->type >= ET4000_TYPE_ISA) { + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; + } + break; case 0x3cd: /*Banking*/ if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { @@ -241,7 +286,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->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; @@ -418,7 +467,8 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) break; case 1: case 2: - et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + if ((et4000->kasan_cfg_index - 0xF0) <= 16) + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; io_removehandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); et4000->kasan_access_addr = (et4000->kasan_cfg_regs[2] << 8) | et4000->kasan_cfg_regs[1]; io_sethandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); @@ -465,7 +515,8 @@ et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) case 4: case 5: if (et4000->kasan_cfg_regs[0] & 1) { - et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; + if ((addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)) <= 4) + et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; } break; case 6: @@ -607,6 +658,19 @@ et4000_recalctimings(svga_t *svga) } } } + + if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { + svga->ma_latch <<= (1 << 0); + svga->rowoffset <<= (1 << 0); + 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 @@ -666,6 +730,7 @@ et4000_init(const device_t *info) fn = BIOS_ROM_PATH; switch (dev->type) { + case ET4000_TYPE_TC6058AF: /* ISA ET4000AX (TC6058AF) */ case ET4000_TYPE_ISA: /* ISA ET4000AX */ dev->vram_size = device_get_config_int("memory") << 10; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); @@ -674,6 +739,8 @@ et4000_init(const device_t *info) NULL, NULL); io_sethandler(0x03c0, 32, et4000_in, NULL, NULL, et4000_out, NULL, NULL, dev); + if (dev->type == ET4000_TYPE_TC6058AF) + fn = TC6058AF_BIOS_ROM_PATH; break; case ET4000_TYPE_MCA: /* MCA ET4000AX */ @@ -750,7 +817,8 @@ et4000_init(const device_t *info) break; } - dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + if (dev->type >= ET4000_TYPE_ISA) + dev->svga.ramdac = device_add(&sc1502x_ramdac_device); dev->vram_mask = dev->vram_size - 1; @@ -790,6 +858,12 @@ et4000_force_redraw(void *priv) dev->svga.fullchange = changeframecount; } +static int +et4000_tc6058af_available(void) +{ + return rom_present(TC6058AF_BIOS_ROM_PATH); +} + static int et4000_available(void) { @@ -808,6 +882,33 @@ et4000_kasan_available(void) return rom_present(KASAN_BIOS_ROM_PATH) && rom_present(KASAN_FONT_ROM_PATH); } +static const device_config_t et4000_tc6058af_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +// clang-format on +}; + static const device_config_t et4000_config[] = { // clang-format off { @@ -839,6 +940,20 @@ static const device_config_t et4000_config[] = { // clang-format on }; +const device_t et4000_tc6058af_isa_device = { + .name = "Tseng Labs ET4000AX (TC6058AF) (ISA)", + .internal_name = "et4000ax_tc6058af", + .flags = DEVICE_ISA, + .local = 0, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_tc6058af_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_tc6058af_config +}; + const device_t et4000_isa_device = { .name = "Tseng Labs ET4000AX (ISA)", .internal_name = "et4000ax", diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index c2ce39778..bc23f224e 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -457,6 +457,7 @@ et4000w32p_recalctimings(svga_t *svga) } } +#if 0 if (svga->adv_flags & FLAG_NOSKEW) { /* On the Cardex ET4000/W32p-based cards, adjust text mode clocks by 1. */ if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ @@ -480,6 +481,7 @@ et4000w32p_recalctimings(svga_t *svga) } } } +#endif if (et4000->type == ET4000W32) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { @@ -2561,6 +2563,9 @@ et4000w32p_pci_read(UNUSED(int func), int addr, void *priv) { et4000w32p_t *et4000 = (et4000w32p_t *) priv; + if (func > 0) + return 0xff; + addr &= 0xff; switch (addr) { @@ -2618,6 +2623,9 @@ et4000w32p_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) et4000w32p_t *et4000 = (et4000w32p_t *) priv; svga_t *svga = &et4000->svga; + if (func > 0) + return; + addr &= 0xff; switch (addr) { diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index bcdd64d40..48740d1ce 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -3038,6 +3038,8 @@ s3_recalctimings(svga_t *svga) s3_t *s3 = (s3_t *) svga->priv; int clk_sel = (svga->miscout >> 2) & 3; + svga->hdisp = svga->hdisp_old; + if (!svga->scrblank && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { if (svga->crtc[0x3a] & 0x10) { /*256+ color register*/ @@ -3047,14 +3049,13 @@ s3_recalctimings(svga_t *svga) } svga->ma_latch |= (s3->ma_ext << 16); - if (s3->chip >= S3_86C928) { - svga->hdisp = svga->hdisp_old; + if (s3->chip >= S3_86C928) { if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + svga->hdisp |= 0x100 * svga->dots_per_clock; } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; @@ -3072,7 +3073,8 @@ s3_recalctimings(svga_t *svga) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; - } + } else if (svga->crtc[0x43] & 0x04) + svga->rowoffset |= 0x100; if (!svga->rowoffset) svga->rowoffset = 0x100; @@ -3341,6 +3343,30 @@ s3_recalctimings(svga_t *svga) } } } + + if (s3->chip >= S3_86C801) { + if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + } + + if (svga->crtc[0x5d] & 0x04) + svga->hblankstart += 0x100; + if (s3->chip >= S3_VISION964) { + /* NOTE: The S3 Trio64V+ datasheet says this is bit 7, but then where is bit 6? + The datasheets for the pre-Trio64V+ cards say +64, which implies bit 6, + and, contrary to VGADOC, it also exists on Trio32, Trio64, Vision868, + and Vision968. */ +#if 0 + pclog("svga->crtc[0x5d] = %02X\n", svga->crtc[0x5d]); +#endif + if (svga->crtc[0x5d] & 0x08) + svga->hblank_ext = 0x40; + svga->hblank_end_len = 0x00000040; + } + } + + svga->hblank_overscan = !(svga->crtc[0x33] & 0x20); } static void diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 0e83c034a..3db97d3f1 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -202,7 +202,7 @@ svga_out(uint16_t addr, uint8_t val, void *priv) break; case 4: svga->chain2_write = !(val & 4); - svga->chain4 = val & 8; + svga->chain4 = (svga->chain4 & ~8) | (val & 8); svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && ((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); break; @@ -307,6 +307,9 @@ svga_out(uint16_t addr, uint8_t val, void *priv) if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); break; + case 0x3da: + svga->fcr = val; + break; default: break; @@ -384,6 +387,9 @@ svga_in(uint16_t addr, void *priv) if (svga->adv_flags & FLAG_RAMDAC_SHIFT) ret >>= 2; break; + case 0x3ca: + ret = svga->fcr; + break; case 0x3cc: ret = svga->miscout; break; @@ -420,6 +426,8 @@ svga_in(uint16_t addr, void *priv) ret = svga->cgastat; + if ((svga->fcr & 0x08) && svga->dispon) + ret |= 0x08; break; default: @@ -453,6 +461,14 @@ svga_recalctimings(svga_t *svga) double _dispontime; double _dispofftime; double disptime; +#ifdef ENABLE_SVGA_LOG + int vsyncend; + int vblankend; + int hdispstart; + int hdispend; + int hsyncstart; + int hsyncend; +#endif svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; @@ -490,7 +506,7 @@ svga_recalctimings(svga_t *svga) svga->vblankstart |= 0x200; svga->vblankstart++; - svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + svga->hdisp = svga->crtc[1] - ((svga->crtc[3] & 0x60) >> 5); svga->hdisp++; svga->htotal = svga->crtc[0]; @@ -513,20 +529,20 @@ svga_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + else + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + 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; switch (svga->gdcreg[5] & 0x60) { @@ -612,6 +628,26 @@ svga_recalctimings(svga_t *svga) } else svga->monitor->mon_overscan_x = 16; + svga->htotal = svga->crtc[0]; + svga->hblankstart = svga->crtc[4] + 1; + svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00); +#if 0 + pclog("htotal = %i, hblankstart = %i, hblank_end_val = %02X\n", svga->htotal, svga->hblankstart, svga->hblank_end_val); +#endif + svga->hblank_end_len = 0x00000040; + svga->hblank_overscan = 1; + + if (!svga->scrblank && svga->attr_palette_enable) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + else + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); + } else + svga->dots_per_clock = 1; + + /* Do svga->recalctimings_ex() here so that the above five variables can be + updated by said function. */ if (vga_on) { if (svga->recalctimings_ex) { svga->recalctimings_ex(svga); @@ -629,6 +665,20 @@ svga_recalctimings(svga_t *svga) xga_recalctimings(svga); } + svga->htotal += 6; /*+6 is required for Tyrian*/ + svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; + if (svga->hblankend <= svga->hblankstart) + svga->hblankend += svga->hblank_end_len; + svga->hblankend += svga->hblank_ext; + + svga->hblank_sub = 0; + if (svga->hblankend > svga->htotal) { + svga->hblankend &= (svga->hblank_end_len - 1); + svga->hblank_sub = svga->hblankend + svga->hblank_overscan; + + svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + } + if (svga->hdisp >= 2048) svga->monitor->mon_overscan_x = 0; @@ -640,6 +690,43 @@ svga_recalctimings(svga_t *svga) crtcconst = svga->clock * svga->char_width; +#ifdef ENABLE_SVGA_LOG + vsyncend = (svga->vsyncstart & 0xfffffff0) | (svga->crtc[0x11] & 0x0f); + if (vsyncend <= svga->vsyncstart) + vsyncend += 0x00000010; + vblankend = (svga->vblankstart & 0xffffff80) | (svga->crtc[0x16] & 0x7f); + if (vblankend <= svga->vblankstart) + vblankend += 0x00000080; + + hdispstart = ((svga->crtc[3] >> 5) & 3); + hdispend = svga->crtc[1] + 1; + hsyncstart = svga->crtc[4] + ((svga->crtc[5] >> 5) & 3) + 1; + hsyncend = (hsyncstart & 0xffffffe0) | (svga->crtc[5] & 0x1f); + if (hsyncend <= hsyncstart) + hsyncend += 0x00000020; +#endif + + svga_log("Last scanline in the vertical period: %i\n" + "First scanline after the last of active display: %i\n" + "First scanline with vertical retrace asserted: %i\n" + "First scanline after the last with vertical retrace asserted: %i\n" + "First scanline of blanking: %i\n" + "First scanline after the last of blanking: %i\n" + "\n" + "Last character in the horizontal period: %i\n" + "First character of active display: %i\n" + "First character after the last of active display: %i\n" + "First character with horizontal retrace asserted: %i\n" + "First character after the last with horizontal retrace asserted: %i\n" + "First character of blanking: %i\n" + "First character after the last of blanking: %i\n" + "\n" + "\n", + svga->vtotal, svga->dispend, svga->vsyncstart, vsyncend, + svga->vblankstart, vblankend, + svga->htotal, hdispstart, hdispend, hsyncstart, hsyncend, + svga->hblankstart, svga->hblankend); + if (ibm8514_on && !svga->dev8514.local) { disptime = svga->dev8514.h_total; _dispontime = svga->dev8514.h_disp; @@ -878,9 +965,9 @@ svga_poll(void *priv) if (ret) { if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else - svga->ma = svga->maback = ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; svga->ma = (svga->ma << 2); svga->maback = (svga->maback << 2); @@ -951,9 +1038,9 @@ svga_poll(void *priv) if ((dev->local && vga_on) || !dev->local) { if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else - svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); + svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; } else if (dev->local && ibm8514_on) { if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); @@ -968,6 +1055,9 @@ svga_poll(void *priv) if (svga->vsync_callback) svga->vsync_callback(svga); } +#if 0 + if (svga->vc == lines_num) { +#endif if (svga->vc == svga->vtotal) { svga->vc = 0; svga->sc = 0; @@ -1090,7 +1180,8 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->ramdac_type = RAMDAC_6BIT; - svga->map8 = svga->pallook; + svga->map8 = svga->pallook; + svga->hblank_overscan = 1; /* Do at least 1 character of overscan after horizontal blanking. */ return 0; } diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index c9369f09c..7ee263aa3 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -70,9 +70,20 @@ svga_render_blank(svga_t *svga) break; } +#if 0 + pclog("svga->displine = %i, svga->y_add = %i, svga->x_add = %i\n", svga->displine, svga->y_add, svga->x_add); +#endif uint32_t *line_ptr = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; +#if 0 + pclog("svga->hdisp = %i, svga->scrollcache = %i, char_width = %i, sizeof(uint32_t) = %i\n", svga->hdisp, svga->scrollcache, char_width, sizeof(uint32_t)); +#endif uint32_t line_width = (uint32_t) (svga->hdisp + svga->scrollcache) * char_width * sizeof(uint32_t); - memset(line_ptr, 0, line_width); + +#if 0 + pclog("line_width = %i\n", line_width); +#endif + if ((svga->hdisp + svga->scrollcache) > 0) + memset(line_ptr, 0, line_width); } void @@ -81,7 +92,7 @@ svga_render_overscan_left(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->scrblank || (svga->hdisp == 0)) + if (svga->scrblank || (svga->hdisp <= 0)) return; uint32_t *line_ptr = svga->monitor->target_buffer->line[svga->displine + svga->y_add]; @@ -97,7 +108,7 @@ svga_render_overscan_right(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->scrblank || (svga->hdisp == 0)) + if (svga->scrblank || (svga->hdisp <= 0)) return; uint32_t *line_ptr = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add + svga->hdisp]; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index eb999eb3f..e8301e3ee 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -148,6 +148,7 @@ video_cards[] = { { &et4000k_isa_device }, { &et2000_device }, { &et3000_isa_device }, + { &et4000_tc6058af_isa_device }, { &et4000_isa_device }, { &et4000w32_device }, { &et4000w32i_isa_device }, From d125caf776c837fd2e9da46a4d19d68b8b6ab068 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 09:27:07 +0100 Subject: [PATCH 02/11] Applied the blanking extensions to S3 Trio64V+ and V2/DX. --- src/video/vid_s3.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index dcb251f02..3b3cebe8d 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -4018,7 +4018,7 @@ s3_trio64v_recalctimings(svga_t *svga) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + svga->hdisp |= 0x100 * svga->dots_per_clock; } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; @@ -4146,6 +4146,24 @@ s3_trio64v_recalctimings(svga_t *svga) break; } } + + if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + } + + if (svga->crtc[0x5d] & 0x04) + svga->hblankstart += 0x100; + + /* NOTE: The S3 Trio64V+ datasheet says this is bit 7, but then where is bit 6? + The datasheets for the pre-Trio64V+ cards say +64, which implies bit 6, + and, contrary to VGADOC, it also exists on Trio32, Trio64, Vision868, + and Vision968. */ + if (svga->crtc[0x5d] & 0x08) + svga->hblank_ext = 0x40; + svga->hblank_end_len = 0x00000040; + + svga->hblank_overscan = !(svga->crtc[0x33] & 0x20); } static void From 8e9a2e0b79168e85fa6080ceb473e6658671d8ce Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 11 Jan 2024 01:48:49 +0600 Subject: [PATCH 03/11] Apply blanking extensions to more SVGA cards. * Fix duplicated logic in vid_svga.c * Voodoo 3/Banshee emulation now has blanking extensions applied * S3 ViRGE and Matrox video cards as well * Tseng ET4000-series cards as well * Fix off-by-one error in vid_cl54xx.c Trident cards are yet to be investigated. XGA and 8514/A are yet to be made blanking extensions compliant. Mach64, Paradise/WDC and OAK OTI cards remain as-is for now. --- src/video/vid_cl54xx.c | 6 +++++- src/video/vid_et4000.c | 2 ++ src/video/vid_et4000w32.c | 2 ++ src/video/vid_mga.c | 9 +++++++++ src/video/vid_s3.c | 10 +++++----- src/video/vid_s3_virge.c | 16 +++++++++++++++- src/video/vid_svga.c | 2 -- src/video/vid_voodoo_banshee.c | 6 ++++++ 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index caac05fc7..738e67607 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -1950,7 +1950,7 @@ gd54xx_recalctimings(svga_t *svga) and the actual blanking comes from the display enable signal. */ /* Start blanking at the first character clock after the last active one. */ svga->hblankstart = svga->crtc[1] + 1; - svga->hblank_end_val = (svga->htotal + 6) & 0x3f; + svga->hblank_end_val = (svga->htotal + 5) & 0xff; /* In this mode, the dots per clock are always 8 or 16, never 9 or 18. */ if (!svga->scrblank && svga->attr_palette_enable) svga->dots_per_clock = (svga->seqregs[1] & 8) ? 16 : 8; @@ -1958,6 +1958,10 @@ gd54xx_recalctimings(svga_t *svga) svga->hblank_overscan = 0; /* Also make sure vertical blanking starts on display end. */ svga->vblankstart = svga->dispend; + + /* Account for horizontal overflow bits. */ + svga->hblank_end_val += (svga->crtc[0x1a] & 0x30) << 2; + svga->hblank_end_len = 0x100; } if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index faf977d7c..882a3e12e 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -613,6 +613,8 @@ et4000_recalctimings(svga_t *svga) svga->rowoffset = 0x100; if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->crtc[0x3f] & 0x04) + svga->hblankstart += 0x100; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index b9c146d89..0133b728b 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -445,6 +445,8 @@ et4000w32p_recalctimings(svga_t *svga) svga->rowoffset += 0x100; if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->crtc[0x3F] & 0x04) + svga->hblankstart += 0x100; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index ccbf1c1b3..9fa9e9389 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -192,6 +192,8 @@ #define CRTCX_R0_OFFSET_MASK (3 << 4) #define CRTCX_R1_HTOTAL8 (1 << 0) +#define CRTCX_R1_HBLKSTRT8 (1 << 1) +#define CRTCX_R1_HBLKEND6 (1 << 6) #define CRTCX_R2_VTOTAL10 (1 << 0) #define CRTCX_R2_VTOTAL11 (1 << 1) @@ -941,6 +943,8 @@ mystique_recalctimings(svga_t *svga) if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8) svga->htotal |= 0x100; + if (mystique->crtcext_regs[1] & CRTCX_R1_HBLKSTRT8) + svga->hblankstart += 0x100; if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL10) svga->vtotal |= 0x400; if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL11) @@ -971,6 +975,11 @@ mystique_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->rowoffset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + svga->hblank_end_len = 0x80; + svga->hblank_end_val += mystique->crtcext_regs[1] & CRTCX_R1_HBLKEND6; + + svga->hblank_overscan = 0; + if (mystique->type != MGA_2164W && mystique->type != MGA_2064W) svga->lut_map = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 3b3cebe8d..6f648f628 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -4013,6 +4013,11 @@ s3_trio64v_recalctimings(svga_t *svga) s3_t *s3 = (s3_t *) svga->priv; int clk_sel = (svga->miscout >> 2) & 3; + if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + } + svga->hdisp = svga->hdisp_old; if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; @@ -4147,11 +4152,6 @@ s3_trio64v_recalctimings(svga_t *svga) } } - if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); - } - if (svga->crtc[0x5d] & 0x04) svga->hblankstart += 0x100; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index ce9dda100..76195189f 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -778,11 +778,16 @@ s3_virge_recalctimings(svga_t *svga) svga->hdisp = svga->hdisp_old; + if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + } + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time += 0x100; - svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + svga->hdisp += 0x100 * svga->dots_per_clock; } if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; @@ -906,6 +911,15 @@ s3_virge_recalctimings(svga_t *svga) } svga->vram_display_mask = virge->vram_mask; } + + if (svga->crtc[0x5d] & 0x04) + svga->hblankstart += 0x100; + + if (svga->crtc[0x5d] & 0x08) + svga->hblank_ext = 0x40; + svga->hblank_end_len = 0x00000040; + + svga->hblank_overscan = !(svga->crtc[0x33] & 0x20); } static void diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 975296e08..a350b6d28 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -738,7 +738,6 @@ svga_recalctimings(svga_t *svga) } else svga->monitor->mon_overscan_x = 16; - svga->htotal = svga->crtc[0]; svga->hblankstart = svga->crtc[4] + 1; svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00); #if 0 @@ -767,7 +766,6 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) xga_recalctimings(svga); - svga->htotal += 6; /*+6 is required for Tyrian*/ svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; if (svga->hblankend <= svga->hblankstart) svga->hblankend += svga->hblank_end_len; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 23236be6f..e10337928 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -552,6 +552,10 @@ banshee_recalctimings(svga_t *svga) svga->htotal += 0x100; if (svga->crtc[0x1a] & 0x04) svga->hdisp += 0x100; + if (svga->crtc[0x1a] & 0x10) + svga->hblankstart += 0x100; + if (svga->crtc[0x1a] & 0x20) + svga->hblank_end_val += 0x40; /*6 R/W Vertical Retrace Start bit 10 0x10 5 R/W Reserved. - 4 R/W Vertical Blank Start bit 10. 0x15 @@ -611,6 +615,8 @@ banshee_recalctimings(svga_t *svga) svga->char_width = 8; svga->split = 99999; + svga->hblank_end_len = 0x80; + if (banshee->vidProcCfg & VIDPROCCFG_2X_MODE) { svga->hdisp *= 2; svga->htotal *= 2; From 03a1f783f2234fad6c35e0d7ea199043736f3d3e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 22:41:13 +0100 Subject: [PATCH 04/11] ATi Mach64: Override (S)VGA horizontal blanking calculation in accelerator CRTC mode. --- src/video/vid_ati_mach64.c | 2 ++ src/video/vid_svga.c | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index da1b5d556..587341538 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -510,6 +510,7 @@ mach64_recalctimings(svga_t *svga) const mach64_t *mach64 = (mach64_t *) svga->priv; if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) { + svga->hoverride = 1; svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; @@ -566,6 +567,7 @@ mach64_recalctimings(svga_t *svga) svga->vram_display_mask = mach64->vram_mask; } else { + svga->hoverride = 0; svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; } } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index a350b6d28..ff8dbbbea 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -766,17 +766,19 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) xga_recalctimings(svga); - svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; - if (svga->hblankend <= svga->hblankstart) - svga->hblankend += svga->hblank_end_len; - svga->hblankend += svga->hblank_ext; + if (!svga->hoverride) { + svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; + if (svga->hblankend <= svga->hblankstart) + svga->hblankend += svga->hblank_end_len; + svga->hblankend += svga->hblank_ext; - svga->hblank_sub = 0; - if (svga->hblankend > svga->htotal) { - svga->hblankend &= (svga->hblank_end_len - 1); - svga->hblank_sub = svga->hblankend + svga->hblank_overscan; + svga->hblank_sub = 0; + if (svga->hblankend > svga->htotal) { + svga->hblankend &= (svga->hblank_end_len - 1); + svga->hblank_sub = svga->hblankend + svga->hblank_overscan; - svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + } } if (svga->hdisp >= 2048) From 0090000f850d15a6259d79a51ff10f3eeed8f81d Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 23:25:16 +0100 Subject: [PATCH 05/11] HT216-32: Apply the blanking calculation. --- src/video/vid_ht216.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 9cd68e4ee..803d5658c 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -312,6 +312,10 @@ ht216_out(uint16_t addr, uint8_t val, void *priv) ht216_remap(ht216); break; + case 0xca: + svga_recalctimings(svga); + break; + case 0xc9: case 0xcf: ht216_remap(ht216); @@ -321,6 +325,7 @@ ht216_out(uint16_t addr, uint8_t val, void *priv) svga->adv_flags &= ~FLAG_RAMDAC_SHIFT; if (val & 0x04) svga->adv_flags |= FLAG_RAMDAC_SHIFT; + svga_recalctimings(svga); fallthrough; /*Bank registers*/ case 0xe8: @@ -688,7 +693,7 @@ ht216_recalctimings(svga_t *svga) if (!(svga->crtc[1] & 1)) svga->hdisp--; svga->hdisp++; - svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp *= svga->dots_per_clock; svga->rowoffset <<= 1; if ((svga->crtc[0x17] & 0x60) == 0x20) /*Would result in a garbled screen with trailing cursor glitches*/ svga->crtc[0x17] |= 0x40; @@ -711,6 +716,9 @@ ht216_recalctimings(svga_t *svga) svga->vram_display_mask = 0x7ffff; else svga->vram_display_mask = (ht216->ht_regs[0xf6] & 0x40) ? ht216->vram_mask : 0x3ffff; + + if (ht216->ht_regs[0xe0] & 0x20) + svga->hblankstart = ((ht216->ht_regs[0xca] >> 2) << 8) + svga->crtc[4] + 1; } static void @@ -1466,9 +1474,8 @@ radius_mca_feedb(UNUSED(void *priv)) return 1; } -void - * - ht216_init(const device_t *info, uint32_t mem_size, int has_rom) +void * +ht216_init(const device_t *info, uint32_t mem_size, int has_rom) { ht216_t *ht216 = malloc(sizeof(ht216_t)); svga_t *svga; From d00dafcf16cc8416901f9a9a1612750afb5ba0d1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 23:30:48 +0100 Subject: [PATCH 06/11] Apply it to ATi 28800 and Mach 8 as well. --- src/video/vid_ati28800.c | 7 +++++++ src/video/vid_ati_mach8.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 09d6279f4..aed95b243 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -136,6 +136,10 @@ ati28800_out(uint16_t addr, uint8_t val, void *priv) if ((old ^ val) & 0x80) svga_recalctimings(svga); break; + case 0xad: + if ((old ^ val) & 0x0c) + svga_recalctimings(svga); + break; case 0xb0: if ((old ^ val) & 0x60) svga_recalctimings(svga); @@ -492,6 +496,9 @@ ati28800_recalctimings(svga_t *svga) } } } + + if (ati28800->regs[0xad] & 0x08) + svga->hblankstart = ((ati28800->regs[0x0d] >> 2) << 8) + svga->crtc[4] + 1; } static void diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 21f6abd29..92ee59e19 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2841,6 +2841,9 @@ mach_recalctimings(svga_t *svga) } } } + + if (ati28800->regs[0xad] & 0x08) + svga->hblankstart = ((ati28800->regs[0x0d] >> 2) << 8) + svga->crtc[4] + 1; } static void From b159ec07bf4e12601460ec9563a4f19d3272f045 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 23:33:08 +0100 Subject: [PATCH 07/11] And vid_svga.h. --- src/include/86box/vid_svga.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 7ba637167..880f79003 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -274,6 +274,9 @@ typedef struct svga_t { /* Enable LUT mapping of >= 24 bpp modes. */ int lut_map; + /* Override the horizontal blanking stuff. */ + int hoverride; + /* Return a 32 bpp color from a 15/16 bpp color. */ uint32_t (*conv_16to32)(struct svga_t *svga, uint16_t color, uint8_t bpp); From fe52ecc3da8f0f6dbcaee7e006b7013e168ad628 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Jan 2024 23:44:27 +0100 Subject: [PATCH 08/11] GreaseMonkey's comments in vid_svga.c. --- src/video/vid_svga.c | 67 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index ff8dbbbea..d092c849e 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -640,11 +640,20 @@ svga_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - if (svga->seqregs[1] & 8) - svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + else + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; else - svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + /*RESEARCH TOPIC: Which chipsets honour 9-dot mode in graphics mode? + One still gets an 8-dot input, but is likely to get some weird chaining through the graphics controller. + Chipsets which honour it, and do an extra pixel (or two, or four) of chaining through the GC pixel shift registers: + - (none found so far) + Chipsets which treat it like it's in 8-dot mode, and affect the monitor timings in the process: + - S3 Trio64V2/DX + */ + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ if (svga->seqregs[1] & 8) { /*40 column*/ @@ -747,11 +756,20 @@ svga_recalctimings(svga_t *svga) svga->hblank_overscan = 1; if (!svga->scrblank && svga->attr_palette_enable) { - /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ - if (svga->seqregs[1] & 8) - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); + else + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); else - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); + /*RESEARCH TOPIC: Which chipsets honour 9-dot mode in graphics mode? + One still gets an 8-dot input, but is likely to get some weird chaining through the graphics controller. + Chipsets which honour it, and do an extra pixel (or two, or four) of chaining through the GC pixel shift registers: + - (none found so far) + Chipsets which treat it like it's in 8-dot mode, and affect the monitor timings in the process: + - S3 Trio64V2/DX + */ + svga->dots_per_clock = ((svga->seqregs[1] & 8) ? 16 : 8); } else svga->dots_per_clock = 1; @@ -766,19 +784,17 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) xga_recalctimings(svga); - if (!svga->hoverride) { - svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; - if (svga->hblankend <= svga->hblankstart) - svga->hblankend += svga->hblank_end_len; - svga->hblankend += svga->hblank_ext; + svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; + if (svga->hblankend <= svga->hblankstart) + svga->hblankend += svga->hblank_end_len; + svga->hblankend += svga->hblank_ext; - svga->hblank_sub = 0; - if (svga->hblankend > svga->htotal) { - svga->hblankend &= (svga->hblank_end_len - 1); - svga->hblank_sub = svga->hblankend + svga->hblank_overscan; + svga->hblank_sub = 0; + if (svga->hblankend > svga->htotal) { + svga->hblankend &= (svga->hblank_end_len - 1); + svga->hblank_sub = svga->hblankend + svga->hblank_overscan; - svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); - } + svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); } if (svga->hdisp >= 2048) @@ -1060,6 +1076,17 @@ svga_poll(void *priv) ret = svga->line_compare(svga); if (ret) { + /*NOTE ON CHARACTER SKEW VALUES: + - CR03 delays the start and end of active video, while continuing to clock things as usual. + This effectively hides N character clocks on the left, and reveals N character clocks on the right. + - CR05 delays the horizontal retrace (HSYNC) signal. It affects the position of the displayed image on the monitor. + Since 86Box at the time of writing (2024-01-10) does not support overscan for anything other than showing the border, + there should be no effect. + - CR0B delays the position of the cursor by a number of character clocks. + So how do the INT 0x10 modes work? + - EGA has some rather interesting values for all of this which can make for interesting research. + - VGA and all of a few SVGA chipsets sampled uses 0 for everything except CR05 in the two 40x25 text modes where it uses 1. + */ if (svga->interlace && svga->oddeven) svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else @@ -1133,7 +1160,7 @@ svga_poll(void *priv) svga->vslines = 0; if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; From c4aa4e888995054aef852d441bfc9d16bb3ab105 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 11 Jan 2024 01:56:32 +0100 Subject: [PATCH 09/11] A minor change to video/vid_svga.c. --- src/video/vid_svga.c | 74 ++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index d092c849e..142037696 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -640,20 +640,11 @@ svga_recalctimings(svga_t *svga) 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) - svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; - else - svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; else - /*RESEARCH TOPIC: Which chipsets honour 9-dot mode in graphics mode? - One still gets an 8-dot input, but is likely to get some weird chaining through the graphics controller. - Chipsets which honour it, and do an extra pixel (or two, or four) of chaining through the GC pixel shift registers: - - (none found so far) - Chipsets which treat it like it's in 8-dot mode, and affect the monitor timings in the process: - - S3 Trio64V2/DX - */ - svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ if (svga->seqregs[1] & 8) { /*40 column*/ @@ -749,27 +740,19 @@ svga_recalctimings(svga_t *svga) svga->hblankstart = svga->crtc[4] + 1; svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00); -#if 0 - pclog("htotal = %i, hblankstart = %i, hblank_end_val = %02X\n", svga->htotal, svga->hblankstart, svga->hblank_end_val); -#endif + + svga_log("htotal = %i, hblankstart = %i, hblank_end_val = %02X\n", + svga->htotal, svga->hblankstart, svga->hblank_end_val); + svga->hblank_end_len = 0x00000040; svga->hblank_overscan = 1; if (!svga->scrblank && svga->attr_palette_enable) { - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); - else - svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); + /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ + if (svga->seqregs[1] & 8) + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 16 : 18); else - /*RESEARCH TOPIC: Which chipsets honour 9-dot mode in graphics mode? - One still gets an 8-dot input, but is likely to get some weird chaining through the graphics controller. - Chipsets which honour it, and do an extra pixel (or two, or four) of chaining through the GC pixel shift registers: - - (none found so far) - Chipsets which treat it like it's in 8-dot mode, and affect the monitor timings in the process: - - S3 Trio64V2/DX - */ - svga->dots_per_clock = ((svga->seqregs[1] & 8) ? 16 : 8); + svga->dots_per_clock = ((svga->seqregs[1] & 1) ? 8 : 9); } else svga->dots_per_clock = 1; @@ -784,17 +767,19 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) xga_recalctimings(svga); - svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; - if (svga->hblankend <= svga->hblankstart) - svga->hblankend += svga->hblank_end_len; - svga->hblankend += svga->hblank_ext; + if (!svga->hoverride) { + svga->hblankend = (svga->hblankstart & ~(svga->hblank_end_len - 1)) | svga->hblank_end_val; + if (svga->hblankend <= svga->hblankstart) + svga->hblankend += svga->hblank_end_len; + svga->hblankend += svga->hblank_ext; - svga->hblank_sub = 0; - if (svga->hblankend > svga->htotal) { - svga->hblankend &= (svga->hblank_end_len - 1); - svga->hblank_sub = svga->hblankend + svga->hblank_overscan; + svga->hblank_sub = 0; + if (svga->hblankend > svga->htotal) { + svga->hblankend &= (svga->hblank_end_len - 1); + svga->hblank_sub = svga->hblankend + svga->hblank_overscan; - svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); + } } if (svga->hdisp >= 2048) @@ -1076,17 +1061,6 @@ svga_poll(void *priv) ret = svga->line_compare(svga); if (ret) { - /*NOTE ON CHARACTER SKEW VALUES: - - CR03 delays the start and end of active video, while continuing to clock things as usual. - This effectively hides N character clocks on the left, and reveals N character clocks on the right. - - CR05 delays the horizontal retrace (HSYNC) signal. It affects the position of the displayed image on the monitor. - Since 86Box at the time of writing (2024-01-10) does not support overscan for anything other than showing the border, - there should be no effect. - - CR0B delays the position of the cursor by a number of character clocks. - So how do the INT 0x10 modes work? - - EGA has some rather interesting values for all of this which can make for interesting research. - - VGA and all of a few SVGA chipsets sampled uses 0 for everything except CR05 in the two 40x25 text modes where it uses 1. - */ if (svga->interlace && svga->oddeven) svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else @@ -1160,7 +1134,7 @@ svga_poll(void *priv) svga->vslines = 0; if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; else svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[3] & 0x60) >> 5) + svga->hblank_sub; From 3010ce4f8ab7e1a06dfa6d9b211d793ae1fcd426 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 11 Jan 2024 02:07:21 +0100 Subject: [PATCH 10/11] Minor ATi fixes. --- src/video/vid_ati28800.c | 9 +++++++-- src/video/vid_ati_mach8.c | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index aed95b243..c2ede4d45 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -407,7 +407,8 @@ ati28800_recalctimings(svga_t *svga) ati28800_t *ati28800 = (ati28800_t *) svga->priv; int clock_sel; - clock_sel = ((svga->miscout >> 2) & 3) | ((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1); + clock_sel = ((svga->miscout >> 2) & 3) | ((ati28800->regs[0xbe] & 0x10) >> 1) | + ((ati28800->regs[0xb9] & 2) << 1); if (ati28800->regs[0xa3] & 0x10) svga->ma_latch |= 0x10000; @@ -447,7 +448,11 @@ ati28800_recalctimings(svga_t *svga) 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); - ati28800_log("SEQREG1 bit 3=%x. gdcreg5 bits 5-6=%02x, 4bit pel=%02x, planar 16color=%02x, apa mode=%02x, attregs10 bit 7=%02x.\n", svga->seqregs[1] & 8, svga->gdcreg[5] & 0x60, ati28800->regs[0xb3] & 0x40, ati28800->regs[0xac] & 0x40, ati28800->regs[0xb6] & 0x18, ati28800->svga.attrregs[0x10] & 0x80); + ati28800_log("SEQREG1 bit 3=%x. gdcreg5 bits 5-6=%02x, 4bit pel=%02x, " + "planar 16color=%02x, apa mode=%02x, attregs10 bit 7=%02x.\n", + svga->seqregs[1] & 8, svga->gdcreg[5] & 0x60, + ati28800->regs[0xb3] & 0x40, ati28800->regs[0xac] & 0x40, + ati28800->regs[0xb6] & 0x18, ati28800->svga.attrregs[0x10] & 0x80); switch (svga->gdcreg[5] & 0x60) { case 0x00: if (svga->seqregs[1] & 8) /*Low res (320)*/ diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 92ee59e19..365a03cee 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2842,8 +2842,8 @@ mach_recalctimings(svga_t *svga) } } - if (ati28800->regs[0xad] & 0x08) - svga->hblankstart = ((ati28800->regs[0x0d] >> 2) << 8) + svga->crtc[4] + 1; + if (mach->regs[0xad] & 0x08) + svga->hblankstart = ((mach->regs[0x0d] >> 2) << 8) + svga->crtc[4] + 1; } static void From 553e58f8efb399f96164e9de7f218606656ca644 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 11 Jan 2024 02:11:23 +0100 Subject: [PATCH 11/11] Remove an unnecessary subtraction proven to be wrong by the S3 and IBM documentation and that was a result of VGADOC being vague. --- src/video/vid_svga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 142037696..39d6a2e22 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -617,7 +617,7 @@ svga_recalctimings(svga_t *svga) svga->vblankstart |= 0x200; svga->vblankstart++; - svga->hdisp = svga->crtc[1] - ((svga->crtc[3] & 0x60) >> 5); + svga->hdisp = svga->crtc[1]; svga->hdisp++; svga->htotal = svga->crtc[0];