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