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 | ... | ... |