3 * Based on qemu/hw/vga.c
5 * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
8 * GiWoong Kim <giwoong.kim@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 #include "maru_common.h"
40 #include "pixel_ops.h"
41 #include "qemu-timer.h"
45 #include "maru_vga_int.h"
46 #include "maru_brightness.h"
47 #include "maru_overlay.h"
48 #include "maru_display.h"
49 #include "emul_state.h"
55 #include <sys/types.h>
58 #include "maru_err_table.h"
59 #include "emul_state.h"
63 void *shared_memory = (void*) 0;
68 MULTI_DEBUG_CHANNEL(qemu, maru_vga);
70 extern pthread_mutex_t mutex_screenshot;
71 extern pthread_cond_t cond_screenshot;
74 //#define DEBUG_VGA_MEM
75 //#define DEBUG_VGA_REG
77 //#define DEBUG_BOCHS_VBE
79 /* 16 state changes per vertical frame @60 Hz */
80 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
82 #define cbswap_32(__x) \
84 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
85 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
86 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
87 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
89 #ifdef HOST_WORDS_BIGENDIAN
90 #define PAT(x) cbswap_32(x)
95 #ifdef HOST_WORDS_BIGENDIAN
101 #ifdef HOST_WORDS_BIGENDIAN
102 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
104 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
109 static const uint32_t mask16[16] = {
130 #ifdef HOST_WORDS_BIGENDIAN
133 #define PAT(x) cbswap_32(x)
136 static const uint32_t dmask16[16] = {
155 static const uint32_t dmask4[4] = {
162 static uint32_t expand4[256];
163 static uint16_t expand2[256];
164 static uint8_t expand4to8[16];
166 static void vga_screen_dump(void *opaque, const char *filename, bool cswitch);
168 static void vga_update_memory_access(VGACommonState *s)
170 MemoryRegion *region, *old_region = s->chain4_alias;
171 target_phys_addr_t base, offset, size;
173 s->chain4_alias = NULL;
175 if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
176 VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
178 switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
186 offset = s->bank_offset;
198 base += isa_mem_base;
199 region = g_malloc(sizeof(*region));
200 memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
201 memory_region_add_subregion_overlap(s->legacy_address_space, base,
203 s->chain4_alias = region;
206 memory_region_del_subregion(s->legacy_address_space, old_region);
207 memory_region_destroy(old_region);
209 s->plane_updated = 0xf;
213 static void vga_dumb_update_retrace_info(VGACommonState *s)
218 static void vga_precise_update_retrace_info(VGACommonState *s)
221 int hretr_start_char;
222 int hretr_skew_chars;
226 int vretr_start_line;
235 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
236 int64_t chars_per_sec;
237 struct vga_precise_retrace *r = &s->retrace_info.precise;
239 htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
240 hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
241 hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
242 hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
244 vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
245 (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
246 ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
247 vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
248 ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
249 ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
250 vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
252 clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
253 clock_sel = (s->msr >> 2) & 3;
254 dots = (s->msr & 1) ? 8 : 9;
256 chars_per_sec = clk_hz[clock_sel] / dots;
258 htotal_chars <<= clocking_mode;
260 r->total_chars = vtotal_lines * htotal_chars;
262 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
264 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
267 r->vstart = vretr_start_line;
268 r->vend = r->vstart + vretr_end_line + 1;
270 r->hstart = hretr_start_char + hretr_skew_chars;
271 r->hend = r->hstart + hretr_end_char + 1;
272 r->htotal = htotal_chars;
275 div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
276 sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
286 "div2 = %d sldiv2 = %d\n"
287 "clocking_mode = %d\n"
288 "clock_sel = %d %d\n"
290 "ticks/char = %" PRId64 "\n"
292 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
310 static uint8_t vga_precise_retrace(VGACommonState *s)
312 struct vga_precise_retrace *r = &s->retrace_info.precise;
313 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
315 if (r->total_chars) {
316 int cur_line, cur_line_char, cur_char;
319 cur_tick = qemu_get_clock_ns(vm_clock);
321 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
322 cur_line = cur_char / r->htotal;
324 if (cur_line >= r->vstart && cur_line <= r->vend) {
325 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
327 cur_line_char = cur_char % r->htotal;
328 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
329 val |= ST01_DISP_ENABLE;
335 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
339 static uint8_t vga_dumb_retrace(VGACommonState *s)
341 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
344 #ifdef CONFIG_BOCHS_VBE
345 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
347 VGACommonState *s = opaque;
353 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
355 VGACommonState *s = opaque;
358 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
359 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
360 switch(s->vbe_index) {
361 /* XXX: do not hardcode ? */
362 case VBE_DISPI_INDEX_XRES:
363 val = VBE_DISPI_MAX_XRES;
365 case VBE_DISPI_INDEX_YRES:
366 val = VBE_DISPI_MAX_YRES;
368 case VBE_DISPI_INDEX_BPP:
369 val = VBE_DISPI_MAX_BPP;
372 val = s->vbe_regs[s->vbe_index];
376 val = s->vbe_regs[s->vbe_index];
378 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
379 val = s->vram_size / (64 * 1024);
383 #ifdef DEBUG_BOCHS_VBE
384 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
389 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
391 VGACommonState *s = opaque;
395 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
397 VGACommonState *s = opaque;
399 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
400 #ifdef DEBUG_BOCHS_VBE
401 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
403 switch(s->vbe_index) {
404 case VBE_DISPI_INDEX_ID:
405 if (val == VBE_DISPI_ID0 ||
406 val == VBE_DISPI_ID1 ||
407 val == VBE_DISPI_ID2 ||
408 val == VBE_DISPI_ID3 ||
409 val == VBE_DISPI_ID4) {
410 s->vbe_regs[s->vbe_index] = val;
413 case VBE_DISPI_INDEX_XRES:
414 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
415 s->vbe_regs[s->vbe_index] = val;
418 case VBE_DISPI_INDEX_YRES:
419 if (val <= VBE_DISPI_MAX_YRES) {
420 s->vbe_regs[s->vbe_index] = val;
423 case VBE_DISPI_INDEX_BPP:
426 if (val == 4 || val == 8 || val == 15 ||
427 val == 16 || val == 24 || val == 32) {
428 s->vbe_regs[s->vbe_index] = val;
431 case VBE_DISPI_INDEX_BANK:
432 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
433 val &= (s->vbe_bank_mask >> 2);
435 val &= s->vbe_bank_mask;
437 s->vbe_regs[s->vbe_index] = val;
438 s->bank_offset = (val << 16);
439 vga_update_memory_access(s);
441 case VBE_DISPI_INDEX_ENABLE:
442 if ((val & VBE_DISPI_ENABLED) &&
443 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
444 int h, shift_control;
446 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
447 s->vbe_regs[VBE_DISPI_INDEX_XRES];
448 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
449 s->vbe_regs[VBE_DISPI_INDEX_YRES];
450 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
451 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
453 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
454 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
456 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
457 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
458 s->vbe_start_addr = 0;
460 /* clear the screen (should be done in BIOS) */
461 if (!(val & VBE_DISPI_NOCLEARMEM)) {
462 memset(s->vram_ptr, 0,
463 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
466 /* we initialize the VGA graphic mode (should be done
468 /* graphic mode + memory map 1 */
469 s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
470 VGA_GR06_GRAPHICS_MODE;
471 s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
472 s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
474 s->cr[VGA_CRTC_H_DISP] =
475 (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
476 /* height (only meaningful if < 1024) */
477 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
478 s->cr[VGA_CRTC_V_DISP_END] = h;
479 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
480 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
481 /* line compare to 1023 */
482 s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
483 s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
484 s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
486 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
488 s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
491 /* set chain 4 mode */
492 s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
493 /* activate all planes */
494 s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
496 s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
497 (shift_control << 5);
498 s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
500 /* XXX: the bios should do that */
503 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
504 s->vbe_regs[s->vbe_index] = val;
505 vga_update_memory_access(s);
507 case VBE_DISPI_INDEX_VIRT_WIDTH:
509 int w, h, line_offset;
511 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
514 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
515 line_offset = w >> 1;
517 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
518 h = s->vram_size / line_offset;
519 /* XXX: support weird bochs semantics ? */
520 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
522 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
523 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
524 s->vbe_line_offset = line_offset;
527 case VBE_DISPI_INDEX_X_OFFSET:
528 case VBE_DISPI_INDEX_Y_OFFSET:
531 s->vbe_regs[s->vbe_index] = val;
532 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
533 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
534 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
535 s->vbe_start_addr += x >> 1;
537 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
538 s->vbe_start_addr >>= 2;
548 typedef void maru_vga_draw_glyph8_func(uint8_t *d, int linesize,
549 const uint8_t *font_ptr, int h,
550 uint32_t fgcol, uint32_t bgcol);
551 typedef void maru_vga_draw_glyph9_func(uint8_t *d, int linesize,
552 const uint8_t *font_ptr, int h,
553 uint32_t fgcol, uint32_t bgcol, int dup9);
554 typedef void maru_vga_draw_line_func(VGACommonState *s1, uint8_t *d,
555 const uint8_t *s, int width);
558 #include "maru_vga_template.h"
561 #include "maru_vga_template.h"
565 #include "maru_vga_template.h"
568 #include "maru_vga_template.h"
572 #include "maru_vga_template.h"
575 #include "maru_vga_template.h"
579 #include "maru_vga_template.h"
581 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
584 col = rgb_to_pixel8(r, g, b);
590 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
593 col = rgb_to_pixel15(r, g, b);
598 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
602 col = rgb_to_pixel15bgr(r, g, b);
607 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
610 col = rgb_to_pixel16(r, g, b);
615 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
619 col = rgb_to_pixel16bgr(r, g, b);
624 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
627 col = rgb_to_pixel32(r, g, b);
631 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
634 col = rgb_to_pixel32bgr(r, g, b);
638 /* return true if the palette was modified */
639 static int update_palette16(VGACommonState *s)
642 uint32_t v, col, *palette;
645 palette = s->last_palette;
646 for(i = 0; i < 16; i++) {
648 if (s->ar[VGA_ATC_MODE] & 0x80) {
649 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
651 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
654 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
655 c6_to_8(s->palette[v + 1]),
656 c6_to_8(s->palette[v + 2]));
657 if (col != palette[i]) {
665 /* return true if the palette was modified */
666 static int update_palette256(VGACommonState *s)
669 uint32_t v, col, *palette;
672 palette = s->last_palette;
674 for(i = 0; i < 256; i++) {
676 col = s->rgb_to_pixel(s->palette[v],
680 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
681 c6_to_8(s->palette[v + 1]),
682 c6_to_8(s->palette[v + 2]));
684 if (col != palette[i]) {
693 static void vga_get_offsets(VGACommonState *s,
694 uint32_t *pline_offset,
695 uint32_t *pstart_addr,
696 uint32_t *pline_compare)
698 uint32_t start_addr, line_offset, line_compare;
699 #ifdef CONFIG_BOCHS_VBE
700 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
701 line_offset = s->vbe_line_offset;
702 start_addr = s->vbe_start_addr;
703 line_compare = 65535;
707 /* compute line_offset in bytes */
708 line_offset = s->cr[VGA_CRTC_OFFSET];
711 /* starting address */
712 start_addr = s->cr[VGA_CRTC_START_LO] |
713 (s->cr[VGA_CRTC_START_HI] << 8);
716 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
717 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
718 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
720 *pline_offset = line_offset;
721 *pstart_addr = start_addr;
722 *pline_compare = line_compare;
725 /* update start_addr and line_offset. Return TRUE if modified */
726 static int update_basic_params(VGACommonState *s)
729 uint32_t start_addr, line_offset, line_compare;
733 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
735 if (line_offset != s->line_offset ||
736 start_addr != s->start_addr ||
737 line_compare != s->line_compare) {
738 s->line_offset = line_offset;
739 s->start_addr = start_addr;
740 s->line_compare = line_compare;
748 static inline int get_depth_index(DisplayState *s)
750 switch(ds_get_bits_per_pixel(s)) {
759 if (is_surface_bgr(s->surface))
766 static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph8_table[NB_DEPTHS] = {
767 maru_vga_draw_glyph8_8,
768 maru_vga_draw_glyph8_16,
769 maru_vga_draw_glyph8_16,
770 maru_vga_draw_glyph8_32,
771 maru_vga_draw_glyph8_32,
772 maru_vga_draw_glyph8_16,
773 maru_vga_draw_glyph8_16,
776 static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph16_table[NB_DEPTHS] = {
777 maru_vga_draw_glyph16_8,
778 maru_vga_draw_glyph16_16,
779 maru_vga_draw_glyph16_16,
780 maru_vga_draw_glyph16_32,
781 maru_vga_draw_glyph16_32,
782 maru_vga_draw_glyph16_16,
783 maru_vga_draw_glyph16_16,
786 static maru_vga_draw_glyph9_func * const maru_vga_draw_glyph9_table[NB_DEPTHS] = {
787 maru_vga_draw_glyph9_8,
788 maru_vga_draw_glyph9_16,
789 maru_vga_draw_glyph9_16,
790 maru_vga_draw_glyph9_32,
791 maru_vga_draw_glyph9_32,
792 maru_vga_draw_glyph9_16,
793 maru_vga_draw_glyph9_16,
796 static const uint8_t cursor_glyph[32 * 4] = {
797 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
798 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
799 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
800 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
801 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
802 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
803 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
804 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
805 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
806 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
807 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
808 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
809 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
810 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
811 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
812 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
815 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
816 int *pcwidth, int *pcheight)
818 int width, cwidth, height, cheight;
820 /* total width & height */
821 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
823 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
826 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
827 cwidth = 16; /* NOTE: no 18 pixel wide */
829 width = (s->cr[VGA_CRTC_H_DISP] + 1);
830 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
831 /* ugly hack for CGA 160x100x16 - explain me the logic */
834 height = s->cr[VGA_CRTC_V_DISP_END] |
835 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
836 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
837 height = (height + 1) / cheight;
846 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
848 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
853 rgb_to_pixel32bgr_dup,
854 rgb_to_pixel15bgr_dup,
855 rgb_to_pixel16bgr_dup,
866 static void vga_draw_text(VGACommonState *s, int full_update)
868 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
869 int cx_min, cx_max, linesize, x_incr, line, line1;
870 uint32_t offset, fgcol, bgcol, v, cursor_offset;
871 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
872 const uint8_t *font_ptr, *font_base[2];
873 int dup9, line_offset, depth_index;
875 uint32_t *ch_attr_ptr;
876 maru_vga_draw_glyph8_func *maru_vga_draw_glyph8;
877 maru_vga_draw_glyph9_func *maru_vga_draw_glyph9;
878 int64_t now = qemu_get_clock_ms(vm_clock);
880 /* compute font data address (in plane 2) */
881 v = s->sr[VGA_SEQ_CHARACTER_MAP];
882 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
883 if (offset != s->font_offsets[0]) {
884 s->font_offsets[0] = offset;
887 font_base[0] = s->vram_ptr + offset;
889 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
890 font_base[1] = s->vram_ptr + offset;
891 if (offset != s->font_offsets[1]) {
892 s->font_offsets[1] = offset;
895 if (s->plane_updated & (1 << 2) || s->chain4_alias) {
896 /* if the plane 2 was modified since the last display, it
897 indicates the font may have been modified */
898 s->plane_updated = 0;
901 full_update |= update_basic_params(s);
903 line_offset = s->line_offset;
905 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
906 if ((height * width) <= 1) {
907 /* better than nothing: exit if transient size is too small */
910 if ((height * width) > CH_ATTR_SIZE) {
911 /* better than nothing: exit if transient size is too big */
915 if (width != s->last_width || height != s->last_height ||
916 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
917 s->last_scr_width = width * cw;
918 s->last_scr_height = height * cheight;
919 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
921 s->last_width = width;
922 s->last_height = height;
923 s->last_ch = cheight;
928 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
929 full_update |= update_palette16(s);
930 palette = s->last_palette;
931 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
933 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
934 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
935 if (cursor_offset != s->cursor_offset ||
936 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
937 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
938 /* if the cursor position changed, we update the old and new
940 if (s->cursor_offset < CH_ATTR_SIZE)
941 s->last_ch_attr[s->cursor_offset] = -1;
942 if (cursor_offset < CH_ATTR_SIZE)
943 s->last_ch_attr[cursor_offset] = -1;
944 s->cursor_offset = cursor_offset;
945 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
946 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
948 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
949 if (now >= s->cursor_blink_time) {
950 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
951 s->cursor_visible_phase = !s->cursor_visible_phase;
954 depth_index = get_depth_index(s->ds);
956 maru_vga_draw_glyph8 = maru_vga_draw_glyph16_table[depth_index];
958 maru_vga_draw_glyph8 = maru_vga_draw_glyph8_table[depth_index];
959 maru_vga_draw_glyph9 = maru_vga_draw_glyph9_table[depth_index];
961 dest = ds_get_data(s->ds);
962 linesize = ds_get_linesize(s->ds);
963 ch_attr_ptr = s->last_ch_attr;
965 offset = s->start_addr * 4;
966 for(cy = 0; cy < height; cy++) {
968 src = s->vram_ptr + offset;
971 for(cx = 0; cx < width; cx++) {
972 ch_attr = *(uint16_t *)src;
973 if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
978 *ch_attr_ptr = ch_attr;
979 #ifdef HOST_WORDS_BIGENDIAN
981 cattr = ch_attr & 0xff;
984 cattr = ch_attr >> 8;
986 font_ptr = font_base[(cattr >> 3) & 1];
987 font_ptr += 32 * 4 * ch;
988 bgcol = palette[cattr >> 4];
989 fgcol = palette[cattr & 0x0f];
991 maru_vga_draw_glyph8(d1, linesize,
992 font_ptr, cheight, fgcol, bgcol);
995 if (ch >= 0xb0 && ch <= 0xdf &&
996 (s->ar[VGA_ATC_MODE] & 0x04)) {
999 maru_vga_draw_glyph9(d1, linesize,
1000 font_ptr, cheight, fgcol, bgcol, dup9);
1002 if (src == cursor_ptr &&
1003 !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1004 s->cursor_visible_phase) {
1005 int line_start, line_last, h;
1006 /* draw the cursor */
1007 line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1008 line_last = s->cr[VGA_CRTC_CURSOR_END] & 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 maru_vga_draw_glyph8(d, linesize,
1017 cursor_glyph, h, fgcol, bgcol);
1019 maru_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;
1034 line1 = line + cheight;
1035 offset += line_offset;
1036 if (line < s->line_compare && line1 >= s->line_compare) {
1044 maru_vga_draw_line2,
1045 maru_vga_draw_line2D2,
1046 maru_vga_draw_line4,
1047 maru_vga_draw_line4D2,
1048 maru_vga_draw_line8D2,
1049 maru_vga_draw_line8,
1050 maru_vga_draw_line15,
1051 maru_vga_draw_line16,
1052 maru_vga_draw_line24,
1053 maru_vga_draw_line32,
1054 maru_vga_draw_line_NB,
1057 static maru_vga_draw_line_func * const maru_vga_draw_line_table[NB_DEPTHS * maru_vga_draw_line_NB] = {
1058 maru_vga_draw_line2_8,
1059 maru_vga_draw_line2_16,
1060 maru_vga_draw_line2_16,
1061 maru_vga_draw_line2_32,
1062 maru_vga_draw_line2_32,
1063 maru_vga_draw_line2_16,
1064 maru_vga_draw_line2_16,
1066 maru_vga_draw_line2d2_8,
1067 maru_vga_draw_line2d2_16,
1068 maru_vga_draw_line2d2_16,
1069 maru_vga_draw_line2d2_32,
1070 maru_vga_draw_line2d2_32,
1071 maru_vga_draw_line2d2_16,
1072 maru_vga_draw_line2d2_16,
1074 maru_vga_draw_line4_8,
1075 maru_vga_draw_line4_16,
1076 maru_vga_draw_line4_16,
1077 maru_vga_draw_line4_32,
1078 maru_vga_draw_line4_32,
1079 maru_vga_draw_line4_16,
1080 maru_vga_draw_line4_16,
1082 maru_vga_draw_line4d2_8,
1083 maru_vga_draw_line4d2_16,
1084 maru_vga_draw_line4d2_16,
1085 maru_vga_draw_line4d2_32,
1086 maru_vga_draw_line4d2_32,
1087 maru_vga_draw_line4d2_16,
1088 maru_vga_draw_line4d2_16,
1090 maru_vga_draw_line8d2_8,
1091 maru_vga_draw_line8d2_16,
1092 maru_vga_draw_line8d2_16,
1093 maru_vga_draw_line8d2_32,
1094 maru_vga_draw_line8d2_32,
1095 maru_vga_draw_line8d2_16,
1096 maru_vga_draw_line8d2_16,
1098 maru_vga_draw_line8_8,
1099 maru_vga_draw_line8_16,
1100 maru_vga_draw_line8_16,
1101 maru_vga_draw_line8_32,
1102 maru_vga_draw_line8_32,
1103 maru_vga_draw_line8_16,
1104 maru_vga_draw_line8_16,
1106 maru_vga_draw_line15_8,
1107 maru_vga_draw_line15_15,
1108 maru_vga_draw_line15_16,
1109 maru_vga_draw_line15_32,
1110 maru_vga_draw_line15_32bgr,
1111 maru_vga_draw_line15_15bgr,
1112 maru_vga_draw_line15_16bgr,
1114 maru_vga_draw_line16_8,
1115 maru_vga_draw_line16_15,
1116 maru_vga_draw_line16_16,
1117 maru_vga_draw_line16_32,
1118 maru_vga_draw_line16_32bgr,
1119 maru_vga_draw_line16_15bgr,
1120 maru_vga_draw_line16_16bgr,
1122 maru_vga_draw_line24_8,
1123 maru_vga_draw_line24_15,
1124 maru_vga_draw_line24_16,
1125 maru_vga_draw_line24_32,
1126 maru_vga_draw_line24_32bgr,
1127 maru_vga_draw_line24_15bgr,
1128 maru_vga_draw_line24_16bgr,
1130 maru_vga_draw_line32_8,
1131 maru_vga_draw_line32_15,
1132 maru_vga_draw_line32_16,
1133 maru_vga_draw_line32_32,
1134 maru_vga_draw_line32_32bgr,
1135 maru_vga_draw_line32_15bgr,
1136 maru_vga_draw_line32_16bgr,
1139 static int vga_get_bpp(VGACommonState *s)
1142 #ifdef CONFIG_BOCHS_VBE
1143 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1144 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1153 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1157 #ifdef CONFIG_BOCHS_VBE
1158 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1159 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1160 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1164 width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1165 height = s->cr[VGA_CRTC_V_DISP_END] |
1166 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1167 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1168 height = (height + 1);
1174 static void vga_sync_dirty_bitmap(VGACommonState *s)
1176 memory_region_sync_dirty_bitmap(&s->vram);
1182 static void vga_draw_graphic(VGACommonState *s, int full_update)
1184 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1185 int width, height, shift_control, line_offset, bwidth, bits;
1186 ram_addr_t page0, page1, page_min, page_max;
1187 int disp_width, multi_scan, multi_run;
1189 uint32_t v, addr1, addr;
1190 maru_vga_draw_line_func *maru_vga_draw_line;
1192 full_update |= update_basic_params(s);
1195 vga_sync_dirty_bitmap(s);
1197 s->get_resolution(s, &width, &height);
1201 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1202 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
1203 if (shift_control != 1) {
1204 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1207 /* in CGA modes, multi_scan is ignored */
1208 /* XXX: is it correct ? */
1209 multi_scan = double_scan;
1211 multi_run = multi_scan;
1212 if (shift_control != s->shift_control ||
1213 double_scan != s->double_scan) {
1215 s->shift_control = shift_control;
1216 s->double_scan = double_scan;
1219 if (shift_control == 0) {
1220 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1223 } else if (shift_control == 1) {
1224 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1229 depth = s->get_bpp(s);
1230 if (s->line_offset != s->last_line_offset ||
1231 disp_width != s->last_width ||
1232 height != s->last_height ||
1233 s->last_depth != depth) {
1234 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1235 if (depth == 16 || depth == 32) {
1239 qemu_free_displaysurface(s->ds);
1241 #ifdef MARU_VGA // create new sufrace by malloc in MARU VGA
1243 /* s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1244 disp_width * 4, (uint8_t*)shared_memory); */
1245 s->ds->surface = qemu_create_displaysurface(s->ds, disp_width, height);
1249 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1251 s->vram_ptr + (s->start_addr * 4));
1254 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1255 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1259 qemu_console_resize(s->ds, disp_width, height);
1261 s->last_scr_width = disp_width;
1262 s->last_scr_height = height;
1263 s->last_width = disp_width;
1264 s->last_height = height;
1265 s->last_line_offset = s->line_offset;
1266 s->last_depth = depth;
1268 } else if (is_buffer_shared(s->ds->surface) &&
1269 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1270 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1275 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1277 if (shift_control == 0) {
1278 full_update |= update_palette16(s);
1279 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1280 v = maru_vga_draw_line4D2;
1282 v = maru_vga_draw_line4;
1285 } else if (shift_control == 1) {
1286 full_update |= update_palette16(s);
1287 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1288 v = maru_vga_draw_line2D2;
1290 v = maru_vga_draw_line2;
1294 switch(s->get_bpp(s)) {
1297 full_update |= update_palette256(s);
1298 v = maru_vga_draw_line8D2;
1302 full_update |= update_palette256(s);
1303 v = maru_vga_draw_line8;
1307 v = maru_vga_draw_line15;
1311 v = maru_vga_draw_line16;
1315 v = maru_vga_draw_line24;
1319 v = maru_vga_draw_line32;
1324 maru_vga_draw_line = maru_vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1326 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) {
1327 s->cursor_invalidate(s);
1330 line_offset = s->line_offset;
1332 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",
1333 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1334 s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
1336 addr1 = (s->start_addr * 4);
1337 bwidth = (width * bits + 7) / 8;
1341 d = ds_get_data(s->ds);
1342 linesize = ds_get_linesize(s->ds);
1344 for(y = 0; y < height; y++) {
1346 if (!(s->cr[0x17] & 1)) {
1348 /* CGA compatibility handling */
1349 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1350 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1352 if (!(s->cr[0x17] & 2)) {
1353 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1355 update = full_update;
1357 page1 = addr + bwidth - 1;
1358 update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
1360 /* explicit invalidation for the hardware cursor */
1361 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1363 #ifdef MARU_VGA // needs full update
1370 if (page0 < page_min)
1372 if (page1 > page_max)
1375 if (!(is_buffer_shared(s->ds->surface))) {
1376 maru_vga_draw_line(s, d, s->vram_ptr + addr, width);
1377 if (s->cursor_draw_line)
1378 s->cursor_draw_line(s, d, y);
1387 uint8_t alpha, c_alpha;
1389 uint16_t overlay_bottom;
1391 if ( overlay0_power ) {
1393 overlay_bottom = overlay0_top + overlay0_height;
1395 if ( overlay0_top <= y && y < overlay_bottom ) {
1397 fb_sub = s->vram_ptr + addr + overlay0_left * 4;
1398 over_sub = overlay_ptr + ( y - overlay0_top ) * overlay0_width * 4;
1399 dst = (uint32_t*) ( s->ds->surface->data + addr + overlay0_left * 4 );
1401 for ( i = 0; i < overlay0_width; i++, fb_sub += 4, over_sub += 4, dst++ ) {
1404 c_alpha = 0xff - alpha;
1406 *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 )
1407 | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 )
1408 | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 );
1415 if ( overlay1_power ) {
1417 overlay_bottom = overlay1_top + overlay1_height;
1419 if ( overlay1_top <= y && y < overlay_bottom ) {
1421 fb_sub = s->vram_ptr + addr + overlay1_left * 4;
1422 over_sub = overlay_ptr + ( y - overlay1_top ) * overlay1_width * 4 + 0x00400000;
1423 dst = (uint32_t*) ( s->ds->surface->data + addr + overlay1_left * 4 );
1425 for ( i = 0; i < overlay1_width; i++, fb_sub += 4, over_sub += 4, dst++ ) {
1428 c_alpha = 0xff - alpha;
1430 *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 )
1431 | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 )
1432 | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 );
1439 if ( brightness_off ) {
1441 dst_sub = s->ds->surface->data + addr;
1442 dst = (uint32_t*) ( s->ds->surface->data + addr );
1444 for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) {
1445 *dst = 0xFF000000; // black
1450 if ( brightness_level < BRIGHTNESS_MAX ) {
1452 alpha = brightness_tbl[brightness_level];
1454 dst_sub = s->ds->surface->data + addr;
1455 dst = (uint32_t*) ( s->ds->surface->data + addr );
1457 for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) {
1458 *dst = ( ( alpha * dst_sub[0] ) >> 8 )
1459 | ( ( alpha * dst_sub[1] ) & 0xFF00 )
1460 | ( ( ( alpha * dst_sub[2] ) & 0xFF00 ) << 8 );
1466 #endif /* MARU_VGA */
1470 /* flush to display */
1471 dpy_update(s->ds, 0, y_start,
1472 disp_width, y - y_start);
1477 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
1478 if ((y1 & mask) == mask)
1479 addr1 += line_offset;
1481 multi_run = multi_scan;
1485 /* line compare acts on the displayed lines */
1486 if (y == s->line_compare)
1491 /* for screenshot */
1492 pthread_mutex_lock(&mutex_screenshot);
1493 MaruScreenshot* maru_screenshot = get_maru_screenshot();
1494 if (maru_screenshot) {
1495 maru_screenshot->isReady = 1;
1496 if (maru_screenshot->request_screenshot == 1) {
1497 memcpy(maru_screenshot->pixel_data, s->ds->surface->data,
1498 s->ds->surface->linesize * s->ds->surface->height);
1499 maru_screenshot->request_screenshot = 0;
1500 pthread_cond_signal(&cond_screenshot);
1503 pthread_mutex_unlock(&mutex_screenshot);
1505 #ifdef CONFIG_USE_SHM
1506 memcpy(shared_memory, s->ds->surface->data,
1507 s->ds->surface->linesize * s->ds->surface->height);
1511 /* flush to display */
1512 dpy_update(s->ds, 0, y_start,
1513 disp_width, y - y_start);
1516 /* reset modified pages */
1517 if (page_max >= page_min) {
1518 memory_region_reset_dirty(&s->vram,
1520 page_max - page_min,
1523 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1526 static void vga_draw_blank(VGACommonState *s, int full_update)
1533 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1537 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1538 if (ds_get_bits_per_pixel(s->ds) == 8)
1539 val = s->rgb_to_pixel(0, 0, 0);
1542 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1543 d = ds_get_data(s->ds);
1544 for(i = 0; i < s->last_scr_height; i++) {
1546 d += ds_get_linesize(s->ds);
1548 dpy_update(s->ds, 0, 0,
1549 s->last_scr_width, s->last_scr_height);
1552 #define GMODE_TEXT 0
1553 #define GMODE_GRAPH 1
1554 #define GMODE_BLANK 2
1556 static void vga_update_display(void *opaque)
1558 VGACommonState *s = opaque;
1559 int full_update, graphic_mode;
1561 qemu_flush_coalesced_mmio_buffer();
1563 if (ds_get_bits_per_pixel(s->ds) == 0) {
1567 if (!(s->ar_index & 0x20)) {
1568 graphic_mode = GMODE_BLANK;
1570 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1572 if (graphic_mode != s->graphic_mode) {
1573 s->graphic_mode = graphic_mode;
1574 s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
1577 switch(graphic_mode) {
1579 vga_draw_text(s, full_update);
1582 vga_draw_graphic(s, full_update);
1586 vga_draw_blank(s, full_update);
1592 /* force a full display refresh */
1593 static void vga_invalidate_display(void *opaque)
1595 VGACommonState *s = opaque;
1598 s->last_height = -1;
1601 #define TEXTMODE_X(x) ((x) % width)
1602 #define TEXTMODE_Y(x) ((x) / width)
1603 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1604 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1605 /* relay text rendering to the display driver
1606 * instead of doing a full vga_update_display() */
1607 static void vga_update_text(void *opaque, console_ch_t *chardata)
1609 VGACommonState *s = opaque;
1610 int graphic_mode, i, cursor_offset, cursor_visible;
1611 int cw, cheight, width, height, size, c_min, c_max;
1613 console_ch_t *dst, val;
1614 char msg_buffer[80];
1615 int full_update = 0;
1617 qemu_flush_coalesced_mmio_buffer();
1619 if (!(s->ar_index & 0x20)) {
1620 graphic_mode = GMODE_BLANK;
1622 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1624 if (graphic_mode != s->graphic_mode) {
1625 s->graphic_mode = graphic_mode;
1628 if (s->last_width == -1) {
1633 switch (graphic_mode) {
1635 /* TODO: update palette */
1636 full_update |= update_basic_params(s);
1638 /* total width & height */
1639 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1641 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1644 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1645 cw = 16; /* NOTE: no 18 pixel wide */
1647 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1648 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1649 /* ugly hack for CGA 160x100x16 - explain me the logic */
1652 height = s->cr[VGA_CRTC_V_DISP_END] |
1653 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1654 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1655 height = (height + 1) / cheight;
1658 size = (height * width);
1659 if (size > CH_ATTR_SIZE) {
1663 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1668 if (width != s->last_width || height != s->last_height ||
1669 cw != s->last_cw || cheight != s->last_ch) {
1670 s->last_scr_width = width * cw;
1671 s->last_scr_height = height * cheight;
1672 s->ds->surface->width = width;
1673 s->ds->surface->height = height;
1675 s->last_width = width;
1676 s->last_height = height;
1677 s->last_ch = cheight;
1682 /* Update "hardware" cursor */
1683 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1684 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1685 if (cursor_offset != s->cursor_offset ||
1686 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1687 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1688 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
1689 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1691 TEXTMODE_X(cursor_offset),
1692 TEXTMODE_Y(cursor_offset));
1694 dpy_cursor(s->ds, -1, -1);
1695 s->cursor_offset = cursor_offset;
1696 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1697 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1700 src = (uint32_t *) s->vram_ptr + s->start_addr;
1704 for (i = 0; i < size; src ++, dst ++, i ++) {
1705 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1708 dpy_update(s->ds, 0, 0, width, height);
1712 for (i = 0; i < size; src ++, dst ++, i ++) {
1713 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1721 for (; i < size; src ++, dst ++, i ++) {
1722 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1729 if (c_min <= c_max) {
1730 i = TEXTMODE_Y(c_min);
1731 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1740 s->get_resolution(s, &width, &height);
1741 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1749 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
1753 /* Display a message */
1755 s->last_height = height = 3;
1756 dpy_cursor(s->ds, -1, -1);
1757 s->ds->surface->width = s->last_width;
1758 s->ds->surface->height = height;
1761 for (dst = chardata, i = 0; i < s->last_width * height; i ++) {
1762 console_write_ch(dst ++, ' ');
1765 size = strlen(msg_buffer);
1766 width = (s->last_width - size) / 2;
1767 dst = chardata + s->last_width + width;
1768 for (i = 0; i < size; i ++) {
1769 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1772 dpy_update(s->ds, 0, 0, s->last_width, height);
1777 static void vga_reset(void *opaque)
1779 VGACommonState *s = opaque;
1780 vga_common_reset(s);
1783 static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
1786 VGACommonState *s = opaque;
1788 return vga_mem_readb(s, addr);
1791 static void vga_mem_write(void *opaque, target_phys_addr_t addr,
1792 uint64_t data, unsigned size)
1794 VGACommonState *s = opaque;
1796 return vga_mem_writeb(s, addr, data);
1799 static int vga_common_post_load(void *opaque, int version_id)
1801 VGACommonState *s = opaque;
1804 s->graphic_mode = -1;
1809 void maru_vga_common_init(VGACommonState *s)
1813 for(i = 0;i < 256; i++) {
1815 for(j = 0; j < 8; j++) {
1816 v |= ((i >> j) & 1) << (j * 4);
1821 for(j = 0; j < 4; j++) {
1822 v |= ((i >> (2 * j)) & 3) << (j * 4);
1826 for(i = 0; i < 16; i++) {
1828 for(j = 0; j < 4; j++) {
1831 v |= b << (2 * j + 1);
1836 /* valid range: 1 MB -> 256 MB */
1837 s->vram_size = 1024 * 1024;
1838 while (s->vram_size < (s->vram_size_mb << 20) &&
1839 s->vram_size < (256 << 20)) {
1842 s->vram_size_mb = s->vram_size >> 20;
1844 #ifdef CONFIG_BOCHS_VBE
1845 s->is_vbe_vmstate = 1;
1847 s->is_vbe_vmstate = 0;
1849 memory_region_init_ram(&s->vram, "maru_vga.vram", s->vram_size);
1850 vmstate_register_ram_global(&s->vram);
1851 xen_register_framebuffer(&s->vram);
1852 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
1853 s->get_bpp = vga_get_bpp;
1854 s->get_offsets = vga_get_offsets;
1855 s->get_resolution = vga_get_resolution;
1856 s->update = vga_update_display;
1857 s->invalidate = vga_invalidate_display;
1858 s->screen_dump = vga_screen_dump;
1859 s->text_update = vga_update_text;
1860 switch (vga_retrace_method) {
1861 case VGA_RETRACE_DUMB:
1862 s->retrace = vga_dumb_retrace;
1863 s->update_retrace_info = vga_dumb_update_retrace_info;
1866 case VGA_RETRACE_PRECISE:
1867 s->retrace = vga_precise_retrace;
1868 s->update_retrace_info = vga_precise_update_retrace_info;
1873 vga_dirty_log_start(s);
1875 #ifdef CONFIG_USE_SHM
1876 /* base + 1 = sdb port */
1877 /* base + 2 = shared memory key */
1878 int mykey = get_emul_vm_base_port() + 2;
1880 INFO("shared memory key: %d, vga ram_size : %d\n", mykey, s->vram_size);
1882 skin_shmid = shmget((key_t)mykey, (size_t)s->vram_size, 0666 | IPC_CREAT);
1883 if (skin_shmid == -1) {
1884 ERR("shmget failed\n");
1885 perror("maru_vga: ");
1886 maru_register_exit_msg(MARU_EXIT_UNKNOWN,
1887 (char*) "Cannot launch this VM.\n"
1888 "Shared memory is not enough.");
1892 shared_memory = shmat(skin_shmid, (void*)0, 0);
1893 if (shared_memory == (void *)-1) {
1894 ERR("shmat failed\n");
1895 perror("maru_vga: ");
1899 memset(shared_memory, 0x00, (size_t)s->vram_size);
1900 printf("Memory attached at %X\n", (int)shared_memory);
1905 #ifdef CONFIG_USE_SHM
1906 void maru_vga_common_fini(void)
1908 if (shmdt(shared_memory) == -1) {
1909 ERR("shmdt failed\n");
1910 perror("maru_vga: ");
1913 if (shmctl(skin_shmid, IPC_RMID, 0) == -1) {
1914 ERR("shmctl failed\n");
1915 perror("maru_vga: ");
1920 static const MemoryRegionPortio vga_portio_list[] = {
1921 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
1922 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
1923 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
1924 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
1925 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
1926 PORTIO_END_OF_LIST(),
1929 #ifdef CONFIG_BOCHS_VBE
1930 static const MemoryRegionPortio vbe_portio_list[] = {
1931 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
1933 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
1935 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
1937 PORTIO_END_OF_LIST(),
1939 #endif /* CONFIG_BOCHS_VBE */
1941 /********************************************************/
1942 /* vga screen dump */
1945 static int maru_ppm_save(const char *filename, struct DisplaySurface *ds)
1953 char *linebuf, *pbuf;
1955 trace_ppm_save(filename, ds);
1956 f = fopen(filename, "wb");
1959 fprintf(f, "P6\n%d %d\n%d\n",
1960 ds->width, ds->height, 255);
1961 linebuf = g_malloc(ds->width * 3);
1963 for(y = 0; y < ds->height; y++) {
1966 for(x = 0; x < ds->width; x++) {
1967 if (ds->pf.bits_per_pixel == 32)
1970 v = (uint32_t) (*(uint16_t *)d);
1971 /* Limited to 8 or fewer bits per channel: */
1972 r = ((v >> ds->pf.rshift) & ds->pf.rmax) << (8 - ds->pf.rbits);
1973 g = ((v >> ds->pf.gshift) & ds->pf.gmax) << (8 - ds->pf.gbits);
1974 b = ((v >> ds->pf.bshift) & ds->pf.bmax) << (8 - ds->pf.bbits);
1978 d += ds->pf.bytes_per_pixel;
1981 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
1990 /* save the vga display in a PPM image even if no display is
1992 static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
1994 VGACommonState *s = opaque;
1997 vga_invalidate_display(s);
2000 ppm_save(filename, s->ds->surface);