/*
* 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
/*
* TODO:
- * - add support for WRITEMASK (GR2F)
+ * - destination write mask support not complete (bits 5..7)
* - optimize linear mappings
* - optimize bitblt functions
*/
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;
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 {
} PCICirrusVGAState;
static uint8_t rop_to_index[256];
-
+
/***************************************
*
* prototypes.
***************************************/
-static void cirrus_bitblt_reset(CirrusVGAState * s);
+static void cirrus_bitblt_reset(CirrusVGAState *s);
+static void cirrus_update_memory_access(CirrusVGAState *s);
/***************************************
*
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,\
ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
};
-static const cirrus_bitblt_rop_t cirrus_colorexpand_transp_inv[16][4] = {
- ROP2(cirrus_colorexpand_transp_inv_0),
- ROP2(cirrus_colorexpand_transp_inv_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_transp_inv_src_and_notdst),
- ROP2(cirrus_colorexpand_transp_inv_notdst),
- ROP2(cirrus_colorexpand_transp_inv_src),
- ROP2(cirrus_colorexpand_transp_inv_1),
- ROP2(cirrus_colorexpand_transp_inv_notsrc_and_dst),
- ROP2(cirrus_colorexpand_transp_inv_src_xor_dst),
- ROP2(cirrus_colorexpand_transp_inv_src_or_dst),
- ROP2(cirrus_colorexpand_transp_inv_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_transp_inv_src_notxor_dst),
- ROP2(cirrus_colorexpand_transp_inv_src_or_notdst),
- ROP2(cirrus_colorexpand_transp_inv_notsrc),
- ROP2(cirrus_colorexpand_transp_inv_notsrc_or_dst),
- ROP2(cirrus_colorexpand_transp_inv_notsrc_and_notdst),
-};
-
static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
ROP2(cirrus_colorexpand_0),
ROP2(cirrus_colorexpand_src_and_dst),
ROP2(cirrus_colorexpand_notsrc_and_notdst),
};
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
+ ROP2(cirrus_colorexpand_pattern_transp_0),
+ ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
+ ROP_NOP2(cirrus_bitblt_rop_nop),
+ ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
+ ROP2(cirrus_colorexpand_pattern_transp_notdst),
+ ROP2(cirrus_colorexpand_pattern_transp_src),
+ ROP2(cirrus_colorexpand_pattern_transp_1),
+ ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
+ ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
+ ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
+ ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
+ ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
+ ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
+ ROP2(cirrus_colorexpand_pattern_transp_notsrc),
+ ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
+ ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
+ ROP2(cirrus_colorexpand_pattern_0),
+ ROP2(cirrus_colorexpand_pattern_src_and_dst),
+ ROP_NOP2(cirrus_bitblt_rop_nop),
+ ROP2(cirrus_colorexpand_pattern_src_and_notdst),
+ ROP2(cirrus_colorexpand_pattern_notdst),
+ ROP2(cirrus_colorexpand_pattern_src),
+ ROP2(cirrus_colorexpand_pattern_1),
+ ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
+ ROP2(cirrus_colorexpand_pattern_src_xor_dst),
+ ROP2(cirrus_colorexpand_pattern_src_or_dst),
+ ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
+ ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
+ ROP2(cirrus_colorexpand_pattern_src_or_notdst),
+ ROP2(cirrus_colorexpand_pattern_notsrc),
+ ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
+ ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
+};
+
static const cirrus_fill_t cirrus_fill[16][4] = {
ROP2(cirrus_fill_0),
ROP2(cirrus_fill_src_and_dst),
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:
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:
static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
const uint8_t * src)
{
- uint8_t work_colorexp[256];
uint8_t *dst;
- int patternbytes = s->cirrus_blt_pixelwidth * 8;
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- cirrus_bitblt_rop_t rop_func;
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_bgcol(s);
- rop_func = cirrus_colorexpand[CIRRUS_ROP_SRC_INDEX][s->cirrus_blt_pixelwidth - 1];
- rop_func(s, work_colorexp, src, patternbytes, 1, patternbytes, 8);
- src = work_colorexp;
- s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_COLOREXPAND;
- }
- if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_PATTERNCOPY) {
-#ifdef DEBUG_BITBLT
- printf("cirrus: blt mode %02x (pattercopy) - unimplemented\n",
- s->cirrus_blt_mode);
-#endif
- return 0;
- }
-
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,
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,
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;
}
{
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);
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)
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
s->cirrus_blt_srcpitch = 8;
} else {
+ /* XXX: check for 24 bpp */
s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
}
s->cirrus_srccounter = s->cirrus_blt_srcpitch;
} 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;
}
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,
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) {
}
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) {
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
+ if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
cirrus_bitblt_bgcol(s);
- s->cirrus_rop = cirrus_colorexpand_transp_inv[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
+ else
cirrus_bitblt_fgcol(s);
- s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
+ s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
} else {
cirrus_bitblt_fgcol(s);
cirrus_bitblt_bgcol(s);
s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
}
} else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- 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]];
+ if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+ if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+ if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
+ cirrus_bitblt_bgcol(s);
+ else
+ cirrus_bitblt_fgcol(s);
+ s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+ } else {
+ cirrus_bitblt_fgcol(s);
+ cirrus_bitblt_bgcol(s);
+ s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+ }
} else {
- s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
+ s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
}
- }
-
+ } else {
+ 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))
*
***************************************/
-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);
| ((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)
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 */
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) {
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
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,
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
case 0x1a: // Miscellaneous Control
case 0x1b: // Extended Display Control
case 0x1c: // Sync Adjust and Genlock
+ case 0x1d: // Overlay Extended Control
s->cr[reg_index] = reg_value;
#ifdef DEBUG_CIRRUS
printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
case 0x26: // Attribute Controller Index Readback (R)
case 0x27: // Part ID (R)
break;
- case 0x1d: // Overlay Extended Control
case 0x25: // Part Status
default:
#ifdef DEBUG_CIRRUS
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);
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);
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;
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);
}
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;
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) {
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;
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;
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);
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);
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
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)
case 0x3c7:
val = s->dac_state;
break;
- case 0x3c9:
+ case 0x3c8:
+ val = s->dac_write_index;
+ s->cirrus_hidden_dac_lockindex = 0;
+ break;
+ case 0x3c9:
if (cirrus_hook_read_palette(s, &val))
break;
val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
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);
case 0x09:
case 0x0c:
case 0x0d:
- case 0x12: /* veritcal display end */
+ case 0x12: /* vertical display end */
s->cr[s->cr_index] = val;
break;
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
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;
- s->sr[0x1F] = 0x22; // MemClock
if (device_id == CIRRUS_ID_CLGD5446) {
/* 4MB 64 bit memory config, always PCI */
+ s->sr[0x1F] = 0x2d; // MemClock
+ s->gr[0x18] = 0x0f; // fastest memory configuration
#if 1
s->sr[0x0f] = 0x98;
s->sr[0x17] = 0x20;
s->real_vram_size = 2048 * 1024;
#endif
} 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;
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,
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);
}
/***************************************
*
***************************************/
-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 */
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);
/* 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 */