* available at http://home.worldonline.dk/~finth/
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qapi/error.h"
+#include "trace.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "ui/console.h"
#include "ui/pixel_ops.h"
-#include "vga_int.h"
#include "hw/loader.h"
+#include "cirrus_vga_internal.h"
/*
* TODO:
*
***************************************/
-// ID
-#define CIRRUS_ID_CLGD5422 (0x23<<2)
-#define CIRRUS_ID_CLGD5426 (0x24<<2)
-#define CIRRUS_ID_CLGD5424 (0x25<<2)
-#define CIRRUS_ID_CLGD5428 (0x26<<2)
-#define CIRRUS_ID_CLGD5430 (0x28<<2)
-#define CIRRUS_ID_CLGD5434 (0x2A<<2)
-#define CIRRUS_ID_CLGD5436 (0x2B<<2)
-#define CIRRUS_ID_CLGD5446 (0x2E<<2)
-
// sequencer 0x07
#define CIRRUS_SR7_BPP_VGA 0x00
#define CIRRUS_SR7_BPP_SVGA 0x01
#define CIRRUS_PNPMMIO_SIZE 0x1000
-struct CirrusVGAState;
-typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
- uint8_t * dst, const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight);
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
- uint8_t *dst, int dst_pitch, int width, int height);
-
-typedef struct CirrusVGAState {
- VGACommonState vga;
-
- MemoryRegion cirrus_vga_io;
- MemoryRegion cirrus_linear_io;
- MemoryRegion cirrus_linear_bitblt_io;
- MemoryRegion cirrus_mmio_io;
- MemoryRegion pci_bar;
- bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
- MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
- MemoryRegion low_mem; /* always mapped, overridden by: */
- MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
- uint32_t cirrus_addr_mask;
- uint32_t linear_mmio_mask;
- uint8_t cirrus_shadow_gr0;
- uint8_t cirrus_shadow_gr1;
- uint8_t cirrus_hidden_dac_lockindex;
- uint8_t cirrus_hidden_dac_data;
- uint32_t cirrus_bank_base[2];
- uint32_t cirrus_bank_limit[2];
- uint8_t cirrus_hidden_palette[48];
- int cirrus_blt_pixelwidth;
- int cirrus_blt_width;
- int cirrus_blt_height;
- int cirrus_blt_dstpitch;
- int cirrus_blt_srcpitch;
- uint32_t cirrus_blt_fgcol;
- uint32_t cirrus_blt_bgcol;
- uint32_t cirrus_blt_dstaddr;
- uint32_t cirrus_blt_srcaddr;
- uint8_t cirrus_blt_mode;
- uint8_t cirrus_blt_modeext;
- cirrus_bitblt_rop_t cirrus_rop;
-#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
- uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
- uint8_t *cirrus_srcptr;
- uint8_t *cirrus_srcptr_end;
- uint32_t cirrus_srccounter;
- /* hwcursor display state */
- int last_hw_cursor_size;
- int last_hw_cursor_x;
- int last_hw_cursor_y;
- int last_hw_cursor_y_start;
- int last_hw_cursor_y_end;
- int real_vram_size; /* XXX: suppress that */
- int device_id;
- int bustype;
-} CirrusVGAState;
+ uint32_t dstaddr, int dst_pitch,
+ int width, int height);
typedef struct PCICirrusVGAState {
PCIDevice dev;
#define PCI_CIRRUS_VGA(obj) \
OBJECT_CHECK(PCICirrusVGAState, (obj), TYPE_PCI_CIRRUS_VGA)
-#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga"
-#define ISA_CIRRUS_VGA(obj) \
- OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA)
-
-typedef struct ISACirrusVGAState {
- ISADevice parent_obj;
-
- CirrusVGAState cirrus_vga;
-} ISACirrusVGAState;
-
static uint8_t rop_to_index[256];
/***************************************
}
if (pitch < 0) {
int64_t min = addr
- + ((int64_t)s->cirrus_blt_height-1) * pitch;
- int32_t max = addr
- + s->cirrus_blt_width;
- if (min < 0 || max > s->vga.vram_size) {
+ + ((int64_t)s->cirrus_blt_height - 1) * pitch
+ - s->cirrus_blt_width;
+ if (min < -1 || addr >= s->vga.vram_size) {
return true;
}
} else {
}
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
- s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
+ s->cirrus_blt_dstaddr)) {
return true;
}
if (dst_only) {
return false;
}
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
- s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
+ s->cirrus_blt_srcaddr)) {
return true;
}
}
static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
+ uint32_t dstaddr, uint32_t srcaddr,
int dstpitch,int srcpitch,
int bltwidth,int bltheight)
{
}
static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
- uint8_t *dst,
+ uint32_t dstaddr,
int dstpitch, int bltwidth,int bltheight)
{
}
+static inline uint8_t cirrus_src(CirrusVGAState *s, uint32_t srcaddr)
+{
+ if (s->cirrus_srccounter) {
+ /* cputovideo */
+ return s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1)];
+ } else {
+ /* videotovideo */
+ return s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask];
+ }
+}
+
+static inline uint16_t cirrus_src16(CirrusVGAState *s, uint32_t srcaddr)
+{
+ uint16_t *src;
+
+ if (s->cirrus_srccounter) {
+ /* cputovideo */
+ src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~1];
+ } else {
+ /* videotovideo */
+ src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~1];
+ }
+ return *src;
+}
+
+static inline uint32_t cirrus_src32(CirrusVGAState *s, uint32_t srcaddr)
+{
+ uint32_t *src;
+
+ if (s->cirrus_srccounter) {
+ /* cputovideo */
+ src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~3];
+ } else {
+ /* videotovideo */
+ src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~3];
+ }
+ return *src;
+}
+
#define ROP_NAME 0
#define ROP_FN(d, s) 0
#include "cirrus_vga_rop.h"
int off_cur;
int off_cur_end;
+ if (off_pitch < 0) {
+ off_begin -= bytesperline - 1;
+ }
+
for (y = 0; y < lines; y++) {
- off_cur = off_begin;
- off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+ off_cur = off_begin;
+ off_cur_end = ((off_cur + bytesperline - 1) & s->cirrus_addr_mask) + 1;
+ assert(off_cur_end >= off_cur);
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
- off_begin += off_pitch;
+ off_begin += off_pitch;
}
}
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
- const uint8_t * src)
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s)
{
- uint8_t *dst;
+ uint32_t patternsize;
+ bool videosrc = !s->cirrus_srccounter;
- dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
+ if (videosrc) {
+ switch (s->vga.get_bpp(&s->vga)) {
+ case 8:
+ patternsize = 64;
+ break;
+ case 15:
+ case 16:
+ patternsize = 128;
+ break;
+ case 24:
+ case 32:
+ default:
+ patternsize = 256;
+ break;
+ }
+ s->cirrus_blt_srcaddr &= ~(patternsize - 1);
+ if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
+ return 0;
+ }
+ }
- if (blit_is_unsafe(s, false))
+ if (blit_is_unsafe(s, true)) {
return 0;
+ }
- (*s->cirrus_rop) (s, dst, src,
+ (*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
+ videosrc ? s->cirrus_blt_srcaddr : 0,
s->cirrus_blt_dstpitch, 0,
s->cirrus_blt_width, s->cirrus_blt_height);
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
return 0;
}
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+ rop_func(s, 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->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
- s->cirrus_addr_mask));
+ return cirrus_bitblt_common_patterncopy(s);
}
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
}
}
- /* we have to flush all pending changes so that the copy
- is generated at the appropriate moment in time */
- if (notify)
- graphic_hw_update(s->vga.con);
-
- (*s->cirrus_rop) (s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->vga.vram_ptr +
- (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+ (*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
+ s->cirrus_blt_srcaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
if (notify) {
- qemu_console_copy(s->vga.con,
- sx, sy, dx, dy,
- s->cirrus_blt_width / depth,
- s->cirrus_blt_height);
+ dpy_gfx_update(s->vga.con, dx, dy,
+ s->cirrus_blt_width / depth,
+ s->cirrus_blt_height);
}
/* we don't have to notify the display that this portion has
if (s->cirrus_srccounter > 0) {
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
+ cirrus_bitblt_common_patterncopy(s);
the_end:
s->cirrus_srccounter = 0;
cirrus_bitblt_reset(s);
} else {
/* at least one scan line */
do {
- (*s->cirrus_rop)(s, s->vga.vram_ptr +
- (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
- s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
+ (*s->cirrus_rop)(s, s->cirrus_blt_dstaddr,
+ 0, 0, 0, s->cirrus_blt_width, 1);
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
s->cirrus_blt_width, 1);
s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
{
int w;
+ if (blit_is_unsafe(s, true)) {
+ return 0;
+ }
+
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
}
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
}
+
+ /* the blit_is_unsafe call above should catch this */
+ assert(s->cirrus_blt_srcpitch <= CIRRUS_BLTBUFSIZE);
+
s->cirrus_srcptr = s->cirrus_bltbuf;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
cirrus_update_memory_access(s);
{
uint8_t blt_rop;
+ if (!s->enable_blitter) {
+ goto bitblt_ignore;
+ }
+
s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
s->cirrus_blt_modeext = s->vga.gr[0x33];
blt_rop = s->vga.gr[0x32];
+ s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
+ s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
+
#ifdef DEBUG_BITBLT
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->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
break;
case 0x07: // Extended Sequencer Mode
- cirrus_update_memory_access(s);
+ cirrus_update_memory_access(s);
+ /* fall through */
case 0x08: // EEPROM Control
case 0x09: // Scratch Register 0
case 0x0a: // Scratch Register 1
break;
}
+ trace_vga_cirrus_write_blt(address, value);
return (uint8_t) value;
}
static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
uint8_t value)
{
+ trace_vga_cirrus_write_blt(address, value);
switch (address) {
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
cirrus_vga_write_gr(s, 0x00, value);
unsigned val = mem_value;
uint8_t *dst;
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
for (x = 0; x < 8; x++) {
+ dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask);
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
} else if (mode == 5) {
*dst = s->cirrus_shadow_gr0;
}
val <<= 1;
- dst++;
}
memory_region_set_dirty(&s->vga.vram, offset, 8);
}
unsigned val = mem_value;
uint8_t *dst;
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
for (x = 0; x < 8; x++) {
+ dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1);
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
*(dst + 1) = s->vga.gr[0x11];
*(dst + 1) = s->vga.gr[0x10];
}
val <<= 1;
- dst += 2;
}
memory_region_set_dirty(&s->vga.vram, offset, 16);
}
uint32_t content;
int y, y_min, y_max;
- src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+ src = s->vga.vram_ptr + s->real_vram_size - 16 * KiB;
if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
src += (s->vga.sr[0x13] & 0x3c) * 256;
y_min = 64;
return;
}
- src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+ src = s->vga.vram_ptr + s->real_vram_size - 16 * KiB;
if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
src += (s->vga.sr[0x13] & 0x3c) * 256;
src += (scr_y - s->vga.hw_cursor_y) * 16;
break;
}
}
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
+ trace_vga_cirrus_read_io(addr, val);
return val;
}
if (vga_ioport_invalid(s, addr)) {
return;
}
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
+ trace_vga_cirrus_write_io(addr, val);
switch (addr) {
case 0x3c0:
s->vga.gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
s->vga.gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
+ cirrus_update_bank_ptr(s, 0);
+ cirrus_update_bank_ptr(s, 1);
cirrus_update_memory_access(s);
/* force refresh */
s->vga.graphic_mode = -1;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
+
return 0;
}
-static const VMStateDescription vmstate_cirrus_vga = {
+const VMStateDescription vmstate_cirrus_vga = {
.name = "cirrus_vga",
.version_id = 2,
.minimum_version_id = 1,
},
};
-static void cirrus_init_common(CirrusVGAState *s, Object *owner,
- int device_id, int is_pci,
- MemoryRegion *system_memory,
- MemoryRegion *system_io)
+void cirrus_init_common(CirrusVGAState *s, Object *owner,
+ int device_id, int is_pci,
+ MemoryRegion *system_memory, MemoryRegion *system_io)
{
int i;
static int inited;
/* I/O handler for LFB */
memory_region_init_io(&s->cirrus_linear_io, owner, &cirrus_linear_io_ops, s,
- "cirrus-linear-io", s->vga.vram_size_mb
- * 1024 * 1024);
+ "cirrus-linear-io", s->vga.vram_size_mb * MiB);
memory_region_set_flush_coalesced(&s->cirrus_linear_io);
/* I/O handler for LFB */
memory_region_set_flush_coalesced(&s->cirrus_mmio_io);
s->real_vram_size =
- (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
+ (s->device_id == CIRRUS_ID_CLGD5446) ? 4 * MiB : 2 * MiB;
/* XXX: s->vga.vram_size must be a power of two */
s->cirrus_addr_mask = s->real_vram_size - 1;
qemu_register_reset(cirrus_reset, s);
}
-/***************************************
- *
- * ISA bus support
- *
- ***************************************/
-
-static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
- VGACommonState *s = &d->cirrus_vga.vga;
-
- /* follow real hardware, cirrus card emulated has 4 MB video memory.
- Also accept 8 MB/16 MB for backward compatibility. */
- if (s->vram_size_mb != 4 && s->vram_size_mb != 8 &&
- s->vram_size_mb != 16) {
- error_setg(errp, "Invalid cirrus_vga ram size '%u'",
- s->vram_size_mb);
- return;
- }
- vga_common_init(s, OBJECT(dev), true);
- cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
- isa_address_space(isadev),
- isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, 0, s->hw_ops, s);
- rom_add_vga(VGABIOS_CIRRUS_FILENAME);
- /* XXX ISA-LFB support */
- /* FIXME not qdev yet */
-}
-
-static Property isa_cirrus_vga_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
- cirrus_vga.vga.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_cirrus_vga;
- dc->realize = isa_cirrus_vga_realizefn;
- dc->props = isa_cirrus_vga_properties;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo isa_cirrus_vga_info = {
- .name = TYPE_ISA_CIRRUS_VGA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISACirrusVGAState),
- .class_init = isa_cirrus_vga_class_init,
-};
-
/***************************************
*
* PCI bus support
return;
}
/* setup VGA */
- vga_common_init(&s->vga, OBJECT(dev), true);
+ vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
static Property pci_vga_cirrus_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
- cirrus_vga.vga.vram_size_mb, 8),
+ cirrus_vga.vga.vram_size_mb, 4),
+ DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState,
+ cirrus_vga.enable_blitter, true),
+ DEFINE_PROP_BOOL("global-vmstate", struct PCICirrusVGAState,
+ cirrus_vga.vga.global_vmstate, false),
DEFINE_PROP_END_OF_LIST(),
};
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCICirrusVGAState),
.class_init = cirrus_vga_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
};
static void cirrus_vga_register_types(void)
{
- type_register_static(&isa_cirrus_vga_info);
type_register_static(&cirrus_vga_info);
}