From f0d93aa00cf4bdce98f7d8518ae1d8623c71b025 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 20 Aug 2025 18:07:15 +0200 Subject: [PATCH] Video clock changes of the day (August 20th, 2025) Make the clocks of the ATI cards (pre-Mach64) more sane and precise (especially the Mach8/32). --- src/include/86box/vid_8514a.h | 1 + src/include/86box/vid_svga.h | 9 +- src/video/clockgen/vid_clockgen_ics2494.c | 341 +++++++++++++++---- src/video/vid_ati18800.c | 2 +- src/video/vid_ati28800.c | 4 +- src/video/vid_ati_mach8.c | 380 ++++++++++++++++------ 6 files changed, 569 insertions(+), 168 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index e15dadfca..4c534c47b 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -278,6 +278,7 @@ typedef struct ibm8514_t { int _8514on; int _8514crt; PALETTE _8514pal; + uint8_t ven_clock; latch8514_t latch; diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index ea34827c3..02c2e0f17 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -498,9 +498,12 @@ extern const device_t bt485a_ramdac_device; extern const device_t gendac_ramdac_device; extern const device_t ibm_rgb528_ramdac_device; extern const device_t ics2494an_305_device; -extern const device_t ati18810_device; -extern const device_t ati18811_0_device; -extern const device_t ati18811_1_device; +extern const device_t ati18810_28800_device; +extern const device_t ati18811_0_28800_device; +extern const device_t ati18811_1_28800_device; +extern const device_t ati18810_mach32_device; +extern const device_t ati18811_0_mach32_device; +extern const device_t ati18811_1_mach32_device; extern const device_t ics2595_device; extern const device_t icd2061_device; extern const device_t ics9161_device; diff --git a/src/video/clockgen/vid_clockgen_ics2494.c b/src/video/clockgen/vid_clockgen_ics2494.c index 350a490cc..33a74fe62 100644 --- a/src/video/clockgen/vid_clockgen_ics2494.c +++ b/src/video/clockgen/vid_clockgen_ics2494.c @@ -48,6 +48,120 @@ ics2494_log(const char *fmt, ...) # define ics2494_log(fmt, ...) #endif +/* Two consecutive byte-writes are NOT allowed. Furthermore an index + * written to 0x01CE is only usable ONCE! Note also that the setting of ATI + * extended registers (especially those with clock selection bits) should be + * bracketed by a sequencer reset. + * + * Boards prior to V5 use 4 crystals. Boards V5 and later use a clock + * generator chip. V3 and V4 boards differ when it comes to choosing clock + * frequencies. + * + * VGA Wonder V3/V4 Board Clock Frequencies + * R E G I S T E R S + * 1CE(*) 3C2 3C2 Frequency + * B2h/BEh + * Bit 6/4 Bit 3 Bit 2 (MHz) + * ------- ------- ------- ------- + * 0 0 0 50.175 + * 0 0 1 56.644 + * 0 1 0 Spare 1 + * 0 1 1 44.900 + * 1 0 0 44.900 + * 1 0 1 50.175 + * 1 1 0 Spare 2 + * 1 1 1 36.000 + * + * (*): V3 uses index B2h, bit 6; V4 uses index BEh, bit 4 + * + * V5, PLUS, XL and XL24 usually have an ATI 18810 clock generator chip, but + * some have an ATI 18811-0, and it's quite conceivable that some exist with + * ATI 18811-1's or ATI 18811-2's. Mach32 boards are known to use any one of + * these clock generators. The possibilities for Mach64 boards also include + * two different flavours of the newer 18818 chips. I have yet to figure out + * how BIOS initialization sets up the board for a particular set of + * frequencies. Mach32 and Mach64 boards also use a different dot clock + * ordering. ATI says there is no reliable way for the driver to determine + * which clock generator is on the board (their BIOS's are tailored to the + * board). + * + * VGA Wonder V5/PLUS/XL/XL24 Board Clock Frequencies + * R E G I S T E R S + * 1CE 1CE 3C2 3C2 Frequency + * B9h BEh (MHz) 18811-0 18811-1 + * Bit 1 Bit 4 Bit 3 Bit 2 18810 18812-0 18811-2 18818-? 18818-? + * ------- ------- ------- ------- ------- ------- ------- ------- ------- + * 0 0 0 0 30.240 30.240 135.000 (*3) (*3) + * 0 0 0 1 32.000 32.000 32.000 110.000 110.000 + * 0 0 1 0 37.500 110.000 110.000 126.000 126.000 + * 0 0 1 1 39.000 80.000 80.000 135.000 135.000 + * 0 1 0 0 42.954 42.954 100.000 50.350 25.175 + * 0 1 0 1 48.771 48.771 126.000 56.644 28.322 + * 0 1 1 0 (*1) 92.400 92.400 63.000 31.500 + * 0 1 1 1 36.000 36.000 36.000 72.000 36.000 + * 1 0 0 0 40.000 39.910 39.910 (*3) (*3) + * 1 0 0 1 56.644 44.900 44.900 80.000 80.000 + * 1 0 1 0 75.000 75.000 75.000 75.000 75.000 + * 1 0 1 1 65.000 65.000 65.000 65.000 65.000 + * 1 1 0 0 50.350 50.350 50.350 40.000 40.000 + * 1 1 0 1 56.640 56.640 56.640 44.900 44.900 + * 1 1 1 0 (*2) (*3) (*3) 49.500 49.500 + * 1 1 1 1 44.900 44.900 44.900 50.000 50.000 + * + * (*1) External 0 (supposedly 16.657 Mhz) + * (*2) External 1 (supposedly 28.322 MHz) + * (*3) This setting doesn't seem to generate anything + * + * Mach32 and Mach64 Board Clock Frequencies + * R E G I S T E R S + * 1CE 1CE 3C2 3C2 Frequency + * B9h BEh (MHz) 18811-0 18811-1 + * Bit 1 Bit 4 Bit 3 Bit 2 18810 18812-0 18811-2 18818-? 18818-? + * ------- ------- ------- ------- ------- ------- ------- ------- ------- + * 0 0 0 0 42.954 42.954 100.000 50.350 25.175 + * 0 0 0 1 48.771 48.771 126.000 56.644 28.322 + * 0 0 1 0 (*1) 92.400 92.400 63.000 31.500 + * 0 0 1 1 36.000 36.000 36.000 72.000 36.000 + * 0 1 0 0 30.240 30.240 135.000 (*3) (*3) + * 0 1 0 1 32.000 32.000 32.000 110.000 110.000 + * 0 1 1 0 37.500 110.000 110.000 126.000 126.000 + * 0 1 1 1 39.000 80.000 80.000 135.000 135.000 + * 1 0 0 0 50.350 50.350 50.350 40.000 40.000 + * 1 0 0 1 56.640 56.640 56.640 44.900 44.900 + * 1 0 1 0 (*2) (*3) (*3) 49.500 49.500 + * 1 0 1 1 44.900 44.900 44.900 50.000 50.000 + * 1 1 0 0 40.000 39.910 39.910 (*3) (*3) + * 1 1 0 1 56.644 44.900 44.900 80.000 80.000 + * 1 1 1 0 75.000 75.000 75.000 75.000 75.000 + * 1 1 1 1 65.000 65.000 65.000 65.000 65.000 + * + * (*1) External 0 (supposedly 16.657 Mhz) + * (*2) External 1 (supposedly 28.322 MHz) + * (*3) This setting doesn't seem to generate anything + * + * Note that, to reduce confusion, this driver masks out the different clock + * ordering. + * + * For all boards, these frequencies can be divided by 1, 2, 3 or 4. + * + * Register 1CE, index B8h + * Bit 7 Bit 6 + * ------- ------- + * 0 0 Divide by 1 + * 0 1 Divide by 2 + * 1 0 Divide by 3 + * 1 1 Divide by 4 + * + * There is some question as to whether or not bit 1 of index 0xB9 can + * be used for clock selection on a V4 board. This driver makes it + * available only if the "undocumented_clocks" option (itself + * undocumented :-)) is specified in XF86Config. + * + * Also it appears that bit 0 of index 0xB9 can also be used for clock + * selection on some boards. It is also only available under XF86Config + * option "undocumented_clocks". + */ + float ics2494_getclock(int clock, void *priv) { @@ -56,7 +170,6 @@ ics2494_getclock(int clock, void *priv) if (clock > 15) clock = 15; - ics2494_log("Clock=%d, freq=%f.\n", clock, ics2494->freq[clock]); return ics2494->freq[clock]; } @@ -67,62 +180,116 @@ ics2494_init(const device_t *info) memset(ics2494, 0, sizeof(ics2494_t)); switch (info->local) { - case 10: + case 0: /* ATI 18810 for ATI 28800 */ - ics2494->freq[0x0] = 42954000.0; - ics2494->freq[0x1] = 48771000.0; - ics2494->freq[0x2] = 0.0; - ics2494->freq[0x3] = 36000000.0; - ics2494->freq[0x4] = 50350000.0; - ics2494->freq[0x5] = 56640000.0; - ics2494->freq[0x6] = 0.0; - ics2494->freq[0x7] = 44900000.0; - ics2494->freq[0x8] = 30240000.0; - ics2494->freq[0x9] = 32000000.0; - ics2494->freq[0xa] = 37500000.0; - ics2494->freq[0xb] = 39000000.0; - ics2494->freq[0xc] = 40000000.0; - ics2494->freq[0xd] = 56644000.0; - ics2494->freq[0xe] = 75000000.0; - ics2494->freq[0xf] = 65000000.0; + ics2494->freq[0] = 30240000.0; + ics2494->freq[1] = 32000000.0; + ics2494->freq[2] = 37500000.0; + ics2494->freq[3] = 39000000.0; + ics2494->freq[4] = 42954000.0; + ics2494->freq[5] = 48771000.0; + ics2494->freq[6] = 0.0; + ics2494->freq[7] = 36000000.0; + ics2494->freq[8] = 40000000.0; + ics2494->freq[9] = 56644000.0; + ics2494->freq[10] = 75000000.0; + ics2494->freq[11] = 65000000.0; + ics2494->freq[12] = 50350000.0; + ics2494->freq[13] = 56640000.0; + ics2494->freq[14] = 0.0; + ics2494->freq[15] = 44900000.0; break; - case 110: - /* ATI 18811-0 for ATI Mach32 */ - ics2494->freq[0x0] = 42954000.0; - ics2494->freq[0x1] = 48771000.0; - ics2494->freq[0x2] = 92400000.0; - ics2494->freq[0x3] = 36000000.0; - ics2494->freq[0x4] = 50350000.0; - ics2494->freq[0x5] = 56640000.0; - ics2494->freq[0x6] = 0.0; - ics2494->freq[0x7] = 44900000.0; - ics2494->freq[0x8] = 30240000.0; - ics2494->freq[0x9] = 32000000.0; - ics2494->freq[0xa] = 110000000.0; - ics2494->freq[0xb] = 80000000.0; - ics2494->freq[0xc] = 39910000.0; - ics2494->freq[0xd] = 44900000.0; - ics2494->freq[0xe] = 75000000.0; - ics2494->freq[0xf] = 65000000.0; + case 1: + /* ATI 18811-0/ATI 18812-0 for ATI 28800 */ + ics2494->freq[0] = 42950000.0; + ics2494->freq[1] = 48770000.0; + ics2494->freq[2] = 92400000.0; + ics2494->freq[3] = 36000000.0; + ics2494->freq[4] = 50350000.0; + ics2494->freq[5] = 56640000.0; + ics2494->freq[7] = 44900000.0; + ics2494->freq[8] = 30240000.0; + ics2494->freq[9] = 32000000.0; + ics2494->freq[10] = 110000000.0; + ics2494->freq[11] = 80000000.0; + ics2494->freq[12] = 39910000.0; + ics2494->freq[13] = 44900000.0; + ics2494->freq[14] = 75000000.0; + ics2494->freq[15] = 65000000.0; break; - case 111: - /* ATI 18811-1 for ATI Mach32 MCA */ - ics2494->freq[0x0] = 100000000.0; - ics2494->freq[0x1] = 126000000.0; - ics2494->freq[0x2] = 92400000.0; - ics2494->freq[0x3] = 36000000.0; - ics2494->freq[0x4] = 50350000.0; - ics2494->freq[0x5] = 56640000.0; - ics2494->freq[0x6] = 0.0; - ics2494->freq[0x7] = 44900000.0; - ics2494->freq[0x8] = 135000000.0; - ics2494->freq[0x9] = 32000000.0; - ics2494->freq[0xa] = 110000000.0; - ics2494->freq[0xb] = 80000000.0; - ics2494->freq[0xc] = 39910000.0; - ics2494->freq[0xd] = 44900000.0; - ics2494->freq[0xe] = 75000000.0; - ics2494->freq[0xf] = 65000000.0; + case 2: + /* ATI 18811-1/ATI 18811-2 for ATI 28800 */ + ics2494->freq[0] = 100000000.0; + ics2494->freq[1] = 126000000.0; + ics2494->freq[2] = 92400000.0; + ics2494->freq[3] = 36000000.0; + ics2494->freq[4] = 50350000.0; + ics2494->freq[5] = 56640000.0; + ics2494->freq[7] = 44900000.0; + ics2494->freq[8] = 135000000.0; + ics2494->freq[9] = 32000000.0; + ics2494->freq[10] = 110000000.0; + ics2494->freq[11] = 80000000.0; + ics2494->freq[12] = 39910000.0; + ics2494->freq[13] = 44900000.0; + ics2494->freq[14] = 75000000.0; + ics2494->freq[15] = 65000000.0; + break; + case 100: + /* ATI 18810 for ATI Mach32 */ + ics2494->freq[0] = 42954000.0; + ics2494->freq[1] = 48771000.0; + ics2494->freq[2] = 0.0; + ics2494->freq[3] = 36000000.0; + ics2494->freq[4] = 30240000.0; + ics2494->freq[5] = 32000000.0; + ics2494->freq[6] = 37500000.0; + ics2494->freq[7] = 39000000.0; + ics2494->freq[8] = 50350000.0; + ics2494->freq[9] = 56640000.0; + ics2494->freq[10] = 0.0; + ics2494->freq[11] = 44900000.0; + ics2494->freq[12] = 40000000.0; + ics2494->freq[13] = 56644000.0; + ics2494->freq[14] = 75000000.0; + ics2494->freq[15] = 65000000.0; + break; + case 101: + /* ATI 18811-0/ATI 18812-0 for ATI Mach32 */ + ics2494->freq[0] = 42954000.0; + ics2494->freq[1] = 48771000.0; + ics2494->freq[2] = 92400000.0; + ics2494->freq[3] = 36000000.0; + ics2494->freq[4] = 30240000.0; + ics2494->freq[5] = 32000000.0; + ics2494->freq[6] = 110000000.0; + ics2494->freq[7] = 80000000.0; + ics2494->freq[8] = 50350000.0; + ics2494->freq[9] = 56640000.0; + ics2494->freq[10] = 0.0; + ics2494->freq[11] = 44900000.0; + ics2494->freq[12] = 39910000.0; + ics2494->freq[13] = 44900000.0; + ics2494->freq[14] = 75000000.0; + ics2494->freq[15] = 65000000.0; + break; + case 102: + /* ATI 18811-1/ATI 18811-2 for ATI Mach32 */ + ics2494->freq[0] = 100000000.0; + ics2494->freq[1] = 126000000.0; + ics2494->freq[2] = 92400000.0; + ics2494->freq[3] = 36000000.0; + ics2494->freq[4] = 50350000.0; + ics2494->freq[5] = 56640000.0; + ics2494->freq[7] = 44900000.0; + ics2494->freq[8] = 135000000.0; + ics2494->freq[9] = 32000000.0; + ics2494->freq[10] = 110000000.0; + ics2494->freq[11] = 80000000.0; + ics2494->freq[12] = 39910000.0; + ics2494->freq[13] = 44900000.0; + ics2494->freq[14] = 75000000.0; + ics2494->freq[15] = 65000000.0; break; case 305: /* ICS2494A(N)-205 for S3 86C924 */ @@ -174,11 +341,11 @@ const device_t ics2494an_305_device = { .config = NULL }; -const device_t ati18810_device = { - .name = "ATI 18810 Clock Generator", - .internal_name = "ati18810", +const device_t ati18810_28800_device = { + .name = "ATI 18810 (ATI 28800) Clock Generator", + .internal_name = "ati18810_28800", .flags = 0, - .local = 10, + .local = 0, .init = ics2494_init, .close = ics2494_close, .reset = NULL, @@ -188,11 +355,11 @@ const device_t ati18810_device = { .config = NULL }; -const device_t ati18811_0_device = { - .name = "ATI 18811-0 Clock Generator", - .internal_name = "ati18811_0", +const device_t ati18811_0_28800_device = { + .name = "ATI 18811-0 (ATI 28800) Clock Generator", + .internal_name = "ati18811_0_28800", .flags = 0, - .local = 110, + .local = 1, .init = ics2494_init, .close = ics2494_close, .reset = NULL, @@ -202,11 +369,53 @@ const device_t ati18811_0_device = { .config = NULL }; -const device_t ati18811_1_device = { - .name = "ATI 18811-1 Clock Generator", - .internal_name = "ati18811_1", +const device_t ati18811_1_28800_device = { + .name = "ATI 18811-1 (ATI 28800) Clock Generator", + .internal_name = "ati18811_1_28800", .flags = 0, - .local = 111, + .local = 2, + .init = ics2494_init, + .close = ics2494_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ati18810_mach32_device = { + .name = "ATI 18810 (ATI Mach32) Clock Generator", + .internal_name = "ati18810_mach32", + .flags = 0, + .local = 100, + .init = ics2494_init, + .close = ics2494_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ati18811_0_mach32_device = { + .name = "ATI 18811-0 (ATI Mach32) Clock Generator", + .internal_name = "ati18811_0_mach32", + .flags = 0, + .local = 101, + .init = ics2494_init, + .close = ics2494_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ati18811_1_mach32_device = { + .name = "ATI 18811-1 (ATI Mach32) Clock Generator", + .internal_name = "ati18811_1_mach32", + .flags = 0, + .local = 102, .init = ics2494_init, .close = ics2494_close, .reset = NULL, diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 9c87746c6..11124a35b 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -269,7 +269,7 @@ ati18800_init(const device_t *info) ati18800_in, ati18800_out, NULL, NULL); - ati18800->svga.clock_gen = device_add(&ati18810_device); + ati18800->svga.clock_gen = device_add(&ati18810_28800_device); ati18800->svga.getclock = ics2494_getclock; io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 284abe78c..69924e53d 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -568,7 +568,7 @@ ati28800k_init(const device_t *info) ati28800k_in, ati28800k_out, NULL, NULL); - ati28800->svga.clock_gen = device_add(&ati18810_device); + ati28800->svga.clock_gen = device_add(&ati18810_28800_device); ati28800->svga.getclock = ics2494_getclock; io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); @@ -646,7 +646,7 @@ ati28800_init(const device_t *info) ati28800_in, ati28800_out, NULL, NULL); - ati28800->svga.clock_gen = device_add(&ati18810_device); + ati28800->svga.clock_gen = device_add(&ati18810_28800_device); ati28800->svga.getclock = ics2494_getclock; io_sethandler(0x01ce, 2, diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index c34ec5514..63b5d02ca 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2431,6 +2431,11 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga_out(addr, val, svga); return; + case 0x3C2: + if (mach->regs[0xb8] & 0x08) + return; + break; + case 0x3C6: case 0x3C7: case 0x3C8: @@ -2465,10 +2470,56 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x3D5: if (svga->crtcreg & 0x20) return; - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80) && !(mach->regs[0xb4] & 0x80)) + if ((svga->crtcreg < 7) && ((svga->crtc[0x11] & 0x80) || (mach->regs[0xb4] & 0x40)) && !(mach->regs[0xb4] & 0x80)) return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80) && !(mach->regs[0xb4] & 0x80)) + if ((svga->crtcreg == 7) && ((svga->crtc[0x11] & 0x80) || (mach->regs[0xb4] & 0x40)) && !(mach->regs[0xb4] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (mach->regs[0xb8] & 0x04) { + if ((svga->crtcreg < 0x0a) && (svga->crtcreg > 0x0d)) + return; + } + if (mach->regs[0xb4] & 0x04) { + if (svga->crtcreg == 9) { + if (val & 0x8f) + return; + } + } + if (mach->regs[0xb4] & 0x08) { + if (svga->crtcreg == 6) + return; + if (svga->crtcreg == 7) { + if (val & 0xaf) + return; + } + if (svga->crtcreg == 9) { + if (val & 0x20) + return; + } + if (svga->crtcreg == 0x11) { + if (val & 0x0f) + return; + } + if ((svga->crtcreg == 0x10) || + (svga->crtcreg == 0x12) || + (svga->crtcreg == 0x15) || + (svga->crtcreg == 0x16)) + return; + } + if (mach->regs[0xb4] & 0x10) { + if ((svga->crtcreg == 0x0a) || + (svga->crtcreg == 0x0b)) + return; + } + if (mach->regs[0xb4] & 0x20) { + if (svga->crtcreg == 8) { + if (val & 0x7f) + return; + } + if (svga->crtcreg == 0x14) { + if (val & 0x1f) + return; + } + } old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; @@ -2726,28 +2777,82 @@ mach_set_resolution(mach_t *mach, svga_t *svga) dev->v_syncstart = 0x0601; mach->accel.clock_sel_mode = 0; - mach_log("ATI Mode: set=%02x, dispcntl=%02x, h_total=%d, hdisp=%d, vdisp=%d, v_total=%04x, v_syncstart=%04x, hsync_start=%d, hsync_width=%d, clocksel=%02x, advancedcntl=%02x.\n", mach->shadow_set & 0x03, dev->disp_cntl, dev->h_total, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart, dev->hsync_start, dev->hsync_width, mach->accel.clock_sel & 0xff, dev->accel.advfunc_cntl & 0x05); if ((dev->disp_cntl_2 >> 5) == 1) { /*Enable the 8514/A subsystem and set modes according to the shadow sets if needed.*/ switch (mach->shadow_set & 0x03) { case 0x01: if (!(dev->accel.advfunc_cntl & 0x04)) { - dev->h_total = 0x64; dev->hdisp = 640; dev->vdisp = 480; - dev->v_total = 0x0419; - dev->v_syncstart = 0x03d7; - mach->accel.clock_sel_mode = 0x50; + mach_log("Mach: EEPROM 640x480: %04x.\n", mach->eeprom.data[7]); + switch (mach->eeprom.data[7] & 0xff) { + case 0x00: /*640x480 60Hz Non-interlaced*/ + default: + dev->h_total = 0x64; + dev->v_total = 0x0419; + dev->v_syncstart = 0x03d7; + mach->accel.clock_sel_mode = 0x50; + break; + case 0x01: /*640x480 72Hz Non-interlaced*/ + dev->h_total = 0x6a; + dev->v_total = 0x040c; + dev->v_syncstart = 0x03d1; + mach->accel.clock_sel_mode = 0x24; + break; + case 0x03: /*640x480 72Hz Non-interlaced Alt*/ + dev->h_total = 0x71; + dev->v_total = 0x04ca; + dev->v_syncstart = 0x0422; + mach->accel.clock_sel_mode = 0x6c; + break; + } } break; case 0x02: if (dev->accel.advfunc_cntl & 0x04) { - dev->h_total = 0x9e; dev->hdisp = 1024; dev->vdisp = 768; - dev->v_total = 0x0669; - dev->v_syncstart = 0x0601; - mach->accel.clock_sel_mode = 0x1c; + mach_log("Mach: EEPROM 1024x768: %04x.\n", mach->eeprom.data[9]); + switch (mach->eeprom.data[9] & 0xff) { + case 0x00: /*1024x768 76Hz Non-interlaced*/ + dev->h_total = 0xa3; + dev->v_total = 0x064b; + dev->v_syncstart = 0x060c; + mach->accel.clock_sel_mode = 0x2c; + break; + + case 0x01: /*1024x768 87Hz Interlaced*/ + default: + dev->h_total = 0x9e; + dev->v_total = 0x0669; + dev->v_syncstart = 0x0601; + mach->accel.clock_sel_mode = 0x1c; + break; + case 0x02: /*1024x768 60Hz Non-interlaced*/ + dev->h_total = 0xa8; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x3c; + break; + case 0x04: /*1024x768 70Hz Non-interlaced*/ + dev->h_total = 0xa6; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x38; + break; + case 0x08: /*1024x768 72Hz Non-interlaced*/ + dev->h_total = 0xa1; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x38; + break; + case 0x82: /*1024x768 66Hz Non-interlaced*/ + dev->h_total = 0xac; + dev->v_total = 0x065c; + dev->v_syncstart = 0x060b; + mach->accel.clock_sel_mode = 0x38; + break; + } } break; @@ -2758,22 +2863,76 @@ mach_set_resolution(mach_t *mach, svga_t *svga) } else if ((dev->disp_cntl_2 >> 5) == 2) { /*Reset 8514/A to defaults if needed.*/ if (dev->accel.advfunc_cntl & 0x04) { if (dev->hdisp == 640) { - dev->h_total = 0x9e; dev->hdisp = 1024; dev->vdisp = 768; - dev->v_total = 0x0669; - dev->v_syncstart = 0x0601; - mach->accel.clock_sel_mode = 0x1c; + mach_log("Mach Reset: EEPROM 1024x768: %04x.\n", mach->eeprom.data[9]); + switch (mach->eeprom.data[9] & 0xff) { + case 0x00: /*1024x768 76Hz Non-interlaced*/ + dev->h_total = 0xa3; + dev->v_total = 0x064b; + dev->v_syncstart = 0x060c; + mach->accel.clock_sel_mode = 0x2c; + break; + case 0x01: /*1024x768 87Hz Interlaced*/ + default: + dev->h_total = 0x9e; + dev->v_total = 0x0669; + dev->v_syncstart = 0x0601; + mach->accel.clock_sel_mode = 0x1c; + break; + case 0x02: /*1024x768 60Hz Non-interlaced*/ + dev->h_total = 0xa8; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x3c; + break; + case 0x04: /*1024x768 70Hz Non-interlaced*/ + dev->h_total = 0xa6; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x38; + break; + case 0x08: /*1024x768 72Hz Non-interlaced*/ + dev->h_total = 0xa1; + dev->v_total = 0x064a; + dev->v_syncstart = 0x0603; + mach->accel.clock_sel_mode = 0x38; + break; + case 0x82: /*1024x768 66Hz Non-interlaced*/ + dev->h_total = 0xac; + dev->v_total = 0x065c; + dev->v_syncstart = 0x060b; + mach->accel.clock_sel_mode = 0x38; + break; + } svga_recalctimings(svga); } } else { if (dev->hdisp == 1024) { - dev->h_total = 0x64; dev->hdisp = 640; dev->vdisp = 480; - dev->v_total = 0x0419; - dev->v_syncstart = 0x03d7; - mach->accel.clock_sel_mode = 0x50; + mach_log("Mach Reset: EEPROM 640x480: %04x.\n", mach->eeprom.data[7]); + switch (mach->eeprom.data[7] & 0xff) { + case 0x00: /*640x480 60Hz Non-interlaced*/ + default: + dev->h_total = 0x64; + dev->v_total = 0x0419; + dev->v_syncstart = 0x03d7; + mach->accel.clock_sel_mode = 0x50; + break; + case 0x01: /*640x480 72Hz Non-interlaced*/ + dev->h_total = 0x6a; + dev->v_total = 0x040c; + dev->v_syncstart = 0x03d1; + mach->accel.clock_sel_mode = 0x24; + break; + case 0x03: /*640x480 72Hz Non-interlaced Alt*/ + dev->h_total = 0x71; + dev->v_total = 0x04ca; + dev->v_syncstart = 0x0422; + mach->accel.clock_sel_mode = 0x6c; + break; + } svga_recalctimings(svga); } } @@ -2797,14 +2956,29 @@ ati8514_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2; - if (mach->accel.clock_sel_mode == 0x1c) { - dev->interlace = 1; - _8514_modes = 1; - } else if (mach->accel.clock_sel_mode == 0x50) { - dev->interlace = 0; - _8514_modes = 2; + switch (mach->accel.clock_sel_mode) { + case 0x1c: + dev->interlace = 1; + _8514_modes = 1; + break; + case 0x24: + case 0x2c: + case 0x38: + case 0x3c: + case 0x50: + case 0x6c: + dev->interlace = 0; + _8514_modes = 2; + break; + default: + break; } + if (_8514_modes) + dev->ven_clock = mach->accel.clock_sel_mode & 0x7c; + else + dev->ven_clock = mach->accel.clock_sel & 0x7c; + dev->accel.ge_offset -= mach->accel.crt_offset; mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", @@ -2826,22 +3000,14 @@ ati8514_recalctimings(svga_t *svga) else if (dev->h_disp == 640) dev->dispend = 480; - dev->h_disp_time = dev->hdisp >> 3; + dev->h_disp_time = dev->h_disp >> 3; - if (_8514_modes) { - svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((mach->accel.clock_sel_mode >> 2) & 0x0f, svga->clock_gen8514) / 2; - if (mach->accel.clock_sel_mode & 0x40) - svga->clock_8514 *= 2; - } else { - svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen8514) / 2; - if (mach->accel.clock_sel & 0x40) - svga->clock_8514 *= 2; - } + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((dev->ven_clock >> 2) & 0x0f, svga->clock_gen8514) / 2.0; + if ((((dev->ven_clock >> 2) & 0x0f) == 0x09) && (dev->h_total == 0x6b)) + svga->clock_8514 /= 2.0; - if (dev->interlace) { + if (dev->interlace) dev->dispend >>= 1; - svga->clock_8514 /= 2; - } mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, @@ -2864,13 +3030,24 @@ mach_recalctimings(svga_t *svga) { mach_t *mach = (mach_t *) svga->priv; ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - int clock_sel; + int clock_sel = 0x00; int _8514_modes = 0; if (mach->regs[0xad] & 0x08) svga->hblankstart = ((mach->regs[0x0d] >> 2) << 8) + svga->crtc[2]; - clock_sel = ((svga->miscout >> 2) & 3) | ((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1); + if (svga->miscout & 0x04) + clock_sel |= 0x01; + if (svga->miscout & 0x08) + clock_sel |= 0x02; + if (mach->regs[0xb9] & 0x02) + clock_sel |= 0x04; + if (mach->regs[0xbe] & 0x10) + clock_sel |= 0x08; + + svga->interlace = !!(mach->regs[0xbe] & 0x02); + if (svga->interlace) + svga->dispend >>= 1; if (ATI_MACH32) { if (mach->regs[0xad] & 0x04) @@ -2911,11 +3088,8 @@ mach_recalctimings(svga_t *svga) svga->ati_4color = 0; } - svga->interlace = !!(mach->regs[0xbe] & 0x02); - if (svga->interlace) - svga->dispend >>= 1; - mach_log("ON=%d, override=%d, gelo=%04x, gehi=%04x, crtlo=%04x, crthi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, mach->accel.crt_offset_lo, mach->accel.crt_offset_hi, svga->hdisp); + if (dev->on) { dev->memaddr_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ dev->interlace = !!(dev->disp_cntl & 0x10); @@ -2925,14 +3099,41 @@ mach_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)); - if (mach->accel.clock_sel_mode == 0x1c) { - dev->interlace = 1; - _8514_modes = 1; - } else if (mach->accel.clock_sel_mode == 0x50) { - dev->interlace = 0; - _8514_modes = 2; + switch (mach->accel.clock_sel_mode) { + case 0x1c: + dev->interlace = 1; + _8514_modes = 1; + break; + case 0x24: + case 0x2c: + case 0x38: + case 0x3c: + case 0x50: + case 0x6c: + dev->interlace = 0; + _8514_modes = 2; + break; + default: + break; } + if (_8514_modes) + dev->ven_clock = mach->accel.clock_sel_mode & 0x7c; + else + dev->ven_clock = mach->accel.clock_sel & 0x7c; + + if (ATI_MACH32) { + mach_log("Mach32: Clock=%02x, double=%02x, h_total=%02x.\n", (dev->ven_clock >> 2) & 0x0f, dev->ven_clock & 0x40, dev->h_total); + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((dev->ven_clock >> 2) & 0x0f, svga->clock_gen8514) / 2.0; + } else { + mach_log("Mach8: Clock=%02x, double=%02x, h_total=%02x, selmode=%02x.\n", (dev->ven_clock >> 2) & 0x0f, dev->ven_clock & 0x40, dev->h_total, mach->accel.clock_sel_mode); + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((dev->ven_clock >> 2) & 0x0f, svga->clock_gen8514) / 2.0; + if ((((dev->ven_clock >> 2) & 0x0f) == 0x09) && (dev->h_total == 0x6b)) + svga->clock_8514 /= 2.0; + } + if (dev->ven_clock & 0x40) + svga->clock_8514 *= 2.0; + if (dev->bpp) { dev->accel.ge_offset <<= 1; mach->accel.crt_offset <<= 1; @@ -2956,31 +3157,19 @@ mach_recalctimings(svga_t *svga) dev->h_disp = dev->hdisp; dev->dispend = dev->vdisp; if (dev->dispend == 959) { /*FIXME: vertical resolution mess on EEPROM tests on Mach8*/ - dev->dispend >>= 1; dev->dispend++; + dev->dispend >>= 1; } else if (dev->dispend == 600) dev->h_disp = 800; else if (dev->h_disp == 640) dev->dispend = 480; - dev->h_disp_time = dev->hdisp >> 3; + dev->h_disp_time = dev->h_disp >> 3; - if (_8514_modes) { - svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel_mode >> 2) & 0x0f, svga->clock_gen) / 2; - if (mach->accel.clock_sel_mode & 0x40) - svga->clock_8514 *= 2; - } else { - svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen) / 2; - if (mach->accel.clock_sel & 0x40) - svga->clock_8514 *= 2; - } + mach_log("8514/A modes=%d, clocksel=%02x, clkselmode=%02x, divide reg ibm=%02x, divide reg vga=%02x, vgainterlace=%x, interlace=%x, htotal=%02x.\n", _8514_modes, mach->accel.clock_sel & 0xfe, mach->accel.clock_sel_mode & 0xfe, mach->accel.clock_sel & 0x40, mach->regs[0xb8] & 0x40, svga->interlace, dev->interlace, dev->htotal); - mach_log("8514/A clock sel=%x, divide reg ibm=%02x, divide reg vga=%02x, vgainterlace=%x, interlace=%x.\n", clock_sel, mach->accel.clock_sel & 0x40, mach->regs[0xb8] & 0xc0, svga->interlace, dev->interlace); - - if (dev->interlace) { + if (dev->interlace) dev->dispend >>= 1; - svga->clock_8514 /= 2; - } if (ATI_MACH32) { switch ((mach->shadow_set >> 8) & 0x03) { @@ -3104,33 +3293,30 @@ mach_recalctimings(svga_t *svga) } } else { dev->mode = VGA_MODE; - if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { + if (!svga->scrblank && svga->attr_palette_enable) { mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d.\n", svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on); - svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); - mach_log("VGA clock sel=%x, divide reg=%02x.\n", clock_sel, mach->regs[0xb8] & 0xc0); - if (svga->interlace) - svga->clock /= 2; + if (ATI_MACH32) + svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); + else + svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel ^ 0x08, svga->clock_gen); - if (ATI_MACH32) { - if (mach->regs[0xb8] & 0x40) - svga->clock *= 2; - } else { - switch (mach->regs[0xb8] & 0xc0) { - case 0x40: - svga->clock *= 2; - break; - case 0x80: - svga->clock *= 3; - break; - case 0xc0: - svga->clock *= 4; - break; - - default: - break; - } + switch ((mach->regs[0xb8] >> 6) & 3) { + case 0: + default: + break; + case 1: + svga->clock *= 2.0; + break; + case 2: + svga->clock *= 3.0; + break; + case 3: + svga->clock *= 4.0; + break; } + + mach_log("VGA clock sel=%02x, divide reg=%02x, miscout bits2-3=%x, machregbe bit4=%02x, machregb9 bit1=%02x, charwidth=%d, htotal=%02x, hdisptime=%02x, seqregs1 bit 3=%02x.\n", clock_sel, (mach->regs[0xb8] >> 6) & 3, svga->miscout & 0x0c, mach->regs[0xbe] & 0x10, mach->regs[0xb9] & 0x02, svga->char_width, svga->htotal, svga->hdisp_time, svga->seqregs[1] & 8); if ((svga->gdcreg[6] & 0x01) || (svga->attrregs[0x10] & 0x01)) { if ((svga->gdcreg[5] & 0x40) || (svga->attrregs[0x10] & 0x40) || (mach->regs[0xb0] & 0x20)) { svga->map8 = svga->pallook; @@ -6376,7 +6562,7 @@ mach32_hwcursor_draw(svga_t *svga, int displine) case 8: color0 = dev->pallook[mach->cursor_col_0]; color1 = dev->pallook[mach->cursor_col_1]; - mach_log("4/8BPP: Color0=%08x, Color1=%08x.\n", color0, color1); + mach_log("4/8BPP: Color0=%08x, Color1=%08x, interlace=%x, oddeven=%d.\n", color0, color1, dev->interlace, dev->hwcursor_oddeven); break; case 15: color0 = video_15to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; @@ -7196,7 +7382,7 @@ mach8_init(const device_t *info) else mach->config1 |= 0x0c; mach->config1 |= 0x0400; - svga->clock_gen = device_add(&ati18811_1_device); + svga->clock_gen = device_add(&ati18811_1_mach32_device); } else if (mach->mca_bus) { video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_mca); if (is286 && !is386) @@ -7204,7 +7390,7 @@ mach8_init(const device_t *info) else mach->config1 |= 0x06; mach->config1 |= 0x0400; - svga->clock_gen = device_add(&ati18811_1_device); + svga->clock_gen = device_add(&ati18811_1_mach32_device); } else if (mach->pci_bus) { video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_pci); mach->config1 |= 0x0e; @@ -7213,11 +7399,11 @@ mach8_init(const device_t *info) else mach->config1 |= 0x0400; mach->config2 |= 0x2000; - svga->clock_gen = device_add(&ati18811_1_device); + svga->clock_gen = device_add(&ati18811_1_mach32_device); } else { video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa); mach->config1 |= 0x0400; - svga->clock_gen = device_add(&ati18811_1_device); + svga->clock_gen = device_add(&ati18811_1_mach32_device); } mem_mapping_add(&mach->mmio_linear_mapping, 0, 0, mach32_ap_readb, mach32_ap_readw, mach32_ap_readl, mach32_ap_writeb, mach32_ap_writew, mach32_ap_writel, NULL, MEM_MAPPING_EXTERNAL, mach); mem_mapping_disable(&mach->mmio_linear_mapping); @@ -7239,10 +7425,12 @@ mach8_init(const device_t *info) mach->config1 |= 0x20; mach->config2 = 0x02; - svga->clock_gen = device_add(&ati18811_0_device); + svga->clock_gen = device_add(&ati18811_1_mach32_device); } dev->bpp = 0; svga->getclock = ics2494_getclock; + svga->clock_gen8514 = svga->clock_gen; + svga->getclock8514 = svga->getclock; dev->on = 0; dev->pitch = 1024; @@ -7341,7 +7529,7 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) dev->accel_out_fifo = ati8514_accel_out_fifo; dev->vblank_start = ati8514_vblank_start; - svga->clock_gen8514 = device_add(&ati18811_0_device); + svga->clock_gen8514 = device_add(&ati18811_1_mach32_device); svga->getclock8514 = ics2494_getclock; }