ia64/xen-unstable

view tools/ioemu/hw/vga.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 06d84bf87159
line source
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 "vl.h"
25 #include "vga_int.h"
27 //#define DEBUG_VGA
28 //#define DEBUG_VGA_MEM
29 //#define DEBUG_VGA_REG
31 //#define DEBUG_S3
32 //#define DEBUG_BOCHS_VBE
34 /* S3 VGA is deprecated - another graphic card will be emulated */
35 //#define CONFIG_S3VGA
37 /* force some bits to zero */
38 const uint8_t sr_mask[8] = {
39 (uint8_t)~0xfc,
40 (uint8_t)~0xc2,
41 (uint8_t)~0xf0,
42 (uint8_t)~0xc0,
43 (uint8_t)~0xf1,
44 (uint8_t)~0xff,
45 (uint8_t)~0xff,
46 (uint8_t)~0x00,
47 };
49 const uint8_t gr_mask[16] = {
50 (uint8_t)~0xf0, /* 0x00 */
51 (uint8_t)~0xf0, /* 0x01 */
52 (uint8_t)~0xf0, /* 0x02 */
53 (uint8_t)~0xe0, /* 0x03 */
54 (uint8_t)~0xfc, /* 0x04 */
55 (uint8_t)~0x84, /* 0x05 */
56 (uint8_t)~0xf0, /* 0x06 */
57 (uint8_t)~0xf0, /* 0x07 */
58 (uint8_t)~0x00, /* 0x08 */
59 (uint8_t)~0xff, /* 0x09 */
60 (uint8_t)~0xff, /* 0x0a */
61 (uint8_t)~0xff, /* 0x0b */
62 (uint8_t)~0xff, /* 0x0c */
63 (uint8_t)~0xff, /* 0x0d */
64 (uint8_t)~0xff, /* 0x0e */
65 (uint8_t)~0xff, /* 0x0f */
66 };
68 #define cbswap_32(__x) \
69 ((uint32_t)( \
70 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
71 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
72 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
73 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75 #ifdef WORDS_BIGENDIAN
76 #define PAT(x) cbswap_32(x)
77 #else
78 #define PAT(x) (x)
79 #endif
81 #ifdef WORDS_BIGENDIAN
82 #define BIG 1
83 #else
84 #define BIG 0
85 #endif
87 #ifdef WORDS_BIGENDIAN
88 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
89 #else
90 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
91 #endif
93 static const uint32_t mask16[16] = {
94 PAT(0x00000000),
95 PAT(0x000000ff),
96 PAT(0x0000ff00),
97 PAT(0x0000ffff),
98 PAT(0x00ff0000),
99 PAT(0x00ff00ff),
100 PAT(0x00ffff00),
101 PAT(0x00ffffff),
102 PAT(0xff000000),
103 PAT(0xff0000ff),
104 PAT(0xff00ff00),
105 PAT(0xff00ffff),
106 PAT(0xffff0000),
107 PAT(0xffff00ff),
108 PAT(0xffffff00),
109 PAT(0xffffffff),
110 };
112 #undef PAT
114 #ifdef WORDS_BIGENDIAN
115 #define PAT(x) (x)
116 #else
117 #define PAT(x) cbswap_32(x)
118 #endif
120 static const uint32_t dmask16[16] = {
121 PAT(0x00000000),
122 PAT(0x000000ff),
123 PAT(0x0000ff00),
124 PAT(0x0000ffff),
125 PAT(0x00ff0000),
126 PAT(0x00ff00ff),
127 PAT(0x00ffff00),
128 PAT(0x00ffffff),
129 PAT(0xff000000),
130 PAT(0xff0000ff),
131 PAT(0xff00ff00),
132 PAT(0xff00ffff),
133 PAT(0xffff0000),
134 PAT(0xffff00ff),
135 PAT(0xffffff00),
136 PAT(0xffffffff),
137 };
139 static const uint32_t dmask4[4] = {
140 PAT(0x00000000),
141 PAT(0x0000ffff),
142 PAT(0xffff0000),
143 PAT(0xffffffff),
144 };
146 static uint32_t expand4[256];
147 static uint16_t expand2[256];
148 static uint8_t expand4to8[16];
150 VGAState *vga_state;
151 int vga_io_memory;
153 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
154 {
155 VGAState *s = opaque;
156 int val, index;
158 /* check port range access depending on color/monochrome mode */
159 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
160 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
161 val = 0xff;
162 } else {
163 switch(addr) {
164 case 0x3c0:
165 if (s->ar_flip_flop == 0) {
166 val = s->ar_index;
167 } else {
168 val = 0;
169 }
170 break;
171 case 0x3c1:
172 index = s->ar_index & 0x1f;
173 if (index < 21)
174 val = s->ar[index];
175 else
176 val = 0;
177 break;
178 case 0x3c2:
179 val = s->st00;
180 break;
181 case 0x3c4:
182 val = s->sr_index;
183 break;
184 case 0x3c5:
185 val = s->sr[s->sr_index];
186 #ifdef DEBUG_VGA_REG
187 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
188 #endif
189 break;
190 case 0x3c7:
191 val = s->dac_state;
192 break;
193 case 0x3c8:
194 val = s->dac_write_index;
195 break;
196 case 0x3c9:
197 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
198 if (++s->dac_sub_index == 3) {
199 s->dac_sub_index = 0;
200 s->dac_read_index++;
201 }
202 break;
203 case 0x3ca:
204 val = s->fcr;
205 break;
206 case 0x3cc:
207 val = s->msr;
208 break;
209 case 0x3ce:
210 val = s->gr_index;
211 break;
212 case 0x3cf:
213 val = s->gr[s->gr_index];
214 #ifdef DEBUG_VGA_REG
215 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
216 #endif
217 break;
218 case 0x3b4:
219 case 0x3d4:
220 val = s->cr_index;
221 break;
222 case 0x3b5:
223 case 0x3d5:
224 val = s->cr[s->cr_index];
225 #ifdef DEBUG_VGA_REG
226 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
227 #endif
228 #ifdef DEBUG_S3
229 if (s->cr_index >= 0x20)
230 printf("S3: CR read index=0x%x val=0x%x\n",
231 s->cr_index, val);
232 #endif
233 break;
234 case 0x3ba:
235 case 0x3da:
236 /* just toggle to fool polling */
237 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
238 val = s->st01;
239 s->ar_flip_flop = 0;
240 break;
241 default:
242 val = 0x00;
243 break;
244 }
245 }
246 #if defined(DEBUG_VGA)
247 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
248 #endif
249 return val;
250 }
252 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
253 {
254 VGAState *s = opaque;
255 int index;
257 /* check port range access depending on color/monochrome mode */
258 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
259 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
260 return;
262 #ifdef DEBUG_VGA
263 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
264 #endif
266 switch(addr) {
267 case 0x3c0:
268 if (s->ar_flip_flop == 0) {
269 val &= 0x3f;
270 s->ar_index = val;
271 } else {
272 index = s->ar_index & 0x1f;
273 switch(index) {
274 case 0x00 ... 0x0f:
275 s->ar[index] = val & 0x3f;
276 break;
277 case 0x10:
278 s->ar[index] = val & ~0x10;
279 break;
280 case 0x11:
281 s->ar[index] = val;
282 break;
283 case 0x12:
284 s->ar[index] = val & ~0xc0;
285 break;
286 case 0x13:
287 s->ar[index] = val & ~0xf0;
288 break;
289 case 0x14:
290 s->ar[index] = val & ~0xf0;
291 break;
292 default:
293 break;
294 }
295 }
296 s->ar_flip_flop ^= 1;
297 break;
298 case 0x3c2:
299 s->msr = val & ~0x10;
300 break;
301 case 0x3c4:
302 s->sr_index = val & 7;
303 break;
304 case 0x3c5:
305 #ifdef DEBUG_VGA_REG
306 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
307 #endif
308 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
309 break;
310 case 0x3c7:
311 s->dac_read_index = val;
312 s->dac_sub_index = 0;
313 s->dac_state = 3;
314 break;
315 case 0x3c8:
316 s->dac_write_index = val;
317 s->dac_sub_index = 0;
318 s->dac_state = 0;
319 break;
320 case 0x3c9:
321 s->dac_cache[s->dac_sub_index] = val;
322 if (++s->dac_sub_index == 3) {
323 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
324 s->dac_sub_index = 0;
325 s->dac_write_index++;
326 }
327 break;
328 case 0x3ce:
329 s->gr_index = val & 0x0f;
330 break;
331 case 0x3cf:
332 #ifdef DEBUG_VGA_REG
333 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
334 #endif
335 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
336 break;
337 case 0x3b4:
338 case 0x3d4:
339 s->cr_index = val;
340 break;
341 case 0x3b5:
342 case 0x3d5:
343 #ifdef DEBUG_VGA_REG
344 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
345 #endif
346 /* handle CR0-7 protection */
347 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
348 /* can always write bit 4 of CR7 */
349 if (s->cr_index == 7)
350 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
351 return;
352 }
353 switch(s->cr_index) {
354 case 0x01: /* horizontal display end */
355 case 0x07:
356 case 0x09:
357 case 0x0c:
358 case 0x0d:
359 case 0x12: /* veritcal display end */
360 s->cr[s->cr_index] = val;
361 break;
363 #ifdef CONFIG_S3VGA
364 /* S3 registers */
365 case 0x2d:
366 case 0x2e:
367 case 0x2f:
368 case 0x30:
369 /* chip ID, cannot write */
370 break;
371 case 0x31:
372 /* update start address */
373 {
374 int v;
375 s->cr[s->cr_index] = val;
376 v = (val >> 4) & 3;
377 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
378 }
379 break;
380 case 0x51:
381 /* update start address */
382 {
383 int v;
384 s->cr[s->cr_index] = val;
385 v = val & 3;
386 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
387 }
388 break;
389 #endif
390 default:
391 s->cr[s->cr_index] = val;
392 break;
393 }
394 #ifdef DEBUG_S3
395 if (s->cr_index >= 0x20)
396 printf("S3: CR write index=0x%x val=0x%x\n",
397 s->cr_index, val);
398 #endif
399 break;
400 case 0x3ba:
401 case 0x3da:
402 s->fcr = val & 0x10;
403 break;
404 }
405 }
407 #ifdef CONFIG_BOCHS_VBE
408 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
409 {
410 VGAState *s = opaque;
411 uint32_t val;
412 val = s->vbe_index;
413 return val;
414 }
416 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
417 {
418 VGAState *s = opaque;
419 uint32_t val;
421 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
422 val = s->vbe_regs[s->vbe_index];
423 else
424 val = 0;
425 #ifdef DEBUG_BOCHS_VBE
426 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
427 #endif
428 return val;
429 }
431 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
432 {
433 VGAState *s = opaque;
434 s->vbe_index = val;
435 }
437 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
438 {
439 VGAState *s = opaque;
441 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
442 #ifdef DEBUG_BOCHS_VBE
443 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
444 #endif
445 switch(s->vbe_index) {
446 case VBE_DISPI_INDEX_ID:
447 if (val == VBE_DISPI_ID0 ||
448 val == VBE_DISPI_ID1 ||
449 val == VBE_DISPI_ID2) {
450 s->vbe_regs[s->vbe_index] = val;
451 }
452 break;
453 case VBE_DISPI_INDEX_XRES:
454 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
455 s->vbe_regs[s->vbe_index] = val;
456 }
457 break;
458 case VBE_DISPI_INDEX_YRES:
459 if (val <= VBE_DISPI_MAX_YRES) {
460 s->vbe_regs[s->vbe_index] = val;
461 }
462 break;
463 case VBE_DISPI_INDEX_BPP:
464 if (val == 0)
465 val = 8;
466 if (val == 4 || val == 8 || val == 15 ||
467 val == 16 || val == 24 || val == 32) {
468 s->vbe_regs[s->vbe_index] = val;
469 }
470 break;
471 case VBE_DISPI_INDEX_BANK:
472 val &= s->vbe_bank_mask;
473 s->vbe_regs[s->vbe_index] = val;
474 s->bank_offset = (val << 16);
475 break;
476 case VBE_DISPI_INDEX_ENABLE:
477 if (val & VBE_DISPI_ENABLED) {
478 int h, shift_control;
480 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
481 s->vbe_regs[VBE_DISPI_INDEX_XRES];
482 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
483 s->vbe_regs[VBE_DISPI_INDEX_YRES];
484 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
485 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
487 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
488 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
489 else
490 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
491 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
492 s->vbe_start_addr = 0;
494 /* clear the screen (should be done in BIOS) */
495 if (!(val & VBE_DISPI_NOCLEARMEM)) {
496 memset(s->vram_ptr, 0,
497 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
498 }
500 /* we initialize the VGA graphic mode (should be done
501 in BIOS) */
502 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
503 s->cr[0x17] |= 3; /* no CGA modes */
504 s->cr[0x13] = s->vbe_line_offset >> 3;
505 /* width */
506 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
507 /* height */
508 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
509 s->cr[0x12] = h;
510 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
511 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
512 /* line compare to 1023 */
513 s->cr[0x18] = 0xff;
514 s->cr[0x07] |= 0x10;
515 s->cr[0x09] |= 0x40;
517 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
518 shift_control = 0;
519 s->sr[0x01] &= ~8; /* no double line */
520 } else {
521 shift_control = 2;
522 s->sr[4] |= 0x08; /* set chain 4 mode */
523 s->sr[2] |= 0x0f; /* activate all planes */
524 }
525 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
526 s->cr[0x09] &= ~0x9f; /* no double scan */
527 } else {
528 /* XXX: the bios should do that */
529 s->bank_offset = 0;
530 }
531 s->vbe_regs[s->vbe_index] = val;
532 break;
533 case VBE_DISPI_INDEX_VIRT_WIDTH:
534 {
535 int w, h, line_offset;
537 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
538 return;
539 w = val;
540 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
541 line_offset = w >> 1;
542 else
543 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
544 h = s->vram_size / line_offset;
545 /* XXX: support weird bochs semantics ? */
546 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
547 return;
548 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
549 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
550 s->vbe_line_offset = line_offset;
551 }
552 break;
553 case VBE_DISPI_INDEX_X_OFFSET:
554 case VBE_DISPI_INDEX_Y_OFFSET:
555 {
556 int x;
557 s->vbe_regs[s->vbe_index] = val;
558 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
559 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
560 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
561 s->vbe_start_addr += x >> 1;
562 else
563 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
564 s->vbe_start_addr >>= 2;
565 }
566 break;
567 default:
568 break;
569 }
570 }
571 }
572 #endif
574 extern FILE *logfile;
575 /* called for accesses between 0xa0000 and 0xc0000 */
576 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
577 {
578 VGAState *s = opaque;
579 int memory_map_mode, plane;
580 uint32_t ret;
582 /* convert to VGA memory offset */
583 memory_map_mode = (s->gr[6] >> 2) & 3;
584 addr &= 0x1ffff;
585 switch(memory_map_mode) {
586 case 0:
587 break;
588 case 1:
589 if (addr >= 0x10000)
590 return 0xff;
591 addr += s->bank_offset;
592 break;
593 case 2:
594 addr -= 0x10000;
595 if (addr >= 0x8000)
596 return 0xff;
597 break;
598 default:
599 case 3:
600 addr -= 0x18000;
601 if (addr >= 0x8000)
602 return 0xff;
603 break;
604 }
606 if (s->sr[4] & 0x08) {
607 /* chain 4 mode : simplest access */
608 ret = s->vram_ptr[addr];
609 } else if (s->gr[5] & 0x10) {
610 /* odd/even mode (aka text mode mapping) */
611 plane = (s->gr[4] & 2) | (addr & 1);
612 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
613 } else {
614 /* standard VGA latched access */
615 s->latch = ((uint32_t *)s->vram_ptr)[addr];
617 if (!(s->gr[5] & 0x08)) {
618 /* read mode 0 */
619 plane = s->gr[4];
620 ret = GET_PLANE(s->latch, plane);
621 } else {
622 /* read mode 1 */
623 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
624 ret |= ret >> 16;
625 ret |= ret >> 8;
626 ret = (~ret) & 0xff;
627 }
628 }
629 return ret;
630 }
632 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
633 {
634 uint32_t v;
635 #ifdef TARGET_WORDS_BIGENDIAN
636 v = vga_mem_readb(opaque, addr) << 8;
637 v |= vga_mem_readb(opaque, addr + 1);
638 #else
639 v = vga_mem_readb(opaque, addr);
640 v |= vga_mem_readb(opaque, addr + 1) << 8;
641 #endif
642 return v;
643 }
645 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
646 {
647 uint32_t v;
648 #ifdef TARGET_WORDS_BIGENDIAN
649 v = vga_mem_readb(opaque, addr) << 24;
650 v |= vga_mem_readb(opaque, addr + 1) << 16;
651 v |= vga_mem_readb(opaque, addr + 2) << 8;
652 v |= vga_mem_readb(opaque, addr + 3);
653 #else
654 v = vga_mem_readb(opaque, addr);
655 v |= vga_mem_readb(opaque, addr + 1) << 8;
656 v |= vga_mem_readb(opaque, addr + 2) << 16;
657 v |= vga_mem_readb(opaque, addr + 3) << 24;
658 #endif
659 return v;
660 }
662 /* called for accesses between 0xa0000 and 0xc0000 */
663 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
664 {
665 VGAState *s = opaque;
666 int memory_map_mode, plane, write_mode, b, func_select, mask;
667 uint32_t write_mask, bit_mask, set_mask;
669 #ifdef DEBUG_VGA_MEM
670 printf("vga: [0x%x] = 0x%02x\n", addr, val);
671 #endif
672 /* convert to VGA memory offset */
673 memory_map_mode = (s->gr[6] >> 2) & 3;
674 addr &= 0x1ffff;
675 switch(memory_map_mode) {
676 case 0:
677 break;
678 case 1:
679 if (addr >= 0x10000)
680 return;
681 addr += s->bank_offset;
682 break;
683 case 2:
684 addr -= 0x10000;
685 if (addr >= 0x8000)
686 return;
687 break;
688 default:
689 case 3:
690 addr -= 0x18000;
691 if (addr >= 0x8000)
692 return;
693 break;
694 }
696 if (s->sr[4] & 0x08) {
697 /* chain 4 mode : simplest access */
698 plane = addr & 3;
699 mask = (1 << plane);
700 if (s->sr[2] & mask) {
701 s->vram_ptr[addr] = val;
702 #ifdef DEBUG_VGA_MEM
703 printf("vga: chain4: [0x%x]\n", addr);
704 #endif
705 s->plane_updated |= mask; /* only used to detect font change */
706 cpu_physical_memory_set_dirty(s->vram_offset + addr);
707 }
708 } else if (s->gr[5] & 0x10) {
709 /* odd/even mode (aka text mode mapping) */
710 plane = (s->gr[4] & 2) | (addr & 1);
711 mask = (1 << plane);
712 if (s->sr[2] & mask) {
713 addr = ((addr & ~1) << 1) | plane;
714 s->vram_ptr[addr] = val;
715 #ifdef DEBUG_VGA_MEM
716 printf("vga: odd/even: [0x%x]\n", addr);
717 #endif
718 s->plane_updated |= mask; /* only used to detect font change */
719 cpu_physical_memory_set_dirty(s->vram_offset + addr);
720 }
721 } else {
722 /* standard VGA latched access */
723 write_mode = s->gr[5] & 3;
724 switch(write_mode) {
725 default:
726 case 0:
727 /* rotate */
728 b = s->gr[3] & 7;
729 val = ((val >> b) | (val << (8 - b))) & 0xff;
730 val |= val << 8;
731 val |= val << 16;
733 /* apply set/reset mask */
734 set_mask = mask16[s->gr[1]];
735 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
736 bit_mask = s->gr[8];
737 break;
738 case 1:
739 val = s->latch;
740 goto do_write;
741 case 2:
742 val = mask16[val & 0x0f];
743 bit_mask = s->gr[8];
744 break;
745 case 3:
746 /* rotate */
747 b = s->gr[3] & 7;
748 val = (val >> b) | (val << (8 - b));
750 bit_mask = s->gr[8] & val;
751 val = mask16[s->gr[0]];
752 break;
753 }
755 /* apply logical operation */
756 func_select = s->gr[3] >> 3;
757 switch(func_select) {
758 case 0:
759 default:
760 /* nothing to do */
761 break;
762 case 1:
763 /* and */
764 val &= s->latch;
765 break;
766 case 2:
767 /* or */
768 val |= s->latch;
769 break;
770 case 3:
771 /* xor */
772 val ^= s->latch;
773 break;
774 }
776 /* apply bit mask */
777 bit_mask |= bit_mask << 8;
778 bit_mask |= bit_mask << 16;
779 val = (val & bit_mask) | (s->latch & ~bit_mask);
781 do_write:
782 /* mask data according to sr[2] */
783 mask = s->sr[2];
784 s->plane_updated |= mask; /* only used to detect font change */
785 write_mask = mask16[mask];
786 ((uint32_t *)s->vram_ptr)[addr] =
787 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
788 (val & write_mask);
789 #ifdef DEBUG_VGA_MEM
790 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
791 addr * 4, write_mask, val);
792 #endif
793 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
794 }
795 }
797 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
798 {
799 #ifdef TARGET_WORDS_BIGENDIAN
800 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
801 vga_mem_writeb(opaque, addr + 1, val & 0xff);
802 #else
803 vga_mem_writeb(opaque, addr, val & 0xff);
804 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
805 #endif
806 }
808 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
809 {
810 #ifdef TARGET_WORDS_BIGENDIAN
811 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
812 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
813 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
814 vga_mem_writeb(opaque, addr + 3, val & 0xff);
815 #else
816 vga_mem_writeb(opaque, addr, val & 0xff);
817 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
818 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
819 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
820 #endif
821 }
823 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
824 const uint8_t *font_ptr, int h,
825 uint32_t fgcol, uint32_t bgcol);
826 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
827 const uint8_t *font_ptr, int h,
828 uint32_t fgcol, uint32_t bgcol, int dup9);
829 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
830 const uint8_t *s, int width);
832 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
833 {
834 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
835 }
837 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
838 {
839 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
840 }
842 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
843 {
844 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
845 }
847 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
848 {
849 return (r << 16) | (g << 8) | b;
850 }
852 #define DEPTH 8
853 #include "vga_template.h"
855 #define DEPTH 15
856 #include "vga_template.h"
858 #define DEPTH 16
859 #include "vga_template.h"
861 #define DEPTH 32
862 #include "vga_template.h"
864 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
865 {
866 unsigned int col;
867 col = rgb_to_pixel8(r, g, b);
868 col |= col << 8;
869 col |= col << 16;
870 return col;
871 }
873 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
874 {
875 unsigned int col;
876 col = rgb_to_pixel15(r, g, b);
877 col |= col << 16;
878 return col;
879 }
881 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
882 {
883 unsigned int col;
884 col = rgb_to_pixel16(r, g, b);
885 col |= col << 16;
886 return col;
887 }
889 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
890 {
891 unsigned int col;
892 col = rgb_to_pixel32(r, g, b);
893 return col;
894 }
896 /* return true if the palette was modified */
897 static int update_palette16(VGAState *s)
898 {
899 int full_update, i;
900 uint32_t v, col, *palette;
902 full_update = 0;
903 palette = s->last_palette;
904 for(i = 0; i < 16; i++) {
905 v = s->ar[i];
906 if (s->ar[0x10] & 0x80)
907 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
908 else
909 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
910 v = v * 3;
911 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
912 c6_to_8(s->palette[v + 1]),
913 c6_to_8(s->palette[v + 2]));
914 if (col != palette[i]) {
915 full_update = 1;
916 palette[i] = col;
917 }
918 }
919 return full_update;
920 }
922 /* return true if the palette was modified */
923 static int update_palette256(VGAState *s)
924 {
925 int full_update, i;
926 uint32_t v, col, *palette;
928 full_update = 0;
929 palette = s->last_palette;
930 v = 0;
931 for(i = 0; i < 256; i++) {
932 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
933 c6_to_8(s->palette[v + 1]),
934 c6_to_8(s->palette[v + 2]));
935 if (col != palette[i]) {
936 full_update = 1;
937 palette[i] = col;
938 }
939 v += 3;
940 }
941 return full_update;
942 }
944 static void vga_get_offsets(VGAState *s,
945 uint32_t *pline_offset,
946 uint32_t *pstart_addr)
947 {
948 uint32_t start_addr, line_offset;
949 #ifdef CONFIG_BOCHS_VBE
950 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
951 line_offset = s->vbe_line_offset;
952 start_addr = s->vbe_start_addr;
953 } else
954 #endif
955 {
956 /* compute line_offset in bytes */
957 line_offset = s->cr[0x13];
958 #ifdef CONFIG_S3VGA
959 {
960 uinr32_t v;
961 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
962 if (v == 0)
963 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
964 line_offset |= (v << 8);
965 }
966 #endif
967 line_offset <<= 3;
969 /* starting address */
970 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
971 #ifdef CONFIG_S3VGA
972 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
973 #endif
974 }
975 *pline_offset = line_offset;
976 *pstart_addr = start_addr;
977 }
979 /* update start_addr and line_offset. Return TRUE if modified */
980 static int update_basic_params(VGAState *s)
981 {
982 int full_update;
983 uint32_t start_addr, line_offset, line_compare;
985 full_update = 0;
987 s->get_offsets(s, &line_offset, &start_addr);
988 /* line compare */
989 line_compare = s->cr[0x18] |
990 ((s->cr[0x07] & 0x10) << 4) |
991 ((s->cr[0x09] & 0x40) << 3);
993 if (line_offset != s->line_offset ||
994 start_addr != s->start_addr ||
995 line_compare != s->line_compare) {
996 s->line_offset = line_offset;
997 s->start_addr = start_addr;
998 s->line_compare = line_compare;
999 full_update = 1;
1001 return full_update;
1004 static inline int get_depth_index(int depth)
1006 switch(depth) {
1007 default:
1008 case 8:
1009 return 0;
1010 case 15:
1011 return 1;
1012 case 16:
1013 return 2;
1014 case 32:
1015 return 3;
1019 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1020 vga_draw_glyph8_8,
1021 vga_draw_glyph8_16,
1022 vga_draw_glyph8_16,
1023 vga_draw_glyph8_32,
1024 };
1026 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1027 vga_draw_glyph16_8,
1028 vga_draw_glyph16_16,
1029 vga_draw_glyph16_16,
1030 vga_draw_glyph16_32,
1031 };
1033 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1034 vga_draw_glyph9_8,
1035 vga_draw_glyph9_16,
1036 vga_draw_glyph9_16,
1037 vga_draw_glyph9_32,
1038 };
1040 static const uint8_t cursor_glyph[32 * 4] = {
1041 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1043 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1045 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1046 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1047 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1048 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1049 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1050 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1051 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1052 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1053 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1054 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1055 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1056 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1057 };
1059 /*
1060 * Text mode update
1061 * Missing:
1062 * - double scan
1063 * - double width
1064 * - underline
1065 * - flashing
1066 */
1067 static void vga_draw_text(VGAState *s, int full_update)
1069 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1070 int cx_min, cx_max, linesize, x_incr;
1071 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1072 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1073 const uint8_t *font_ptr, *font_base[2];
1074 int dup9, line_offset, depth_index;
1075 uint32_t *palette;
1076 uint32_t *ch_attr_ptr;
1077 vga_draw_glyph8_func *vga_draw_glyph8;
1078 vga_draw_glyph9_func *vga_draw_glyph9;
1080 full_update |= update_palette16(s);
1081 palette = s->last_palette;
1083 /* compute font data address (in plane 2) */
1084 v = s->sr[3];
1085 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1086 if (offset != s->font_offsets[0]) {
1087 s->font_offsets[0] = offset;
1088 full_update = 1;
1090 font_base[0] = s->vram_ptr + offset;
1092 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1093 font_base[1] = s->vram_ptr + offset;
1094 if (offset != s->font_offsets[1]) {
1095 s->font_offsets[1] = offset;
1096 full_update = 1;
1098 if (s->plane_updated & (1 << 2)) {
1099 /* if the plane 2 was modified since the last display, it
1100 indicates the font may have been modified */
1101 s->plane_updated = 0;
1102 full_update = 1;
1104 full_update |= update_basic_params(s);
1106 line_offset = s->line_offset;
1107 s1 = s->vram_ptr + (s->start_addr * 4);
1109 /* total width & height */
1110 cheight = (s->cr[9] & 0x1f) + 1;
1111 cw = 8;
1112 if (!(s->sr[1] & 0x01))
1113 cw = 9;
1114 if (s->sr[1] & 0x08)
1115 cw = 16; /* NOTE: no 18 pixel wide */
1116 x_incr = cw * ((s->ds->depth + 7) >> 3);
1117 width = (s->cr[0x01] + 1);
1118 if (s->cr[0x06] == 100) {
1119 /* ugly hack for CGA 160x100x16 - explain me the logic */
1120 height = 100;
1121 } else {
1122 height = s->cr[0x12] |
1123 ((s->cr[0x07] & 0x02) << 7) |
1124 ((s->cr[0x07] & 0x40) << 3);
1125 height = (height + 1) / cheight;
1127 if ((height * width) > CH_ATTR_SIZE) {
1128 /* better than nothing: exit if transient size is too big */
1129 return;
1132 if (width != s->last_width || height != s->last_height ||
1133 cw != s->last_cw || cheight != s->last_ch) {
1134 s->last_scr_width = width * cw;
1135 s->last_scr_height = height * cheight;
1136 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1137 s->last_width = width;
1138 s->last_height = height;
1139 s->last_ch = cheight;
1140 s->last_cw = cw;
1141 full_update = 1;
1143 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1144 if (cursor_offset != s->cursor_offset ||
1145 s->cr[0xa] != s->cursor_start ||
1146 s->cr[0xb] != s->cursor_end) {
1147 /* if the cursor position changed, we update the old and new
1148 chars */
1149 if (s->cursor_offset < CH_ATTR_SIZE)
1150 s->last_ch_attr[s->cursor_offset] = -1;
1151 if (cursor_offset < CH_ATTR_SIZE)
1152 s->last_ch_attr[cursor_offset] = -1;
1153 s->cursor_offset = cursor_offset;
1154 s->cursor_start = s->cr[0xa];
1155 s->cursor_end = s->cr[0xb];
1157 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1159 depth_index = get_depth_index(s->ds->depth);
1160 if (cw == 16)
1161 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1162 else
1163 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1164 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1166 dest = s->ds->data;
1167 linesize = s->ds->linesize;
1168 ch_attr_ptr = s->last_ch_attr;
1169 for(cy = 0; cy < height; cy++) {
1170 d1 = dest;
1171 src = s1;
1172 cx_min = width;
1173 cx_max = -1;
1174 for(cx = 0; cx < width; cx++) {
1175 ch_attr = *(uint16_t *)src;
1176 if (full_update || ch_attr != *ch_attr_ptr) {
1177 if (cx < cx_min)
1178 cx_min = cx;
1179 if (cx > cx_max)
1180 cx_max = cx;
1181 *ch_attr_ptr = ch_attr;
1182 #ifdef WORDS_BIGENDIAN
1183 ch = ch_attr >> 8;
1184 cattr = ch_attr & 0xff;
1185 #else
1186 ch = ch_attr & 0xff;
1187 cattr = ch_attr >> 8;
1188 #endif
1189 font_ptr = font_base[(cattr >> 3) & 1];
1190 font_ptr += 32 * 4 * ch;
1191 bgcol = palette[cattr >> 4];
1192 fgcol = palette[cattr & 0x0f];
1193 if (cw != 9) {
1194 vga_draw_glyph8(d1, linesize,
1195 font_ptr, cheight, fgcol, bgcol);
1196 } else {
1197 dup9 = 0;
1198 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1199 dup9 = 1;
1200 vga_draw_glyph9(d1, linesize,
1201 font_ptr, cheight, fgcol, bgcol, dup9);
1203 if (src == cursor_ptr &&
1204 !(s->cr[0x0a] & 0x20)) {
1205 int line_start, line_last, h;
1206 /* draw the cursor */
1207 line_start = s->cr[0x0a] & 0x1f;
1208 line_last = s->cr[0x0b] & 0x1f;
1209 /* XXX: check that */
1210 if (line_last > cheight - 1)
1211 line_last = cheight - 1;
1212 if (line_last >= line_start && line_start < cheight) {
1213 h = line_last - line_start + 1;
1214 d = d1 + linesize * line_start;
1215 if (cw != 9) {
1216 vga_draw_glyph8(d, linesize,
1217 cursor_glyph, h, fgcol, bgcol);
1218 } else {
1219 vga_draw_glyph9(d, linesize,
1220 cursor_glyph, h, fgcol, bgcol, 1);
1225 d1 += x_incr;
1226 src += 4;
1227 ch_attr_ptr++;
1229 if (cx_max != -1) {
1230 dpy_update(s->ds, cx_min * cw, cy * cheight,
1231 (cx_max - cx_min + 1) * cw, cheight);
1233 dest += linesize * cheight;
1234 s1 += line_offset;
1238 enum {
1239 VGA_DRAW_LINE2,
1240 VGA_DRAW_LINE2D2,
1241 VGA_DRAW_LINE4,
1242 VGA_DRAW_LINE4D2,
1243 VGA_DRAW_LINE8D2,
1244 VGA_DRAW_LINE8,
1245 VGA_DRAW_LINE15,
1246 VGA_DRAW_LINE16,
1247 VGA_DRAW_LINE24,
1248 VGA_DRAW_LINE32,
1249 VGA_DRAW_LINE_NB,
1250 };
1252 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1253 vga_draw_line2_8,
1254 vga_draw_line2_16,
1255 vga_draw_line2_16,
1256 vga_draw_line2_32,
1258 vga_draw_line2d2_8,
1259 vga_draw_line2d2_16,
1260 vga_draw_line2d2_16,
1261 vga_draw_line2d2_32,
1263 vga_draw_line4_8,
1264 vga_draw_line4_16,
1265 vga_draw_line4_16,
1266 vga_draw_line4_32,
1268 vga_draw_line4d2_8,
1269 vga_draw_line4d2_16,
1270 vga_draw_line4d2_16,
1271 vga_draw_line4d2_32,
1273 vga_draw_line8d2_8,
1274 vga_draw_line8d2_16,
1275 vga_draw_line8d2_16,
1276 vga_draw_line8d2_32,
1278 vga_draw_line8_8,
1279 vga_draw_line8_16,
1280 vga_draw_line8_16,
1281 vga_draw_line8_32,
1283 vga_draw_line15_8,
1284 vga_draw_line15_15,
1285 vga_draw_line15_16,
1286 vga_draw_line15_32,
1288 vga_draw_line16_8,
1289 vga_draw_line16_15,
1290 vga_draw_line16_16,
1291 vga_draw_line16_32,
1293 vga_draw_line24_8,
1294 vga_draw_line24_15,
1295 vga_draw_line24_16,
1296 vga_draw_line24_32,
1298 vga_draw_line32_8,
1299 vga_draw_line32_15,
1300 vga_draw_line32_16,
1301 vga_draw_line32_32,
1302 };
1304 static int vga_get_bpp(VGAState *s)
1306 int ret;
1307 #ifdef CONFIG_BOCHS_VBE
1308 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1309 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1310 } else
1311 #endif
1313 ret = 0;
1315 return ret;
1318 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1320 int width, height;
1322 width = (s->cr[0x01] + 1) * 8;
1323 height = s->cr[0x12] |
1324 ((s->cr[0x07] & 0x02) << 7) |
1325 ((s->cr[0x07] & 0x40) << 3);
1326 height = (height + 1);
1327 *pwidth = width;
1328 *pheight = height;
1331 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1333 int y;
1334 if (y1 >= VGA_MAX_HEIGHT)
1335 return;
1336 if (y2 >= VGA_MAX_HEIGHT)
1337 y2 = VGA_MAX_HEIGHT;
1338 for(y = y1; y < y2; y++) {
1339 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1343 /*
1344 * graphic modes
1345 */
1346 static void vga_draw_graphic(VGAState *s, int full_update)
1348 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1349 int width, height, shift_control, line_offset, page0, page1, bwidth;
1350 int disp_width, multi_scan, multi_run;
1351 uint8_t *d;
1352 uint32_t v, addr1, addr;
1353 vga_draw_line_func *vga_draw_line;
1355 full_update |= update_basic_params(s);
1357 s->get_resolution(s, &width, &height);
1358 disp_width = width;
1360 shift_control = (s->gr[0x05] >> 5) & 3;
1361 double_scan = (s->cr[0x09] >> 7);
1362 if (shift_control != 1) {
1363 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1364 } else {
1365 /* in CGA modes, multi_scan is ignored */
1366 /* XXX: is it correct ? */
1367 multi_scan = double_scan;
1369 multi_run = multi_scan;
1370 if (shift_control != s->shift_control ||
1371 double_scan != s->double_scan) {
1372 full_update = 1;
1373 s->shift_control = shift_control;
1374 s->double_scan = double_scan;
1377 if (shift_control == 0) {
1378 full_update |= update_palette16(s);
1379 if (s->sr[0x01] & 8) {
1380 v = VGA_DRAW_LINE4D2;
1381 disp_width <<= 1;
1382 } else {
1383 v = VGA_DRAW_LINE4;
1385 } else if (shift_control == 1) {
1386 full_update |= update_palette16(s);
1387 if (s->sr[0x01] & 8) {
1388 v = VGA_DRAW_LINE2D2;
1389 disp_width <<= 1;
1390 } else {
1391 v = VGA_DRAW_LINE2;
1393 } else {
1394 switch(s->get_bpp(s)) {
1395 default:
1396 case 0:
1397 full_update |= update_palette256(s);
1398 v = VGA_DRAW_LINE8D2;
1399 break;
1400 case 8:
1401 full_update |= update_palette256(s);
1402 v = VGA_DRAW_LINE8;
1403 break;
1404 case 15:
1405 v = VGA_DRAW_LINE15;
1406 break;
1407 case 16:
1408 v = VGA_DRAW_LINE16;
1409 break;
1410 case 24:
1411 v = VGA_DRAW_LINE24;
1412 break;
1413 case 32:
1414 v = VGA_DRAW_LINE32;
1415 break;
1418 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1420 if (disp_width != s->last_width ||
1421 height != s->last_height) {
1422 dpy_resize(s->ds, disp_width, height);
1423 s->last_scr_width = disp_width;
1424 s->last_scr_height = height;
1425 s->last_width = disp_width;
1426 s->last_height = height;
1427 full_update = 1;
1429 if (s->cursor_invalidate)
1430 s->cursor_invalidate(s);
1432 line_offset = s->line_offset;
1433 #if 0
1434 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",
1435 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1436 #endif
1437 addr1 = (s->start_addr * 4);
1438 bwidth = width * 4;
1439 y_start = -1;
1440 page_min = 0x7fffffff;
1441 page_max = -1;
1442 d = s->ds->data;
1443 linesize = s->ds->linesize;
1444 y1 = 0;
1445 for(y = 0; y < height; y++) {
1446 addr = addr1;
1447 if (!(s->cr[0x17] & 1)) {
1448 int shift;
1449 /* CGA compatibility handling */
1450 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1451 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1453 if (!(s->cr[0x17] & 2)) {
1454 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1456 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1457 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1458 update = full_update | cpu_physical_memory_is_dirty(page0) |
1459 cpu_physical_memory_is_dirty(page1);
1460 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1461 /* if wide line, can use another page */
1462 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1464 /* explicit invalidation for the hardware cursor */
1465 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1466 if (update) {
1467 if (y_start < 0)
1468 y_start = y;
1469 if (page0 < page_min)
1470 page_min = page0;
1471 if (page1 > page_max)
1472 page_max = page1;
1473 vga_draw_line(s, d, s->vram_ptr + addr, width);
1474 if (s->cursor_draw_line)
1475 s->cursor_draw_line(s, d, y);
1476 } else {
1477 if (y_start >= 0) {
1478 /* flush to display */
1479 dpy_update(s->ds, 0, y_start,
1480 disp_width, y - y_start);
1481 y_start = -1;
1484 if (!multi_run) {
1485 mask = (s->cr[0x17] & 3) ^ 3;
1486 if ((y1 & mask) == mask)
1487 addr1 += line_offset;
1488 y1++;
1489 multi_run = multi_scan;
1490 } else {
1491 multi_run--;
1493 /* line compare acts on the displayed lines */
1494 if (y == s->line_compare)
1495 addr1 = 0;
1496 d += linesize;
1498 if (y_start >= 0) {
1499 /* flush to display */
1500 dpy_update(s->ds, 0, y_start,
1501 disp_width, y - y_start);
1503 /* reset modified pages */
1504 if (page_max != -1) {
1505 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1507 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1510 static void vga_draw_blank(VGAState *s, int full_update)
1512 int i, w, val;
1513 uint8_t *d;
1515 if (!full_update)
1516 return;
1517 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1518 return;
1519 if (s->ds->depth == 8)
1520 val = s->rgb_to_pixel(0, 0, 0);
1521 else
1522 val = 0;
1523 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1524 d = s->ds->data;
1525 for(i = 0; i < s->last_scr_height; i++) {
1526 memset(d, val, w);
1527 d += s->ds->linesize;
1529 dpy_update(s->ds, 0, 0,
1530 s->last_scr_width, s->last_scr_height);
1533 #define GMODE_TEXT 0
1534 #define GMODE_GRAPH 1
1535 #define GMODE_BLANK 2
1537 void vga_update_display(void)
1539 VGAState *s = vga_state;
1540 int full_update, graphic_mode;
1542 if (s->ds->depth == 0) {
1543 /* nothing to do */
1544 } else {
1545 switch(s->ds->depth) {
1546 case 8:
1547 s->rgb_to_pixel = rgb_to_pixel8_dup;
1548 break;
1549 case 15:
1550 s->rgb_to_pixel = rgb_to_pixel15_dup;
1551 break;
1552 default:
1553 case 16:
1554 s->rgb_to_pixel = rgb_to_pixel16_dup;
1555 break;
1556 case 32:
1557 s->rgb_to_pixel = rgb_to_pixel32_dup;
1558 break;
1561 full_update = 0;
1562 if (!(s->ar_index & 0x20)) {
1563 graphic_mode = GMODE_BLANK;
1564 } else {
1565 graphic_mode = s->gr[6] & 1;
1567 if (graphic_mode != s->graphic_mode) {
1568 s->graphic_mode = graphic_mode;
1569 full_update = 1;
1571 switch(graphic_mode) {
1572 case GMODE_TEXT:
1573 vga_draw_text(s, full_update);
1574 break;
1575 case GMODE_GRAPH:
1576 vga_draw_graphic(s, full_update);
1577 break;
1578 case GMODE_BLANK:
1579 default:
1580 vga_draw_blank(s, full_update);
1581 break;
1586 /* force a full display refresh */
1587 void vga_invalidate_display(void)
1589 VGAState *s = vga_state;
1591 s->last_width = -1;
1592 s->last_height = -1;
1595 static void vga_reset(VGAState *s)
1597 memset(s, 0, sizeof(VGAState));
1598 #ifdef CONFIG_S3VGA
1599 /* chip ID for 8c968 */
1600 s->cr[0x2d] = 0x88;
1601 s->cr[0x2e] = 0xb0;
1602 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1603 s->cr[0x30] = 0xe1;
1604 #endif
1605 s->graphic_mode = -1; /* force full update */
1608 static CPUReadMemoryFunc *vga_mem_read[3] = {
1609 vga_mem_readb,
1610 vga_mem_readw,
1611 vga_mem_readl,
1612 };
1614 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1615 vga_mem_writeb,
1616 vga_mem_writew,
1617 vga_mem_writel,
1618 };
1620 static void vga_save(QEMUFile *f, void *opaque)
1622 VGAState *s = opaque;
1624 qemu_put_be32s(f, &s->latch);
1625 qemu_put_8s(f, &s->sr_index);
1626 qemu_put_buffer(f, s->sr, 8);
1627 qemu_put_8s(f, &s->gr_index);
1628 qemu_put_buffer(f, s->gr, 16);
1629 qemu_put_8s(f, &s->ar_index);
1630 qemu_put_buffer(f, s->ar, 21);
1631 qemu_put_be32s(f, &s->ar_flip_flop);
1632 qemu_put_8s(f, &s->cr_index);
1633 qemu_put_buffer(f, s->cr, 256);
1634 qemu_put_8s(f, &s->msr);
1635 qemu_put_8s(f, &s->fcr);
1636 qemu_put_8s(f, &s->st00);
1637 qemu_put_8s(f, &s->st01);
1639 qemu_put_8s(f, &s->dac_state);
1640 qemu_put_8s(f, &s->dac_sub_index);
1641 qemu_put_8s(f, &s->dac_read_index);
1642 qemu_put_8s(f, &s->dac_write_index);
1643 qemu_put_buffer(f, s->dac_cache, 3);
1644 qemu_put_buffer(f, s->palette, 768);
1646 qemu_put_be32s(f, &s->bank_offset);
1647 #ifdef CONFIG_BOCHS_VBE
1648 qemu_put_byte(f, 1);
1649 qemu_put_be16s(f, &s->vbe_index);
1650 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1651 qemu_put_be16s(f, &s->vbe_regs[i]);
1652 qemu_put_be32s(f, &s->vbe_start_addr);
1653 qemu_put_be32s(f, &s->vbe_line_offset);
1654 qemu_put_be32s(f, &s->vbe_bank_mask);
1655 #else
1656 qemu_put_byte(f, 0);
1657 #endif
1660 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1662 VGAState *s = opaque;
1663 int is_vbe;
1665 if (version_id != 1)
1666 return -EINVAL;
1668 qemu_get_be32s(f, &s->latch);
1669 qemu_get_8s(f, &s->sr_index);
1670 qemu_get_buffer(f, s->sr, 8);
1671 qemu_get_8s(f, &s->gr_index);
1672 qemu_get_buffer(f, s->gr, 16);
1673 qemu_get_8s(f, &s->ar_index);
1674 qemu_get_buffer(f, s->ar, 21);
1675 qemu_get_be32s(f, &s->ar_flip_flop);
1676 qemu_get_8s(f, &s->cr_index);
1677 qemu_get_buffer(f, s->cr, 256);
1678 qemu_get_8s(f, &s->msr);
1679 qemu_get_8s(f, &s->fcr);
1680 qemu_get_8s(f, &s->st00);
1681 qemu_get_8s(f, &s->st01);
1683 qemu_get_8s(f, &s->dac_state);
1684 qemu_get_8s(f, &s->dac_sub_index);
1685 qemu_get_8s(f, &s->dac_read_index);
1686 qemu_get_8s(f, &s->dac_write_index);
1687 qemu_get_buffer(f, s->dac_cache, 3);
1688 qemu_get_buffer(f, s->palette, 768);
1690 qemu_get_be32s(f, &s->bank_offset);
1691 is_vbe = qemu_get_byte(f);
1692 #ifdef CONFIG_BOCHS_VBE
1693 if (!is_vbe)
1694 return -EINVAL;
1695 qemu_get_be16s(f, &s->vbe_index);
1696 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1697 qemu_get_be16s(f, &s->vbe_regs[i]);
1698 qemu_get_be32s(f, &s->vbe_start_addr);
1699 qemu_get_be32s(f, &s->vbe_line_offset);
1700 qemu_get_be32s(f, &s->vbe_bank_mask);
1701 #else
1702 if (is_vbe)
1703 return -EINVAL;
1704 #endif
1706 /* force refresh */
1707 s->graphic_mode = -1;
1708 return 0;
1711 static void vga_map(PCIDevice *pci_dev, int region_num,
1712 uint32_t addr, uint32_t size, int type)
1714 VGAState *s = vga_state;
1716 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1719 /* do the same job as vgabios before vgabios get ready */
1720 void vga_bios_init(VGAState *s)
1722 uint8_t palette_model[192] = {
1723 0, 0, 0, 0, 0, 170, 0, 170, 0, 0, 170, 170, 170, 0, 0, 170,
1724 0, 170, 170, 85, 0, 170, 170, 170, 85, 85, 85, 85, 85, 255, 85, 255,
1725 85, 85, 255, 255, 255, 85, 85, 255, 85, 255, 255, 255, 85, 255, 255, 255,
1726 0, 21, 0, 0, 21, 42, 0, 63, 0, 0, 63, 42, 42, 21, 0, 42,
1727 21, 42, 42, 63, 0, 42, 63, 42, 0, 21, 21, 0, 21, 63, 0, 63,
1728 21, 0, 63, 63, 42, 21, 21, 42, 21, 63, 42, 63, 21, 42, 63, 63,
1729 21, 0, 0, 21, 0, 42, 21, 42, 0, 21, 42, 42, 63, 0, 0, 63,
1730 0, 42, 63, 42, 0, 63, 42, 42, 21, 0, 21, 21, 0, 63, 21, 42,
1731 21, 21, 42, 63, 63, 0, 21, 63, 0, 63, 63, 42, 21, 63, 42, 63,
1732 21, 21, 0, 21, 21, 42, 21, 63, 0, 21, 63, 42, 63, 21, 0, 63,
1733 21, 42, 63, 63, 0, 63, 63, 42, 21, 21, 21, 21, 21, 63, 21, 63,
1734 21, 21, 63, 63, 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63
1735 };
1737 s->latch = 0;
1739 s->sr_index = 3;
1740 s->sr[0] = 3;
1741 s->sr[1] = 0;
1742 s->sr[2] = 3;
1743 s->sr[3] = 0;
1744 s->sr[4] = 2;
1745 s->sr[5] = 0;
1746 s->sr[6] = 0;
1747 s->sr[7] = 0;
1749 s->gr_index = 5;
1750 s->gr[0] = 0;
1751 s->gr[1] = 0;
1752 s->gr[2] = 0;
1753 s->gr[3] = 0;
1754 s->gr[4] = 0;
1755 s->gr[5] = 16;
1756 s->gr[6] = 14;
1757 s->gr[7] = 15;
1758 s->gr[8] = 255;
1760 /*changed by out 0x03c0*/
1761 s->ar_index = 32;
1762 s->ar[0] = 0;
1763 s->ar[1] = 1;
1764 s->ar[2] = 2;
1765 s->ar[3] = 3;
1766 s->ar[4] = 4;
1767 s->ar[5] = 5;
1768 s->ar[6] = 6;
1769 s->ar[7] = 7;
1770 s->ar[8] = 8;
1771 s->ar[9] = 9;
1772 s->ar[10] = 10;
1773 s->ar[11] = 11;
1774 s->ar[12] = 12;
1775 s->ar[13] = 13;
1776 s->ar[14] = 14;
1777 s->ar[15] = 15;
1778 s->ar[16] = 12;
1779 s->ar[17] = 0;
1780 s->ar[18] = 15;
1781 s->ar[19] = 8;
1782 s->ar[20] = 0;
1784 s->ar_flip_flop = 1;
1786 s->cr_index = 15;
1787 s->cr[0] = 95;
1788 s->cr[1] = 79;
1789 s->cr[2] = 80;
1790 s->cr[3] = 130;
1791 s->cr[4] = 85;
1792 s->cr[5] = 129;
1793 s->cr[6] = 191;
1794 s->cr[7] = 31;
1795 s->cr[8] = 0;
1796 s->cr[9] = 79;
1797 s->cr[10] = 14;
1798 s->cr[11] = 15;
1799 s->cr[12] = 0;
1800 s->cr[13] = 0;
1801 s->cr[14] = 5;
1802 s->cr[15] = 160;
1803 s->cr[16] = 156;
1804 s->cr[17] = 142;
1805 s->cr[18] = 143;
1806 s->cr[19] = 40;
1807 s->cr[20] = 31;
1808 s->cr[21] = 150;
1809 s->cr[22] = 185;
1810 s->cr[23] = 163;
1811 s->cr[24] = 255;
1813 s->msr = 103;
1814 s->fcr = 0;
1815 s->st00 = 0;
1816 s->st01 = 0;
1818 /*dac_* & platte will be initialized by os through out 0x03c8 & out 0c03c9(1:3) */
1819 s->dac_state = 0;
1820 s->dac_sub_index = 0;
1821 s->dac_read_index = 0;
1822 s->dac_write_index = 16;
1823 s->dac_cache[0] = 255;
1824 s->dac_cache[1] = 255;
1825 s->dac_cache[2] = 255;
1827 /*platte*/
1828 memcpy(s->palette, palette_model, 192);
1830 s->bank_offset= 0;
1831 s->graphic_mode = -1;
1833 /* TODO:add vbe support if enable it */
1835 FILE *qemuf = fopen("/etc/xen/qemu-vgaram-bin", "rb");
1836 if (!qemuf) {
1837 fprintf(logfile, "open qemu vgaram binary failed!\n");
1838 } else {
1839 /*load vram contents, else vga console can't boot */
1840 qemu_get_buffer(qemuf, s->vram_ptr, 256*1024);
1842 fclose(qemuf);
1847 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1848 unsigned long vga_ram_offset, int vga_ram_size)
1850 int i, j, v, b;
1852 for(i = 0;i < 256; i++) {
1853 v = 0;
1854 for(j = 0; j < 8; j++) {
1855 v |= ((i >> j) & 1) << (j * 4);
1857 expand4[i] = v;
1859 v = 0;
1860 for(j = 0; j < 4; j++) {
1861 v |= ((i >> (2 * j)) & 3) << (j * 4);
1863 expand2[i] = v;
1865 for(i = 0; i < 16; i++) {
1866 v = 0;
1867 for(j = 0; j < 4; j++) {
1868 b = ((i >> j) & 1);
1869 v |= b << (2 * j);
1870 v |= b << (2 * j + 1);
1872 expand4to8[i] = v;
1875 vga_reset(s);
1877 /* qemu's vga mem is not detached from phys_ram_base and can cause DM abort
1878 * when guest write vga mem, so allocate a new one */
1879 s->vram_ptr = qemu_mallocz(vga_ram_size);
1881 s->vram_offset = vga_ram_offset;
1882 s->vram_size = vga_ram_size;
1883 s->ds = ds;
1884 s->get_bpp = vga_get_bpp;
1885 s->get_offsets = vga_get_offsets;
1886 s->get_resolution = vga_get_resolution;
1887 /* XXX: currently needed for display */
1888 vga_state = s;
1892 int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
1893 unsigned long vga_ram_offset, int vga_ram_size)
1895 VGAState *s;
1897 s = qemu_mallocz(sizeof(VGAState));
1898 if (!s)
1899 return -1;
1901 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1903 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1905 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1907 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1908 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1909 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1910 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1912 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1914 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1915 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1916 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1917 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1918 s->bank_offset = 0;
1920 #ifdef CONFIG_BOCHS_VBE
1921 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1922 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1923 #if defined (TARGET_I386)
1924 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1925 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1927 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1928 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1930 /* old Bochs IO ports */
1931 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1932 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1934 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1935 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1936 #else
1937 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1938 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1940 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1941 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1942 #endif
1943 #endif /* CONFIG_BOCHS_VBE */
1945 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1946 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1947 vga_io_memory);
1949 if (bus) {
1950 PCIDevice *d;
1951 uint8_t *pci_conf;
1953 d = pci_register_device(bus, "VGA",
1954 sizeof(PCIDevice),
1955 -1, NULL, NULL);
1956 pci_conf = d->config;
1957 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1958 pci_conf[0x01] = 0x12;
1959 pci_conf[0x02] = 0x11;
1960 pci_conf[0x03] = 0x11;
1961 pci_conf[0x0a] = 0x00; // VGA controller
1962 pci_conf[0x0b] = 0x03;
1963 pci_conf[0x0e] = 0x00; // header_type
1965 /* XXX: vga_ram_size must be a power of two */
1966 pci_register_io_region(d, 0, vga_ram_size,
1967 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1968 } else {
1969 #ifdef CONFIG_BOCHS_VBE
1970 /* XXX: use optimized standard vga accesses */
1971 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1972 vga_ram_size, vga_ram_offset);
1973 #endif
1976 vga_bios_init(s);
1977 return 0;
1980 /********************************************************/
1981 /* vga screen dump */
1983 static int vga_save_w, vga_save_h;
1985 static void vga_save_dpy_update(DisplayState *s,
1986 int x, int y, int w, int h)
1990 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1992 s->linesize = w * 4;
1993 s->data = qemu_malloc(h * s->linesize);
1994 vga_save_w = w;
1995 vga_save_h = h;
1998 static void vga_save_dpy_refresh(DisplayState *s)
2002 static int ppm_save(const char *filename, uint8_t *data,
2003 int w, int h, int linesize)
2005 FILE *f;
2006 uint8_t *d, *d1;
2007 unsigned int v;
2008 int y, x;
2010 f = fopen(filename, "wb");
2011 if (!f)
2012 return -1;
2013 fprintf(f, "P6\n%d %d\n%d\n",
2014 w, h, 255);
2015 d1 = data;
2016 for(y = 0; y < h; y++) {
2017 d = d1;
2018 for(x = 0; x < w; x++) {
2019 v = *(uint32_t *)d;
2020 fputc((v >> 16) & 0xff, f);
2021 fputc((v >> 8) & 0xff, f);
2022 fputc((v) & 0xff, f);
2023 d += 4;
2025 d1 += linesize;
2027 fclose(f);
2028 return 0;
2031 /* save the vga display in a PPM image even if no display is
2032 available */
2033 void vga_screen_dump(const char *filename)
2035 VGAState *s = vga_state;
2036 DisplayState *saved_ds, ds1, *ds = &ds1;
2038 /* XXX: this is a little hackish */
2039 vga_invalidate_display();
2040 saved_ds = s->ds;
2042 memset(ds, 0, sizeof(DisplayState));
2043 ds->dpy_update = vga_save_dpy_update;
2044 ds->dpy_resize = vga_save_dpy_resize;
2045 ds->dpy_refresh = vga_save_dpy_refresh;
2046 ds->depth = 32;
2048 s->ds = ds;
2049 s->graphic_mode = -1;
2050 vga_update_display();
2052 if (ds->data) {
2053 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2054 s->ds->linesize);
2055 qemu_free(ds->data);
2057 s->ds = saved_ds;