* THE SOFTWARE.
*/
/*
- * Reference: Finn Thogersons' VGADOC4b
- * available at http://home.worldonline.dk/~finth/
+ * Reference: Finn Thogersons' VGADOC4b:
+ *
+ * http://web.archive.org/web/20021019054927/http://home.worldonline.dk/finth/
+ *
+ * VGADOC4b.ZIP content available at:
+ *
+ * https://pdos.csail.mit.edu/6.828/2005/readings/hardware/vgadoc
*/
+
#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+#include "sysemu/reset.h"
#include "qapi/error.h"
#include "trace.h"
-#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "ui/console.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.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];
/***************************************
}
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"
}
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, bool videosrc)
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s)
{
uint32_t patternsize;
- uint8_t *dst;
- uint8_t *src;
-
- dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
+ bool videosrc = !s->cirrus_srccounter;
if (videosrc) {
switch (s->vga.get_bpp(&s->vga)) {
if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
return 0;
}
- src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
- } else {
- src = s->cirrus_bltbuf;
}
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,
+ 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, true);
+ 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->vga.vram_ptr + s->cirrus_blt_srcaddr,
+ (*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, false);
+ 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_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;
{
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->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
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;
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(),
};
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "Cirrus CLGD 54xx VGA";
dc->vmsd = &vmstate_pci_cirrus_vga;
- dc->props = pci_vga_cirrus_properties;
+ device_class_set_props(dc, pci_vga_cirrus_properties);
dc->hotpluggable = false;
}
.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);
}