|
1 /* |
|
2 * QEMU VGA Emulator. |
|
3 * |
|
4 * Copyright (c) 2003 Fabrice Bellard |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 #include "hw.h" |
|
25 #include "console.h" |
|
26 #include "pc.h" |
|
27 #include "pci.h" |
|
28 #include "vga_int.h" |
|
29 #include "pixel_ops.h" |
|
30 #include "qemu-timer.h" |
|
31 #include "kvm.h" |
|
32 |
|
33 //#define DEBUG_VGA |
|
34 //#define DEBUG_VGA_MEM |
|
35 //#define DEBUG_VGA_REG |
|
36 |
|
37 //#define DEBUG_BOCHS_VBE |
|
38 |
|
39 /* force some bits to zero */ |
|
40 const uint8_t sr_mask[8] = { |
|
41 (uint8_t)~0xfc, |
|
42 (uint8_t)~0xc2, |
|
43 (uint8_t)~0xf0, |
|
44 (uint8_t)~0xc0, |
|
45 (uint8_t)~0xf1, |
|
46 (uint8_t)~0xff, |
|
47 (uint8_t)~0xff, |
|
48 (uint8_t)~0x00, |
|
49 }; |
|
50 |
|
51 const uint8_t gr_mask[16] = { |
|
52 (uint8_t)~0xf0, /* 0x00 */ |
|
53 (uint8_t)~0xf0, /* 0x01 */ |
|
54 (uint8_t)~0xf0, /* 0x02 */ |
|
55 (uint8_t)~0xe0, /* 0x03 */ |
|
56 (uint8_t)~0xfc, /* 0x04 */ |
|
57 (uint8_t)~0x84, /* 0x05 */ |
|
58 (uint8_t)~0xf0, /* 0x06 */ |
|
59 (uint8_t)~0xf0, /* 0x07 */ |
|
60 (uint8_t)~0x00, /* 0x08 */ |
|
61 (uint8_t)~0xff, /* 0x09 */ |
|
62 (uint8_t)~0xff, /* 0x0a */ |
|
63 (uint8_t)~0xff, /* 0x0b */ |
|
64 (uint8_t)~0xff, /* 0x0c */ |
|
65 (uint8_t)~0xff, /* 0x0d */ |
|
66 (uint8_t)~0xff, /* 0x0e */ |
|
67 (uint8_t)~0xff, /* 0x0f */ |
|
68 }; |
|
69 |
|
70 #define cbswap_32(__x) \ |
|
71 ((uint32_t)( \ |
|
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ |
|
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ |
|
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ |
|
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) |
|
76 |
|
77 #ifdef WORDS_BIGENDIAN |
|
78 #define PAT(x) cbswap_32(x) |
|
79 #else |
|
80 #define PAT(x) (x) |
|
81 #endif |
|
82 |
|
83 #ifdef WORDS_BIGENDIAN |
|
84 #define BIG 1 |
|
85 #else |
|
86 #define BIG 0 |
|
87 #endif |
|
88 |
|
89 #ifdef WORDS_BIGENDIAN |
|
90 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) |
|
91 #else |
|
92 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) |
|
93 #endif |
|
94 |
|
95 static const uint32_t mask16[16] = { |
|
96 PAT(0x00000000), |
|
97 PAT(0x000000ff), |
|
98 PAT(0x0000ff00), |
|
99 PAT(0x0000ffff), |
|
100 PAT(0x00ff0000), |
|
101 PAT(0x00ff00ff), |
|
102 PAT(0x00ffff00), |
|
103 PAT(0x00ffffff), |
|
104 PAT(0xff000000), |
|
105 PAT(0xff0000ff), |
|
106 PAT(0xff00ff00), |
|
107 PAT(0xff00ffff), |
|
108 PAT(0xffff0000), |
|
109 PAT(0xffff00ff), |
|
110 PAT(0xffffff00), |
|
111 PAT(0xffffffff), |
|
112 }; |
|
113 |
|
114 #undef PAT |
|
115 |
|
116 #ifdef WORDS_BIGENDIAN |
|
117 #define PAT(x) (x) |
|
118 #else |
|
119 #define PAT(x) cbswap_32(x) |
|
120 #endif |
|
121 |
|
122 static const uint32_t dmask16[16] = { |
|
123 PAT(0x00000000), |
|
124 PAT(0x000000ff), |
|
125 PAT(0x0000ff00), |
|
126 PAT(0x0000ffff), |
|
127 PAT(0x00ff0000), |
|
128 PAT(0x00ff00ff), |
|
129 PAT(0x00ffff00), |
|
130 PAT(0x00ffffff), |
|
131 PAT(0xff000000), |
|
132 PAT(0xff0000ff), |
|
133 PAT(0xff00ff00), |
|
134 PAT(0xff00ffff), |
|
135 PAT(0xffff0000), |
|
136 PAT(0xffff00ff), |
|
137 PAT(0xffffff00), |
|
138 PAT(0xffffffff), |
|
139 }; |
|
140 |
|
141 static const uint32_t dmask4[4] = { |
|
142 PAT(0x00000000), |
|
143 PAT(0x0000ffff), |
|
144 PAT(0xffff0000), |
|
145 PAT(0xffffffff), |
|
146 }; |
|
147 |
|
148 static uint32_t expand4[256]; |
|
149 static uint16_t expand2[256]; |
|
150 static uint8_t expand4to8[16]; |
|
151 |
|
152 static void vga_screen_dump(void *opaque, const char *filename); |
|
153 |
|
154 static void vga_dumb_update_retrace_info(VGAState *s) |
|
155 { |
|
156 (void) s; |
|
157 } |
|
158 |
|
159 static void vga_precise_update_retrace_info(VGAState *s) |
|
160 { |
|
161 int htotal_chars; |
|
162 int hretr_start_char; |
|
163 int hretr_skew_chars; |
|
164 int hretr_end_char; |
|
165 |
|
166 int vtotal_lines; |
|
167 int vretr_start_line; |
|
168 int vretr_end_line; |
|
169 |
|
170 int div2, sldiv2, dots; |
|
171 int clocking_mode; |
|
172 int clock_sel; |
|
173 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000}; |
|
174 int64_t chars_per_sec; |
|
175 struct vga_precise_retrace *r = &s->retrace_info.precise; |
|
176 |
|
177 htotal_chars = s->cr[0x00] + 5; |
|
178 hretr_start_char = s->cr[0x04]; |
|
179 hretr_skew_chars = (s->cr[0x05] >> 5) & 3; |
|
180 hretr_end_char = s->cr[0x05] & 0x1f; |
|
181 |
|
182 vtotal_lines = (s->cr[0x06] |
|
183 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2 |
|
184 ; |
|
185 vretr_start_line = s->cr[0x10] |
|
186 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8) |
|
187 ; |
|
188 vretr_end_line = s->cr[0x11] & 0xf; |
|
189 |
|
190 |
|
191 div2 = (s->cr[0x17] >> 2) & 1; |
|
192 sldiv2 = (s->cr[0x17] >> 3) & 1; |
|
193 |
|
194 clocking_mode = (s->sr[0x01] >> 3) & 1; |
|
195 clock_sel = (s->msr >> 2) & 3; |
|
196 dots = (s->msr & 1) ? 8 : 9; |
|
197 |
|
198 chars_per_sec = clk_hz[clock_sel] / dots; |
|
199 |
|
200 htotal_chars <<= clocking_mode; |
|
201 |
|
202 r->total_chars = vtotal_lines * 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 #if 0 |
|
217 printf ( |
|
218 "hz=%f\n" |
|
219 "htotal = %d\n" |
|
220 "hretr_start = %d\n" |
|
221 "hretr_skew = %d\n" |
|
222 "hretr_end = %d\n" |
|
223 "vtotal = %d\n" |
|
224 "vretr_start = %d\n" |
|
225 "vretr_end = %d\n" |
|
226 "div2 = %d sldiv2 = %d\n" |
|
227 "clocking_mode = %d\n" |
|
228 "clock_sel = %d %d\n" |
|
229 "dots = %d\n" |
|
230 "ticks/char = %lld\n" |
|
231 "\n", |
|
232 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars), |
|
233 htotal_chars, |
|
234 hretr_start_char, |
|
235 hretr_skew_chars, |
|
236 hretr_end_char, |
|
237 vtotal_lines, |
|
238 vretr_start_line, |
|
239 vretr_end_line, |
|
240 div2, sldiv2, |
|
241 clocking_mode, |
|
242 clock_sel, |
|
243 clk_hz[clock_sel], |
|
244 dots, |
|
245 r->ticks_per_char |
|
246 ); |
|
247 #endif |
|
248 } |
|
249 |
|
250 static uint8_t vga_precise_retrace(VGAState *s) |
|
251 { |
|
252 struct vga_precise_retrace *r = &s->retrace_info.precise; |
|
253 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE); |
|
254 |
|
255 if (r->total_chars) { |
|
256 int cur_line, cur_line_char, cur_char; |
|
257 int64_t cur_tick; |
|
258 |
|
259 cur_tick = qemu_get_clock(vm_clock); |
|
260 |
|
261 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars; |
|
262 cur_line = cur_char / r->htotal; |
|
263 |
|
264 if (cur_line >= r->vstart && cur_line <= r->vend) { |
|
265 val |= ST01_V_RETRACE | ST01_DISP_ENABLE; |
|
266 } else { |
|
267 cur_line_char = cur_char % r->htotal; |
|
268 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) { |
|
269 val |= ST01_DISP_ENABLE; |
|
270 } |
|
271 } |
|
272 |
|
273 return val; |
|
274 } else { |
|
275 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); |
|
276 } |
|
277 } |
|
278 |
|
279 static uint8_t vga_dumb_retrace(VGAState *s) |
|
280 { |
|
281 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); |
|
282 } |
|
283 |
|
284 static uint32_t vga_ioport_read(void *opaque, uint32_t addr) |
|
285 { |
|
286 VGAState *s = opaque; |
|
287 int val, index; |
|
288 |
|
289 /* check port range access depending on color/monochrome mode */ |
|
290 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || |
|
291 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) { |
|
292 val = 0xff; |
|
293 } else { |
|
294 switch(addr) { |
|
295 case 0x3c0: |
|
296 if (s->ar_flip_flop == 0) { |
|
297 val = s->ar_index; |
|
298 } else { |
|
299 val = 0; |
|
300 } |
|
301 break; |
|
302 case 0x3c1: |
|
303 index = s->ar_index & 0x1f; |
|
304 if (index < 21) |
|
305 val = s->ar[index]; |
|
306 else |
|
307 val = 0; |
|
308 break; |
|
309 case 0x3c2: |
|
310 val = s->st00; |
|
311 break; |
|
312 case 0x3c4: |
|
313 val = s->sr_index; |
|
314 break; |
|
315 case 0x3c5: |
|
316 val = s->sr[s->sr_index]; |
|
317 #ifdef DEBUG_VGA_REG |
|
318 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); |
|
319 #endif |
|
320 break; |
|
321 case 0x3c7: |
|
322 val = s->dac_state; |
|
323 break; |
|
324 case 0x3c8: |
|
325 val = s->dac_write_index; |
|
326 break; |
|
327 case 0x3c9: |
|
328 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; |
|
329 if (++s->dac_sub_index == 3) { |
|
330 s->dac_sub_index = 0; |
|
331 s->dac_read_index++; |
|
332 } |
|
333 break; |
|
334 case 0x3ca: |
|
335 val = s->fcr; |
|
336 break; |
|
337 case 0x3cc: |
|
338 val = s->msr; |
|
339 break; |
|
340 case 0x3ce: |
|
341 val = s->gr_index; |
|
342 break; |
|
343 case 0x3cf: |
|
344 val = s->gr[s->gr_index]; |
|
345 #ifdef DEBUG_VGA_REG |
|
346 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); |
|
347 #endif |
|
348 break; |
|
349 case 0x3b4: |
|
350 case 0x3d4: |
|
351 val = s->cr_index; |
|
352 break; |
|
353 case 0x3b5: |
|
354 case 0x3d5: |
|
355 val = s->cr[s->cr_index]; |
|
356 #ifdef DEBUG_VGA_REG |
|
357 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); |
|
358 #endif |
|
359 break; |
|
360 case 0x3ba: |
|
361 case 0x3da: |
|
362 /* just toggle to fool polling */ |
|
363 val = s->st01 = s->retrace(s); |
|
364 s->ar_flip_flop = 0; |
|
365 break; |
|
366 default: |
|
367 val = 0x00; |
|
368 break; |
|
369 } |
|
370 } |
|
371 #if defined(DEBUG_VGA) |
|
372 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); |
|
373 #endif |
|
374 return val; |
|
375 } |
|
376 |
|
377 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
|
378 { |
|
379 VGAState *s = opaque; |
|
380 int index; |
|
381 |
|
382 /* check port range access depending on color/monochrome mode */ |
|
383 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || |
|
384 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) |
|
385 return; |
|
386 |
|
387 #ifdef DEBUG_VGA |
|
388 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); |
|
389 #endif |
|
390 |
|
391 switch(addr) { |
|
392 case 0x3c0: |
|
393 if (s->ar_flip_flop == 0) { |
|
394 val &= 0x3f; |
|
395 s->ar_index = val; |
|
396 } else { |
|
397 index = s->ar_index & 0x1f; |
|
398 switch(index) { |
|
399 case 0x00 ... 0x0f: |
|
400 s->ar[index] = val & 0x3f; |
|
401 break; |
|
402 case 0x10: |
|
403 s->ar[index] = val & ~0x10; |
|
404 break; |
|
405 case 0x11: |
|
406 s->ar[index] = val; |
|
407 break; |
|
408 case 0x12: |
|
409 s->ar[index] = val & ~0xc0; |
|
410 break; |
|
411 case 0x13: |
|
412 s->ar[index] = val & ~0xf0; |
|
413 break; |
|
414 case 0x14: |
|
415 s->ar[index] = val & ~0xf0; |
|
416 break; |
|
417 default: |
|
418 break; |
|
419 } |
|
420 } |
|
421 s->ar_flip_flop ^= 1; |
|
422 break; |
|
423 case 0x3c2: |
|
424 s->msr = val & ~0x10; |
|
425 s->update_retrace_info(s); |
|
426 break; |
|
427 case 0x3c4: |
|
428 s->sr_index = val & 7; |
|
429 break; |
|
430 case 0x3c5: |
|
431 #ifdef DEBUG_VGA_REG |
|
432 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); |
|
433 #endif |
|
434 s->sr[s->sr_index] = val & sr_mask[s->sr_index]; |
|
435 if (s->sr_index == 1) s->update_retrace_info(s); |
|
436 break; |
|
437 case 0x3c7: |
|
438 s->dac_read_index = val; |
|
439 s->dac_sub_index = 0; |
|
440 s->dac_state = 3; |
|
441 break; |
|
442 case 0x3c8: |
|
443 s->dac_write_index = val; |
|
444 s->dac_sub_index = 0; |
|
445 s->dac_state = 0; |
|
446 break; |
|
447 case 0x3c9: |
|
448 s->dac_cache[s->dac_sub_index] = val; |
|
449 if (++s->dac_sub_index == 3) { |
|
450 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); |
|
451 s->dac_sub_index = 0; |
|
452 s->dac_write_index++; |
|
453 } |
|
454 break; |
|
455 case 0x3ce: |
|
456 s->gr_index = val & 0x0f; |
|
457 break; |
|
458 case 0x3cf: |
|
459 #ifdef DEBUG_VGA_REG |
|
460 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); |
|
461 #endif |
|
462 s->gr[s->gr_index] = val & gr_mask[s->gr_index]; |
|
463 break; |
|
464 case 0x3b4: |
|
465 case 0x3d4: |
|
466 s->cr_index = val; |
|
467 break; |
|
468 case 0x3b5: |
|
469 case 0x3d5: |
|
470 #ifdef DEBUG_VGA_REG |
|
471 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); |
|
472 #endif |
|
473 /* handle CR0-7 protection */ |
|
474 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { |
|
475 /* can always write bit 4 of CR7 */ |
|
476 if (s->cr_index == 7) |
|
477 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); |
|
478 return; |
|
479 } |
|
480 switch(s->cr_index) { |
|
481 case 0x01: /* horizontal display end */ |
|
482 case 0x07: |
|
483 case 0x09: |
|
484 case 0x0c: |
|
485 case 0x0d: |
|
486 case 0x12: /* vertical display end */ |
|
487 s->cr[s->cr_index] = val; |
|
488 break; |
|
489 default: |
|
490 s->cr[s->cr_index] = val; |
|
491 break; |
|
492 } |
|
493 |
|
494 switch(s->cr_index) { |
|
495 case 0x00: |
|
496 case 0x04: |
|
497 case 0x05: |
|
498 case 0x06: |
|
499 case 0x07: |
|
500 case 0x11: |
|
501 case 0x17: |
|
502 s->update_retrace_info(s); |
|
503 break; |
|
504 } |
|
505 break; |
|
506 case 0x3ba: |
|
507 case 0x3da: |
|
508 s->fcr = val & 0x10; |
|
509 break; |
|
510 } |
|
511 } |
|
512 |
|
513 #ifdef CONFIG_BOCHS_VBE |
|
514 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) |
|
515 { |
|
516 VGAState *s = opaque; |
|
517 uint32_t val; |
|
518 val = s->vbe_index; |
|
519 return val; |
|
520 } |
|
521 |
|
522 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) |
|
523 { |
|
524 VGAState *s = opaque; |
|
525 uint32_t val; |
|
526 |
|
527 if (s->vbe_index <= VBE_DISPI_INDEX_NB) { |
|
528 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { |
|
529 switch(s->vbe_index) { |
|
530 /* XXX: do not hardcode ? */ |
|
531 case VBE_DISPI_INDEX_XRES: |
|
532 val = VBE_DISPI_MAX_XRES; |
|
533 break; |
|
534 case VBE_DISPI_INDEX_YRES: |
|
535 val = VBE_DISPI_MAX_YRES; |
|
536 break; |
|
537 case VBE_DISPI_INDEX_BPP: |
|
538 val = VBE_DISPI_MAX_BPP; |
|
539 break; |
|
540 default: |
|
541 val = s->vbe_regs[s->vbe_index]; |
|
542 break; |
|
543 } |
|
544 } else { |
|
545 val = s->vbe_regs[s->vbe_index]; |
|
546 } |
|
547 } else { |
|
548 val = 0; |
|
549 } |
|
550 #ifdef DEBUG_BOCHS_VBE |
|
551 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); |
|
552 #endif |
|
553 return val; |
|
554 } |
|
555 |
|
556 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) |
|
557 { |
|
558 VGAState *s = opaque; |
|
559 s->vbe_index = val; |
|
560 } |
|
561 |
|
562 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) |
|
563 { |
|
564 VGAState *s = opaque; |
|
565 |
|
566 if (s->vbe_index <= VBE_DISPI_INDEX_NB) { |
|
567 #ifdef DEBUG_BOCHS_VBE |
|
568 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); |
|
569 #endif |
|
570 switch(s->vbe_index) { |
|
571 case VBE_DISPI_INDEX_ID: |
|
572 if (val == VBE_DISPI_ID0 || |
|
573 val == VBE_DISPI_ID1 || |
|
574 val == VBE_DISPI_ID2 || |
|
575 val == VBE_DISPI_ID3 || |
|
576 val == VBE_DISPI_ID4) { |
|
577 s->vbe_regs[s->vbe_index] = val; |
|
578 } |
|
579 break; |
|
580 case VBE_DISPI_INDEX_XRES: |
|
581 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { |
|
582 s->vbe_regs[s->vbe_index] = val; |
|
583 } |
|
584 break; |
|
585 case VBE_DISPI_INDEX_YRES: |
|
586 if (val <= VBE_DISPI_MAX_YRES) { |
|
587 s->vbe_regs[s->vbe_index] = val; |
|
588 } |
|
589 break; |
|
590 case VBE_DISPI_INDEX_BPP: |
|
591 if (val == 0) |
|
592 val = 8; |
|
593 if (val == 4 || val == 8 || val == 15 || |
|
594 val == 16 || val == 24 || val == 32) { |
|
595 s->vbe_regs[s->vbe_index] = val; |
|
596 } |
|
597 break; |
|
598 case VBE_DISPI_INDEX_BANK: |
|
599 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { |
|
600 val &= (s->vbe_bank_mask >> 2); |
|
601 } else { |
|
602 val &= s->vbe_bank_mask; |
|
603 } |
|
604 s->vbe_regs[s->vbe_index] = val; |
|
605 s->bank_offset = (val << 16); |
|
606 break; |
|
607 case VBE_DISPI_INDEX_ENABLE: |
|
608 if ((val & VBE_DISPI_ENABLED) && |
|
609 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { |
|
610 int h, shift_control; |
|
611 |
|
612 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = |
|
613 s->vbe_regs[VBE_DISPI_INDEX_XRES]; |
|
614 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = |
|
615 s->vbe_regs[VBE_DISPI_INDEX_YRES]; |
|
616 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; |
|
617 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; |
|
618 |
|
619 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) |
|
620 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; |
|
621 else |
|
622 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * |
|
623 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); |
|
624 s->vbe_start_addr = 0; |
|
625 |
|
626 /* clear the screen (should be done in BIOS) */ |
|
627 if (!(val & VBE_DISPI_NOCLEARMEM)) { |
|
628 memset(s->vram_ptr, 0, |
|
629 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); |
|
630 } |
|
631 |
|
632 /* we initialize the VGA graphic mode (should be done |
|
633 in BIOS) */ |
|
634 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ |
|
635 s->cr[0x17] |= 3; /* no CGA modes */ |
|
636 s->cr[0x13] = s->vbe_line_offset >> 3; |
|
637 /* width */ |
|
638 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; |
|
639 /* height (only meaningful if < 1024) */ |
|
640 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; |
|
641 s->cr[0x12] = h; |
|
642 s->cr[0x07] = (s->cr[0x07] & ~0x42) | |
|
643 ((h >> 7) & 0x02) | ((h >> 3) & 0x40); |
|
644 /* line compare to 1023 */ |
|
645 s->cr[0x18] = 0xff; |
|
646 s->cr[0x07] |= 0x10; |
|
647 s->cr[0x09] |= 0x40; |
|
648 |
|
649 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { |
|
650 shift_control = 0; |
|
651 s->sr[0x01] &= ~8; /* no double line */ |
|
652 } else { |
|
653 shift_control = 2; |
|
654 s->sr[4] |= 0x08; /* set chain 4 mode */ |
|
655 s->sr[2] |= 0x0f; /* activate all planes */ |
|
656 } |
|
657 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); |
|
658 s->cr[0x09] &= ~0x9f; /* no double scan */ |
|
659 } else { |
|
660 /* XXX: the bios should do that */ |
|
661 s->bank_offset = 0; |
|
662 } |
|
663 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0; |
|
664 s->vbe_regs[s->vbe_index] = val; |
|
665 break; |
|
666 case VBE_DISPI_INDEX_VIRT_WIDTH: |
|
667 { |
|
668 int w, h, line_offset; |
|
669 |
|
670 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES]) |
|
671 return; |
|
672 w = val; |
|
673 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) |
|
674 line_offset = w >> 1; |
|
675 else |
|
676 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); |
|
677 h = s->vram_size / line_offset; |
|
678 /* XXX: support weird bochs semantics ? */ |
|
679 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) |
|
680 return; |
|
681 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w; |
|
682 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; |
|
683 s->vbe_line_offset = line_offset; |
|
684 } |
|
685 break; |
|
686 case VBE_DISPI_INDEX_X_OFFSET: |
|
687 case VBE_DISPI_INDEX_Y_OFFSET: |
|
688 { |
|
689 int x; |
|
690 s->vbe_regs[s->vbe_index] = val; |
|
691 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]; |
|
692 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET]; |
|
693 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) |
|
694 s->vbe_start_addr += x >> 1; |
|
695 else |
|
696 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); |
|
697 s->vbe_start_addr >>= 2; |
|
698 } |
|
699 break; |
|
700 default: |
|
701 break; |
|
702 } |
|
703 } |
|
704 } |
|
705 #endif |
|
706 |
|
707 /* called for accesses between 0xa0000 and 0xc0000 */ |
|
708 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) |
|
709 { |
|
710 VGAState *s = opaque; |
|
711 int memory_map_mode, plane; |
|
712 uint32_t ret; |
|
713 |
|
714 /* convert to VGA memory offset */ |
|
715 memory_map_mode = (s->gr[6] >> 2) & 3; |
|
716 addr &= 0x1ffff; |
|
717 switch(memory_map_mode) { |
|
718 case 0: |
|
719 break; |
|
720 case 1: |
|
721 if (addr >= 0x10000) |
|
722 return 0xff; |
|
723 addr += s->bank_offset; |
|
724 break; |
|
725 case 2: |
|
726 addr -= 0x10000; |
|
727 if (addr >= 0x8000) |
|
728 return 0xff; |
|
729 break; |
|
730 default: |
|
731 case 3: |
|
732 addr -= 0x18000; |
|
733 if (addr >= 0x8000) |
|
734 return 0xff; |
|
735 break; |
|
736 } |
|
737 |
|
738 if (s->sr[4] & 0x08) { |
|
739 /* chain 4 mode : simplest access */ |
|
740 ret = s->vram_ptr[addr]; |
|
741 } else if (s->gr[5] & 0x10) { |
|
742 /* odd/even mode (aka text mode mapping) */ |
|
743 plane = (s->gr[4] & 2) | (addr & 1); |
|
744 ret = s->vram_ptr[((addr & ~1) << 1) | plane]; |
|
745 } else { |
|
746 /* standard VGA latched access */ |
|
747 s->latch = ((uint32_t *)s->vram_ptr)[addr]; |
|
748 |
|
749 if (!(s->gr[5] & 0x08)) { |
|
750 /* read mode 0 */ |
|
751 plane = s->gr[4]; |
|
752 ret = GET_PLANE(s->latch, plane); |
|
753 } else { |
|
754 /* read mode 1 */ |
|
755 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]]; |
|
756 ret |= ret >> 16; |
|
757 ret |= ret >> 8; |
|
758 ret = (~ret) & 0xff; |
|
759 } |
|
760 } |
|
761 return ret; |
|
762 } |
|
763 |
|
764 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr) |
|
765 { |
|
766 uint32_t v; |
|
767 #ifdef TARGET_WORDS_BIGENDIAN |
|
768 v = vga_mem_readb(opaque, addr) << 8; |
|
769 v |= vga_mem_readb(opaque, addr + 1); |
|
770 #else |
|
771 v = vga_mem_readb(opaque, addr); |
|
772 v |= vga_mem_readb(opaque, addr + 1) << 8; |
|
773 #endif |
|
774 return v; |
|
775 } |
|
776 |
|
777 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr) |
|
778 { |
|
779 uint32_t v; |
|
780 #ifdef TARGET_WORDS_BIGENDIAN |
|
781 v = vga_mem_readb(opaque, addr) << 24; |
|
782 v |= vga_mem_readb(opaque, addr + 1) << 16; |
|
783 v |= vga_mem_readb(opaque, addr + 2) << 8; |
|
784 v |= vga_mem_readb(opaque, addr + 3); |
|
785 #else |
|
786 v = vga_mem_readb(opaque, addr); |
|
787 v |= vga_mem_readb(opaque, addr + 1) << 8; |
|
788 v |= vga_mem_readb(opaque, addr + 2) << 16; |
|
789 v |= vga_mem_readb(opaque, addr + 3) << 24; |
|
790 #endif |
|
791 return v; |
|
792 } |
|
793 |
|
794 /* called for accesses between 0xa0000 and 0xc0000 */ |
|
795 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
796 { |
|
797 VGAState *s = opaque; |
|
798 int memory_map_mode, plane, write_mode, b, func_select, mask; |
|
799 uint32_t write_mask, bit_mask, set_mask; |
|
800 |
|
801 #ifdef DEBUG_VGA_MEM |
|
802 printf("vga: [0x%x] = 0x%02x\n", addr, val); |
|
803 #endif |
|
804 /* convert to VGA memory offset */ |
|
805 memory_map_mode = (s->gr[6] >> 2) & 3; |
|
806 addr &= 0x1ffff; |
|
807 switch(memory_map_mode) { |
|
808 case 0: |
|
809 break; |
|
810 case 1: |
|
811 if (addr >= 0x10000) |
|
812 return; |
|
813 addr += s->bank_offset; |
|
814 break; |
|
815 case 2: |
|
816 addr -= 0x10000; |
|
817 if (addr >= 0x8000) |
|
818 return; |
|
819 break; |
|
820 default: |
|
821 case 3: |
|
822 addr -= 0x18000; |
|
823 if (addr >= 0x8000) |
|
824 return; |
|
825 break; |
|
826 } |
|
827 |
|
828 if (s->sr[4] & 0x08) { |
|
829 /* chain 4 mode : simplest access */ |
|
830 plane = addr & 3; |
|
831 mask = (1 << plane); |
|
832 if (s->sr[2] & mask) { |
|
833 s->vram_ptr[addr] = val; |
|
834 #ifdef DEBUG_VGA_MEM |
|
835 printf("vga: chain4: [0x%x]\n", addr); |
|
836 #endif |
|
837 s->plane_updated |= mask; /* only used to detect font change */ |
|
838 cpu_physical_memory_set_dirty(s->vram_offset + addr); |
|
839 } |
|
840 } else if (s->gr[5] & 0x10) { |
|
841 /* odd/even mode (aka text mode mapping) */ |
|
842 plane = (s->gr[4] & 2) | (addr & 1); |
|
843 mask = (1 << plane); |
|
844 if (s->sr[2] & mask) { |
|
845 addr = ((addr & ~1) << 1) | plane; |
|
846 s->vram_ptr[addr] = val; |
|
847 #ifdef DEBUG_VGA_MEM |
|
848 printf("vga: odd/even: [0x%x]\n", addr); |
|
849 #endif |
|
850 s->plane_updated |= mask; /* only used to detect font change */ |
|
851 cpu_physical_memory_set_dirty(s->vram_offset + addr); |
|
852 } |
|
853 } else { |
|
854 /* standard VGA latched access */ |
|
855 write_mode = s->gr[5] & 3; |
|
856 switch(write_mode) { |
|
857 default: |
|
858 case 0: |
|
859 /* rotate */ |
|
860 b = s->gr[3] & 7; |
|
861 val = ((val >> b) | (val << (8 - b))) & 0xff; |
|
862 val |= val << 8; |
|
863 val |= val << 16; |
|
864 |
|
865 /* apply set/reset mask */ |
|
866 set_mask = mask16[s->gr[1]]; |
|
867 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask); |
|
868 bit_mask = s->gr[8]; |
|
869 break; |
|
870 case 1: |
|
871 val = s->latch; |
|
872 goto do_write; |
|
873 case 2: |
|
874 val = mask16[val & 0x0f]; |
|
875 bit_mask = s->gr[8]; |
|
876 break; |
|
877 case 3: |
|
878 /* rotate */ |
|
879 b = s->gr[3] & 7; |
|
880 val = (val >> b) | (val << (8 - b)); |
|
881 |
|
882 bit_mask = s->gr[8] & val; |
|
883 val = mask16[s->gr[0]]; |
|
884 break; |
|
885 } |
|
886 |
|
887 /* apply logical operation */ |
|
888 func_select = s->gr[3] >> 3; |
|
889 switch(func_select) { |
|
890 case 0: |
|
891 default: |
|
892 /* nothing to do */ |
|
893 break; |
|
894 case 1: |
|
895 /* and */ |
|
896 val &= s->latch; |
|
897 break; |
|
898 case 2: |
|
899 /* or */ |
|
900 val |= s->latch; |
|
901 break; |
|
902 case 3: |
|
903 /* xor */ |
|
904 val ^= s->latch; |
|
905 break; |
|
906 } |
|
907 |
|
908 /* apply bit mask */ |
|
909 bit_mask |= bit_mask << 8; |
|
910 bit_mask |= bit_mask << 16; |
|
911 val = (val & bit_mask) | (s->latch & ~bit_mask); |
|
912 |
|
913 do_write: |
|
914 /* mask data according to sr[2] */ |
|
915 mask = s->sr[2]; |
|
916 s->plane_updated |= mask; /* only used to detect font change */ |
|
917 write_mask = mask16[mask]; |
|
918 ((uint32_t *)s->vram_ptr)[addr] = |
|
919 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | |
|
920 (val & write_mask); |
|
921 #ifdef DEBUG_VGA_MEM |
|
922 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", |
|
923 addr * 4, write_mask, val); |
|
924 #endif |
|
925 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2)); |
|
926 } |
|
927 } |
|
928 |
|
929 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
930 { |
|
931 #ifdef TARGET_WORDS_BIGENDIAN |
|
932 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); |
|
933 vga_mem_writeb(opaque, addr + 1, val & 0xff); |
|
934 #else |
|
935 vga_mem_writeb(opaque, addr, val & 0xff); |
|
936 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
937 #endif |
|
938 } |
|
939 |
|
940 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
941 { |
|
942 #ifdef TARGET_WORDS_BIGENDIAN |
|
943 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); |
|
944 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); |
|
945 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); |
|
946 vga_mem_writeb(opaque, addr + 3, val & 0xff); |
|
947 #else |
|
948 vga_mem_writeb(opaque, addr, val & 0xff); |
|
949 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
950 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); |
|
951 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); |
|
952 #endif |
|
953 } |
|
954 |
|
955 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, |
|
956 const uint8_t *font_ptr, int h, |
|
957 uint32_t fgcol, uint32_t bgcol); |
|
958 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize, |
|
959 const uint8_t *font_ptr, int h, |
|
960 uint32_t fgcol, uint32_t bgcol, int dup9); |
|
961 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, |
|
962 const uint8_t *s, int width); |
|
963 |
|
964 #define DEPTH 8 |
|
965 #include "vga_template.h" |
|
966 |
|
967 #define DEPTH 15 |
|
968 #include "vga_template.h" |
|
969 |
|
970 #define BGR_FORMAT |
|
971 #define DEPTH 15 |
|
972 #include "vga_template.h" |
|
973 |
|
974 #define DEPTH 16 |
|
975 #include "vga_template.h" |
|
976 |
|
977 #define BGR_FORMAT |
|
978 #define DEPTH 16 |
|
979 #include "vga_template.h" |
|
980 |
|
981 #define DEPTH 32 |
|
982 #include "vga_template.h" |
|
983 |
|
984 #define BGR_FORMAT |
|
985 #define DEPTH 32 |
|
986 #include "vga_template.h" |
|
987 |
|
988 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) |
|
989 { |
|
990 unsigned int col; |
|
991 col = rgb_to_pixel8(r, g, b); |
|
992 col |= col << 8; |
|
993 col |= col << 16; |
|
994 return col; |
|
995 } |
|
996 |
|
997 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b) |
|
998 { |
|
999 unsigned int col; |
|
1000 col = rgb_to_pixel15(r, g, b); |
|
1001 col |= col << 16; |
|
1002 return col; |
|
1003 } |
|
1004 |
|
1005 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g, |
|
1006 unsigned int b) |
|
1007 { |
|
1008 unsigned int col; |
|
1009 col = rgb_to_pixel15bgr(r, g, b); |
|
1010 col |= col << 16; |
|
1011 return col; |
|
1012 } |
|
1013 |
|
1014 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) |
|
1015 { |
|
1016 unsigned int col; |
|
1017 col = rgb_to_pixel16(r, g, b); |
|
1018 col |= col << 16; |
|
1019 return col; |
|
1020 } |
|
1021 |
|
1022 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g, |
|
1023 unsigned int b) |
|
1024 { |
|
1025 unsigned int col; |
|
1026 col = rgb_to_pixel16bgr(r, g, b); |
|
1027 col |= col << 16; |
|
1028 return col; |
|
1029 } |
|
1030 |
|
1031 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) |
|
1032 { |
|
1033 unsigned int col; |
|
1034 col = rgb_to_pixel32(r, g, b); |
|
1035 return col; |
|
1036 } |
|
1037 |
|
1038 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) |
|
1039 { |
|
1040 unsigned int col; |
|
1041 col = rgb_to_pixel32bgr(r, g, b); |
|
1042 return col; |
|
1043 } |
|
1044 |
|
1045 /* return true if the palette was modified */ |
|
1046 static int update_palette16(VGAState *s) |
|
1047 { |
|
1048 int full_update, i; |
|
1049 uint32_t v, col, *palette; |
|
1050 |
|
1051 full_update = 0; |
|
1052 palette = s->last_palette; |
|
1053 for(i = 0; i < 16; i++) { |
|
1054 v = s->ar[i]; |
|
1055 if (s->ar[0x10] & 0x80) |
|
1056 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf); |
|
1057 else |
|
1058 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); |
|
1059 v = v * 3; |
|
1060 col = s->rgb_to_pixel(c6_to_8(s->palette[v]), |
|
1061 c6_to_8(s->palette[v + 1]), |
|
1062 c6_to_8(s->palette[v + 2])); |
|
1063 if (col != palette[i]) { |
|
1064 full_update = 1; |
|
1065 palette[i] = col; |
|
1066 } |
|
1067 } |
|
1068 return full_update; |
|
1069 } |
|
1070 |
|
1071 /* return true if the palette was modified */ |
|
1072 static int update_palette256(VGAState *s) |
|
1073 { |
|
1074 int full_update, i; |
|
1075 uint32_t v, col, *palette; |
|
1076 |
|
1077 full_update = 0; |
|
1078 palette = s->last_palette; |
|
1079 v = 0; |
|
1080 for(i = 0; i < 256; i++) { |
|
1081 if (s->dac_8bit) { |
|
1082 col = s->rgb_to_pixel(s->palette[v], |
|
1083 s->palette[v + 1], |
|
1084 s->palette[v + 2]); |
|
1085 } else { |
|
1086 col = s->rgb_to_pixel(c6_to_8(s->palette[v]), |
|
1087 c6_to_8(s->palette[v + 1]), |
|
1088 c6_to_8(s->palette[v + 2])); |
|
1089 } |
|
1090 if (col != palette[i]) { |
|
1091 full_update = 1; |
|
1092 palette[i] = col; |
|
1093 } |
|
1094 v += 3; |
|
1095 } |
|
1096 return full_update; |
|
1097 } |
|
1098 |
|
1099 static void vga_get_offsets(VGAState *s, |
|
1100 uint32_t *pline_offset, |
|
1101 uint32_t *pstart_addr, |
|
1102 uint32_t *pline_compare) |
|
1103 { |
|
1104 uint32_t start_addr, line_offset, line_compare; |
|
1105 #ifdef CONFIG_BOCHS_VBE |
|
1106 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { |
|
1107 line_offset = s->vbe_line_offset; |
|
1108 start_addr = s->vbe_start_addr; |
|
1109 line_compare = 65535; |
|
1110 } else |
|
1111 #endif |
|
1112 { |
|
1113 /* compute line_offset in bytes */ |
|
1114 line_offset = s->cr[0x13]; |
|
1115 line_offset <<= 3; |
|
1116 |
|
1117 /* starting address */ |
|
1118 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); |
|
1119 |
|
1120 /* line compare */ |
|
1121 line_compare = s->cr[0x18] | |
|
1122 ((s->cr[0x07] & 0x10) << 4) | |
|
1123 ((s->cr[0x09] & 0x40) << 3); |
|
1124 } |
|
1125 *pline_offset = line_offset; |
|
1126 *pstart_addr = start_addr; |
|
1127 *pline_compare = line_compare; |
|
1128 } |
|
1129 |
|
1130 /* update start_addr and line_offset. Return TRUE if modified */ |
|
1131 static int update_basic_params(VGAState *s) |
|
1132 { |
|
1133 int full_update; |
|
1134 uint32_t start_addr, line_offset, line_compare; |
|
1135 |
|
1136 full_update = 0; |
|
1137 |
|
1138 s->get_offsets(s, &line_offset, &start_addr, &line_compare); |
|
1139 |
|
1140 if (line_offset != s->line_offset || |
|
1141 start_addr != s->start_addr || |
|
1142 line_compare != s->line_compare) { |
|
1143 s->line_offset = line_offset; |
|
1144 s->start_addr = start_addr; |
|
1145 s->line_compare = line_compare; |
|
1146 full_update = 1; |
|
1147 } |
|
1148 return full_update; |
|
1149 } |
|
1150 |
|
1151 #define NB_DEPTHS 7 |
|
1152 |
|
1153 static inline int get_depth_index(DisplayState *s) |
|
1154 { |
|
1155 switch(ds_get_bits_per_pixel(s)) { |
|
1156 default: |
|
1157 case 8: |
|
1158 return 0; |
|
1159 case 15: |
|
1160 if (ds_get_bgr(s)) |
|
1161 return 5; |
|
1162 else |
|
1163 return 1; |
|
1164 case 16: |
|
1165 if (ds_get_bgr(s)) |
|
1166 return 6; |
|
1167 else |
|
1168 return 2; |
|
1169 case 32: |
|
1170 if (ds_get_bgr(s)) |
|
1171 return 4; |
|
1172 else |
|
1173 return 3; |
|
1174 } |
|
1175 } |
|
1176 |
|
1177 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { |
|
1178 vga_draw_glyph8_8, |
|
1179 vga_draw_glyph8_16, |
|
1180 vga_draw_glyph8_16, |
|
1181 vga_draw_glyph8_32, |
|
1182 vga_draw_glyph8_32, |
|
1183 vga_draw_glyph8_16, |
|
1184 vga_draw_glyph8_16, |
|
1185 }; |
|
1186 |
|
1187 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { |
|
1188 vga_draw_glyph16_8, |
|
1189 vga_draw_glyph16_16, |
|
1190 vga_draw_glyph16_16, |
|
1191 vga_draw_glyph16_32, |
|
1192 vga_draw_glyph16_32, |
|
1193 vga_draw_glyph16_16, |
|
1194 vga_draw_glyph16_16, |
|
1195 }; |
|
1196 |
|
1197 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { |
|
1198 vga_draw_glyph9_8, |
|
1199 vga_draw_glyph9_16, |
|
1200 vga_draw_glyph9_16, |
|
1201 vga_draw_glyph9_32, |
|
1202 vga_draw_glyph9_32, |
|
1203 vga_draw_glyph9_16, |
|
1204 vga_draw_glyph9_16, |
|
1205 }; |
|
1206 |
|
1207 static const uint8_t cursor_glyph[32 * 4] = { |
|
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1215 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
1224 }; |
|
1225 |
|
1226 /* |
|
1227 * Text mode update |
|
1228 * Missing: |
|
1229 * - double scan |
|
1230 * - double width |
|
1231 * - underline |
|
1232 * - flashing |
|
1233 */ |
|
1234 static void vga_draw_text(VGAState *s, int full_update) |
|
1235 { |
|
1236 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; |
|
1237 int cx_min, cx_max, linesize, x_incr; |
|
1238 uint32_t offset, fgcol, bgcol, v, cursor_offset; |
|
1239 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr; |
|
1240 const uint8_t *font_ptr, *font_base[2]; |
|
1241 int dup9, line_offset, depth_index; |
|
1242 uint32_t *palette; |
|
1243 uint32_t *ch_attr_ptr; |
|
1244 vga_draw_glyph8_func *vga_draw_glyph8; |
|
1245 vga_draw_glyph9_func *vga_draw_glyph9; |
|
1246 |
|
1247 vga_dirty_log_stop(s); |
|
1248 |
|
1249 full_update |= update_palette16(s); |
|
1250 palette = s->last_palette; |
|
1251 |
|
1252 /* compute font data address (in plane 2) */ |
|
1253 v = s->sr[3]; |
|
1254 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; |
|
1255 if (offset != s->font_offsets[0]) { |
|
1256 s->font_offsets[0] = offset; |
|
1257 full_update = 1; |
|
1258 } |
|
1259 font_base[0] = s->vram_ptr + offset; |
|
1260 |
|
1261 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; |
|
1262 font_base[1] = s->vram_ptr + offset; |
|
1263 if (offset != s->font_offsets[1]) { |
|
1264 s->font_offsets[1] = offset; |
|
1265 full_update = 1; |
|
1266 } |
|
1267 if (s->plane_updated & (1 << 2)) { |
|
1268 /* if the plane 2 was modified since the last display, it |
|
1269 indicates the font may have been modified */ |
|
1270 s->plane_updated = 0; |
|
1271 full_update = 1; |
|
1272 } |
|
1273 full_update |= update_basic_params(s); |
|
1274 |
|
1275 line_offset = s->line_offset; |
|
1276 s1 = s->vram_ptr + (s->start_addr * 4); |
|
1277 |
|
1278 /* total width & height */ |
|
1279 cheight = (s->cr[9] & 0x1f) + 1; |
|
1280 cw = 8; |
|
1281 if (!(s->sr[1] & 0x01)) |
|
1282 cw = 9; |
|
1283 if (s->sr[1] & 0x08) |
|
1284 cw = 16; /* NOTE: no 18 pixel wide */ |
|
1285 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); |
|
1286 width = (s->cr[0x01] + 1); |
|
1287 if (s->cr[0x06] == 100) { |
|
1288 /* ugly hack for CGA 160x100x16 - explain me the logic */ |
|
1289 height = 100; |
|
1290 } else { |
|
1291 height = s->cr[0x12] | |
|
1292 ((s->cr[0x07] & 0x02) << 7) | |
|
1293 ((s->cr[0x07] & 0x40) << 3); |
|
1294 height = (height + 1) / cheight; |
|
1295 } |
|
1296 if ((height * width) > CH_ATTR_SIZE) { |
|
1297 /* better than nothing: exit if transient size is too big */ |
|
1298 return; |
|
1299 } |
|
1300 |
|
1301 if (width != s->last_width || height != s->last_height || |
|
1302 cw != s->last_cw || cheight != s->last_ch) { |
|
1303 s->last_scr_width = width * cw; |
|
1304 s->last_scr_height = height * cheight; |
|
1305 gui_resize_vt(s->ds, s->last_scr_width, s->last_scr_height); |
|
1306 s->last_width = width; |
|
1307 s->last_height = height; |
|
1308 s->last_ch = cheight; |
|
1309 s->last_cw = cw; |
|
1310 full_update = 1; |
|
1311 } |
|
1312 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; |
|
1313 if (cursor_offset != s->cursor_offset || |
|
1314 s->cr[0xa] != s->cursor_start || |
|
1315 s->cr[0xb] != s->cursor_end) { |
|
1316 /* if the cursor position changed, we update the old and new |
|
1317 chars */ |
|
1318 if (s->cursor_offset < CH_ATTR_SIZE) |
|
1319 s->last_ch_attr[s->cursor_offset] = -1; |
|
1320 if (cursor_offset < CH_ATTR_SIZE) |
|
1321 s->last_ch_attr[cursor_offset] = -1; |
|
1322 s->cursor_offset = cursor_offset; |
|
1323 s->cursor_start = s->cr[0xa]; |
|
1324 s->cursor_end = s->cr[0xb]; |
|
1325 } |
|
1326 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; |
|
1327 |
|
1328 depth_index = get_depth_index(s->ds); |
|
1329 if (cw == 16) |
|
1330 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; |
|
1331 else |
|
1332 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; |
|
1333 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; |
|
1334 |
|
1335 dest = ds_get_data(s->ds); |
|
1336 linesize = ds_get_linesize(s->ds); |
|
1337 ch_attr_ptr = s->last_ch_attr; |
|
1338 for(cy = 0; cy < height; cy++) { |
|
1339 d1 = dest; |
|
1340 src = s1; |
|
1341 cx_min = width; |
|
1342 cx_max = -1; |
|
1343 for(cx = 0; cx < width; cx++) { |
|
1344 ch_attr = *(uint16_t *)src; |
|
1345 if (full_update || ch_attr != *ch_attr_ptr) { |
|
1346 if (cx < cx_min) |
|
1347 cx_min = cx; |
|
1348 if (cx > cx_max) |
|
1349 cx_max = cx; |
|
1350 *ch_attr_ptr = ch_attr; |
|
1351 #ifdef WORDS_BIGENDIAN |
|
1352 ch = ch_attr >> 8; |
|
1353 cattr = ch_attr & 0xff; |
|
1354 #else |
|
1355 ch = ch_attr & 0xff; |
|
1356 cattr = ch_attr >> 8; |
|
1357 #endif |
|
1358 font_ptr = font_base[(cattr >> 3) & 1]; |
|
1359 font_ptr += 32 * 4 * ch; |
|
1360 bgcol = palette[cattr >> 4]; |
|
1361 fgcol = palette[cattr & 0x0f]; |
|
1362 if (cw != 9) { |
|
1363 vga_draw_glyph8(d1, linesize, |
|
1364 font_ptr, cheight, fgcol, bgcol); |
|
1365 } else { |
|
1366 dup9 = 0; |
|
1367 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) |
|
1368 dup9 = 1; |
|
1369 vga_draw_glyph9(d1, linesize, |
|
1370 font_ptr, cheight, fgcol, bgcol, dup9); |
|
1371 } |
|
1372 if (src == cursor_ptr && |
|
1373 !(s->cr[0x0a] & 0x20)) { |
|
1374 int line_start, line_last, h; |
|
1375 /* draw the cursor */ |
|
1376 line_start = s->cr[0x0a] & 0x1f; |
|
1377 line_last = s->cr[0x0b] & 0x1f; |
|
1378 /* XXX: check that */ |
|
1379 if (line_last > cheight - 1) |
|
1380 line_last = cheight - 1; |
|
1381 if (line_last >= line_start && line_start < cheight) { |
|
1382 h = line_last - line_start + 1; |
|
1383 d = d1 + linesize * line_start; |
|
1384 if (cw != 9) { |
|
1385 vga_draw_glyph8(d, linesize, |
|
1386 cursor_glyph, h, fgcol, bgcol); |
|
1387 } else { |
|
1388 vga_draw_glyph9(d, linesize, |
|
1389 cursor_glyph, h, fgcol, bgcol, 1); |
|
1390 } |
|
1391 } |
|
1392 } |
|
1393 } |
|
1394 d1 += x_incr; |
|
1395 src += 4; |
|
1396 ch_attr_ptr++; |
|
1397 } |
|
1398 if (cx_max != -1) { |
|
1399 dpy_update(s->ds, cx_min * cw, cy * cheight, |
|
1400 (cx_max - cx_min + 1) * cw, cheight); |
|
1401 } |
|
1402 dest += linesize * cheight; |
|
1403 s1 += line_offset; |
|
1404 } |
|
1405 } |
|
1406 |
|
1407 enum { |
|
1408 VGA_DRAW_LINE2, |
|
1409 VGA_DRAW_LINE2D2, |
|
1410 VGA_DRAW_LINE4, |
|
1411 VGA_DRAW_LINE4D2, |
|
1412 VGA_DRAW_LINE8D2, |
|
1413 VGA_DRAW_LINE8, |
|
1414 VGA_DRAW_LINE15, |
|
1415 VGA_DRAW_LINE16, |
|
1416 VGA_DRAW_LINE24, |
|
1417 VGA_DRAW_LINE32, |
|
1418 VGA_DRAW_LINE_NB, |
|
1419 }; |
|
1420 |
|
1421 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { |
|
1422 vga_draw_line2_8, |
|
1423 vga_draw_line2_16, |
|
1424 vga_draw_line2_16, |
|
1425 vga_draw_line2_32, |
|
1426 vga_draw_line2_32, |
|
1427 vga_draw_line2_16, |
|
1428 vga_draw_line2_16, |
|
1429 |
|
1430 vga_draw_line2d2_8, |
|
1431 vga_draw_line2d2_16, |
|
1432 vga_draw_line2d2_16, |
|
1433 vga_draw_line2d2_32, |
|
1434 vga_draw_line2d2_32, |
|
1435 vga_draw_line2d2_16, |
|
1436 vga_draw_line2d2_16, |
|
1437 |
|
1438 vga_draw_line4_8, |
|
1439 vga_draw_line4_16, |
|
1440 vga_draw_line4_16, |
|
1441 vga_draw_line4_32, |
|
1442 vga_draw_line4_32, |
|
1443 vga_draw_line4_16, |
|
1444 vga_draw_line4_16, |
|
1445 |
|
1446 vga_draw_line4d2_8, |
|
1447 vga_draw_line4d2_16, |
|
1448 vga_draw_line4d2_16, |
|
1449 vga_draw_line4d2_32, |
|
1450 vga_draw_line4d2_32, |
|
1451 vga_draw_line4d2_16, |
|
1452 vga_draw_line4d2_16, |
|
1453 |
|
1454 vga_draw_line8d2_8, |
|
1455 vga_draw_line8d2_16, |
|
1456 vga_draw_line8d2_16, |
|
1457 vga_draw_line8d2_32, |
|
1458 vga_draw_line8d2_32, |
|
1459 vga_draw_line8d2_16, |
|
1460 vga_draw_line8d2_16, |
|
1461 |
|
1462 vga_draw_line8_8, |
|
1463 vga_draw_line8_16, |
|
1464 vga_draw_line8_16, |
|
1465 vga_draw_line8_32, |
|
1466 vga_draw_line8_32, |
|
1467 vga_draw_line8_16, |
|
1468 vga_draw_line8_16, |
|
1469 |
|
1470 vga_draw_line15_8, |
|
1471 vga_draw_line15_15, |
|
1472 vga_draw_line15_16, |
|
1473 vga_draw_line15_32, |
|
1474 vga_draw_line15_32bgr, |
|
1475 vga_draw_line15_15bgr, |
|
1476 vga_draw_line15_16bgr, |
|
1477 |
|
1478 vga_draw_line16_8, |
|
1479 vga_draw_line16_15, |
|
1480 vga_draw_line16_16, |
|
1481 vga_draw_line16_32, |
|
1482 vga_draw_line16_32bgr, |
|
1483 vga_draw_line16_15bgr, |
|
1484 vga_draw_line16_16bgr, |
|
1485 |
|
1486 vga_draw_line24_8, |
|
1487 vga_draw_line24_15, |
|
1488 vga_draw_line24_16, |
|
1489 vga_draw_line24_32, |
|
1490 vga_draw_line24_32bgr, |
|
1491 vga_draw_line24_15bgr, |
|
1492 vga_draw_line24_16bgr, |
|
1493 |
|
1494 vga_draw_line32_8, |
|
1495 vga_draw_line32_15, |
|
1496 vga_draw_line32_16, |
|
1497 vga_draw_line32_32, |
|
1498 vga_draw_line32_32bgr, |
|
1499 vga_draw_line32_15bgr, |
|
1500 vga_draw_line32_16bgr, |
|
1501 }; |
|
1502 |
|
1503 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); |
|
1504 |
|
1505 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { |
|
1506 rgb_to_pixel8_dup, |
|
1507 rgb_to_pixel15_dup, |
|
1508 rgb_to_pixel16_dup, |
|
1509 rgb_to_pixel32_dup, |
|
1510 rgb_to_pixel32bgr_dup, |
|
1511 rgb_to_pixel15bgr_dup, |
|
1512 rgb_to_pixel16bgr_dup, |
|
1513 }; |
|
1514 |
|
1515 static int vga_get_bpp(VGAState *s) |
|
1516 { |
|
1517 int ret; |
|
1518 #ifdef CONFIG_BOCHS_VBE |
|
1519 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { |
|
1520 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; |
|
1521 } else |
|
1522 #endif |
|
1523 { |
|
1524 ret = 0; |
|
1525 } |
|
1526 return ret; |
|
1527 } |
|
1528 |
|
1529 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) |
|
1530 { |
|
1531 int width, height; |
|
1532 |
|
1533 #ifdef CONFIG_BOCHS_VBE |
|
1534 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { |
|
1535 width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; |
|
1536 height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; |
|
1537 } else |
|
1538 #endif |
|
1539 { |
|
1540 width = (s->cr[0x01] + 1) * 8; |
|
1541 height = s->cr[0x12] | |
|
1542 ((s->cr[0x07] & 0x02) << 7) | |
|
1543 ((s->cr[0x07] & 0x40) << 3); |
|
1544 height = (height + 1); |
|
1545 } |
|
1546 *pwidth = width; |
|
1547 *pheight = height; |
|
1548 } |
|
1549 |
|
1550 void vga_invalidate_scanlines(VGAState *s, int y1, int y2) |
|
1551 { |
|
1552 int y; |
|
1553 if (y1 >= VGA_MAX_HEIGHT) |
|
1554 return; |
|
1555 if (y2 >= VGA_MAX_HEIGHT) |
|
1556 y2 = VGA_MAX_HEIGHT; |
|
1557 for(y = y1; y < y2; y++) { |
|
1558 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f); |
|
1559 } |
|
1560 } |
|
1561 |
|
1562 static void vga_sync_dirty_bitmap(VGAState *s) |
|
1563 { |
|
1564 if (s->map_addr) |
|
1565 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end); |
|
1566 |
|
1567 if (s->lfb_vram_mapped) { |
|
1568 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000); |
|
1569 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000); |
|
1570 } |
|
1571 vga_dirty_log_start(s); |
|
1572 } |
|
1573 |
|
1574 /* |
|
1575 * graphic modes |
|
1576 */ |
|
1577 static void vga_draw_graphic(VGAState *s, int full_update) |
|
1578 { |
|
1579 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; |
|
1580 int width, height, shift_control, line_offset, page0, page1, bwidth, bits; |
|
1581 int disp_width, multi_scan, multi_run; |
|
1582 uint8_t *d; |
|
1583 uint32_t v, addr1, addr; |
|
1584 vga_draw_line_func *vga_draw_line; |
|
1585 |
|
1586 full_update |= update_basic_params(s); |
|
1587 |
|
1588 if (!full_update) |
|
1589 vga_sync_dirty_bitmap(s); |
|
1590 |
|
1591 s->get_resolution(s, &width, &height); |
|
1592 disp_width = width; |
|
1593 |
|
1594 shift_control = (s->gr[0x05] >> 5) & 3; |
|
1595 double_scan = (s->cr[0x09] >> 7); |
|
1596 if (shift_control != 1) { |
|
1597 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; |
|
1598 } else { |
|
1599 /* in CGA modes, multi_scan is ignored */ |
|
1600 /* XXX: is it correct ? */ |
|
1601 multi_scan = double_scan; |
|
1602 } |
|
1603 multi_run = multi_scan; |
|
1604 if (shift_control != s->shift_control || |
|
1605 double_scan != s->double_scan) { |
|
1606 full_update = 1; |
|
1607 s->shift_control = shift_control; |
|
1608 s->double_scan = double_scan; |
|
1609 } |
|
1610 |
|
1611 if (shift_control == 0) { |
|
1612 full_update |= update_palette16(s); |
|
1613 if (s->sr[0x01] & 8) { |
|
1614 v = VGA_DRAW_LINE4D2; |
|
1615 disp_width <<= 1; |
|
1616 } else { |
|
1617 v = VGA_DRAW_LINE4; |
|
1618 } |
|
1619 bits = 4; |
|
1620 } else if (shift_control == 1) { |
|
1621 full_update |= update_palette16(s); |
|
1622 if (s->sr[0x01] & 8) { |
|
1623 v = VGA_DRAW_LINE2D2; |
|
1624 disp_width <<= 1; |
|
1625 } else { |
|
1626 v = VGA_DRAW_LINE2; |
|
1627 } |
|
1628 bits = 4; |
|
1629 } else { |
|
1630 switch(s->get_bpp(s)) { |
|
1631 default: |
|
1632 case 0: |
|
1633 full_update |= update_palette256(s); |
|
1634 v = VGA_DRAW_LINE8D2; |
|
1635 bits = 4; |
|
1636 break; |
|
1637 case 8: |
|
1638 full_update |= update_palette256(s); |
|
1639 v = VGA_DRAW_LINE8; |
|
1640 bits = 8; |
|
1641 break; |
|
1642 case 15: |
|
1643 v = VGA_DRAW_LINE15; |
|
1644 bits = 16; |
|
1645 break; |
|
1646 case 16: |
|
1647 v = VGA_DRAW_LINE16; |
|
1648 bits = 16; |
|
1649 break; |
|
1650 case 24: |
|
1651 v = VGA_DRAW_LINE24; |
|
1652 bits = 24; |
|
1653 break; |
|
1654 case 32: |
|
1655 v = VGA_DRAW_LINE32; |
|
1656 bits = 32; |
|
1657 break; |
|
1658 } |
|
1659 } |
|
1660 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; |
|
1661 |
|
1662 if (disp_width != s->last_width || |
|
1663 height != s->last_height) { |
|
1664 gui_resize_vt(s->ds, disp_width, height); |
|
1665 s->last_scr_width = disp_width; |
|
1666 s->last_scr_height = height; |
|
1667 s->last_width = disp_width; |
|
1668 s->last_height = height; |
|
1669 full_update = 1; |
|
1670 } |
|
1671 if (s->cursor_invalidate) |
|
1672 s->cursor_invalidate(s); |
|
1673 |
|
1674 line_offset = s->line_offset; |
|
1675 #if 0 |
|
1676 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", |
|
1677 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); |
|
1678 #endif |
|
1679 addr1 = (s->start_addr * 4); |
|
1680 bwidth = (width * bits + 7) / 8; |
|
1681 y_start = -1; |
|
1682 page_min = 0x7fffffff; |
|
1683 page_max = -1; |
|
1684 d = ds_get_data(s->ds); |
|
1685 linesize = ds_get_linesize(s->ds); |
|
1686 y1 = 0; |
|
1687 for(y = 0; y < height; y++) { |
|
1688 addr = addr1; |
|
1689 if (!(s->cr[0x17] & 1)) { |
|
1690 int shift; |
|
1691 /* CGA compatibility handling */ |
|
1692 shift = 14 + ((s->cr[0x17] >> 6) & 1); |
|
1693 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); |
|
1694 } |
|
1695 if (!(s->cr[0x17] & 2)) { |
|
1696 addr = (addr & ~0x8000) | ((y1 & 2) << 14); |
|
1697 } |
|
1698 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK); |
|
1699 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK); |
|
1700 update = full_update | |
|
1701 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) | |
|
1702 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG); |
|
1703 if ((page1 - page0) > TARGET_PAGE_SIZE) { |
|
1704 /* if wide line, can use another page */ |
|
1705 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, |
|
1706 VGA_DIRTY_FLAG); |
|
1707 } |
|
1708 /* explicit invalidation for the hardware cursor */ |
|
1709 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; |
|
1710 if (update) { |
|
1711 if (y_start < 0) |
|
1712 y_start = y; |
|
1713 if (page0 < page_min) |
|
1714 page_min = page0; |
|
1715 if (page1 > page_max) |
|
1716 page_max = page1; |
|
1717 vga_draw_line(s, d, s->vram_ptr + addr, width); |
|
1718 if (s->cursor_draw_line) |
|
1719 s->cursor_draw_line(s, d, y); |
|
1720 } else { |
|
1721 if (y_start >= 0) { |
|
1722 /* flush to display */ |
|
1723 dpy_update(s->ds, 0, y_start, |
|
1724 disp_width, y - y_start); |
|
1725 y_start = -1; |
|
1726 } |
|
1727 } |
|
1728 if (!multi_run) { |
|
1729 mask = (s->cr[0x17] & 3) ^ 3; |
|
1730 if ((y1 & mask) == mask) |
|
1731 addr1 += line_offset; |
|
1732 y1++; |
|
1733 multi_run = multi_scan; |
|
1734 } else { |
|
1735 multi_run--; |
|
1736 } |
|
1737 /* line compare acts on the displayed lines */ |
|
1738 if (y == s->line_compare) |
|
1739 addr1 = 0; |
|
1740 d += linesize; |
|
1741 } |
|
1742 if (y_start >= 0) { |
|
1743 /* flush to display */ |
|
1744 dpy_update(s->ds, 0, y_start, |
|
1745 disp_width, y - y_start); |
|
1746 } |
|
1747 /* reset modified pages */ |
|
1748 if (page_max != -1) { |
|
1749 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, |
|
1750 VGA_DIRTY_FLAG); |
|
1751 } |
|
1752 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); |
|
1753 } |
|
1754 |
|
1755 static void vga_draw_blank(VGAState *s, int full_update) |
|
1756 { |
|
1757 int i, w, val; |
|
1758 uint8_t *d; |
|
1759 |
|
1760 if (!full_update) |
|
1761 return; |
|
1762 if (s->last_scr_width <= 0 || s->last_scr_height <= 0) |
|
1763 return; |
|
1764 vga_dirty_log_stop(s); |
|
1765 |
|
1766 if (ds_get_bits_per_pixel(s->ds) == 8) |
|
1767 val = s->rgb_to_pixel(0, 0, 0); |
|
1768 else |
|
1769 val = 0; |
|
1770 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); |
|
1771 d = ds_get_data(s->ds); |
|
1772 for(i = 0; i < s->last_scr_height; i++) { |
|
1773 memset(d, val, w); |
|
1774 d += ds_get_linesize(s->ds); |
|
1775 } |
|
1776 dpy_update(s->ds, 0, 0, |
|
1777 s->last_scr_width, s->last_scr_height); |
|
1778 } |
|
1779 |
|
1780 #define GMODE_TEXT 0 |
|
1781 #define GMODE_GRAPH 1 |
|
1782 #define GMODE_BLANK 2 |
|
1783 |
|
1784 static void vga_update_display(void *opaque) |
|
1785 { |
|
1786 VGAState *s = (VGAState *)opaque; |
|
1787 int full_update, graphic_mode; |
|
1788 |
|
1789 if (ds_get_bits_per_pixel(s->ds) == 0) { |
|
1790 /* nothing to do */ |
|
1791 } else { |
|
1792 s->rgb_to_pixel = |
|
1793 rgb_to_pixel_dup_table[get_depth_index(s->ds)]; |
|
1794 |
|
1795 full_update = 0; |
|
1796 if (!(s->ar_index & 0x20)) { |
|
1797 graphic_mode = GMODE_BLANK; |
|
1798 } else { |
|
1799 graphic_mode = s->gr[6] & 1; |
|
1800 } |
|
1801 if (graphic_mode != s->graphic_mode) { |
|
1802 s->graphic_mode = graphic_mode; |
|
1803 full_update = 1; |
|
1804 } |
|
1805 switch(graphic_mode) { |
|
1806 case GMODE_TEXT: |
|
1807 vga_draw_text(s, full_update); |
|
1808 break; |
|
1809 case GMODE_GRAPH: |
|
1810 vga_draw_graphic(s, full_update); |
|
1811 break; |
|
1812 case GMODE_BLANK: |
|
1813 default: |
|
1814 vga_draw_blank(s, full_update); |
|
1815 break; |
|
1816 } |
|
1817 } |
|
1818 } |
|
1819 |
|
1820 /* force a full display refresh */ |
|
1821 static void vga_invalidate_display(void *opaque) |
|
1822 { |
|
1823 VGAState *s = (VGAState *)opaque; |
|
1824 |
|
1825 s->last_width = -1; |
|
1826 s->last_height = -1; |
|
1827 } |
|
1828 |
|
1829 static void vga_reset(VGAState *s) |
|
1830 { |
|
1831 memset(s, 0, sizeof(VGAState)); |
|
1832 s->graphic_mode = -1; /* force full update */ |
|
1833 } |
|
1834 |
|
1835 #define TEXTMODE_X(x) ((x) % width) |
|
1836 #define TEXTMODE_Y(x) ((x) / width) |
|
1837 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ |
|
1838 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) |
|
1839 /* relay text rendering to the display driver |
|
1840 * instead of doing a full vga_update_display() */ |
|
1841 static void vga_update_text(void *opaque, console_ch_t *chardata) |
|
1842 { |
|
1843 VGAState *s = (VGAState *) opaque; |
|
1844 int graphic_mode, i, cursor_offset, cursor_visible; |
|
1845 int cw, cheight, width, height, size, c_min, c_max; |
|
1846 uint32_t *src; |
|
1847 console_ch_t *dst, val; |
|
1848 char msg_buffer[80]; |
|
1849 int full_update = 0; |
|
1850 |
|
1851 if (!(s->ar_index & 0x20)) { |
|
1852 graphic_mode = GMODE_BLANK; |
|
1853 } else { |
|
1854 graphic_mode = s->gr[6] & 1; |
|
1855 } |
|
1856 if (graphic_mode != s->graphic_mode) { |
|
1857 s->graphic_mode = graphic_mode; |
|
1858 full_update = 1; |
|
1859 } |
|
1860 if (s->last_width == -1) { |
|
1861 s->last_width = 0; |
|
1862 full_update = 1; |
|
1863 } |
|
1864 |
|
1865 switch (graphic_mode) { |
|
1866 case GMODE_TEXT: |
|
1867 /* TODO: update palette */ |
|
1868 full_update |= update_basic_params(s); |
|
1869 |
|
1870 /* total width & height */ |
|
1871 cheight = (s->cr[9] & 0x1f) + 1; |
|
1872 cw = 8; |
|
1873 if (!(s->sr[1] & 0x01)) |
|
1874 cw = 9; |
|
1875 if (s->sr[1] & 0x08) |
|
1876 cw = 16; /* NOTE: no 18 pixel wide */ |
|
1877 width = (s->cr[0x01] + 1); |
|
1878 if (s->cr[0x06] == 100) { |
|
1879 /* ugly hack for CGA 160x100x16 - explain me the logic */ |
|
1880 height = 100; |
|
1881 } else { |
|
1882 height = s->cr[0x12] | |
|
1883 ((s->cr[0x07] & 0x02) << 7) | |
|
1884 ((s->cr[0x07] & 0x40) << 3); |
|
1885 height = (height + 1) / cheight; |
|
1886 } |
|
1887 |
|
1888 size = (height * width); |
|
1889 if (size > CH_ATTR_SIZE) { |
|
1890 if (!full_update) |
|
1891 return; |
|
1892 |
|
1893 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode", |
|
1894 width, height); |
|
1895 break; |
|
1896 } |
|
1897 |
|
1898 if (width != s->last_width || height != s->last_height || |
|
1899 cw != s->last_cw || cheight != s->last_ch) { |
|
1900 s->last_scr_width = width * cw; |
|
1901 s->last_scr_height = height * cheight; |
|
1902 gui_resize_vt(s->ds, width, height); |
|
1903 s->last_width = width; |
|
1904 s->last_height = height; |
|
1905 s->last_ch = cheight; |
|
1906 s->last_cw = cw; |
|
1907 full_update = 1; |
|
1908 } |
|
1909 |
|
1910 /* Update "hardware" cursor */ |
|
1911 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; |
|
1912 if (cursor_offset != s->cursor_offset || |
|
1913 s->cr[0xa] != s->cursor_start || |
|
1914 s->cr[0xb] != s->cursor_end || full_update) { |
|
1915 cursor_visible = !(s->cr[0xa] & 0x20); |
|
1916 if (cursor_visible && cursor_offset < size && cursor_offset >= 0) |
|
1917 dpy_cursor(s->ds, |
|
1918 TEXTMODE_X(cursor_offset), |
|
1919 TEXTMODE_Y(cursor_offset)); |
|
1920 else |
|
1921 dpy_cursor(s->ds, -1, -1); |
|
1922 s->cursor_offset = cursor_offset; |
|
1923 s->cursor_start = s->cr[0xa]; |
|
1924 s->cursor_end = s->cr[0xb]; |
|
1925 } |
|
1926 |
|
1927 src = (uint32_t *) s->vram_ptr + s->start_addr; |
|
1928 dst = chardata; |
|
1929 |
|
1930 if (full_update) { |
|
1931 for (i = 0; i < size; src ++, dst ++, i ++) |
|
1932 console_write_ch(dst, VMEM2CHTYPE(*src)); |
|
1933 |
|
1934 dpy_update(s->ds, 0, 0, width, height); |
|
1935 } else { |
|
1936 c_max = 0; |
|
1937 |
|
1938 for (i = 0; i < size; src ++, dst ++, i ++) { |
|
1939 console_write_ch(&val, VMEM2CHTYPE(*src)); |
|
1940 if (*dst != val) { |
|
1941 *dst = val; |
|
1942 c_max = i; |
|
1943 break; |
|
1944 } |
|
1945 } |
|
1946 c_min = i; |
|
1947 for (; i < size; src ++, dst ++, i ++) { |
|
1948 console_write_ch(&val, VMEM2CHTYPE(*src)); |
|
1949 if (*dst != val) { |
|
1950 *dst = val; |
|
1951 c_max = i; |
|
1952 } |
|
1953 } |
|
1954 |
|
1955 if (c_min <= c_max) { |
|
1956 i = TEXTMODE_Y(c_min); |
|
1957 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); |
|
1958 } |
|
1959 } |
|
1960 |
|
1961 return; |
|
1962 case GMODE_GRAPH: |
|
1963 if (!full_update) |
|
1964 return; |
|
1965 |
|
1966 s->get_resolution(s, &width, &height); |
|
1967 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode", |
|
1968 width, height); |
|
1969 break; |
|
1970 case GMODE_BLANK: |
|
1971 default: |
|
1972 if (!full_update) |
|
1973 return; |
|
1974 |
|
1975 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode"); |
|
1976 break; |
|
1977 } |
|
1978 |
|
1979 /* Display a message */ |
|
1980 s->last_width = 60; |
|
1981 s->last_height = height = 3; |
|
1982 dpy_cursor(s->ds, -1, -1); |
|
1983 gui_resize_vt(s->ds, s->last_width, height); |
|
1984 |
|
1985 for (dst = chardata, i = 0; i < s->last_width * height; i ++) |
|
1986 console_write_ch(dst ++, ' '); |
|
1987 |
|
1988 size = strlen(msg_buffer); |
|
1989 width = (s->last_width - size) / 2; |
|
1990 dst = chardata + s->last_width + width; |
|
1991 for (i = 0; i < size; i ++) |
|
1992 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); |
|
1993 |
|
1994 dpy_update(s->ds, 0, 0, s->last_width, height); |
|
1995 } |
|
1996 |
|
1997 static CPUReadMemoryFunc *vga_mem_read[3] = { |
|
1998 vga_mem_readb, |
|
1999 vga_mem_readw, |
|
2000 vga_mem_readl, |
|
2001 }; |
|
2002 |
|
2003 static CPUWriteMemoryFunc *vga_mem_write[3] = { |
|
2004 vga_mem_writeb, |
|
2005 vga_mem_writew, |
|
2006 vga_mem_writel, |
|
2007 }; |
|
2008 |
|
2009 static void vga_save(QEMUFile *f, void *opaque) |
|
2010 { |
|
2011 VGAState *s = opaque; |
|
2012 int i; |
|
2013 |
|
2014 if (s->pci_dev) |
|
2015 pci_device_save(s->pci_dev, f); |
|
2016 |
|
2017 qemu_put_be32s(f, &s->latch); |
|
2018 qemu_put_8s(f, &s->sr_index); |
|
2019 qemu_put_buffer(f, s->sr, 8); |
|
2020 qemu_put_8s(f, &s->gr_index); |
|
2021 qemu_put_buffer(f, s->gr, 16); |
|
2022 qemu_put_8s(f, &s->ar_index); |
|
2023 qemu_put_buffer(f, s->ar, 21); |
|
2024 qemu_put_be32(f, s->ar_flip_flop); |
|
2025 qemu_put_8s(f, &s->cr_index); |
|
2026 qemu_put_buffer(f, s->cr, 256); |
|
2027 qemu_put_8s(f, &s->msr); |
|
2028 qemu_put_8s(f, &s->fcr); |
|
2029 qemu_put_byte(f, s->st00); |
|
2030 qemu_put_8s(f, &s->st01); |
|
2031 |
|
2032 qemu_put_8s(f, &s->dac_state); |
|
2033 qemu_put_8s(f, &s->dac_sub_index); |
|
2034 qemu_put_8s(f, &s->dac_read_index); |
|
2035 qemu_put_8s(f, &s->dac_write_index); |
|
2036 qemu_put_buffer(f, s->dac_cache, 3); |
|
2037 qemu_put_buffer(f, s->palette, 768); |
|
2038 |
|
2039 qemu_put_be32(f, s->bank_offset); |
|
2040 #ifdef CONFIG_BOCHS_VBE |
|
2041 qemu_put_byte(f, 1); |
|
2042 qemu_put_be16s(f, &s->vbe_index); |
|
2043 for(i = 0; i < VBE_DISPI_INDEX_NB; i++) |
|
2044 qemu_put_be16s(f, &s->vbe_regs[i]); |
|
2045 qemu_put_be32s(f, &s->vbe_start_addr); |
|
2046 qemu_put_be32s(f, &s->vbe_line_offset); |
|
2047 qemu_put_be32s(f, &s->vbe_bank_mask); |
|
2048 #else |
|
2049 qemu_put_byte(f, 0); |
|
2050 #endif |
|
2051 } |
|
2052 |
|
2053 static int vga_load(QEMUFile *f, void *opaque, int version_id) |
|
2054 { |
|
2055 VGAState *s = opaque; |
|
2056 int is_vbe, i, ret; |
|
2057 |
|
2058 if (version_id > 2) |
|
2059 return -EINVAL; |
|
2060 |
|
2061 if (s->pci_dev && version_id >= 2) { |
|
2062 ret = pci_device_load(s->pci_dev, f); |
|
2063 if (ret < 0) |
|
2064 return ret; |
|
2065 } |
|
2066 |
|
2067 qemu_get_be32s(f, &s->latch); |
|
2068 qemu_get_8s(f, &s->sr_index); |
|
2069 qemu_get_buffer(f, s->sr, 8); |
|
2070 qemu_get_8s(f, &s->gr_index); |
|
2071 qemu_get_buffer(f, s->gr, 16); |
|
2072 qemu_get_8s(f, &s->ar_index); |
|
2073 qemu_get_buffer(f, s->ar, 21); |
|
2074 s->ar_flip_flop=qemu_get_be32(f); |
|
2075 qemu_get_8s(f, &s->cr_index); |
|
2076 qemu_get_buffer(f, s->cr, 256); |
|
2077 qemu_get_8s(f, &s->msr); |
|
2078 qemu_get_8s(f, &s->fcr); |
|
2079 qemu_get_8s(f, &s->st00); |
|
2080 qemu_get_8s(f, &s->st01); |
|
2081 |
|
2082 qemu_get_8s(f, &s->dac_state); |
|
2083 qemu_get_8s(f, &s->dac_sub_index); |
|
2084 qemu_get_8s(f, &s->dac_read_index); |
|
2085 qemu_get_8s(f, &s->dac_write_index); |
|
2086 qemu_get_buffer(f, s->dac_cache, 3); |
|
2087 qemu_get_buffer(f, s->palette, 768); |
|
2088 |
|
2089 s->bank_offset=qemu_get_be32(f); |
|
2090 is_vbe = qemu_get_byte(f); |
|
2091 #ifdef CONFIG_BOCHS_VBE |
|
2092 if (!is_vbe) |
|
2093 return -EINVAL; |
|
2094 qemu_get_be16s(f, &s->vbe_index); |
|
2095 for(i = 0; i < VBE_DISPI_INDEX_NB; i++) |
|
2096 qemu_get_be16s(f, &s->vbe_regs[i]); |
|
2097 qemu_get_be32s(f, &s->vbe_start_addr); |
|
2098 qemu_get_be32s(f, &s->vbe_line_offset); |
|
2099 qemu_get_be32s(f, &s->vbe_bank_mask); |
|
2100 #else |
|
2101 if (is_vbe) |
|
2102 return -EINVAL; |
|
2103 #endif |
|
2104 |
|
2105 /* force refresh */ |
|
2106 s->graphic_mode = -1; |
|
2107 return 0; |
|
2108 } |
|
2109 |
|
2110 typedef struct PCIVGAState { |
|
2111 PCIDevice dev; |
|
2112 VGAState vga_state; |
|
2113 } PCIVGAState; |
|
2114 |
|
2115 void vga_dirty_log_start(VGAState *s) |
|
2116 { |
|
2117 if (kvm_enabled() && s->map_addr) |
|
2118 kvm_log_start(s->map_addr, s->map_end - s->map_addr); |
|
2119 |
|
2120 if (kvm_enabled() && s->lfb_vram_mapped) { |
|
2121 kvm_log_start(isa_mem_base + 0xa0000, 0x8000); |
|
2122 kvm_log_start(isa_mem_base + 0xa8000, 0x8000); |
|
2123 } |
|
2124 } |
|
2125 |
|
2126 void vga_dirty_log_stop(VGAState *s) |
|
2127 { |
|
2128 if (kvm_enabled() && s->map_addr) |
|
2129 kvm_log_stop(s->map_addr, s->map_end - s->map_addr); |
|
2130 |
|
2131 if (kvm_enabled() && s->lfb_vram_mapped) { |
|
2132 kvm_log_stop(isa_mem_base + 0xa0000, 0x8000); |
|
2133 kvm_log_stop(isa_mem_base + 0xa8000, 0x8000); |
|
2134 } |
|
2135 } |
|
2136 |
|
2137 static void vga_map(PCIDevice *pci_dev, int region_num, |
|
2138 uint32_t addr, uint32_t size, int type) |
|
2139 { |
|
2140 PCIVGAState *d = (PCIVGAState *)pci_dev; |
|
2141 VGAState *s = &d->vga_state; |
|
2142 if (region_num == PCI_ROM_SLOT) { |
|
2143 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); |
|
2144 } else { |
|
2145 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); |
|
2146 } |
|
2147 |
|
2148 s->map_addr = addr; |
|
2149 s->map_end = addr + VGA_RAM_SIZE; |
|
2150 |
|
2151 vga_dirty_log_start(s); |
|
2152 } |
|
2153 |
|
2154 void vga_common_init(VGAState *s, /*DisplayState *ds, */uint8_t *vga_ram_base, |
|
2155 ram_addr_t vga_ram_offset, int vga_ram_size) |
|
2156 { |
|
2157 int i, j, v, b; |
|
2158 |
|
2159 for(i = 0;i < 256; i++) { |
|
2160 v = 0; |
|
2161 for(j = 0; j < 8; j++) { |
|
2162 v |= ((i >> j) & 1) << (j * 4); |
|
2163 } |
|
2164 expand4[i] = v; |
|
2165 |
|
2166 v = 0; |
|
2167 for(j = 0; j < 4; j++) { |
|
2168 v |= ((i >> (2 * j)) & 3) << (j * 4); |
|
2169 } |
|
2170 expand2[i] = v; |
|
2171 } |
|
2172 for(i = 0; i < 16; i++) { |
|
2173 v = 0; |
|
2174 for(j = 0; j < 4; j++) { |
|
2175 b = ((i >> j) & 1); |
|
2176 v |= b << (2 * j); |
|
2177 v |= b << (2 * j + 1); |
|
2178 } |
|
2179 expand4to8[i] = v; |
|
2180 } |
|
2181 |
|
2182 vga_reset(s); |
|
2183 |
|
2184 s->vram_ptr = vga_ram_base; |
|
2185 s->vram_offset = vga_ram_offset; |
|
2186 s->vram_size = vga_ram_size; |
|
2187 // s->ds = ds; |
|
2188 s->get_bpp = vga_get_bpp; |
|
2189 s->get_offsets = vga_get_offsets; |
|
2190 s->get_resolution = vga_get_resolution; |
|
2191 s->update = vga_update_display; |
|
2192 s->invalidate = vga_invalidate_display; |
|
2193 s->screen_dump = vga_screen_dump; |
|
2194 s->text_update = vga_update_text; |
|
2195 switch (vga_retrace_method) { |
|
2196 case VGA_RETRACE_DUMB: |
|
2197 s->retrace = vga_dumb_retrace; |
|
2198 s->update_retrace_info = vga_dumb_update_retrace_info; |
|
2199 break; |
|
2200 |
|
2201 case VGA_RETRACE_PRECISE: |
|
2202 s->retrace = vga_precise_retrace; |
|
2203 s->update_retrace_info = vga_precise_update_retrace_info; |
|
2204 memset(&s->retrace_info, 0, sizeof (s->retrace_info)); |
|
2205 break; |
|
2206 } |
|
2207 } |
|
2208 |
|
2209 /* used by both ISA and PCI */ |
|
2210 void vga_init(VGAState *s) |
|
2211 { |
|
2212 int vga_io_memory; |
|
2213 |
|
2214 register_savevm("vga", 0, 2, vga_save, vga_load, s); |
|
2215 |
|
2216 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); |
|
2217 |
|
2218 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); |
|
2219 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s); |
|
2220 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s); |
|
2221 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s); |
|
2222 |
|
2223 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s); |
|
2224 |
|
2225 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s); |
|
2226 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); |
|
2227 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); |
|
2228 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); |
|
2229 s->bank_offset = 0; |
|
2230 |
|
2231 #ifdef CONFIG_BOCHS_VBE |
|
2232 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; |
|
2233 s->vbe_bank_mask = ((s->vram_size >> 16) - 1); |
|
2234 #if defined (TARGET_I386) |
|
2235 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); |
|
2236 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s); |
|
2237 |
|
2238 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); |
|
2239 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s); |
|
2240 |
|
2241 /* old Bochs IO ports */ |
|
2242 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s); |
|
2243 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s); |
|
2244 |
|
2245 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s); |
|
2246 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); |
|
2247 #else |
|
2248 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); |
|
2249 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s); |
|
2250 |
|
2251 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); |
|
2252 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s); |
|
2253 #endif |
|
2254 #endif /* CONFIG_BOCHS_VBE */ |
|
2255 |
|
2256 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); |
|
2257 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, |
|
2258 vga_io_memory); |
|
2259 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000); |
|
2260 } |
|
2261 |
|
2262 /* Memory mapped interface */ |
|
2263 static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr) |
|
2264 { |
|
2265 VGAState *s = opaque; |
|
2266 |
|
2267 return vga_ioport_read(s, addr >> s->it_shift) & 0xff; |
|
2268 } |
|
2269 |
|
2270 static void vga_mm_writeb (void *opaque, |
|
2271 target_phys_addr_t addr, uint32_t value) |
|
2272 { |
|
2273 VGAState *s = opaque; |
|
2274 |
|
2275 vga_ioport_write(s, addr >> s->it_shift, value & 0xff); |
|
2276 } |
|
2277 |
|
2278 static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr) |
|
2279 { |
|
2280 VGAState *s = opaque; |
|
2281 |
|
2282 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff; |
|
2283 } |
|
2284 |
|
2285 static void vga_mm_writew (void *opaque, |
|
2286 target_phys_addr_t addr, uint32_t value) |
|
2287 { |
|
2288 VGAState *s = opaque; |
|
2289 |
|
2290 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff); |
|
2291 } |
|
2292 |
|
2293 static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr) |
|
2294 { |
|
2295 VGAState *s = opaque; |
|
2296 |
|
2297 return vga_ioport_read(s, addr >> s->it_shift); |
|
2298 } |
|
2299 |
|
2300 static void vga_mm_writel (void *opaque, |
|
2301 target_phys_addr_t addr, uint32_t value) |
|
2302 { |
|
2303 VGAState *s = opaque; |
|
2304 |
|
2305 vga_ioport_write(s, addr >> s->it_shift, value); |
|
2306 } |
|
2307 |
|
2308 static CPUReadMemoryFunc *vga_mm_read_ctrl[] = { |
|
2309 &vga_mm_readb, |
|
2310 &vga_mm_readw, |
|
2311 &vga_mm_readl, |
|
2312 }; |
|
2313 |
|
2314 static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = { |
|
2315 &vga_mm_writeb, |
|
2316 &vga_mm_writew, |
|
2317 &vga_mm_writel, |
|
2318 }; |
|
2319 |
|
2320 static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base, |
|
2321 target_phys_addr_t ctrl_base, int it_shift) |
|
2322 { |
|
2323 int s_ioport_ctrl, vga_io_memory; |
|
2324 |
|
2325 s->it_shift = it_shift; |
|
2326 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s); |
|
2327 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); |
|
2328 |
|
2329 register_savevm("vga", 0, 2, vga_save, vga_load, s); |
|
2330 |
|
2331 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl); |
|
2332 s->bank_offset = 0; |
|
2333 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory); |
|
2334 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000); |
|
2335 } |
|
2336 |
|
2337 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, |
|
2338 unsigned long vga_ram_offset, int vga_ram_size) |
|
2339 { |
|
2340 VGAState *s; |
|
2341 |
|
2342 s = qemu_mallocz(sizeof(VGAState)); |
|
2343 if (!s) |
|
2344 return -1; |
|
2345 |
|
2346 vga_common_init(s, /*ds,*/ vga_ram_base, vga_ram_offset, vga_ram_size); |
|
2347 vga_init(s); |
|
2348 |
|
2349 s->ds = gui_get_graphic_console(NULL, s->update, s->invalidate, |
|
2350 s->screen_dump, /*s->text_update,*/ s); /* DFG TODO */ |
|
2351 #ifdef CONFIG_BOCHS_VBE |
|
2352 /* XXX: use optimized standard vga accesses */ |
|
2353 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, |
|
2354 vga_ram_size, vga_ram_offset); |
|
2355 #endif |
|
2356 return 0; |
|
2357 } |
|
2358 |
|
2359 int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, |
|
2360 unsigned long vga_ram_offset, int vga_ram_size, |
|
2361 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, |
|
2362 int it_shift) |
|
2363 { |
|
2364 VGAState *s; |
|
2365 |
|
2366 s = qemu_mallocz(sizeof(VGAState)); |
|
2367 if (!s) |
|
2368 return -1; |
|
2369 |
|
2370 vga_common_init(s, /*ds,*/ vga_ram_base, vga_ram_offset, vga_ram_size); |
|
2371 vga_mm_init(s, vram_base, ctrl_base, it_shift); |
|
2372 |
|
2373 s->ds = gui_get_graphic_console(NULL, s->update, s->invalidate, |
|
2374 s->screen_dump, /* s->text_update,*/ s); /* TODO DFG */ |
|
2375 |
|
2376 #ifdef CONFIG_BOCHS_VBE |
|
2377 /* XXX: use optimized standard vga accesses */ |
|
2378 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, |
|
2379 vga_ram_size, vga_ram_offset); |
|
2380 #endif |
|
2381 return 0; |
|
2382 } |
|
2383 |
|
2384 int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, |
|
2385 unsigned long vga_ram_offset, int vga_ram_size, |
|
2386 unsigned long vga_bios_offset, int vga_bios_size) |
|
2387 { |
|
2388 PCIVGAState *d; |
|
2389 VGAState *s; |
|
2390 uint8_t *pci_conf; |
|
2391 |
|
2392 d = (PCIVGAState *)pci_register_device(bus, "VGA", |
|
2393 sizeof(PCIVGAState), |
|
2394 -1, NULL, NULL); |
|
2395 if (!d) |
|
2396 return -1; |
|
2397 s = &d->vga_state; |
|
2398 |
|
2399 vga_common_init(s, /*ds,*/ vga_ram_base, vga_ram_offset, vga_ram_size); |
|
2400 vga_init(s); |
|
2401 |
|
2402 s->ds = gui_get_graphic_console(NULL, s->update, s->invalidate, |
|
2403 s->screen_dump, /* s->text_update,*/ s); /* DFG TODO */ |
|
2404 |
|
2405 s->pci_dev = &d->dev; |
|
2406 |
|
2407 pci_conf = d->dev.config; |
|
2408 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) |
|
2409 pci_conf[0x01] = 0x12; |
|
2410 pci_conf[0x02] = 0x11; |
|
2411 pci_conf[0x03] = 0x11; |
|
2412 pci_conf[0x0a] = 0x00; // VGA controller |
|
2413 pci_conf[0x0b] = 0x03; |
|
2414 pci_conf[0x0e] = 0x00; // header_type |
|
2415 |
|
2416 /* XXX: vga_ram_size must be a power of two */ |
|
2417 pci_register_io_region(&d->dev, 0, vga_ram_size, |
|
2418 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); |
|
2419 if (vga_bios_size != 0) { |
|
2420 unsigned int bios_total_size; |
|
2421 s->bios_offset = vga_bios_offset; |
|
2422 s->bios_size = vga_bios_size; |
|
2423 /* must be a power of two */ |
|
2424 bios_total_size = 1; |
|
2425 while (bios_total_size < vga_bios_size) |
|
2426 bios_total_size <<= 1; |
|
2427 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, |
|
2428 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); |
|
2429 } |
|
2430 return 0; |
|
2431 } |
|
2432 |
|
2433 /********************************************************/ |
|
2434 /* vga screen dump */ |
|
2435 |
|
2436 static int vga_save_w, vga_save_h; |
|
2437 |
|
2438 static void vga_save_dpy_update(DisplayState *s, |
|
2439 int x, int y, int w, int h) |
|
2440 { |
|
2441 } |
|
2442 |
|
2443 #if 0 |
|
2444 DFG TODO |
|
2445 static void vga_save_dpy_resize(DisplayState *s, int w, int h) |
|
2446 { |
|
2447 s->linesize = w * 4; |
|
2448 s->data = qemu_mallocz(h * s->linesize); |
|
2449 vga_save_w = w; |
|
2450 vga_save_h = h; |
|
2451 } |
|
2452 |
|
2453 static void vga_save_dpy_refresh(DisplayState *s) |
|
2454 { |
|
2455 } |
|
2456 #endif |
|
2457 |
|
2458 int ppm_save(const char *filename, uint8_t *data, |
|
2459 int w, int h, int linesize) |
|
2460 { |
|
2461 FILE *f; |
|
2462 uint8_t *d, *d1; |
|
2463 unsigned int v; |
|
2464 int y, x; |
|
2465 |
|
2466 f = fopen(filename, "wb"); |
|
2467 if (!f) |
|
2468 return -1; |
|
2469 fprintf(f, "P6\n%d %d\n%d\n", |
|
2470 w, h, 255); |
|
2471 d1 = data; |
|
2472 for(y = 0; y < h; y++) { |
|
2473 d = d1; |
|
2474 for(x = 0; x < w; x++) { |
|
2475 v = *(uint32_t *)d; |
|
2476 fputc((v >> 16) & 0xff, f); |
|
2477 fputc((v >> 8) & 0xff, f); |
|
2478 fputc((v) & 0xff, f); |
|
2479 d += 4; |
|
2480 } |
|
2481 d1 += linesize; |
|
2482 } |
|
2483 fclose(f); |
|
2484 return 0; |
|
2485 } |
|
2486 |
|
2487 /* save the vga display in a PPM image even if no display is |
|
2488 available */ |
|
2489 static void vga_screen_dump(void *opaque, const char *filename) |
|
2490 { |
|
2491 #if 0 |
|
2492 DFG TODO |
|
2493 VGAState *s = (VGAState *)opaque; |
|
2494 DisplayState *saved_ds, ds1, *ds = &ds1; |
|
2495 |
|
2496 /* XXX: this is a little hackish */ |
|
2497 vga_invalidate_display(s); |
|
2498 saved_ds = s->ds; |
|
2499 |
|
2500 memset(ds, 0, sizeof(DisplayState)); |
|
2501 ds->dpy_update = vga_save_dpy_update; |
|
2502 #if 0 |
|
2503 DFG TODO |
|
2504 ds->dpy_resize = vga_save_dpy_resize; |
|
2505 ds->dpy_refresh = vga_save_dpy_refresh; |
|
2506 #endif |
|
2507 ds->depth = 32; |
|
2508 |
|
2509 s->ds = ds; |
|
2510 s->graphic_mode = -1; |
|
2511 vga_update_display(s); |
|
2512 |
|
2513 if (ds_get_data(ds)) { |
|
2514 ppm_save(filename, ds_get_data(ds), vga_save_w, vga_save_h, |
|
2515 ds_get_linesize(s->ds)); |
|
2516 qemu_free(ds_get_data(ds)); |
|
2517 } |
|
2518 s->ds = saved_ds; |
|
2519 #endif |
|
2520 } |
|
2521 |