Commit cb5a7aa8c32141bb19a8f6571f630c779faebc25
1 parent
3893c124
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
Showing
5 changed files
with
220 additions
and
6 deletions
hw/cirrus_vga.c
| ... | ... | @@ -2744,8 +2744,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) |
| 2744 | 2744 | case 0x3ba: |
| 2745 | 2745 | case 0x3da: |
| 2746 | 2746 | /* just toggle to fool polling */ |
| 2747 | - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; | |
| 2748 | - val = s->st01; | |
| 2747 | + val = s->st01 = s->retrace((VGAState *) s); | |
| 2749 | 2748 | s->ar_flip_flop = 0; |
| 2750 | 2749 | break; |
| 2751 | 2750 | default: |
| ... | ... | @@ -2808,6 +2807,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 2808 | 2807 | break; |
| 2809 | 2808 | case 0x3c2: |
| 2810 | 2809 | s->msr = val & ~0x10; |
| 2810 | + s->update_retrace_info((VGAState *) s); | |
| 2811 | 2811 | break; |
| 2812 | 2812 | case 0x3c4: |
| 2813 | 2813 | s->sr_index = val; |
| ... | ... | @@ -2819,6 +2819,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 2819 | 2819 | printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); |
| 2820 | 2820 | #endif |
| 2821 | 2821 | s->sr[s->sr_index] = val & sr_mask[s->sr_index]; |
| 2822 | + if (s->sr_index == 1) s->update_retrace_info((VGAState *) s); | |
| 2822 | 2823 | break; |
| 2823 | 2824 | case 0x3c6: |
| 2824 | 2825 | cirrus_write_hidden_dac(s, val); |
| ... | ... | @@ -2886,6 +2887,18 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 2886 | 2887 | s->cr[s->cr_index] = val; |
| 2887 | 2888 | break; |
| 2888 | 2889 | } |
| 2890 | + | |
| 2891 | + switch(s->cr_index) { | |
| 2892 | + case 0x00: | |
| 2893 | + case 0x04: | |
| 2894 | + case 0x05: | |
| 2895 | + case 0x06: | |
| 2896 | + case 0x07: | |
| 2897 | + case 0x11: | |
| 2898 | + case 0x17: | |
| 2899 | + s->update_retrace_info((VGAState *) s); | |
| 2900 | + break; | |
| 2901 | + } | |
| 2889 | 2902 | break; |
| 2890 | 2903 | case 0x3ba: |
| 2891 | 2904 | case 0x3da: | ... | ... |
hw/pc.h
| ... | ... | @@ -108,6 +108,12 @@ void i440fx_init_memory_mappings(PCIDevice *d); |
| 108 | 108 | int piix4_init(PCIBus *bus, int devfn); |
| 109 | 109 | |
| 110 | 110 | /* vga.c */ |
| 111 | +enum vga_retrace_method { | |
| 112 | + VGA_RETRACE_DUMB, | |
| 113 | + VGA_RETRACE_PRECISE | |
| 114 | +}; | |
| 115 | + | |
| 116 | +extern enum vga_retrace_method vga_retrace_method; | |
| 111 | 117 | |
| 112 | 118 | #ifndef TARGET_SPARC |
| 113 | 119 | #define VGA_RAM_SIZE (8192 * 1024) | ... | ... |
hw/vga.c
| ... | ... | @@ -27,6 +27,7 @@ |
| 27 | 27 | #include "pci.h" |
| 28 | 28 | #include "vga_int.h" |
| 29 | 29 | #include "pixel_ops.h" |
| 30 | +#include "qemu-timer.h" | |
| 30 | 31 | |
| 31 | 32 | //#define DEBUG_VGA |
| 32 | 33 | //#define DEBUG_VGA_MEM |
| ... | ... | @@ -149,6 +150,139 @@ static uint8_t expand4to8[16]; |
| 149 | 150 | |
| 150 | 151 | static void vga_screen_dump(void *opaque, const char *filename); |
| 151 | 152 | |
| 153 | +static void vga_dumb_update_retrace_info(VGAState *s) | |
| 154 | +{ | |
| 155 | + (void) s; | |
| 156 | +} | |
| 157 | + | |
| 158 | +static void vga_precise_update_retrace_info(VGAState *s) | |
| 159 | +{ | |
| 160 | + int htotal_chars; | |
| 161 | + int hretr_start_char; | |
| 162 | + int hretr_skew_chars; | |
| 163 | + int hretr_end_char; | |
| 164 | + | |
| 165 | + int vtotal_lines; | |
| 166 | + int vretr_start_line; | |
| 167 | + int vretr_end_line; | |
| 168 | + | |
| 169 | + int div2, sldiv2, dots; | |
| 170 | + int clocking_mode; | |
| 171 | + int clock_sel; | |
| 172 | + const int hz[] = {25175000, 28322000, 25175000, 25175000}; | |
| 173 | + int64_t chars_per_sec; | |
| 174 | + struct vga_precise_retrace *r = &s->retrace_info.precise; | |
| 175 | + | |
| 176 | + htotal_chars = s->cr[0x00] + 5; | |
| 177 | + hretr_start_char = s->cr[0x04]; | |
| 178 | + hretr_skew_chars = (s->cr[0x05] >> 5) & 3; | |
| 179 | + hretr_end_char = s->cr[0x05] & 0x1f; | |
| 180 | + | |
| 181 | + vtotal_lines = (s->cr[0x06] | |
| 182 | + | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2 | |
| 183 | + ; | |
| 184 | + vretr_start_line = s->cr[0x10] | |
| 185 | + | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8) | |
| 186 | + ; | |
| 187 | + vretr_end_line = s->cr[0x11] & 0xf; | |
| 188 | + | |
| 189 | + | |
| 190 | + div2 = (s->cr[0x17] >> 2) & 1; | |
| 191 | + sldiv2 = (s->cr[0x17] >> 3) & 1; | |
| 192 | + | |
| 193 | + clocking_mode = (s->sr[0x01] >> 3) & 1; | |
| 194 | + clock_sel = (s->msr >> 2) & 3; | |
| 195 | + dots = (s->msr & 1) ? 9 : 8; | |
| 196 | + | |
| 197 | + chars_per_sec = hz[clock_sel] / dots; | |
| 198 | + | |
| 199 | + htotal_chars <<= clocking_mode; | |
| 200 | + | |
| 201 | + r->total_chars = vtotal_lines * htotal_chars; | |
| 202 | + r->total_chars = (vretr_start_line + vretr_end_line + 1) * htotal_chars; | |
| 203 | + if (r->freq) { | |
| 204 | + r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq); | |
| 205 | + } else { | |
| 206 | + r->ticks_per_char = ticks_per_sec / chars_per_sec; | |
| 207 | + } | |
| 208 | + | |
| 209 | + r->vstart = vretr_start_line; | |
| 210 | + r->vend = r->vstart + vretr_end_line + 1; | |
| 211 | + | |
| 212 | + r->hstart = hretr_start_char + hretr_skew_chars; | |
| 213 | + r->hend = r->hstart + hretr_end_char + 1; | |
| 214 | + r->htotal = htotal_chars; | |
| 215 | + | |
| 216 | + printf("hz=%f\n", | |
| 217 | + (double) ticks_per_sec / (r->ticks_per_char * r->total_chars)); | |
| 218 | +#if 0 /* def DEBUG_RETRACE */ | |
| 219 | + printf("hz=%f\n", | |
| 220 | + (double) ticks_per_sec / (r->ticks_per_char * r->total_chars)); | |
| 221 | + printf ( | |
| 222 | + "htotal = %d\n" | |
| 223 | + "hretr_start = %d\n" | |
| 224 | + "hretr_skew = %d\n" | |
| 225 | + "hretr_end = %d\n" | |
| 226 | + "vtotal = %d\n" | |
| 227 | + "vretr_start = %d\n" | |
| 228 | + "vretr_end = %d\n" | |
| 229 | + "div2 = %d sldiv2 = %d\n" | |
| 230 | + "clocking_mode = %d\n" | |
| 231 | + "clock_sel = %d %d\n" | |
| 232 | + "dots = %d\n" | |
| 233 | + "ticks/char = %lld\n" | |
| 234 | + "\n", | |
| 235 | + htotal_chars, | |
| 236 | + hretr_start_char, | |
| 237 | + hretr_skew_chars, | |
| 238 | + hretr_end_char, | |
| 239 | + vtotal_lines, | |
| 240 | + vretr_start_line, | |
| 241 | + vretr_end_line, | |
| 242 | + div2, sldiv2, | |
| 243 | + clocking_mode, | |
| 244 | + clock_sel, | |
| 245 | + hz[clock_sel], | |
| 246 | + dots, | |
| 247 | + r->ticks_per_char | |
| 248 | + ); | |
| 249 | +#endif | |
| 250 | +} | |
| 251 | + | |
| 252 | +static uint8_t vga_precise_retrace(VGAState *s) | |
| 253 | +{ | |
| 254 | + struct vga_precise_retrace *r = &s->retrace_info.precise; | |
| 255 | + uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE); | |
| 256 | + | |
| 257 | + if (r->total_chars) { | |
| 258 | + int cur_line, cur_line_char, cur_char; | |
| 259 | + int64_t cur_tick; | |
| 260 | + | |
| 261 | + cur_tick = qemu_get_clock(vm_clock); | |
| 262 | + | |
| 263 | + cur_char = (cur_tick / r->ticks_per_char) % r->total_chars; | |
| 264 | + cur_line = cur_char / r->htotal; | |
| 265 | + | |
| 266 | + if (cur_line >= r->vstart && cur_line <= r->vend) { | |
| 267 | + val |= ST01_V_RETRACE | ST01_DISP_ENABLE; | |
| 268 | + } | |
| 269 | + | |
| 270 | + cur_line_char = cur_char % r->htotal; | |
| 271 | + if (cur_line_char >= r->hstart && cur_line_char <= r->hend) { | |
| 272 | + val |= ST01_DISP_ENABLE; | |
| 273 | + } | |
| 274 | + | |
| 275 | + return val; | |
| 276 | + } else { | |
| 277 | + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); | |
| 278 | + } | |
| 279 | +} | |
| 280 | + | |
| 281 | +static uint8_t vga_dumb_retrace(VGAState *s) | |
| 282 | +{ | |
| 283 | + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); | |
| 284 | +} | |
| 285 | + | |
| 152 | 286 | static uint32_t vga_ioport_read(void *opaque, uint32_t addr) |
| 153 | 287 | { |
| 154 | 288 | VGAState *s = opaque; |
| ... | ... | @@ -228,8 +362,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) |
| 228 | 362 | case 0x3ba: |
| 229 | 363 | case 0x3da: |
| 230 | 364 | /* just toggle to fool polling */ |
| 231 | - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; | |
| 232 | - val = s->st01; | |
| 365 | + val = s->st01 = s->retrace(s); | |
| 233 | 366 | s->ar_flip_flop = 0; |
| 234 | 367 | break; |
| 235 | 368 | default: |
| ... | ... | @@ -291,6 +424,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 291 | 424 | break; |
| 292 | 425 | case 0x3c2: |
| 293 | 426 | s->msr = val & ~0x10; |
| 427 | + s->update_retrace_info(s); | |
| 294 | 428 | break; |
| 295 | 429 | case 0x3c4: |
| 296 | 430 | s->sr_index = val & 7; |
| ... | ... | @@ -300,6 +434,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 300 | 434 | printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); |
| 301 | 435 | #endif |
| 302 | 436 | s->sr[s->sr_index] = val & sr_mask[s->sr_index]; |
| 437 | + if (s->sr_index == 1) s->update_retrace_info(s); | |
| 303 | 438 | break; |
| 304 | 439 | case 0x3c7: |
| 305 | 440 | s->dac_read_index = val; |
| ... | ... | @@ -357,6 +492,18 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 357 | 492 | s->cr[s->cr_index] = val; |
| 358 | 493 | break; |
| 359 | 494 | } |
| 495 | + | |
| 496 | + switch(s->cr_index) { | |
| 497 | + case 0x00: | |
| 498 | + case 0x04: | |
| 499 | + case 0x05: | |
| 500 | + case 0x06: | |
| 501 | + case 0x07: | |
| 502 | + case 0x11: | |
| 503 | + case 0x17: | |
| 504 | + s->update_retrace_info(s); | |
| 505 | + break; | |
| 506 | + } | |
| 360 | 507 | break; |
| 361 | 508 | case 0x3ba: |
| 362 | 509 | case 0x3da: |
| ... | ... | @@ -2001,6 +2148,18 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, |
| 2001 | 2148 | s->invalidate = vga_invalidate_display; |
| 2002 | 2149 | s->screen_dump = vga_screen_dump; |
| 2003 | 2150 | s->text_update = vga_update_text; |
| 2151 | + switch (vga_retrace_method) { | |
| 2152 | + case VGA_RETRACE_DUMB: | |
| 2153 | + s->retrace = vga_dumb_retrace; | |
| 2154 | + s->update_retrace_info = vga_dumb_update_retrace_info; | |
| 2155 | + break; | |
| 2156 | + | |
| 2157 | + case VGA_RETRACE_PRECISE: | |
| 2158 | + s->retrace = vga_precise_retrace; | |
| 2159 | + s->update_retrace_info = vga_precise_update_retrace_info; | |
| 2160 | + memset(&s->retrace_info, 0, sizeof (s->retrace_info)); | |
| 2161 | + break; | |
| 2162 | + } | |
| 2004 | 2163 | } |
| 2005 | 2164 | |
| 2006 | 2165 | /* used by both ISA and PCI */ | ... | ... |
hw/vga_int.h
| ... | ... | @@ -79,6 +79,25 @@ |
| 79 | 79 | #define CH_ATTR_SIZE (160 * 100) |
| 80 | 80 | #define VGA_MAX_HEIGHT 2048 |
| 81 | 81 | |
| 82 | +struct vga_precise_retrace { | |
| 83 | + int64_t ticks_per_char; | |
| 84 | + int64_t total_chars; | |
| 85 | + int htotal; | |
| 86 | + int hstart; | |
| 87 | + int hend; | |
| 88 | + int vstart; | |
| 89 | + int vend; | |
| 90 | + int freq; | |
| 91 | +}; | |
| 92 | + | |
| 93 | +union vga_retrace { | |
| 94 | + struct vga_precise_retrace precise; | |
| 95 | +}; | |
| 96 | + | |
| 97 | +struct VGAState; | |
| 98 | +typedef uint8_t (* vga_retrace_fn)(struct VGAState *s); | |
| 99 | +typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); | |
| 100 | + | |
| 82 | 101 | #define VGA_STATE_COMMON \ |
| 83 | 102 | uint8_t *vram_ptr; \ |
| 84 | 103 | unsigned long vram_offset; \ |
| ... | ... | @@ -147,7 +166,11 @@ |
| 147 | 166 | void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \ |
| 148 | 167 | /* tell for each page if it has been updated since the last time */ \ |
| 149 | 168 | uint32_t last_palette[256]; \ |
| 150 | - uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ | |
| 169 | + uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ \ | |
| 170 | + /* retrace */ \ | |
| 171 | + vga_retrace_fn retrace; \ | |
| 172 | + vga_update_retrace_info_fn update_retrace_info; \ | |
| 173 | + union vga_retrace retrace_info; | |
| 151 | 174 | |
| 152 | 175 | |
| 153 | 176 | typedef struct VGAState { | ... | ... |
vl.c
| ... | ... | @@ -174,6 +174,7 @@ int nb_drives; |
| 174 | 174 | /* point to the block driver where the snapshots are managed */ |
| 175 | 175 | BlockDriverState *bs_snapshots; |
| 176 | 176 | int vga_ram_size; |
| 177 | +enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; | |
| 177 | 178 | static DisplayState display_state; |
| 178 | 179 | int nographic; |
| 179 | 180 | int curses; |
| ... | ... | @@ -8203,7 +8204,19 @@ static void select_vgahw (const char *p) |
| 8203 | 8204 | fprintf(stderr, "Unknown vga type: %s\n", p); |
| 8204 | 8205 | exit(1); |
| 8205 | 8206 | } |
| 8206 | - if (*opts) goto invalid_vga; | |
| 8207 | + while (*opts) { | |
| 8208 | + const char *nextopt; | |
| 8209 | + | |
| 8210 | + if (strstart(opts, ",retrace=", &nextopt)) { | |
| 8211 | + opts = nextopt; | |
| 8212 | + if (strstart(opts, "dumb", &nextopt)) | |
| 8213 | + vga_retrace_method = VGA_RETRACE_DUMB; | |
| 8214 | + else if (strstart(opts, "precise", &nextopt)) | |
| 8215 | + vga_retrace_method = VGA_RETRACE_PRECISE; | |
| 8216 | + else goto invalid_vga; | |
| 8217 | + } else goto invalid_vga; | |
| 8218 | + opts = nextopt; | |
| 8219 | + } | |
| 8207 | 8220 | } |
| 8208 | 8221 | |
| 8209 | 8222 | #ifdef _WIN32 | ... | ... |