From 55854afa8680ab89c9a3c8bb68f400936fc1e1ca Mon Sep 17 00:00:00 2001 From: Volker Ruppert Date: Tue, 14 Feb 2012 20:56:42 +0000 Subject: [PATCH] - calculate horizontal and vertical frequency from CRT for more accurate retrace timing (TODO: length of retrace signals should be calculated, too) --- bochs/iodev/vgacore.cc | 71 ++++++++++++++++++++++++++---------------- bochs/iodev/vgacore.h | 7 +++++ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/bochs/iodev/vgacore.cc b/bochs/iodev/vgacore.cc index 340fe5b56..1e8554ec0 100644 --- a/bochs/iodev/vgacore.cc +++ b/bochs/iodev/vgacore.cc @@ -156,6 +156,8 @@ void bx_vgacore_c::init_standard_vga(void) BX_VGA_THIS s.plane_shift = 16; BX_VGA_THIS s.dac_shift = 2; BX_VGA_THIS s.last_bpp = 8; + BX_VGA_THIS s.htotal_usec = 31; + BX_VGA_THIS s.vtotal_usec = 14285; BX_VGA_THIS s.max_xres = 800; BX_VGA_THIS s.max_yres = 600; @@ -378,6 +380,7 @@ void bx_vgacore_c::after_restore_state(void) BX_VGA_THIS s.last_xres = BX_VGA_THIS s.max_xres; BX_VGA_THIS s.last_yres = BX_VGA_THIS s.max_yres; BX_VGA_THIS redraw_area(0, 0, BX_VGA_THIS s.max_xres, BX_VGA_THIS s.max_yres); + BX_VGA_THIS calculate_retrace_timing(); BX_VGA_THIS update(); bx_gui->flush(); } @@ -421,6 +424,24 @@ void bx_vgacore_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piW } } +void bx_vgacore_c::calculate_retrace_timing() +{ + Bit32u dot_clock[4] = {25175000, 28322000, 25175000, 25175000}; + Bit32u htotal, clock, cwidth, vtotal, hfreq, vfreq; + + htotal = BX_VGA_THIS s.CRTC.reg[0] + 5; + htotal <<= BX_VGA_THIS s.x_dotclockdiv2; + cwidth = ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 1) ? 8 : 9; + clock = dot_clock[BX_VGA_THIS s.misc_output.clock_select]; + hfreq = clock / (htotal * cwidth); + BX_VGA_THIS s.htotal_usec = 1000000 / hfreq; + vtotal = BX_VGA_THIS s.CRTC.reg[6] + ((BX_VGA_THIS s.CRTC.reg[7] & 0x01) << 8) + + ((BX_VGA_THIS s.CRTC.reg[7] & 0x20) << 4) + 2; + vfreq = hfreq / vtotal; + BX_VGA_THIS s.vtotal_usec = 1000000 / vfreq; + BX_DEBUG(("hfreq = %.1f kHz / vfreq = %d Hz", ((double)hfreq / 1000), vfreq)); +} + // static IO port read callback handler // redirects to non-static class handler to avoid virtual functions @@ -432,9 +453,8 @@ Bit32u bx_vgacore_c::read_handler(void *this_ptr, Bit32u address, unsigned io_le Bit32u bx_vgacore_c::read(Bit32u address, unsigned io_len) { - bx_bool horiz_retrace = 0, vert_retrace = 0; - Bit64u usec; - Bit16u ret16, vertres; + Bit64u display_usec, line_usec; + Bit16u ret16; Bit8u retval; #if defined(VGA_TRACE_FEATURE) @@ -475,27 +495,16 @@ Bit32u bx_vgacore_c::read(Bit32u address, unsigned io_len) // 1 = display is not in the display mode; either the // horizontal or vertical retrace period is active - // using 72 Hz vertical frequency - usec = bx_pc_system.time_usec(); - switch ((BX_VGA_THIS s.misc_output.vert_sync_pol << 1) | BX_VGA_THIS s.misc_output.horiz_sync_pol) - { - case 0: vertres = 200; break; - case 1: vertres = 400; break; - case 2: vertres = 350; break; - default: vertres = 480; break; - } - if ((usec % 13888) < 70) { - vert_retrace = 1; - } - if ((usec % (13888 / vertres)) == 0) { - horiz_retrace = 1; - } - retval = 0; - if (horiz_retrace || vert_retrace) - retval = 0x01; - if (vert_retrace) - retval |= 0x08; + display_usec = bx_pc_system.time_usec() % BX_VGA_THIS s.vtotal_usec; + if (display_usec < 70) { + retval |= 0x09; + } else { + line_usec = display_usec % BX_VGA_THIS s.htotal_usec; + if (line_usec == 0) { + retval |= 0x01; + } + } /* reading this port resets the flip-flop to address mode */ BX_VGA_THIS s.attribute_ctrl.flip_flop = 0; @@ -930,6 +939,7 @@ void bx_vgacore_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool BX_DEBUG((" vert_sync_pol = %u", (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol)); #endif + calculate_retrace_timing(); break; case 0x03c3: // VGA enable @@ -974,6 +984,7 @@ void bx_vgacore_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool } BX_VGA_THIS s.sequencer.reg1 = value & 0x3d; BX_VGA_THIS s.x_dotclockdiv2 = ((value & 0x08) > 0); + calculate_retrace_timing(); break; case 2: /* sequencer: map mask register */ BX_VGA_THIS s.sequencer.map_mask = (value & 0x0f); @@ -1182,12 +1193,17 @@ void bx_vgacore_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) { BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value; switch (BX_VGA_THIS s.CRTC.address) { + case 0x00: + case 0x06: + calculate_retrace_timing(); + break; case 0x07: BX_VGA_THIS s.vertical_display_end &= 0xff; if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x02) BX_VGA_THIS s.vertical_display_end |= 0x100; if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x40) BX_VGA_THIS s.vertical_display_end |= 0x200; BX_VGA_THIS s.line_compare &= 0x2ff; if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100; + calculate_retrace_timing(); needs_update = 1; break; case 0x08: @@ -1223,6 +1239,7 @@ void bx_vgacore_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool case 0x12: BX_VGA_THIS s.vertical_display_end &= 0x300; BX_VGA_THIS s.vertical_display_end |= BX_VGA_THIS s.CRTC.reg[0x12]; + calculate_retrace_timing(); break; case 0x13: case 0x14: @@ -1344,6 +1361,7 @@ void bx_vgacore_c::update(void) static unsigned cs_counter = 1; static bx_bool cs_visible = 0; bx_bool cs_toggle = 0; + Bit64u display_usec; cs_counter--; /* no screen update necessary */ @@ -1369,10 +1387,11 @@ void bx_vgacore_c::update(void) || (BX_VGA_THIS s.sequencer.reg1 & 0x20)) return; - /* skip screen update if the vertical retrace is in progress - (using 72 Hz vertical frequency) */ - if ((bx_pc_system.time_usec() % 13888) < 70) + /* skip screen update if the vertical retrace is in progress */ + display_usec = bx_pc_system.time_usec() % BX_VGA_THIS s.vtotal_usec; + if (display_usec < 70) { return; + } // fields that effect the way video memory is serialized into screen output: // GRAPHICS CONTROLLER: diff --git a/bochs/iodev/vgacore.h b/bochs/iodev/vgacore.h index 06dca8b61..7f880d9b1 100644 --- a/bochs/iodev/vgacore.h +++ b/bochs/iodev/vgacore.h @@ -96,6 +96,7 @@ protected: bx_bool get_dac_palette(Bit8u **palette_ptr, Bit8u shift); void update(void); void determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth); + void calculate_retrace_timing(void); struct { struct { @@ -204,13 +205,19 @@ protected: Bit16u charmap_address; bx_bool x_dotclockdiv2; bx_bool y_doublescan; + // h/v retrace timing + Bit32u htotal_usec; + Bit32u vtotal_usec; + // shift values for extensions Bit8u plane_shift; Bit32u plane_offset; Bit8u dac_shift; + // last active resolution and bpp Bit16u last_xres; Bit16u last_yres; Bit8u last_bpp; Bit8u last_msl; + // maximum resolution and number of tiles Bit16u max_xres; Bit16u max_yres; Bit16u num_x_tiles;