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