mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
Optional "precise" VGA retrace support
Selected via: -vga <name>,retrace=precise git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5336 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
3893c124e7
commit
cb5a7aa8c3
5 changed files with 220 additions and 6 deletions
|
@ -2744,8 +2744,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
|
|||
case 0x3ba:
|
||||
case 0x3da:
|
||||
/* just toggle to fool polling */
|
||||
s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
|
||||
val = s->st01;
|
||||
val = s->st01 = s->retrace((VGAState *) s);
|
||||
s->ar_flip_flop = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -2808,6 +2807,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
break;
|
||||
case 0x3c2:
|
||||
s->msr = val & ~0x10;
|
||||
s->update_retrace_info((VGAState *) s);
|
||||
break;
|
||||
case 0x3c4:
|
||||
s->sr_index = val;
|
||||
|
@ -2819,6 +2819,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
|
||||
#endif
|
||||
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
|
||||
if (s->sr_index == 1) s->update_retrace_info((VGAState *) s);
|
||||
break;
|
||||
case 0x3c6:
|
||||
cirrus_write_hidden_dac(s, val);
|
||||
|
@ -2886,6 +2887,18 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
s->cr[s->cr_index] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(s->cr_index) {
|
||||
case 0x00:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x11:
|
||||
case 0x17:
|
||||
s->update_retrace_info((VGAState *) s);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x3ba:
|
||||
case 0x3da:
|
||||
|
|
6
hw/pc.h
6
hw/pc.h
|
@ -108,6 +108,12 @@ void i440fx_init_memory_mappings(PCIDevice *d);
|
|||
int piix4_init(PCIBus *bus, int devfn);
|
||||
|
||||
/* vga.c */
|
||||
enum vga_retrace_method {
|
||||
VGA_RETRACE_DUMB,
|
||||
VGA_RETRACE_PRECISE
|
||||
};
|
||||
|
||||
extern enum vga_retrace_method vga_retrace_method;
|
||||
|
||||
#ifndef TARGET_SPARC
|
||||
#define VGA_RAM_SIZE (8192 * 1024)
|
||||
|
|
163
hw/vga.c
163
hw/vga.c
|
@ -27,6 +27,7 @@
|
|||
#include "pci.h"
|
||||
#include "vga_int.h"
|
||||
#include "pixel_ops.h"
|
||||
#include "qemu-timer.h"
|
||||
|
||||
//#define DEBUG_VGA
|
||||
//#define DEBUG_VGA_MEM
|
||||
|
@ -149,6 +150,139 @@ static uint8_t expand4to8[16];
|
|||
|
||||
static void vga_screen_dump(void *opaque, const char *filename);
|
||||
|
||||
static void vga_dumb_update_retrace_info(VGAState *s)
|
||||
{
|
||||
(void) s;
|
||||
}
|
||||
|
||||
static void vga_precise_update_retrace_info(VGAState *s)
|
||||
{
|
||||
int htotal_chars;
|
||||
int hretr_start_char;
|
||||
int hretr_skew_chars;
|
||||
int hretr_end_char;
|
||||
|
||||
int vtotal_lines;
|
||||
int vretr_start_line;
|
||||
int vretr_end_line;
|
||||
|
||||
int div2, sldiv2, dots;
|
||||
int clocking_mode;
|
||||
int clock_sel;
|
||||
const int hz[] = {25175000, 28322000, 25175000, 25175000};
|
||||
int64_t chars_per_sec;
|
||||
struct vga_precise_retrace *r = &s->retrace_info.precise;
|
||||
|
||||
htotal_chars = s->cr[0x00] + 5;
|
||||
hretr_start_char = s->cr[0x04];
|
||||
hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
|
||||
hretr_end_char = s->cr[0x05] & 0x1f;
|
||||
|
||||
vtotal_lines = (s->cr[0x06]
|
||||
| (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
|
||||
;
|
||||
vretr_start_line = s->cr[0x10]
|
||||
| ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
|
||||
;
|
||||
vretr_end_line = s->cr[0x11] & 0xf;
|
||||
|
||||
|
||||
div2 = (s->cr[0x17] >> 2) & 1;
|
||||
sldiv2 = (s->cr[0x17] >> 3) & 1;
|
||||
|
||||
clocking_mode = (s->sr[0x01] >> 3) & 1;
|
||||
clock_sel = (s->msr >> 2) & 3;
|
||||
dots = (s->msr & 1) ? 9 : 8;
|
||||
|
||||
chars_per_sec = hz[clock_sel] / dots;
|
||||
|
||||
htotal_chars <<= clocking_mode;
|
||||
|
||||
r->total_chars = vtotal_lines * htotal_chars;
|
||||
r->total_chars = (vretr_start_line + vretr_end_line + 1) * htotal_chars;
|
||||
if (r->freq) {
|
||||
r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
|
||||
} else {
|
||||
r->ticks_per_char = ticks_per_sec / chars_per_sec;
|
||||
}
|
||||
|
||||
r->vstart = vretr_start_line;
|
||||
r->vend = r->vstart + vretr_end_line + 1;
|
||||
|
||||
r->hstart = hretr_start_char + hretr_skew_chars;
|
||||
r->hend = r->hstart + hretr_end_char + 1;
|
||||
r->htotal = htotal_chars;
|
||||
|
||||
printf("hz=%f\n",
|
||||
(double) ticks_per_sec / (r->ticks_per_char * r->total_chars));
|
||||
#if 0 /* def DEBUG_RETRACE */
|
||||
printf("hz=%f\n",
|
||||
(double) ticks_per_sec / (r->ticks_per_char * r->total_chars));
|
||||
printf (
|
||||
"htotal = %d\n"
|
||||
"hretr_start = %d\n"
|
||||
"hretr_skew = %d\n"
|
||||
"hretr_end = %d\n"
|
||||
"vtotal = %d\n"
|
||||
"vretr_start = %d\n"
|
||||
"vretr_end = %d\n"
|
||||
"div2 = %d sldiv2 = %d\n"
|
||||
"clocking_mode = %d\n"
|
||||
"clock_sel = %d %d\n"
|
||||
"dots = %d\n"
|
||||
"ticks/char = %lld\n"
|
||||
"\n",
|
||||
htotal_chars,
|
||||
hretr_start_char,
|
||||
hretr_skew_chars,
|
||||
hretr_end_char,
|
||||
vtotal_lines,
|
||||
vretr_start_line,
|
||||
vretr_end_line,
|
||||
div2, sldiv2,
|
||||
clocking_mode,
|
||||
clock_sel,
|
||||
hz[clock_sel],
|
||||
dots,
|
||||
r->ticks_per_char
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t vga_precise_retrace(VGAState *s)
|
||||
{
|
||||
struct vga_precise_retrace *r = &s->retrace_info.precise;
|
||||
uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
|
||||
|
||||
if (r->total_chars) {
|
||||
int cur_line, cur_line_char, cur_char;
|
||||
int64_t cur_tick;
|
||||
|
||||
cur_tick = qemu_get_clock(vm_clock);
|
||||
|
||||
cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
|
||||
cur_line = cur_char / r->htotal;
|
||||
|
||||
if (cur_line >= r->vstart && cur_line <= r->vend) {
|
||||
val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
|
||||
}
|
||||
|
||||
cur_line_char = cur_char % r->htotal;
|
||||
if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
|
||||
val |= ST01_DISP_ENABLE;
|
||||
}
|
||||
|
||||
return val;
|
||||
} else {
|
||||
return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t vga_dumb_retrace(VGAState *s)
|
||||
{
|
||||
return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
|
||||
}
|
||||
|
||||
static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
|
||||
{
|
||||
VGAState *s = opaque;
|
||||
|
@ -228,8 +362,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
|
|||
case 0x3ba:
|
||||
case 0x3da:
|
||||
/* just toggle to fool polling */
|
||||
s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
|
||||
val = s->st01;
|
||||
val = s->st01 = s->retrace(s);
|
||||
s->ar_flip_flop = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -291,6 +424,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
break;
|
||||
case 0x3c2:
|
||||
s->msr = val & ~0x10;
|
||||
s->update_retrace_info(s);
|
||||
break;
|
||||
case 0x3c4:
|
||||
s->sr_index = val & 7;
|
||||
|
@ -300,6 +434,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
|
||||
#endif
|
||||
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
|
||||
if (s->sr_index == 1) s->update_retrace_info(s);
|
||||
break;
|
||||
case 0x3c7:
|
||||
s->dac_read_index = val;
|
||||
|
@ -357,6 +492,18 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
s->cr[s->cr_index] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(s->cr_index) {
|
||||
case 0x00:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x11:
|
||||
case 0x17:
|
||||
s->update_retrace_info(s);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x3ba:
|
||||
case 0x3da:
|
||||
|
@ -2001,6 +2148,18 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
|
|||
s->invalidate = vga_invalidate_display;
|
||||
s->screen_dump = vga_screen_dump;
|
||||
s->text_update = vga_update_text;
|
||||
switch (vga_retrace_method) {
|
||||
case VGA_RETRACE_DUMB:
|
||||
s->retrace = vga_dumb_retrace;
|
||||
s->update_retrace_info = vga_dumb_update_retrace_info;
|
||||
break;
|
||||
|
||||
case VGA_RETRACE_PRECISE:
|
||||
s->retrace = vga_precise_retrace;
|
||||
s->update_retrace_info = vga_precise_update_retrace_info;
|
||||
memset(&s->retrace_info, 0, sizeof (s->retrace_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* used by both ISA and PCI */
|
||||
|
|
25
hw/vga_int.h
25
hw/vga_int.h
|
@ -79,6 +79,25 @@
|
|||
#define CH_ATTR_SIZE (160 * 100)
|
||||
#define VGA_MAX_HEIGHT 2048
|
||||
|
||||
struct vga_precise_retrace {
|
||||
int64_t ticks_per_char;
|
||||
int64_t total_chars;
|
||||
int htotal;
|
||||
int hstart;
|
||||
int hend;
|
||||
int vstart;
|
||||
int vend;
|
||||
int freq;
|
||||
};
|
||||
|
||||
union vga_retrace {
|
||||
struct vga_precise_retrace precise;
|
||||
};
|
||||
|
||||
struct VGAState;
|
||||
typedef uint8_t (* vga_retrace_fn)(struct VGAState *s);
|
||||
typedef void (* vga_update_retrace_info_fn)(struct VGAState *s);
|
||||
|
||||
#define VGA_STATE_COMMON \
|
||||
uint8_t *vram_ptr; \
|
||||
unsigned long vram_offset; \
|
||||
|
@ -147,7 +166,11 @@
|
|||
void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \
|
||||
/* tell for each page if it has been updated since the last time */ \
|
||||
uint32_t last_palette[256]; \
|
||||
uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
|
||||
uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ \
|
||||
/* retrace */ \
|
||||
vga_retrace_fn retrace; \
|
||||
vga_update_retrace_info_fn update_retrace_info; \
|
||||
union vga_retrace retrace_info;
|
||||
|
||||
|
||||
typedef struct VGAState {
|
||||
|
|
15
vl.c
15
vl.c
|
@ -174,6 +174,7 @@ int nb_drives;
|
|||
/* point to the block driver where the snapshots are managed */
|
||||
BlockDriverState *bs_snapshots;
|
||||
int vga_ram_size;
|
||||
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
|
||||
static DisplayState display_state;
|
||||
int nographic;
|
||||
int curses;
|
||||
|
@ -8203,7 +8204,19 @@ static void select_vgahw (const char *p)
|
|||
fprintf(stderr, "Unknown vga type: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
if (*opts) goto invalid_vga;
|
||||
while (*opts) {
|
||||
const char *nextopt;
|
||||
|
||||
if (strstart(opts, ",retrace=", &nextopt)) {
|
||||
opts = nextopt;
|
||||
if (strstart(opts, "dumb", &nextopt))
|
||||
vga_retrace_method = VGA_RETRACE_DUMB;
|
||||
else if (strstart(opts, "precise", &nextopt))
|
||||
vga_retrace_method = VGA_RETRACE_PRECISE;
|
||||
else goto invalid_vga;
|
||||
} else goto invalid_vga;
|
||||
opts = nextopt;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
Loading…
Reference in a new issue