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
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
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] = {
50 const uint8_t gr_mask
[16] = {
69 #define cbswap_32(__x) \
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)
82 #ifdef HOST_WORDS_BIGENDIAN
88 #ifdef HOST_WORDS_BIGENDIAN
89 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
94 static const uint32_t mask16
[16] = {
115 #ifdef HOST_WORDS_BIGENDIAN
118 #define PAT(x) cbswap_32(x)
121 static const uint32_t dmask16
[16] = {
140 static const uint32_t dmask4
[4] = {
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
)
160 static void vga_precise_update_retrace_info(VGACommonState
*s
)
163 int hretr_start_char
;
164 int hretr_skew_chars
;
168 int vretr_start_line
;
171 int div2
, sldiv2
, dots
;
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
;
205 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
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
;
227 "div2 = %d sldiv2 = %d\n"
228 "clocking_mode = %d\n"
229 "clock_sel = %d %d\n"
231 "ticks/char = %lld\n"
233 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
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
;
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
;
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
;
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
) {
289 return (addr
>= 0x3b0 && addr
<= 0x3bf);
292 return (addr
>= 0x3d0 && addr
<= 0x3df);
296 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
298 VGACommonState
*s
= opaque
;
301 if (vga_ioport_invalid(s
, addr
)) {
306 if (s
->ar_flip_flop
== 0) {
313 index
= s
->ar_index
& 0x1f;
326 val
= s
->sr
[s
->sr_index
];
328 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
335 val
= s
->dac_write_index
;
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;
354 val
= s
->gr
[s
->gr_index
];
356 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
365 val
= s
->cr
[s
->cr_index
];
367 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
372 /* just toggle to fool polling */
373 val
= s
->st01
= s
->retrace(s
);
381 #if defined(DEBUG_VGA)
382 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
387 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
389 VGACommonState
*s
= opaque
;
392 /* check port range access depending on color/monochrome mode */
393 if (vga_ioport_invalid(s
, addr
)) {
397 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
402 if (s
->ar_flip_flop
== 0) {
406 index
= s
->ar_index
& 0x1f;
409 s
->ar
[index
] = val
& 0x3f;
412 s
->ar
[index
] = val
& ~0x10;
418 s
->ar
[index
] = val
& ~0xc0;
421 s
->ar
[index
] = val
& ~0xf0;
424 s
->ar
[index
] = val
& ~0xf0;
430 s
->ar_flip_flop
^= 1;
433 s
->msr
= val
& ~0x10;
434 s
->update_retrace_info(s
);
437 s
->sr_index
= val
& 7;
441 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
443 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
444 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
447 s
->dac_read_index
= val
;
448 s
->dac_sub_index
= 0;
452 s
->dac_write_index
= val
;
453 s
->dac_sub_index
= 0;
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
++;
465 s
->gr_index
= val
& 0x0f;
469 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
471 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
480 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
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);
489 s
->cr
[s
->cr_index
] = val
;
491 switch(s
->cr_index
) {
499 s
->update_retrace_info(s
);
510 #ifdef CONFIG_BOCHS_VBE
511 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
513 VGACommonState
*s
= opaque
;
519 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
521 VGACommonState
*s
= opaque
;
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
;
531 case VBE_DISPI_INDEX_YRES
:
532 val
= VBE_DISPI_MAX_YRES
;
534 case VBE_DISPI_INDEX_BPP
:
535 val
= VBE_DISPI_MAX_BPP
;
538 val
= s
->vbe_regs
[s
->vbe_index
];
542 val
= s
->vbe_regs
[s
->vbe_index
];
547 #ifdef DEBUG_BOCHS_VBE
548 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
553 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
555 VGACommonState
*s
= opaque
;
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
);
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
;
577 case VBE_DISPI_INDEX_XRES
:
578 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
579 s
->vbe_regs
[s
->vbe_index
] = val
;
582 case VBE_DISPI_INDEX_YRES
:
583 if (val
<= VBE_DISPI_MAX_YRES
) {
584 s
->vbe_regs
[s
->vbe_index
] = val
;
587 case VBE_DISPI_INDEX_BPP
:
590 if (val
== 4 || val
== 8 || val
== 15 ||
591 val
== 16 || val
== 24 || val
== 32) {
592 s
->vbe_regs
[s
->vbe_index
] = val
;
595 case VBE_DISPI_INDEX_BANK
:
596 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
597 val
&= (s
->vbe_bank_mask
>> 2);
599 val
&= s
->vbe_bank_mask
;
601 s
->vbe_regs
[s
->vbe_index
] = val
;
602 s
->bank_offset
= (val
<< 16);
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;
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
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;
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;
639 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
640 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
641 /* line compare to 1023 */
646 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
648 s
->sr
[0x01] &= ~8; /* no double line */
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 */
657 /* XXX: the bios should do that */
660 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
661 s
->vbe_regs
[s
->vbe_index
] = val
;
663 case VBE_DISPI_INDEX_VIRT_WIDTH
:
665 int w
, h
, line_offset
;
667 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
670 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
671 line_offset
= w
>> 1;
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
])
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
;
683 case VBE_DISPI_INDEX_X_OFFSET
:
684 case VBE_DISPI_INDEX_Y_OFFSET
:
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;
693 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
694 s
->vbe_start_addr
>>= 2;
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
;
711 /* convert to VGA memory offset */
712 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
714 switch(memory_map_mode
) {
720 addr
+= s
->bank_offset
;
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
];
743 /* standard VGA latched access */
744 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
746 if (!(s
->gr
[5] & 0x08)) {
749 ret
= GET_PLANE(s
->latch
, plane
);
752 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
761 static uint32_t vga_mem_readw(void *opaque
, target_phys_addr_t addr
)
764 #ifdef TARGET_WORDS_BIGENDIAN
765 v
= vga_mem_readb(opaque
, addr
) << 8;
766 v
|= vga_mem_readb(opaque
, addr
+ 1);
768 v
= vga_mem_readb(opaque
, addr
);
769 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
774 static uint32_t vga_mem_readl(void *opaque
, target_phys_addr_t addr
)
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);
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;
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
;
799 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
801 /* convert to VGA memory offset */
802 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
804 switch(memory_map_mode
) {
810 addr
+= s
->bank_offset
;
825 if (s
->sr
[4] & 0x08) {
826 /* chain 4 mode : simplest access */
829 if (s
->sr
[2] & mask
) {
830 s
->vram_ptr
[addr
] = val
;
832 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
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);
841 if (s
->sr
[2] & mask
) {
842 addr
= ((addr
& ~1) << 1) | plane
;
843 s
->vram_ptr
[addr
] = val
;
845 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
847 s
->plane_updated
|= mask
; /* only used to detect font change */
848 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
851 /* standard VGA latched access */
852 write_mode
= s
->gr
[5] & 3;
858 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
862 /* apply set/reset mask */
863 set_mask
= mask16
[s
->gr
[1]];
864 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
871 val
= mask16
[val
& 0x0f];
877 val
= (val
>> b
) | (val
<< (8 - b
));
879 bit_mask
= s
->gr
[8] & val
;
880 val
= mask16
[s
->gr
[0]];
884 /* apply logical operation */
885 func_select
= s
->gr
[3] >> 3;
886 switch(func_select
) {
906 bit_mask
|= bit_mask
<< 8;
907 bit_mask
|= bit_mask
<< 16;
908 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
911 /* mask data according to 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
) |
919 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
920 addr
* 4, write_mask
, val
);
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);
932 vga_mem_writeb(opaque
, addr
, val
& 0xff);
933 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
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);
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);
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
);
962 #include "vga_template.h"
965 #include "vga_template.h"
969 #include "vga_template.h"
972 #include "vga_template.h"
976 #include "vga_template.h"
979 #include "vga_template.h"
983 #include "vga_template.h"
985 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
988 col
= rgb_to_pixel8(r
, g
, b
);
994 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
997 col
= rgb_to_pixel15(r
, g
, b
);
1002 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1006 col
= rgb_to_pixel15bgr(r
, g
, b
);
1011 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1014 col
= rgb_to_pixel16(r
, g
, b
);
1019 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1023 col
= rgb_to_pixel16bgr(r
, g
, b
);
1028 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1031 col
= rgb_to_pixel32(r
, g
, b
);
1035 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1038 col
= rgb_to_pixel32bgr(r
, g
, b
);
1042 /* return true if the palette was modified */
1043 static int update_palette16(VGACommonState
*s
)
1046 uint32_t v
, col
, *palette
;
1049 palette
= s
->last_palette
;
1050 for(i
= 0; i
< 16; i
++) {
1052 if (s
->ar
[0x10] & 0x80)
1053 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1055 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
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
]) {
1068 /* return true if the palette was modified */
1069 static int update_palette256(VGACommonState
*s
)
1072 uint32_t v
, col
, *palette
;
1075 palette
= s
->last_palette
;
1077 for(i
= 0; i
< 256; i
++) {
1079 col
= s
->rgb_to_pixel(s
->palette
[v
],
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
]) {
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;
1110 /* compute line_offset in bytes */
1111 line_offset
= s
->cr
[0x13];
1114 /* starting address */
1115 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
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
)
1131 uint32_t start_addr
, line_offset
, line_compare
;
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
;
1150 static inline int get_depth_index(DisplayState
*s
)
1152 switch(ds_get_bits_per_pixel(s
)) {
1161 if (is_surface_bgr(s
->surface
))
1168 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[NB_DEPTHS
] = {
1178 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[NB_DEPTHS
] = {
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
] = {
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;
1225 if (!(s
->sr
[1] & 0x01))
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 */
1234 height
= s
->cr
[0x12] |
1235 ((s
->cr
[0x07] & 0x02) << 7) |
1236 ((s
->cr
[0x07] & 0x40) << 3);
1237 height
= (height
+ 1) / cheight
;
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
] = {
1253 rgb_to_pixel32bgr_dup
,
1254 rgb_to_pixel15bgr_dup
,
1255 rgb_to_pixel16bgr_dup
,
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
;
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) */
1281 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1282 if (offset
!= s
->font_offsets
[0]) {
1283 s
->font_offsets
[0] = offset
;
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
;
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;
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 */
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
);
1318 s
->last_width
= width
;
1319 s
->last_height
= height
;
1320 s
->last_ch
= cheight
;
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
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
);
1348 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
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
++) {
1361 for(cx
= 0; cx
< width
; cx
++) {
1362 ch_attr
= *(uint16_t *)src
;
1363 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1368 *ch_attr_ptr
= ch_attr
;
1369 #ifdef HOST_WORDS_BIGENDIAN
1371 cattr
= ch_attr
& 0xff;
1373 ch
= ch_attr
& 0xff;
1374 cattr
= ch_attr
>> 8;
1376 font_ptr
= font_base
[(cattr
>> 3) & 1];
1377 font_ptr
+= 32 * 4 * ch
;
1378 bgcol
= palette
[cattr
>> 4];
1379 fgcol
= palette
[cattr
& 0x0f];
1381 vga_draw_glyph8(d1
, linesize
,
1382 font_ptr
, cheight
, fgcol
, bgcol
);
1385 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
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
;
1403 vga_draw_glyph8(d
, linesize
,
1404 cursor_glyph
, h
, fgcol
, bgcol
);
1406 vga_draw_glyph9(d
, linesize
,
1407 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1417 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1418 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1420 dest
+= linesize
* cheight
;
1439 static vga_draw_line_func
*vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
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
,
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
,
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
,
1492 vga_draw_line15_32bgr
,
1493 vga_draw_line15_15bgr
,
1494 vga_draw_line15_16bgr
,
1500 vga_draw_line16_32bgr
,
1501 vga_draw_line16_15bgr
,
1502 vga_draw_line16_16bgr
,
1508 vga_draw_line24_32bgr
,
1509 vga_draw_line24_15bgr
,
1510 vga_draw_line24_16bgr
,
1516 vga_draw_line32_32bgr
,
1517 vga_draw_line32_15bgr
,
1518 vga_draw_line32_16bgr
,
1521 static int vga_get_bpp(VGACommonState
*s
)
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
];
1535 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
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
];
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);
1556 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1559 if (y1
>= VGA_MAX_HEIGHT
)
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
)
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);
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
;
1589 uint32_t v
, addr1
, addr
;
1590 vga_draw_line_func
*vga_draw_line
;
1592 full_update
|= update_basic_params(s
);
1595 vga_sync_dirty_bitmap(s
);
1597 s
->get_resolution(s
, &width
, &height
);
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;
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
) {
1613 s
->shift_control
= shift_control
;
1614 s
->double_scan
= double_scan
;
1617 if (shift_control
== 0) {
1618 if (s
->sr
[0x01] & 8) {
1621 } else if (shift_control
== 1) {
1622 if (s
->sr
[0x01] & 8) {
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) {
1637 qemu_free_displaysurface(s
->ds
);
1638 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
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
);
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
;
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);
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
;
1672 } else if (shift_control
== 1) {
1673 full_update
|= update_palette16(s
);
1674 if (s
->sr
[0x01] & 8) {
1675 v
= VGA_DRAW_LINE2D2
;
1681 switch(s
->get_bpp(s
)) {
1684 full_update
|= update_palette256(s
);
1685 v
= VGA_DRAW_LINE8D2
;
1689 full_update
|= update_palette256(s
);
1694 v
= VGA_DRAW_LINE15
;
1698 v
= VGA_DRAW_LINE16
;
1702 v
= VGA_DRAW_LINE24
;
1706 v
= VGA_DRAW_LINE32
;
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
;
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]);
1721 addr1
= (s
->start_addr
* 4);
1722 bwidth
= (width
* bits
+ 7) / 8;
1726 d
= ds_get_data(s
->ds
);
1727 linesize
= ds_get_linesize(s
->ds
);
1729 for(y
= 0; y
< height
; y
++) {
1731 if (!(s
->cr
[0x17] & 1)) {
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
,
1750 /* explicit invalidation for the hardware cursor */
1751 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1755 if (page0
< page_min
)
1757 if (page1
> page_max
)
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
);
1766 /* flush to display */
1767 dpy_update(s
->ds
, 0, y_start
,
1768 disp_width
, y
- y_start
);
1773 mask
= (s
->cr
[0x17] & 3) ^ 3;
1774 if ((y1
& mask
) == mask
)
1775 addr1
+= line_offset
;
1777 multi_run
= multi_scan
;
1781 /* line compare acts on the displayed lines */
1782 if (y
== s
->line_compare
)
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
,
1796 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1799 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1806 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
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);
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
++) {
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) {
1837 full_update
= s
->full_update
;
1839 if (!(s
->ar_index
& 0x20)) {
1840 graphic_mode
= GMODE_BLANK
;
1842 graphic_mode
= s
->gr
[6] & 1;
1844 if (graphic_mode
!= s
->graphic_mode
) {
1845 s
->graphic_mode
= graphic_mode
;
1848 switch(graphic_mode
) {
1850 vga_draw_text(s
, full_update
);
1853 vga_draw_graphic(s
, full_update
);
1857 vga_draw_blank(s
, full_update
);
1863 /* force a full display refresh */
1864 static void vga_invalidate_display(void *opaque
)
1866 VGACommonState
*s
= opaque
;
1871 void vga_common_reset(VGACommonState
*s
)
1877 s
->lfb_vram_mapped
= 0;
1881 memset(s
->sr
, '\0', sizeof(s
->sr
));
1883 memset(s
->gr
, '\0', sizeof(s
->gr
));
1885 memset(s
->ar
, '\0', sizeof(s
->ar
));
1886 s
->ar_flip_flop
= 0;
1888 memset(s
->cr
, '\0', sizeof(s
->cr
));
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
));
1899 memset(s
->palette
, '\0', sizeof(s
->palette
));
1901 #ifdef CONFIG_BOCHS_VBE
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;
1909 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1910 s
->graphic_mode
= -1; /* force full update */
1911 s
->shift_control
= 0;
1914 s
->line_compare
= 0;
1916 s
->plane_updated
= 0;
1921 s
->last_scr_width
= 0;
1922 s
->last_scr_height
= 0;
1923 s
->cursor_start
= 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
:
1932 case VGA_RETRACE_PRECISE
:
1933 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
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
;
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
;
1963 graphic_mode
= s
->gr
[6] & 1;
1965 if (graphic_mode
!= s
->graphic_mode
) {
1966 s
->graphic_mode
= graphic_mode
;
1969 if (s
->last_width
== -1) {
1974 switch (graphic_mode
) {
1976 /* TODO: update palette */
1977 full_update
|= update_basic_params(s
);
1979 /* total width & height */
1980 cheight
= (s
->cr
[9] & 0x1f) + 1;
1982 if (!(s
->sr
[1] & 0x01))
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 */
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
) {
2002 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
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
;
2014 s
->last_width
= width
;
2015 s
->last_height
= height
;
2016 s
->last_ch
= cheight
;
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)
2029 TEXTMODE_X(cursor_offset
),
2030 TEXTMODE_Y(cursor_offset
));
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
;
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
);
2049 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2050 console_write_ch(&val
, VMEM2CHTYPE(*src
));
2058 for (; i
< size
; src
++, dst
++, i
++) {
2059 console_write_ch(&val
, VMEM2CHTYPE(*src
));
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);
2077 s
->get_resolution(s
, &width
, &height
);
2078 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2086 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2090 /* Display a message */
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
;
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] = {
2116 CPUWriteMemoryFunc
* const vga_mem_write
[3] = {
2122 void vga_common_save(QEMUFile
*f
, void *opaque
)
2124 VGACommonState
*s
= opaque
;
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
);
2159 qemu_put_byte(f
, 0);
2163 int vga_common_load(QEMUFile
*f
, void *opaque
, int version_id
)
2165 VGACommonState
*s
= opaque
;
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
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
);
2210 s
->graphic_mode
= -1;
2214 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2218 for(i
= 0;i
< 256; i
++) {
2220 for(j
= 0; j
< 8; j
++) {
2221 v
|= ((i
>> j
) & 1) << (j
* 4);
2226 for(j
= 0; j
< 4; j
++) {
2227 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2231 for(i
= 0; i
< 16; i
++) {
2233 for(j
= 0; j
< 4; j
++) {
2236 v
|= b
<< (2 * j
+ 1);
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
;
2257 case VGA_RETRACE_PRECISE
:
2258 s
->retrace
= vga_precise_retrace
;
2259 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2265 /* used by both ISA and PCI */
2266 void vga_init(VGACommonState
*s
)
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
);
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
);
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
);
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,
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
)
2344 f
= fopen(filename
, "wb");
2347 fprintf(f
, "P6\n%d %d\n%d\n",
2348 ds
->width
, ds
->height
, 255);
2350 for(y
= 0; y
< ds
->height
; y
++) {
2352 for(x
= 0; x
< ds
->width
; x
++) {
2353 if (ds
->pf
.bits_per_pixel
== 32)
2356 v
= (uint32_t) (*(uint16_t *)d
);
2357 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) * 256 /
2359 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) * 256 /
2361 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) * 256 /
2366 d
+= ds
->pf
.bytes_per_pixel
;
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
);
2386 /* save the vga display in a PPM image even if no display is
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
);