linux-user: fix old style decrement usage
[qemu/kraxel.git] / hw / vga.c
blob514371c39b1a66407a95ec1bf3caa6a64271766a
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 div2, sldiv2, dots;
172 int clocking_mode;
173 int clock_sel;
174 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
175 int64_t chars_per_sec;
176 struct vga_precise_retrace *r = &s->retrace_info.precise;
178 htotal_chars = s->cr[0x00] + 5;
179 hretr_start_char = s->cr[0x04];
180 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
181 hretr_end_char = s->cr[0x05] & 0x1f;
183 vtotal_lines = (s->cr[0x06]
184 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
186 vretr_start_line = s->cr[0x10]
187 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
189 vretr_end_line = s->cr[0x11] & 0xf;
192 div2 = (s->cr[0x17] >> 2) & 1;
193 sldiv2 = (s->cr[0x17] >> 3) & 1;
195 clocking_mode = (s->sr[0x01] >> 3) & 1;
196 clock_sel = (s->msr >> 2) & 3;
197 dots = (s->msr & 1) ? 8 : 9;
199 chars_per_sec = clk_hz[clock_sel] / dots;
201 htotal_chars <<= clocking_mode;
203 r->total_chars = vtotal_lines * htotal_chars;
204 if (r->freq) {
205 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
206 } else {
207 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
210 r->vstart = vretr_start_line;
211 r->vend = r->vstart + vretr_end_line + 1;
213 r->hstart = hretr_start_char + hretr_skew_chars;
214 r->hend = r->hstart + hretr_end_char + 1;
215 r->htotal = htotal_chars;
217 #if 0
218 printf (
219 "hz=%f\n"
220 "htotal = %d\n"
221 "hretr_start = %d\n"
222 "hretr_skew = %d\n"
223 "hretr_end = %d\n"
224 "vtotal = %d\n"
225 "vretr_start = %d\n"
226 "vretr_end = %d\n"
227 "div2 = %d sldiv2 = %d\n"
228 "clocking_mode = %d\n"
229 "clock_sel = %d %d\n"
230 "dots = %d\n"
231 "ticks/char = %lld\n"
232 "\n",
233 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
234 htotal_chars,
235 hretr_start_char,
236 hretr_skew_chars,
237 hretr_end_char,
238 vtotal_lines,
239 vretr_start_line,
240 vretr_end_line,
241 div2, sldiv2,
242 clocking_mode,
243 clock_sel,
244 clk_hz[clock_sel],
245 dots,
246 r->ticks_per_char
248 #endif
251 static uint8_t vga_precise_retrace(VGACommonState *s)
253 struct vga_precise_retrace *r = &s->retrace_info.precise;
254 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
256 if (r->total_chars) {
257 int cur_line, cur_line_char, cur_char;
258 int64_t cur_tick;
260 cur_tick = qemu_get_clock(vm_clock);
262 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
263 cur_line = cur_char / r->htotal;
265 if (cur_line >= r->vstart && cur_line <= r->vend) {
266 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
267 } else {
268 cur_line_char = cur_char % r->htotal;
269 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
270 val |= ST01_DISP_ENABLE;
274 return val;
275 } else {
276 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
280 static uint8_t vga_dumb_retrace(VGACommonState *s)
282 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
285 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
287 if (s->msr & MSR_COLOR_EMULATION) {
288 /* Color */
289 return (addr >= 0x3b0 && addr <= 0x3bf);
290 } else {
291 /* Monochrome */
292 return (addr >= 0x3d0 && addr <= 0x3df);
296 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
298 VGACommonState *s = opaque;
299 int val, index;
301 if (vga_ioport_invalid(s, addr)) {
302 val = 0xff;
303 } else {
304 switch(addr) {
305 case 0x3c0:
306 if (s->ar_flip_flop == 0) {
307 val = s->ar_index;
308 } else {
309 val = 0;
311 break;
312 case 0x3c1:
313 index = s->ar_index & 0x1f;
314 if (index < 21)
315 val = s->ar[index];
316 else
317 val = 0;
318 break;
319 case 0x3c2:
320 val = s->st00;
321 break;
322 case 0x3c4:
323 val = s->sr_index;
324 break;
325 case 0x3c5:
326 val = s->sr[s->sr_index];
327 #ifdef DEBUG_VGA_REG
328 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
329 #endif
330 break;
331 case 0x3c7:
332 val = s->dac_state;
333 break;
334 case 0x3c8:
335 val = s->dac_write_index;
336 break;
337 case 0x3c9:
338 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
339 if (++s->dac_sub_index == 3) {
340 s->dac_sub_index = 0;
341 s->dac_read_index++;
343 break;
344 case 0x3ca:
345 val = s->fcr;
346 break;
347 case 0x3cc:
348 val = s->msr;
349 break;
350 case 0x3ce:
351 val = s->gr_index;
352 break;
353 case 0x3cf:
354 val = s->gr[s->gr_index];
355 #ifdef DEBUG_VGA_REG
356 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
357 #endif
358 break;
359 case 0x3b4:
360 case 0x3d4:
361 val = s->cr_index;
362 break;
363 case 0x3b5:
364 case 0x3d5:
365 val = s->cr[s->cr_index];
366 #ifdef DEBUG_VGA_REG
367 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
368 #endif
369 break;
370 case 0x3ba:
371 case 0x3da:
372 /* just toggle to fool polling */
373 val = s->st01 = s->retrace(s);
374 s->ar_flip_flop = 0;
375 break;
376 default:
377 val = 0x00;
378 break;
381 #if defined(DEBUG_VGA)
382 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
383 #endif
384 return val;
387 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
389 VGACommonState *s = opaque;
390 int index;
392 /* check port range access depending on color/monochrome mode */
393 if (vga_ioport_invalid(s, addr)) {
394 return;
396 #ifdef DEBUG_VGA
397 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
398 #endif
400 switch(addr) {
401 case 0x3c0:
402 if (s->ar_flip_flop == 0) {
403 val &= 0x3f;
404 s->ar_index = val;
405 } else {
406 index = s->ar_index & 0x1f;
407 switch(index) {
408 case 0x00 ... 0x0f:
409 s->ar[index] = val & 0x3f;
410 break;
411 case 0x10:
412 s->ar[index] = val & ~0x10;
413 break;
414 case 0x11:
415 s->ar[index] = val;
416 break;
417 case 0x12:
418 s->ar[index] = val & ~0xc0;
419 break;
420 case 0x13:
421 s->ar[index] = val & ~0xf0;
422 break;
423 case 0x14:
424 s->ar[index] = val & ~0xf0;
425 break;
426 default:
427 break;
430 s->ar_flip_flop ^= 1;
431 break;
432 case 0x3c2:
433 s->msr = val & ~0x10;
434 s->update_retrace_info(s);
435 break;
436 case 0x3c4:
437 s->sr_index = val & 7;
438 break;
439 case 0x3c5:
440 #ifdef DEBUG_VGA_REG
441 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
442 #endif
443 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
444 if (s->sr_index == 1) s->update_retrace_info(s);
445 break;
446 case 0x3c7:
447 s->dac_read_index = val;
448 s->dac_sub_index = 0;
449 s->dac_state = 3;
450 break;
451 case 0x3c8:
452 s->dac_write_index = val;
453 s->dac_sub_index = 0;
454 s->dac_state = 0;
455 break;
456 case 0x3c9:
457 s->dac_cache[s->dac_sub_index] = val;
458 if (++s->dac_sub_index == 3) {
459 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
460 s->dac_sub_index = 0;
461 s->dac_write_index++;
463 break;
464 case 0x3ce:
465 s->gr_index = val & 0x0f;
466 break;
467 case 0x3cf:
468 #ifdef DEBUG_VGA_REG
469 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
470 #endif
471 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
472 break;
473 case 0x3b4:
474 case 0x3d4:
475 s->cr_index = val;
476 break;
477 case 0x3b5:
478 case 0x3d5:
479 #ifdef DEBUG_VGA_REG
480 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
481 #endif
482 /* handle CR0-7 protection */
483 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
484 /* can always write bit 4 of CR7 */
485 if (s->cr_index == 7)
486 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
487 return;
489 s->cr[s->cr_index] = val;
491 switch(s->cr_index) {
492 case 0x00:
493 case 0x04:
494 case 0x05:
495 case 0x06:
496 case 0x07:
497 case 0x11:
498 case 0x17:
499 s->update_retrace_info(s);
500 break;
502 break;
503 case 0x3ba:
504 case 0x3da:
505 s->fcr = val & 0x10;
506 break;
510 #ifdef CONFIG_BOCHS_VBE
511 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
513 VGACommonState *s = opaque;
514 uint32_t val;
515 val = s->vbe_index;
516 return val;
519 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
521 VGACommonState *s = opaque;
522 uint32_t val;
524 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
525 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
526 switch(s->vbe_index) {
527 /* XXX: do not hardcode ? */
528 case VBE_DISPI_INDEX_XRES:
529 val = VBE_DISPI_MAX_XRES;
530 break;
531 case VBE_DISPI_INDEX_YRES:
532 val = VBE_DISPI_MAX_YRES;
533 break;
534 case VBE_DISPI_INDEX_BPP:
535 val = VBE_DISPI_MAX_BPP;
536 break;
537 default:
538 val = s->vbe_regs[s->vbe_index];
539 break;
541 } else {
542 val = s->vbe_regs[s->vbe_index];
544 } else {
545 val = 0;
547 #ifdef DEBUG_BOCHS_VBE
548 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
549 #endif
550 return val;
553 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
555 VGACommonState *s = opaque;
556 s->vbe_index = val;
559 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
561 VGACommonState *s = opaque;
563 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
564 #ifdef DEBUG_BOCHS_VBE
565 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
566 #endif
567 switch(s->vbe_index) {
568 case VBE_DISPI_INDEX_ID:
569 if (val == VBE_DISPI_ID0 ||
570 val == VBE_DISPI_ID1 ||
571 val == VBE_DISPI_ID2 ||
572 val == VBE_DISPI_ID3 ||
573 val == VBE_DISPI_ID4) {
574 s->vbe_regs[s->vbe_index] = val;
576 break;
577 case VBE_DISPI_INDEX_XRES:
578 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
579 s->vbe_regs[s->vbe_index] = val;
581 break;
582 case VBE_DISPI_INDEX_YRES:
583 if (val <= VBE_DISPI_MAX_YRES) {
584 s->vbe_regs[s->vbe_index] = val;
586 break;
587 case VBE_DISPI_INDEX_BPP:
588 if (val == 0)
589 val = 8;
590 if (val == 4 || val == 8 || val == 15 ||
591 val == 16 || val == 24 || val == 32) {
592 s->vbe_regs[s->vbe_index] = val;
594 break;
595 case VBE_DISPI_INDEX_BANK:
596 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
597 val &= (s->vbe_bank_mask >> 2);
598 } else {
599 val &= s->vbe_bank_mask;
601 s->vbe_regs[s->vbe_index] = val;
602 s->bank_offset = (val << 16);
603 break;
604 case VBE_DISPI_INDEX_ENABLE:
605 if ((val & VBE_DISPI_ENABLED) &&
606 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
607 int h, shift_control;
609 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
610 s->vbe_regs[VBE_DISPI_INDEX_XRES];
611 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
612 s->vbe_regs[VBE_DISPI_INDEX_YRES];
613 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
614 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
616 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
617 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
618 else
619 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
620 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
621 s->vbe_start_addr = 0;
623 /* clear the screen (should be done in BIOS) */
624 if (!(val & VBE_DISPI_NOCLEARMEM)) {
625 memset(s->vram_ptr, 0,
626 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
629 /* we initialize the VGA graphic mode (should be done
630 in BIOS) */
631 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
632 s->cr[0x17] |= 3; /* no CGA modes */
633 s->cr[0x13] = s->vbe_line_offset >> 3;
634 /* width */
635 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
636 /* height (only meaningful if < 1024) */
637 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
638 s->cr[0x12] = h;
639 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
640 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
641 /* line compare to 1023 */
642 s->cr[0x18] = 0xff;
643 s->cr[0x07] |= 0x10;
644 s->cr[0x09] |= 0x40;
646 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
647 shift_control = 0;
648 s->sr[0x01] &= ~8; /* no double line */
649 } else {
650 shift_control = 2;
651 s->sr[4] |= 0x08; /* set chain 4 mode */
652 s->sr[2] |= 0x0f; /* activate all planes */
654 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
655 s->cr[0x09] &= ~0x9f; /* no double scan */
656 } else {
657 /* XXX: the bios should do that */
658 s->bank_offset = 0;
660 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
661 s->vbe_regs[s->vbe_index] = val;
662 break;
663 case VBE_DISPI_INDEX_VIRT_WIDTH:
665 int w, h, line_offset;
667 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
668 return;
669 w = val;
670 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
671 line_offset = w >> 1;
672 else
673 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
674 h = s->vram_size / line_offset;
675 /* XXX: support weird bochs semantics ? */
676 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
677 return;
678 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
679 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
680 s->vbe_line_offset = line_offset;
682 break;
683 case VBE_DISPI_INDEX_X_OFFSET:
684 case VBE_DISPI_INDEX_Y_OFFSET:
686 int x;
687 s->vbe_regs[s->vbe_index] = val;
688 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
689 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
690 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
691 s->vbe_start_addr += x >> 1;
692 else
693 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
694 s->vbe_start_addr >>= 2;
696 break;
697 default:
698 break;
702 #endif
704 /* called for accesses between 0xa0000 and 0xc0000 */
705 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
707 VGACommonState *s = opaque;
708 int memory_map_mode, plane;
709 uint32_t ret;
711 /* convert to VGA memory offset */
712 memory_map_mode = (s->gr[6] >> 2) & 3;
713 addr &= 0x1ffff;
714 switch(memory_map_mode) {
715 case 0:
716 break;
717 case 1:
718 if (addr >= 0x10000)
719 return 0xff;
720 addr += s->bank_offset;
721 break;
722 case 2:
723 addr -= 0x10000;
724 if (addr >= 0x8000)
725 return 0xff;
726 break;
727 default:
728 case 3:
729 addr -= 0x18000;
730 if (addr >= 0x8000)
731 return 0xff;
732 break;
735 if (s->sr[4] & 0x08) {
736 /* chain 4 mode : simplest access */
737 ret = s->vram_ptr[addr];
738 } else if (s->gr[5] & 0x10) {
739 /* odd/even mode (aka text mode mapping) */
740 plane = (s->gr[4] & 2) | (addr & 1);
741 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
742 } else {
743 /* standard VGA latched access */
744 s->latch = ((uint32_t *)s->vram_ptr)[addr];
746 if (!(s->gr[5] & 0x08)) {
747 /* read mode 0 */
748 plane = s->gr[4];
749 ret = GET_PLANE(s->latch, plane);
750 } else {
751 /* read mode 1 */
752 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
753 ret |= ret >> 16;
754 ret |= ret >> 8;
755 ret = (~ret) & 0xff;
758 return ret;
761 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
763 uint32_t v;
764 #ifdef TARGET_WORDS_BIGENDIAN
765 v = vga_mem_readb(opaque, addr) << 8;
766 v |= vga_mem_readb(opaque, addr + 1);
767 #else
768 v = vga_mem_readb(opaque, addr);
769 v |= vga_mem_readb(opaque, addr + 1) << 8;
770 #endif
771 return v;
774 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
776 uint32_t v;
777 #ifdef TARGET_WORDS_BIGENDIAN
778 v = vga_mem_readb(opaque, addr) << 24;
779 v |= vga_mem_readb(opaque, addr + 1) << 16;
780 v |= vga_mem_readb(opaque, addr + 2) << 8;
781 v |= vga_mem_readb(opaque, addr + 3);
782 #else
783 v = vga_mem_readb(opaque, addr);
784 v |= vga_mem_readb(opaque, addr + 1) << 8;
785 v |= vga_mem_readb(opaque, addr + 2) << 16;
786 v |= vga_mem_readb(opaque, addr + 3) << 24;
787 #endif
788 return v;
791 /* called for accesses between 0xa0000 and 0xc0000 */
792 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
794 VGACommonState *s = opaque;
795 int memory_map_mode, plane, write_mode, b, func_select, mask;
796 uint32_t write_mask, bit_mask, set_mask;
798 #ifdef DEBUG_VGA_MEM
799 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
800 #endif
801 /* convert to VGA memory offset */
802 memory_map_mode = (s->gr[6] >> 2) & 3;
803 addr &= 0x1ffff;
804 switch(memory_map_mode) {
805 case 0:
806 break;
807 case 1:
808 if (addr >= 0x10000)
809 return;
810 addr += s->bank_offset;
811 break;
812 case 2:
813 addr -= 0x10000;
814 if (addr >= 0x8000)
815 return;
816 break;
817 default:
818 case 3:
819 addr -= 0x18000;
820 if (addr >= 0x8000)
821 return;
822 break;
825 if (s->sr[4] & 0x08) {
826 /* chain 4 mode : simplest access */
827 plane = addr & 3;
828 mask = (1 << plane);
829 if (s->sr[2] & mask) {
830 s->vram_ptr[addr] = val;
831 #ifdef DEBUG_VGA_MEM
832 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
833 #endif
834 s->plane_updated |= mask; /* only used to detect font change */
835 cpu_physical_memory_set_dirty(s->vram_offset + addr);
837 } else if (s->gr[5] & 0x10) {
838 /* odd/even mode (aka text mode mapping) */
839 plane = (s->gr[4] & 2) | (addr & 1);
840 mask = (1 << plane);
841 if (s->sr[2] & mask) {
842 addr = ((addr & ~1) << 1) | plane;
843 s->vram_ptr[addr] = val;
844 #ifdef DEBUG_VGA_MEM
845 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
846 #endif
847 s->plane_updated |= mask; /* only used to detect font change */
848 cpu_physical_memory_set_dirty(s->vram_offset + addr);
850 } else {
851 /* standard VGA latched access */
852 write_mode = s->gr[5] & 3;
853 switch(write_mode) {
854 default:
855 case 0:
856 /* rotate */
857 b = s->gr[3] & 7;
858 val = ((val >> b) | (val << (8 - b))) & 0xff;
859 val |= val << 8;
860 val |= val << 16;
862 /* apply set/reset mask */
863 set_mask = mask16[s->gr[1]];
864 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
865 bit_mask = s->gr[8];
866 break;
867 case 1:
868 val = s->latch;
869 goto do_write;
870 case 2:
871 val = mask16[val & 0x0f];
872 bit_mask = s->gr[8];
873 break;
874 case 3:
875 /* rotate */
876 b = s->gr[3] & 7;
877 val = (val >> b) | (val << (8 - b));
879 bit_mask = s->gr[8] & val;
880 val = mask16[s->gr[0]];
881 break;
884 /* apply logical operation */
885 func_select = s->gr[3] >> 3;
886 switch(func_select) {
887 case 0:
888 default:
889 /* nothing to do */
890 break;
891 case 1:
892 /* and */
893 val &= s->latch;
894 break;
895 case 2:
896 /* or */
897 val |= s->latch;
898 break;
899 case 3:
900 /* xor */
901 val ^= s->latch;
902 break;
905 /* apply bit mask */
906 bit_mask |= bit_mask << 8;
907 bit_mask |= bit_mask << 16;
908 val = (val & bit_mask) | (s->latch & ~bit_mask);
910 do_write:
911 /* mask data according to sr[2] */
912 mask = s->sr[2];
913 s->plane_updated |= mask; /* only used to detect font change */
914 write_mask = mask16[mask];
915 ((uint32_t *)s->vram_ptr)[addr] =
916 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
917 (val & write_mask);
918 #ifdef DEBUG_VGA_MEM
919 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
920 addr * 4, write_mask, val);
921 #endif
922 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
926 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
928 #ifdef TARGET_WORDS_BIGENDIAN
929 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
930 vga_mem_writeb(opaque, addr + 1, val & 0xff);
931 #else
932 vga_mem_writeb(opaque, addr, val & 0xff);
933 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
934 #endif
937 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
939 #ifdef TARGET_WORDS_BIGENDIAN
940 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
941 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
942 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
943 vga_mem_writeb(opaque, addr + 3, val & 0xff);
944 #else
945 vga_mem_writeb(opaque, addr, val & 0xff);
946 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
947 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
948 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
949 #endif
952 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
953 const uint8_t *font_ptr, int h,
954 uint32_t fgcol, uint32_t bgcol);
955 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
956 const uint8_t *font_ptr, int h,
957 uint32_t fgcol, uint32_t bgcol, int dup9);
958 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
959 const uint8_t *s, int width);
961 #define DEPTH 8
962 #include "vga_template.h"
964 #define DEPTH 15
965 #include "vga_template.h"
967 #define BGR_FORMAT
968 #define DEPTH 15
969 #include "vga_template.h"
971 #define DEPTH 16
972 #include "vga_template.h"
974 #define BGR_FORMAT
975 #define DEPTH 16
976 #include "vga_template.h"
978 #define DEPTH 32
979 #include "vga_template.h"
981 #define BGR_FORMAT
982 #define DEPTH 32
983 #include "vga_template.h"
985 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
987 unsigned int col;
988 col = rgb_to_pixel8(r, g, b);
989 col |= col << 8;
990 col |= col << 16;
991 return col;
994 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
996 unsigned int col;
997 col = rgb_to_pixel15(r, g, b);
998 col |= col << 16;
999 return col;
1002 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1003 unsigned int b)
1005 unsigned int col;
1006 col = rgb_to_pixel15bgr(r, g, b);
1007 col |= col << 16;
1008 return col;
1011 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1013 unsigned int col;
1014 col = rgb_to_pixel16(r, g, b);
1015 col |= col << 16;
1016 return col;
1019 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1020 unsigned int b)
1022 unsigned int col;
1023 col = rgb_to_pixel16bgr(r, g, b);
1024 col |= col << 16;
1025 return col;
1028 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1030 unsigned int col;
1031 col = rgb_to_pixel32(r, g, b);
1032 return col;
1035 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1037 unsigned int col;
1038 col = rgb_to_pixel32bgr(r, g, b);
1039 return col;
1042 /* return true if the palette was modified */
1043 static int update_palette16(VGACommonState *s)
1045 int full_update, i;
1046 uint32_t v, col, *palette;
1048 full_update = 0;
1049 palette = s->last_palette;
1050 for(i = 0; i < 16; i++) {
1051 v = s->ar[i];
1052 if (s->ar[0x10] & 0x80)
1053 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1054 else
1055 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1056 v = v * 3;
1057 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1058 c6_to_8(s->palette[v + 1]),
1059 c6_to_8(s->palette[v + 2]));
1060 if (col != palette[i]) {
1061 full_update = 1;
1062 palette[i] = col;
1065 return full_update;
1068 /* return true if the palette was modified */
1069 static int update_palette256(VGACommonState *s)
1071 int full_update, i;
1072 uint32_t v, col, *palette;
1074 full_update = 0;
1075 palette = s->last_palette;
1076 v = 0;
1077 for(i = 0; i < 256; i++) {
1078 if (s->dac_8bit) {
1079 col = s->rgb_to_pixel(s->palette[v],
1080 s->palette[v + 1],
1081 s->palette[v + 2]);
1082 } else {
1083 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1084 c6_to_8(s->palette[v + 1]),
1085 c6_to_8(s->palette[v + 2]));
1087 if (col != palette[i]) {
1088 full_update = 1;
1089 palette[i] = col;
1091 v += 3;
1093 return full_update;
1096 static void vga_get_offsets(VGACommonState *s,
1097 uint32_t *pline_offset,
1098 uint32_t *pstart_addr,
1099 uint32_t *pline_compare)
1101 uint32_t start_addr, line_offset, line_compare;
1102 #ifdef CONFIG_BOCHS_VBE
1103 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1104 line_offset = s->vbe_line_offset;
1105 start_addr = s->vbe_start_addr;
1106 line_compare = 65535;
1107 } else
1108 #endif
1110 /* compute line_offset in bytes */
1111 line_offset = s->cr[0x13];
1112 line_offset <<= 3;
1114 /* starting address */
1115 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1117 /* line compare */
1118 line_compare = s->cr[0x18] |
1119 ((s->cr[0x07] & 0x10) << 4) |
1120 ((s->cr[0x09] & 0x40) << 3);
1122 *pline_offset = line_offset;
1123 *pstart_addr = start_addr;
1124 *pline_compare = line_compare;
1127 /* update start_addr and line_offset. Return TRUE if modified */
1128 static int update_basic_params(VGACommonState *s)
1130 int full_update;
1131 uint32_t start_addr, line_offset, line_compare;
1133 full_update = 0;
1135 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1137 if (line_offset != s->line_offset ||
1138 start_addr != s->start_addr ||
1139 line_compare != s->line_compare) {
1140 s->line_offset = line_offset;
1141 s->start_addr = start_addr;
1142 s->line_compare = line_compare;
1143 full_update = 1;
1145 return full_update;
1148 #define NB_DEPTHS 7
1150 static inline int get_depth_index(DisplayState *s)
1152 switch(ds_get_bits_per_pixel(s)) {
1153 default:
1154 case 8:
1155 return 0;
1156 case 15:
1157 return 1;
1158 case 16:
1159 return 2;
1160 case 32:
1161 if (is_surface_bgr(s->surface))
1162 return 4;
1163 else
1164 return 3;
1168 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1169 vga_draw_glyph8_8,
1170 vga_draw_glyph8_16,
1171 vga_draw_glyph8_16,
1172 vga_draw_glyph8_32,
1173 vga_draw_glyph8_32,
1174 vga_draw_glyph8_16,
1175 vga_draw_glyph8_16,
1178 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1179 vga_draw_glyph16_8,
1180 vga_draw_glyph16_16,
1181 vga_draw_glyph16_16,
1182 vga_draw_glyph16_32,
1183 vga_draw_glyph16_32,
1184 vga_draw_glyph16_16,
1185 vga_draw_glyph16_16,
1188 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1189 vga_draw_glyph9_8,
1190 vga_draw_glyph9_16,
1191 vga_draw_glyph9_16,
1192 vga_draw_glyph9_32,
1193 vga_draw_glyph9_32,
1194 vga_draw_glyph9_16,
1195 vga_draw_glyph9_16,
1198 static const uint8_t cursor_glyph[32 * 4] = {
1199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1217 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1218 int *pcwidth, int *pcheight)
1220 int width, cwidth, height, cheight;
1222 /* total width & height */
1223 cheight = (s->cr[9] & 0x1f) + 1;
1224 cwidth = 8;
1225 if (!(s->sr[1] & 0x01))
1226 cwidth = 9;
1227 if (s->sr[1] & 0x08)
1228 cwidth = 16; /* NOTE: no 18 pixel wide */
1229 width = (s->cr[0x01] + 1);
1230 if (s->cr[0x06] == 100) {
1231 /* ugly hack for CGA 160x100x16 - explain me the logic */
1232 height = 100;
1233 } else {
1234 height = s->cr[0x12] |
1235 ((s->cr[0x07] & 0x02) << 7) |
1236 ((s->cr[0x07] & 0x40) << 3);
1237 height = (height + 1) / cheight;
1240 *pwidth = width;
1241 *pheight = height;
1242 *pcwidth = cwidth;
1243 *pcheight = cheight;
1246 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1248 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1249 rgb_to_pixel8_dup,
1250 rgb_to_pixel15_dup,
1251 rgb_to_pixel16_dup,
1252 rgb_to_pixel32_dup,
1253 rgb_to_pixel32bgr_dup,
1254 rgb_to_pixel15bgr_dup,
1255 rgb_to_pixel16bgr_dup,
1259 * Text mode update
1260 * Missing:
1261 * - double scan
1262 * - double width
1263 * - underline
1264 * - flashing
1266 static void vga_draw_text(VGACommonState *s, int full_update)
1268 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1269 int cx_min, cx_max, linesize, x_incr;
1270 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1271 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1272 const uint8_t *font_ptr, *font_base[2];
1273 int dup9, line_offset, depth_index;
1274 uint32_t *palette;
1275 uint32_t *ch_attr_ptr;
1276 vga_draw_glyph8_func *vga_draw_glyph8;
1277 vga_draw_glyph9_func *vga_draw_glyph9;
1279 /* compute font data address (in plane 2) */
1280 v = s->sr[3];
1281 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1282 if (offset != s->font_offsets[0]) {
1283 s->font_offsets[0] = offset;
1284 full_update = 1;
1286 font_base[0] = s->vram_ptr + offset;
1288 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1289 font_base[1] = s->vram_ptr + offset;
1290 if (offset != s->font_offsets[1]) {
1291 s->font_offsets[1] = offset;
1292 full_update = 1;
1294 if (s->plane_updated & (1 << 2)) {
1295 /* if the plane 2 was modified since the last display, it
1296 indicates the font may have been modified */
1297 s->plane_updated = 0;
1298 full_update = 1;
1300 full_update |= update_basic_params(s);
1302 line_offset = s->line_offset;
1303 s1 = s->vram_ptr + (s->start_addr * 4);
1305 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1306 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1307 if ((height * width) > CH_ATTR_SIZE) {
1308 /* better than nothing: exit if transient size is too big */
1309 return;
1312 if (width != s->last_width || height != s->last_height ||
1313 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1314 s->last_scr_width = width * cw;
1315 s->last_scr_height = height * cheight;
1316 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1317 s->last_depth = 0;
1318 s->last_width = width;
1319 s->last_height = height;
1320 s->last_ch = cheight;
1321 s->last_cw = cw;
1322 full_update = 1;
1324 s->rgb_to_pixel =
1325 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1326 full_update |= update_palette16(s);
1327 palette = s->last_palette;
1328 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1330 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1331 if (cursor_offset != s->cursor_offset ||
1332 s->cr[0xa] != s->cursor_start ||
1333 s->cr[0xb] != s->cursor_end) {
1334 /* if the cursor position changed, we update the old and new
1335 chars */
1336 if (s->cursor_offset < CH_ATTR_SIZE)
1337 s->last_ch_attr[s->cursor_offset] = -1;
1338 if (cursor_offset < CH_ATTR_SIZE)
1339 s->last_ch_attr[cursor_offset] = -1;
1340 s->cursor_offset = cursor_offset;
1341 s->cursor_start = s->cr[0xa];
1342 s->cursor_end = s->cr[0xb];
1344 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1346 depth_index = get_depth_index(s->ds);
1347 if (cw == 16)
1348 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1349 else
1350 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1351 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1353 dest = ds_get_data(s->ds);
1354 linesize = ds_get_linesize(s->ds);
1355 ch_attr_ptr = s->last_ch_attr;
1356 for(cy = 0; cy < height; cy++) {
1357 d1 = dest;
1358 src = s1;
1359 cx_min = width;
1360 cx_max = -1;
1361 for(cx = 0; cx < width; cx++) {
1362 ch_attr = *(uint16_t *)src;
1363 if (full_update || ch_attr != *ch_attr_ptr) {
1364 if (cx < cx_min)
1365 cx_min = cx;
1366 if (cx > cx_max)
1367 cx_max = cx;
1368 *ch_attr_ptr = ch_attr;
1369 #ifdef HOST_WORDS_BIGENDIAN
1370 ch = ch_attr >> 8;
1371 cattr = ch_attr & 0xff;
1372 #else
1373 ch = ch_attr & 0xff;
1374 cattr = ch_attr >> 8;
1375 #endif
1376 font_ptr = font_base[(cattr >> 3) & 1];
1377 font_ptr += 32 * 4 * ch;
1378 bgcol = palette[cattr >> 4];
1379 fgcol = palette[cattr & 0x0f];
1380 if (cw != 9) {
1381 vga_draw_glyph8(d1, linesize,
1382 font_ptr, cheight, fgcol, bgcol);
1383 } else {
1384 dup9 = 0;
1385 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1386 dup9 = 1;
1387 vga_draw_glyph9(d1, linesize,
1388 font_ptr, cheight, fgcol, bgcol, dup9);
1390 if (src == cursor_ptr &&
1391 !(s->cr[0x0a] & 0x20)) {
1392 int line_start, line_last, h;
1393 /* draw the cursor */
1394 line_start = s->cr[0x0a] & 0x1f;
1395 line_last = s->cr[0x0b] & 0x1f;
1396 /* XXX: check that */
1397 if (line_last > cheight - 1)
1398 line_last = cheight - 1;
1399 if (line_last >= line_start && line_start < cheight) {
1400 h = line_last - line_start + 1;
1401 d = d1 + linesize * line_start;
1402 if (cw != 9) {
1403 vga_draw_glyph8(d, linesize,
1404 cursor_glyph, h, fgcol, bgcol);
1405 } else {
1406 vga_draw_glyph9(d, linesize,
1407 cursor_glyph, h, fgcol, bgcol, 1);
1412 d1 += x_incr;
1413 src += 4;
1414 ch_attr_ptr++;
1416 if (cx_max != -1) {
1417 dpy_update(s->ds, cx_min * cw, cy * cheight,
1418 (cx_max - cx_min + 1) * cw, cheight);
1420 dest += linesize * cheight;
1421 s1 += line_offset;
1425 enum {
1426 VGA_DRAW_LINE2,
1427 VGA_DRAW_LINE2D2,
1428 VGA_DRAW_LINE4,
1429 VGA_DRAW_LINE4D2,
1430 VGA_DRAW_LINE8D2,
1431 VGA_DRAW_LINE8,
1432 VGA_DRAW_LINE15,
1433 VGA_DRAW_LINE16,
1434 VGA_DRAW_LINE24,
1435 VGA_DRAW_LINE32,
1436 VGA_DRAW_LINE_NB,
1439 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1440 vga_draw_line2_8,
1441 vga_draw_line2_16,
1442 vga_draw_line2_16,
1443 vga_draw_line2_32,
1444 vga_draw_line2_32,
1445 vga_draw_line2_16,
1446 vga_draw_line2_16,
1448 vga_draw_line2d2_8,
1449 vga_draw_line2d2_16,
1450 vga_draw_line2d2_16,
1451 vga_draw_line2d2_32,
1452 vga_draw_line2d2_32,
1453 vga_draw_line2d2_16,
1454 vga_draw_line2d2_16,
1456 vga_draw_line4_8,
1457 vga_draw_line4_16,
1458 vga_draw_line4_16,
1459 vga_draw_line4_32,
1460 vga_draw_line4_32,
1461 vga_draw_line4_16,
1462 vga_draw_line4_16,
1464 vga_draw_line4d2_8,
1465 vga_draw_line4d2_16,
1466 vga_draw_line4d2_16,
1467 vga_draw_line4d2_32,
1468 vga_draw_line4d2_32,
1469 vga_draw_line4d2_16,
1470 vga_draw_line4d2_16,
1472 vga_draw_line8d2_8,
1473 vga_draw_line8d2_16,
1474 vga_draw_line8d2_16,
1475 vga_draw_line8d2_32,
1476 vga_draw_line8d2_32,
1477 vga_draw_line8d2_16,
1478 vga_draw_line8d2_16,
1480 vga_draw_line8_8,
1481 vga_draw_line8_16,
1482 vga_draw_line8_16,
1483 vga_draw_line8_32,
1484 vga_draw_line8_32,
1485 vga_draw_line8_16,
1486 vga_draw_line8_16,
1488 vga_draw_line15_8,
1489 vga_draw_line15_15,
1490 vga_draw_line15_16,
1491 vga_draw_line15_32,
1492 vga_draw_line15_32bgr,
1493 vga_draw_line15_15bgr,
1494 vga_draw_line15_16bgr,
1496 vga_draw_line16_8,
1497 vga_draw_line16_15,
1498 vga_draw_line16_16,
1499 vga_draw_line16_32,
1500 vga_draw_line16_32bgr,
1501 vga_draw_line16_15bgr,
1502 vga_draw_line16_16bgr,
1504 vga_draw_line24_8,
1505 vga_draw_line24_15,
1506 vga_draw_line24_16,
1507 vga_draw_line24_32,
1508 vga_draw_line24_32bgr,
1509 vga_draw_line24_15bgr,
1510 vga_draw_line24_16bgr,
1512 vga_draw_line32_8,
1513 vga_draw_line32_15,
1514 vga_draw_line32_16,
1515 vga_draw_line32_32,
1516 vga_draw_line32_32bgr,
1517 vga_draw_line32_15bgr,
1518 vga_draw_line32_16bgr,
1521 static int vga_get_bpp(VGACommonState *s)
1523 int ret;
1524 #ifdef CONFIG_BOCHS_VBE
1525 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1526 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1527 } else
1528 #endif
1530 ret = 0;
1532 return ret;
1535 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1537 int width, height;
1539 #ifdef CONFIG_BOCHS_VBE
1540 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1541 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1542 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1543 } else
1544 #endif
1546 width = (s->cr[0x01] + 1) * 8;
1547 height = s->cr[0x12] |
1548 ((s->cr[0x07] & 0x02) << 7) |
1549 ((s->cr[0x07] & 0x40) << 3);
1550 height = (height + 1);
1552 *pwidth = width;
1553 *pheight = height;
1556 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1558 int y;
1559 if (y1 >= VGA_MAX_HEIGHT)
1560 return;
1561 if (y2 >= VGA_MAX_HEIGHT)
1562 y2 = VGA_MAX_HEIGHT;
1563 for(y = y1; y < y2; y++) {
1564 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1568 static void vga_sync_dirty_bitmap(VGACommonState *s)
1570 if (s->map_addr)
1571 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1573 if (s->lfb_vram_mapped) {
1574 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1575 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1580 * graphic modes
1582 static void vga_draw_graphic(VGACommonState *s, int full_update)
1584 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1585 int width, height, shift_control, line_offset, bwidth, bits;
1586 ram_addr_t page0, page1, page_min, page_max;
1587 int disp_width, multi_scan, multi_run;
1588 uint8_t *d;
1589 uint32_t v, addr1, addr;
1590 vga_draw_line_func *vga_draw_line;
1592 full_update |= update_basic_params(s);
1594 if (!full_update)
1595 vga_sync_dirty_bitmap(s);
1597 s->get_resolution(s, &width, &height);
1598 disp_width = width;
1600 shift_control = (s->gr[0x05] >> 5) & 3;
1601 double_scan = (s->cr[0x09] >> 7);
1602 if (shift_control != 1) {
1603 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1604 } else {
1605 /* in CGA modes, multi_scan is ignored */
1606 /* XXX: is it correct ? */
1607 multi_scan = double_scan;
1609 multi_run = multi_scan;
1610 if (shift_control != s->shift_control ||
1611 double_scan != s->double_scan) {
1612 full_update = 1;
1613 s->shift_control = shift_control;
1614 s->double_scan = double_scan;
1617 if (shift_control == 0) {
1618 if (s->sr[0x01] & 8) {
1619 disp_width <<= 1;
1621 } else if (shift_control == 1) {
1622 if (s->sr[0x01] & 8) {
1623 disp_width <<= 1;
1627 depth = s->get_bpp(s);
1628 if (s->line_offset != s->last_line_offset ||
1629 disp_width != s->last_width ||
1630 height != s->last_height ||
1631 s->last_depth != depth) {
1632 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1633 if (depth == 16 || depth == 32) {
1634 #else
1635 if (depth == 32) {
1636 #endif
1637 qemu_free_displaysurface(s->ds);
1638 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1639 s->line_offset,
1640 s->vram_ptr + (s->start_addr * 4));
1641 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1642 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1643 #endif
1644 dpy_resize(s->ds);
1645 } else {
1646 qemu_console_resize(s->ds, disp_width, height);
1648 s->last_scr_width = disp_width;
1649 s->last_scr_height = height;
1650 s->last_width = disp_width;
1651 s->last_height = height;
1652 s->last_line_offset = s->line_offset;
1653 s->last_depth = depth;
1654 full_update = 1;
1655 } else if (is_buffer_shared(s->ds->surface) &&
1656 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1657 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1658 dpy_setdata(s->ds);
1661 s->rgb_to_pixel =
1662 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1664 if (shift_control == 0) {
1665 full_update |= update_palette16(s);
1666 if (s->sr[0x01] & 8) {
1667 v = VGA_DRAW_LINE4D2;
1668 } else {
1669 v = VGA_DRAW_LINE4;
1671 bits = 4;
1672 } else if (shift_control == 1) {
1673 full_update |= update_palette16(s);
1674 if (s->sr[0x01] & 8) {
1675 v = VGA_DRAW_LINE2D2;
1676 } else {
1677 v = VGA_DRAW_LINE2;
1679 bits = 4;
1680 } else {
1681 switch(s->get_bpp(s)) {
1682 default:
1683 case 0:
1684 full_update |= update_palette256(s);
1685 v = VGA_DRAW_LINE8D2;
1686 bits = 4;
1687 break;
1688 case 8:
1689 full_update |= update_palette256(s);
1690 v = VGA_DRAW_LINE8;
1691 bits = 8;
1692 break;
1693 case 15:
1694 v = VGA_DRAW_LINE15;
1695 bits = 16;
1696 break;
1697 case 16:
1698 v = VGA_DRAW_LINE16;
1699 bits = 16;
1700 break;
1701 case 24:
1702 v = VGA_DRAW_LINE24;
1703 bits = 24;
1704 break;
1705 case 32:
1706 v = VGA_DRAW_LINE32;
1707 bits = 32;
1708 break;
1711 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1713 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1714 s->cursor_invalidate(s);
1716 line_offset = s->line_offset;
1717 #if 0
1718 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",
1719 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1720 #endif
1721 addr1 = (s->start_addr * 4);
1722 bwidth = (width * bits + 7) / 8;
1723 y_start = -1;
1724 page_min = -1;
1725 page_max = 0;
1726 d = ds_get_data(s->ds);
1727 linesize = ds_get_linesize(s->ds);
1728 y1 = 0;
1729 for(y = 0; y < height; y++) {
1730 addr = addr1;
1731 if (!(s->cr[0x17] & 1)) {
1732 int shift;
1733 /* CGA compatibility handling */
1734 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1735 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1737 if (!(s->cr[0x17] & 2)) {
1738 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1740 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1741 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1742 update = full_update |
1743 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1744 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1745 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1746 /* if wide line, can use another page */
1747 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1748 VGA_DIRTY_FLAG);
1750 /* explicit invalidation for the hardware cursor */
1751 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1752 if (update) {
1753 if (y_start < 0)
1754 y_start = y;
1755 if (page0 < page_min)
1756 page_min = page0;
1757 if (page1 > page_max)
1758 page_max = page1;
1759 if (!(is_buffer_shared(s->ds->surface))) {
1760 vga_draw_line(s, d, s->vram_ptr + addr, width);
1761 if (s->cursor_draw_line)
1762 s->cursor_draw_line(s, d, y);
1764 } else {
1765 if (y_start >= 0) {
1766 /* flush to display */
1767 dpy_update(s->ds, 0, y_start,
1768 disp_width, y - y_start);
1769 y_start = -1;
1772 if (!multi_run) {
1773 mask = (s->cr[0x17] & 3) ^ 3;
1774 if ((y1 & mask) == mask)
1775 addr1 += line_offset;
1776 y1++;
1777 multi_run = multi_scan;
1778 } else {
1779 multi_run--;
1781 /* line compare acts on the displayed lines */
1782 if (y == s->line_compare)
1783 addr1 = 0;
1784 d += linesize;
1786 if (y_start >= 0) {
1787 /* flush to display */
1788 dpy_update(s->ds, 0, y_start,
1789 disp_width, y - y_start);
1791 /* reset modified pages */
1792 if (page_max >= page_min) {
1793 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1794 VGA_DIRTY_FLAG);
1796 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1799 static void vga_draw_blank(VGACommonState *s, int full_update)
1801 int i, w, val;
1802 uint8_t *d;
1804 if (!full_update)
1805 return;
1806 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1807 return;
1809 s->rgb_to_pixel =
1810 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1811 if (ds_get_bits_per_pixel(s->ds) == 8)
1812 val = s->rgb_to_pixel(0, 0, 0);
1813 else
1814 val = 0;
1815 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1816 d = ds_get_data(s->ds);
1817 for(i = 0; i < s->last_scr_height; i++) {
1818 memset(d, val, w);
1819 d += ds_get_linesize(s->ds);
1821 dpy_update(s->ds, 0, 0,
1822 s->last_scr_width, s->last_scr_height);
1825 #define GMODE_TEXT 0
1826 #define GMODE_GRAPH 1
1827 #define GMODE_BLANK 2
1829 static void vga_update_display(void *opaque)
1831 VGACommonState *s = opaque;
1832 int full_update, graphic_mode;
1834 if (ds_get_bits_per_pixel(s->ds) == 0) {
1835 /* nothing to do */
1836 } else {
1837 full_update = s->full_update;
1838 s->full_update = 0;
1839 if (!(s->ar_index & 0x20)) {
1840 graphic_mode = GMODE_BLANK;
1841 } else {
1842 graphic_mode = s->gr[6] & 1;
1844 if (graphic_mode != s->graphic_mode) {
1845 s->graphic_mode = graphic_mode;
1846 full_update = 1;
1848 switch(graphic_mode) {
1849 case GMODE_TEXT:
1850 vga_draw_text(s, full_update);
1851 break;
1852 case GMODE_GRAPH:
1853 vga_draw_graphic(s, full_update);
1854 break;
1855 case GMODE_BLANK:
1856 default:
1857 vga_draw_blank(s, full_update);
1858 break;
1863 /* force a full display refresh */
1864 static void vga_invalidate_display(void *opaque)
1866 VGACommonState *s = opaque;
1868 s->full_update = 1;
1871 void vga_common_reset(VGACommonState *s)
1873 s->lfb_addr = 0;
1874 s->lfb_end = 0;
1875 s->map_addr = 0;
1876 s->map_end = 0;
1877 s->lfb_vram_mapped = 0;
1878 s->bios_offset = 0;
1879 s->bios_size = 0;
1880 s->sr_index = 0;
1881 memset(s->sr, '\0', sizeof(s->sr));
1882 s->gr_index = 0;
1883 memset(s->gr, '\0', sizeof(s->gr));
1884 s->ar_index = 0;
1885 memset(s->ar, '\0', sizeof(s->ar));
1886 s->ar_flip_flop = 0;
1887 s->cr_index = 0;
1888 memset(s->cr, '\0', sizeof(s->cr));
1889 s->msr = 0;
1890 s->fcr = 0;
1891 s->st00 = 0;
1892 s->st01 = 0;
1893 s->dac_state = 0;
1894 s->dac_sub_index = 0;
1895 s->dac_read_index = 0;
1896 s->dac_write_index = 0;
1897 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1898 s->dac_8bit = 0;
1899 memset(s->palette, '\0', sizeof(s->palette));
1900 s->bank_offset = 0;
1901 #ifdef CONFIG_BOCHS_VBE
1902 s->vbe_index = 0;
1903 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1904 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1905 s->vbe_start_addr = 0;
1906 s->vbe_line_offset = 0;
1907 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1908 #endif
1909 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1910 s->graphic_mode = -1; /* force full update */
1911 s->shift_control = 0;
1912 s->double_scan = 0;
1913 s->line_offset = 0;
1914 s->line_compare = 0;
1915 s->start_addr = 0;
1916 s->plane_updated = 0;
1917 s->last_cw = 0;
1918 s->last_ch = 0;
1919 s->last_width = 0;
1920 s->last_height = 0;
1921 s->last_scr_width = 0;
1922 s->last_scr_height = 0;
1923 s->cursor_start = 0;
1924 s->cursor_end = 0;
1925 s->cursor_offset = 0;
1926 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1927 memset(s->last_palette, '\0', sizeof(s->last_palette));
1928 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1929 switch (vga_retrace_method) {
1930 case VGA_RETRACE_DUMB:
1931 break;
1932 case VGA_RETRACE_PRECISE:
1933 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1934 break;
1938 static void vga_reset(void *opaque)
1940 VGACommonState *s = opaque;
1941 vga_common_reset(s);
1944 #define TEXTMODE_X(x) ((x) % width)
1945 #define TEXTMODE_Y(x) ((x) / width)
1946 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1947 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1948 /* relay text rendering to the display driver
1949 * instead of doing a full vga_update_display() */
1950 static void vga_update_text(void *opaque, console_ch_t *chardata)
1952 VGACommonState *s = opaque;
1953 int graphic_mode, i, cursor_offset, cursor_visible;
1954 int cw, cheight, width, height, size, c_min, c_max;
1955 uint32_t *src;
1956 console_ch_t *dst, val;
1957 char msg_buffer[80];
1958 int full_update = 0;
1960 if (!(s->ar_index & 0x20)) {
1961 graphic_mode = GMODE_BLANK;
1962 } else {
1963 graphic_mode = s->gr[6] & 1;
1965 if (graphic_mode != s->graphic_mode) {
1966 s->graphic_mode = graphic_mode;
1967 full_update = 1;
1969 if (s->last_width == -1) {
1970 s->last_width = 0;
1971 full_update = 1;
1974 switch (graphic_mode) {
1975 case GMODE_TEXT:
1976 /* TODO: update palette */
1977 full_update |= update_basic_params(s);
1979 /* total width & height */
1980 cheight = (s->cr[9] & 0x1f) + 1;
1981 cw = 8;
1982 if (!(s->sr[1] & 0x01))
1983 cw = 9;
1984 if (s->sr[1] & 0x08)
1985 cw = 16; /* NOTE: no 18 pixel wide */
1986 width = (s->cr[0x01] + 1);
1987 if (s->cr[0x06] == 100) {
1988 /* ugly hack for CGA 160x100x16 - explain me the logic */
1989 height = 100;
1990 } else {
1991 height = s->cr[0x12] |
1992 ((s->cr[0x07] & 0x02) << 7) |
1993 ((s->cr[0x07] & 0x40) << 3);
1994 height = (height + 1) / cheight;
1997 size = (height * width);
1998 if (size > CH_ATTR_SIZE) {
1999 if (!full_update)
2000 return;
2002 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2003 width, height);
2004 break;
2007 if (width != s->last_width || height != s->last_height ||
2008 cw != s->last_cw || cheight != s->last_ch) {
2009 s->last_scr_width = width * cw;
2010 s->last_scr_height = height * cheight;
2011 s->ds->surface->width = width;
2012 s->ds->surface->height = height;
2013 dpy_resize(s->ds);
2014 s->last_width = width;
2015 s->last_height = height;
2016 s->last_ch = cheight;
2017 s->last_cw = cw;
2018 full_update = 1;
2021 /* Update "hardware" cursor */
2022 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2023 if (cursor_offset != s->cursor_offset ||
2024 s->cr[0xa] != s->cursor_start ||
2025 s->cr[0xb] != s->cursor_end || full_update) {
2026 cursor_visible = !(s->cr[0xa] & 0x20);
2027 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2028 dpy_cursor(s->ds,
2029 TEXTMODE_X(cursor_offset),
2030 TEXTMODE_Y(cursor_offset));
2031 else
2032 dpy_cursor(s->ds, -1, -1);
2033 s->cursor_offset = cursor_offset;
2034 s->cursor_start = s->cr[0xa];
2035 s->cursor_end = s->cr[0xb];
2038 src = (uint32_t *) s->vram_ptr + s->start_addr;
2039 dst = chardata;
2041 if (full_update) {
2042 for (i = 0; i < size; src ++, dst ++, i ++)
2043 console_write_ch(dst, VMEM2CHTYPE(*src));
2045 dpy_update(s->ds, 0, 0, width, height);
2046 } else {
2047 c_max = 0;
2049 for (i = 0; i < size; src ++, dst ++, i ++) {
2050 console_write_ch(&val, VMEM2CHTYPE(*src));
2051 if (*dst != val) {
2052 *dst = val;
2053 c_max = i;
2054 break;
2057 c_min = i;
2058 for (; i < size; src ++, dst ++, i ++) {
2059 console_write_ch(&val, VMEM2CHTYPE(*src));
2060 if (*dst != val) {
2061 *dst = val;
2062 c_max = i;
2066 if (c_min <= c_max) {
2067 i = TEXTMODE_Y(c_min);
2068 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2072 return;
2073 case GMODE_GRAPH:
2074 if (!full_update)
2075 return;
2077 s->get_resolution(s, &width, &height);
2078 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2079 width, height);
2080 break;
2081 case GMODE_BLANK:
2082 default:
2083 if (!full_update)
2084 return;
2086 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2087 break;
2090 /* Display a message */
2091 s->last_width = 60;
2092 s->last_height = height = 3;
2093 dpy_cursor(s->ds, -1, -1);
2094 s->ds->surface->width = s->last_width;
2095 s->ds->surface->height = height;
2096 dpy_resize(s->ds);
2098 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2099 console_write_ch(dst ++, ' ');
2101 size = strlen(msg_buffer);
2102 width = (s->last_width - size) / 2;
2103 dst = chardata + s->last_width + width;
2104 for (i = 0; i < size; i ++)
2105 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2107 dpy_update(s->ds, 0, 0, s->last_width, height);
2110 CPUReadMemoryFunc * const vga_mem_read[3] = {
2111 vga_mem_readb,
2112 vga_mem_readw,
2113 vga_mem_readl,
2116 CPUWriteMemoryFunc * const vga_mem_write[3] = {
2117 vga_mem_writeb,
2118 vga_mem_writew,
2119 vga_mem_writel,
2122 void vga_common_save(QEMUFile *f, void *opaque)
2124 VGACommonState *s = opaque;
2125 int i;
2127 qemu_put_be32s(f, &s->latch);
2128 qemu_put_8s(f, &s->sr_index);
2129 qemu_put_buffer(f, s->sr, 8);
2130 qemu_put_8s(f, &s->gr_index);
2131 qemu_put_buffer(f, s->gr, 16);
2132 qemu_put_8s(f, &s->ar_index);
2133 qemu_put_buffer(f, s->ar, 21);
2134 qemu_put_be32(f, s->ar_flip_flop);
2135 qemu_put_8s(f, &s->cr_index);
2136 qemu_put_buffer(f, s->cr, 256);
2137 qemu_put_8s(f, &s->msr);
2138 qemu_put_8s(f, &s->fcr);
2139 qemu_put_byte(f, s->st00);
2140 qemu_put_8s(f, &s->st01);
2142 qemu_put_8s(f, &s->dac_state);
2143 qemu_put_8s(f, &s->dac_sub_index);
2144 qemu_put_8s(f, &s->dac_read_index);
2145 qemu_put_8s(f, &s->dac_write_index);
2146 qemu_put_buffer(f, s->dac_cache, 3);
2147 qemu_put_buffer(f, s->palette, 768);
2149 qemu_put_be32(f, s->bank_offset);
2150 #ifdef CONFIG_BOCHS_VBE
2151 qemu_put_byte(f, 1);
2152 qemu_put_be16s(f, &s->vbe_index);
2153 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2154 qemu_put_be16s(f, &s->vbe_regs[i]);
2155 qemu_put_be32s(f, &s->vbe_start_addr);
2156 qemu_put_be32s(f, &s->vbe_line_offset);
2157 qemu_put_be32s(f, &s->vbe_bank_mask);
2158 #else
2159 qemu_put_byte(f, 0);
2160 #endif
2163 int vga_common_load(QEMUFile *f, void *opaque, int version_id)
2165 VGACommonState *s = opaque;
2166 int is_vbe, i;
2168 if (version_id > 2)
2169 return -EINVAL;
2171 qemu_get_be32s(f, &s->latch);
2172 qemu_get_8s(f, &s->sr_index);
2173 qemu_get_buffer(f, s->sr, 8);
2174 qemu_get_8s(f, &s->gr_index);
2175 qemu_get_buffer(f, s->gr, 16);
2176 qemu_get_8s(f, &s->ar_index);
2177 qemu_get_buffer(f, s->ar, 21);
2178 s->ar_flip_flop=qemu_get_be32(f);
2179 qemu_get_8s(f, &s->cr_index);
2180 qemu_get_buffer(f, s->cr, 256);
2181 qemu_get_8s(f, &s->msr);
2182 qemu_get_8s(f, &s->fcr);
2183 qemu_get_8s(f, &s->st00);
2184 qemu_get_8s(f, &s->st01);
2186 qemu_get_8s(f, &s->dac_state);
2187 qemu_get_8s(f, &s->dac_sub_index);
2188 qemu_get_8s(f, &s->dac_read_index);
2189 qemu_get_8s(f, &s->dac_write_index);
2190 qemu_get_buffer(f, s->dac_cache, 3);
2191 qemu_get_buffer(f, s->palette, 768);
2193 s->bank_offset=qemu_get_be32(f);
2194 is_vbe = qemu_get_byte(f);
2195 #ifdef CONFIG_BOCHS_VBE
2196 if (!is_vbe)
2197 return -EINVAL;
2198 qemu_get_be16s(f, &s->vbe_index);
2199 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2200 qemu_get_be16s(f, &s->vbe_regs[i]);
2201 qemu_get_be32s(f, &s->vbe_start_addr);
2202 qemu_get_be32s(f, &s->vbe_line_offset);
2203 qemu_get_be32s(f, &s->vbe_bank_mask);
2204 #else
2205 if (is_vbe)
2206 return -EINVAL;
2207 #endif
2209 /* force refresh */
2210 s->graphic_mode = -1;
2211 return 0;
2214 void vga_common_init(VGACommonState *s, int vga_ram_size)
2216 int i, j, v, b;
2218 for(i = 0;i < 256; i++) {
2219 v = 0;
2220 for(j = 0; j < 8; j++) {
2221 v |= ((i >> j) & 1) << (j * 4);
2223 expand4[i] = v;
2225 v = 0;
2226 for(j = 0; j < 4; j++) {
2227 v |= ((i >> (2 * j)) & 3) << (j * 4);
2229 expand2[i] = v;
2231 for(i = 0; i < 16; i++) {
2232 v = 0;
2233 for(j = 0; j < 4; j++) {
2234 b = ((i >> j) & 1);
2235 v |= b << (2 * j);
2236 v |= b << (2 * j + 1);
2238 expand4to8[i] = v;
2241 s->vram_offset = qemu_ram_alloc(vga_ram_size);
2242 s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
2243 s->vram_size = vga_ram_size;
2244 s->get_bpp = vga_get_bpp;
2245 s->get_offsets = vga_get_offsets;
2246 s->get_resolution = vga_get_resolution;
2247 s->update = vga_update_display;
2248 s->invalidate = vga_invalidate_display;
2249 s->screen_dump = vga_screen_dump;
2250 s->text_update = vga_update_text;
2251 switch (vga_retrace_method) {
2252 case VGA_RETRACE_DUMB:
2253 s->retrace = vga_dumb_retrace;
2254 s->update_retrace_info = vga_dumb_update_retrace_info;
2255 break;
2257 case VGA_RETRACE_PRECISE:
2258 s->retrace = vga_precise_retrace;
2259 s->update_retrace_info = vga_precise_update_retrace_info;
2260 break;
2262 vga_reset(s);
2265 /* used by both ISA and PCI */
2266 void vga_init(VGACommonState *s)
2268 int vga_io_memory;
2270 qemu_register_reset(vga_reset, s);
2272 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2274 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2275 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2276 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2277 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2279 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2281 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2282 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2283 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2284 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2285 s->bank_offset = 0;
2287 #ifdef CONFIG_BOCHS_VBE
2288 #if defined (TARGET_I386)
2289 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2290 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2292 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2293 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2295 /* old Bochs IO ports */
2296 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2297 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2299 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2300 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2301 #else
2302 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2303 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2305 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2306 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2307 #endif
2308 #endif /* CONFIG_BOCHS_VBE */
2310 vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2311 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2312 vga_io_memory);
2313 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2316 /********************************************************/
2317 /* vga screen dump */
2319 static void vga_save_dpy_update(DisplayState *ds,
2320 int x, int y, int w, int h)
2322 if (screen_dump_filename) {
2323 ppm_save(screen_dump_filename, ds->surface);
2324 screen_dump_filename = NULL;
2328 static void vga_save_dpy_resize(DisplayState *s)
2332 static void vga_save_dpy_refresh(DisplayState *s)
2336 int ppm_save(const char *filename, struct DisplaySurface *ds)
2338 FILE *f;
2339 uint8_t *d, *d1;
2340 uint32_t v;
2341 int y, x;
2342 uint8_t r, g, b;
2344 f = fopen(filename, "wb");
2345 if (!f)
2346 return -1;
2347 fprintf(f, "P6\n%d %d\n%d\n",
2348 ds->width, ds->height, 255);
2349 d1 = ds->data;
2350 for(y = 0; y < ds->height; y++) {
2351 d = d1;
2352 for(x = 0; x < ds->width; x++) {
2353 if (ds->pf.bits_per_pixel == 32)
2354 v = *(uint32_t *)d;
2355 else
2356 v = (uint32_t) (*(uint16_t *)d);
2357 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2358 (ds->pf.rmax + 1);
2359 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2360 (ds->pf.gmax + 1);
2361 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2362 (ds->pf.bmax + 1);
2363 fputc(r, f);
2364 fputc(g, f);
2365 fputc(b, f);
2366 d += ds->pf.bytes_per_pixel;
2368 d1 += ds->linesize;
2370 fclose(f);
2371 return 0;
2374 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2376 DisplayChangeListener *dcl;
2378 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2379 dcl->dpy_update = vga_save_dpy_update;
2380 dcl->dpy_resize = vga_save_dpy_resize;
2381 dcl->dpy_refresh = vga_save_dpy_refresh;
2382 register_displaychangelistener(ds, dcl);
2383 return dcl;
2386 /* save the vga display in a PPM image even if no display is
2387 available */
2388 static void vga_screen_dump(void *opaque, const char *filename)
2390 VGACommonState *s = opaque;
2392 if (!screen_dump_dcl)
2393 screen_dump_dcl = vga_screen_dump_init(s->ds);
2395 screen_dump_filename = (char *)filename;
2396 vga_invalidate_display(s);
2397 vga_hw_update();