- calculate horizontal and vertical frequency from CRT for more accurate retrace

timing (TODO: length of retrace signals should be calculated, too)
This commit is contained in:
Volker Ruppert 2012-02-14 20:56:42 +00:00
parent 2f5be164d2
commit 55854afa86
2 changed files with 52 additions and 26 deletions

View File

@ -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:

View File

@ -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;