Implemented more accurate screen update timing calculation using the RAMDAC

video clock. Removed dependencies to the cpu / memory clock.
This commit is contained in:
Volker Ruppert 2014-01-07 22:32:22 +00:00
parent ed163dd846
commit fc5c22d78f
5 changed files with 86 additions and 29 deletions

View File

@ -204,10 +204,8 @@ void bx_voodoo_c::init(void)
if (model == VOODOO_2) {
init_pci_conf(0x121a, 0x0002, 0x02, 0x038000, 0x00);
BX_VOODOO_THIS pci_conf[0x10] = 0x08;
BX_VOODOO_THIS s.clock = STD_VOODOO_2_CLOCK;
} else {
init_pci_conf(0x121a, 0x0001, 0x02, 0x000000, 0x00);
BX_VOODOO_THIS s.clock = STD_VOODOO_1_CLOCK;
}
BX_VOODOO_THIS pci_conf[0x3d] = BX_PCI_INTA;
BX_VOODOO_THIS pci_base_address[0] = 0;
@ -442,34 +440,47 @@ void bx_voodoo_c::mode_change_timer_handler(void *this_ptr)
bx_virt_timer.deactivate_timer(BX_VOODOO_THIS s.update_timer_id);
DEV_vga_set_override(0, NULL);
BX_VOODOO_THIS s.vdraw.override_on = 0;
BX_VOODOO_THIS s.vdraw.width = 0;
BX_VOODOO_THIS s.vdraw.height = 0;
}
if ((BX_VOODOO_THIS s.vdraw.clock_enabled && BX_VOODOO_THIS s.vdraw.output_on) && !BX_VOODOO_THIS s.vdraw.override_on) {
if ((v->reg[hSync].u == 0) || (v->reg[vSync].u == 0))
return;
// switching on
int htotal = ((v->reg[hSync].u >> 16) & 0x3ff) + 1 + (v->reg[hSync].u & 0xff) + 1;
int vtotal = ((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff);
int vsync = ((v->reg[vSync].u >> 16) & 0xfff);
double hfreq = BX_VOODOO_THIS s.clock / htotal; // Voodoo1 50 MHz / Voodoo2 90 MHz
if (((v->reg[fbiInit1].u >> 20) & 3) == 1) { // VCLK div 2
hfreq /= 2;
}
unsigned vfreq = (unsigned)(hfreq / vtotal);
BX_VOODOO_THIS s.vdraw.vtotal_usec = 1000000 / vfreq;
BX_VOODOO_THIS s.vdraw.vsync_usec = vsync * (unsigned)(1000000 / hfreq);
if (!BX_VOODOO_THIS update_timing())
return;
DEV_vga_set_override(1, BX_VOODOO_THIS_PTR);
BX_VOODOO_THIS s.vdraw.override_on = 1;
BX_VOODOO_THIS s.vdraw.width = v->fbi.width+1;
BX_VOODOO_THIS s.vdraw.height = v->fbi.height;
BX_INFO(("Voodoo output %dx%d@%uHz", v->fbi.width, v->fbi.height, vfreq));
bx_gui->dimension_update(v->fbi.width+1, v->fbi.height, 0, 0, 16);
update_timer_handler(NULL);
bx_virt_timer.activate_timer(BX_VOODOO_THIS s.update_timer_id, (Bit32u)BX_VOODOO_THIS s.vdraw.vtotal_usec, 1);
}
}
bx_bool bx_voodoo_c::update_timing(void)
{
if (!BX_VOODOO_THIS s.vdraw.clock_enabled || !BX_VOODOO_THIS s.vdraw.output_on)
return 0;
if ((v->reg[hSync].u == 0) || (v->reg[vSync].u == 0))
return 0;
int htotal = ((v->reg[hSync].u >> 16) & 0x3ff) + 1 + (v->reg[hSync].u & 0xff) + 1;
int vtotal = ((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff);
int vsync = ((v->reg[vSync].u >> 16) & 0xfff);
double hfreq = (double)(v->dac.clk0_freq * 1000) / htotal;
if (((v->reg[fbiInit1].u >> 20) & 3) == 1) { // VCLK div 2
hfreq /= 2;
}
double vfreq = hfreq / (double)vtotal;
BX_VOODOO_THIS s.vdraw.vtotal_usec = (unsigned)(1000000.0 / vfreq);
BX_VOODOO_THIS s.vdraw.vsync_usec = vsync * (unsigned)(1000000.0 / hfreq);
if ((BX_VOODOO_THIS s.vdraw.width != v->fbi.width) ||
(BX_VOODOO_THIS s.vdraw.height != v->fbi.height)) {
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);
}
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);
return 1;
}
void bx_voodoo_c::refresh_display(void *this_ptr, bx_bool redraw)
{
if (redraw) {

View File

@ -36,7 +36,6 @@ typedef struct {
bx_bool override_on;
bx_bool screen_update_pending;
} vdraw;
double clock;
int mode_change_timer_id;
int update_timer_id;
Bit8u devfunc;
@ -62,6 +61,7 @@ public:
static bx_bool get_retrace(void);
static void output_enable(bx_bool enabled);
static void update_screen_start(void);
static bx_bool update_timing(void);
private:
bx_voodoo_t s;

View File

@ -1635,6 +1635,11 @@ struct _dac_state
{
Bit8u reg[8]; /* 8 registers */
Bit8u read_result; /* pending read result */
Bit8u data_size;
Bit8u clk0_m;
Bit8u clk0_n;
Bit8u clk0_p;
Bit32u clk0_freq;
};

View File

@ -1397,6 +1397,37 @@ void recompute_video_memory(voodoo_state *v)
void dacdata_w(dac_state *d, Bit8u regnum, Bit8u data)
{
d->reg[regnum] = data;
/* switch off the DAC register requested */
switch (regnum) {
case 4: // PLLWMA
case 7: // PLLRMA
if (data == 0x0e) {
d->data_size = 1;
} else {
d->data_size = 2;
}
break;
case 5: // PLLDATA
switch (d->reg[4]) { // PLLWMA
case 0x00:
if (d->data_size == 2) {
d->clk0_m = data;
} else if (d->data_size == 1) {
d->clk0_n = data & 0x1f;
d->clk0_p = data >> 5;
}
break;
case 0x0e:
if ((d->data_size == 1) && ((data & 0x21) == 0x21)) {
d->clk0_freq = (Bit32u)((14318.0 * (d->clk0_m + 2)) / ((1 << d->clk0_p) * (d->clk0_n + 2)));
Voodoo_update_timing();
}
break;
}
d->data_size--;
break;
}
}
@ -1405,16 +1436,22 @@ void dacdata_r(dac_state *d, Bit8u regnum)
Bit8u result = 0xff;
/* switch off the DAC register requested */
switch (regnum)
{
case 5:
/* this is just to make startup happy */
switch (d->reg[7])
{
switch (regnum) {
case 5: // PLLDATA
switch (d->reg[7]) { // PLLRMA
case 0x00:
if (d->data_size == 2) {
result = d->clk0_m;
} else if (d->data_size == 1) {
result = d->clk0_n | (d->clk0_p << 5);
}
break;
/* this is just to make startup happy */
case 0x01: result = 0x55; break;
case 0x07: result = 0x71; break;
case 0x0b: result = 0x79; break;
}
d->data_size--;
break;
default:
@ -1846,7 +1883,7 @@ void register_w(Bit32u offset, Bit32u data)
#endif
/* configure the new framebuffer info */
v->fbi.width = hvis;
v->fbi.width = hvis + 1;
v->fbi.height = vvis;
v->fbi.xoffs = hbp;
v->fbi.yoffs = vbp;
@ -2840,6 +2877,9 @@ void voodoo_init(Bit8u _type)
v->chipmask = 0x01 | 0x02 | 0x04 | 0x08;
memset(v->dac.reg, 0, sizeof(v->dac.reg));
v->dac.read_result = 0;
v->dac.clk0_m = 0x37;
v->dac.clk0_n = 0x02;
v->dac.clk0_p = 0x03;
/* create a table of precomputed 1/n and log2(n) values */
/* n ranges from 1.0000 to 2.0000 */

View File

@ -150,5 +150,6 @@ READ32_DEVICE_HANDLER( banshee_rom_r );
#define Voodoo_UpdateScreenStart() theVoodooDevice->update_screen_start()
#define Voodoo_Output_Enable(x) theVoodooDevice->output_enable(x)
#define Voodoo_get_retrace() theVoodooDevice->get_retrace()
#define Voodoo_update_timing() theVoodooDevice->update_timing()
#endif