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
41 #include <netinet/in.h>
43 #define NO_THUNK_TYPE_SIZE
52 //#define DEBUG_VGA_MEM
53 //#define DEBUG_VGA_REG
56 //#define DEBUG_BOCHS_VBE
60 #define MSR_COLOR_EMULATION 0x01
61 #define MSR_PAGE_SELECT 0x20
63 #define ST01_V_RETRACE 0x08
64 #define ST01_DISP_ENABLE 0x01
66 /* bochs VBE support */
67 #define CONFIG_BOCHS_VBE
69 #define VBE_DISPI_MAX_XRES 1024
70 #define VBE_DISPI_MAX_YRES 768
72 #define VBE_DISPI_INDEX_ID 0x0
73 #define VBE_DISPI_INDEX_XRES 0x1
74 #define VBE_DISPI_INDEX_YRES 0x2
75 #define VBE_DISPI_INDEX_BPP 0x3
76 #define VBE_DISPI_INDEX_ENABLE 0x4
77 #define VBE_DISPI_INDEX_BANK 0x5
78 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
79 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
80 #define VBE_DISPI_INDEX_X_OFFSET 0x8
81 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
82 #define VBE_DISPI_INDEX_NB 0xa
84 #define VBE_DISPI_ID0 0xB0C0
85 #define VBE_DISPI_ID1 0xB0C1
86 #define VBE_DISPI_ID2 0xB0C2
88 #define VBE_DISPI_DISABLED 0x00
89 #define VBE_DISPI_ENABLED 0x01
90 #define VBE_DISPI_LFB_ENABLED 0x40
91 #define VBE_DISPI_NOCLEARMEM 0x80
93 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
95 typedef struct VGAState
{
97 unsigned long vram_offset
;
98 unsigned int vram_size
;
108 uint8_t cr
[256]; /* CRT registers */
109 uint8_t msr
; /* Misc Output Register */
110 uint8_t fcr
; /* Feature Control Register */
111 uint8_t st00
; /* status 0 */
112 uint8_t st01
; /* status 1 */
114 uint8_t dac_sub_index
;
115 uint8_t dac_read_index
;
116 uint8_t dac_write_index
;
117 uint8_t dac_cache
[3]; /* used when writing */
118 uint8_t palette
[768];
119 uint32_t bank_offset
;
120 #ifdef CONFIG_BOCHS_VBE
122 uint16_t vbe_regs
[VBE_DISPI_INDEX_NB
];
123 uint32_t vbe_start_addr
;
124 uint32_t vbe_line_offset
;
125 uint32_t vbe_bank_mask
;
127 /* display refresh support */
129 uint32_t font_offsets
[2];
131 uint8_t shift_control
;
133 uint32_t line_offset
;
134 uint32_t line_compare
;
136 uint8_t last_cw
, last_ch
;
137 uint32_t last_width
, last_height
;
138 uint8_t cursor_start
, cursor_end
;
139 uint32_t cursor_offset
;
140 unsigned int (*rgb_to_pixel
)(unsigned int r
, unsigned int g
, unsigned b
);
141 /* tell for each page if it has been updated since the last time */
142 uint32_t last_palette
[256];
143 #define CH_ATTR_SIZE (160 * 100)
144 uint32_t last_ch_attr
[CH_ATTR_SIZE
]; /* XXX: make it dynamic */
147 /* force some bits to zero */
148 static const uint8_t sr_mask
[8] = {
159 static const uint8_t gr_mask
[16] = {
160 (uint8_t)~0xf0, /* 0x00 */
161 (uint8_t)~0xf0, /* 0x01 */
162 (uint8_t)~0xf0, /* 0x02 */
163 (uint8_t)~0xe0, /* 0x03 */
164 (uint8_t)~0xfc, /* 0x04 */
165 (uint8_t)~0x84, /* 0x05 */
166 (uint8_t)~0xf0, /* 0x06 */
167 (uint8_t)~0xf0, /* 0x07 */
168 (uint8_t)~0x00, /* 0x08 */
169 (uint8_t)~0xff, /* 0x09 */
170 (uint8_t)~0xff, /* 0x0a */
171 (uint8_t)~0xff, /* 0x0b */
172 (uint8_t)~0xff, /* 0x0c */
173 (uint8_t)~0xff, /* 0x0d */
174 (uint8_t)~0xff, /* 0x0e */
175 (uint8_t)~0xff, /* 0x0f */
178 #define cbswap_32(__x) \
180 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
181 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
182 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
183 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
185 #ifdef WORDS_BIGENDIAN
186 #define PAT(x) cbswap_32(x)
191 #ifdef WORDS_BIGENDIAN
197 #ifdef WORDS_BIGENDIAN
198 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
200 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
203 static const uint32_t mask16
[16] = {
224 #ifdef WORDS_BIGENDIAN
227 #define PAT(x) cbswap_32(x)
230 static const uint32_t dmask16
[16] = {
249 static const uint32_t dmask4
[4] = {
256 static uint32_t expand4
[256];
257 static uint16_t expand2
[256];
258 static uint8_t expand4to8
[16];
263 static uint32_t vga_ioport_read(CPUState
*env
, uint32_t addr
)
265 VGAState
*s
= &vga_state
;
268 /* check port range access depending on color/monochrome mode */
269 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
270 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
275 if (s
->ar_flip_flop
== 0) {
282 index
= s
->ar_index
& 0x1f;
295 val
= s
->sr
[s
->sr_index
];
297 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
304 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
305 if (++s
->dac_sub_index
== 3) {
306 s
->dac_sub_index
= 0;
320 val
= s
->gr
[s
->gr_index
];
322 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
331 val
= s
->cr
[s
->cr_index
];
333 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
336 if (s
->cr_index
>= 0x20)
337 printf("S3: CR read index=0x%x val=0x%x\n",
343 /* just toggle to fool polling */
344 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
353 #if defined(DEBUG_VGA)
354 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
359 static void vga_ioport_write(CPUState
*env
, uint32_t addr
, uint32_t val
)
361 VGAState
*s
= &vga_state
;
364 /* check port range access depending on color/monochrome mode */
365 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
366 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
370 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
375 if (s
->ar_flip_flop
== 0) {
379 index
= s
->ar_index
& 0x1f;
382 s
->ar
[index
] = val
& 0x3f;
385 s
->ar
[index
] = val
& ~0x10;
391 s
->ar
[index
] = val
& ~0xc0;
394 s
->ar
[index
] = val
& ~0xf0;
397 s
->ar
[index
] = val
& ~0xf0;
403 s
->ar_flip_flop
^= 1;
406 s
->msr
= val
& ~0x10;
409 s
->sr_index
= val
& 7;
413 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
415 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
418 s
->dac_read_index
= val
;
419 s
->dac_sub_index
= 0;
423 s
->dac_write_index
= val
;
424 s
->dac_sub_index
= 0;
428 s
->dac_cache
[s
->dac_sub_index
] = val
;
429 if (++s
->dac_sub_index
== 3) {
430 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
431 s
->dac_sub_index
= 0;
432 s
->dac_write_index
++;
436 s
->gr_index
= val
& 0x0f;
440 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
442 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
451 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
453 /* handle CR0-7 protection */
454 if ((s
->cr
[11] & 0x80) && s
->cr_index
<= 7) {
455 /* can always write bit 4 of CR7 */
456 if (s
->cr_index
== 7)
457 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
460 switch(s
->cr_index
) {
461 case 0x01: /* horizontal display end */
466 case 0x12: /* veritcal display end */
467 s
->cr
[s
->cr_index
] = val
;
476 /* chip ID, cannot write */
479 /* update start address */
480 s
->cr
[s
->cr_index
] = val
;
482 s
->cr
[0x69] = (s
->cr
[69] & ~0x03) | v
;
485 /* update start address */
486 s
->cr
[s
->cr_index
] = val
;
488 s
->cr
[0x69] = (s
->cr
[69] & ~0x0c) | (v
<< 2);
492 s
->cr
[s
->cr_index
] = val
;
496 if (s
->cr_index
>= 0x20)
497 printf("S3: CR write index=0x%x val=0x%x\n",
508 #ifdef CONFIG_BOCHS_VBE
509 static uint32_t vbe_ioport_read(CPUState
*env
, uint32_t addr
)
511 VGAState
*s
= &vga_state
;
518 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
)
519 val
= s
->vbe_regs
[s
->vbe_index
];
522 #ifdef DEBUG_BOCHS_VBE
523 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
529 static void vbe_ioport_write(CPUState
*env
, uint32_t addr
, uint32_t val
)
531 VGAState
*s
= &vga_state
;
536 } else if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
537 #ifdef DEBUG_BOCHS_VBE
538 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
540 switch(s
->vbe_index
) {
541 case VBE_DISPI_INDEX_ID
:
542 if (val
== VBE_DISPI_ID0
||
543 val
== VBE_DISPI_ID1
||
544 val
== VBE_DISPI_ID2
) {
545 s
->vbe_regs
[s
->vbe_index
] = val
;
548 case VBE_DISPI_INDEX_XRES
:
549 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
550 s
->vbe_regs
[s
->vbe_index
] = val
;
553 case VBE_DISPI_INDEX_YRES
:
554 if (val
<= VBE_DISPI_MAX_YRES
) {
555 s
->vbe_regs
[s
->vbe_index
] = val
;
558 case VBE_DISPI_INDEX_BPP
:
561 if (val
== 4 || val
== 8 || val
== 15 ||
562 val
== 16 || val
== 24 || val
== 32) {
563 s
->vbe_regs
[s
->vbe_index
] = val
;
566 case VBE_DISPI_INDEX_BANK
:
567 val
&= s
->vbe_bank_mask
;
568 s
->vbe_regs
[s
->vbe_index
] = val
;
569 s
->bank_offset
= (val
<< 16) - 0xa0000;
571 case VBE_DISPI_INDEX_ENABLE
:
572 if (val
& VBE_DISPI_ENABLED
) {
573 int h
, shift_control
;
575 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
576 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
577 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
578 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
579 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
580 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
582 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
583 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
585 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
586 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
587 s
->vbe_start_addr
= 0;
589 /* clear the screen (should be done in BIOS) */
590 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
591 memset(s
->vram_ptr
, 0,
592 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
595 /* we initialize the VGA graphic mode (should be done
597 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
598 s
->cr
[0x17] |= 3; /* no CGA modes */
599 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
601 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
603 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
605 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
606 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
607 /* line compare to 1023 */
612 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
614 s
->sr
[0x01] &= ~8; /* no double line */
618 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
619 s
->cr
[0x09] &= ~0x9f; /* no double scan */
620 s
->vbe_regs
[s
->vbe_index
] = val
;
622 /* XXX: the bios should do that */
623 s
->bank_offset
= -0xa0000;
626 case VBE_DISPI_INDEX_VIRT_WIDTH
:
628 int w
, h
, line_offset
;
630 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
633 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
634 line_offset
= w
>> 1;
636 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
637 h
= s
->vram_size
/ line_offset
;
638 /* XXX: support weird bochs semantics ? */
639 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
641 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
642 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
643 s
->vbe_line_offset
= line_offset
;
646 case VBE_DISPI_INDEX_X_OFFSET
:
647 case VBE_DISPI_INDEX_Y_OFFSET
:
650 s
->vbe_regs
[s
->vbe_index
] = val
;
651 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
652 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
653 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
654 s
->vbe_start_addr
+= x
>> 1;
656 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
657 s
->vbe_start_addr
>>= 2;
667 /* called for accesses between 0xa0000 and 0xc0000 */
668 static uint32_t vga_mem_readb(uint32_t addr
)
670 VGAState
*s
= &vga_state
;
671 int memory_map_mode
, plane
;
674 /* convert to VGA memory offset */
675 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
676 switch(memory_map_mode
) {
683 addr
+= s
->bank_offset
;
698 if (s
->sr
[4] & 0x08) {
699 /* chain 4 mode : simplest access */
700 ret
= s
->vram_ptr
[addr
];
701 } else if (s
->gr
[5] & 0x10) {
702 /* odd/even mode (aka text mode mapping) */
703 plane
= (s
->gr
[4] & 2) | (addr
& 1);
704 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
706 /* standard VGA latched access */
707 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
709 if (!(s
->gr
[5] & 0x08)) {
712 ret
= GET_PLANE(s
->latch
, plane
);
715 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
724 static uint32_t vga_mem_readw(uint32_t addr
)
727 v
= vga_mem_readb(addr
);
728 v
|= vga_mem_readb(addr
+ 1) << 8;
732 static uint32_t vga_mem_readl(uint32_t addr
)
735 v
= vga_mem_readb(addr
);
736 v
|= vga_mem_readb(addr
+ 1) << 8;
737 v
|= vga_mem_readb(addr
+ 2) << 16;
738 v
|= vga_mem_readb(addr
+ 3) << 24;
742 /* called for accesses between 0xa0000 and 0xc0000 */
743 void vga_mem_writeb(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
745 VGAState
*s
= &vga_state
;
746 int memory_map_mode
, plane
, write_mode
, b
, func_select
;
747 uint32_t write_mask
, bit_mask
, set_mask
;
750 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
752 /* convert to VGA memory offset */
753 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
754 switch(memory_map_mode
) {
761 addr
+= s
->bank_offset
;
776 if (s
->sr
[4] & 0x08) {
777 /* chain 4 mode : simplest access */
779 if (s
->sr
[2] & (1 << plane
)) {
780 s
->vram_ptr
[addr
] = val
;
782 printf("vga: chain4: [0x%x]\n", addr
);
784 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
786 } else if (s
->gr
[5] & 0x10) {
787 /* odd/even mode (aka text mode mapping) */
788 plane
= (s
->gr
[4] & 2) | (addr
& 1);
789 if (s
->sr
[2] & (1 << plane
)) {
790 addr
= ((addr
& ~1) << 1) | plane
;
791 s
->vram_ptr
[addr
] = val
;
793 printf("vga: odd/even: [0x%x]\n", addr
);
795 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
798 /* standard VGA latched access */
799 write_mode
= s
->gr
[5] & 3;
805 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
809 /* apply set/reset mask */
810 set_mask
= mask16
[s
->gr
[1]];
811 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
818 val
= mask16
[val
& 0x0f];
824 val
= (val
>> b
) | (val
<< (8 - b
));
826 bit_mask
= s
->gr
[8] & val
;
827 val
= mask16
[s
->gr
[0]];
831 /* apply logical operation */
832 func_select
= s
->gr
[3] >> 3;
833 switch(func_select
) {
853 bit_mask
|= bit_mask
<< 8;
854 bit_mask
|= bit_mask
<< 16;
855 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
858 /* mask data according to sr[2] */
859 write_mask
= mask16
[s
->sr
[2]];
860 ((uint32_t *)s
->vram_ptr
)[addr
] =
861 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
864 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
865 addr
* 4, write_mask
, val
);
867 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
871 void vga_mem_writew(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
873 vga_mem_writeb(addr
, val
& 0xff, vaddr
);
874 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff, vaddr
);
877 void vga_mem_writel(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
879 vga_mem_writeb(addr
, val
& 0xff, vaddr
);
880 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff, vaddr
);
881 vga_mem_writeb(addr
+ 2, (val
>> 16) & 0xff, vaddr
);
882 vga_mem_writeb(addr
+ 3, (val
>> 24) & 0xff, vaddr
);
885 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
886 const uint8_t *font_ptr
, int h
,
887 uint32_t fgcol
, uint32_t bgcol
);
888 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
889 const uint8_t *font_ptr
, int h
,
890 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
891 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
892 const uint8_t *s
, int width
);
894 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
900 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
902 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
905 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
907 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
910 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
912 return (r
<< 16) | (g
<< 8) | b
;
916 #include "vga_template.h"
919 #include "vga_template.h"
922 #include "vga_template.h"
925 #include "vga_template.h"
927 static inline int c6_to_8(int v
)
932 return (v
<< 2) | (b
<< 1) | b
;
935 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
938 col
= rgb_to_pixel8(r
, g
, b
);
944 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
947 col
= rgb_to_pixel15(r
, g
, b
);
952 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
955 col
= rgb_to_pixel16(r
, g
, b
);
960 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
963 col
= rgb_to_pixel32(r
, g
, b
);
967 /* return true if the palette was modified */
968 static int update_palette16(VGAState
*s
)
971 uint32_t v
, col
, *palette
;
974 palette
= s
->last_palette
;
975 for(i
= 0; i
< 16; i
++) {
977 if (s
->ar
[0x10] & 0x80)
978 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
980 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
982 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
983 c6_to_8(s
->palette
[v
+ 1]),
984 c6_to_8(s
->palette
[v
+ 2]));
985 if (col
!= palette
[i
]) {
993 /* return true if the palette was modified */
994 static int update_palette256(VGAState
*s
)
997 uint32_t v
, col
, *palette
;
1000 palette
= s
->last_palette
;
1002 for(i
= 0; i
< 256; i
++) {
1003 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1004 c6_to_8(s
->palette
[v
+ 1]),
1005 c6_to_8(s
->palette
[v
+ 2]));
1006 if (col
!= palette
[i
]) {
1015 /* update start_addr and line_offset. Return TRUE if modified */
1016 static int update_basic_params(VGAState
*s
)
1019 uint32_t start_addr
, line_offset
, line_compare
, v
;
1023 #ifdef CONFIG_BOCHS_VBE
1024 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1025 line_offset
= s
->vbe_line_offset
;
1026 start_addr
= s
->vbe_start_addr
;
1030 /* compute line_offset in bytes */
1031 line_offset
= s
->cr
[0x13];
1033 v
= (s
->cr
[0x51] >> 4) & 3; /* S3 extension */
1035 v
= (s
->cr
[0x43] >> 2) & 1; /* S3 extension */
1036 line_offset
|= (v
<< 8);
1040 /* starting address */
1041 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1043 start_addr
|= (s
->cr
[0x69] & 0x1f) << 16; /* S3 extension */
1048 line_compare
= s
->cr
[0x18] |
1049 ((s
->cr
[0x07] & 0x10) << 4) |
1050 ((s
->cr
[0x09] & 0x40) << 3);
1052 if (line_offset
!= s
->line_offset
||
1053 start_addr
!= s
->start_addr
||
1054 line_compare
!= s
->line_compare
) {
1055 s
->line_offset
= line_offset
;
1056 s
->start_addr
= start_addr
;
1057 s
->line_compare
= line_compare
;
1063 static inline int get_depth_index(int depth
)
1078 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[4] = {
1085 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[4] = {
1087 vga_draw_glyph16_16
,
1088 vga_draw_glyph16_16
,
1089 vga_draw_glyph16_32
,
1092 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[4] = {
1099 static const uint8_t cursor_glyph
[32 * 4] = {
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1126 static void vga_draw_text(VGAState
*s
, int full_update
)
1128 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1129 int cx_min
, cx_max
, linesize
, x_incr
;
1130 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1131 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1132 const uint8_t *font_ptr
, *font_base
[2];
1133 int dup9
, line_offset
, depth_index
;
1135 uint32_t *ch_attr_ptr
;
1136 vga_draw_glyph8_func
*vga_draw_glyph8
;
1137 vga_draw_glyph9_func
*vga_draw_glyph9
;
1139 full_update
|= update_palette16(s
);
1140 palette
= s
->last_palette
;
1142 /* compute font data address (in plane 2) */
1144 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1145 if (offset
!= s
->font_offsets
[0]) {
1146 s
->font_offsets
[0] = offset
;
1149 font_base
[0] = s
->vram_ptr
+ offset
;
1151 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1152 font_base
[1] = s
->vram_ptr
+ offset
;
1153 if (offset
!= s
->font_offsets
[1]) {
1154 s
->font_offsets
[1] = offset
;
1158 full_update
|= update_basic_params(s
);
1160 line_offset
= s
->line_offset
;
1161 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1163 /* total width & height */
1164 cheight
= (s
->cr
[9] & 0x1f) + 1;
1166 if (s
->sr
[1] & 0x01)
1168 if (s
->sr
[1] & 0x08)
1169 cw
= 16; /* NOTE: no 18 pixel wide */
1170 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1171 width
= (s
->cr
[0x01] + 1);
1172 if (s
->cr
[0x06] == 100) {
1173 /* ugly hack for CGA 160x100x16 - explain me the logic */
1176 height
= s
->cr
[0x12] |
1177 ((s
->cr
[0x07] & 0x02) << 7) |
1178 ((s
->cr
[0x07] & 0x40) << 3);
1179 height
= (height
+ 1) / cheight
;
1181 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1182 cw
!= s
->last_cw
|| cw
!= s
->last_cw
) {
1183 dpy_resize(s
->ds
, width
* cw
, height
* cheight
);
1184 s
->last_width
= width
;
1185 s
->last_height
= height
;
1186 s
->last_ch
= cheight
;
1190 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1191 if (cursor_offset
!= s
->cursor_offset
||
1192 s
->cr
[0xa] != s
->cursor_start
||
1193 s
->cr
[0xb] != s
->cursor_end
) {
1194 /* if the cursor position changed, we update the old and new
1196 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1197 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1198 if (cursor_offset
< CH_ATTR_SIZE
)
1199 s
->last_ch_attr
[cursor_offset
] = -1;
1200 s
->cursor_offset
= cursor_offset
;
1201 s
->cursor_start
= s
->cr
[0xa];
1202 s
->cursor_end
= s
->cr
[0xb];
1204 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1206 depth_index
= get_depth_index(s
->ds
->depth
);
1208 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1210 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1211 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1214 linesize
= s
->ds
->linesize
;
1215 ch_attr_ptr
= s
->last_ch_attr
;
1216 for(cy
= 0; cy
< height
; cy
++) {
1221 for(cx
= 0; cx
< width
; cx
++) {
1222 ch_attr
= *(uint16_t *)src
;
1223 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1228 *ch_attr_ptr
= ch_attr
;
1229 #ifdef WORDS_BIGENDIAN
1231 cattr
= ch_attr
& 0xff;
1233 ch
= ch_attr
& 0xff;
1234 cattr
= ch_attr
>> 8;
1236 font_ptr
= font_base
[(cattr
>> 3) & 1];
1237 font_ptr
+= 32 * 4 * ch
;
1238 bgcol
= palette
[cattr
>> 4];
1239 fgcol
= palette
[cattr
& 0x0f];
1241 vga_draw_glyph8(d1
, linesize
,
1242 font_ptr
, cheight
, fgcol
, bgcol
);
1245 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1247 vga_draw_glyph9(d1
, linesize
,
1248 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1250 if (src
== cursor_ptr
&&
1251 !(s
->cr
[0x0a] & 0x20)) {
1252 int line_start
, line_last
, h
;
1253 /* draw the cursor */
1254 line_start
= s
->cr
[0x0a] & 0x1f;
1255 line_last
= s
->cr
[0x0b] & 0x1f;
1256 /* XXX: check that */
1257 if (line_last
> cheight
- 1)
1258 line_last
= cheight
- 1;
1259 if (line_last
>= line_start
&& line_start
< cheight
) {
1260 h
= line_last
- line_start
+ 1;
1261 d
= d1
+ linesize
* line_start
;
1263 vga_draw_glyph8(d
, linesize
,
1264 cursor_glyph
, h
, fgcol
, bgcol
);
1266 vga_draw_glyph9(d
, linesize
,
1267 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1277 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1278 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1280 dest
+= linesize
* cheight
;
1299 static vga_draw_line_func
*vga_draw_line_table
[4 * VGA_DRAW_LINE_NB
] = {
1306 vga_draw_line2d2_16
,
1307 vga_draw_line2d2_16
,
1308 vga_draw_line2d2_32
,
1316 vga_draw_line4d2_16
,
1317 vga_draw_line4d2_16
,
1318 vga_draw_line4d2_32
,
1321 vga_draw_line8d2_16
,
1322 vga_draw_line8d2_16
,
1323 vga_draw_line8d2_32
,
1357 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1359 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1360 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1361 int disp_width
, multi_scan
, multi_run
;
1363 uint32_t v
, addr1
, addr
;
1364 vga_draw_line_func
*vga_draw_line
;
1366 full_update
|= update_basic_params(s
);
1368 width
= (s
->cr
[0x01] + 1) * 8;
1369 height
= s
->cr
[0x12] |
1370 ((s
->cr
[0x07] & 0x02) << 7) |
1371 ((s
->cr
[0x07] & 0x40) << 3);
1372 height
= (height
+ 1);
1375 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1376 double_scan
= (s
->cr
[0x09] & 0x80);
1377 if (shift_control
> 1) {
1378 multi_scan
= (s
->cr
[0x09] & 0x1f);
1382 multi_run
= multi_scan
;
1383 if (shift_control
!= s
->shift_control
||
1384 double_scan
!= s
->double_scan
) {
1386 s
->shift_control
= shift_control
;
1387 s
->double_scan
= double_scan
;
1390 if (shift_control
== 0) {
1391 full_update
|= update_palette16(s
);
1392 if (s
->sr
[0x01] & 8) {
1393 v
= VGA_DRAW_LINE4D2
;
1398 } else if (shift_control
== 1) {
1399 full_update
|= update_palette16(s
);
1400 if (s
->sr
[0x01] & 8) {
1401 v
= VGA_DRAW_LINE2D2
;
1407 #ifdef CONFIG_BOCHS_VBE
1408 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1409 switch(s
->vbe_regs
[VBE_DISPI_INDEX_BPP
]) {
1412 full_update
|= update_palette256(s
);
1416 v
= VGA_DRAW_LINE15
;
1419 v
= VGA_DRAW_LINE16
;
1422 v
= VGA_DRAW_LINE24
;
1425 v
= VGA_DRAW_LINE32
;
1431 full_update
|= update_palette256(s
);
1432 v
= VGA_DRAW_LINE8D2
;
1435 vga_draw_line
= vga_draw_line_table
[v
* 4 + get_depth_index(s
->ds
->depth
)];
1437 if (disp_width
!= s
->last_width
||
1438 height
!= s
->last_height
) {
1439 dpy_resize(s
->ds
, disp_width
, height
);
1440 s
->last_width
= disp_width
;
1441 s
->last_height
= height
;
1445 line_offset
= s
->line_offset
;
1447 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1448 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1450 addr1
= (s
->start_addr
* 4);
1453 page_min
= 0x7fffffff;
1456 linesize
= s
->ds
->linesize
;
1458 for(y
= 0; y
< height
; y
++) {
1460 if (!(s
->cr
[0x17] & 1)) {
1462 /* CGA compatibility handling */
1463 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1464 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1466 if (!(s
->cr
[0x17] & 2)) {
1467 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1469 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1470 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1471 update
= full_update
| cpu_physical_memory_is_dirty(page0
) |
1472 cpu_physical_memory_is_dirty(page1
);
1473 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1474 /* if wide line, can use another page */
1475 update
|= cpu_physical_memory_is_dirty(page0
+ TARGET_PAGE_SIZE
);
1480 if (page0
< page_min
)
1482 if (page1
> page_max
)
1484 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1487 /* flush to display */
1488 dpy_update(s
->ds
, 0, y_start
,
1489 disp_width
, y
- y_start
);
1494 if (!double_scan
|| (y
& 1) != 0) {
1495 if (y1
== s
->line_compare
) {
1498 mask
= (s
->cr
[0x17] & 3) ^ 3;
1499 if ((y1
& mask
) == mask
)
1500 addr1
+= line_offset
;
1504 multi_run
= multi_scan
;
1512 /* flush to display */
1513 dpy_update(s
->ds
, 0, y_start
,
1514 disp_width
, y
- y_start
);
1516 /* reset modified pages */
1517 if (page_max
!= -1) {
1518 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
);
1522 /* draw text terminal (very limited, just for simple boot debug
1524 static int last_cursor_pos
;
1526 void vga_draw_dumb(VGAState
*s
)
1528 int c
, i
, cursor_pos
, eol
;
1530 cursor_pos
= s
->cr
[0x0f] | (s
->cr
[0x0e] << 8);
1532 for(i
= last_cursor_pos
; i
< cursor_pos
; i
++) {
1533 /* XXX: should use vga RAM */
1534 c
= phys_ram_base
[0xb8000 + (i
) * 2];
1545 last_cursor_pos
= cursor_pos
;
1548 void vga_update_display(void)
1550 VGAState
*s
= &vga_state
;
1551 int full_update
, graphic_mode
;
1553 if (s
->ds
->depth
== 0) {
1557 graphic_mode
= s
->gr
[6] & 1;
1558 if (graphic_mode
!= s
->graphic_mode
) {
1559 s
->graphic_mode
= graphic_mode
;
1563 vga_draw_graphic(s
, full_update
);
1565 vga_draw_text(s
, full_update
);
1569 void vga_reset(VGAState
*s
)
1571 memset(s
, 0, sizeof(VGAState
));
1573 /* chip ID for 8c968 */
1576 s
->cr
[0x2f] = 0x01; /* XXX: check revision code */
1579 s
->graphic_mode
= -1; /* force full update */
1582 CPUReadMemoryFunc
*vga_mem_read
[3] = {
1588 CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1594 int vga_initialize(DisplayState
*ds
, uint8_t *vga_ram_base
,
1595 unsigned long vga_ram_offset
, int vga_ram_size
)
1597 VGAState
*s
= &vga_state
;
1600 for(i
= 0;i
< 256; i
++) {
1602 for(j
= 0; j
< 8; j
++) {
1603 v
|= ((i
>> j
) & 1) << (j
* 4);
1608 for(j
= 0; j
< 4; j
++) {
1609 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1613 for(i
= 0; i
< 16; i
++) {
1615 for(j
= 0; j
< 4; j
++) {
1618 v
|= b
<< (2 * j
+ 1);
1627 s
->rgb_to_pixel
= rgb_to_pixel8_dup
;
1630 s
->rgb_to_pixel
= rgb_to_pixel15_dup
;
1634 s
->rgb_to_pixel
= rgb_to_pixel16_dup
;
1637 s
->rgb_to_pixel
= rgb_to_pixel32_dup
;
1641 s
->vram_ptr
= vga_ram_base
;
1642 s
->vram_offset
= vga_ram_offset
;
1643 s
->vram_size
= vga_ram_size
;
1646 register_ioport_write(0x3c0, 16, vga_ioport_write
, 1);
1648 register_ioport_write(0x3b4, 2, vga_ioport_write
, 1);
1649 register_ioport_write(0x3d4, 2, vga_ioport_write
, 1);
1650 register_ioport_write(0x3ba, 1, vga_ioport_write
, 1);
1651 register_ioport_write(0x3da, 1, vga_ioport_write
, 1);
1653 register_ioport_read(0x3c0, 16, vga_ioport_read
, 1);
1655 register_ioport_read(0x3b4, 2, vga_ioport_read
, 1);
1656 register_ioport_read(0x3d4, 2, vga_ioport_read
, 1);
1657 register_ioport_read(0x3ba, 1, vga_ioport_read
, 1);
1658 register_ioport_read(0x3da, 1, vga_ioport_read
, 1);
1659 s
->bank_offset
= -0xa0000;
1661 #ifdef CONFIG_BOCHS_VBE
1662 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
1663 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
1664 register_ioport_read(0x1ce, 1, vbe_ioport_read
, 2);
1665 register_ioport_read(0x1cf, 1, vbe_ioport_read
, 2);
1667 register_ioport_write(0x1ce, 1, vbe_ioport_write
, 2);
1668 register_ioport_write(0x1cf, 1, vbe_ioport_write
, 2);
1671 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
);
1672 #if defined (TARGET_I386)
1673 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory
);
1674 #ifdef CONFIG_BOCHS_VBE
1675 /* XXX: use optimized standard vga accesses */
1676 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1677 vga_ram_size
, vga_ram_offset
);
1679 #elif defined (TARGET_PPC)
1680 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory
);