X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Fcirrus_vga.c;h=85bf4a21ff174448ad7ee47ce561471479c6c31a;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=d354fadd25d176359d1f1004f41af2ce6205ed7c;hpb=b30d4608dae994cf57cab4824f3307de026fd373;p=qemu diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d354fad..85bf4a2 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1,9 +1,9 @@ /* * QEMU Cirrus CLGD 54xx VGA Emulator. - * + * * Copyright (c) 2004 Fabrice Bellard * Copyright (c) 2004 Makoto Suzuki (suzu) - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -31,7 +31,7 @@ /* * TODO: - * - add support for WRITEMASK (GR2F) + * - destination write mask support not complete (bits 5..7) * - optimize linear mappings * - optimize bitblt functions */ @@ -259,9 +259,6 @@ typedef struct CirrusVGAState { uint8_t *cirrus_srcptr; uint8_t *cirrus_srcptr_end; uint32_t cirrus_srccounter; - uint8_t *cirrus_dstptr; - uint8_t *cirrus_dstptr_end; - uint32_t cirrus_dstcounter; /* hwcursor display state */ int last_hw_cursor_size; int last_hw_cursor_x; @@ -269,6 +266,7 @@ typedef struct CirrusVGAState { int last_hw_cursor_y_start; int last_hw_cursor_y_end; int real_vram_size; /* XXX: suppress that */ + CPUWriteMemoryFunc **cirrus_linear_write; } CirrusVGAState; typedef struct PCICirrusVGAState { @@ -277,7 +275,7 @@ typedef struct PCICirrusVGAState { } PCICirrusVGAState; static uint8_t rop_to_index[256]; - + /*************************************** * * prototypes. @@ -285,7 +283,8 @@ static uint8_t rop_to_index[256]; ***************************************/ -static void cirrus_bitblt_reset(CirrusVGAState * s); +static void cirrus_bitblt_reset(CirrusVGAState *s); +static void cirrus_update_memory_access(CirrusVGAState *s); /*************************************** * @@ -403,7 +402,54 @@ static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = { cirrus_bitblt_rop_bkwd_notsrc_or_dst, cirrus_bitblt_rop_bkwd_notsrc_and_notdst, }; - + +#define TRANSP_ROP(name) {\ + name ## _8,\ + name ## _16,\ + } +#define TRANSP_NOP(func) {\ + func,\ + func,\ + } + +static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = { + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst), + TRANSP_NOP(cirrus_bitblt_rop_nop), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst), +}; + +static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = { + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst), + TRANSP_NOP(cirrus_bitblt_rop_nop), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst), +}; + #define ROP2(name) {\ name ## _8,\ name ## _16,\ @@ -544,7 +590,7 @@ static inline void cirrus_bitblt_fgcol(CirrusVGAState *s) s->cirrus_blt_fgcol = le16_to_cpu(color); break; case 3: - s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | + s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | (s->gr[0x13] << 16); break; default: @@ -568,7 +614,7 @@ static inline void cirrus_bitblt_bgcol(CirrusVGAState *s) s->cirrus_blt_bgcol = le16_to_cpu(color); break; case 3: - s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | + s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) | (s->gr[0x12] << 16); break; default: @@ -607,7 +653,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, dst = s->vram_ptr + s->cirrus_blt_dstaddr; (*s->cirrus_rop) (s, dst, src, - s->cirrus_blt_dstpitch, 0, + s->cirrus_blt_dstpitch, 0, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, @@ -622,7 +668,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) cirrus_fill_t rop_func; rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, + rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, @@ -641,19 +687,94 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) { return cirrus_bitblt_common_patterncopy(s, - s->vram_ptr + + s->vram_ptr + (s->cirrus_blt_srcaddr & ~7)); } -static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) +static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) { + int sx, sy; + int dx, dy; + int width, height; + int depth; + int notify = 0; + + depth = s->get_bpp((VGAState *)s) / 8; + s->get_resolution((VGAState *)s, &width, &height); + + /* extra x, y */ + sx = (src % (width * depth)) / depth; + sy = (src / (width * depth)); + dx = (dst % (width *depth)) / depth; + dy = (dst / (width * depth)); + + /* normalize width */ + w /= depth; + + /* if we're doing a backward copy, we have to adjust + our x/y to be the upper left corner (instead of the lower + right corner) */ + if (s->cirrus_blt_dstpitch < 0) { + sx -= (s->cirrus_blt_width / depth) - 1; + dx -= (s->cirrus_blt_width / depth) - 1; + sy -= s->cirrus_blt_height - 1; + dy -= s->cirrus_blt_height - 1; + } + + /* are we in the visible portion of memory? */ + if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 && + (sx + w) <= width && (sy + h) <= height && + (dx + w) <= width && (dy + h) <= height) { + notify = 1; + } + + /* make to sure only copy if it's a plain copy ROP */ + if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src && + *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src) + notify = 0; + + /* we have to flush all pending changes so that the copy + is generated at the appropriate moment in time */ + if (notify) + vga_hw_update(); + (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, s->vram_ptr + s->cirrus_blt_srcaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); + + if (notify) + s->ds->dpy_copy(s->ds, + sx, sy, dx, dy, + s->cirrus_blt_width / depth, + s->cirrus_blt_height); + + /* we don't have to notify the display that this portion has + changed since dpy_copy implies this */ + + if (!notify) + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); +} + +static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) +{ + if (s->ds->dpy_copy) { + cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, + s->cirrus_blt_srcaddr - s->start_addr, + s->cirrus_blt_width, s->cirrus_blt_height); + } else { + (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, + s->vram_ptr + s->cirrus_blt_srcaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); + } + return 1; } @@ -667,7 +788,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) { int copy_count; uint8_t *end_ptr; - + if (s->cirrus_srccounter > 0) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf); @@ -711,9 +832,7 @@ static void cirrus_bitblt_reset(CirrusVGAState * s) s->cirrus_srcptr = &s->cirrus_bltbuf[0]; s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; s->cirrus_srccounter = 0; - s->cirrus_dstptr = &s->cirrus_bltbuf[0]; - s->cirrus_dstptr_end = &s->cirrus_bltbuf[0]; - s->cirrus_dstcounter = 0; + cirrus_update_memory_access(s); } static int cirrus_bitblt_cputovideo(CirrusVGAState * s) @@ -735,17 +854,19 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth; - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) s->cirrus_blt_srcpitch = ((w + 31) >> 5); else s->cirrus_blt_srcpitch = ((w + 7) >> 3); } else { - s->cirrus_blt_srcpitch = s->cirrus_blt_width; + /* always align input size to 32 bits */ + s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3; } s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height; } s->cirrus_srcptr = s->cirrus_bltbuf; s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; + cirrus_update_memory_access(s); return 1; } @@ -791,8 +912,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s) blt_rop = s->gr[0x32]; #ifdef DEBUG_BITBLT - printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spicth=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", - blt_rop, + printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", + blt_rop, s->cirrus_blt_mode, s->cirrus_blt_modeext, s->cirrus_blt_width, @@ -801,7 +922,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_srcpitch, s->cirrus_blt_dstaddr, s->cirrus_blt_srcaddr, - s->sr[0x2f]); + s->gr[0x2f]); #endif switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { @@ -836,16 +957,16 @@ static void cirrus_bitblt_start(CirrusVGAState * s) } if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) && - (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | + (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_TRANSPARENTCOMP | - CIRRUS_BLTMODE_PATTERNCOPY | - CIRRUS_BLTMODE_COLOREXPAND)) == + CIRRUS_BLTMODE_PATTERNCOPY | + CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) { cirrus_bitblt_fgcol(s); cirrus_bitblt_solidfill(s, blt_rop); } else { - if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | - CIRRUS_BLTMODE_PATTERNCOPY)) == + if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | + CIRRUS_BLTMODE_PATTERNCOPY)) == CIRRUS_BLTMODE_COLOREXPAND) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { @@ -876,15 +997,28 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; - } else { - s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; - } - } - + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + if (s->cirrus_blt_pixelwidth > 2) { + printf("src transparent without colorexpand must be 8bpp or 16bpp\n"); + goto bitblt_ignore; + } + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } + } else { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; + } else { + s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; + } + } + } // setup bitblt engine. if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { if (!cirrus_bitblt_cputovideo(s)) @@ -925,13 +1059,13 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) * ***************************************/ -static void cirrus_get_offsets(VGAState *s1, - uint32_t *pline_offset, - uint32_t *pstart_addr) +static void cirrus_get_offsets(VGAState *s1, + uint32_t *pline_offset, + uint32_t *pstart_addr, + uint32_t *pline_compare) { CirrusVGAState * s = (CirrusVGAState *)s1; - uint32_t start_addr; - uint32_t line_offset; + uint32_t start_addr, line_offset, line_compare; line_offset = s->cr[0x13] | ((s->cr[0x1b] & 0x10) << 4); @@ -944,6 +1078,11 @@ static void cirrus_get_offsets(VGAState *s1, | ((s->cr[0x1b] & 0x0c) << 15) | ((s->cr[0x1d] & 0x80) << 12); *pstart_addr = start_addr; + + line_compare = s->cr[0x18] | + ((s->cr[0x07] & 0x10) << 4) | + ((s->cr[0x09] & 0x40) << 3); + *pline_compare = line_compare; } static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) @@ -1009,10 +1148,10 @@ static int cirrus_get_bpp(VGAState *s1) static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - + width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); height = (height + 1); /* interlace support */ @@ -1043,10 +1182,10 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) else offset <<= 12; - if (s->vram_size <= offset) + if (s->real_vram_size <= offset) limit = 0; else - limit = s->vram_size - offset; + limit = s->real_vram_size - offset; if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) { if (limit > 0x8000) { @@ -1199,7 +1338,6 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x14: // Scratch Register 2 case 0x15: // Scratch Register 3 case 0x16: // Performance Tuning Register - case 0x17: // Configuration Readback and Extended Control case 0x18: // Signature Generator Control case 0x19: // Signature Generator Result case 0x1a: // Signature Generator Result @@ -1214,6 +1352,10 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) reg_index, reg_value); #endif break; + case 0x17: // Configuration Readback and Extended Control + s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7); + cirrus_update_memory_access(s); + break; default: #ifdef DEBUG_CIRRUS printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index, @@ -1348,13 +1490,19 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) return CIRRUS_HOOK_NOT_HANDLED; case 0x05: // Standard VGA, Cirrus extended mode s->gr[reg_index] = reg_value & 0x7f; + cirrus_update_memory_access(s); break; case 0x09: // bank offset #0 case 0x0A: // bank offset #1 + s->gr[reg_index] = reg_value; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + break; case 0x0B: s->gr[reg_index] = reg_value; cirrus_update_bank_ptr(s, 0); cirrus_update_bank_ptr(s, 1); + cirrus_update_memory_access(s); break; case 0x10: // BGCOLOR 0x0000ff00 case 0x11: // FGCOLOR 0x0000ff00 @@ -1772,11 +1920,12 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->cirrus_shadow_gr1; + *dst = s->cirrus_shadow_gr1; } else if (mode == 5) { - *dst++ = s->cirrus_shadow_gr0; + *dst = s->cirrus_shadow_gr0; } val <<= 1; + dst++; } cpu_physical_memory_set_dirty(s->vram_offset + offset); cpu_physical_memory_set_dirty(s->vram_offset + offset + 7); @@ -1794,13 +1943,14 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->cirrus_shadow_gr1; - *dst++ = s->gr[0x11]; + *dst = s->cirrus_shadow_gr1; + *(dst + 1) = s->gr[0x11]; } else if (mode == 5) { - *dst++ = s->cirrus_shadow_gr0; - *dst++ = s->gr[0x10]; + *dst = s->cirrus_shadow_gr0; + *(dst + 1) = s->gr[0x10]; } val <<= 1; + dst += 2; } cpu_physical_memory_set_dirty(s->vram_offset + offset); cpu_physical_memory_set_dirty(s->vram_offset + offset + 15); @@ -1886,7 +2036,7 @@ static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr) return v; } -static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, +static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t mem_value) { CirrusVGAState *s = opaque; @@ -1997,7 +2147,7 @@ static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = { static inline void invalidate_cursor1(CirrusVGAState *s) { if (s->last_hw_cursor_size) { - vga_invalidate_scanlines((VGAState *)s, + vga_invalidate_scanlines((VGAState *)s, s->last_hw_cursor_y + s->last_hw_cursor_y_start, s->last_hw_cursor_y + s->last_hw_cursor_y_end); } @@ -2073,7 +2223,7 @@ static void cirrus_cursor_invalidate(VGAState *s1) s->last_hw_cursor_y != s->hw_cursor_y) { invalidate_cursor1(s); - + s->last_hw_cursor_size = size; s->last_hw_cursor_x = s->hw_cursor_x; s->last_hw_cursor_y = s->hw_cursor_y; @@ -2090,8 +2240,8 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) unsigned int color0, color1; const uint8_t *palette, *src; uint32_t content; - - if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) + + if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) return; /* fast test to see if the cursor intersects with the scan line */ if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { @@ -2102,7 +2252,7 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) if (scr_y < s->hw_cursor_y || scr_y >= (s->hw_cursor_y + h)) return; - + src = s->vram_ptr + s->real_vram_size - 16 * 1024; if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { src += (s->sr[0x13] & 0x3c) * 256; @@ -2132,11 +2282,11 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) x2 = s->last_scr_width; w = x2 - x1; palette = s->cirrus_hidden_palette; - color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), - c6_to_8(palette[0x0 * 3 + 1]), + color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), + c6_to_8(palette[0x0 * 3 + 1]), c6_to_8(palette[0x0 * 3 + 2])); - color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), - c6_to_8(palette[0xf * 3 + 1]), + color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), + c6_to_8(palette[0xf * 3 + 1]), c6_to_8(palette[0xf * 3 + 2])); bpp = ((s->ds->depth + 7) >> 3); d1 += x1 * bpp; @@ -2171,7 +2321,7 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) addr &= s->cirrus_addr_mask; - if (((s->sr[0x17] & 0x44) == 0x44) && + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ ret = cirrus_mmio_blt_read(s, addr & 0xff); @@ -2229,8 +2379,8 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, unsigned mode; addr &= s->cirrus_addr_mask; - - if (((s->sr[0x17] & 0x44) == 0x44) && + + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ cirrus_mmio_blt_write(s, addr & 0xff, val); @@ -2304,6 +2454,36 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = { cirrus_linear_writel, }; +static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + *(s->vram_ptr + addr) = val; + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + +static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val); + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + +static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val); + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + /*************************************** * * system to screen memory access @@ -2405,6 +2585,37 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { cirrus_linear_bitblt_writel, }; +/* Compute the memory access functions */ +static void cirrus_update_memory_access(CirrusVGAState *s) +{ + unsigned mode; + + if ((s->sr[0x17] & 0x44) == 0x44) { + goto generic_io; + } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + goto generic_io; + } else { + if ((s->gr[0x0B] & 0x14) == 0x14) { + goto generic_io; + } else if (s->gr[0x0B] & 0x02) { + goto generic_io; + } + + mode = s->gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { + s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; + s->cirrus_linear_write[1] = cirrus_linear_mem_writew; + s->cirrus_linear_write[2] = cirrus_linear_mem_writel; + } else { + generic_io: + s->cirrus_linear_write[0] = cirrus_linear_writeb; + s->cirrus_linear_write[1] = cirrus_linear_writew; + s->cirrus_linear_write[2] = cirrus_linear_writel; + } + } +} + + /* I/O ports */ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -2621,7 +2832,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); #endif /* handle CR0-7 protection */ - if ((s->cr[11] & 0x80) && s->cr_index <= 7) { + if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { /* can always write bit 4 of CR7 */ if (s->cr_index == 7) s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); @@ -2633,7 +2844,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x09: case 0x0c: case 0x0d: - case 0x12: /* veritcal display end */ + case 0x12: /* vertical display end */ s->cr[s->cr_index] = val; break; @@ -2753,6 +2964,105 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { cirrus_mmio_writel, }; +/* load/save state */ + +static void cirrus_vga_save(QEMUFile *f, void *opaque) +{ + CirrusVGAState *s = opaque; + + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + + qemu_put_be32s(f, &s->latch); + qemu_put_8s(f, &s->sr_index); + qemu_put_buffer(f, s->sr, 256); + qemu_put_8s(f, &s->gr_index); + qemu_put_8s(f, &s->cirrus_shadow_gr0); + qemu_put_8s(f, &s->cirrus_shadow_gr1); + qemu_put_buffer(f, s->gr + 2, 254); + qemu_put_8s(f, &s->ar_index); + qemu_put_buffer(f, s->ar, 21); + qemu_put_be32s(f, &s->ar_flip_flop); + qemu_put_8s(f, &s->cr_index); + qemu_put_buffer(f, s->cr, 256); + qemu_put_8s(f, &s->msr); + qemu_put_8s(f, &s->fcr); + qemu_put_8s(f, &s->st00); + qemu_put_8s(f, &s->st01); + + qemu_put_8s(f, &s->dac_state); + qemu_put_8s(f, &s->dac_sub_index); + qemu_put_8s(f, &s->dac_read_index); + qemu_put_8s(f, &s->dac_write_index); + qemu_put_buffer(f, s->dac_cache, 3); + qemu_put_buffer(f, s->palette, 768); + + qemu_put_be32s(f, &s->bank_offset); + + qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex); + qemu_put_8s(f, &s->cirrus_hidden_dac_data); + + qemu_put_be32s(f, &s->hw_cursor_x); + qemu_put_be32s(f, &s->hw_cursor_y); + /* XXX: we do not save the bitblt state - we assume we do not save + the state when the blitter is active */ +} + +static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) +{ + CirrusVGAState *s = opaque; + int ret; + + if (version_id > 2) + return -EINVAL; + + if (s->pci_dev && version_id >= 2) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + + qemu_get_be32s(f, &s->latch); + qemu_get_8s(f, &s->sr_index); + qemu_get_buffer(f, s->sr, 256); + qemu_get_8s(f, &s->gr_index); + qemu_get_8s(f, &s->cirrus_shadow_gr0); + qemu_get_8s(f, &s->cirrus_shadow_gr1); + s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f; + s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f; + qemu_get_buffer(f, s->gr + 2, 254); + qemu_get_8s(f, &s->ar_index); + qemu_get_buffer(f, s->ar, 21); + qemu_get_be32s(f, &s->ar_flip_flop); + qemu_get_8s(f, &s->cr_index); + qemu_get_buffer(f, s->cr, 256); + qemu_get_8s(f, &s->msr); + qemu_get_8s(f, &s->fcr); + qemu_get_8s(f, &s->st00); + qemu_get_8s(f, &s->st01); + + qemu_get_8s(f, &s->dac_state); + qemu_get_8s(f, &s->dac_sub_index); + qemu_get_8s(f, &s->dac_read_index); + qemu_get_8s(f, &s->dac_write_index); + qemu_get_buffer(f, s->dac_cache, 3); + qemu_get_buffer(f, s->palette, 768); + + qemu_get_be32s(f, &s->bank_offset); + + qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex); + qemu_get_8s(f, &s->cirrus_hidden_dac_data); + + qemu_get_be32s(f, &s->hw_cursor_x); + qemu_get_be32s(f, &s->hw_cursor_y); + + /* force refresh */ + s->graphic_mode = -1; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + return 0; +} + /*************************************** * * initialize @@ -2800,9 +3110,9 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, + vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, cirrus_vga_mem_write, s); - cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, + cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); s->sr[0x06] = 0x0f; @@ -2824,7 +3134,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) } else { s->sr[0x1F] = 0x22; // MemClock s->sr[0x0F] = CIRRUS_MEMSIZE_2M; - if (is_pci) + if (is_pci) s->sr[0x17] = CIRRUS_BUSTYPE_PCI; else s->sr[0x17] = CIRRUS_BUSTYPE_ISA; @@ -2844,6 +3154,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->cirrus_linear_io_addr = cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s); + s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr); + /* I/O handler for LFB */ s->cirrus_linear_bitblt_io_addr = cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, @@ -2862,6 +3174,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->get_resolution = cirrus_get_resolution; s->cursor_invalidate = cirrus_cursor_invalidate; s->cursor_draw_line = cirrus_cursor_draw_line; + + register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s); } /*************************************** @@ -2870,14 +3184,14 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) * ***************************************/ -void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { CirrusVGAState *s; s = qemu_mallocz(sizeof(CirrusVGAState)); - - vga_common_init((VGAState *)s, + + vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); /* XXX ISA-LFB support */ @@ -2910,19 +3224,19 @@ static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, s->cirrus_mmio_io_addr); } -void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { PCICirrusVGAState *d; uint8_t *pci_conf; CirrusVGAState *s; int device_id; - + device_id = CIRRUS_ID_CLGD5446; /* setup PCI configuration registers */ - d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", - sizeof(PCICirrusVGAState), + d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", + sizeof(PCICirrusVGAState), -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); @@ -2936,10 +3250,14 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, /* setup VGA */ s = &d->cirrus_vga; - vga_common_init((VGAState *)s, + vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, device_id, 1); + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + + s->pci_dev = (PCIDevice *)d; + /* setup memory space */ /* memory #0 LFB */ /* memory #1 memory-mapped I/O */