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