2 * QEMU VGA Emulator. An S3 86c968 is emulated
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>
48 #define NO_THUNK_TYPE_SIZE
52 //#define DEBUG_VGA_MEM
54 #define MSR_COLOR_EMULATION 0x01
55 #define MSR_PAGE_SELECT 0x20
57 #define ST01_V_RETRACE 0x08
58 #define ST01_DISP_ENABLE 0x01
60 typedef struct VGAState
{
62 unsigned long vram_offset
;
63 unsigned int vram_size
;
73 uint8_t cr
[256]; /* CRT registers */
74 uint8_t msr
; /* Misc Output Register */
75 uint8_t fcr
; /* Feature Control Register */
76 uint8_t st00
; /* status 0 */
77 uint8_t st01
; /* status 1 */
79 uint8_t dac_sub_index
;
80 uint8_t dac_read_index
;
81 uint8_t dac_write_index
;
82 uint8_t dac_cache
[3]; /* used when writing */
85 /* display refresh support */
87 uint32_t font_offsets
[2];
89 uint8_t shift_control
;
92 uint32_t line_compare
;
94 uint8_t last_cw
, last_ch
;
95 uint32_t last_width
, last_height
;
96 uint8_t cursor_start
, cursor_end
;
97 uint32_t cursor_offset
;
98 unsigned int (*rgb_to_pixel
)(unsigned int r
, unsigned int g
, unsigned b
);
99 /* tell for each page if it has been updated since the last time */
100 uint8_t vram_updated
[VGA_RAM_SIZE
/ 4096];
101 uint32_t last_palette
[256];
102 #define CH_ATTR_SIZE (160 * 100)
103 uint32_t last_ch_attr
[CH_ATTR_SIZE
]; /* XXX: make it dynamic */
106 /* force some bits to zero */
107 static const uint8_t sr_mask
[8] = {
118 static const uint8_t gr_mask
[16] = {
119 (uint8_t)~0xf0, /* 0x00 */
120 (uint8_t)~0xf0, /* 0x01 */
121 (uint8_t)~0xf0, /* 0x02 */
122 (uint8_t)~0xe0, /* 0x03 */
123 (uint8_t)~0xfc, /* 0x04 */
124 (uint8_t)~0x84, /* 0x05 */
125 (uint8_t)~0xf0, /* 0x06 */
126 (uint8_t)~0xf0, /* 0x07 */
127 (uint8_t)~0x00, /* 0x08 */
128 (uint8_t)~0xff, /* 0x09 */
129 (uint8_t)~0xff, /* 0x0a */
130 (uint8_t)~0xff, /* 0x0b */
131 (uint8_t)~0xff, /* 0x0c */
132 (uint8_t)~0xff, /* 0x0d */
133 (uint8_t)~0xff, /* 0x0e */
134 (uint8_t)~0xff, /* 0x0f */
137 #define cbswap_32(__x) \
139 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
140 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
141 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
142 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
144 #ifdef WORDS_BIGENDIAN
145 #define PAT(x) cbswap_32(x)
150 #ifdef WORDS_BIGENDIAN
156 #ifdef WORDS_BIGENDIAN
157 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
159 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
162 static const uint32_t mask16
[16] = {
183 #ifdef WORDS_BIGENDIAN
186 #define PAT(x) cbswap_32(x)
189 static const uint32_t dmask16
[16] = {
208 static const uint32_t dmask4
[4] = {
215 static uint32_t expand4
[256];
216 static uint16_t expand2
[256];
217 static uint8_t expand4to8
[16];
222 static uint32_t vga_ioport_read(CPUX86State
*env
, uint32_t addr
)
224 VGAState
*s
= &vga_state
;
227 /* check port range access depending on color/monochrome mode */
228 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
229 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
234 if (s
->ar_flip_flop
== 0) {
241 index
= s
->ar_index
& 0x1f;
254 val
= s
->sr
[s
->sr_index
];
260 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
261 if (++s
->dac_sub_index
== 3) {
262 s
->dac_sub_index
= 0;
276 val
= s
->gr
[s
->gr_index
];
284 val
= s
->cr
[s
->cr_index
];
288 /* just toggle to fool polling */
289 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
299 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
304 static void vga_ioport_write(CPUX86State
*env
, uint32_t addr
, uint32_t val
)
306 VGAState
*s
= &vga_state
;
309 /* check port range access depending on color/monochrome mode */
310 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
311 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
315 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
320 if (s
->ar_flip_flop
== 0) {
324 index
= s
->ar_index
& 0x1f;
327 s
->ar
[index
] = val
& 0x3f;
330 s
->ar
[index
] = val
& ~0x10;
336 s
->ar
[index
] = val
& ~0xc0;
339 s
->ar
[index
] = val
& ~0xf0;
342 s
->ar
[index
] = val
& ~0xf0;
348 s
->ar_flip_flop
^= 1;
351 s
->msr
= val
& ~0x10;
354 s
->sr_index
= val
& 7;
357 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
360 s
->dac_read_index
= val
;
361 s
->dac_sub_index
= 0;
365 s
->dac_write_index
= val
;
366 s
->dac_sub_index
= 0;
370 s
->dac_cache
[s
->dac_sub_index
] = val
;
371 if (++s
->dac_sub_index
== 3) {
372 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
373 s
->dac_sub_index
= 0;
374 s
->dac_write_index
++;
378 s
->gr_index
= val
& 0x0f;
381 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
389 /* handle CR0-7 protection */
390 if ((s
->cr
[11] & 0x80) && s
->cr_index
<= 7) {
391 /* can always write bit 4 of CR7 */
392 if (s
->cr_index
== 7)
393 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
396 switch(s
->cr_index
) {
397 case 0x01: /* horizontal display end */
402 case 0x12: /* veritcal display end */
403 s
->cr
[s
->cr_index
] = val
;
411 /* chip ID, cannot write */
414 /* update start address */
415 s
->cr
[s
->cr_index
] = val
;
417 s
->cr
[0x69] = (s
->cr
[69] & ~0x03) | v
;
420 /* update start address */
421 s
->cr
[s
->cr_index
] = val
;
423 s
->cr
[0x69] = (s
->cr
[69] & ~0x0c) | (v
<< 2);
426 s
->cr
[s
->cr_index
] = val
;
437 /* called for accesses between 0xa0000 and 0xc0000 */
438 static uint32_t vga_mem_readb(uint32_t addr
)
440 VGAState
*s
= &vga_state
;
441 int memory_map_mode
, plane
;
444 /* convert to VGA memory offset */
445 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
446 switch(memory_map_mode
) {
466 if (s
->sr
[4] & 0x08) {
467 /* chain 4 mode : simplest access */
468 ret
= s
->vram_ptr
[addr
];
469 } else if (s
->gr
[5] & 0x10) {
470 /* odd/even mode (aka text mode mapping) */
471 plane
= (s
->gr
[4] & 2) | (addr
& 1);
472 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
474 /* standard VGA latched access */
475 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
477 if (!(s
->gr
[5] & 0x08)) {
480 ret
= GET_PLANE(s
->latch
, plane
);
483 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
492 static uint32_t vga_mem_readw(uint32_t addr
)
495 v
= vga_mem_readb(addr
);
496 v
|= vga_mem_readb(addr
+ 1) << 8;
500 static uint32_t vga_mem_readl(uint32_t addr
)
503 v
= vga_mem_readb(addr
);
504 v
|= vga_mem_readb(addr
+ 1) << 8;
505 v
|= vga_mem_readb(addr
+ 2) << 16;
506 v
|= vga_mem_readb(addr
+ 3) << 24;
511 /* called for accesses between 0xa0000 and 0xc0000 */
512 void vga_mem_writeb(uint32_t addr
, uint32_t val
)
514 VGAState
*s
= &vga_state
;
515 int memory_map_mode
, plane
, write_mode
, b
, func_select
;
516 uint32_t write_mask
, bit_mask
, set_mask
;
519 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
521 /* convert to VGA memory offset */
522 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
523 switch(memory_map_mode
) {
543 if (s
->sr
[4] & 0x08) {
544 /* chain 4 mode : simplest access */
546 if (s
->sr
[2] & (1 << plane
)) {
547 s
->vram_ptr
[addr
] = val
;
549 printf("vga: chain4: [0x%x]\n", addr
);
551 s
->vram_updated
[addr
>> 12] = 1;
553 } else if (s
->gr
[5] & 0x10) {
554 /* odd/even mode (aka text mode mapping) */
555 plane
= (s
->gr
[4] & 2) | (addr
& 1);
556 if (s
->sr
[2] & (1 << plane
)) {
557 addr
= ((addr
& ~1) << 1) | plane
;
558 s
->vram_ptr
[addr
] = val
;
560 printf("vga: odd/even: [0x%x]\n", addr
);
562 s
->vram_updated
[addr
>> 12] = 1;
565 /* standard VGA latched access */
566 write_mode
= s
->gr
[5] & 3;
572 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
576 /* apply set/reset mask */
577 set_mask
= mask16
[s
->gr
[1]];
578 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
585 val
= mask16
[val
& 0x0f];
591 val
= ((val
>> b
) | (val
<< (8 - b
)));
593 bit_mask
= s
->gr
[8] & val
;
594 val
= mask16
[s
->gr
[0]];
598 /* apply logical operation */
599 func_select
= s
->gr
[3] >> 3;
600 switch(func_select
) {
620 bit_mask
|= bit_mask
<< 8;
621 bit_mask
|= bit_mask
<< 16;
622 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
625 /* mask data according to sr[2] */
626 write_mask
= mask16
[s
->sr
[2]];
627 ((uint32_t *)s
->vram_ptr
)[addr
] =
628 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
631 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
632 addr
* 4, write_mask
, val
);
634 s
->vram_updated
[addr
>> 10] = 1;
638 void vga_mem_writew(uint32_t addr
, uint32_t val
)
640 vga_mem_writeb(addr
, val
& 0xff);
641 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff);
644 void vga_mem_writel(uint32_t addr
, uint32_t val
)
646 vga_mem_writeb(addr
, val
& 0xff);
647 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff);
648 vga_mem_writeb(addr
+ 2, (val
>> 16) & 0xff);
649 vga_mem_writeb(addr
+ 3, (val
>> 24) & 0xff);
652 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
653 const uint8_t *font_ptr
, int h
,
654 uint32_t fgcol
, uint32_t bgcol
);
655 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
656 const uint8_t *font_ptr
, int h
,
657 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
658 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
659 const uint8_t *s
, int width
);
661 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
667 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
669 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
672 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
674 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
677 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
679 return (r
<< 16) | (g
<< 8) | b
;
683 #include "vga_template.h"
686 #include "vga_template.h"
689 #include "vga_template.h"
692 #include "vga_template.h"
694 static inline int c6_to_8(int v
)
699 return (v
<< 2) | (b
<< 1) | b
;
702 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
705 col
= rgb_to_pixel8(r
, g
, b
);
711 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
714 col
= rgb_to_pixel15(r
, g
, b
);
719 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
722 col
= rgb_to_pixel16(r
, g
, b
);
727 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
730 col
= rgb_to_pixel32(r
, g
, b
);
734 /* return true if the palette was modified */
735 static int update_palette16(VGAState
*s
)
738 uint32_t v
, col
, *palette
;
741 palette
= s
->last_palette
;
742 for(i
= 0; i
< 16; i
++) {
744 if (s
->ar
[0x10] & 0x80)
745 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
747 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
749 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
750 c6_to_8(s
->palette
[v
+ 1]),
751 c6_to_8(s
->palette
[v
+ 2]));
752 if (col
!= palette
[i
]) {
760 /* return true if the palette was modified */
761 static int update_palette256(VGAState
*s
)
764 uint32_t v
, col
, *palette
;
767 palette
= s
->last_palette
;
769 for(i
= 0; i
< 256; i
++) {
770 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
771 c6_to_8(s
->palette
[v
+ 1]),
772 c6_to_8(s
->palette
[v
+ 2]));
773 if (col
!= palette
[i
]) {
782 /* update start_addr and line_offset. Return TRUE if modified */
783 static int update_basic_params(VGAState
*s
)
786 uint32_t start_addr
, line_offset
, line_compare
, v
;
789 /* compute line_offset in bytes */
790 v
= (s
->cr
[0x51] >> 4) & 3; /* S3 extension */
792 v
= (s
->cr
[0x43] >> 2) & 1; /* S3 extension */
793 line_offset
= s
->cr
[0x13] | (v
<< 8);
796 /* starting address */
797 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
798 start_addr
|= (s
->cr
[0x69] & 0x1f) << 16; /* S3 extension */
801 line_compare
= s
->cr
[0x18] |
802 ((s
->cr
[0x07] & 0x10) << 4) |
803 ((s
->cr
[0x09] & 0x40) << 3);
805 if (line_offset
!= s
->line_offset
||
806 start_addr
!= s
->start_addr
||
807 line_compare
!= s
->line_compare
) {
808 s
->line_offset
= line_offset
;
809 s
->start_addr
= start_addr
;
810 s
->line_compare
= line_compare
;
816 static inline int get_depth_index(int depth
)
831 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[4] = {
838 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[4] = {
845 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[4] = {
852 static const uint8_t cursor_glyph
[32 * 4] = {
853 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
854 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
855 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
856 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
857 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
858 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
859 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
860 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
861 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
862 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
863 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
864 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
865 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
866 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
867 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
868 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
879 static void vga_draw_text(VGAState
*s
, int full_update
)
881 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
882 int cx_min
, cx_max
, linesize
, x_incr
;
883 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
884 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
885 const uint8_t *font_ptr
, *font_base
[2];
886 int dup9
, line_offset
, depth_index
;
888 uint32_t *ch_attr_ptr
;
889 vga_draw_glyph8_func
*vga_draw_glyph8
;
890 vga_draw_glyph9_func
*vga_draw_glyph9
;
892 full_update
|= update_palette16(s
);
893 palette
= s
->last_palette
;
895 /* compute font data address (in plane 2) */
897 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
898 if (offset
!= s
->font_offsets
[0]) {
899 s
->font_offsets
[0] = offset
;
902 font_base
[0] = s
->vram_ptr
+ offset
;
904 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
905 font_base
[1] = s
->vram_ptr
+ offset
;
906 if (offset
!= s
->font_offsets
[1]) {
907 s
->font_offsets
[1] = offset
;
911 full_update
|= update_basic_params(s
);
913 line_offset
= s
->line_offset
;
914 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
916 /* total width & height */
917 cheight
= (s
->cr
[9] & 0x1f) + 1;
922 cw
= 16; /* NOTE: no 18 pixel wide */
923 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
924 width
= (s
->cr
[0x01] + 1);
925 if (s
->cr
[0x06] == 100) {
926 /* ugly hack for CGA 160x100x16 - explain me the logic */
929 height
= s
->cr
[0x12] |
930 ((s
->cr
[0x07] & 0x02) << 7) |
931 ((s
->cr
[0x07] & 0x40) << 3);
932 height
= (height
+ 1) / cheight
;
934 if (width
!= s
->last_width
|| height
!= s
->last_height
||
935 cw
!= s
->last_cw
|| cw
!= s
->last_cw
) {
936 dpy_resize(s
->ds
, width
* cw
, height
* cheight
);
937 s
->last_width
= width
;
938 s
->last_height
= height
;
939 s
->last_ch
= cheight
;
943 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
944 if (cursor_offset
!= s
->cursor_offset
||
945 s
->cr
[0xa] != s
->cursor_start
||
946 s
->cr
[0xb] != s
->cursor_end
) {
947 /* if the cursor position changed, we update the old and new
949 if (s
->cursor_offset
< CH_ATTR_SIZE
)
950 s
->last_ch_attr
[s
->cursor_offset
] = -1;
951 if (cursor_offset
< CH_ATTR_SIZE
)
952 s
->last_ch_attr
[cursor_offset
] = -1;
953 s
->cursor_offset
= cursor_offset
;
954 s
->cursor_start
= s
->cr
[0xa];
955 s
->cursor_end
= s
->cr
[0xb];
957 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
959 depth_index
= get_depth_index(s
->ds
->depth
);
961 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
963 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
964 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
967 linesize
= s
->ds
->linesize
;
968 ch_attr_ptr
= s
->last_ch_attr
;
969 for(cy
= 0; cy
< height
; cy
++) {
974 for(cx
= 0; cx
< width
; cx
++) {
975 ch_attr
= *(uint16_t *)src
;
976 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
981 *ch_attr_ptr
= ch_attr
;
982 #ifdef WORDS_BIGENDIAN
984 cattr
= ch_attr
& 0xff;
987 cattr
= ch_attr
>> 8;
989 font_ptr
= font_base
[(cattr
>> 3) & 1];
990 font_ptr
+= 32 * 4 * ch
;
991 bgcol
= palette
[cattr
>> 4];
992 fgcol
= palette
[cattr
& 0x0f];
994 vga_draw_glyph8(d1
, linesize
,
995 font_ptr
, cheight
, fgcol
, bgcol
);
998 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1000 vga_draw_glyph9(d1
, linesize
,
1001 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1003 if (src
== cursor_ptr
&&
1004 !(s
->cr
[0x0a] & 0x20)) {
1005 int line_start
, line_last
, h
;
1006 /* draw the cursor */
1007 line_start
= s
->cr
[0x0a] & 0x1f;
1008 line_last
= s
->cr
[0x0b] & 0x1f;
1009 /* XXX: check that */
1010 if (line_last
> cheight
- 1)
1011 line_last
= cheight
- 1;
1012 if (line_last
>= line_start
&& line_start
< cheight
) {
1013 h
= line_last
- line_start
+ 1;
1014 d
= d1
+ linesize
* line_start
;
1016 vga_draw_glyph8(d
, linesize
,
1017 cursor_glyph
, h
, fgcol
, bgcol
);
1019 vga_draw_glyph9(d
, linesize
,
1020 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1030 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1031 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1033 dest
+= linesize
* cheight
;
1051 static vga_draw_line_func
*vga_draw_line_table
[4 * VGA_DRAW_LINE_NB
] = {
1058 vga_draw_line2d2_16
,
1059 vga_draw_line2d2_16
,
1060 vga_draw_line2d2_32
,
1068 vga_draw_line4d2_16
,
1069 vga_draw_line4d2_16
,
1070 vga_draw_line4d2_32
,
1073 vga_draw_line8d2_16
,
1074 vga_draw_line8d2_16
,
1075 vga_draw_line8d2_32
,
1104 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1106 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1107 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1108 int disp_width
, multi_scan
, multi_run
;
1110 uint32_t v
, addr1
, addr
;
1111 vga_draw_line_func
*vga_draw_line
;
1113 full_update
|= update_basic_params(s
);
1115 width
= (s
->cr
[0x01] + 1) * 8;
1116 height
= s
->cr
[0x12] |
1117 ((s
->cr
[0x07] & 0x02) << 7) |
1118 ((s
->cr
[0x07] & 0x40) << 3);
1119 height
= (height
+ 1);
1122 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1123 double_scan
= (s
->cr
[0x09] & 0x80);
1124 if (shift_control
> 1) {
1125 multi_scan
= (s
->cr
[0x09] & 0x1f);
1129 multi_run
= multi_scan
;
1130 if (shift_control
!= s
->shift_control
||
1131 double_scan
!= s
->double_scan
) {
1133 s
->shift_control
= shift_control
;
1134 s
->double_scan
= double_scan
;
1137 if (shift_control
== 0) {
1138 full_update
|= update_palette16(s
);
1139 if (s
->sr
[0x01] & 8) {
1140 v
= VGA_DRAW_LINE4D2
;
1145 } else if (shift_control
== 1) {
1146 full_update
|= update_palette16(s
);
1147 if (s
->sr
[0x01] & 8) {
1148 v
= VGA_DRAW_LINE2D2
;
1154 full_update
|= update_palette256(s
);
1155 v
= VGA_DRAW_LINE8D2
;
1157 vga_draw_line
= vga_draw_line_table
[v
* 4 + get_depth_index(s
->ds
->depth
)];
1159 if (disp_width
!= s
->last_width
||
1160 height
!= s
->last_height
) {
1161 dpy_resize(s
->ds
, disp_width
, height
);
1162 s
->last_width
= disp_width
;
1163 s
->last_height
= height
;
1167 line_offset
= s
->line_offset
;
1169 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1170 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1172 addr1
= (s
->start_addr
* 4);
1175 page_min
= 0x7fffffff;
1178 linesize
= s
->ds
->linesize
;
1180 for(y
= 0; y
< height
; y
++) {
1182 if (!(s
->cr
[0x17] & 1)) {
1184 /* CGA compatibility handling */
1185 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1186 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1188 if (!(s
->cr
[0x17] & 2)) {
1189 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1192 page1
= (addr
+ bwidth
- 1) >> 12;
1193 update
= full_update
| s
->vram_updated
[page0
] | s
->vram_updated
[page1
];
1194 if ((page1
- page0
) > 1) {
1195 /* if wide line, can use another page */
1196 update
|= s
->vram_updated
[page0
+ 1];
1201 if (page0
< page_min
)
1203 if (page1
> page_max
)
1205 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1208 /* flush to display */
1209 dpy_update(s
->ds
, 0, y_start
,
1210 disp_width
, y
- y_start
);
1215 if (!double_scan
|| (y
& 1) != 0) {
1216 if (y1
== s
->line_compare
) {
1219 mask
= (s
->cr
[0x17] & 3) ^ 3;
1220 if ((y1
& mask
) == mask
)
1221 addr1
+= line_offset
;
1225 multi_run
= multi_scan
;
1233 /* flush to display */
1234 dpy_update(s
->ds
, 0, y_start
,
1235 disp_width
, y
- y_start
);
1237 /* reset modified pages */
1238 if (page_max
!= -1) {
1239 memset(s
->vram_updated
+ page_min
, 0, page_max
- page_min
+ 1);
1243 /* draw text terminal (very limited, just for simple boot debug
1245 static int last_cursor_pos
;
1247 void vga_draw_dumb(VGAState
*s
)
1249 int c
, i
, cursor_pos
, eol
;
1251 cursor_pos
= s
->cr
[0x0f] | (s
->cr
[0x0e] << 8);
1253 for(i
= last_cursor_pos
; i
< cursor_pos
; i
++) {
1254 /* XXX: should use vga RAM */
1255 c
= phys_ram_base
[0xb8000 + (i
) * 2];
1266 last_cursor_pos
= cursor_pos
;
1269 void vga_update_display(void)
1271 VGAState
*s
= &vga_state
;
1272 int full_update
, graphic_mode
;
1274 if (s
->ds
->depth
== 0) {
1278 graphic_mode
= s
->gr
[6] & 1;
1279 if (graphic_mode
!= s
->graphic_mode
) {
1280 s
->graphic_mode
= graphic_mode
;
1284 vga_draw_graphic(s
, full_update
);
1286 vga_draw_text(s
, full_update
);
1290 void vga_reset(VGAState
*s
)
1292 memset(s
, 0, sizeof(VGAState
));
1293 /* chip ID for 8c968 */
1296 s
->cr
[0x2f] = 0x01; /* XXX: check revision code */
1298 s
->graphic_mode
= -1; /* force full update */
1301 CPUReadMemoryFunc
*vga_mem_read
[3] = {
1307 CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1313 int vga_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
1314 unsigned long vga_ram_offset
, int vga_ram_size
)
1316 VGAState
*s
= &vga_state
;
1319 for(i
= 0;i
< 256; i
++) {
1321 for(j
= 0; j
< 8; j
++) {
1322 v
|= ((i
>> j
) & 1) << (j
* 4);
1327 for(j
= 0; j
< 4; j
++) {
1328 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1332 for(i
= 0; i
< 16; i
++) {
1334 for(j
= 0; j
< 4; j
++) {
1337 v
|= b
<< (2 * j
+ 1);
1346 s
->rgb_to_pixel
= rgb_to_pixel8_dup
;
1349 s
->rgb_to_pixel
= rgb_to_pixel15_dup
;
1353 s
->rgb_to_pixel
= rgb_to_pixel16_dup
;
1356 s
->rgb_to_pixel
= rgb_to_pixel32_dup
;
1360 s
->vram_ptr
= vga_ram_base
;
1361 s
->vram_offset
= vga_ram_offset
;
1362 s
->vram_size
= vga_ram_size
;
1365 register_ioport_write(0x3c0, 16, vga_ioport_write
, 1);
1367 register_ioport_write(0x3b4, 2, vga_ioport_write
, 1);
1368 register_ioport_write(0x3d4, 2, vga_ioport_write
, 1);
1369 register_ioport_write(0x3ba, 1, vga_ioport_write
, 1);
1370 register_ioport_write(0x3da, 1, vga_ioport_write
, 1);
1372 register_ioport_read(0x3c0, 16, vga_ioport_read
, 1);
1374 register_ioport_read(0x3b4, 2, vga_ioport_read
, 1);
1375 register_ioport_read(0x3d4, 2, vga_ioport_read
, 1);
1376 register_ioport_read(0x3ba, 1, vga_ioport_read
, 1);
1377 register_ioport_read(0x3da, 1, vga_ioport_read
, 1);
1379 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
);
1380 cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory
);