vga-isa: convert to qdev
[qemu/mdroth.git] / hw / vga.c
blob3ef85fbf9758c3ad921f93f664e10a2b95fd69aa
1 /*
2 * QEMU VGA Emulator.
4 * Copyright (c) 2003 Fabrice Bellard
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 "hw.h"
25 #include "console.h"
26 #include "pc.h"
27 #include "pci.h"
28 #include "vga_int.h"
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
32 //#define DEBUG_VGA
33 //#define DEBUG_VGA_MEM
34 //#define DEBUG_VGA_REG
36 //#define DEBUG_BOCHS_VBE
38 /* force some bits to zero */
39 const uint8_t sr_mask[8] = {
40 0x03,
41 0x3d,
42 0x0f,
43 0x3f,
44 0x0e,
45 0x00,
46 0x00,
47 0xff,
50 const uint8_t gr_mask[16] = {
51 0x0f, /* 0x00 */
52 0x0f, /* 0x01 */
53 0x0f, /* 0x02 */
54 0x1f, /* 0x03 */
55 0x03, /* 0x04 */
56 0x7b, /* 0x05 */
57 0x0f, /* 0x06 */
58 0x0f, /* 0x07 */
59 0xff, /* 0x08 */
60 0x00, /* 0x09 */
61 0x00, /* 0x0a */
62 0x00, /* 0x0b */
63 0x00, /* 0x0c */
64 0x00, /* 0x0d */
65 0x00, /* 0x0e */
66 0x00, /* 0x0f */
69 #define cbswap_32(__x) \
70 ((uint32_t)( \
71 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
73 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
74 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76 #ifdef HOST_WORDS_BIGENDIAN
77 #define PAT(x) cbswap_32(x)
78 #else
79 #define PAT(x) (x)
80 #endif
82 #ifdef HOST_WORDS_BIGENDIAN
83 #define BIG 1
84 #else
85 #define BIG 0
86 #endif
88 #ifdef HOST_WORDS_BIGENDIAN
89 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90 #else
91 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
92 #endif
94 static const uint32_t mask16[16] = {
95 PAT(0x00000000),
96 PAT(0x000000ff),
97 PAT(0x0000ff00),
98 PAT(0x0000ffff),
99 PAT(0x00ff0000),
100 PAT(0x00ff00ff),
101 PAT(0x00ffff00),
102 PAT(0x00ffffff),
103 PAT(0xff000000),
104 PAT(0xff0000ff),
105 PAT(0xff00ff00),
106 PAT(0xff00ffff),
107 PAT(0xffff0000),
108 PAT(0xffff00ff),
109 PAT(0xffffff00),
110 PAT(0xffffffff),
113 #undef PAT
115 #ifdef HOST_WORDS_BIGENDIAN
116 #define PAT(x) (x)
117 #else
118 #define PAT(x) cbswap_32(x)
119 #endif
121 static const uint32_t dmask16[16] = {
122 PAT(0x00000000),
123 PAT(0x000000ff),
124 PAT(0x0000ff00),
125 PAT(0x0000ffff),
126 PAT(0x00ff0000),
127 PAT(0x00ff00ff),
128 PAT(0x00ffff00),
129 PAT(0x00ffffff),
130 PAT(0xff000000),
131 PAT(0xff0000ff),
132 PAT(0xff00ff00),
133 PAT(0xff00ffff),
134 PAT(0xffff0000),
135 PAT(0xffff00ff),
136 PAT(0xffffff00),
137 PAT(0xffffffff),
140 static const uint32_t dmask4[4] = {
141 PAT(0x00000000),
142 PAT(0x0000ffff),
143 PAT(0xffff0000),
144 PAT(0xffffffff),
147 static uint32_t expand4[256];
148 static uint16_t expand2[256];
149 static uint8_t expand4to8[16];
151 static void vga_screen_dump(void *opaque, const char *filename);
152 static char *screen_dump_filename;
153 static DisplayChangeListener *screen_dump_dcl;
155 static void vga_dumb_update_retrace_info(VGACommonState *s)
157 (void) s;
160 static void vga_precise_update_retrace_info(VGACommonState *s)
162 int htotal_chars;
163 int hretr_start_char;
164 int hretr_skew_chars;
165 int hretr_end_char;
167 int vtotal_lines;
168 int vretr_start_line;
169 int vretr_end_line;
171 int dots;
172 #if 0
173 int div2, sldiv2;
174 #endif
175 int clocking_mode;
176 int clock_sel;
177 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
178 int64_t chars_per_sec;
179 struct vga_precise_retrace *r = &s->retrace_info.precise;
181 htotal_chars = s->cr[0x00] + 5;
182 hretr_start_char = s->cr[0x04];
183 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
184 hretr_end_char = s->cr[0x05] & 0x1f;
186 vtotal_lines = (s->cr[0x06]
187 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
189 vretr_start_line = s->cr[0x10]
190 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
192 vretr_end_line = s->cr[0x11] & 0xf;
196 clocking_mode = (s->sr[0x01] >> 3) & 1;
197 clock_sel = (s->msr >> 2) & 3;
198 dots = (s->msr & 1) ? 8 : 9;
200 chars_per_sec = clk_hz[clock_sel] / dots;
202 htotal_chars <<= clocking_mode;
204 r->total_chars = vtotal_lines * htotal_chars;
205 if (r->freq) {
206 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
207 } else {
208 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
211 r->vstart = vretr_start_line;
212 r->vend = r->vstart + vretr_end_line + 1;
214 r->hstart = hretr_start_char + hretr_skew_chars;
215 r->hend = r->hstart + hretr_end_char + 1;
216 r->htotal = htotal_chars;
218 #if 0
219 div2 = (s->cr[0x17] >> 2) & 1;
220 sldiv2 = (s->cr[0x17] >> 3) & 1;
221 printf (
222 "hz=%f\n"
223 "htotal = %d\n"
224 "hretr_start = %d\n"
225 "hretr_skew = %d\n"
226 "hretr_end = %d\n"
227 "vtotal = %d\n"
228 "vretr_start = %d\n"
229 "vretr_end = %d\n"
230 "div2 = %d sldiv2 = %d\n"
231 "clocking_mode = %d\n"
232 "clock_sel = %d %d\n"
233 "dots = %d\n"
234 "ticks/char = %" PRId64 "\n"
235 "\n",
236 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
237 htotal_chars,
238 hretr_start_char,
239 hretr_skew_chars,
240 hretr_end_char,
241 vtotal_lines,
242 vretr_start_line,
243 vretr_end_line,
244 div2, sldiv2,
245 clocking_mode,
246 clock_sel,
247 clk_hz[clock_sel],
248 dots,
249 r->ticks_per_char
251 #endif
254 static uint8_t vga_precise_retrace(VGACommonState *s)
256 struct vga_precise_retrace *r = &s->retrace_info.precise;
257 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
259 if (r->total_chars) {
260 int cur_line, cur_line_char, cur_char;
261 int64_t cur_tick;
263 cur_tick = qemu_get_clock(vm_clock);
265 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
266 cur_line = cur_char / r->htotal;
268 if (cur_line >= r->vstart && cur_line <= r->vend) {
269 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
270 } else {
271 cur_line_char = cur_char % r->htotal;
272 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
273 val |= ST01_DISP_ENABLE;
277 return val;
278 } else {
279 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
283 static uint8_t vga_dumb_retrace(VGACommonState *s)
285 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
288 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
290 if (s->msr & MSR_COLOR_EMULATION) {
291 /* Color */
292 return (addr >= 0x3b0 && addr <= 0x3bf);
293 } else {
294 /* Monochrome */
295 return (addr >= 0x3d0 && addr <= 0x3df);
299 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
301 VGACommonState *s = opaque;
302 int val, index;
304 if (vga_ioport_invalid(s, addr)) {
305 val = 0xff;
306 } else {
307 switch(addr) {
308 case 0x3c0:
309 if (s->ar_flip_flop == 0) {
310 val = s->ar_index;
311 } else {
312 val = 0;
314 break;
315 case 0x3c1:
316 index = s->ar_index & 0x1f;
317 if (index < 21)
318 val = s->ar[index];
319 else
320 val = 0;
321 break;
322 case 0x3c2:
323 val = s->st00;
324 break;
325 case 0x3c4:
326 val = s->sr_index;
327 break;
328 case 0x3c5:
329 val = s->sr[s->sr_index];
330 #ifdef DEBUG_VGA_REG
331 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
332 #endif
333 break;
334 case 0x3c7:
335 val = s->dac_state;
336 break;
337 case 0x3c8:
338 val = s->dac_write_index;
339 break;
340 case 0x3c9:
341 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
342 if (++s->dac_sub_index == 3) {
343 s->dac_sub_index = 0;
344 s->dac_read_index++;
346 break;
347 case 0x3ca:
348 val = s->fcr;
349 break;
350 case 0x3cc:
351 val = s->msr;
352 break;
353 case 0x3ce:
354 val = s->gr_index;
355 break;
356 case 0x3cf:
357 val = s->gr[s->gr_index];
358 #ifdef DEBUG_VGA_REG
359 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
360 #endif
361 break;
362 case 0x3b4:
363 case 0x3d4:
364 val = s->cr_index;
365 break;
366 case 0x3b5:
367 case 0x3d5:
368 val = s->cr[s->cr_index];
369 #ifdef DEBUG_VGA_REG
370 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
371 #endif
372 break;
373 case 0x3ba:
374 case 0x3da:
375 /* just toggle to fool polling */
376 val = s->st01 = s->retrace(s);
377 s->ar_flip_flop = 0;
378 break;
379 default:
380 val = 0x00;
381 break;
384 #if defined(DEBUG_VGA)
385 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
386 #endif
387 return val;
390 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
392 VGACommonState *s = opaque;
393 int index;
395 /* check port range access depending on color/monochrome mode */
396 if (vga_ioport_invalid(s, addr)) {
397 return;
399 #ifdef DEBUG_VGA
400 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
401 #endif
403 switch(addr) {
404 case 0x3c0:
405 if (s->ar_flip_flop == 0) {
406 val &= 0x3f;
407 s->ar_index = val;
408 } else {
409 index = s->ar_index & 0x1f;
410 switch(index) {
411 case 0x00 ... 0x0f:
412 s->ar[index] = val & 0x3f;
413 break;
414 case 0x10:
415 s->ar[index] = val & ~0x10;
416 break;
417 case 0x11:
418 s->ar[index] = val;
419 break;
420 case 0x12:
421 s->ar[index] = val & ~0xc0;
422 break;
423 case 0x13:
424 s->ar[index] = val & ~0xf0;
425 break;
426 case 0x14:
427 s->ar[index] = val & ~0xf0;
428 break;
429 default:
430 break;
433 s->ar_flip_flop ^= 1;
434 break;
435 case 0x3c2:
436 s->msr = val & ~0x10;
437 s->update_retrace_info(s);
438 break;
439 case 0x3c4:
440 s->sr_index = val & 7;
441 break;
442 case 0x3c5:
443 #ifdef DEBUG_VGA_REG
444 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
445 #endif
446 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
447 if (s->sr_index == 1) s->update_retrace_info(s);
448 break;
449 case 0x3c7:
450 s->dac_read_index = val;
451 s->dac_sub_index = 0;
452 s->dac_state = 3;
453 break;
454 case 0x3c8:
455 s->dac_write_index = val;
456 s->dac_sub_index = 0;
457 s->dac_state = 0;
458 break;
459 case 0x3c9:
460 s->dac_cache[s->dac_sub_index] = val;
461 if (++s->dac_sub_index == 3) {
462 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
463 s->dac_sub_index = 0;
464 s->dac_write_index++;
466 break;
467 case 0x3ce:
468 s->gr_index = val & 0x0f;
469 break;
470 case 0x3cf:
471 #ifdef DEBUG_VGA_REG
472 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
473 #endif
474 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
475 break;
476 case 0x3b4:
477 case 0x3d4:
478 s->cr_index = val;
479 break;
480 case 0x3b5:
481 case 0x3d5:
482 #ifdef DEBUG_VGA_REG
483 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
484 #endif
485 /* handle CR0-7 protection */
486 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
487 /* can always write bit 4 of CR7 */
488 if (s->cr_index == 7)
489 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
490 return;
492 s->cr[s->cr_index] = val;
494 switch(s->cr_index) {
495 case 0x00:
496 case 0x04:
497 case 0x05:
498 case 0x06:
499 case 0x07:
500 case 0x11:
501 case 0x17:
502 s->update_retrace_info(s);
503 break;
505 break;
506 case 0x3ba:
507 case 0x3da:
508 s->fcr = val & 0x10;
509 break;
513 #ifdef CONFIG_BOCHS_VBE
514 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
516 VGACommonState *s = opaque;
517 uint32_t val;
518 val = s->vbe_index;
519 return val;
522 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
524 VGACommonState *s = opaque;
525 uint32_t val;
527 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
528 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
529 switch(s->vbe_index) {
530 /* XXX: do not hardcode ? */
531 case VBE_DISPI_INDEX_XRES:
532 val = VBE_DISPI_MAX_XRES;
533 break;
534 case VBE_DISPI_INDEX_YRES:
535 val = VBE_DISPI_MAX_YRES;
536 break;
537 case VBE_DISPI_INDEX_BPP:
538 val = VBE_DISPI_MAX_BPP;
539 break;
540 default:
541 val = s->vbe_regs[s->vbe_index];
542 break;
544 } else {
545 val = s->vbe_regs[s->vbe_index];
547 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
548 val = s->vram_size / (64 * 1024);
549 } else {
550 val = 0;
552 #ifdef DEBUG_BOCHS_VBE
553 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
554 #endif
555 return val;
558 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
560 VGACommonState *s = opaque;
561 s->vbe_index = val;
564 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
566 VGACommonState *s = opaque;
568 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
569 #ifdef DEBUG_BOCHS_VBE
570 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
571 #endif
572 switch(s->vbe_index) {
573 case VBE_DISPI_INDEX_ID:
574 if (val == VBE_DISPI_ID0 ||
575 val == VBE_DISPI_ID1 ||
576 val == VBE_DISPI_ID2 ||
577 val == VBE_DISPI_ID3 ||
578 val == VBE_DISPI_ID4) {
579 s->vbe_regs[s->vbe_index] = val;
581 break;
582 case VBE_DISPI_INDEX_XRES:
583 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
584 s->vbe_regs[s->vbe_index] = val;
586 break;
587 case VBE_DISPI_INDEX_YRES:
588 if (val <= VBE_DISPI_MAX_YRES) {
589 s->vbe_regs[s->vbe_index] = val;
591 break;
592 case VBE_DISPI_INDEX_BPP:
593 if (val == 0)
594 val = 8;
595 if (val == 4 || val == 8 || val == 15 ||
596 val == 16 || val == 24 || val == 32) {
597 s->vbe_regs[s->vbe_index] = val;
599 break;
600 case VBE_DISPI_INDEX_BANK:
601 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
602 val &= (s->vbe_bank_mask >> 2);
603 } else {
604 val &= s->vbe_bank_mask;
606 s->vbe_regs[s->vbe_index] = val;
607 s->bank_offset = (val << 16);
608 break;
609 case VBE_DISPI_INDEX_ENABLE:
610 if ((val & VBE_DISPI_ENABLED) &&
611 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
612 int h, shift_control;
614 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
615 s->vbe_regs[VBE_DISPI_INDEX_XRES];
616 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
617 s->vbe_regs[VBE_DISPI_INDEX_YRES];
618 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
619 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
621 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
622 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
623 else
624 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
625 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
626 s->vbe_start_addr = 0;
628 /* clear the screen (should be done in BIOS) */
629 if (!(val & VBE_DISPI_NOCLEARMEM)) {
630 memset(s->vram_ptr, 0,
631 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
634 /* we initialize the VGA graphic mode (should be done
635 in BIOS) */
636 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
637 s->cr[0x17] |= 3; /* no CGA modes */
638 s->cr[0x13] = s->vbe_line_offset >> 3;
639 /* width */
640 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
641 /* height (only meaningful if < 1024) */
642 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
643 s->cr[0x12] = h;
644 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
645 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
646 /* line compare to 1023 */
647 s->cr[0x18] = 0xff;
648 s->cr[0x07] |= 0x10;
649 s->cr[0x09] |= 0x40;
651 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
652 shift_control = 0;
653 s->sr[0x01] &= ~8; /* no double line */
654 } else {
655 shift_control = 2;
656 s->sr[4] |= 0x08; /* set chain 4 mode */
657 s->sr[2] |= 0x0f; /* activate all planes */
659 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
660 s->cr[0x09] &= ~0x9f; /* no double scan */
661 } else {
662 /* XXX: the bios should do that */
663 s->bank_offset = 0;
665 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
666 s->vbe_regs[s->vbe_index] = val;
667 break;
668 case VBE_DISPI_INDEX_VIRT_WIDTH:
670 int w, h, line_offset;
672 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
673 return;
674 w = val;
675 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
676 line_offset = w >> 1;
677 else
678 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
679 h = s->vram_size / line_offset;
680 /* XXX: support weird bochs semantics ? */
681 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
682 return;
683 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
684 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
685 s->vbe_line_offset = line_offset;
687 break;
688 case VBE_DISPI_INDEX_X_OFFSET:
689 case VBE_DISPI_INDEX_Y_OFFSET:
691 int x;
692 s->vbe_regs[s->vbe_index] = val;
693 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
694 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
695 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
696 s->vbe_start_addr += x >> 1;
697 else
698 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
699 s->vbe_start_addr >>= 2;
701 break;
702 default:
703 break;
707 #endif
709 /* called for accesses between 0xa0000 and 0xc0000 */
710 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
712 VGACommonState *s = opaque;
713 int memory_map_mode, plane;
714 uint32_t ret;
716 /* convert to VGA memory offset */
717 memory_map_mode = (s->gr[6] >> 2) & 3;
718 addr &= 0x1ffff;
719 switch(memory_map_mode) {
720 case 0:
721 break;
722 case 1:
723 if (addr >= 0x10000)
724 return 0xff;
725 addr += s->bank_offset;
726 break;
727 case 2:
728 addr -= 0x10000;
729 if (addr >= 0x8000)
730 return 0xff;
731 break;
732 default:
733 case 3:
734 addr -= 0x18000;
735 if (addr >= 0x8000)
736 return 0xff;
737 break;
740 if (s->sr[4] & 0x08) {
741 /* chain 4 mode : simplest access */
742 ret = s->vram_ptr[addr];
743 } else if (s->gr[5] & 0x10) {
744 /* odd/even mode (aka text mode mapping) */
745 plane = (s->gr[4] & 2) | (addr & 1);
746 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
747 } else {
748 /* standard VGA latched access */
749 s->latch = ((uint32_t *)s->vram_ptr)[addr];
751 if (!(s->gr[5] & 0x08)) {
752 /* read mode 0 */
753 plane = s->gr[4];
754 ret = GET_PLANE(s->latch, plane);
755 } else {
756 /* read mode 1 */
757 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
758 ret |= ret >> 16;
759 ret |= ret >> 8;
760 ret = (~ret) & 0xff;
763 return ret;
766 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
768 uint32_t v;
769 v = vga_mem_readb(opaque, addr);
770 v |= vga_mem_readb(opaque, addr + 1) << 8;
771 return v;
774 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
776 uint32_t v;
777 v = vga_mem_readb(opaque, addr);
778 v |= vga_mem_readb(opaque, addr + 1) << 8;
779 v |= vga_mem_readb(opaque, addr + 2) << 16;
780 v |= vga_mem_readb(opaque, addr + 3) << 24;
781 return v;
784 /* called for accesses between 0xa0000 and 0xc0000 */
785 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
787 VGACommonState *s = opaque;
788 int memory_map_mode, plane, write_mode, b, func_select, mask;
789 uint32_t write_mask, bit_mask, set_mask;
791 #ifdef DEBUG_VGA_MEM
792 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
793 #endif
794 /* convert to VGA memory offset */
795 memory_map_mode = (s->gr[6] >> 2) & 3;
796 addr &= 0x1ffff;
797 switch(memory_map_mode) {
798 case 0:
799 break;
800 case 1:
801 if (addr >= 0x10000)
802 return;
803 addr += s->bank_offset;
804 break;
805 case 2:
806 addr -= 0x10000;
807 if (addr >= 0x8000)
808 return;
809 break;
810 default:
811 case 3:
812 addr -= 0x18000;
813 if (addr >= 0x8000)
814 return;
815 break;
818 if (s->sr[4] & 0x08) {
819 /* chain 4 mode : simplest access */
820 plane = addr & 3;
821 mask = (1 << plane);
822 if (s->sr[2] & mask) {
823 s->vram_ptr[addr] = val;
824 #ifdef DEBUG_VGA_MEM
825 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
826 #endif
827 s->plane_updated |= mask; /* only used to detect font change */
828 cpu_physical_memory_set_dirty(s->vram_offset + addr);
830 } else if (s->gr[5] & 0x10) {
831 /* odd/even mode (aka text mode mapping) */
832 plane = (s->gr[4] & 2) | (addr & 1);
833 mask = (1 << plane);
834 if (s->sr[2] & mask) {
835 addr = ((addr & ~1) << 1) | plane;
836 s->vram_ptr[addr] = val;
837 #ifdef DEBUG_VGA_MEM
838 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
839 #endif
840 s->plane_updated |= mask; /* only used to detect font change */
841 cpu_physical_memory_set_dirty(s->vram_offset + addr);
843 } else {
844 /* standard VGA latched access */
845 write_mode = s->gr[5] & 3;
846 switch(write_mode) {
847 default:
848 case 0:
849 /* rotate */
850 b = s->gr[3] & 7;
851 val = ((val >> b) | (val << (8 - b))) & 0xff;
852 val |= val << 8;
853 val |= val << 16;
855 /* apply set/reset mask */
856 set_mask = mask16[s->gr[1]];
857 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
858 bit_mask = s->gr[8];
859 break;
860 case 1:
861 val = s->latch;
862 goto do_write;
863 case 2:
864 val = mask16[val & 0x0f];
865 bit_mask = s->gr[8];
866 break;
867 case 3:
868 /* rotate */
869 b = s->gr[3] & 7;
870 val = (val >> b) | (val << (8 - b));
872 bit_mask = s->gr[8] & val;
873 val = mask16[s->gr[0]];
874 break;
877 /* apply logical operation */
878 func_select = s->gr[3] >> 3;
879 switch(func_select) {
880 case 0:
881 default:
882 /* nothing to do */
883 break;
884 case 1:
885 /* and */
886 val &= s->latch;
887 break;
888 case 2:
889 /* or */
890 val |= s->latch;
891 break;
892 case 3:
893 /* xor */
894 val ^= s->latch;
895 break;
898 /* apply bit mask */
899 bit_mask |= bit_mask << 8;
900 bit_mask |= bit_mask << 16;
901 val = (val & bit_mask) | (s->latch & ~bit_mask);
903 do_write:
904 /* mask data according to sr[2] */
905 mask = s->sr[2];
906 s->plane_updated |= mask; /* only used to detect font change */
907 write_mask = mask16[mask];
908 ((uint32_t *)s->vram_ptr)[addr] =
909 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
910 (val & write_mask);
911 #ifdef DEBUG_VGA_MEM
912 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
913 addr * 4, write_mask, val);
914 #endif
915 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
919 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
921 vga_mem_writeb(opaque, addr, val & 0xff);
922 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
925 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
927 vga_mem_writeb(opaque, addr, val & 0xff);
928 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
929 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
930 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
933 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
934 const uint8_t *font_ptr, int h,
935 uint32_t fgcol, uint32_t bgcol);
936 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
937 const uint8_t *font_ptr, int h,
938 uint32_t fgcol, uint32_t bgcol, int dup9);
939 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
940 const uint8_t *s, int width);
942 #define DEPTH 8
943 #include "vga_template.h"
945 #define DEPTH 15
946 #include "vga_template.h"
948 #define BGR_FORMAT
949 #define DEPTH 15
950 #include "vga_template.h"
952 #define DEPTH 16
953 #include "vga_template.h"
955 #define BGR_FORMAT
956 #define DEPTH 16
957 #include "vga_template.h"
959 #define DEPTH 32
960 #include "vga_template.h"
962 #define BGR_FORMAT
963 #define DEPTH 32
964 #include "vga_template.h"
966 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
968 unsigned int col;
969 col = rgb_to_pixel8(r, g, b);
970 col |= col << 8;
971 col |= col << 16;
972 return col;
975 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
977 unsigned int col;
978 col = rgb_to_pixel15(r, g, b);
979 col |= col << 16;
980 return col;
983 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
984 unsigned int b)
986 unsigned int col;
987 col = rgb_to_pixel15bgr(r, g, b);
988 col |= col << 16;
989 return col;
992 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
994 unsigned int col;
995 col = rgb_to_pixel16(r, g, b);
996 col |= col << 16;
997 return col;
1000 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1001 unsigned int b)
1003 unsigned int col;
1004 col = rgb_to_pixel16bgr(r, g, b);
1005 col |= col << 16;
1006 return col;
1009 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1011 unsigned int col;
1012 col = rgb_to_pixel32(r, g, b);
1013 return col;
1016 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1018 unsigned int col;
1019 col = rgb_to_pixel32bgr(r, g, b);
1020 return col;
1023 /* return true if the palette was modified */
1024 static int update_palette16(VGACommonState *s)
1026 int full_update, i;
1027 uint32_t v, col, *palette;
1029 full_update = 0;
1030 palette = s->last_palette;
1031 for(i = 0; i < 16; i++) {
1032 v = s->ar[i];
1033 if (s->ar[0x10] & 0x80)
1034 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1035 else
1036 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1037 v = v * 3;
1038 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1039 c6_to_8(s->palette[v + 1]),
1040 c6_to_8(s->palette[v + 2]));
1041 if (col != palette[i]) {
1042 full_update = 1;
1043 palette[i] = col;
1046 return full_update;
1049 /* return true if the palette was modified */
1050 static int update_palette256(VGACommonState *s)
1052 int full_update, i;
1053 uint32_t v, col, *palette;
1055 full_update = 0;
1056 palette = s->last_palette;
1057 v = 0;
1058 for(i = 0; i < 256; i++) {
1059 if (s->dac_8bit) {
1060 col = s->rgb_to_pixel(s->palette[v],
1061 s->palette[v + 1],
1062 s->palette[v + 2]);
1063 } else {
1064 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1065 c6_to_8(s->palette[v + 1]),
1066 c6_to_8(s->palette[v + 2]));
1068 if (col != palette[i]) {
1069 full_update = 1;
1070 palette[i] = col;
1072 v += 3;
1074 return full_update;
1077 static void vga_get_offsets(VGACommonState *s,
1078 uint32_t *pline_offset,
1079 uint32_t *pstart_addr,
1080 uint32_t *pline_compare)
1082 uint32_t start_addr, line_offset, line_compare;
1083 #ifdef CONFIG_BOCHS_VBE
1084 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1085 line_offset = s->vbe_line_offset;
1086 start_addr = s->vbe_start_addr;
1087 line_compare = 65535;
1088 } else
1089 #endif
1091 /* compute line_offset in bytes */
1092 line_offset = s->cr[0x13];
1093 line_offset <<= 3;
1095 /* starting address */
1096 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1098 /* line compare */
1099 line_compare = s->cr[0x18] |
1100 ((s->cr[0x07] & 0x10) << 4) |
1101 ((s->cr[0x09] & 0x40) << 3);
1103 *pline_offset = line_offset;
1104 *pstart_addr = start_addr;
1105 *pline_compare = line_compare;
1108 /* update start_addr and line_offset. Return TRUE if modified */
1109 static int update_basic_params(VGACommonState *s)
1111 int full_update;
1112 uint32_t start_addr, line_offset, line_compare;
1114 full_update = 0;
1116 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1118 if (line_offset != s->line_offset ||
1119 start_addr != s->start_addr ||
1120 line_compare != s->line_compare) {
1121 s->line_offset = line_offset;
1122 s->start_addr = start_addr;
1123 s->line_compare = line_compare;
1124 full_update = 1;
1126 return full_update;
1129 #define NB_DEPTHS 7
1131 static inline int get_depth_index(DisplayState *s)
1133 switch(ds_get_bits_per_pixel(s)) {
1134 default:
1135 case 8:
1136 return 0;
1137 case 15:
1138 return 1;
1139 case 16:
1140 return 2;
1141 case 32:
1142 if (is_surface_bgr(s->surface))
1143 return 4;
1144 else
1145 return 3;
1149 static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1150 vga_draw_glyph8_8,
1151 vga_draw_glyph8_16,
1152 vga_draw_glyph8_16,
1153 vga_draw_glyph8_32,
1154 vga_draw_glyph8_32,
1155 vga_draw_glyph8_16,
1156 vga_draw_glyph8_16,
1159 static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1160 vga_draw_glyph16_8,
1161 vga_draw_glyph16_16,
1162 vga_draw_glyph16_16,
1163 vga_draw_glyph16_32,
1164 vga_draw_glyph16_32,
1165 vga_draw_glyph16_16,
1166 vga_draw_glyph16_16,
1169 static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1170 vga_draw_glyph9_8,
1171 vga_draw_glyph9_16,
1172 vga_draw_glyph9_16,
1173 vga_draw_glyph9_32,
1174 vga_draw_glyph9_32,
1175 vga_draw_glyph9_16,
1176 vga_draw_glyph9_16,
1179 static const uint8_t cursor_glyph[32 * 4] = {
1180 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1181 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1182 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1183 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1184 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1185 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1186 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1187 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1188 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1189 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1190 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1191 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1192 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1193 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1199 int *pcwidth, int *pcheight)
1201 int width, cwidth, height, cheight;
1203 /* total width & height */
1204 cheight = (s->cr[9] & 0x1f) + 1;
1205 cwidth = 8;
1206 if (!(s->sr[1] & 0x01))
1207 cwidth = 9;
1208 if (s->sr[1] & 0x08)
1209 cwidth = 16; /* NOTE: no 18 pixel wide */
1210 width = (s->cr[0x01] + 1);
1211 if (s->cr[0x06] == 100) {
1212 /* ugly hack for CGA 160x100x16 - explain me the logic */
1213 height = 100;
1214 } else {
1215 height = s->cr[0x12] |
1216 ((s->cr[0x07] & 0x02) << 7) |
1217 ((s->cr[0x07] & 0x40) << 3);
1218 height = (height + 1) / cheight;
1221 *pwidth = width;
1222 *pheight = height;
1223 *pcwidth = cwidth;
1224 *pcheight = cheight;
1227 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1229 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1230 rgb_to_pixel8_dup,
1231 rgb_to_pixel15_dup,
1232 rgb_to_pixel16_dup,
1233 rgb_to_pixel32_dup,
1234 rgb_to_pixel32bgr_dup,
1235 rgb_to_pixel15bgr_dup,
1236 rgb_to_pixel16bgr_dup,
1240 * Text mode update
1241 * Missing:
1242 * - double scan
1243 * - double width
1244 * - underline
1245 * - flashing
1247 static void vga_draw_text(VGACommonState *s, int full_update)
1249 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1250 int cx_min, cx_max, linesize, x_incr, line, line1;
1251 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1252 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1253 const uint8_t *font_ptr, *font_base[2];
1254 int dup9, line_offset, depth_index;
1255 uint32_t *palette;
1256 uint32_t *ch_attr_ptr;
1257 vga_draw_glyph8_func *vga_draw_glyph8;
1258 vga_draw_glyph9_func *vga_draw_glyph9;
1260 /* compute font data address (in plane 2) */
1261 v = s->sr[3];
1262 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1263 if (offset != s->font_offsets[0]) {
1264 s->font_offsets[0] = offset;
1265 full_update = 1;
1267 font_base[0] = s->vram_ptr + offset;
1269 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1270 font_base[1] = s->vram_ptr + offset;
1271 if (offset != s->font_offsets[1]) {
1272 s->font_offsets[1] = offset;
1273 full_update = 1;
1275 if (s->plane_updated & (1 << 2)) {
1276 /* if the plane 2 was modified since the last display, it
1277 indicates the font may have been modified */
1278 s->plane_updated = 0;
1279 full_update = 1;
1281 full_update |= update_basic_params(s);
1283 line_offset = s->line_offset;
1285 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1286 if ((height * width) > CH_ATTR_SIZE) {
1287 /* better than nothing: exit if transient size is too big */
1288 return;
1291 if (width != s->last_width || height != s->last_height ||
1292 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1293 s->last_scr_width = width * cw;
1294 s->last_scr_height = height * cheight;
1295 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1296 s->last_depth = 0;
1297 s->last_width = width;
1298 s->last_height = height;
1299 s->last_ch = cheight;
1300 s->last_cw = cw;
1301 full_update = 1;
1303 s->rgb_to_pixel =
1304 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1305 full_update |= update_palette16(s);
1306 palette = s->last_palette;
1307 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1309 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1310 if (cursor_offset != s->cursor_offset ||
1311 s->cr[0xa] != s->cursor_start ||
1312 s->cr[0xb] != s->cursor_end) {
1313 /* if the cursor position changed, we update the old and new
1314 chars */
1315 if (s->cursor_offset < CH_ATTR_SIZE)
1316 s->last_ch_attr[s->cursor_offset] = -1;
1317 if (cursor_offset < CH_ATTR_SIZE)
1318 s->last_ch_attr[cursor_offset] = -1;
1319 s->cursor_offset = cursor_offset;
1320 s->cursor_start = s->cr[0xa];
1321 s->cursor_end = s->cr[0xb];
1323 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1325 depth_index = get_depth_index(s->ds);
1326 if (cw == 16)
1327 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1328 else
1329 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1330 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1332 dest = ds_get_data(s->ds);
1333 linesize = ds_get_linesize(s->ds);
1334 ch_attr_ptr = s->last_ch_attr;
1335 line = 0;
1336 offset = s->start_addr * 4;
1337 for(cy = 0; cy < height; cy++) {
1338 d1 = dest;
1339 src = s->vram_ptr + offset;
1340 cx_min = width;
1341 cx_max = -1;
1342 for(cx = 0; cx < width; cx++) {
1343 ch_attr = *(uint16_t *)src;
1344 if (full_update || ch_attr != *ch_attr_ptr) {
1345 if (cx < cx_min)
1346 cx_min = cx;
1347 if (cx > cx_max)
1348 cx_max = cx;
1349 *ch_attr_ptr = ch_attr;
1350 #ifdef HOST_WORDS_BIGENDIAN
1351 ch = ch_attr >> 8;
1352 cattr = ch_attr & 0xff;
1353 #else
1354 ch = ch_attr & 0xff;
1355 cattr = ch_attr >> 8;
1356 #endif
1357 font_ptr = font_base[(cattr >> 3) & 1];
1358 font_ptr += 32 * 4 * ch;
1359 bgcol = palette[cattr >> 4];
1360 fgcol = palette[cattr & 0x0f];
1361 if (cw != 9) {
1362 vga_draw_glyph8(d1, linesize,
1363 font_ptr, cheight, fgcol, bgcol);
1364 } else {
1365 dup9 = 0;
1366 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1367 dup9 = 1;
1368 vga_draw_glyph9(d1, linesize,
1369 font_ptr, cheight, fgcol, bgcol, dup9);
1371 if (src == cursor_ptr &&
1372 !(s->cr[0x0a] & 0x20)) {
1373 int line_start, line_last, h;
1374 /* draw the cursor */
1375 line_start = s->cr[0x0a] & 0x1f;
1376 line_last = s->cr[0x0b] & 0x1f;
1377 /* XXX: check that */
1378 if (line_last > cheight - 1)
1379 line_last = cheight - 1;
1380 if (line_last >= line_start && line_start < cheight) {
1381 h = line_last - line_start + 1;
1382 d = d1 + linesize * line_start;
1383 if (cw != 9) {
1384 vga_draw_glyph8(d, linesize,
1385 cursor_glyph, h, fgcol, bgcol);
1386 } else {
1387 vga_draw_glyph9(d, linesize,
1388 cursor_glyph, h, fgcol, bgcol, 1);
1393 d1 += x_incr;
1394 src += 4;
1395 ch_attr_ptr++;
1397 if (cx_max != -1) {
1398 dpy_update(s->ds, cx_min * cw, cy * cheight,
1399 (cx_max - cx_min + 1) * cw, cheight);
1401 dest += linesize * cheight;
1402 line1 = line + cheight;
1403 offset += line_offset;
1404 if (line < s->line_compare && line1 >= s->line_compare) {
1405 offset = 0;
1407 line = line1;
1411 enum {
1412 VGA_DRAW_LINE2,
1413 VGA_DRAW_LINE2D2,
1414 VGA_DRAW_LINE4,
1415 VGA_DRAW_LINE4D2,
1416 VGA_DRAW_LINE8D2,
1417 VGA_DRAW_LINE8,
1418 VGA_DRAW_LINE15,
1419 VGA_DRAW_LINE16,
1420 VGA_DRAW_LINE24,
1421 VGA_DRAW_LINE32,
1422 VGA_DRAW_LINE_NB,
1425 static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1426 vga_draw_line2_8,
1427 vga_draw_line2_16,
1428 vga_draw_line2_16,
1429 vga_draw_line2_32,
1430 vga_draw_line2_32,
1431 vga_draw_line2_16,
1432 vga_draw_line2_16,
1434 vga_draw_line2d2_8,
1435 vga_draw_line2d2_16,
1436 vga_draw_line2d2_16,
1437 vga_draw_line2d2_32,
1438 vga_draw_line2d2_32,
1439 vga_draw_line2d2_16,
1440 vga_draw_line2d2_16,
1442 vga_draw_line4_8,
1443 vga_draw_line4_16,
1444 vga_draw_line4_16,
1445 vga_draw_line4_32,
1446 vga_draw_line4_32,
1447 vga_draw_line4_16,
1448 vga_draw_line4_16,
1450 vga_draw_line4d2_8,
1451 vga_draw_line4d2_16,
1452 vga_draw_line4d2_16,
1453 vga_draw_line4d2_32,
1454 vga_draw_line4d2_32,
1455 vga_draw_line4d2_16,
1456 vga_draw_line4d2_16,
1458 vga_draw_line8d2_8,
1459 vga_draw_line8d2_16,
1460 vga_draw_line8d2_16,
1461 vga_draw_line8d2_32,
1462 vga_draw_line8d2_32,
1463 vga_draw_line8d2_16,
1464 vga_draw_line8d2_16,
1466 vga_draw_line8_8,
1467 vga_draw_line8_16,
1468 vga_draw_line8_16,
1469 vga_draw_line8_32,
1470 vga_draw_line8_32,
1471 vga_draw_line8_16,
1472 vga_draw_line8_16,
1474 vga_draw_line15_8,
1475 vga_draw_line15_15,
1476 vga_draw_line15_16,
1477 vga_draw_line15_32,
1478 vga_draw_line15_32bgr,
1479 vga_draw_line15_15bgr,
1480 vga_draw_line15_16bgr,
1482 vga_draw_line16_8,
1483 vga_draw_line16_15,
1484 vga_draw_line16_16,
1485 vga_draw_line16_32,
1486 vga_draw_line16_32bgr,
1487 vga_draw_line16_15bgr,
1488 vga_draw_line16_16bgr,
1490 vga_draw_line24_8,
1491 vga_draw_line24_15,
1492 vga_draw_line24_16,
1493 vga_draw_line24_32,
1494 vga_draw_line24_32bgr,
1495 vga_draw_line24_15bgr,
1496 vga_draw_line24_16bgr,
1498 vga_draw_line32_8,
1499 vga_draw_line32_15,
1500 vga_draw_line32_16,
1501 vga_draw_line32_32,
1502 vga_draw_line32_32bgr,
1503 vga_draw_line32_15bgr,
1504 vga_draw_line32_16bgr,
1507 static int vga_get_bpp(VGACommonState *s)
1509 int ret;
1510 #ifdef CONFIG_BOCHS_VBE
1511 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1512 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1513 } else
1514 #endif
1516 ret = 0;
1518 return ret;
1521 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1523 int width, height;
1525 #ifdef CONFIG_BOCHS_VBE
1526 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1527 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1528 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1529 } else
1530 #endif
1532 width = (s->cr[0x01] + 1) * 8;
1533 height = s->cr[0x12] |
1534 ((s->cr[0x07] & 0x02) << 7) |
1535 ((s->cr[0x07] & 0x40) << 3);
1536 height = (height + 1);
1538 *pwidth = width;
1539 *pheight = height;
1542 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1544 int y;
1545 if (y1 >= VGA_MAX_HEIGHT)
1546 return;
1547 if (y2 >= VGA_MAX_HEIGHT)
1548 y2 = VGA_MAX_HEIGHT;
1549 for(y = y1; y < y2; y++) {
1550 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1554 static void vga_sync_dirty_bitmap(VGACommonState *s)
1556 if (s->map_addr)
1557 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1559 if (s->lfb_vram_mapped) {
1560 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1561 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1564 #ifdef CONFIG_BOCHS_VBE
1565 if (s->vbe_mapped) {
1566 cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1567 VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
1569 #endif
1573 void vga_dirty_log_start(VGACommonState *s)
1575 if (s->map_addr) {
1576 cpu_physical_log_start(s->map_addr, s->map_end - s->map_addr);
1579 if (s->lfb_vram_mapped) {
1580 cpu_physical_log_start(isa_mem_base + 0xa0000, 0x8000);
1581 cpu_physical_log_start(isa_mem_base + 0xa8000, 0x8000);
1584 #ifdef CONFIG_BOCHS_VBE
1585 if (s->vbe_mapped) {
1586 cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1588 #endif
1591 void vga_dirty_log_stop(VGACommonState *s)
1593 if (s->map_addr) {
1594 cpu_physical_log_stop(s->map_addr, s->map_end - s->map_addr);
1597 if (s->lfb_vram_mapped) {
1598 cpu_physical_log_stop(isa_mem_base + 0xa0000, 0x8000);
1599 cpu_physical_log_stop(isa_mem_base + 0xa8000, 0x8000);
1602 #ifdef CONFIG_BOCHS_VBE
1603 if (s->vbe_mapped) {
1604 cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1606 #endif
1609 void vga_dirty_log_restart(VGACommonState *s)
1611 vga_dirty_log_stop(s);
1612 vga_dirty_log_start(s);
1616 * graphic modes
1618 static void vga_draw_graphic(VGACommonState *s, int full_update)
1620 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1621 int width, height, shift_control, line_offset, bwidth, bits;
1622 ram_addr_t page0, page1, page_min, page_max;
1623 int disp_width, multi_scan, multi_run;
1624 uint8_t *d;
1625 uint32_t v, addr1, addr;
1626 vga_draw_line_func *vga_draw_line;
1628 full_update |= update_basic_params(s);
1630 if (!full_update)
1631 vga_sync_dirty_bitmap(s);
1633 s->get_resolution(s, &width, &height);
1634 disp_width = width;
1636 shift_control = (s->gr[0x05] >> 5) & 3;
1637 double_scan = (s->cr[0x09] >> 7);
1638 if (shift_control != 1) {
1639 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1640 } else {
1641 /* in CGA modes, multi_scan is ignored */
1642 /* XXX: is it correct ? */
1643 multi_scan = double_scan;
1645 multi_run = multi_scan;
1646 if (shift_control != s->shift_control ||
1647 double_scan != s->double_scan) {
1648 full_update = 1;
1649 s->shift_control = shift_control;
1650 s->double_scan = double_scan;
1653 if (shift_control == 0) {
1654 if (s->sr[0x01] & 8) {
1655 disp_width <<= 1;
1657 } else if (shift_control == 1) {
1658 if (s->sr[0x01] & 8) {
1659 disp_width <<= 1;
1663 depth = s->get_bpp(s);
1664 if (s->line_offset != s->last_line_offset ||
1665 disp_width != s->last_width ||
1666 height != s->last_height ||
1667 s->last_depth != depth) {
1668 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1669 if (depth == 16 || depth == 32) {
1670 #else
1671 if (depth == 32) {
1672 #endif
1673 qemu_free_displaysurface(s->ds);
1674 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1675 s->line_offset,
1676 s->vram_ptr + (s->start_addr * 4));
1677 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1678 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1679 #endif
1680 dpy_resize(s->ds);
1681 } else {
1682 qemu_console_resize(s->ds, disp_width, height);
1684 s->last_scr_width = disp_width;
1685 s->last_scr_height = height;
1686 s->last_width = disp_width;
1687 s->last_height = height;
1688 s->last_line_offset = s->line_offset;
1689 s->last_depth = depth;
1690 full_update = 1;
1691 } else if (is_buffer_shared(s->ds->surface) &&
1692 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1693 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1694 dpy_setdata(s->ds);
1697 s->rgb_to_pixel =
1698 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1700 if (shift_control == 0) {
1701 full_update |= update_palette16(s);
1702 if (s->sr[0x01] & 8) {
1703 v = VGA_DRAW_LINE4D2;
1704 } else {
1705 v = VGA_DRAW_LINE4;
1707 bits = 4;
1708 } else if (shift_control == 1) {
1709 full_update |= update_palette16(s);
1710 if (s->sr[0x01] & 8) {
1711 v = VGA_DRAW_LINE2D2;
1712 } else {
1713 v = VGA_DRAW_LINE2;
1715 bits = 4;
1716 } else {
1717 switch(s->get_bpp(s)) {
1718 default:
1719 case 0:
1720 full_update |= update_palette256(s);
1721 v = VGA_DRAW_LINE8D2;
1722 bits = 4;
1723 break;
1724 case 8:
1725 full_update |= update_palette256(s);
1726 v = VGA_DRAW_LINE8;
1727 bits = 8;
1728 break;
1729 case 15:
1730 v = VGA_DRAW_LINE15;
1731 bits = 16;
1732 break;
1733 case 16:
1734 v = VGA_DRAW_LINE16;
1735 bits = 16;
1736 break;
1737 case 24:
1738 v = VGA_DRAW_LINE24;
1739 bits = 24;
1740 break;
1741 case 32:
1742 v = VGA_DRAW_LINE32;
1743 bits = 32;
1744 break;
1747 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1749 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1750 s->cursor_invalidate(s);
1752 line_offset = s->line_offset;
1753 #if 0
1754 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",
1755 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1756 #endif
1757 addr1 = (s->start_addr * 4);
1758 bwidth = (width * bits + 7) / 8;
1759 y_start = -1;
1760 page_min = -1;
1761 page_max = 0;
1762 d = ds_get_data(s->ds);
1763 linesize = ds_get_linesize(s->ds);
1764 y1 = 0;
1765 for(y = 0; y < height; y++) {
1766 addr = addr1;
1767 if (!(s->cr[0x17] & 1)) {
1768 int shift;
1769 /* CGA compatibility handling */
1770 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1771 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1773 if (!(s->cr[0x17] & 2)) {
1774 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1776 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1777 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1778 update = full_update |
1779 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1780 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1781 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1782 /* if wide line, can use another page */
1783 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1784 VGA_DIRTY_FLAG);
1786 /* explicit invalidation for the hardware cursor */
1787 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1788 if (update) {
1789 if (y_start < 0)
1790 y_start = y;
1791 if (page0 < page_min)
1792 page_min = page0;
1793 if (page1 > page_max)
1794 page_max = page1;
1795 if (!(is_buffer_shared(s->ds->surface))) {
1796 vga_draw_line(s, d, s->vram_ptr + addr, width);
1797 if (s->cursor_draw_line)
1798 s->cursor_draw_line(s, d, y);
1800 } else {
1801 if (y_start >= 0) {
1802 /* flush to display */
1803 dpy_update(s->ds, 0, y_start,
1804 disp_width, y - y_start);
1805 y_start = -1;
1808 if (!multi_run) {
1809 mask = (s->cr[0x17] & 3) ^ 3;
1810 if ((y1 & mask) == mask)
1811 addr1 += line_offset;
1812 y1++;
1813 multi_run = multi_scan;
1814 } else {
1815 multi_run--;
1817 /* line compare acts on the displayed lines */
1818 if (y == s->line_compare)
1819 addr1 = 0;
1820 d += linesize;
1822 if (y_start >= 0) {
1823 /* flush to display */
1824 dpy_update(s->ds, 0, y_start,
1825 disp_width, y - y_start);
1827 /* reset modified pages */
1828 if (page_max >= page_min) {
1829 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1830 VGA_DIRTY_FLAG);
1832 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1835 static void vga_draw_blank(VGACommonState *s, int full_update)
1837 int i, w, val;
1838 uint8_t *d;
1840 if (!full_update)
1841 return;
1842 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1843 return;
1845 s->rgb_to_pixel =
1846 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1847 if (ds_get_bits_per_pixel(s->ds) == 8)
1848 val = s->rgb_to_pixel(0, 0, 0);
1849 else
1850 val = 0;
1851 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1852 d = ds_get_data(s->ds);
1853 for(i = 0; i < s->last_scr_height; i++) {
1854 memset(d, val, w);
1855 d += ds_get_linesize(s->ds);
1857 dpy_update(s->ds, 0, 0,
1858 s->last_scr_width, s->last_scr_height);
1861 #define GMODE_TEXT 0
1862 #define GMODE_GRAPH 1
1863 #define GMODE_BLANK 2
1865 static void vga_update_display(void *opaque)
1867 VGACommonState *s = opaque;
1868 int full_update, graphic_mode;
1870 if (ds_get_bits_per_pixel(s->ds) == 0) {
1871 /* nothing to do */
1872 } else {
1873 full_update = 0;
1874 if (!(s->ar_index & 0x20)) {
1875 graphic_mode = GMODE_BLANK;
1876 } else {
1877 graphic_mode = s->gr[6] & 1;
1879 if (graphic_mode != s->graphic_mode) {
1880 s->graphic_mode = graphic_mode;
1881 full_update = 1;
1883 switch(graphic_mode) {
1884 case GMODE_TEXT:
1885 vga_draw_text(s, full_update);
1886 break;
1887 case GMODE_GRAPH:
1888 vga_draw_graphic(s, full_update);
1889 break;
1890 case GMODE_BLANK:
1891 default:
1892 vga_draw_blank(s, full_update);
1893 break;
1898 /* force a full display refresh */
1899 static void vga_invalidate_display(void *opaque)
1901 VGACommonState *s = opaque;
1903 s->last_width = -1;
1904 s->last_height = -1;
1907 void vga_common_reset(VGACommonState *s)
1909 s->lfb_addr = 0;
1910 s->lfb_end = 0;
1911 s->map_addr = 0;
1912 s->map_end = 0;
1913 s->lfb_vram_mapped = 0;
1914 s->sr_index = 0;
1915 memset(s->sr, '\0', sizeof(s->sr));
1916 s->gr_index = 0;
1917 memset(s->gr, '\0', sizeof(s->gr));
1918 s->ar_index = 0;
1919 memset(s->ar, '\0', sizeof(s->ar));
1920 s->ar_flip_flop = 0;
1921 s->cr_index = 0;
1922 memset(s->cr, '\0', sizeof(s->cr));
1923 s->msr = 0;
1924 s->fcr = 0;
1925 s->st00 = 0;
1926 s->st01 = 0;
1927 s->dac_state = 0;
1928 s->dac_sub_index = 0;
1929 s->dac_read_index = 0;
1930 s->dac_write_index = 0;
1931 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1932 s->dac_8bit = 0;
1933 memset(s->palette, '\0', sizeof(s->palette));
1934 s->bank_offset = 0;
1935 #ifdef CONFIG_BOCHS_VBE
1936 s->vbe_index = 0;
1937 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1938 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1939 s->vbe_start_addr = 0;
1940 s->vbe_line_offset = 0;
1941 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1942 #endif
1943 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1944 s->graphic_mode = -1; /* force full update */
1945 s->shift_control = 0;
1946 s->double_scan = 0;
1947 s->line_offset = 0;
1948 s->line_compare = 0;
1949 s->start_addr = 0;
1950 s->plane_updated = 0;
1951 s->last_cw = 0;
1952 s->last_ch = 0;
1953 s->last_width = 0;
1954 s->last_height = 0;
1955 s->last_scr_width = 0;
1956 s->last_scr_height = 0;
1957 s->cursor_start = 0;
1958 s->cursor_end = 0;
1959 s->cursor_offset = 0;
1960 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1961 memset(s->last_palette, '\0', sizeof(s->last_palette));
1962 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1963 switch (vga_retrace_method) {
1964 case VGA_RETRACE_DUMB:
1965 break;
1966 case VGA_RETRACE_PRECISE:
1967 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1968 break;
1972 static void vga_reset(void *opaque)
1974 VGACommonState *s = opaque;
1975 vga_common_reset(s);
1978 #define TEXTMODE_X(x) ((x) % width)
1979 #define TEXTMODE_Y(x) ((x) / width)
1980 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1981 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1982 /* relay text rendering to the display driver
1983 * instead of doing a full vga_update_display() */
1984 static void vga_update_text(void *opaque, console_ch_t *chardata)
1986 VGACommonState *s = opaque;
1987 int graphic_mode, i, cursor_offset, cursor_visible;
1988 int cw, cheight, width, height, size, c_min, c_max;
1989 uint32_t *src;
1990 console_ch_t *dst, val;
1991 char msg_buffer[80];
1992 int full_update = 0;
1994 if (!(s->ar_index & 0x20)) {
1995 graphic_mode = GMODE_BLANK;
1996 } else {
1997 graphic_mode = s->gr[6] & 1;
1999 if (graphic_mode != s->graphic_mode) {
2000 s->graphic_mode = graphic_mode;
2001 full_update = 1;
2003 if (s->last_width == -1) {
2004 s->last_width = 0;
2005 full_update = 1;
2008 switch (graphic_mode) {
2009 case GMODE_TEXT:
2010 /* TODO: update palette */
2011 full_update |= update_basic_params(s);
2013 /* total width & height */
2014 cheight = (s->cr[9] & 0x1f) + 1;
2015 cw = 8;
2016 if (!(s->sr[1] & 0x01))
2017 cw = 9;
2018 if (s->sr[1] & 0x08)
2019 cw = 16; /* NOTE: no 18 pixel wide */
2020 width = (s->cr[0x01] + 1);
2021 if (s->cr[0x06] == 100) {
2022 /* ugly hack for CGA 160x100x16 - explain me the logic */
2023 height = 100;
2024 } else {
2025 height = s->cr[0x12] |
2026 ((s->cr[0x07] & 0x02) << 7) |
2027 ((s->cr[0x07] & 0x40) << 3);
2028 height = (height + 1) / cheight;
2031 size = (height * width);
2032 if (size > CH_ATTR_SIZE) {
2033 if (!full_update)
2034 return;
2036 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2037 width, height);
2038 break;
2041 if (width != s->last_width || height != s->last_height ||
2042 cw != s->last_cw || cheight != s->last_ch) {
2043 s->last_scr_width = width * cw;
2044 s->last_scr_height = height * cheight;
2045 s->ds->surface->width = width;
2046 s->ds->surface->height = height;
2047 dpy_resize(s->ds);
2048 s->last_width = width;
2049 s->last_height = height;
2050 s->last_ch = cheight;
2051 s->last_cw = cw;
2052 full_update = 1;
2055 /* Update "hardware" cursor */
2056 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2057 if (cursor_offset != s->cursor_offset ||
2058 s->cr[0xa] != s->cursor_start ||
2059 s->cr[0xb] != s->cursor_end || full_update) {
2060 cursor_visible = !(s->cr[0xa] & 0x20);
2061 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2062 dpy_cursor(s->ds,
2063 TEXTMODE_X(cursor_offset),
2064 TEXTMODE_Y(cursor_offset));
2065 else
2066 dpy_cursor(s->ds, -1, -1);
2067 s->cursor_offset = cursor_offset;
2068 s->cursor_start = s->cr[0xa];
2069 s->cursor_end = s->cr[0xb];
2072 src = (uint32_t *) s->vram_ptr + s->start_addr;
2073 dst = chardata;
2075 if (full_update) {
2076 for (i = 0; i < size; src ++, dst ++, i ++)
2077 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
2079 dpy_update(s->ds, 0, 0, width, height);
2080 } else {
2081 c_max = 0;
2083 for (i = 0; i < size; src ++, dst ++, i ++) {
2084 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2085 if (*dst != val) {
2086 *dst = val;
2087 c_max = i;
2088 break;
2091 c_min = i;
2092 for (; i < size; src ++, dst ++, i ++) {
2093 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2094 if (*dst != val) {
2095 *dst = val;
2096 c_max = i;
2100 if (c_min <= c_max) {
2101 i = TEXTMODE_Y(c_min);
2102 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2106 return;
2107 case GMODE_GRAPH:
2108 if (!full_update)
2109 return;
2111 s->get_resolution(s, &width, &height);
2112 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2113 width, height);
2114 break;
2115 case GMODE_BLANK:
2116 default:
2117 if (!full_update)
2118 return;
2120 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2121 break;
2124 /* Display a message */
2125 s->last_width = 60;
2126 s->last_height = height = 3;
2127 dpy_cursor(s->ds, -1, -1);
2128 s->ds->surface->width = s->last_width;
2129 s->ds->surface->height = height;
2130 dpy_resize(s->ds);
2132 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2133 console_write_ch(dst ++, ' ');
2135 size = strlen(msg_buffer);
2136 width = (s->last_width - size) / 2;
2137 dst = chardata + s->last_width + width;
2138 for (i = 0; i < size; i ++)
2139 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2141 dpy_update(s->ds, 0, 0, s->last_width, height);
2144 CPUReadMemoryFunc * const vga_mem_read[3] = {
2145 vga_mem_readb,
2146 vga_mem_readw,
2147 vga_mem_readl,
2150 CPUWriteMemoryFunc * const vga_mem_write[3] = {
2151 vga_mem_writeb,
2152 vga_mem_writew,
2153 vga_mem_writel,
2156 static int vga_common_post_load(void *opaque, int version_id)
2158 VGACommonState *s = opaque;
2160 /* force refresh */
2161 s->graphic_mode = -1;
2162 return 0;
2165 const VMStateDescription vmstate_vga_common = {
2166 .name = "vga",
2167 .version_id = 2,
2168 .minimum_version_id = 2,
2169 .minimum_version_id_old = 2,
2170 .post_load = vga_common_post_load,
2171 .fields = (VMStateField []) {
2172 VMSTATE_UINT32(latch, VGACommonState),
2173 VMSTATE_UINT8(sr_index, VGACommonState),
2174 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2175 VMSTATE_UINT8(gr_index, VGACommonState),
2176 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2177 VMSTATE_UINT8(ar_index, VGACommonState),
2178 VMSTATE_BUFFER(ar, VGACommonState),
2179 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2180 VMSTATE_UINT8(cr_index, VGACommonState),
2181 VMSTATE_BUFFER(cr, VGACommonState),
2182 VMSTATE_UINT8(msr, VGACommonState),
2183 VMSTATE_UINT8(fcr, VGACommonState),
2184 VMSTATE_UINT8(st00, VGACommonState),
2185 VMSTATE_UINT8(st01, VGACommonState),
2187 VMSTATE_UINT8(dac_state, VGACommonState),
2188 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2189 VMSTATE_UINT8(dac_read_index, VGACommonState),
2190 VMSTATE_UINT8(dac_write_index, VGACommonState),
2191 VMSTATE_BUFFER(dac_cache, VGACommonState),
2192 VMSTATE_BUFFER(palette, VGACommonState),
2194 VMSTATE_INT32(bank_offset, VGACommonState),
2195 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2196 #ifdef CONFIG_BOCHS_VBE
2197 VMSTATE_UINT16(vbe_index, VGACommonState),
2198 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2199 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2200 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2201 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2202 #endif
2203 VMSTATE_END_OF_LIST()
2207 void vga_common_init(VGACommonState *s, int vga_ram_size)
2209 int i, j, v, b;
2211 for(i = 0;i < 256; i++) {
2212 v = 0;
2213 for(j = 0; j < 8; j++) {
2214 v |= ((i >> j) & 1) << (j * 4);
2216 expand4[i] = v;
2218 v = 0;
2219 for(j = 0; j < 4; j++) {
2220 v |= ((i >> (2 * j)) & 3) << (j * 4);
2222 expand2[i] = v;
2224 for(i = 0; i < 16; i++) {
2225 v = 0;
2226 for(j = 0; j < 4; j++) {
2227 b = ((i >> j) & 1);
2228 v |= b << (2 * j);
2229 v |= b << (2 * j + 1);
2231 expand4to8[i] = v;
2234 #ifdef CONFIG_BOCHS_VBE
2235 s->is_vbe_vmstate = 1;
2236 #else
2237 s->is_vbe_vmstate = 0;
2238 #endif
2239 s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
2240 s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
2241 s->vram_size = vga_ram_size;
2242 s->get_bpp = vga_get_bpp;
2243 s->get_offsets = vga_get_offsets;
2244 s->get_resolution = vga_get_resolution;
2245 s->update = vga_update_display;
2246 s->invalidate = vga_invalidate_display;
2247 s->screen_dump = vga_screen_dump;
2248 s->text_update = vga_update_text;
2249 switch (vga_retrace_method) {
2250 case VGA_RETRACE_DUMB:
2251 s->retrace = vga_dumb_retrace;
2252 s->update_retrace_info = vga_dumb_update_retrace_info;
2253 break;
2255 case VGA_RETRACE_PRECISE:
2256 s->retrace = vga_precise_retrace;
2257 s->update_retrace_info = vga_precise_update_retrace_info;
2258 break;
2262 /* used by both ISA and PCI */
2263 int vga_init_io(VGACommonState *s)
2265 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2267 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2268 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2269 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2270 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2272 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2274 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2275 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2276 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2277 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2279 #ifdef CONFIG_BOCHS_VBE
2280 #if defined (TARGET_I386)
2281 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2282 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2284 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2285 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2286 #else
2287 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2288 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2290 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2291 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2292 #endif
2293 #endif /* CONFIG_BOCHS_VBE */
2295 return cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
2296 DEVICE_LITTLE_ENDIAN);
2299 void vga_init(VGACommonState *s)
2301 int vga_io_memory;
2303 qemu_register_reset(vga_reset, s);
2305 s->bank_offset = 0;
2307 vga_io_memory = vga_init_io(s);
2308 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2309 vga_io_memory);
2310 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2313 void vga_init_vbe(VGACommonState *s)
2315 #ifdef CONFIG_BOCHS_VBE
2316 /* XXX: use optimized standard vga accesses */
2317 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2318 VGA_RAM_SIZE, s->vram_offset);
2319 s->vbe_mapped = 1;
2320 #endif
2322 /********************************************************/
2323 /* vga screen dump */
2325 static void vga_save_dpy_update(DisplayState *ds,
2326 int x, int y, int w, int h)
2328 if (screen_dump_filename) {
2329 ppm_save(screen_dump_filename, ds->surface);
2330 screen_dump_filename = NULL;
2334 static void vga_save_dpy_resize(DisplayState *s)
2338 static void vga_save_dpy_refresh(DisplayState *s)
2342 int ppm_save(const char *filename, struct DisplaySurface *ds)
2344 FILE *f;
2345 uint8_t *d, *d1;
2346 uint32_t v;
2347 int y, x;
2348 uint8_t r, g, b;
2350 f = fopen(filename, "wb");
2351 if (!f)
2352 return -1;
2353 fprintf(f, "P6\n%d %d\n%d\n",
2354 ds->width, ds->height, 255);
2355 d1 = ds->data;
2356 for(y = 0; y < ds->height; y++) {
2357 d = d1;
2358 for(x = 0; x < ds->width; x++) {
2359 if (ds->pf.bits_per_pixel == 32)
2360 v = *(uint32_t *)d;
2361 else
2362 v = (uint32_t) (*(uint16_t *)d);
2363 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2364 (ds->pf.rmax + 1);
2365 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2366 (ds->pf.gmax + 1);
2367 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2368 (ds->pf.bmax + 1);
2369 fputc(r, f);
2370 fputc(g, f);
2371 fputc(b, f);
2372 d += ds->pf.bytes_per_pixel;
2374 d1 += ds->linesize;
2376 fclose(f);
2377 return 0;
2380 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2382 DisplayChangeListener *dcl;
2384 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2385 dcl->dpy_update = vga_save_dpy_update;
2386 dcl->dpy_resize = vga_save_dpy_resize;
2387 dcl->dpy_refresh = vga_save_dpy_refresh;
2388 register_displaychangelistener(ds, dcl);
2389 return dcl;
2392 /* save the vga display in a PPM image even if no display is
2393 available */
2394 static void vga_screen_dump(void *opaque, const char *filename)
2396 VGACommonState *s = opaque;
2398 if (!screen_dump_dcl)
2399 screen_dump_dcl = vga_screen_dump_init(s->ds);
2401 screen_dump_filename = (char *)filename;
2402 vga_invalidate_display(s);
2403 vga_hw_update();