From b6adf1e5aaf7c3a88a207872733703bbc54a16b9 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 23 Jan 2026 01:05:04 +0100 Subject: [PATCH] S3 and 8514/A compatible fixes for various stuff. 1. Correct some more clock bugs of the ELSA Winner NeXTSTEP/OPENSTEP third party driver (please report any regressions if possible on other stuff). 2. Line Vector command with flag 0x211x (r/w) is now more usable (not perfect yet) and fill brushes now have correct colors (but also not perfect either) in Windows 2.x' 8514/a drivers. --- src/include/86box/vid_8514a.h | 3 + src/video/vid_8514a.c | 154 ++++++++++++++++++++++++++++------ src/video/vid_ati_mach8.c | 7 +- src/video/vid_s3.c | 126 ++++++++++++++++++---------- 4 files changed, 221 insertions(+), 69 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index dddb216f6..d0cd25547 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -164,8 +164,11 @@ typedef struct ibm8514_t { int y_count; int input; int input2; + int input3; int output; int output2; + int output3; + int init_cx; int ssv_len; int ssv_len_back; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index d521c07d5..ca7e182b0 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -289,9 +289,9 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in val = (val >> 8) | (val << 8); } if ((cmd <= 2) || (cmd == 4) || (cmd == 6)) { - if ((dev->accel.cmd & 0x08) && (cmd >= 2)) + if ((dev->accel.cmd & 0x08) && (cmd >= 1)) { monoxfer = val; - else { + } else { if (val & 0x02) nibble |= 0x80; if (val & 0x04) @@ -893,8 +893,12 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) READ_HIGH(dev->accel.dest + dev->accel.cx, temp); } ibm8514_accel_out_pixtrans(svga, port, (temp >> 8) & 0xff, len); - } else + } else { + if (dev->accel.input3) + temp = 0xffff; + ibm8514_accel_out_pixtrans(svga, port, temp, len); + } } } break; @@ -1393,8 +1397,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 1: /*Draw line*/ if (!cpu_input) { + dev->accel.init_cx = 0; + dev->accel.input3 = 0; dev->accel.output = 0; + dev->accel.output3 = 0; dev->accel.x_count = 0; + dev->accel.xx_count = 0; dev->accel.cx = dev->accel.cur_x; if (dev->accel.cur_x >= 0x600) @@ -1406,12 +1414,20 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sy = dev->accel.maj_axis_pcnt; + ibm8514_log("CMD=%d, full=%04x, curx=%d, cury=%d, pixcntl=%x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, bkgdmix=%02x, and3=%d, sy=%d.\n", + cmd, dev->accel.cmd, dev->accel.cx, dev->accel.cy, pixcntl, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.bkgd_mix, and3, dev->accel.sy); + ibm8514_log("Line Draw 8514/A CMD=%04x, frgdmix=%d, bkgdmix=%d, c(%d,%d), pixcntl=%d, sy=%d, polyfill=%x, selfrmix=%02x, selbkmix=%02x, bkgdcol=%02x, frgdcol=%02x, clipt=%d, clipb=%d.\n", dev->accel.cmd, frgd_mix, bkgd_mix, dev->accel.cx, dev->accel.cy, pixcntl, dev->accel.sy, dev->accel.multifunc[0x0a] & 6, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, bkgd_color, frgd_color, dev->accel.clip_top, clip_b); if (ibm8514_cpu_src(svga)) { if (dev->accel.cmd & 0x02) { if (!(dev->accel.cmd & 0x1000)) { - if (dev->accel.cmd & 0x08) - dev->accel.output = 1; + if (dev->accel.cmd & 0x08) { + if (dev->accel.cmd == 0x211b) { + dev->accel.x_count = dev->accel.cx - (and3 + 3); + dev->accel.sy += (and3 + 3); + } else + dev->accel.output = 1; + } } } dev->force_busy = 1; @@ -1420,11 +1436,20 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->data_available2 = 0; return; /*Wait for data from CPU*/ } else if (ibm8514_cpu_dest(svga)) { + if (dev->accel.cmd & 0x02) { + if (!(dev->accel.cmd & 0x1000)) { + if (dev->accel.cmd & 0x08) { + if ((frgd_mix == 3) && (bkgd_mix == 3) && (pixcntl == 0) && + ((dev->accel.multifunc[0x0a] & 0x06) == 0x04) && (dev->accel.frgd_mix != 0x07)) /*Kinda of a workaround for fill brushes on 8514/A using Windows 2.x*/ + dev->accel.input3 = 1; + } + } + } dev->force_busy = 1; dev->force_busy2 = 1; dev->data_available = 1; dev->data_available2 = 1; - return; + return; /*Wait for data from CPU*/ } } @@ -1432,10 +1457,17 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (ibm8514_cpu_dest(svga) && cpu_input && (dev->accel.cmd & 0x02)) count >>= 1; - if (dev->accel.cmd & 0x02) - ibm8514_log("Line Draw Vector Single pixtrans=%04x, count=%d.\n", mix_dat, count); + if (dev->accel.cmd == 0x211b) { + if (and3 >= 2) { + if (dev->accel.sy < (count << 1)) + count <<= 1; + } + } + if (dev->accel.cmd & 0x1000) + ibm8514_log("Vector Line %d: full=%04x, odd=%d, c(%d,%d), frgdmix=%d, bkgdmix=%d, xcount=%d, and3=%d, len(%d,%d), CURX=%d, Width=%d, pixcntl=%d, mix_dat=%08x, count=%d, cpu_data=%08x, cpu_input=%d.\n", cmd, dev->accel.cmd, dev->accel.input, dev->accel.cx, dev->accel.cy, frgd_mix, bkgd_mix, dev->accel.x_count, and3, dev->accel.sx, dev->accel.sy, dev->accel.cur_x, dev->accel.maj_axis_pcnt, pixcntl, mix_dat, count, cpu_dat, cpu_input); while (count-- && (dev->accel.sy >= 0)) { + ibm8514_log("CurrentX=%d, CurrentY=%d, Count=%d.\n", dev->accel.cx, dev->accel.cy, count); if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && @@ -1455,6 +1487,17 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (pixcntl == 3) src_dat = ((src_dat & rd_mask) == rd_mask); } else { + if (dev->accel.cmd == 0x211b) { + if (dev->accel.x_count != dev->accel.cx) { + dev->accel.output3 = 1; + } else { + dev->accel.output3 = 0; + } + + if (dev->accel.output3 == 1) + goto skip_vector_line_write; + } + if (dev->accel.output) { switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: @@ -1523,6 +1566,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } else if (!(dev->accel.cmd & 0x04)) { WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); } + } else if (dev->accel.input3) { + if ((dev->accel.cmd & 0x04) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat ? dest_dat : 0xff); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat ? dest_dat : 0xff); + } } } } @@ -1542,13 +1591,6 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat break; } - if (dev->accel.output) - mix_dat >>= 1; - else { - mix_dat <<= 1; - mix_dat |= 1; - } - if (dev->bpp) cpu_dat >>= 16; else @@ -1560,37 +1602,90 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat break; case 0x20: dev->accel.cx++; - dev->accel.cy--; + if (!dev->accel.output3) + dev->accel.cy--; break; case 0x40: - dev->accel.cy--; + if (!dev->accel.output3) + dev->accel.cy--; break; case 0x60: dev->accel.cx--; - dev->accel.cy--; + if (!dev->accel.output3) + dev->accel.cy--; break; case 0x80: dev->accel.cx--; break; case 0xa0: dev->accel.cx--; - dev->accel.cy++; + if (!dev->accel.output3) + dev->accel.cy++; break; case 0xc0: - dev->accel.cy++; + if (!dev->accel.output3) + dev->accel.cy++; break; case 0xe0: dev->accel.cx++; - dev->accel.cy++; + if (!dev->accel.output3) + dev->accel.cy++; break; default: break; } +skip_vector_line_write: + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.x_count++; + break; + case 0x20: + dev->accel.x_count++; + if (dev->accel.output3) + dev->accel.cy--; + break; + case 0x40: + if (dev->accel.output3) + dev->accel.cy--; + break; + case 0x60: + dev->accel.x_count--; + if (dev->accel.output3) + dev->accel.cy--; + break; + case 0x80: + dev->accel.x_count--; + break; + case 0xa0: + dev->accel.x_count--; + if (dev->accel.output3) + dev->accel.cy++; + break; + case 0xc0: + if (dev->accel.output3) + dev->accel.cy++; + break; + case 0xe0: + dev->accel.x_count++; + if (dev->accel.output3) + dev->accel.cy++; + break; + + default: + break; + } + + if (dev->accel.output) + mix_dat >>= 1; + else { + mix_dat <<= 1; + mix_dat |= 1; + } + dev->accel.sy--; } - dev->accel.x_count = 0; dev->accel.output = 0; } else { /*Bresenham Line*/ if (pixcntl == 1) { @@ -1819,6 +1914,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.output = 0; dev->accel.input = 0; dev->accel.input2 = 0; + dev->accel.input3 = 0; dev->accel.odd_in = 0; dev->accel.cx = dev->accel.cur_x; @@ -1832,6 +1928,9 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; + ibm8514_log("CMD=%d, full=%04x, curx=%d, cury=%d, pixcntl=%x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, bkgdmix=%02x.\n", + cmd, dev->accel.cmd, dev->accel.cx, dev->accel.cy, pixcntl, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.bkgd_mix); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); if (cmd == 4) @@ -1883,9 +1982,13 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sx -= 2; } } + } else { + if ((dev->accel.cmd == 0x41f0) && (frgd_mix == 3) && (bkgd_mix == 3) && + (pixcntl == 0)) + dev->accel.input3 = 1; } } - ibm8514_log("INPUT=%d.\n", dev->accel.input); + ibm8514_log("INPUT1=%d, INPUT2=%d.\n", dev->accel.input, dev->accel.input2); dev->force_busy = 1; dev->force_busy2 = 1; dev->data_available = 1; @@ -2056,7 +2159,7 @@ skip_vector_rect_write: ibm8514_log("Vectored Rectangle with normal processing (TODO).\n"); } else { /*Normal Rectangle*/ if (cpu_input) { - ibm8514_log("Normal Pixel Rectangle Fill Transfer SY=%d.\n", dev->accel.sy); + ibm8514_log("Normal Pixel Rectangle Fill Transfer SY=%d, fullcmd=%04x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, polygontype=%02x, pixcntl=%x, curx=%d, cury=%d.\n", dev->accel.sy, dev->accel.cmd, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.multifunc[0x0a] & 0x06, pixcntl, dev->accel.cx, dev->accel.cy); while (count-- && (dev->accel.sy >= 0)) { if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && @@ -2844,6 +2947,9 @@ skip_nibble_rect_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; + ibm8514_log("CMD=%d, full=%04x, curx=%d, cury=%d, destx=%d, desty=%d, pixcntl=%x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, bkgdmix=%02x.\n", + cmd, dev->accel.cmd, dev->accel.cx, dev->accel.cy, dev->accel.dx, dev->accel.dy, pixcntl, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.bkgd_mix); + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); dev->accel.fill_state = 0; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 81abadd56..ccb194146 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -915,7 +915,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.cx > 0) dev->accel.cx--; mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", - mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); } else { mach->accel.src_stepx = 1; @@ -4717,6 +4717,11 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in dev->force_busy = 1; dev->data_available = 1; } + if (dev->accel.input3) + temp = 0xffff; + + mach_log("Opcode=%d, Len=%d, port=%04x, input=%d, temp=%04x, fullcmd=%04x, crx=%d, cry=%d, frgdsel=%x, bkgdsel=%x.\n", cmd, len, port, dev->accel.input, temp, dev->accel.cmd, dev->accel.cx, dev->accel.cy, dev->accel.frgd_sel, dev->accel.bkgd_sel); + if (dev->accel.input) { ibm8514_accel_out_pixtrans(svga, port, temp & 0xff, len); if (dev->accel.odd_in) { /*WORDs on odd destination scan lengths.*/ diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 101d3ae8b..fc7499ff6 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -1924,7 +1924,9 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) { - if ((port != 0x9ee8) && (port != 0x9d48)) { + int port_pixtrans = ((port != 0x9ae8) && (port != 0x9948) && (port != 0x9ee8) && (port != 0x9d48)); + + if (port_pixtrans) { s3_log("[%04X:%08X] OUT PORTW=%04x, val=%04x, CMD=%04x, C(%d,%d), WRTMASK=%04x.\n", CS, cpu_state.pc, port, val, s3->accel.cmd, s3->accel.cur_x, s3->accel.cur_y, s3->accel.wrt_mask); s3_log(".\n"); if ((port == 0xb2e8) || (port == 0xb148)) { @@ -1946,18 +1948,30 @@ s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) } } } else { - s3->accel.short_stroke = val; - s3->accel.ssv_state = 1; + switch (port) { + case 0x9948: + case 0x9ae8: + s3_accel_out_fifo(s3, port, val); + s3_accel_out_fifo(s3, port + 1, val >> 8); + break; + case 0x9d48: + case 0x9ee8: + s3->accel.short_stroke = val; + s3->accel.ssv_state = 1; - s3->accel.cx = s3->accel.cur_x & 0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; - if (s3->accel.cmd & 0x1000) { - s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); - s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); - } else { - s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); - s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); + if (s3->accel.cmd & 0x1000) { + s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); + s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); + } else { + s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); + s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); + } + break; + default: + break; } } } @@ -2857,7 +2871,7 @@ s3_io_remove_alt(s3_t *s3) io_removehandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9948, 0x0004, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0x9d48, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -2883,6 +2897,7 @@ s3_io_remove(s3_t *s3) io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); io_removehandler(0x82ec, 0x0002, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + io_removehandler(0x02e8, 0x0002, s3_in, NULL, NULL, NULL, NULL, NULL, s3); io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -2892,7 +2907,7 @@ s3_io_remove(s3_t *s3) io_removehandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ae8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0x9ee8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -2946,9 +2961,10 @@ s3_io_set_alt(s3_t *s3) io_sethandler(0x9548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) - io_sethandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9948, 0x0004, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); else - io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9948, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); + io_sethandler(0x9d48, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_sethandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -2984,6 +3000,8 @@ s3_io_set(s3_t *s3) } io_sethandler(0x82ec, 0x0002, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x02e8, 0x0002, s3_in, NULL, NULL, NULL, NULL, NULL, s3); io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -3003,9 +3021,10 @@ s3_io_set(s3_t *s3) io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) - io_sethandler(0x9ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0004, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); else - io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -3085,6 +3104,7 @@ s3_out(uint16_t addr, uint8_t val, void *priv) else svga->write_bank = svga->read_bank = s3->bank << 14; + s3_log("Chain4=%02x.\n", svga->chain4); svga_recalctimings(svga); } else if (svga->seqaddr == 9) { svga->seqregs[9] = val & 0x80; @@ -3432,6 +3452,14 @@ s3_in(uint16_t addr, void *priv) s3_log("%04X:%08X: %03X: s3_in.\n", CS, cpu_state.pc, addr); switch (addr) { + case 0x2e8: + temp = 0; + if (svga->vc == svga->vsyncstart) { + if (s3->accel.advfunc_cntl & 0x04) + temp |= 0x02; + } + return temp; + case 0x3c1: if (svga->attraddr > 0x14) return 0xff; @@ -4114,8 +4142,10 @@ s3_recalctimings(svga_t *svga) svga->dots_per_clock >>= 1; svga->clock *= 2.0; } else { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; + if (clk_sel != 2) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } } } break; @@ -4197,6 +4227,9 @@ s3_recalctimings(svga_t *svga) if (!s3->elsa_eeprom) { if (svga->hdisp == 832) svga->hdisp -= 32; + } else { + if (clk_sel > 7) + svga->clock *= 2.0; } break; case TVP3026: /*TVP3026 RAMDAC and clock chip*/ @@ -4316,8 +4349,10 @@ s3_recalctimings(svga_t *svga) svga->dots_per_clock >>= 1; svga->clock *= 2.0; } else { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; + if (clk_sel != 2) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } } } break; @@ -4655,6 +4690,9 @@ s3_recalctimings(svga_t *svga) if (!s3->elsa_eeprom) { if (svga->hdisp == 832) svga->hdisp -= 32; + } else { + if (clk_sel > 7) + svga->clock *= 2.0; } break; case TVP3026: /*TVP3026 RAMDAC and clock chip*/ @@ -4989,7 +5027,7 @@ s3_updatemapping(s3_t *s3) /*Linear framebuffer*/ mem_mapping_disable(&svga->mapping); - switch (svga->crtc[0x58] & 3) { + switch (svga->crtc[0x58] & 0x03) { case 0: /*64k*/ s3->linear_size = 0x10000; break; @@ -4999,7 +5037,7 @@ s3_updatemapping(s3_t *s3) case 2: /*2mb*/ s3->linear_size = 0x200000; break; - case 3: /*8mb*/ + case 3: /*8mb*/ switch (s3->chip) { /* Not on video cards that don't support 4MB*/ case S3_TRIO64: case S3_TRIO64V: @@ -5098,7 +5136,7 @@ s3_accel_out(uint16_t port, uint8_t val, void *priv) s3_t *s3 = (s3_t *) priv; svga_t *svga = &s3->svga; - s3_log("%04X:%08X: OUTB FIFO=%04x, val=%02x.\n", CS, cpu_state.pc, port, val); + s3_log("%04X:%08X: OUTB FIFO=%04x, val=%02x, 8514/A functions=%x.\n", CS, cpu_state.pc, port, val, s3->enable_8514); if (port >= 0x8000) { if (!s3->enable_8514) @@ -5121,9 +5159,11 @@ s3_accel_out(uint16_t port, uint8_t val, void *priv) s3->accel.subsys_cntl = (s3->accel.subsys_cntl & 0xff) | (val << 8); s3_update_irqs(s3); break; + case 0x45e8: case 0x46e8: s3->accel.setup_md = (s3->accel.setup_md & 0xff00) | val; break; + case 0x45e9: case 0x46e9: s3->accel.setup_md = (s3->accel.setup_md & 0xff) | (val << 8); break; @@ -5151,7 +5191,7 @@ s3_accel_out_w(uint16_t port, uint16_t val, void *priv) { s3_t *s3 = (s3_t *) priv; - s3_log("%04X:%08X: OUTW FIFO=%04x, val=%04x.\n", CS, cpu_state.pc, port, val); + s3_log("%04X:%08X: OUTW FIFO=%04x, val=%04x, 8514/A functions=%x.\n", CS, cpu_state.pc, port, val, s3->enable_8514); if (!s3->enable_8514) return; @@ -5185,8 +5225,9 @@ s3_accel_in(uint16_t port, void *priv) svga_t *svga = &s3->svga; int temp; uint8_t temp2 = 0x00; + int enhanced_8bpp_modes = !!((svga->crtc[0x3a] & 0x10) && !svga->lowres); - s3_log("%04X:%08X: INB=%04x.\n", CS, cpu_state.pc, port); + s3_log("%04X:%08X: INB=%04x, 8514/A functions=%x.\n", CS, cpu_state.pc, port, s3->enable_8514); if (!s3->enable_8514) return 0xff; @@ -5194,7 +5235,7 @@ s3_accel_in(uint16_t port, void *priv) switch (port) { case 0x4148: case 0x42e8: - return s3->subsys_stat; + return s3->subsys_stat | (enhanced_8bpp_modes ? 0x80 : 0x00); case 0x4149: case 0x42e9: return s3->accel.subsys_cntl >> 8; @@ -5331,20 +5372,10 @@ s3_accel_in(uint16_t port, void *priv) if (s3->force_busy) temp |= 0x02; /*Hardware busy*/ else { - switch (s3->accel.cmd >> 13) { /*Some drivers may not set FIFO on but may still turn on FIFO empty bits!*/ + switch (s3->accel.cmd >> 13) { /*Some drivers may not set FIFO on but may still turn FIFO empty bits on!*/ case 0: - if (s3->accel.cmd & 0x100) { - if (!s3->accel.ssv_len) - temp |= 0x04; - } else - temp |= 0x04; - break; case 1: - if (s3->accel.cmd & 0x100) { - if (!s3->accel.sy) - temp |= 0x04; - } else - temp |= 0x04; + temp |= 0x04; break; case 2: case 6: @@ -6305,11 +6336,14 @@ s3_accel_in_w(uint16_t port, void *priv) uint16_t temp1 = 0x0000; uint16_t temp2 = 0x0000; const uint16_t *vram_w = (uint16_t *) svga->vram; + int port_pixtrans = ((port != 0x9ae8) && (port != 0x9948) && (port != 0x9ee8) && (port != 0x9d48)); + + s3_log("%04X:%08X: INW=%04x, 8514/A functions=%x.\n", CS, cpu_state.pc, port, s3->enable_8514); if (!s3->enable_8514) return 0xffff; - if (port != 0x9ee8 && port != 0x9d48) { + if (port_pixtrans) { if (s3_cpu_dest(s3)) { READ_PIXTRANS_WORD @@ -6377,10 +6411,8 @@ s3_accel_in_w(uint16_t port, void *priv) } } } else { - if (s3_enable_fifo(s3)) - s3_wait_fifo_idle(s3); - - temp = s3->accel.short_stroke; + temp = s3_accel_in(port, s3); + temp |= (s3_accel_in(port + 1, s3) << 8); } return temp; @@ -6451,6 +6483,8 @@ s3_accel_write(uint32_t addr, uint8_t val, void *priv) const svga_t *svga = &s3->svga; uint32_t addr_mask = (svga->crtc[0x53] & 0x08) ? 0x1ffff : 0xffff; + s3_log("%04X:%08X: WRITEB, 8514/A functions=%x.\n", CS, cpu_state.pc, s3->enable_8514); + if (!s3->enable_8514) return; @@ -6494,6 +6528,8 @@ s3_accel_write_w(uint32_t addr, uint16_t val, void *priv) const svga_t *svga = &s3->svga; uint32_t addr_mask = (svga->crtc[0x53] & 0x08) ? 0x1ffff : 0xffff; + s3_log("%04X:%08X: WRITEW, 8514/A functions=%x.\n", CS, cpu_state.pc, s3->enable_8514); + if (!s3->enable_8514) return; @@ -6528,6 +6564,8 @@ s3_accel_write_l(uint32_t addr, uint32_t val, void *priv) svga_t *svga = &s3->svga; uint32_t addr_mask = (svga->crtc[0x53] & 0x08) ? 0x1ffff : 0xffff; + s3_log("%04X:%08X: WRITEL, 8514/A functions=%x.\n", CS, cpu_state.pc, s3->enable_8514); + if (!s3->enable_8514) return;