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
27 //#define DEBUG_VGA_MEM
28 //#define DEBUG_VGA_REG
31 //#define DEBUG_BOCHS_VBE
35 #define MSR_COLOR_EMULATION 0x01
36 #define MSR_PAGE_SELECT 0x20
38 #define ST01_V_RETRACE 0x08
39 #define ST01_DISP_ENABLE 0x01
41 /* bochs VBE support */
42 #define CONFIG_BOCHS_VBE
44 #define VBE_DISPI_MAX_XRES 1024
45 #define VBE_DISPI_MAX_YRES 768
47 #define VBE_DISPI_INDEX_ID 0x0
48 #define VBE_DISPI_INDEX_XRES 0x1
49 #define VBE_DISPI_INDEX_YRES 0x2
50 #define VBE_DISPI_INDEX_BPP 0x3
51 #define VBE_DISPI_INDEX_ENABLE 0x4
52 #define VBE_DISPI_INDEX_BANK 0x5
53 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
54 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
55 #define VBE_DISPI_INDEX_X_OFFSET 0x8
56 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
57 #define VBE_DISPI_INDEX_NB 0xa
59 #define VBE_DISPI_ID0 0xB0C0
60 #define VBE_DISPI_ID1 0xB0C1
61 #define VBE_DISPI_ID2 0xB0C2
63 #define VBE_DISPI_DISABLED 0x00
64 #define VBE_DISPI_ENABLED 0x01
65 #define VBE_DISPI_LFB_ENABLED 0x40
66 #define VBE_DISPI_NOCLEARMEM 0x80
68 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
70 typedef struct VGAState {
72 unsigned long vram_offset;
73 unsigned int vram_size;
83 uint8_t cr[256]; /* CRT registers */
84 uint8_t msr; /* Misc Output Register */
85 uint8_t fcr; /* Feature Control Register */
86 uint8_t st00; /* status 0 */
87 uint8_t st01; /* status 1 */
89 uint8_t dac_sub_index;
90 uint8_t dac_read_index;
91 uint8_t dac_write_index;
92 uint8_t dac_cache[3]; /* used when writing */
95 #ifdef CONFIG_BOCHS_VBE
97 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
98 uint32_t vbe_start_addr;
99 uint32_t vbe_line_offset;
100 uint32_t vbe_bank_mask;
102 /* display refresh support */
104 uint32_t font_offsets[2];
106 uint8_t shift_control;
108 uint32_t line_offset;
109 uint32_t line_compare;
111 uint8_t last_cw, last_ch;
112 uint32_t last_width, last_height;
113 uint8_t cursor_start, cursor_end;
114 uint32_t cursor_offset;
115 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
116 /* tell for each page if it has been updated since the last time */
117 uint32_t last_palette[256];
118 #define CH_ATTR_SIZE (160 * 100)
119 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
122 /* force some bits to zero */
123 static const uint8_t sr_mask[8] = {
134 static const uint8_t gr_mask[16] = {
135 (uint8_t)~0xf0, /* 0x00 */
136 (uint8_t)~0xf0, /* 0x01 */
137 (uint8_t)~0xf0, /* 0x02 */
138 (uint8_t)~0xe0, /* 0x03 */
139 (uint8_t)~0xfc, /* 0x04 */
140 (uint8_t)~0x84, /* 0x05 */
141 (uint8_t)~0xf0, /* 0x06 */
142 (uint8_t)~0xf0, /* 0x07 */
143 (uint8_t)~0x00, /* 0x08 */
144 (uint8_t)~0xff, /* 0x09 */
145 (uint8_t)~0xff, /* 0x0a */
146 (uint8_t)~0xff, /* 0x0b */
147 (uint8_t)~0xff, /* 0x0c */
148 (uint8_t)~0xff, /* 0x0d */
149 (uint8_t)~0xff, /* 0x0e */
150 (uint8_t)~0xff, /* 0x0f */
153 #define cbswap_32(__x) \
155 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
156 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
157 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
158 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
160 #ifdef WORDS_BIGENDIAN
161 #define PAT(x) cbswap_32(x)
166 #ifdef WORDS_BIGENDIAN
172 #ifdef WORDS_BIGENDIAN
173 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
175 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
178 static const uint32_t mask16[16] = {
199 #ifdef WORDS_BIGENDIAN
202 #define PAT(x) cbswap_32(x)
205 static const uint32_t dmask16[16] = {
224 static const uint32_t dmask4[4] = {
231 static uint32_t expand4[256];
232 static uint16_t expand2[256];
233 static uint8_t expand4to8[16];
238 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
240 VGAState *s = opaque;
243 /* check port range access depending on color/monochrome mode */
244 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
245 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
250 if (s->ar_flip_flop == 0) {
257 index = s->ar_index & 0x1f;
270 val = s->sr[s->sr_index];
272 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
279 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
280 if (++s->dac_sub_index == 3) {
281 s->dac_sub_index = 0;
295 val = s->gr[s->gr_index];
297 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
306 val = s->cr[s->cr_index];
308 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
311 if (s->cr_index >= 0x20)
312 printf("S3: CR read index=0x%x val=0x%x\n",
318 /* just toggle to fool polling */
319 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
328 #if defined(DEBUG_VGA)
329 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
334 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
336 VGAState *s = opaque;
339 /* check port range access depending on color/monochrome mode */
340 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
341 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
345 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
350 if (s->ar_flip_flop == 0) {
354 index = s->ar_index & 0x1f;
357 s->ar[index] = val & 0x3f;
360 s->ar[index] = val & ~0x10;
366 s->ar[index] = val & ~0xc0;
369 s->ar[index] = val & ~0xf0;
372 s->ar[index] = val & ~0xf0;
378 s->ar_flip_flop ^= 1;
381 s->msr = val & ~0x10;
384 s->sr_index = val & 7;
388 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
390 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
393 s->dac_read_index = val;
394 s->dac_sub_index = 0;
398 s->dac_write_index = val;
399 s->dac_sub_index = 0;
403 s->dac_cache[s->dac_sub_index] = val;
404 if (++s->dac_sub_index == 3) {
405 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
406 s->dac_sub_index = 0;
407 s->dac_write_index++;
411 s->gr_index = val & 0x0f;
415 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
417 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
426 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
428 /* handle CR0-7 protection */
429 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
430 /* can always write bit 4 of CR7 */
431 if (s->cr_index == 7)
432 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
435 switch(s->cr_index) {
436 case 0x01: /* horizontal display end */
441 case 0x12: /* veritcal display end */
442 s->cr[s->cr_index] = val;
451 /* chip ID, cannot write */
454 /* update start address */
455 s->cr[s->cr_index] = val;
457 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
460 /* update start address */
461 s->cr[s->cr_index] = val;
463 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
467 s->cr[s->cr_index] = val;
471 if (s->cr_index >= 0x20)
472 printf("S3: CR write index=0x%x val=0x%x\n",
483 #ifdef CONFIG_BOCHS_VBE
484 static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
486 VGAState *s = opaque;
493 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
494 val = s->vbe_regs[s->vbe_index];
497 #ifdef DEBUG_BOCHS_VBE
498 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
504 static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
506 VGAState *s = opaque;
511 } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
512 #ifdef DEBUG_BOCHS_VBE
513 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
515 switch(s->vbe_index) {
516 case VBE_DISPI_INDEX_ID:
517 if (val == VBE_DISPI_ID0 ||
518 val == VBE_DISPI_ID1 ||
519 val == VBE_DISPI_ID2) {
520 s->vbe_regs[s->vbe_index] = val;
523 case VBE_DISPI_INDEX_XRES:
524 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
525 s->vbe_regs[s->vbe_index] = val;
528 case VBE_DISPI_INDEX_YRES:
529 if (val <= VBE_DISPI_MAX_YRES) {
530 s->vbe_regs[s->vbe_index] = val;
533 case VBE_DISPI_INDEX_BPP:
536 if (val == 4 || val == 8 || val == 15 ||
537 val == 16 || val == 24 || val == 32) {
538 s->vbe_regs[s->vbe_index] = val;
541 case VBE_DISPI_INDEX_BANK:
542 val &= s->vbe_bank_mask;
543 s->vbe_regs[s->vbe_index] = val;
544 s->bank_offset = (val << 16) - 0xa0000;
546 case VBE_DISPI_INDEX_ENABLE:
547 if (val & VBE_DISPI_ENABLED) {
548 int h, shift_control;
550 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
551 s->vbe_regs[VBE_DISPI_INDEX_XRES];
552 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
553 s->vbe_regs[VBE_DISPI_INDEX_YRES];
554 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
555 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
557 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
558 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
560 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
561 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
562 s->vbe_start_addr = 0;
564 /* clear the screen (should be done in BIOS) */
565 if (!(val & VBE_DISPI_NOCLEARMEM)) {
566 memset(s->vram_ptr, 0,
567 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
570 /* we initialize the VGA graphic mode (should be done
572 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
573 s->cr[0x17] |= 3; /* no CGA modes */
574 s->cr[0x13] = s->vbe_line_offset >> 3;
576 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
578 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
580 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
581 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
582 /* line compare to 1023 */
587 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
589 s->sr[0x01] &= ~8; /* no double line */
593 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
594 s->cr[0x09] &= ~0x9f; /* no double scan */
595 s->vbe_regs[s->vbe_index] = val;
597 /* XXX: the bios should do that */
598 s->bank_offset = -0xa0000;
601 case VBE_DISPI_INDEX_VIRT_WIDTH:
603 int w, h, line_offset;
605 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
608 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
609 line_offset = w >> 1;
611 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
612 h = s->vram_size / line_offset;
613 /* XXX: support weird bochs semantics ? */
614 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
616 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
617 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
618 s->vbe_line_offset = line_offset;
621 case VBE_DISPI_INDEX_X_OFFSET:
622 case VBE_DISPI_INDEX_Y_OFFSET:
625 s->vbe_regs[s->vbe_index] = val;
626 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
627 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
628 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
629 s->vbe_start_addr += x >> 1;
631 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
632 s->vbe_start_addr >>= 2;
642 /* called for accesses between 0xa0000 and 0xc0000 */
643 static uint32_t vga_mem_readb(uint32_t addr)
645 VGAState *s = &vga_state;
646 int memory_map_mode, plane;
649 /* convert to VGA memory offset */
650 memory_map_mode = (s->gr[6] >> 2) & 3;
651 switch(memory_map_mode) {
658 addr += s->bank_offset;
673 if (s->sr[4] & 0x08) {
674 /* chain 4 mode : simplest access */
675 ret = s->vram_ptr[addr];
676 } else if (s->gr[5] & 0x10) {
677 /* odd/even mode (aka text mode mapping) */
678 plane = (s->gr[4] & 2) | (addr & 1);
679 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
681 /* standard VGA latched access */
682 s->latch = ((uint32_t *)s->vram_ptr)[addr];
684 if (!(s->gr[5] & 0x08)) {
687 ret = GET_PLANE(s->latch, plane);
690 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
699 static uint32_t vga_mem_readw(uint32_t addr)
702 v = vga_mem_readb(addr);
703 v |= vga_mem_readb(addr + 1) << 8;
707 static uint32_t vga_mem_readl(uint32_t addr)
710 v = vga_mem_readb(addr);
711 v |= vga_mem_readb(addr + 1) << 8;
712 v |= vga_mem_readb(addr + 2) << 16;
713 v |= vga_mem_readb(addr + 3) << 24;
717 /* called for accesses between 0xa0000 and 0xc0000 */
718 static void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
720 VGAState *s = &vga_state;
721 int memory_map_mode, plane, write_mode, b, func_select;
722 uint32_t write_mask, bit_mask, set_mask;
725 printf("vga: [0x%x] = 0x%02x\n", addr, val);
727 /* convert to VGA memory offset */
728 memory_map_mode = (s->gr[6] >> 2) & 3;
729 switch(memory_map_mode) {
736 addr += s->bank_offset;
751 if (s->sr[4] & 0x08) {
752 /* chain 4 mode : simplest access */
754 if (s->sr[2] & (1 << plane)) {
755 s->vram_ptr[addr] = val;
757 printf("vga: chain4: [0x%x]\n", addr);
759 cpu_physical_memory_set_dirty(s->vram_offset + addr);
761 } else if (s->gr[5] & 0x10) {
762 /* odd/even mode (aka text mode mapping) */
763 plane = (s->gr[4] & 2) | (addr & 1);
764 if (s->sr[2] & (1 << plane)) {
765 addr = ((addr & ~1) << 1) | plane;
766 s->vram_ptr[addr] = val;
768 printf("vga: odd/even: [0x%x]\n", addr);
770 cpu_physical_memory_set_dirty(s->vram_offset + addr);
773 /* standard VGA latched access */
774 write_mode = s->gr[5] & 3;
780 val = ((val >> b) | (val << (8 - b))) & 0xff;
784 /* apply set/reset mask */
785 set_mask = mask16[s->gr[1]];
786 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
793 val = mask16[val & 0x0f];
799 val = (val >> b) | (val << (8 - b));
801 bit_mask = s->gr[8] & val;
802 val = mask16[s->gr[0]];
806 /* apply logical operation */
807 func_select = s->gr[3] >> 3;
808 switch(func_select) {
828 bit_mask |= bit_mask << 8;
829 bit_mask |= bit_mask << 16;
830 val = (val & bit_mask) | (s->latch & ~bit_mask);
833 /* mask data according to sr[2] */
834 write_mask = mask16[s->sr[2]];
835 ((uint32_t *)s->vram_ptr)[addr] =
836 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
839 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
840 addr * 4, write_mask, val);
842 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
846 static void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
848 vga_mem_writeb(addr, val & 0xff, vaddr);
849 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
852 static void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
854 vga_mem_writeb(addr, val & 0xff, vaddr);
855 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
856 vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr);
857 vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr);
860 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
861 const uint8_t *font_ptr, int h,
862 uint32_t fgcol, uint32_t bgcol);
863 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
864 const uint8_t *font_ptr, int h,
865 uint32_t fgcol, uint32_t bgcol, int dup9);
866 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
867 const uint8_t *s, int width);
869 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
875 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
877 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
880 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
882 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
885 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
887 return (r << 16) | (g << 8) | b;
891 #include "vga_template.h"
894 #include "vga_template.h"
897 #include "vga_template.h"
900 #include "vga_template.h"
902 static inline int c6_to_8(int v)
907 return (v << 2) | (b << 1) | b;
910 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
913 col = rgb_to_pixel8(r, g, b);
919 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
922 col = rgb_to_pixel15(r, g, b);
927 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
930 col = rgb_to_pixel16(r, g, b);
935 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
938 col = rgb_to_pixel32(r, g, b);
942 /* return true if the palette was modified */
943 static int update_palette16(VGAState *s)
946 uint32_t v, col, *palette;
949 palette = s->last_palette;
950 for(i = 0; i < 16; i++) {
952 if (s->ar[0x10] & 0x80)
953 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
955 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
957 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
958 c6_to_8(s->palette[v + 1]),
959 c6_to_8(s->palette[v + 2]));
960 if (col != palette[i]) {
968 /* return true if the palette was modified */
969 static int update_palette256(VGAState *s)
972 uint32_t v, col, *palette;
975 palette = s->last_palette;
977 for(i = 0; i < 256; i++) {
978 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
979 c6_to_8(s->palette[v + 1]),
980 c6_to_8(s->palette[v + 2]));
981 if (col != palette[i]) {
990 /* update start_addr and line_offset. Return TRUE if modified */
991 static int update_basic_params(VGAState *s)
994 uint32_t start_addr, line_offset, line_compare, v;
998 #ifdef CONFIG_BOCHS_VBE
999 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1000 line_offset = s->vbe_line_offset;
1001 start_addr = s->vbe_start_addr;
1005 /* compute line_offset in bytes */
1006 line_offset = s->cr[0x13];
1008 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1010 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1011 line_offset |= (v << 8);
1015 /* starting address */
1016 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1018 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
1023 line_compare = s->cr[0x18] |
1024 ((s->cr[0x07] & 0x10) << 4) |
1025 ((s->cr[0x09] & 0x40) << 3);
1027 if (line_offset != s->line_offset ||
1028 start_addr != s->start_addr ||
1029 line_compare != s->line_compare) {
1030 s->line_offset = line_offset;
1031 s->start_addr = start_addr;
1032 s->line_compare = line_compare;
1038 static inline int get_depth_index(int depth)
1053 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1060 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1062 vga_draw_glyph16_16,
1063 vga_draw_glyph16_16,
1064 vga_draw_glyph16_32,
1067 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1074 static const uint8_t cursor_glyph[32 * 4] = {
1075 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1076 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1077 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1078 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1079 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1080 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1081 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1082 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1083 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1084 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1085 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1086 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1087 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1088 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1089 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1090 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 static void vga_draw_text(VGAState *s, int full_update)
1103 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1104 int cx_min, cx_max, linesize, x_incr;
1105 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1106 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1107 const uint8_t *font_ptr, *font_base[2];
1108 int dup9, line_offset, depth_index;
1110 uint32_t *ch_attr_ptr;
1111 vga_draw_glyph8_func *vga_draw_glyph8;
1112 vga_draw_glyph9_func *vga_draw_glyph9;
1114 full_update |= update_palette16(s);
1115 palette = s->last_palette;
1117 /* compute font data address (in plane 2) */
1119 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1120 if (offset != s->font_offsets[0]) {
1121 s->font_offsets[0] = offset;
1124 font_base[0] = s->vram_ptr + offset;
1126 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1127 font_base[1] = s->vram_ptr + offset;
1128 if (offset != s->font_offsets[1]) {
1129 s->font_offsets[1] = offset;
1133 full_update |= update_basic_params(s);
1135 line_offset = s->line_offset;
1136 s1 = s->vram_ptr + (s->start_addr * 4);
1138 /* total width & height */
1139 cheight = (s->cr[9] & 0x1f) + 1;
1141 if (s->sr[1] & 0x01)
1143 if (s->sr[1] & 0x08)
1144 cw = 16; /* NOTE: no 18 pixel wide */
1145 x_incr = cw * ((s->ds->depth + 7) >> 3);
1146 width = (s->cr[0x01] + 1);
1147 if (s->cr[0x06] == 100) {
1148 /* ugly hack for CGA 160x100x16 - explain me the logic */
1151 height = s->cr[0x12] |
1152 ((s->cr[0x07] & 0x02) << 7) |
1153 ((s->cr[0x07] & 0x40) << 3);
1154 height = (height + 1) / cheight;
1156 if (width != s->last_width || height != s->last_height ||
1157 cw != s->last_cw || cw != s->last_cw) {
1158 dpy_resize(s->ds, width * cw, height * cheight);
1159 s->last_width = width;
1160 s->last_height = height;
1161 s->last_ch = cheight;
1165 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1166 if (cursor_offset != s->cursor_offset ||
1167 s->cr[0xa] != s->cursor_start ||
1168 s->cr[0xb] != s->cursor_end) {
1169 /* if the cursor position changed, we update the old and new
1171 if (s->cursor_offset < CH_ATTR_SIZE)
1172 s->last_ch_attr[s->cursor_offset] = -1;
1173 if (cursor_offset < CH_ATTR_SIZE)
1174 s->last_ch_attr[cursor_offset] = -1;
1175 s->cursor_offset = cursor_offset;
1176 s->cursor_start = s->cr[0xa];
1177 s->cursor_end = s->cr[0xb];
1179 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1181 depth_index = get_depth_index(s->ds->depth);
1183 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1185 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1186 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1189 linesize = s->ds->linesize;
1190 ch_attr_ptr = s->last_ch_attr;
1191 for(cy = 0; cy < height; cy++) {
1196 for(cx = 0; cx < width; cx++) {
1197 ch_attr = *(uint16_t *)src;
1198 if (full_update || ch_attr != *ch_attr_ptr) {
1203 *ch_attr_ptr = ch_attr;
1204 #ifdef WORDS_BIGENDIAN
1206 cattr = ch_attr & 0xff;
1208 ch = ch_attr & 0xff;
1209 cattr = ch_attr >> 8;
1211 font_ptr = font_base[(cattr >> 3) & 1];
1212 font_ptr += 32 * 4 * ch;
1213 bgcol = palette[cattr >> 4];
1214 fgcol = palette[cattr & 0x0f];
1216 vga_draw_glyph8(d1, linesize,
1217 font_ptr, cheight, fgcol, bgcol);
1220 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1222 vga_draw_glyph9(d1, linesize,
1223 font_ptr, cheight, fgcol, bgcol, dup9);
1225 if (src == cursor_ptr &&
1226 !(s->cr[0x0a] & 0x20)) {
1227 int line_start, line_last, h;
1228 /* draw the cursor */
1229 line_start = s->cr[0x0a] & 0x1f;
1230 line_last = s->cr[0x0b] & 0x1f;
1231 /* XXX: check that */
1232 if (line_last > cheight - 1)
1233 line_last = cheight - 1;
1234 if (line_last >= line_start && line_start < cheight) {
1235 h = line_last - line_start + 1;
1236 d = d1 + linesize * line_start;
1238 vga_draw_glyph8(d, linesize,
1239 cursor_glyph, h, fgcol, bgcol);
1241 vga_draw_glyph9(d, linesize,
1242 cursor_glyph, h, fgcol, bgcol, 1);
1252 dpy_update(s->ds, cx_min * cw, cy * cheight,
1253 (cx_max - cx_min + 1) * cw, cheight);
1255 dest += linesize * cheight;
1274 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1281 vga_draw_line2d2_16,
1282 vga_draw_line2d2_16,
1283 vga_draw_line2d2_32,
1291 vga_draw_line4d2_16,
1292 vga_draw_line4d2_16,
1293 vga_draw_line4d2_32,
1296 vga_draw_line8d2_16,
1297 vga_draw_line8d2_16,
1298 vga_draw_line8d2_32,
1332 static void vga_draw_graphic(VGAState *s, int full_update)
1334 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1335 int width, height, shift_control, line_offset, page0, page1, bwidth;
1336 int disp_width, multi_scan, multi_run;
1338 uint32_t v, addr1, addr;
1339 vga_draw_line_func *vga_draw_line;
1341 full_update |= update_basic_params(s);
1343 width = (s->cr[0x01] + 1) * 8;
1344 height = s->cr[0x12] |
1345 ((s->cr[0x07] & 0x02) << 7) |
1346 ((s->cr[0x07] & 0x40) << 3);
1347 height = (height + 1);
1350 shift_control = (s->gr[0x05] >> 5) & 3;
1351 double_scan = (s->cr[0x09] & 0x80);
1352 if (shift_control > 1) {
1353 multi_scan = (s->cr[0x09] & 0x1f);
1357 multi_run = multi_scan;
1358 if (shift_control != s->shift_control ||
1359 double_scan != s->double_scan) {
1361 s->shift_control = shift_control;
1362 s->double_scan = double_scan;
1365 if (shift_control == 0) {
1366 full_update |= update_palette16(s);
1367 if (s->sr[0x01] & 8) {
1368 v = VGA_DRAW_LINE4D2;
1373 } else if (shift_control == 1) {
1374 full_update |= update_palette16(s);
1375 if (s->sr[0x01] & 8) {
1376 v = VGA_DRAW_LINE2D2;
1382 #ifdef CONFIG_BOCHS_VBE
1383 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1384 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1387 full_update |= update_palette256(s);
1391 v = VGA_DRAW_LINE15;
1394 v = VGA_DRAW_LINE16;
1397 v = VGA_DRAW_LINE24;
1400 v = VGA_DRAW_LINE32;
1406 full_update |= update_palette256(s);
1407 v = VGA_DRAW_LINE8D2;
1410 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1412 if (disp_width != s->last_width ||
1413 height != s->last_height) {
1414 dpy_resize(s->ds, disp_width, height);
1415 s->last_width = disp_width;
1416 s->last_height = height;
1420 line_offset = s->line_offset;
1422 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1423 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1425 addr1 = (s->start_addr * 4);
1428 page_min = 0x7fffffff;
1431 linesize = s->ds->linesize;
1433 for(y = 0; y < height; y++) {
1435 if (!(s->cr[0x17] & 1)) {
1437 /* CGA compatibility handling */
1438 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1439 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1441 if (!(s->cr[0x17] & 2)) {
1442 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1444 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1445 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1446 update = full_update | cpu_physical_memory_is_dirty(page0) |
1447 cpu_physical_memory_is_dirty(page1);
1448 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1449 /* if wide line, can use another page */
1450 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1455 if (page0 < page_min)
1457 if (page1 > page_max)
1459 vga_draw_line(s, d, s->vram_ptr + addr, width);
1462 /* flush to display */
1463 dpy_update(s->ds, 0, y_start,
1464 disp_width, y - y_start);
1469 if (!double_scan || (y & 1) != 0) {
1470 if (y1 == s->line_compare) {
1473 mask = (s->cr[0x17] & 3) ^ 3;
1474 if ((y1 & mask) == mask)
1475 addr1 += line_offset;
1479 multi_run = multi_scan;
1487 /* flush to display */
1488 dpy_update(s->ds, 0, y_start,
1489 disp_width, y - y_start);
1491 /* reset modified pages */
1492 if (page_max != -1) {
1493 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1497 void vga_update_display(void)
1499 VGAState *s = &vga_state;
1500 int full_update, graphic_mode;
1502 if (s->ds->depth == 0) {
1505 switch(s->ds->depth) {
1507 s->rgb_to_pixel = rgb_to_pixel8_dup;
1510 s->rgb_to_pixel = rgb_to_pixel15_dup;
1514 s->rgb_to_pixel = rgb_to_pixel16_dup;
1517 s->rgb_to_pixel = rgb_to_pixel32_dup;
1522 graphic_mode = s->gr[6] & 1;
1523 if (graphic_mode != s->graphic_mode) {
1524 s->graphic_mode = graphic_mode;
1528 vga_draw_graphic(s, full_update);
1530 vga_draw_text(s, full_update);
1534 static void vga_reset(VGAState *s)
1536 memset(s, 0, sizeof(VGAState));
1538 /* chip ID for 8c968 */
1541 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1544 s->graphic_mode = -1; /* force full update */
1547 static CPUReadMemoryFunc *vga_mem_read[3] = {
1553 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1559 static void vga_save(QEMUFile *f, void *opaque)
1561 VGAState *s = opaque;
1564 qemu_put_be32s(f, &s->latch);
1565 qemu_put_8s(f, &s->sr_index);
1566 qemu_put_buffer(f, s->sr, 8);
1567 qemu_put_8s(f, &s->gr_index);
1568 qemu_put_buffer(f, s->gr, 16);
1569 qemu_put_8s(f, &s->ar_index);
1570 qemu_put_buffer(f, s->ar, 21);
1571 qemu_put_be32s(f, &s->ar_flip_flop);
1572 qemu_put_8s(f, &s->cr_index);
1573 qemu_put_buffer(f, s->cr, 256);
1574 qemu_put_8s(f, &s->msr);
1575 qemu_put_8s(f, &s->fcr);
1576 qemu_put_8s(f, &s->st00);
1577 qemu_put_8s(f, &s->st01);
1579 qemu_put_8s(f, &s->dac_state);
1580 qemu_put_8s(f, &s->dac_sub_index);
1581 qemu_put_8s(f, &s->dac_read_index);
1582 qemu_put_8s(f, &s->dac_write_index);
1583 qemu_put_buffer(f, s->dac_cache, 3);
1584 qemu_put_buffer(f, s->palette, 768);
1586 qemu_put_be32s(f, &s->bank_offset);
1587 #ifdef CONFIG_BOCHS_VBE
1588 qemu_put_byte(f, 1);
1589 qemu_put_be16s(f, &s->vbe_index);
1590 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1591 qemu_put_be16s(f, &s->vbe_regs[i]);
1592 qemu_put_be32s(f, &s->vbe_start_addr);
1593 qemu_put_be32s(f, &s->vbe_line_offset);
1594 qemu_put_be32s(f, &s->vbe_bank_mask);
1596 qemu_put_byte(f, 0);
1600 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1602 VGAState *s = opaque;
1605 if (version_id != 1)
1608 qemu_get_be32s(f, &s->latch);
1609 qemu_get_8s(f, &s->sr_index);
1610 qemu_get_buffer(f, s->sr, 8);
1611 qemu_get_8s(f, &s->gr_index);
1612 qemu_get_buffer(f, s->gr, 16);
1613 qemu_get_8s(f, &s->ar_index);
1614 qemu_get_buffer(f, s->ar, 21);
1615 qemu_get_be32s(f, &s->ar_flip_flop);
1616 qemu_get_8s(f, &s->cr_index);
1617 qemu_get_buffer(f, s->cr, 256);
1618 qemu_get_8s(f, &s->msr);
1619 qemu_get_8s(f, &s->fcr);
1620 qemu_get_8s(f, &s->st00);
1621 qemu_get_8s(f, &s->st01);
1623 qemu_get_8s(f, &s->dac_state);
1624 qemu_get_8s(f, &s->dac_sub_index);
1625 qemu_get_8s(f, &s->dac_read_index);
1626 qemu_get_8s(f, &s->dac_write_index);
1627 qemu_get_buffer(f, s->dac_cache, 3);
1628 qemu_get_buffer(f, s->palette, 768);
1630 qemu_get_be32s(f, &s->bank_offset);
1631 is_vbe = qemu_get_byte(f);
1632 #ifdef CONFIG_BOCHS_VBE
1635 qemu_get_be16s(f, &s->vbe_index);
1636 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1637 qemu_get_be16s(f, &s->vbe_regs[i]);
1638 qemu_get_be32s(f, &s->vbe_start_addr);
1639 qemu_get_be32s(f, &s->vbe_line_offset);
1640 qemu_get_be32s(f, &s->vbe_bank_mask);
1647 s->graphic_mode = -1;
1651 int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1652 unsigned long vga_ram_offset, int vga_ram_size)
1654 VGAState *s = &vga_state;
1657 for(i = 0;i < 256; i++) {
1659 for(j = 0; j < 8; j++) {
1660 v |= ((i >> j) & 1) << (j * 4);
1665 for(j = 0; j < 4; j++) {
1666 v |= ((i >> (2 * j)) & 3) << (j * 4);
1670 for(i = 0; i < 16; i++) {
1672 for(j = 0; j < 4; j++) {
1675 v |= b << (2 * j + 1);
1682 s->vram_ptr = vga_ram_base;
1683 s->vram_offset = vga_ram_offset;
1684 s->vram_size = vga_ram_size;
1687 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1689 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1691 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1692 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1693 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1694 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1696 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1698 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1699 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1700 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1701 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1702 s->bank_offset = -0xa0000;
1704 #ifdef CONFIG_BOCHS_VBE
1705 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1706 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1707 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1708 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
1710 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1711 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
1714 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1715 #if defined (TARGET_I386)
1716 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
1717 #ifdef CONFIG_BOCHS_VBE
1718 /* XXX: use optimized standard vga accesses */
1719 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1720 vga_ram_size, vga_ram_offset);
1722 #elif defined (TARGET_PPC)
1723 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1728 /********************************************************/
1729 /* vga screen dump */
1731 static int vga_save_w, vga_save_h;
1733 static void vga_save_dpy_update(DisplayState *s,
1734 int x, int y, int w, int h)
1738 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1740 s->linesize = w * 4;
1741 s->data = qemu_malloc(h * s->linesize);
1746 static void vga_save_dpy_refresh(DisplayState *s)
1750 static int ppm_save(const char *filename, uint8_t *data,
1751 int w, int h, int linesize)
1758 f = fopen(filename, "wb");
1761 fprintf(f, "P6\n%d %d\n%d\n",
1764 for(y = 0; y < h; y++) {
1766 for(x = 0; x < w; x++) {
1768 fputc((v >> 16) & 0xff, f);
1769 fputc((v >> 8) & 0xff, f);
1770 fputc((v) & 0xff, f);
1779 /* save the vga display in a PPM image even if no display is
1781 void vga_screen_dump(const char *filename)
1783 VGAState *s = &vga_state;
1784 DisplayState *saved_ds, ds1, *ds = &ds1;
1786 /* XXX: this is a little hackish */
1788 s->last_height = -1;
1791 memset(ds, 0, sizeof(DisplayState));
1792 ds->dpy_update = vga_save_dpy_update;
1793 ds->dpy_resize = vga_save_dpy_resize;
1794 ds->dpy_refresh = vga_save_dpy_refresh;
1798 s->graphic_mode = -1;
1799 vga_update_display();
1802 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1804 qemu_free(ds->data);