aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/cirrus_vga.c17
-rw-r--r--hw/pc.h6
-rw-r--r--hw/vga.c163
-rw-r--r--hw/vga_int.h25
-rw-r--r--vl.c15
5 files changed, 220 insertions, 6 deletions
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 53688a0eac..55f3ced340 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -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:
diff --git a/hw/pc.h b/hw/pc.h
index 28628491dc..e2da853715 100644
--- a/hw/pc.h
+++ b/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)
diff --git a/hw/vga.c b/hw/vga.c
index eb0bae8b93..366da11bee 100644
--- a/hw/vga.c
+++ b/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 */
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 343da34574..82a755ebfe 100644
--- a/hw/vga_int.h
+++ b/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 {
diff --git a/vl.c b/vl.c
index 07b5a4aee6..eeefe592e5 100644
--- a/vl.c
+++ b/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