Some work on the timing code of the Bochs display adapters.

- Voodoo: Use the VGA/Cirrus timers to drive the gui screen update.
  The vertical retrace emulation is still driven by a separate timer.
- VGA/Cirrus: Since we are using the virtual timer, we also have to read
  time_usec() from it.
- vgacore: removed unused timer methods.
This commit is contained in:
Volker Ruppert 2017-05-01 11:54:12 +00:00
parent 73c914a7f6
commit 8b96faf99e
8 changed files with 72 additions and 75 deletions

View File

@ -430,9 +430,9 @@ vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
# VOODOO:
# This defines the Voodoo Graphics emulation (experimental). Currently
# supported models are 'voodoo1' and 'voodoo2'. The Voodoo2 support is not
# yet complete. The 'realtime' option is very similar to the vga realtime
# option. If set to 1 (default), the Voodoo timer is based on realtime,
# otherwise it is driven by the cpu and depends on the ips setting.
# yet complete. The 'realtime' option controls the behaviour of the timer
# used for the vertical retrace emulation. The gui screen update timing
# is controlled by the related 'vga' options.
#
# Examples:
# voodoo: enabled=1, model=voodoo1, realtime=1

View File

@ -1,5 +1,5 @@
.\"Document Author: Timothy R. Butler - tbutler@uninetsolutions.com"
.TH bochsrc 5 "30 Apr 2017" "bochsrc" "The Bochs Project"
.TH bochsrc 5 "1 May 2017" "bochsrc" "The Bochs Project"
.\"SKIP_SECTION"
.SH NAME
bochsrc \- Configuration file for Bochs.
@ -483,9 +483,9 @@ Examples:
.I "voodoo:"
This defines the Voodoo Graphics emulation (experimental). Currently
supported models are 'voodoo1' and 'voodoo2'. The Voodoo2 support is not
yet complete. The 'realtime' option is very similar to the vga realtime
option. If set to 1 (default), the Voodoo timer is based on realtime,
otherwise it is driven by the cpu and depends on the ips setting.
yet complete. The 'realtime' option controls the behaviour of the timer
used for the vertical retrace emulation. The gui screen update timing
is controlled by the related 'vga' options.
Example:
voodoo: enabled=1, model=voodoo1, realtime=1

View File

@ -821,12 +821,12 @@ void bx_svga_cirrus_c::get_text_snapshot(Bit8u **text_snapshot,
Bit64s bx_svga_cirrus_c::svga_param_handler(bx_param_c *param, int set, Bit64s val)
{
if (set) {
BX_CIRRUS_THIS update_interval = (Bit32u)(1000000 / val);
BX_INFO(("Changing timer interval to %d", BX_CIRRUS_THIS update_interval));
Bit32u update_interval = (Bit32u)(1000000 / val);
BX_INFO(("Changing timer interval to %d", update_interval));
BX_CIRRUS_THIS svga_timer_handler(theSvga);
bx_virt_timer.activate_timer(BX_CIRRUS_THIS timer_id, BX_CIRRUS_THIS update_interval, 1);
if (BX_CIRRUS_THIS update_interval < 300000) {
BX_CIRRUS_THIS s.blink_counter = 300000 / (unsigned)BX_CIRRUS_THIS update_interval;
bx_virt_timer.activate_timer(BX_CIRRUS_THIS timer_id, update_interval, 1);
if (update_interval < 300000) {
BX_CIRRUS_THIS s.blink_counter = 300000 / (unsigned)update_interval;
} else {
BX_CIRRUS_THIS s.blink_counter = 1;
}
@ -1228,6 +1228,12 @@ void bx_svga_cirrus_c::svga_update(void)
{
unsigned width, height, pitch;
#if BX_SUPPORT_PCI
if (BX_CIRRUS_THIS s.vga_override && (BX_CIRRUS_THIS s.nvgadev != NULL)) {
BX_CIRRUS_THIS s.nvgadev->update();
return;
}
#endif
/* skip screen update when the sequencer is in reset mode or video is disabled */
if (! BX_CIRRUS_THIS s.sequencer.reset1 ||
! BX_CIRRUS_THIS s.sequencer.reset2 ||

View File

@ -330,12 +330,12 @@ Bit64s bx_vga_c::vga_param_handler(bx_param_c *param, int set, Bit64s val)
{
// handler for runtime parameter 'vga: update_freq'
if (set) {
BX_VGA_THIS update_interval = (Bit32u)(1000000 / val);
BX_INFO(("Changing timer interval to %d", BX_VGA_THIS update_interval));
Bit32u update_interval = (Bit32u)(1000000 / val);
BX_INFO(("Changing timer interval to %d", update_interval));
BX_VGA_THIS timer_handler(theVga);
bx_virt_timer.activate_timer(BX_VGA_THIS timer_id, BX_VGA_THIS update_interval, 1);
if (BX_VGA_THIS update_interval < 300000) {
BX_VGA_THIS s.blink_counter = 300000 / (unsigned)BX_VGA_THIS update_interval;
bx_virt_timer.activate_timer(BX_VGA_THIS timer_id, update_interval, 1);
if (update_interval < 300000) {
BX_VGA_THIS s.blink_counter = 300000 / (unsigned)update_interval;
} else {
BX_VGA_THIS s.blink_counter = 1;
}
@ -378,6 +378,12 @@ void bx_vga_c::update(void)
{
unsigned iHeight, iWidth;
#if BX_SUPPORT_PCI
if (BX_VGA_THIS s.vga_override && (BX_VGA_THIS s.nvgadev != NULL)) {
BX_VGA_THIS s.nvgadev->update();
return;
}
#endif
if (BX_VGA_THIS vbe.enabled) {
/* no screen update necessary */
if ((BX_VGA_THIS s.vga_mem_updated==0) && BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
@ -391,7 +397,7 @@ void bx_vga_c::update(void)
/* skip screen update if the vertical retrace is in progress
(using 72 Hz vertical frequency) */
if ((bx_pc_system.time_usec() % 13888) < 70)
if ((bx_virt_timer.time_usec(BX_VGA_THIS realtime) % 13888) < 70)
return;
if (BX_VGA_THIS vbe.bpp != VBE_DISPI_BPP_4) {

View File

@ -259,18 +259,18 @@ void bx_vgacore_c::init_iohandlers(bx_read_handler_t f_read, bx_write_handler_t
void bx_vgacore_c::init_systemtimer(bx_timer_handler_t f_timer, param_event_handler f_param)
{
const bx_bool realtime = SIM->get_param_bool(BXPN_VGA_REALTIME)->get();
BX_VGA_THIS realtime = SIM->get_param_bool(BXPN_VGA_REALTIME)->get();
bx_param_num_c *vga_update_freq = SIM->get_param_num(BXPN_VGA_UPDATE_FREQUENCY);
BX_VGA_THIS update_interval = (Bit32u)(1000000 / vga_update_freq->get());
BX_INFO(("interval=%u, mode=%s", BX_VGA_THIS update_interval, realtime ? "realtime":"standard"));
Bit32u update_interval = (Bit32u)(1000000 / vga_update_freq->get());
BX_INFO(("interval=%u, mode=%s", update_interval, BX_VGA_THIS realtime ? "realtime":"standard"));
if (BX_VGA_THIS timer_id == BX_NULL_TIMER_HANDLE) {
BX_VGA_THIS timer_id = bx_virt_timer.register_timer(this, f_timer,
BX_VGA_THIS update_interval, 1, 1, realtime, "vga");
update_interval, 1, 1, BX_VGA_THIS realtime, "vga");
vga_update_freq->set_handler(f_param);
}
// VGA text mode cursor blink frequency 1.875 Hz
if (BX_VGA_THIS update_interval < 266666) {
BX_VGA_THIS s.blink_counter = 266666 / (unsigned)BX_VGA_THIS update_interval;
if (update_interval < 266666) {
BX_VGA_THIS s.blink_counter = 266666 / (unsigned)update_interval;
} else {
BX_VGA_THIS s.blink_counter = 1;
}
@ -378,11 +378,9 @@ 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 update();
bx_gui->flush();
} else {
bx_virt_timer.deactivate_timer(BX_VGA_THIS timer_id);
}
BX_VGA_THIS update();
bx_gui->flush();
}
void bx_vgacore_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth)
@ -507,7 +505,7 @@ Bit32u bx_vgacore_c::read(Bit32u address, unsigned io_len)
// horizontal or vertical retrace period is active
retval = 0;
display_usec = bx_pc_system.time_usec() % BX_VGA_THIS s.vtotal_usec;
display_usec = bx_virt_timer.time_usec(BX_VGA_THIS realtime) % BX_VGA_THIS s.vtotal_usec;
if ((display_usec >= BX_VGA_THIS s.vrstart_usec) &&
(display_usec <= BX_VGA_THIS s.vrend_usec)) {
retval |= 0x08;
@ -1302,28 +1300,13 @@ void bx_vgacore_c::set_override(bx_bool enabled, void *dev)
#if BX_SUPPORT_PCI
BX_VGA_THIS s.nvgadev = (bx_nonvga_device_c*)dev;
#endif
if (enabled) {
bx_virt_timer.deactivate_timer(BX_VGA_THIS timer_id);
} else {
bx_virt_timer.activate_timer(BX_VGA_THIS timer_id, BX_VGA_THIS update_interval, 1);
if (!enabled) {
bx_gui->dimension_update(BX_VGA_THIS s.last_xres, BX_VGA_THIS s.last_yres,
BX_VGA_THIS s.last_fw, BX_VGA_THIS s.last_fh, BX_VGA_THIS s.last_bpp);
BX_VGA_THIS redraw_area(0, 0, BX_VGA_THIS s.last_xres, BX_VGA_THIS s.last_yres);
}
}
void bx_vgacore_c::timer_handler(void *this_ptr)
{
bx_vgacore_c *class_ptr = (bx_vgacore_c *) this_ptr;
class_ptr->timer();
}
void bx_vgacore_c::timer(void)
{
update();
bx_gui->flush();
}
Bit8u bx_vgacore_c::get_vga_pixel(Bit16u x, Bit16u y, Bit16u saddr, Bit16u lc, bx_bool bs, Bit8u **plane)
{
Bit8u attribute, bit_no, palette_reg_val, DAC_regno;
@ -1388,7 +1371,7 @@ bx_bool bx_vgacore_c::skip_update(void)
return 1;
/* skip screen update if the vertical retrace is in progress */
display_usec = bx_pc_system.time_usec() % BX_VGA_THIS s.vtotal_usec;
display_usec = bx_virt_timer.time_usec(BX_VGA_THIS realtime) % BX_VGA_THIS s.vtotal_usec;
if ((display_usec > BX_VGA_THIS s.vrstart_usec) &&
(display_usec < BX_VGA_THIS s.vrend_usec)) {
return 1;

View File

@ -51,6 +51,7 @@ public:
virtual void redraw_area(unsigned x0, unsigned y0,
unsigned width, unsigned height) {}
virtual void refresh_display(void *this_ptr, bx_bool redraw) {}
virtual void update(void) {}
};
#endif
@ -79,9 +80,6 @@ public:
unsigned *txWidth);
virtual void init_vga_extension(void) {}
static void timer_handler(void *);
void timer(void);
protected:
void init_standard_vga(void);
void init_gui(void);
@ -239,7 +237,7 @@ protected:
} s; // state information
int timer_id;
Bit32u update_interval;
bx_bool realtime;
bx_bool extension_init;
bx_bool pci_enabled;
};

View File

@ -160,7 +160,7 @@ bx_voodoo_c::bx_voodoo_c()
{
put("VOODOO");
s.mode_change_timer_id = BX_NULL_TIMER_HANDLE;
s.update_timer_id = BX_NULL_TIMER_HANDLE;
s.vertical_timer_id = BX_NULL_TIMER_HANDLE;
v = NULL;
}
@ -196,14 +196,15 @@ void bx_voodoo_c::init(void)
BX_VOODOO_THIS s.mode_change_timer_id = bx_virt_timer.register_timer(this, mode_change_timer_handler,
1000, 0, 0, 0, "voodoo_mode_change");
}
if (BX_VOODOO_THIS s.update_timer_id == BX_NULL_TIMER_HANDLE) {
BX_VOODOO_THIS s.update_timer_id = bx_virt_timer.register_timer(this, update_timer_handler,
50000, 1, 0, BX_VOODOO_THIS s.vdraw.realtime, "voodoo_update");
if (BX_VOODOO_THIS s.vertical_timer_id == BX_NULL_TIMER_HANDLE) {
BX_VOODOO_THIS s.vertical_timer_id = bx_virt_timer.register_timer(this, vertical_timer_handler,
50000, 1, 0, BX_VOODOO_THIS s.vdraw.realtime, "vertical_timer");
}
BX_VOODOO_THIS s.vdraw.clock_enabled = 1;
BX_VOODOO_THIS s.vdraw.output_on = 0;
BX_VOODOO_THIS s.vdraw.override_on = 0;
BX_VOODOO_THIS s.vdraw.screen_update_pending = 0;
BX_VOODOO_THIS s.vdraw.gui_update_pending = 0;
v = new voodoo_state;
BX_VOODOO_THIS s.model = (Bit8u)SIM->get_param_enum("model", base)->get();
@ -452,7 +453,7 @@ void bx_voodoo_c::mode_change_timer_handler(void *this_ptr)
if ((!BX_VOODOO_THIS s.vdraw.clock_enabled || !BX_VOODOO_THIS s.vdraw.output_on) && BX_VOODOO_THIS s.vdraw.override_on) {
// switching off
bx_virt_timer.deactivate_timer(BX_VOODOO_THIS s.update_timer_id);
bx_virt_timer.deactivate_timer(BX_VOODOO_THIS s.vertical_timer_id);
DEV_vga_set_override(0, NULL);
BX_VOODOO_THIS s.vdraw.override_on = 0;
BX_VOODOO_THIS s.vdraw.width = 0;
@ -503,10 +504,10 @@ bx_bool bx_voodoo_c::update_timing(void)
BX_VOODOO_THIS s.vdraw.width = v->fbi.width;
BX_VOODOO_THIS s.vdraw.height = v->fbi.height;
bx_gui->dimension_update(v->fbi.width, v->fbi.height, 0, 0, 16);
update_timer_handler(NULL);
vertical_timer_handler(NULL);
}
BX_INFO(("Voodoo output %dx%d@%uHz", v->fbi.width, v->fbi.height, (unsigned)vfreq));
bx_virt_timer.activate_timer(BX_VOODOO_THIS s.update_timer_id, (Bit32u)BX_VOODOO_THIS s.vdraw.vtotal_usec, 1);
bx_virt_timer.activate_timer(BX_VOODOO_THIS s.vertical_timer_id, (Bit32u)BX_VOODOO_THIS s.vdraw.vtotal_usec, 1);
return 1;
}
@ -515,15 +516,26 @@ void bx_voodoo_c::refresh_display(void *this_ptr, bx_bool redraw)
if (redraw) {
redraw_area(0, 0, v->fbi.width, v->fbi.height);
}
update_timer_handler(this_ptr);
vertical_timer_handler(this_ptr);
}
void bx_voodoo_c::update_timer_handler(void *this_ptr)
void bx_voodoo_c::vertical_timer_handler(void *this_ptr)
{
UNUSED(this_ptr);
update();
bx_gui->flush();
BX_VOODOO_THIS s.vdraw.frame_start = bx_virt_timer.time_usec(BX_VOODOO_THIS s.vdraw.realtime);
if (v->fbi.vblank_swap_pending) {
swap_buffers(v);
}
rectangle re;
re.min_x = re.min_y = 0;
re.max_x = v->fbi.width;
re.max_y = v->fbi.height;
if (!voodoo_update(&re))
return;
BX_VOODOO_THIS s.vdraw.gui_update_pending = 1;
}
void bx_voodoo_c::update(void)
@ -537,17 +549,7 @@ void bx_voodoo_c::update(void)
Bit8u * tile_ptr, * tile_ptr2;
bx_svga_tileinfo_t info;
BX_VOODOO_THIS s.vdraw.frame_start = bx_virt_timer.time_usec(BX_VOODOO_THIS s.vdraw.realtime);
if (v->fbi.vblank_swap_pending) {
swap_buffers(v);
}
rectangle re;
re.min_x = re.min_y = 0;
re.max_x = v->fbi.width;
re.max_y = v->fbi.height;
if (!voodoo_update(&re))
if (!BX_VOODOO_THIS s.vdraw.gui_update_pending)
return;
Bit8u *disp_ptr = (Bit8u*)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
@ -601,6 +603,7 @@ void bx_voodoo_c::update(void)
} else {
BX_PANIC(("cannot get svga tile info"));
}
BX_VOODOO_THIS s.vdraw.gui_update_pending = 0;
}
void bx_voodoo_c::redraw_area(unsigned x0, unsigned y0, unsigned width,

View File

@ -39,10 +39,11 @@ typedef struct {
bx_bool output_on;
bx_bool override_on;
bx_bool screen_update_pending;
bx_bool gui_update_pending;
bx_bool realtime;
} vdraw;
int mode_change_timer_id;
int update_timer_id;
int vertical_timer_id;
Bit8u devfunc;
} bx_voodoo_t;
@ -59,6 +60,7 @@ public:
virtual void refresh_display(void *this_ptr, bx_bool redraw);
virtual void redraw_area(unsigned x0, unsigned y0,
unsigned width, unsigned height);
virtual void update(void);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
@ -76,8 +78,7 @@ private:
static bx_bool mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param);
static void mode_change_timer_handler(void *);
static void update_timer_handler(void *);
static void update(void);
static void vertical_timer_handler(void *);
};
#endif