qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Vincent Hanquez <tab@snarc.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] qemu X3100 project
Date: Thu, 20 Mar 2008 19:32:40 +0000	[thread overview]
Message-ID: <20080320193240.GA1058@snarc.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1738 bytes --]

Hello QEMU ML,

I'm please to announce my qemu x3100 project. The ultimate goal is fully
emulating an intel x3100 graphic card (also known as GMA965), to be able
to hopefully support 3D in qemu guests (and any user of qemu code base).

However, the emulation is not complete yet; This is a long task, and
lots of things need to be done, fixed and better integrated. I've
started a month and a half, and at this point I think it would be useful
to share it to the qemu mailing list, since it's got some basic features
done, maybe people will be interested in helping ;)

So what does works ?
- VGA mode :)
- linux - intel drv 2.2.1 - non accelerated (32 bits depth only)
- linux - intel drv 2.2.1 - XAA acceleration (32 bits depth only)
- linux - intel drv 2.2.1 - partial EXA (32 bits only)
                            (missing some text unfortunately see below)

So what doesn't works yet:
- Anything that's related to 3d.
- tiled surfaces.
- some text in EXA since driver is using 3d engine to do some 2d stuff.
- GART, only faked at the moment.
- Windows guests when using intel drivers.
- VESA emulation.
- better switch back to VGA mode (corrupted background color ATM).

if you want to try the card, just apply the patch in attachment,
recompile, and start qemu using your usual command line and adding
-x3100. make sure you are using a 32 bits color depth in your linux
guest, and by default Xorg Intel driver will use EXA; to switch to XAA,
add in your xorg.conf near the intel driver declaration:

	Option "AccelMethod" "XAA"

There's a lots to be done, and the code need also cleanup (using correct
types, remove some ugly macros, remove bugs, etc), hence I appreciate
any encouragement, comments and/or patches ;)

-- 
Vincent

[-- Attachment #2: qemu-x3100.patch --]
[-- Type: text/x-diff, Size: 85703 bytes --]

diff --git a/Makefile.target b/Makefile.target
index 9c83733..f813daa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -535,6 +535,7 @@ OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
 OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
 OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
+OBJS+= x3100_debug.o x3100_vga.o x3100_gtt.o x3100_fb.o x3100_mi.o x3100_regs.o x3100.o
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
diff --git a/hw/pc.c b/hw/pc.c
index 2a569c7..03a6d1a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -706,6 +706,7 @@ static void pc_init1(int ram_size, int vga_ram_size,
     char buf[1024];
     int ret, linux_boot, i;
     ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
+    ram_addr_t x3100_ram_addr = 0;
     int bios_size, isa_bios_size, vga_bios_size;
     PCIBus *pci_bus;
     int piix3_devfn = -1;
@@ -753,7 +754,13 @@ static void pc_init1(int ram_size, int vga_ram_size,
     cpu_register_physical_memory(0, ram_size, ram_addr);
 
     /* allocate VGA RAM */
-    vga_ram_addr = qemu_ram_alloc(vga_ram_size);
+
+    if (x3100_enabled) {
+       vga_ram_addr = qemu_ram_alloc(vga_ram_size - X3100_RAM_SIZE);
+       x3100_ram_addr = qemu_ram_alloc(X3100_RAM_SIZE);
+    }
+    else
+       vga_ram_addr = qemu_ram_alloc(vga_ram_size);
 
     /* BIOS load */
     if (bios_name == NULL)
@@ -872,6 +879,14 @@ static void pc_init1(int ram_size, int vga_ram_size,
                             vga_ram_addr, vga_ram_size);
         else
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+    } else if (x3100_enabled) {
+	if (pci_enabled)
+            pci_x3100_init(pci_bus, ds, phys_ram_base + vga_ram_addr,
+                           vga_ram_addr, vga_ram_size,
+                           phys_ram_base + x3100_ram_addr, x3100_ram_addr,
+	                   x3100_debug);
+        else
+            fprintf(stderr, "%s: x3100: no PCI bus\n", __FUNCTION__);
     } else {
         if (pci_enabled) {
             pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr,
diff --git a/hw/pc.h b/hw/pc.h
index 9f83050..d91407f 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -113,6 +113,8 @@ int piix4_init(PCIBus *bus, int devfn);
 #define VGA_RAM_SIZE (9 * 1024 * 1024)
 #endif
 
+#define X3100_RAM_SIZE (128 * 1024 * 1024)
+
 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                  unsigned long vga_ram_offset, int vga_ram_size);
 int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
@@ -123,6 +125,11 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
                     target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
                     int it_shift);
 
+int pci_x3100_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+                   unsigned long vga_ram_offset, int vga_ram_size,
+                   uint8_t *x3100_ram_base, unsigned long x3100_ram_offset,
+                   int debug);
+
 /* cirrus_vga.c */
 void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
                          unsigned long vga_ram_offset, int vga_ram_size);
diff --git a/hw/pci.h b/hw/pci.h
index e870987..47a4e67 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -17,7 +17,9 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
 
 #define PCI_ADDRESS_SPACE_MEM		0x00
 #define PCI_ADDRESS_SPACE_IO		0x01
+#define PCI_ADDRESS_SPACE_MEM64		0x04
 #define PCI_ADDRESS_SPACE_MEM_PREFETCH	0x08
+#define PCI_ADDRESS_SPACE_MEM64_PREFETCH 0x0c
 
 typedef struct PCIIORegion {
     uint32_t addr; /* current PCI mapping address. -1 means not mapped */
diff --git a/hw/x3100.c b/hw/x3100.c
new file mode 100644
index 0000000..ad73329
--- /dev/null
+++ b/hw/x3100.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#include "x3100.h"
+#include "x3100_regs.h"
+
+typedef struct PCIX3100State {
+	PCIDevice dev;
+	X3100State state;
+} PCIX3100State;
+
+typedef struct PCIX3100DsState {
+	PCIDevice dev;
+	X3100DsState state;
+} PCIX3100DsState;
+
+static inline X3100State *pcidev_to_gmastate(PCIDevice *pci_dev)
+{
+	return &((PCIX3100State *) pci_dev)->state;
+}
+
+static inline X3100DsState *pcidev_to_gmadsstate(PCIDevice *pci_dev)
+{
+	return &((PCIX3100DsState *) pci_dev)->state;
+}
+
+/******************************************************************************/
+static void x3100_mmio2_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	printf("mmio2 %lx %x\n", addr, val);
+}
+
+static uint32_t x3100_mmio2_readl(void *opaque, target_phys_addr_t addr)
+{
+	printf("mmio2 %lx\n", addr);
+	return 0;
+}
+
+static CPUReadMemoryFunc *x3100_mmio2_read[3] = {
+	x3100_mmio2_readl, x3100_mmio2_readl, x3100_mmio2_readl,
+};
+
+static CPUWriteMemoryFunc *x3100_mmio2_write[3] = {
+	x3100_mmio2_writel, x3100_mmio2_writel, x3100_mmio2_writel,
+};
+
+/******************************************************************************/
+static uint32_t x3100_ioport_read(void *opaque, uint32_t addr)
+{
+	X3100State *s = opaque;
+	x3100_dbg(DBG_CLASS_IOPORT, "IOPORT: r(%x)\n", addr);
+	return 0;
+}
+
+static void x3100_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+	X3100State *s = opaque;
+	x3100_dbg(DBG_CLASS_IOPORT, "IOPORT: w(%x,%x)\n", addr, val);
+}
+
+/******************************************************************************/
+static void mmio_map(PCIDevice *pci_dev, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+	X3100State *s = pcidev_to_gmastate(pci_dev);
+
+	x3100_dbg(DBG_CLASS_MAP, "MAP: MMIO (%d,%x,%x,%x)\n", region_num, addr, size, type);
+	if (region_num == 0) {
+		cpu_register_physical_memory(addr, size / 2, s->registered_mmio_index);
+		cpu_register_physical_memory(addr + size / 2, size / 2, s->registered_gtt_index);
+	} else if (region_num == 2) {
+		s->mi_start = addr;
+		cpu_register_physical_memory(addr, size, s->registered_ram_index);
+	}
+}
+
+static void io_map(PCIDevice *pci_dev, int region_num,
+                   uint32_t addr, uint32_t size, int type)
+{
+	X3100State *s = pcidev_to_gmastate(pci_dev);
+
+	x3100_dbg(DBG_CLASS_MAP, "MAP: IO (%d,%x,%x,%x)\n", region_num, addr, size, type);
+	register_ioport_read(addr, size, 4, x3100_ioport_read, s);
+	register_ioport_write(addr, size, 4, x3100_ioport_write, s);
+}
+
+static void void_map(PCIDevice *pci_dev, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+	X3100DsState *s = pcidev_to_gmadsstate(pci_dev);
+
+	x3100_dbg(DBG_CLASS_MAP, "MAP: VOID (%d,%x,%x,%x)\n", region_num, addr, size, type);
+	cpu_register_physical_memory(addr, size, s->registered_other_index);
+}
+
+#define PCI_VENDOR_INTEL		0x8086
+#define PCI_DEVICE_INTEL_GMA965HB	0x2A00
+#define PCI_DEVICE_INTEL_X3100		0x2A02
+#define PCI_CLASS_VGA_BASE		0x030000
+
+static PCIX3100State * register_graphic_ctrl(PCIBus *bus, DisplayState *ds,
+                                             uint8_t *vga_ram_base,
+                                             unsigned long vga_ram_offset,
+                                             int vga_ram_size,
+                                             uint8_t *x3100_ram_base,
+                                             unsigned long x3100_ram_offset)
+{
+	PCIX3100State *d;
+	uint8_t *pci_conf;
+	X3100State *s;
+	int vga_io_memory;
+
+	d = (PCIX3100State *) pci_register_device(bus, "X3100",
+	                                          sizeof(PCIX3100State),
+	                                          -1, NULL, NULL);
+	pci_conf = d->dev.config;
+
+	pci_conf[0x00] = PCI_VENDOR_INTEL & 0xff;
+	pci_conf[0x01] = PCI_VENDOR_INTEL >> 8;
+	pci_conf[0x02] = PCI_DEVICE_INTEL_X3100 & 0xff;
+	pci_conf[0x03] = PCI_DEVICE_INTEL_X3100 >> 8;
+
+	pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
+
+	pci_conf[0x09] = PCI_CLASS_VGA_BASE & 0xff;
+	pci_conf[0x0a] = (PCI_CLASS_VGA_BASE >> 8) & 0xff;
+	pci_conf[0x0b] = PCI_CLASS_VGA_BASE >> 16;
+
+	pci_conf[0x0e] = 0x80; // header_type
+	pci_conf[0x34] = 0x90;
+	pci_conf[0x3d] = 1; /* interrupt pin 1 */
+	pci_conf[0x44] = 0x48; /* capabilities pointer */
+	pci_conf[0x52] = 0x30; /* mirror of GMCH graphics*/
+	pci_conf[0x53] = 0x00;
+	pci_conf[0x62] = 0x02; /* multi size aperture control */
+	pci_conf[0x90] = 0x05; /* MSI capability ID */
+	pci_conf[0x91] = 0xd0;
+	pci_conf[0xa4] = 0x09; /* FLR capability ID */
+	pci_conf[0xa5] = 0x00;
+	pci_conf[0xa6] = 0x06; /* FLR Len Ver */
+	pci_conf[0xa7] = 0x20;
+	pci_conf[0xd0] = 0x01; /* PM Capability ID */
+	pci_conf[0xd1] = 0x00;
+	pci_conf[0xd2] = 0x22; /* PM capability */
+	pci_conf[0xd3] = 0x00;
+
+	s = &d->state;
+
+	s->registered_mmio_index = cpu_register_io_memory(0, x3100_mmio_read,
+	                                                  x3100_mmio_write, s);
+	s->registered_gtt_index = cpu_register_io_memory(0, x3100_gtt_read,
+	                                                 x3100_gtt_write, s);
+	s->registered_ram_index = cpu_register_io_memory(0, x3100_mi_read,
+	                                                 x3100_mi_write, s);
+
+	pci_register_io_region(&d->dev, 0, 1024 * 1024,
+	                       PCI_ADDRESS_SPACE_MEM64, mmio_map);
+	pci_register_io_region(&d->dev, 2, 128 * 1024 * 1024,
+	                       PCI_ADDRESS_SPACE_MEM64_PREFETCH, mmio_map);
+	pci_register_io_region(&d->dev, 4, 8, PCI_ADDRESS_SPACE_IO, io_map);
+
+	x3100_regs_init(s);
+
+	vga_common_init((VGAState *) s, ds, vga_ram_base,
+	                vga_ram_offset, vga_ram_size);
+
+	graphic_console_init(s->ds, s->update, s->invalidate,
+	                     s->screen_dump, s->text_update, s);
+
+	/* register all vga ioports */
+	register_ioport_write(0x3c0, 16, 1, x3100_vga_ioport_write, s);
+
+	register_ioport_write(0x3b4, 2, 1, x3100_vga_ioport_write, s);
+	register_ioport_write(0x3d4, 2, 1, x3100_vga_ioport_write, s);
+	register_ioport_write(0x3ba, 1, 1, x3100_vga_ioport_write, s);
+	register_ioport_write(0x3da, 1, 1, x3100_vga_ioport_write, s);
+
+	register_ioport_read(0x3c0, 16, 1, x3100_vga_ioport_read, s);
+
+	register_ioport_read(0x3b4, 2, 1, x3100_vga_ioport_read, s);
+	register_ioport_read(0x3d4, 2, 1, x3100_vga_ioport_read, s);
+	register_ioport_read(0x3ba, 1, 1, x3100_vga_ioport_read, s);
+	register_ioport_read(0x3da, 1, 1, x3100_vga_ioport_read, s);
+
+	/* register to VGA memory */
+	vga_io_memory = cpu_register_io_memory(0, x3100_vga_mem_read,
+	                                       x3100_vga_mem_write, s);
+	cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
+	                             vga_io_memory);
+
+	s->redraw_timer = qemu_new_timer(rt_clock, x3100_fb_update, s);
+
+	s->redraw_x1 = s->redraw_y1 = 0xfffff;
+	s->redraw_x2 = s->redraw_y2 = 0x0;
+
+	s->gtt_size_kb = 128;
+	s->ram = x3100_ram_base;
+	s->ram_offset = x3100_ram_offset;
+
+	return d;
+}
+
+static PCIX3100DsState * register_display_ctrl(PCIBus *bus, int devfn)
+{
+	PCIX3100DsState *d;
+	uint8_t *pci_conf;
+	X3100DsState *s;
+
+	d = (PCIX3100DsState *) pci_register_device(bus, "X3100Disp",
+	                                            sizeof(PCIX3100DsState),
+	                                            -1, NULL, NULL);
+	pci_conf = d->dev.config;
+	pci_conf[0x00] = PCI_VENDOR_INTEL & 0xff;
+	pci_conf[0x01] = PCI_VENDOR_INTEL >> 8;
+	pci_conf[0x02] = PCI_DEVICE_INTEL_X3100 & 0xff;
+	pci_conf[0x03] = PCI_DEVICE_INTEL_X3100 >> 8;
+	pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
+	pci_conf[0x0a] = 0x80; /* Display controller */
+	pci_conf[0x0b] = 0x03; 
+	pci_conf[0x0e] = 0x00; /* header_type */
+	pci_conf[0x3d] = 0;  /* interrupt pin 0 */
+
+	s = &d->state;
+
+	pci_register_io_region(&d->dev, 0, 1024 * 1024, PCI_ADDRESS_SPACE_MEM64, void_map);
+
+	s->registered_other_index = cpu_register_io_memory(0, x3100_mmio2_read,
+	                                                   x3100_mmio2_write, s);
+
+	return d;
+}
+
+static int register_host_bridge(PCIBus *bus)
+{
+	PCIDevice *dev;
+	uint8_t *pci_conf;
+
+	dev = pci_register_device(bus, "GM965HB", sizeof(PCIDevice), -1, NULL, NULL);
+
+	pci_conf = dev->config;
+
+	pci_conf[0x00] = PCI_VENDOR_INTEL & 0xff;
+	pci_conf[0x01] = PCI_VENDOR_INTEL >> 8;
+	pci_conf[0x02] = PCI_DEVICE_INTEL_GMA965HB & 0xff;
+	pci_conf[0x03] = PCI_DEVICE_INTEL_GMA965HB >> 8;
+
+	pci_conf[0x0a] = 0x00; /* HOST Bridge controller */
+	pci_conf[0x0b] = 0x06;
+
+	return 0;
+}
+
+int pci_x3100_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+                   unsigned long vga_ram_offset, int vga_ram_size,
+                   uint8_t *x3100_ram_base, unsigned long x3100_ram_offset,
+                   int debug)
+{
+	PCIX3100State *d;
+	PCIX3100DsState *d2;
+
+	/* fake host bridge to have access to GTT */
+	register_host_bridge(bus);
+
+	d = register_graphic_ctrl(bus, ds,
+	                          vga_ram_base, vga_ram_offset, vga_ram_size,
+	                          x3100_ram_base, x3100_ram_offset);
+	d2 = register_display_ctrl(bus, d->dev.devfn + 2);
+
+	/* output files are hardcoded, but once we don't need flexible debugs
+	 * everything can be simplified */
+	if (debug) {
+		FILE *f;
+
+		f = fopen("qemu_intel_x3100.dump", "w");
+		if (!f)
+			f = stderr;
+
+		x3100_dbg_set_output(0, f);
+
+		f = fopen("qemu_intel_x3100.mi.dump", "w");
+		x3100_dbg_set_output(1, f);
+
+		x3100_dbg_set_class(DBG_CLASS_REG, 0, 1);
+		x3100_dbg_set_class(DBG_CLASS_MAP, 0, 1);
+		x3100_dbg_set_class(DBG_CLASS_IOPORT, 0, 1);
+		x3100_dbg_set_class(DBG_CLASS_MI, 1, 1);
+		x3100_dbg_set_class(DBG_CLASS_INST, 0, 1);
+		x3100_dbg_set_class(DBG_CLASS_GTT, 0, 1);
+	}
+
+	return 0;
+}
diff --git a/hw/x3100.h b/hw/x3100.h
new file mode 100644
index 0000000..b57951b
--- /dev/null
+++ b/hw/x3100.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+#ifndef QEMU_X3100_H
+#define QEMU_X3100_H
+
+#include "hw.h"	
+#include "pc.h"
+#include "pci.h"
+#include "console.h"
+#include "vga_int.h"
+#include "qemu-timer.h"
+
+#define X3100_EVENT_MOUSE_UPDATE	(1 << 1)
+#define X3100_EVENT_RESIZE		(1 << 2)
+#define X3100_EVENT_RING		(1 << 3)
+
+#define X3100_REFRESH_INTERVAL		(1000 / 30)
+
+#define BITS(x,f,t)	(((x) >> f) & ((1 << t) - 1))
+
+typedef struct X3100State {
+	VGA_STATE_COMMON
+
+	int registered_mmio_index; /* qemu index of operations for mmio */
+	int registered_gtt_index; /* qemu index of operations for GTT */
+	int registered_ram_index; /* qemu index of operations for ram */
+
+	target_phys_addr_t mi_start;
+
+	int gtt_enable;
+	int gtt_size_kb;
+	unsigned long gtt_base_addr;
+	unsigned long gtt_tbl[128 * 1024];
+
+	unsigned long ram_offset;
+	uint8_t *ram;
+
+	int gpioctl[8];
+	uint32_t ier, iir, imr, isr;
+	struct {
+		uint32_t start;
+		uint32_t end;
+	} fences[16];
+
+	struct {
+		int enable;
+		int autoreport;
+		int tail;
+		int headcount;
+		int head;
+		int start;
+		int length;
+		uint32_t control;
+	} ring;
+
+	struct {
+		int addr_start;
+		int addr_offset;
+		uint8_t enable;
+		uint8_t gamma;
+		uint8_t tiled;
+		uint8_t rotated;
+		uint32_t stride;
+		uint8_t format;
+		uint8_t cpp;
+		uint16_t width;
+		uint16_t height;
+		uint16_t out_width;
+		uint16_t out_height;
+	} dsp[2];
+
+	struct {
+		/* clipping rectangle */
+		struct { int x1, y1, x2, y2, xorigin, yorigin; } cliprect;
+		/* pipelined ptrs */
+		uint32_t vs, gs, clip, sf, wm, color;
+		/* binding tables */
+		struct { uint32_t vs, gs, clip, sf, ps; } bt;
+		int gs_enable, clip_enable;
+	} ff;
+
+	int mouse_show;
+	int mouse_x;
+	int mouse_y;
+
+	int eventpending;
+
+	target_phys_addr_t fb_start;
+	target_phys_addr_t fb_end;
+	uint16_t fb_sz_w;
+	uint16_t fb_sz_h;
+	uint32_t *fb;
+
+	QEMUTimer *redraw_timer;
+	int need_redraw;
+	int redraw_x1, redraw_x2, redraw_y1, redraw_y2;
+
+	uint8_t *mmio_regs;
+} X3100State;
+
+typedef struct X3100DsState {
+	int registered_other_index;
+} X3100DsState;
+
+void x3100_regs_init(X3100State *state);
+void x3100_regs_write(X3100State *state, int addr, uint32_t val);
+uint32_t x3100_regs_read(X3100State *state, int addr);
+
+typedef enum {
+	DBG_CLASS_REG,
+	DBG_CLASS_MI,
+	DBG_CLASS_INST,
+	DBG_CLASS_MAP,
+	DBG_CLASS_GTT,
+	DBG_CLASS_IOPORT,
+} x3100_dbg_class;
+
+/* debug facility */
+void x3100_dbg(x3100_dbg_class cl, const char *fmt, ...);
+void x3100_dbg_set_output(int nb, FILE *output);
+void x3100_dbg_set_class(x3100_dbg_class cl, int output, int enable);
+
+/* vga part */
+uint32_t x3100_vga_ioport_read(void *opaque, uint32_t addr);
+void x3100_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+extern CPUReadMemoryFunc *x3100_vga_mem_read[3];
+extern CPUWriteMemoryFunc *x3100_vga_mem_write[3];
+
+/* memory interface (mi) part */
+extern CPUReadMemoryFunc *x3100_mi_read[3];
+extern CPUWriteMemoryFunc *x3100_mi_write[3];
+
+void x3100_ring_process(X3100State *state);
+
+/* register mmio part */
+extern CPUReadMemoryFunc *x3100_mmio_read[3];
+extern CPUWriteMemoryFunc *x3100_mmio_write[3];
+
+/* gtt/gart part */
+extern CPUReadMemoryFunc *x3100_gtt_read[3];
+extern CPUWriteMemoryFunc *x3100_gtt_write[3];
+
+/* framebuffer stuff */
+void x3100_fb_update(void *opaque);
+void x3100_fb_write(X3100State *state, int size, int addr, uint32_t val);
+uint32_t x3100_fb_read(X3100State *state, int size, int addr);
+void x3100_fb_queue_refresh(X3100State *state, uint32_t x, uint32_t y);
+void x3100_fb_queue_refresh_rect(X3100State *state, uint32_t x1, uint32_t y1,
+                                                    uint32_t x2, uint32_t y2);
+void x3100_fb_xy_set(X3100State *state, int x, int y, uint32_t val);
+
+#endif
diff --git a/hw/x3100_debug.c b/hw/x3100_debug.c
new file mode 100644
index 0000000..59df746
--- /dev/null
+++ b/hw/x3100_debug.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "x3100.h"
+
+static FILE * dbg_outputs[] =
+{
+	[0] = NULL,
+	[1] = NULL,
+};
+
+struct dbgclass { int enable; int output; };
+
+static struct dbgclass dbg_class_enabled[] =
+{
+	[DBG_CLASS_REG] = { 0, 0 },
+	[DBG_CLASS_MI] = { 0, 0 },
+	[DBG_CLASS_INST] = { 0, 0 },
+	[DBG_CLASS_MAP] = { 0, 0 },
+	[DBG_CLASS_GTT] = { 0, 0 },
+	[DBG_CLASS_IOPORT] = { 0, 0 },
+};
+
+void x3100_dbg(x3100_dbg_class cl, const char *fmt, ...)
+{
+	va_list ap;
+	FILE *out;
+
+	if (!dbg_class_enabled[cl].enable)
+		return;
+	out = dbg_outputs[dbg_class_enabled[cl].output];
+	va_start(ap, fmt);
+	vfprintf(out, fmt, ap);
+	va_end(ap);
+	fflush(out);
+}
+
+void x3100_dbg_set_output(int nb, FILE *output)
+{
+	dbg_outputs[nb] = output;
+}
+
+void x3100_dbg_set_class(x3100_dbg_class cl, int output, int enable)
+{
+	dbg_class_enabled[cl].output = output;
+	dbg_class_enabled[cl].enable = enable;
+}
diff --git a/hw/x3100_fb.c b/hw/x3100_fb.c
new file mode 100644
index 0000000..6a322ef
--- /dev/null
+++ b/hw/x3100_fb.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#include "x3100.h"
+
+void x3100_fb_update(void *opaque)
+{
+	X3100State *state = opaque;
+
+	if (state->need_redraw) {
+		#if 0
+		printf("refreshing with %d<->%d x %d<->%d\n",
+		       state->redraw_x1, state->redraw_x2, state->redraw_y1, state->redraw_y2);
+		#endif
+		state->ds->dpy_update(state->ds,
+		                      state->redraw_x1, state->redraw_y1,
+		                      (state->redraw_x2 - state->redraw_x1) + 1,
+		                      (state->redraw_y2 - state->redraw_y1) + 1);
+		state->redraw_x1 = state->redraw_y1 = 0xfffff;
+		state->redraw_x2 = state->redraw_y2 = 0x0;
+		state->need_redraw = 0;
+	}
+}
+
+void x3100_fb_queue_refresh(X3100State *state, uint32_t x, uint32_t y)
+{
+	if (!state->need_redraw) {
+		state->need_redraw = 1;
+		qemu_mod_timer(state->redraw_timer, qemu_get_clock(rt_clock) + X3100_REFRESH_INTERVAL);
+	}
+
+	if (x < state->redraw_x1) state->redraw_x1 = x;
+	if (state->redraw_x2 < x) state->redraw_x2 = x;
+	if (y < state->redraw_y1) state->redraw_y1 = y;
+	if (state->redraw_y2 < y) state->redraw_y2 = y;
+}
+
+void x3100_fb_queue_refresh_rect(X3100State *state, uint32_t x1, uint32_t y1,
+                                                    uint32_t x2, uint32_t y2)
+{
+	/* FIXME: optimize */
+	if (x2 >= state->dsp[0].out_width) x2 = state->dsp[0].out_width - 1;
+	if (y2 >= state->dsp[0].out_height) y2 = state->dsp[0].out_height - 1;
+	x3100_fb_queue_refresh(state, x1, y1);
+	x3100_fb_queue_refresh(state, x2, y2);
+}
+
+void x3100_fb_write(X3100State *state, int size, int addr, uint32_t val)
+{
+	uint32_t offset;
+	uint32_t *ptr;
+	int x, y;
+
+	offset = addr / 4;
+	/* addr is in bytes */
+	x = (state->dsp[0].width > 0) ? offset % state->dsp[0].width : -1;
+	y = (state->dsp[0].width > 0) ? offset / state->dsp[0].width : -1;
+
+	ptr = (uint32_t *) state->ds->data;
+	ptr += (state->ds->linesize / 4 * y);
+	ptr += x;
+	switch (size) {
+	case 4: *ptr = val; break;
+	case 1:
+		*(((uint8_t *) ptr) + (addr % 4)) = val;
+		break;
+	}
+	x3100_fb_queue_refresh(state, x, y);
+}
+
+
+
+uint32_t x3100_fb_read(X3100State *state, int size, int addr)
+{
+	uint32_t offset;
+	uint32_t *ptr;
+	uint32_t r;
+	int x, y;
+
+	offset = addr / 4;
+	/* addr is in bytes */
+	x = (state->dsp[0].width > 0) ? offset % state->dsp[0].width : -1;
+	y = (state->dsp[0].width > 0) ? offset / state->dsp[0].width : -1;
+
+	ptr = (uint32_t *) state->ds->data;
+	ptr += (state->ds->linesize / 4 * y);
+	ptr += x;
+	switch (size) {
+	case 4: r = *ptr; break;
+	case 2: r = *(((uint16_t *) ptr) + (addr % 2)); break;
+	case 1: r = *(((uint8_t *) ptr) + (addr % 4)); break;
+	}
+	return r;
+}
+
+void x3100_fb_xy_set(X3100State *state, int x, int y, uint32_t val)
+{
+	uint32_t *ptr;
+	ptr = (uint32_t *) state->ds->data;
+	ptr += (state->ds->linesize / 4 * y);
+	ptr += x;
+	*ptr = val;
+}
diff --git a/hw/x3100_gtt.c b/hw/x3100_gtt.c
new file mode 100644
index 0000000..9bb100a
--- /dev/null
+++ b/hw/x3100_gtt.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#include "x3100.h"
+
+static uint32_t x3100_gtt_readb(void *opaque, target_phys_addr_t addr)
+{
+	x3100_dbg(DBG_CLASS_GTT, "GTT: r(1,%lx)\n", addr);
+	return -1;
+}
+
+static uint32_t x3100_gtt_readw(void *opaque, target_phys_addr_t addr)
+{
+	x3100_dbg(DBG_CLASS_GTT, "GTT: r(2,%lx)\n", addr);
+	return -1;
+}
+
+static uint32_t x3100_gtt_readl(void *opaque, target_phys_addr_t addr)
+{
+	X3100State *s = opaque;
+	int a;
+	uint32_t ret;
+
+	a = ((addr & (1024 * 1024 - 1)) - 512 * 1024) / 4;
+	ret = (a >= 0 && a <= 128 * 1024) ? s->gtt_tbl[a] : 0;
+	x3100_dbg(DBG_CLASS_GTT, "GTT: r(4,%lx) = %x (A=%x, M=%x, V=%d)\n",
+	          addr, ret, ret & 0xfffff000, (ret >> 1) & 0x3, ret & 0x1);
+	
+	return ret;
+}
+
+static void x3100_gtt_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	x3100_dbg(DBG_CLASS_GTT, "GTT: w(1,%lx,%x)\n", addr, val);
+}
+
+static void x3100_gtt_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	x3100_dbg(DBG_CLASS_GTT, "GTT: w(2,%lx,%x)\n", addr, val);
+}
+
+static void x3100_gtt_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	X3100State *s = opaque;
+	int a;
+
+	a = ((addr & (1024 * 1024 - 1)) - 512 * 1024) / 4;
+	if (a >= 0 && a <= 128 * 1024)
+		s->gtt_tbl[a] = val;
+	x3100_dbg(DBG_CLASS_GTT, "GTT: w(4,%lx,%x) (A=%x, M=%x, V=%d)\n",
+	          addr, val, val & 0xfffff000, (val >> 1) & 0x3, val & 0x1);
+}
+
+CPUReadMemoryFunc *x3100_gtt_read[3] = {
+	x3100_gtt_readb, x3100_gtt_readw, x3100_gtt_readl,
+};
+
+CPUWriteMemoryFunc *x3100_gtt_write[3] = {
+	x3100_gtt_writeb, x3100_gtt_writew, x3100_gtt_writel,
+};
diff --git a/hw/x3100_mi.c b/hw/x3100_mi.c
new file mode 100644
index 0000000..b356cbc
--- /dev/null
+++ b/hw/x3100_mi.c
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#include "x3100.h"
+#include "x3100_mi.h"
+
+struct handler_fct {
+	int (*f)(X3100State *state, uint32_t *ptr);
+	int dword;
+	int ignore;
+};
+
+
+static inline int get_bpp_from_colordepth(int colordepth)
+{
+	switch (colordepth) {
+	case 0: return 1; /* 8 bits */
+	case 1: return 2; /* 16 bits (565) */
+	case 2: return 2; /* 16 bits (1555) */
+	case 3: default: return 4; /* 32 bits */
+	}
+}
+
+static int cmd_mi_set_context(X3100State *state, uint32_t *ringdata)
+{
+	int addr;
+
+	addr = ringdata[1] >> 11;
+
+	x3100_dbg(DBG_CLASS_MI, "MI: set_context(addr=%x)\n", addr);
+	return 0;
+}
+
+static int cmd_mi_display_flip(X3100State *state, uint32_t *ringdata)
+{
+	return ((ringdata[0] >> 22) & 0x1) ? 3 : 4;
+}
+
+static int cmd_2d_xy_mono_src_copy_blt(X3100State *state, uint32_t *ringdata)
+{
+	int dst_x1, dst_y1, dst_x2, dst_y2, dst_pitch;
+	uint32_t src_fg_color, src_bg_color;
+	uint32_t dst, src;
+	int rop, dst_tiled, bpp, is_display, transparency;
+	int x, y;
+	uint8_t *dst_ptr, *src_ptr;
+
+	rop = (ringdata[1] >> 16) & 0xff;
+	dst_pitch = ringdata[1] & 0xffff;
+	dst_y1 = ringdata[2] >> 16;
+	dst_x1 = ringdata[2] & 0xffff;
+	dst_y2 = ringdata[3] >> 16;
+	dst_x2 = ringdata[3] & 0xffff;
+	dst_tiled = ringdata[0] >> 11 & 0x1;
+	dst = ringdata[4];
+	src = ringdata[5];
+	src_bg_color = ringdata[6];
+	src_fg_color = ringdata[7];
+	transparency = ringdata[1] >> 29 & 0x1;
+
+	bpp = get_bpp_from_colordepth(ringdata[1] >> 24 & 0x3);
+
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d xy_mono_src_copy_blt(rop=%x, trans=%d, dst=%x (%d,%d) (%d,%d) (%d), src=%x (bg=%x) (fg=%x))\n",
+	          rop, transparency, dst, dst_x1, dst_y1, dst_x2, dst_y2, dst_pitch,
+		  src, src_bg_color, src_fg_color);
+
+	dst_ptr = state->ram + dst;
+	src_ptr = state->ram + src;
+	is_display = (dst == state->dsp[0].addr_start);
+
+	for (y = dst_y1; y < dst_y2; y++)
+		for (x = dst_x1; x < dst_x2; x++) {
+			uint32_t *dpa;
+			uint8_t *spa;
+			uint32_t val;
+
+			dpa = (uint32_t *) (dst_ptr + (y * dst_pitch) + (x * bpp));
+			spa = (uint8_t *) (src_ptr + (y * dst_pitch) + (x / 8));
+			val = !!(*spa & (1 << (7 - (x % 8))))
+				? src_fg_color
+				: (transparency ? *dpa : src_bg_color);
+			switch (rop) {
+			case 0x88: /*D&S*/ val &= *dpa; break;
+			case 0xcc: /*S*/ break;
+			default: val = *dpa; break;
+			}
+			*dpa = val;
+
+			if (dst >= state->dsp[0].addr_start &&
+			    dst < (state->fb_end - state->mi_start)) {
+				int offset = dst - state->dsp[0].addr_start;
+				int xscreen, yscreen;
+				yscreen = ((offset / dst_pitch)) + y;
+				xscreen = ((offset % dst_pitch) / bpp) + x;
+				x3100_fb_xy_set(state, xscreen, yscreen, val);
+				x3100_fb_queue_refresh(state, xscreen, yscreen);
+			}
+		}
+	return 0;
+}
+
+static int cmd_2d_xy_mono_pat_blt(X3100State *state, uint32_t *ringdata)
+{
+	int dst_x1, dst_y1, dst_x2, dst_y2; 
+	int rop, dst_pitch;
+	uint32_t dst, pat_bg_color, pat_fg_color, pat_d0, pat_d1;
+	int pat_h_seed, pat_v_seed;
+
+	pat_h_seed = (ringdata[0] >> 12) & 0x3;
+	pat_v_seed = (ringdata[0] >> 8) & 0x3;
+	rop = (ringdata[1] >> 16) & 0xff;
+	dst_pitch = ringdata[1] & 0xffff;
+	dst_y1 = ringdata[2] >> 16;
+	dst_x1 = ringdata[2] & 0xffff;
+	dst_y2 = ringdata[3] >> 16;
+	dst_x2 = ringdata[3] & 0xffff;
+	dst = ringdata[4];
+	pat_bg_color = ringdata[5];
+	pat_fg_color = ringdata[6];
+	pat_d0 = ringdata[7];
+	pat_d1 = ringdata[8];
+
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d xy_mono_pat_blt(rop=%x, dst=%x (%d,%d) (%d,%d) (%d), pat (bg=%x) (fg=%x) (d0=%x) (d1=%x) (vseed=%x) (hseed=%x))\n",
+	          rop, dst, dst_x1, dst_y1, dst_x2, dst_y2, dst_pitch,
+		  pat_bg_color, pat_fg_color, pat_d0, pat_d1, pat_v_seed, pat_h_seed);
+	return 0;
+}
+	
+static int cmd_2d_src_copy_blt(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d src_copy_blt(dest_height=%d, dest_width=%d, dest=%x, src=%x)\n",
+			ringdata[2] >> 16,
+			(ringdata[2]) & 0xffff,
+			ringdata[3],
+			ringdata[5]);
+	return 0;
+}
+
+/*
+ * use by the linux driver in EXA mode
+ */
+static int cmd_2d_xy_src_copy_blt(X3100State *state, uint32_t *ringdata)
+{
+	int dst_x1, dst_y1, dst_x2, dst_y2, src_x1, src_y1;
+	int dst_pitch, src_pitch, dst_tiled, src_tiled;
+	uint32_t dst, src;
+	uint8_t *dst_ptr, *src_ptr;
+	int rop;
+	int is_display;
+	int bpp;
+	int y, x;
+	int dy, dx;
+
+	dst_tiled = (ringdata[0] >> 11) & 0x1;
+	rop = (ringdata[1] >> 16) & 0xff;
+	dst_pitch = ringdata[1] & 0xffff;
+	dst_y1 = ringdata[2] >> 16;
+	dst_x1 = ringdata[2] & 0xffff;
+	dst_y2 = ringdata[3] >> 16;
+	dst_x2 = ringdata[3] & 0xffff;
+	dst = ringdata[4];
+	src_y1 = ringdata[5] >> 16;
+	src_x1 = ringdata[5] & 0xffff;
+	src_pitch = ringdata[6] & 0xffff;
+	src_tiled = (ringdata[0] >> 15) & 0x1;
+	src = ringdata[7];
+
+	if (src_tiled)
+		src_pitch <<= 2;
+	if (dst_tiled)
+		dst_pitch <<= 2;
+
+	bpp = get_bpp_from_colordepth(ringdata[1] >> 24 & 0x3);
+
+	is_display = (dst == state->dsp[0].addr_start);
+
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d xy_src_copy_blt(bpp=%x, rop=%x, clip=%d, dst=%x (%d,%d) (%d,%d) (%d) (t=%d), src=%x (%d, %d) (%d) (t=%d))\n",
+	          bpp, rop, (ringdata[1] >> 30) & 0x1,
+	          dst, dst_x1, dst_y1, dst_x2, dst_y2, dst_pitch, dst_tiled,
+	          src, src_x1, src_y1, src_pitch, src_tiled);
+
+	dst_ptr = state->ram + dst;
+	src_ptr = state->ram + src;
+
+	/* check if we overlap, but else normal left->right,top->bottom copy */
+	dy = dx = 1;
+	if (dst == src) {
+		dy = (dst_y1 <= src_y1) ? 1 : -1;
+		dx = (dst_x1 <= src_x1) ? 1 : -1;
+	}
+
+	for (y = (dy == 1) ? dst_y1 : dst_y2 - 1;
+	     (dy == 1) ? y < dst_y2 : y >= dst_y1;
+	     y += dy) {
+		for (x = (dx == 1) ? dst_x1 : dst_x2 - 1;
+		     (dx == 1) ? x < dst_x2 : x >= dst_x1;
+		     x += dx) {
+			uint32_t *dpa, *spa;
+
+			/* FIXME: tile is not implemented */
+			if (dst_tiled)
+				dpa = (uint32_t *) (dst_ptr + (y * dst_pitch) + (x * bpp));
+			else
+				dpa = (uint32_t *) (dst_ptr + (y * dst_pitch) + (x * bpp));
+			/* FIXME: tile is not implemented */
+			if (src_tiled) {
+				spa = (uint32_t *) (src_ptr +
+						    ((src_y1 + (y - dst_y1)) * src_pitch) +
+						    ((src_x1 + (x - dst_x1)) * bpp));
+			} else {
+				spa = (uint32_t *) (src_ptr +
+						    ((src_y1 + (y - dst_y1)) * src_pitch) +
+						    ((src_x1 + (x - dst_x1)) * bpp));
+			}
+			switch (rop) {
+			case 0xcc: /*S*/ *dpa = *spa; break;
+			case 0xee: /*D|S*/ *dpa |= *spa; break;
+			default: break;
+			}
+			if (is_display &&
+			    x < state->dsp[0].out_width && y < state->dsp[0].out_height)
+				x3100_fb_xy_set(state, x, y, *spa);
+		}
+	}
+	if (is_display) {
+		x3100_fb_queue_refresh_rect(state, dst_x1, dst_y1, dst_x2, dst_y2);
+	}
+	return 0;
+}
+
+static int cmd_2d_color_blt(X3100State *state, uint32_t *ringdata)
+{
+	int dst_w, dst_h, dst_pitch, rop, bpp;
+	uint32_t dst;
+	uint32_t color;
+	int y, x;
+	uint8_t *dst_ptr;
+	int is_display;
+
+	rop = (ringdata[1] >> 16) & 0xff;
+	dst_pitch = ringdata[1] &  0xffff;
+	dst_h = ringdata[2] >> 16;
+	dst_w = ringdata[2] & 0xffff;
+	dst = ringdata[3];
+	color = ringdata[4];
+
+	bpp = get_bpp_from_colordepth(ringdata[1] >> 24 & 0x3);
+
+	is_display = (dst >= state->dsp[0].addr_start && dst < (state->fb_end - state->mi_start));
+
+	x3100_dbg(DBG_CLASS_MI,
+	          "MI: 2d color_blt(rop=%x, dst=%x (%d,%d) (%d), color=%x)\n",
+	          rop, dst, dst_w, dst_h, dst_pitch, color);
+
+	dst_ptr = (uint8_t *) (state->ram + dst);
+	for (y = 0; y < dst_h; y++)
+		for (x = 0; x < (dst_w / bpp); x++) {
+			uint32_t *dpa;
+			uint32_t val;
+
+			dpa = (uint32_t *) (dst_ptr + (y * dst_pitch) + (x * bpp));
+			switch (rop) {
+			case 0xf0: /*P*/ val = color; break;
+			case 0x5a: /*D^P*/ val = *dpa ^ color; break;
+			default: val = *dpa; break;
+			}
+			*dpa = val;
+			if (dst >= state->dsp[0].addr_start &&
+			    dst < (state->fb_end - state->mi_start)) {
+				int offset = dst - state->dsp[0].addr_start;
+				int xscreen, yscreen;
+				yscreen = ((offset / dst_pitch)) + y;
+				xscreen = ((offset % dst_pitch) / bpp) + x;
+				x3100_fb_xy_set(state, xscreen, yscreen, val);
+				x3100_fb_queue_refresh(state, xscreen, yscreen);
+			}
+		}
+	return 0;
+}
+
+/*
+ * use by the linux driver in EXA mode
+ */
+static int cmd_2d_xy_color_blt(X3100State *state, uint32_t *ringdata)
+{
+	int dst_x1, dst_y1, dst_x2, dst_y2;
+	int dst_pitch, rop, bpp;
+	uint32_t color;
+	uint32_t dst;
+	uint8_t *dst_ptr;
+	int is_display;
+	int y, x;
+
+	rop = (ringdata[1] >> 16) & 0xff;
+	dst_y1 = ringdata[2] >> 16;
+	dst_x1 = ringdata[2] & 0xffff;
+	dst_y2 = ringdata[3] >> 16;
+	dst_x2 = ringdata[3] & 0xffff;
+	dst_pitch = ringdata[1] & 0xffff;
+	dst = ringdata[4];
+	color = ringdata[5];
+
+	bpp = get_bpp_from_colordepth(ringdata[1] >> 24 & 0x3);
+
+	is_display = (dst == state->dsp[0].addr_start);
+
+	x3100_dbg(DBG_CLASS_MI,
+	          "MI: 2d xy_color_blt(rop=%x, dst=%x (%d,%d) (%d,%d) (%d) (t=%d), color=%x)\n",
+	          rop, dst, dst_x1, dst_y1, dst_x2, dst_y2, dst_pitch, (ringdata[0] >> 11) & 0x1, color);
+	dst_ptr = state->ram + dst;
+
+	for (y = dst_y1; y < dst_y2; y++)
+		for (x = dst_x1; x < dst_x2; x++) {
+			uint32_t *dpa;
+			uint32_t val;
+
+			dpa = (uint32_t *) (dst_ptr + (y * dst_pitch) + (x * bpp));
+			switch (rop) {
+			case 0xf0: /* P */ val = color; break;
+			case 0x5a: /* D ^ P */ val = *dpa ^ color; break;
+			default: val = *dpa; break;
+			}
+			*dpa = val;
+
+			if (is_display)
+				x3100_fb_xy_set(state, x, y, val);
+		}
+	if (is_display)
+		x3100_fb_queue_refresh_rect(state, dst_x1, dst_y1, dst_x2, dst_y2);
+	return 0;
+}
+
+static int cmd_2d_xy_pat_blt_immediate(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI,
+	          "MI: 2d xy_pat_blt_immediate:\n");
+	return 0;
+}
+
+static int cmd_gfx_urb_fence(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: gfx urb fence: CLIP=(%x,%d) GS=(%x,%d) VS=(%x,%d) CS=(%x,%d) VFE=(%x,%d) SF=(%x,%d)\n",
+	          ringdata[1] >> 20 & 0x3ff, ringdata[0] >> 10 & 0x1,
+	          ringdata[1] >> 10 & 0x3ff, ringdata[0] >> 9 & 0x1,
+	          ringdata[1] & 0x3ff, ringdata[0] >> 8 & 0x1,
+	          ringdata[2] >> 20 & 0x3ff, ringdata[0] >> 13 & 0x1,
+	          ringdata[2] >> 10 & 0x3ff, ringdata[0] >> 12 & 0x1,
+	          ringdata[2] & 0x3ff, ringdata[0] >> 11 & 0x1);
+	return 0;
+}
+
+static int cmd_gfx_urb_state(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: gfx urb state: size=%d entries=%d\n",
+	          ringdata[1] >> 4 & 0xf, ringdata[1] & 0x7);
+	return (ringdata[0] & 0xff) + 2;
+}
+
+static int cmd_gfx_constant_buffer(X3100State *state, uint32_t *ringdata)
+{
+	return (ringdata[0] & 0xff) + 2;
+}
+
+static int cmd_gfx_state_prefetch(X3100State *state, uint32_t *ringdata)
+{
+	return (ringdata[0] & 0xff) + 2;
+}
+
+static int cmd_gfx_state_base_addr(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d gfx state base: (gen %x %d) (surface %x %d) "
+	                        "(indirect %x %d) (genupper %x %d) (indirect upper %x %d)\n",
+	          ringdata[1] & ~0xfff, ringdata[1] & 0x1,
+	          ringdata[2] & ~0xfff, ringdata[2] & 0x1,
+	          ringdata[3] & ~0xfff, ringdata[3] & 0x1,
+	          ringdata[4] & ~0xfff, ringdata[4] & 0x1,
+	          ringdata[5] & ~0xfff, ringdata[5] & 0x1);
+	return 0;
+}
+
+static int cmd_gfx_state_sip(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d gfx state SIP: %x\n",
+	          ringdata[1] >> 4);
+	return 0;
+}
+
+static int cmd_gfx_pipeline_select(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 2d gfx pipeline select: %s\n",
+	          (ringdata[0] & 0x1) ? "media" : "3D");
+	return 0;
+}
+
+static int cmd_3d_drawing_rectangle(X3100State *state, uint32_t *ringdata)
+{
+	state->ff.cliprect.y1 = ringdata[1] >> 16;
+	state->ff.cliprect.x1 = ringdata[1] & 0xffff;
+	state->ff.cliprect.y2 = ringdata[2] >> 16;
+	state->ff.cliprect.x2 = ringdata[2] & 0xffff;
+	state->ff.cliprect.yorigin = ringdata[3] >> 16;
+	state->ff.cliprect.xorigin = ringdata[3] & 0xffff;
+
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d drawing rectangle: "
+	                        "min=(%d,%d) max=(%d,%d) origin=(%d,%d)\n",
+	          state->ff.cliprect.x1, state->ff.cliprect.y1,
+	          state->ff.cliprect.x2, state->ff.cliprect.y2,
+	          state->ff.cliprect.xorigin, state->ff.cliprect.yorigin);
+	return 0;
+}
+
+static int cmd_3d_pipelined_ptrs(X3100State *state, uint32_t *ringdata)
+{
+	int got_diff = 0;
+
+	/* a bit ugly, but useful to not repeat useless debugging message. */
+	#define SET_DIFF(var, newval) \
+		if ((var) != (newval)) { (var) = (newval); got_diff = 1; }
+	SET_DIFF(state->ff.vs, ringdata[1] & ~0x1f);
+	SET_DIFF(state->ff.gs, ringdata[2] & ~0x1f);
+	SET_DIFF(state->ff.gs_enable, ringdata[2] & 0x1);
+	SET_DIFF(state->ff.clip, ringdata[3] & ~0x1f);
+	SET_DIFF(state->ff.clip_enable, ringdata[3] & 0x1);
+	SET_DIFF(state->ff.sf, ringdata[4] & ~0x1f);
+	SET_DIFF(state->ff.wm, ringdata[5] & ~0x1f);
+	SET_DIFF(state->ff.color, ringdata[6] & ~0x3f);
+	#undef SET_DIFF
+
+	if (got_diff)
+		x3100_dbg(DBG_CLASS_MI, "MI: 3d pipelined ptrs: vs=%x gs=%x,%d "
+					"clip=%x,%d sf=%x wm=%x color=%x\n",
+		          state->ff.vs, state->ff.gs, state->ff.gs_enable,
+		          state->ff.clip, state->ff.clip_enable,
+		          state->ff.sf, state->ff.wm, state->ff.color);
+	return 0;
+}
+
+static int cmd_3d_binding_table_ptrs(X3100State *state, uint32_t *ringdata)
+{
+	int got_diff = 0;
+	/* a bit ugly, but useful to not repeat useless debugging message. */
+	#define SET_DIFF(var, newval) \
+		if ((var) != (newval)) { (var) = (newval); got_diff = 1; }
+	SET_DIFF(state->ff.bt.vs, ringdata[1] & ~0x1f);
+	SET_DIFF(state->ff.bt.gs, ringdata[2] & ~0x1f);
+	SET_DIFF(state->ff.bt.clip, ringdata[3] & ~0x1f);
+	SET_DIFF(state->ff.bt.sf, ringdata[4] & ~0x1f);
+	SET_DIFF(state->ff.bt.ps, ringdata[5] & ~0x1f);
+	#undef SET_DIFF
+
+	if (got_diff)
+		x3100_dbg(DBG_CLASS_MI, "MI: 3d binding table ptrs: "
+					"vs=%x gs=%x clip=%x sf=%x ps=%x\n",
+			  state->ff.bt.vs, state->ff.bt.gs, state->ff.bt.clip,
+			  state->ff.bt.sf, state->ff.bt.ps);
+	return 0;
+}
+
+static int cmd_3d_vertex_buffers(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d vertex buffers: len=%d\n", (ringdata[1] & 0xff) + 2);
+	return (ringdata[1] & 0xff) + 2; /* 4n-1 */
+}
+
+static int cmd_3d_vertex_elements(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d vertex elements: \n");
+	return (ringdata[1] & 0xff) + 2; /* 4n-1 */
+}
+
+static int cmd_3d_index_buffer(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d index buffer: \n");
+	return 0;
+}
+
+static int cmd_3d_vf_statistics(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d vf statistics: \n");
+	return 0;
+}
+
+static int cmd_3d_pipe_control(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d pipe control: dest=(%x,%d) imm=(%x %x)\n",
+	          ringdata[1] & ~0xf, (ringdata[1] >> 2) & 0x1,
+	          ringdata[2], ringdata[3]);
+	return 0;
+}
+
+static int cmd_3d_primitive(X3100State *state, uint32_t *ringdata)
+{
+	x3100_dbg(DBG_CLASS_MI, "MI: 3d primitive: access=%s, prim_type=%x, vertex#=%d, start=%x, base=%x\n",
+	          (ringdata[0] >> 16 & 0x1) ? "random" : "sequential",
+	          ringdata[0] >> 10 & 0xf, ringdata[1], ringdata[2], ringdata[5]
+	          );
+	return 0;
+}
+
+/********************************************************************************/
+/********************************************************************************/
+/********************************************************************************/
+static struct handler_fct cmds_mi[] =
+{
+	[CMD_MI_NOP] = { NULL, 1, 1 },
+	[CMD_MI_USER_INT] = { NULL, 1, 1 },
+	[CMD_MI_WAIT_FOR_EVENT] = { NULL, 1, 1 },
+	[CMD_MI_FLUSH] = { NULL, 1, 1 },
+	[CMD_MI_ARB_CHECK] = { NULL, 1, 1 },
+	[CMD_MI_REPORT_HEAD] = { NULL, 1, 1 },
+	[CMD_MI_BATCH_END] = { NULL, 1, 1 },
+	[CMD_MI_OVERLAY_FLIP] = { NULL, 2, 1 },
+	[CMD_MI_LOAD_SL_INCL] = { NULL, 2, 1 },
+	[CMD_MI_LOAD_SL_EXCL] = { NULL, 2, 1 },
+	[CMD_MI_DISP_FLIP] = { cmd_mi_display_flip, 0, 0 },
+	[CMD_MI_SET_CONTEXT] = { cmd_mi_set_context, 2, 0 },
+	[CMD_MI_STORE_DATA_IMM] = { NULL, 5, 1 },
+	[CMD_MI_STORE_DATA_INDEX] = { NULL, 4, 1 },
+	[CMD_MI_LOAD_REG] = { NULL, 3, 1 },
+	[CMD_MI_STORE_REG_MEM] = { NULL, 3, 1 },
+	[CMD_MI_BATCH_START] = { NULL, 2, 0 },
+};
+
+static struct handler_fct cmds_2d[] =
+{
+	[CMD_2D_COLOR_BLT] = { cmd_2d_color_blt, 5, 0 },
+	[CMD_2D_SRC_COPY_BLT] = { cmd_2d_src_copy_blt, 6, 0 },
+	[CMD_2D_XY_SETUP_BLT] = { NULL, 8, 0 },
+	[CMD_2D_XY_SETUP_MONO_PATTERN_SL_BLT] = { NULL, 9, 0 },
+	[CMD_2D_XY_SETUP_CLIP_BLT] = { NULL, 3, 0 },
+	[CMD_2D_XY_PIXEL_BLT] = { NULL, 2, 0 },
+	[CMD_2D_XY_SCANLINES_BLT] = { NULL, 3, 0 },
+	[CMD_2D_XY_TEXT_BLT] = { NULL, 4, 0 },
+	[CMD_2D_XY_TEXT_IMMEDIATE_BLT] = { NULL, 6, 0 },
+	[CMD_2D_XY_COLOR_BLT] = { cmd_2d_xy_color_blt, 6, 0 },
+	[CMD_2D_XY_PAT_BLT] = { NULL, 6, 0 },
+	[CMD_2D_XY_PAT_CHROMA_BLT] = { NULL, 8, 0 },
+	[CMD_2D_XY_PAT_BLT_IMMEDIATE] = { cmd_2d_xy_pat_blt_immediate, 8, 0 },
+	[CMD_2D_XY_PAT_CHROMA_BLT_IMMEDIATE] = { NULL, 10, 0 },
+	[CMD_2D_XY_MONO_PAT_BLT] = { cmd_2d_xy_mono_pat_blt, 9, 0 },
+	[CMD_2D_XY_MONO_PAT_FIXED_BLT] = { NULL, 7, 0 },
+	[CMD_2D_XY_SRC_COPY_BLT] = { cmd_2d_xy_src_copy_blt, 8, 0 },
+	[CMD_2D_XY_SRC_COPY_CHROMA_BLT] = { NULL, 10, 0 },
+	[CMD_2D_XY_MONO_SRC_COPY_BLT] = { cmd_2d_xy_mono_src_copy_blt, 8, 0 },
+	[CMD_2D_XY_MONO_SRC_COPY_IMMEDIATE_BLT] = { NULL, 10, 0 },
+	[CMD_2D_XY_FULL_BLT] = { NULL, 9, 0 },
+	[CMD_2D_XY_FULL_IMMEDIATE_PATTERN_BLT] = { NULL, 11, 0 },
+	[CMD_2D_XY_FULL_MONO_SRC_BLT] = { NULL, 9, 0 },
+	[CMD_2D_XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT] = { NULL, 10, 0 },
+	[CMD_2D_XY_FULL_MONO_PATTERN_BLT] = { NULL, 12, 0 },
+	[CMD_2D_XY_FULL_MONO_PATTERN_MONO_SRC_BLT] = { NULL, 12, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_common_pipelined[] =
+{
+	[CMD_GFX_URB_FENCE] = { cmd_gfx_urb_fence, 3, 0 },
+	[CMD_GFX_URB_STATE] = { cmd_gfx_urb_state, 0, 0 },
+	[CMD_GFX_CONSTANT_BUFFER] = { cmd_gfx_constant_buffer, 0, 0 },
+	[CMD_GFX_STATE_PREFETCH] = { cmd_gfx_state_prefetch, 0, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_common_npipelined[] =
+{
+	[CMD_GFX_STATE_BASE_ADDR] = { cmd_gfx_state_base_addr, 6, 0 },
+	[CMD_GFX_STATE_SIP] = { cmd_gfx_state_sip, 2, 0 },
+	[CMD_GFX_PIPELINE_SELECT] = { cmd_gfx_pipeline_select, 1, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_3d_pipelined[] =
+{
+	[CMD_3D_PIPELINED_PTRS] = { cmd_3d_pipelined_ptrs, 7, 0 },
+	[CMD_3D_BINDING_TABLE_PTRS] = { cmd_3d_binding_table_ptrs, 6, 0 },
+	[CMD_3D_VERTEX_BUFFERS] = { cmd_3d_vertex_buffers, 0, 0 },
+	[CMD_3D_VERTEX_ELEMENTS] = { cmd_3d_vertex_elements, 0, 0 },
+	[CMD_3D_INDEX_BUFFER] = { cmd_3d_index_buffer, 4, 0 },
+	[CMD_3D_VF_STATISTICS] = { cmd_3d_vf_statistics, 0, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_3d_npipelined[] =
+{
+	[CMD_3D_DRAWING_RECTANGLE] = { cmd_3d_drawing_rectangle, 4, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_3d_pipe_ctrl[] =
+{
+	[0] = { cmd_3d_pipe_control, 4, 0 },
+};
+
+static struct handler_fct cmds_gfxpipe_3d_primitive[] =
+{
+	[0] = { cmd_3d_primitive, 6, 0 },
+};
+
+static int call_on_table(X3100State *state, struct handler_fct *table, char *ty,
+                         int array_sz, int index, uint32_t *ringdata)
+{
+	struct handler_fct *h;
+	if (index < 0 || index >= array_sz) {
+		x3100_dbg(DBG_CLASS_MI, "MI: %s : index not handled %d\n",
+		          ty, index);
+		return 0;
+	}
+
+	h = &table[index];
+	if (h->ignore)
+		return h->dword;
+	if (!h->f) {
+		x3100_dbg(DBG_CLASS_MI, "MI: %s cmd not handled (header %x)\n",
+		          ty, ringdata[0]);
+		return 0;
+	}
+
+	if (h->dword > 0) {
+		h->f(state, ringdata);
+		return h->dword;
+	} else
+		return h->f(state, ringdata);
+}
+
+void x3100_ring_process(X3100State *state)
+{
+	int tmp;
+	uint32_t *ringdata;
+
+	if (!state->ring.enable)
+		return;
+	//printf("ring: head %x => tail %x\n", state->ring.head, state->ring.tail);
+#define DOHANDLER(index, tbl, ty) \
+	dword = call_on_table(state, tbl, ty, ARRAY_SIZE(tbl), index, \
+	              ringdata + (tmp / 4))
+
+	ringdata = (uint32_t *) (state->ram + state->ring.start);
+
+	tmp = state->ring.head;
+	while (tmp < state->ring.tail) {
+		uint32_t header = ringdata[tmp / 4];
+		int dword = 0;
+
+		switch (HDR_TYPE(header)) {
+		case CMD_TYPE_MI:
+			DOHANDLER(HDR_MI_OP(header), cmds_mi, "mi");
+			break;
+		case CMD_TYPE_2D:
+			DOHANDLER(HDR_2D_OP(header), cmds_2d, "2D");
+			break;
+		case CMD_TYPE_GFXPIPE:
+			switch (HDR_GFXPIPE_PIPELINE(header)) {
+			case GFXPIPE_COMMON:
+				switch (HDR_GFXPIPE_OP(header)) {
+				case COMMON_OP_PIPELINED:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_common_pipelined, "GFX COM PIPE");
+					break;
+				case COMMON_OP_NPIPELINED:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_common_npipelined, "GFX COM NPIPE");
+					break;
+				default:
+					break;
+				}
+				break;
+			case GFXPIPE_3D:
+				switch (HDR_GFXPIPE_OP(header)) {
+				case G3D_OP_PIPELINED:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_3d_pipelined, "GFX 3D PIPE");
+					break;
+				case G3D_OP_NPIPELINED:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_3d_npipelined, "GFX 3D NPIPE");
+					break;
+				case G3D_OP_PIPE_CTRL:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_3d_pipe_ctrl, "GFX 3D PIPE CTRL");
+					break;
+				case G3D_OP_PRIMITIVE:
+					DOHANDLER(HDR_GFXPIPE_SUBOP(header),
+					          cmds_gfxpipe_3d_primitive, "GFX 3D PRIMITIVE");
+					break;
+				default:
+					break;
+				}
+				
+				break;
+			default:
+				break;
+			}
+			break;
+		default: /* reserved */
+			break;
+		}
+		if (!dword) {
+			x3100_dbg(DBG_CLASS_MI, "MI: unknown header %x (ty=%x)\n",
+			          header, HDR_TYPE(header));
+			dword = 1;
+		}
+		tmp += dword * 4;
+	}
+
+	state->ring.head = state->ring.tail;
+#undef DOHANDLER
+}
+
+static uint32_t x3100_mi_readb(void *opaque, target_phys_addr_t addr)
+{
+	X3100State *state = opaque;
+	addr -= state->mi_start;
+	return *(state->ram + addr);
+}
+
+static uint32_t x3100_mi_readw(void *opaque, target_phys_addr_t addr)
+{
+	X3100State *state = opaque;
+	addr -= state->mi_start;
+	return *((uint16_t *) (state->ram + addr));
+}
+
+static uint32_t x3100_mi_readl(void *opaque, target_phys_addr_t addr)
+{
+	X3100State *state = opaque;
+	addr -= state->mi_start;
+	return *((uint32_t *) (state->ram + addr));
+}
+
+static void x3100_mi_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	X3100State *state = opaque;
+
+	if (state->dsp[0].enable && addr >= state->fb_start && addr < state->fb_end) {
+		x3100_fb_write(state, 1, addr - state->fb_start, val & 0xff);
+	}
+	addr -= state->mi_start;
+	*((uint8_t *) (state->ram + addr)) = val & 0xff;
+	cpu_physical_memory_set_dirty(state->ram_offset + addr);
+}
+
+static void x3100_mi_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	X3100State *state = opaque;
+	addr -= state->mi_start;
+	*((uint16_t *) (state->ram + addr)) = val & 0xffff;
+	cpu_physical_memory_set_dirty(state->ram_offset + addr);
+}
+
+static void x3100_mi_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	X3100State *state = opaque;
+
+	if (state->dsp[0].enable && addr >= state->fb_start && addr < state->fb_end) {
+		x3100_fb_write(state, 4, addr - state->fb_start, val);
+	}
+	addr -= state->mi_start;
+	*((uint32_t *) (state->ram + addr)) = val;
+	cpu_physical_memory_set_dirty(state->ram_offset + addr);
+}
+
+CPUReadMemoryFunc *x3100_mi_read[3] = {
+	x3100_mi_readb, x3100_mi_readw, x3100_mi_readl,
+};
+
+CPUWriteMemoryFunc *x3100_mi_write[3] = {
+	x3100_mi_writeb, x3100_mi_writew, x3100_mi_writel,
+};
diff --git a/hw/x3100_mi.h b/hw/x3100_mi.h
new file mode 100644
index 0000000..99bbd3c
--- /dev/null
+++ b/hw/x3100_mi.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#define HDR_TYPE(x)	(x >> 29)
+#define HDR_MI_OP(x)	((x >> 23) & 0x3f)
+#define HDR_2D_OP(x)	((x >> 22) & 0x7f)
+
+#define HDR_GFXPIPE_PIPELINE(x)	((x >> 27) & 0x3)
+#define HDR_GFXPIPE_OP(x)	((x >> 24) & 0x7)
+#define HDR_GFXPIPE_SUBOP(x)	((x >> 16) & 0xff)
+
+
+#define CMD_TYPE_MI		0x0
+#define CMD_TYPE_2D		0x2
+#define CMD_TYPE_GFXPIPE	0x3
+
+#define CMD_MI_NOP		0x00
+#define CMD_MI_USER_INT		0x02
+#define CMD_MI_WAIT_FOR_EVENT	0x03
+#define CMD_MI_FLUSH		0x04
+#define CMD_MI_ARB_CHECK	0x05
+#define CMD_MI_REPORT_HEAD	0x07
+#define CMD_MI_BATCH_END	0x0A
+#define CMD_MI_OVERLAY_FLIP	0x11
+#define CMD_MI_LOAD_SL_INCL	0x12
+#define CMD_MI_LOAD_SL_EXCL	0x13
+#define CMD_MI_DISP_FLIP	0x14
+#define CMD_MI_SET_CONTEXT	0x18
+#define CMD_MI_STORE_DATA_IMM	0x20
+#define CMD_MI_STORE_DATA_INDEX	0x21
+#define CMD_MI_LOAD_REG		0x22
+#define CMD_MI_STORE_REG_MEM	0x24
+#define CMD_MI_BATCH_START	0x31
+
+#define CMD_2D_XY_SETUP_BLT 			0x01
+#define CMD_2D_XY_SETUP_CLIP_BLT		0x03
+#define CMD_2D_XY_SETUP_MONO_PATTERN_SL_BLT	0x11
+#define CMD_2D_XY_PIXEL_BLT			0x24
+#define CMD_2D_XY_SCANLINES_BLT			0x25
+#define CMD_2D_XY_TEXT_BLT			0x26
+#define CMD_2D_XY_TEXT_IMMEDIATE_BLT		0x31
+#define CMD_2D_COLOR_BLT			0x40
+#define CMD_2D_SRC_COPY_BLT			0x43
+#define CMD_2D_XY_COLOR_BLT			0x50
+#define CMD_2D_XY_PAT_BLT			0x51
+#define CMD_2D_XY_MONO_PAT_BLT			0x52
+#define CMD_2D_XY_SRC_COPY_BLT			0x53
+#define CMD_2D_XY_MONO_SRC_COPY_BLT		0x54
+#define CMD_2D_XY_FULL_BLT			0x55
+#define CMD_2D_XY_FULL_MONO_SRC_BLT		0x56
+#define CMD_2D_XY_FULL_MONO_PATTERN_BLT		0x57
+#define CMD_2D_XY_FULL_MONO_PATTERN_MONO_SRC_BLT 0x58
+#define CMD_2D_XY_MONO_PAT_FIXED_BLT		0x59
+#define CMD_2D_XY_MONO_SRC_COPY_IMMEDIATE_BLT	0x71
+#define CMD_2D_XY_PAT_BLT_IMMEDIATE		0x72
+#define CMD_2D_XY_SRC_COPY_CHROMA_BLT		0x73
+#define CMD_2D_XY_FULL_IMMEDIATE_PATTERN_BLT	0x74
+#define CMD_2D_XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT 0x75
+#define CMD_2D_XY_PAT_CHROMA_BLT		0x76
+#define CMD_2D_XY_PAT_CHROMA_BLT_IMMEDIATE	0x77
+
+#define GFXPIPE_COMMON				0x0
+# define COMMON_OP_PIPELINED			0x0
+#  define CMD_GFX_URB_FENCE			0x0
+#  define CMD_GFX_URB_STATE			0x1
+#  define CMD_GFX_CONSTANT_BUFFER		0x2
+#  define CMD_GFX_STATE_PREFETCH		0x3
+# define COMMON_OP_NPIPELINED			0x1
+#  define CMD_GFX_STATE_BASE_ADDR		0x1
+#  define CMD_GFX_STATE_SIP			0x2
+#  define CMD_GFX_PIPELINE_SELECT		0x4
+#define GFXPIPE_3D				0x3
+# define G3D_OP_PIPELINED			0x0
+#  define CMD_3D_PIPELINED_PTRS			0x00
+#  define CMD_3D_BINDING_TABLE_PTRS		0x01
+#  define CMD_3D_VERTEX_BUFFERS			0x08
+#  define CMD_3D_VERTEX_ELEMENTS		0x09
+#  define CMD_3D_INDEX_BUFFER			0x0A
+#  define CMD_3D_VF_STATISTICS			0x0B
+# define G3D_OP_NPIPELINED			0x1
+#  define CMD_3D_DRAWING_RECTANGLE		0x00
+#  define CMD_3D_CONSTANT_COLOR			0x01
+#  define CMD_3D_SAMPLER_PALETTE_LOAD		0x02
+#  define CMD_3D_CHROMA_KEY			0x04
+#  define CMD_3D_DEPTH_BUFFER			0x05
+#  define CMD_3D_POLY_STIPPLE_OFFSET		0x06
+#  define CMD_3D_POLY_STIPPLE_PATTERN		0x07
+#  define CMD_3D_LINE_STIPPLE			0x08
+#  define CMD_3D_GLOBAL_DEPTH_OFFSET_CLAMP	0x09
+#  define CMD_3D_AA_LINE_PARAMS			0x0A
+#  define CMD_3D_GS_SVB_INDEX			0x0B
+# define G3D_OP_PIPE_CTRL			0x2
+# define G3D_OP_PRIMITIVE			0x3
+
+typedef enum {
+	PRIM3D_POINTLIST = 0x01,
+	PRIM3D_LINELIST = 0x02,
+	PRIM3D_LINESTRIP = 0x03,
+	PRIM3D_TRILIST = 0x04,
+	PRIM3D_TRISTRIP = 0x05,
+	PRIM3D_TRIFAN = 0x06,
+	PRIM3D_QUADLIST = 0x07,
+	PRIM3D_QUADSTRIP = 0x08,
+	PRIM3D_TRISTRIP_REVERSE = 0x0D,
+	PRIM3D_POLYGON = 0x0E,
+	PRIM3D_RECTLIST = 0x0F,
+	PRIM3D_LINELOOP = 0x10,
+	PRIM3D_POINTLIST_BF = 0x11,
+	PRIM3D_LINESTRIP_CONT = 0x12,
+	PRIM3D_LINESTRIP_BF = 0x13,
+	PRIM3D_LINESTRIP_CONT_BF = 0x14,
+	PRIM3D_TRIFAN_NOSTIPPLE = 0x16,
+} prim3d_types;
diff --git a/hw/x3100_regs.c b/hw/x3100_regs.c
new file mode 100644
index 0000000..f258478
--- /dev/null
+++ b/hw/x3100_regs.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ *
+ * QEMU Intel X3100 emulation
+ */
+
+#include "x3100.h"
+#include "x3100_regs.h"
+
+typedef struct mmio_reg_fct {
+	uint32_t (*read)(X3100State *state, int addr);
+	void (*write)(X3100State *state, int addr, uint32_t val);
+} mmio_reg_fct;
+
+struct mmio_reg_range
+{
+	int start;
+	int end;
+	mmio_reg_fct *fct;
+	char *desc;
+};
+
+/********************************************************************/
+
+static void reserved_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	x3100_dbg(DBG_CLASS_REG, "reserved: w(%x,%x)\n", addr, val);
+}
+
+static uint32_t reserved_mmio_read(X3100State *state, int addr)
+{
+	x3100_dbg(DBG_CLASS_REG, "reserved: r(%x)\n", addr);
+	return 0x0;
+}
+
+static mmio_reg_fct reserved_mmio =
+{
+	.read = reserved_mmio_read,
+	.write = reserved_mmio_write,
+};
+
+static void unimplemented_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+}
+
+static uint32_t unimplemented_mmio_read(X3100State *state, int addr)
+{
+	return 0x0;
+}
+
+static mmio_reg_fct unimplemented_mmio =
+{
+	.read = unimplemented_mmio_read,
+	.write = unimplemented_mmio_write,
+};
+
+static void dummy_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	*((uint32_t *) (state->mmio_regs + addr)) = val;
+}
+
+static uint32_t dummy_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	ret = *((uint32_t *) (state->mmio_regs + addr));
+	return ret;
+}
+
+static mmio_reg_fct dummy_mmio =
+{
+	.read = dummy_mmio_read,
+	.write = dummy_mmio_write,
+};
+
+/********************************************************************/
+static void imi_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	int handled = 1;
+
+	switch (addr) {
+	case REG_IMI_PGTBL_CTL:
+		state->gtt_enable = (val & 1);
+		switch ((val & 0xf) >> 1) {
+		case 0: state->gtt_size_kb = 512; break;
+		case 1: state->gtt_size_kb = 256; break;
+		case 2: state->gtt_size_kb = 128; break;
+		case 3: case 4: case 5: default:
+			state->gtt_enable = 0; break;
+		}
+		state->gtt_base_addr = (val >> 4 & 0xf) << 32
+		                    || (val & 0xfffff000);
+		break;
+	case REG_IMI_PRB0_TAIL:
+		state->ring.tail = val;
+		//printf("ring tail %x\n", val);
+		state->eventpending |= X3100_EVENT_RING;
+		break;
+	case REG_IMI_PRB0_HEAD:
+		state->ring.headcount = val >> 17;
+		state->ring.head = val & 0x1ffffc;
+		printf("ring head %x count %x\n",
+		       state->ring.head, state->ring.headcount);
+		break;
+	case REG_IMI_PRB0_START:
+		state->ring.start = val;
+		printf("ring start %x\n", state->ring.start);
+		break;
+	case REG_IMI_PRB0_CTL:
+		state->ring.enable = val & 0x1;
+		state->ring.autoreport = (val >> 1) & 0x3;
+		state->ring.length = (((val >> 12) & 0x1ff) + 1) * 4096;
+		printf("ring enable %d autoreport %x length %d (val %x)\n",
+		       state->ring.enable, state->ring.autoreport,
+		       state->ring.length, val);
+		break;
+	case REG_IMI_IER:
+		state->ier = val;
+		printf("ier: %.8x\n", val);
+		break;
+	case REG_IMI_IIR:
+		state->iir = val;
+		printf("iir: %.8x\n", val);
+		break;
+	case REG_IMI_IMR:
+		state->imr = val;
+		printf("imr: %.8x\n", val);
+		break;
+	case REG_IMI_ISR:
+		state->isr = val;
+		printf("isr: %.8x\n", val);
+		break;
+	default:
+		handled = 0;
+		*((uint32_t *) (state->mmio_regs + addr)) = val;
+		break;
+	}
+	//fprintf(out, "imi write at %x <- %x\n", addr, val);
+}
+
+static uint32_t imi_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	int handled = 1;
+
+	switch (addr) {
+	case REG_IMI_PGTBL_CTL:
+		ret = state->gtt_enable == 1;
+		ret |= ((state->gtt_size_kb == 512) ? 0
+		     : (state->gtt_size_kb == 256) ? 1
+		     : (state->gtt_size_kb == 128) ? 2 : 0) << 1;
+		ret |= (state->gtt_base_addr & 0xfffff000);
+		break;
+	case REG_IMI_PRB0_TAIL:
+		ret = state->ring.tail;
+		break;
+	case REG_IMI_PRB0_HEAD:
+		ret = state->ring.headcount << 17 | state->ring.head;
+		break;
+	case REG_IMI_PRB0_START:
+		ret = state->ring.start;
+		break;
+	case REG_IMI_PRB0_CTL:
+		ret = (((state->ring.length / 4096) - 1) << 12)
+		    | (state->ring.autoreport << 1)
+		    | (state->ring.enable);
+		break;
+	case REG_IMI_IER: ret = state->ier; break;
+	case REG_IMI_IIR: ret = state->iir; break;
+	case REG_IMI_IMR: ret = state->imr; break;
+	case REG_IMI_ISR: ret = state->isr; break;
+	default:
+		handled = 0;
+		ret = *((uint32_t *) (state->mmio_regs + addr));
+		break;
+	}
+	//fprintf(out, "imi read at %x (value %x) (handled = %d)\n", addr, ret, handled);
+	return ret;
+}
+
+static mmio_reg_fct imi_mmio =
+{
+	.read = imi_mmio_read,
+	.write = imi_mmio_write,
+};
+
+/********************************************************************/
+static void fence_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	int handled = 1;
+
+	if (addr >= FENCE_START && addr < FENCE_END) {
+		int fence_offset = (addr - FENCE_START) / 8; 
+		switch ((addr - FENCE_START) % 8) {
+		case 0:
+			printf("fence %d start: %.8x\n", fence_offset, val);
+			state->fences[fence_offset].start = val;
+			break;
+		case 1:
+			printf("fence %d end: %.8x\n", fence_offset, val);
+			state->fences[fence_offset].end = val;
+			break;
+		}
+		return;
+	}
+	switch (addr) {
+	default:
+		handled = 0;
+		*((uint32_t *) (state->mmio_regs + addr)) = val;
+		break;
+	}
+}
+
+static uint32_t fence_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	int handled = 1;
+
+	switch (addr) {
+	default:
+		handled = 0;
+		ret = *((uint32_t *) (state->mmio_regs + addr));
+		break;
+	}
+	return ret;
+}
+
+static mmio_reg_fct fence_mmio =
+{
+	.read = fence_mmio_read,
+	.write = fence_mmio_write,
+};
+
+/********************************************************************/
+static void ioc_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	int handled = 1;
+
+	switch (addr) {
+	case REG_IOC_GPIOCTL_0:
+		state->gpioctl[0] = val;
+		break;
+	default:
+		handled = 0;
+		break;
+	}
+}
+
+static uint32_t ioc_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	int handled = 1;
+
+	switch (addr) {
+	case REG_IOC_GPIOCTL_0:
+		return state->gpioctl[0] & ~(0x4 | 0x100 | 0x400);
+		break;
+	default:
+		handled = 0;
+		break;
+	}
+	return ret;
+}
+
+static mmio_reg_fct ioc_mmio =
+{
+	.read = ioc_mmio_read,
+	.write = ioc_mmio_write,
+};
+/********************************************************************/
+
+
+static void display_engine_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	if (addr > REG_DE_TV_start && addr <= REG_DE_TV_end)
+		return;
+	switch (addr) {
+	case REG_DE_HTOTAL_A:
+		printf("htotal: total=%d active=%d\n", (val >> 16) & 0x1fff, val & 0xfff);
+		break;
+	case REG_DE_HBLANK_A:
+		printf("hblank: end=%d start=%d\n", (val >> 16) & 0x1fff, val & 0x1fff);
+		break;
+	case REG_DE_HSYNC_A:
+		printf("hsync: end=%d start=%d\n", (val >> 16) & 0x1fff, val & 0x1fff);
+		break;
+	case REG_DE_VTOTAL_A:
+		printf("vtotal: total=%d active=%d\n", (val >> 16) & 0x1fff, val & 0xfff);
+		break;
+	case REG_DE_VBLANK_A:
+		printf("vblank: end=%d start=%d\n", (val >> 16) & 0x1fff, val & 0x1fff);
+		break;
+	case REG_DE_VSYNC_A:
+		printf("vsync: end=%d start=%d\n", (val >> 16) & 0x1fff, val & 0x1fff);
+		break;
+	case REG_DE_PIPEASRC:
+		printf("pipe size set %dx%d\n", ((val >> 16) & 0xfff) + 1, (val & 0xfff) + 1);
+		state->dsp[0].out_width = ((val >> 16) & 0xfff) + 1;
+		state->dsp[0].out_height = (val & 0xfff) + 1;
+		break;
+	case REG_DE_PORT_HOTPLUG_EN:
+		if (val & 0x8) {
+			*((uint32_t *) (state->mmio_regs + REG_DE_PORT_HOTPLUG_STAT)) = 3 << 8;
+		}
+		break;
+	default:
+		break;
+	}
+	*((uint32_t *) (state->mmio_regs + addr)) = val;
+}
+
+static uint32_t display_engine_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	//if (addr > REG_DE_TV_start && addr <= REG_DE_TV_end)
+	//	return;
+	switch (addr) {
+	case REG_DE_PORT_HOTPLUG_EN:
+		ret = *((uint32_t *) (state->mmio_regs + addr));
+		return ret;
+	case REG_DE_TV_out_control: return 0x20; /* disable TV */
+	}
+	ret = *((uint32_t *) (state->mmio_regs + addr));
+	return ret;
+}
+
+static mmio_reg_fct display_engine_mmio =
+{
+	.read = display_engine_mmio_read,
+	.write = display_engine_mmio_write,
+};
+/********************************************************************/
+
+static void clock_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	*((uint32_t *) (state->mmio_regs + addr)) = val;
+}
+
+static uint32_t clock_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	int handled = 1;
+
+	switch (addr) {
+	case REG_CR_VGA0: ret = REG_CR_VGA0_DEFAULT; break;
+	case REG_CR_VGA1: ret = REG_CR_VGA1_DEFAULT; break;
+	case REG_CR_VGA_PD: ret = REG_CR_VGA_PD_DEFAULT; break;
+	case REG_CR_DPLLA_CTRL: ret = REG_CR_DPLLA_CTRL_DEFAULT; break;
+	case REG_CR_DPLLB_CTRL: ret = REG_CR_DPLLB_CTRL_DEFAULT; break;
+	case REG_CR_DPLLAMD: ret = REG_CR_DPLLAMD_DEFAULT; break;
+	case REG_CR_DPLLBMD: ret = REG_CR_DPLLBMD_DEFAULT; break;
+	case REG_CR_FPA0: ret = REG_CR_FPA0_DEFAULT; break;
+	case REG_CR_FPA1: ret = REG_CR_FPA1_DEFAULT; break;
+	case REG_CR_FPB0: ret = REG_CR_FPB0_DEFAULT; break;
+	case REG_CR_FPB1: ret = REG_CR_FPB1_DEFAULT; break;
+	case REG_CR_DPLL_TEST: ret = REG_CR_DPLL_TEST_DEFAULT; break;
+	case REG_CR_D_STATE: ret = REG_CR_D_STATE_DEFAULT; break;
+	case REG_CR_DSPCLK_GATE_D: ret = REG_CR_DSPCLK_GATE_D_DEFAULT; break;
+	case REG_CR_RENCLK_GATE_D1: ret = REG_CR_RENCLK_GATE_D1_DEFAULT; break;
+	case REG_CR_RENDCLK_GATE_D2: ret = REG_CR_RENDCLK_GATE_D2_DEFAULT; break;
+	case REG_CR_RAMCLK_GATE_D: ret = REG_CR_RAMCLK_GATE_D_DEFAULT; break;
+	default:
+		handled = 0;
+		ret = *((uint32_t *) (state->mmio_regs + addr));
+		break;
+	}
+	return ret;
+}
+
+static mmio_reg_fct clock_mmio =
+{
+	.read = clock_mmio_read,
+	.write = clock_mmio_write,
+};
+
+/********************************************************************/
+static void display_mmio_write(X3100State *state, int addr, uint32_t val)
+{
+	int handled = 1;
+
+	switch (addr) {
+	case REG_DR_VGACNTRL:
+		printf("%sing VGA\n", (val & 0x80000000) ? "disabl" : "enabl");
+		break;
+	case REG_DR_CURACNTR:
+		state->mouse_show = (val & 0x27) != 0;
+		state->eventpending |= X3100_EVENT_MOUSE_UPDATE;
+		break;
+	case REG_DR_CURAPOS:
+		state->mouse_y = ((val & 0x80000000) ? -1 : 1) * ((val >> 16) & 0xfff);
+		state->mouse_x = ((val & 0x8000) ? -1 : 1) * (val & 0xfff);
+		state->eventpending |= X3100_EVENT_MOUSE_UPDATE;
+		break;
+	case REG_DR_DSPACNTR:
+		printf("display: %d gamma: %d format: %d tiled: %d rotated: %d\n",
+		       (val >> 31) & 0x1, (val >> 30) & 0x1,
+		       (val >> 26) & 0xf, (val >> 15 & 0x1),
+		       (val >> 10) & 0x1);
+		state->dsp[0].enable = (val >> 31) & 0x1;
+		state->dsp[0].gamma = (val >> 30) & 0x1;
+		state->dsp[0].format = (val >> 26) & 0xf;
+		state->dsp[0].tiled = (val >> 15) & 0x1;
+		state->dsp[0].rotated = (val >> 10) & 0x1;
+		if (state->dsp[0].enable) {
+			state->eventpending |= X3100_EVENT_RESIZE;
+
+			switch (state->dsp[0].format) {
+			case FORMAT_BGRX_32: state->dsp[0].cpp = 4; break;
+			case FORMAT_BGRX_16: state->dsp[0].cpp = 2; break;
+			default: state->dsp[0].cpp = 4; /* FIXME */
+			}
+
+			state->dsp[0].width = state->dsp[0].stride / state->dsp[0].cpp;
+
+			/* FIXME: hardcoded height based on width.
+			 * need to find a better way to actually have the actual value */
+			switch (state->dsp[0].width) {
+			case 320: state->dsp[0].height = 240; break;
+			case 640: state->dsp[0].height = 480; break;
+			case 800: state->dsp[0].height = 600; break;
+			case 1024: state->dsp[0].height = 768; break;
+			case 1280: state->dsp[0].height = 1024; break;
+			case 1600: state->dsp[0].height = 1200; break;
+			case 1900: state->dsp[0].height = 1200; break;
+			default: state->dsp[0].height = 200;
+			}
+			printf("dsp enabled (width=%d,height=%d,fmt=%d,cpp=%d)\n",
+			       state->dsp[0].width, state->dsp[0].height,
+			       state->dsp[0].format, state->dsp[0].cpp);
+		} else {
+			state->fb_start = state->fb_end = 0;
+		}
+		break;
+	case REG_DR_DSPALINOFF: state->dsp[0].addr_offset = val; break;
+	case REG_DR_DSPASTRIDE: state->dsp[0].stride = val; break;
+	case REG_DR_DSPASURF:
+		state->dsp[0].addr_start = val;
+		state->fb_start = state->mi_start + state->dsp[0].addr_start;
+		state->fb_end = state->fb_start +
+		               (state->dsp[0].stride * state->dsp[0].out_height);
+		printf("framebuffer start: %lx end: %lx\n", state->fb_start, state->fb_end);
+		break;
+	case REG_DR_DSPATILEOFF:
+		printf("tileoff: %x\n", val);
+		break;
+	default:
+		handled = 0;
+		break;
+	}
+	*((uint32_t *) (state->mmio_regs + addr)) = val;
+}
+
+static uint32_t display_mmio_read(X3100State *state, int addr)
+{
+	uint32_t ret;
+	int handled = 1;
+
+	switch (addr) {
+	case REG_DR_DSPALINOFF: ret = state->dsp[0].addr_offset; break;
+	case REG_DR_DSPASURF: ret = state->dsp[0].addr_start; break;
+	default:
+		handled = 0;
+		ret = *((uint32_t *) (state->mmio_regs + addr));
+		break;
+	}
+	return ret;
+}
+
+static mmio_reg_fct display_mmio =
+{
+	.read = display_mmio_read,
+	.write = display_mmio_write,
+};
+
+/********************************************************************/
+struct mmio_reg_range mmio_regs_table[23];
+
+void x3100_regs_init(X3100State *state)
+{
+	state->gpioctl[0] = 0x808;
+	state->imr = 0xfffedfff;
+	state->mmio_regs = malloc(512 * 1024);
+	memset(state->mmio_regs, '\0', 512 * 1024);
+
+	/* FIXME: would be better as some kind of radix tree */
+	#define D(i,s,e,d,f)	mmio_regs_table[i].start = s; \
+				mmio_regs_table[i].end = e; \
+				mmio_regs_table[i].fct = &f; \
+				mmio_regs_table[i].desc = d
+	D(0,  0x00000, 0x00FFF, "VGA", unimplemented_mmio);
+	D(1,  0x01000, 0x01FFF, "reserved", reserved_mmio);
+	D(2,  0x02000, 0x02FFF, "Instruction/Memory/Interrupt", imi_mmio);
+	D(3,  0x03000, 0x031FF, "Fence & PP GTT control", fence_mmio);
+	D(4,  0x03200, 0x03FFF, "Frame buffer compression", unimplemented_mmio);
+	D(5,  0x04000, 0x043FF, "reserved", reserved_mmio);
+	D(6,  0x04400, 0x04FFF, "reserved", reserved_mmio);
+	D(7,  0x05000, 0x05FFF, "I/O control", ioc_mmio);
+	D(8,  0x06000, 0x06FFF, "Clock control", clock_mmio);
+	D(9,  0x07000, 0x073FF, "3D internal debug", unimplemented_mmio);
+	D(10, 0x07400, 0x088FF, "GPE debug", unimplemented_mmio);
+	D(11, 0x08900, 0x08FFF, "reserved", reserved_mmio);
+	D(12, 0x09000, 0x09FFF, "reserved", reserved_mmio);
+	D(13, 0x0A000, 0x0AFFF, "Display palette", unimplemented_mmio);
+	D(14, 0x0B000, 0x0FFFF, "reserved", reserved_mmio);
+	D(15, 0x10000, 0x13FFF, "MMIO MCHBAR", unimplemented_mmio);
+	D(16, 0x14000, 0x2FFFF, "reserved", reserved_mmio);
+	D(17, 0x30000, 0x3FFFF, "Overlay", unimplemented_mmio);
+	D(18, 0x40000, 0x5FFFF, "reserved", reserved_mmio);
+	D(19, 0x60000, 0x6FFFF, "Display engine pipeline", display_engine_mmio);
+	D(20, 0x70000, 0x72FFF, "Display and cursor", display_mmio);
+	D(21, 0x73000, 0x73FFF, "Performance counters", unimplemented_mmio);
+	D(22, 0x74000, 0x7FFFF, "reserved", reserved_mmio);
+	#undef D
+}
+
+
+static struct mmio_reg_range * get_reg_range(int addr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mmio_regs_table); i++)
+		if (addr >= mmio_regs_table[i].start &&
+		    addr <= mmio_regs_table[i].end)
+			break;
+	return (i < ARRAY_SIZE(mmio_regs_table)) ? &mmio_regs_table[i] : NULL;
+}
+
+void x3100_regs_write(X3100State *state, int addr, uint32_t val)
+{
+	struct mmio_reg_range *range;
+	
+	range = get_reg_range(addr);
+	if (!range)
+		return;
+	x3100_dbg(DBG_CLASS_REG, "REG: w(%x,%x)   [%s]\n", addr, val, range->desc);
+	(range->fct->write)(state, addr, val);
+
+	/* check if we got events, and process them if any */
+	if (state->eventpending) {
+		if ((state->eventpending & X3100_EVENT_MOUSE_UPDATE) &&
+		    (state->ds->mouse_set != NULL)) {
+			state->ds->mouse_set(state->mouse_x, state->mouse_y, state->mouse_show);
+		}
+
+		if ((state->eventpending & X3100_EVENT_RESIZE) &&
+		    (state->ds->dpy_resize != NULL)) {
+			state->ds->dpy_resize(state->ds,
+			                      state->dsp[0].out_width,
+			                      state->dsp[0].out_height);
+		}
+
+		if (state->eventpending & X3100_EVENT_RING) {
+			x3100_ring_process(state);
+		}
+		/* reset the event pending */
+		state->eventpending = 0;
+	}
+}
+
+uint32_t x3100_regs_read(X3100State *state, int addr)
+{
+	struct mmio_reg_range *range;
+	uint32_t ret;
+	static int previous_addr = -1;
+	static int previous_ret = -1;
+	static int last_previous = 0;
+
+	range = get_reg_range(addr);
+	if (!range)
+		return 0xdeadbeef;
+	ret = (range->fct->read)(state, addr);
+	if (addr != previous_addr || previous_ret != ret) {
+		if (last_previous > 0)
+			x3100_dbg(DBG_CLASS_REG, "REG: last read repeated %d times\n",
+			                         last_previous);
+		x3100_dbg(DBG_CLASS_REG, "REG: r(%x) = %x   [%s]\n", addr, ret, range->desc);
+		previous_addr = addr;
+		previous_ret = ret;
+		last_previous = 0;
+	} else
+		last_previous++;
+	return ret;
+}
+
+static uint32_t x3100_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+	addr &= 0x7ffff;
+	if (addr >= 0 && addr < 0x1000)
+		return x3100_vga_ioport_read(opaque, addr);
+		
+	printf("MMIO R(1) = %lx\n", addr);
+	return -1;
+}
+
+static uint32_t x3100_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+	uint32_t ret;
+
+	addr &= 0x7ffff;
+	ret = x3100_regs_read(opaque, addr & ~0x3);
+	switch (addr % 2) {
+	case 0: ret &= 0xffff; break;
+	case 1: ret >>= 16; break;
+	}
+	return ret;
+}
+
+static uint32_t x3100_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+	addr &= 0x7ffff;
+	return x3100_regs_read(opaque, addr);
+}
+
+static void x3100_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	addr &= 0x7ffff;
+	if (addr >= 0 && addr < 0x1000) {
+		x3100_vga_ioport_write(opaque, addr, val);
+		return;
+	}
+	printf("MMIO W(1) = %lx -> %x\n", addr, val);
+}
+
+static void x3100_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	uint32_t ret;
+	addr &= 0x7ffff;
+	ret = x3100_regs_read(opaque, addr & ~0x3);
+	switch (addr % 2) {
+	case 0: val = (ret & ~0xffff) | (val & 0xffff); break;
+	case 1: val = (ret & 0xffff) | (val << 16); break;
+	}
+	x3100_regs_write(opaque, addr & ~0x3, val);
+}
+
+static void x3100_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	addr &= 0x7ffff;
+	x3100_regs_write(opaque, addr, val);
+}
+
+CPUReadMemoryFunc *x3100_mmio_read[3] = {
+	x3100_mmio_readb, x3100_mmio_readw, x3100_mmio_readl,
+};
+
+CPUWriteMemoryFunc *x3100_mmio_write[3] = {
+	x3100_mmio_writeb, x3100_mmio_writew, x3100_mmio_writel,
+};
diff --git a/hw/x3100_regs.h b/hw/x3100_regs.h
new file mode 100644
index 0000000..4cd9493
--- /dev/null
+++ b/hw/x3100_regs.h
@@ -0,0 +1,206 @@
+#ifndef QEMU_X3100_REGS_H
+#define QEMU_X3100_REGS_H
+
+/* instruction memory interrupt */
+#define REG_IMI_PGTBL_CTL		0x02020
+#define REG_IMI_PGTBL_ER		0x02024
+#define REG_IMI_EXCC			0x02028
+#define REG_IMI_PRB0_TAIL		0x02030
+#define REG_IMI_PRB0_HEAD		0x02034
+#define REG_IMI_PRB0_START		0x02038
+#define REG_IMI_PRB0_CTL		0x0203C
+#define REG_IMI_HW_MEMRD		0x02060
+#define REG_IMI_IPEIR			0x02064
+#define REG_IMI_IPEHR			0x02068
+#define REG_IMI_INSTDONE		0x0206C
+#define REG_IMI_INSTPS			0x02070
+#define REG_IMI_ACTHD			0x02074
+#define REG_IMI_DMA_FADD_P		0x02078
+#define REG_IMI_INSTDONE_1		0x0207C
+#define REG_IMI_HWS_PGA			0x02080
+#define REG_IMI_PWRCTXA			0x02088
+#define REG_IMI_NOPID			0x02094
+#define REG_IMI_HWSTAM			0x02098
+#define REG_IMI_MI_MODE			0x0209C
+#define REG_IMI_IER			0x020A0
+#define REG_IMI_IIR			0x020A4
+#define REG_IMI_IMR			0x020A8
+#define REG_IMI_ISR			0x020AC
+#define REG_IMI_EIR			0x020B0
+#define REG_IMI_EMR			0x020B4
+#define REG_IMI_ESR			0x020B8
+#define REG_IMI_INSTPM			0x020C0
+#define REG_IMI_PGTBL_CTL2		0x020C4
+#define REG_IMI_PGTBL_STR2		0x020C8
+#define REG_IMI_MI_DISPLAY_POWER_DOWN	0x020E0
+#define REG_IMI_MI_ARB_STATE		0x020E4
+#define REG_IMI_MI_RDRET_STATE		0x020FC
+#define REG_IMI_CACHE_MODE_0		0x02120
+#define REG_IMI_CACHE_MODE_1		0x02124
+#define REG_IMI_UHPTR			0x02134
+#define REG_IMI_BB_ADDR			0x02140
+#define REG_IMI_BB_STATE		0x02148
+#define REG_IMI_GFX_FLSH_CNTL		0x02170
+#define REG_IMI_CCID0			0x02180
+#define REG_IMI_CXT_SIZE		0x021A0
+#define REG_IMI_CXT_SIZE_NOEXT		0x021A4
+#define REG_IMI_ECOSKPD			0x021D0
+#define REG_IMI_CSFLFSM			0x02200
+#define REG_IMI_CSFLFLAG		0x02204
+#define REG_IMI_CSFLTRK			0x02208
+#define REG_IMI_CSCMDOP			0x0220C
+#define REG_IMI_CSCMDVLD		0x02210
+#define REG_IMI_PS_DEPTH_COUNT		0x02350
+#define REG_IMI_TIMESTAMP		0x02358
+#define REG_IMI_CLKCMP			0x02360
+#define REG_IMI_VFDC			0x02450
+#define REG_IMI_VFSKPD			0x02470
+
+#define FENCE_START			0x03000
+#define FENCE_END			0x0307F
+
+/* gmbus & io control */
+#define REG_IOC_GPIOCTL_0		0x05010
+#define REG_IOC_GPIOCTL_1		0x05014
+#define REG_IOC_GPIOCTL_2		0x05018
+#define REG_IOC_GPIOCTL_3		0x0501C
+#define REG_IOC_GPIOCTL_4		0x05020
+#define REG_IOC_GPIOCTL_5		0x05024
+#define REG_IOC_GPIOCTL_6		0x05028
+#define REG_IOC_GPIOCTL_7		0x0502C
+
+/* clock */
+#define REG_CR_VGA0                     0x06000
+#define REG_CR_VGA0_DEFAULT             0x00031108
+#define REG_CR_VGA1                     0x06004
+#define REG_CR_VGA1_DEFAULT             0x00031406
+#define REG_CR_VGA_PD                   0x06010
+#define REG_CR_VGA_PD_DEFAULT           0x00020002
+#define REG_CR_DPLLA_CTRL               0x06014
+#define REG_CR_DPLLA_CTRL_DEFAULT       0x04020C00
+#define REG_CR_DPLLB_CTRL               0x06018
+#define REG_CR_DPLLB_CTRL_DEFAULT       0x04020C00
+#define REG_CR_DPLLAMD                  0x0601C
+#define REG_CR_DPLLAMD_DEFAULT          0x00000003
+#define REG_CR_DPLLBMD                  0x06020
+#define REG_CR_DPLLBMD_DEFAULT          0x00000003
+#define REG_CR_FPA0                     0x06040
+#define REG_CR_FPA0_DEFAULT             0x00031108
+#define REG_CR_FPA1                     0x06044
+#define REG_CR_FPA1_DEFAULT             0x00031108
+#define REG_CR_FPB0                     0x06048
+#define REG_CR_FPB0_DEFAULT             0x00031108
+#define REG_CR_FPB1                     0x0604C
+#define REG_CR_FPB1_DEFAULT             0x00031108
+#define REG_CR_DPLL_TEST                0x0606C
+#define REG_CR_DPLL_TEST_DEFAULT        0x00010001
+#define REG_CR_D_STATE                  0x06104
+#define REG_CR_D_STATE_DEFAULT          0x00000000
+#define REG_CR_DSPCLK_GATE_D            0x06200
+#define REG_CR_DSPCLK_GATE_D_DEFAULT    0x10000000
+#define REG_CR_RENCLK_GATE_D1           0x06204
+#define REG_CR_RENCLK_GATE_D1_DEFAULT   0x00000000
+#define REG_CR_RENDCLK_GATE_D2          0x06208
+#define REG_CR_RENDCLK_GATE_D2_DEFAULT  0x00000000
+#define REG_CR_RAMCLK_GATE_D            0x06210
+#define REG_CR_RAMCLK_GATE_D_DEFAULT    0x00000000
+
+/* display engine */
+#define REG_DE_HTOTAL_A		0x60000
+#define REG_DE_HBLANK_A		0x60004
+#define REG_DE_HSYNC_A		0x60008
+#define REG_DE_VTOTAL_A		0x6000C
+#define REG_DE_VBLANK_A		0x60010
+#define REG_DE_VSYNC_A		0x60014
+#define REG_DE_PIPEASRC		0x6001C
+#define REG_DE_BCLRPAT_A	0x60020
+#define REG_DE_VSYNCSHIFT_A	0x60028
+#define REG_DE_CRCCtrlColorA	0x60050
+#define REG_DE_HTOTAL_B		0x61000
+#define REG_DE_HBLANK_B		0x61004
+#define REG_DE_HSYNC_B		0x61008
+#define REG_DE_VTOTAL_B		0x6100C
+#define REG_DE_VBLANK_B		0x61010
+#define REG_DE_VSYNC_B		0x61014
+#define REG_DE_PIPEBSRC		0x6101C
+#define REG_DE_BCLRPAT_B	0x61020
+#define REG_DE_VSYNCSHIFT_B	0x61028
+
+
+#define REG_DE_ADPA		0x61100
+#define REG_DE_PORT_HOTPLUG_EN	0x61110
+#define REG_DE_PORT_HOTPLUG_STAT 0x61114
+
+#define REG_DE_TV_start		0x68000
+#define REG_DE_TV_out_control 	REG_DE_TV_start
+#define REG_DE_TV_end		0x68500
+
+/* display register */
+#define REG_DR_PIPEA_DSL	0x70000
+#define REG_DR_PIPEA_SLC	0x70004
+#define REG_DR_PIPEACONF	0x70008
+
+#define REG_DR_CURACNTR		0x70080
+#define REG_DR_CURABASE		0x70084
+#define REG_DR_CURAPOS		0x70088
+
+#define REG_DR_DSPACNTR		0x70180
+#define REG_DR_DSPALINOFF	0x70184
+#define REG_DR_DSPASTRIDE	0x70188
+#define REG_DR_DSPAKEYVAL	0x70194
+#define REG_DR_DSPAKEYMSK	0x70198
+#define REG_DR_DSPASURF		0x7019C
+#define REG_DR_DSPATILEOFF	0x701A4
+#define REG_DR_DSPAFLPQSTAT	0x70200
+
+#define REG_DR_SWF00		0x70410
+#define REG_DR_SWF01		0x70414
+#define REG_DR_SWF02		0x70418
+#define REG_DR_SWF03		0x7041C
+#define REG_DR_SWF04		0x70420
+#define REG_DR_SWF05		0x70424
+#define REG_DR_SWF06		0x70428
+#define REG_DR_SWF07		0x7042C
+#define REG_DR_SWF08		0x70430
+#define REG_DR_SWF09		0x70434
+#define REG_DR_SWF0A		0x70438
+#define REG_DR_SWF0B		0x7043C
+#define REG_DR_SWF0C		0x70440
+#define REG_DR_SWF0D		0x70444
+#define REG_DR_SWF0E		0x70448
+#define REG_DR_SWF0F		0x7044C
+
+#define REG_DR_DSPBCNTR		0x71180
+#define REG_DR_DSPBLINOFFSET	0x71184
+#define REG_DR_DSPBSTRIDE	0x71188
+#define REG_DR_DSPBKEYVAL	0x71194
+#define REG_DR_DSPBKEYMSK	0x71198
+#define REG_DR_DSPBSURF		0x7119C
+#define REG_DR_DSPBTILEOFF	0x711A4
+#define REG_DR_DSPBFLPQSTAT	0x71200
+
+#define REG_DR_VGACNTRL		0x71400
+#define REG_DR_SWF10		0x71410
+#define REG_DR_SWF11		0x71414
+#define REG_DR_SWF12		0x71418
+#define REG_DR_SWF13		0x7141C
+#define REG_DR_SWF14		0x71420
+#define REG_DR_SWF15		0x71424
+#define REG_DR_SWF16		0x71428
+#define REG_DR_SWF17		0x7142C
+#define REG_DR_SWF18		0x71430
+#define REG_DR_SWF19		0x71434
+#define REG_DR_SWF1A		0x71438
+#define REG_DR_SWF1B		0x7143C
+#define REG_DR_SWF1C		0x71440
+#define REG_DR_SWF1D		0x71444
+#define REG_DR_SWF1E		0x71448
+#define REG_DR_SWF1F		0x7144C
+#define REG_DR_SWF30		0x72414
+#define REG_DR_SWF31		0x72418
+#define REG_DR_SWF32		0x7241C
+
+#define FORMAT_BGRX_16		0x5
+#define FORMAT_BGRX_32		0x6
+
+#endif
diff --git a/hw/x3100_vga.c b/hw/x3100_vga.c
new file mode 100644
index 0000000..31295e3
--- /dev/null
+++ b/hw/x3100_vga.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2008 Vincent Hanquez
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * QEMU Intel X3100 emulation
+ * VGA Part copied from vga.c, but different file to add later
+ * proper hooks to interact with the X3100 in VGA mode.
+ *
+ */
+#include "x3100.h"
+
+uint32_t x3100_vga_ioport_read(void *opaque, uint32_t addr)
+{
+	X3100State *s = opaque;
+	int v;
+	switch (addr) {
+	case 0x3c0: return (s->ar_flip_flop == 0) ? s->ar_index : 0;
+	case 0x3c1: return ((s->ar_index & 0x1f) < 21) ? s->ar[s->ar_index & 0x1f] : 0;
+	case 0x3c2: return s->st00; 
+	case 0x3c4: return s->sr_index;
+	case 0x3c5: return s->sr[s->sr_index];
+	case 0x3c7: return s->dac_state;
+	case 0x3c8: return s->dac_write_index;
+	case 0x3c9:
+		v = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
+		if (++s->dac_sub_index == 3) {
+			s->dac_sub_index = 0; s->dac_read_index++;
+		}
+		return v;
+	case 0x3ca: return s->fcr;
+	case 0x3cc: return s->msr;
+	case 0x3ce: return s->gr_index;
+	case 0x3cf: return s->gr[s->gr_index];
+	case 0x3b4: case 0x3d4: return s->cr_index;
+	case 0x3b5: case 0x3d5: return s->cr[s->cr_index];
+	case 0x3ba: case 0x3da:
+		s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
+		v = s->st01;
+		s->ar_flip_flop = 0;
+		return v;
+	default:
+		printf("vga ioport R: %x\n", addr);
+		return 0xff;
+	}
+}
+
+void x3100_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+	X3100State *s = opaque;
+	int index;
+
+	switch (addr) {
+	case 0x3c0:
+		if (s->ar_flip_flop == 0) {
+			val &= 0x3f;
+			s->ar_index = val;
+		} else {
+			index = s->ar_index & 0x1f;
+			switch (index) {
+				case 0x00 ... 0x0f:
+					s->ar[index] = val & 0x3f;
+					break;
+				case 0x10:
+					s->ar[index] = val & ~0x10;
+					break;
+				case 0x11:
+					s->ar[index] = val;
+					break;
+				case 0x12:
+					s->ar[index] = val & ~0xc0;
+					break;
+				case 0x13:
+					s->ar[index] = val & ~0xf0;
+					break;
+				case 0x14:
+					s->ar[index] = val & ~0xf0;
+					break;
+				default:
+					break;
+			}
+		}
+		s->ar_flip_flop ^= 1;
+		break;
+	case 0x3c2:
+		s->msr = val & ~0x10;
+		break;
+	case 0x3c4:
+		s->sr_index = val;
+		break;
+	case 0x3c5:
+		s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+		break;
+	case 0x3c7:
+		s->dac_read_index = val;
+		s->dac_sub_index = 0;
+		s->dac_state = 3;
+		break;
+	case 0x3c8:
+		s->dac_write_index = val;
+		s->dac_sub_index = 0;
+		s->dac_state = 0;
+		break;
+	case 0x3c9:
+		s->dac_cache[s->dac_sub_index] = val;
+		if (++s->dac_sub_index == 3) {
+			memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
+			s->dac_sub_index = 0;
+			s->dac_write_index++;
+		}
+		break;
+	case 0x3ce:
+		s->gr_index = val;
+		break;
+	case 0x3cf:
+		s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+		break;
+	case 0x3b4:
+	case 0x3d4:
+		s->cr_index = val;
+		break;
+	case 0x3b5:
+	case 0x3d5:
+		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);
+			return;
+		}
+		switch (s->cr_index) {
+			case 0x01: /* horizontal display end */
+			case 0x07:
+			case 0x09:
+			case 0x0c:
+			case 0x0d:
+			case 0x12: /* vertical display end */
+				s->cr[s->cr_index] = val;
+				break;
+
+			default:
+				s->cr[s->cr_index] = val;
+				break;
+		}
+		break;
+	case 0x3ba:
+	case 0x3da:
+		s->fcr = val & 0x10;
+		break;
+	default:
+		printf("vga ioport W: %x:%x\n", addr, val);
+	}
+}
+
+static uint32_t x3100_vga_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+	X3100State *s = opaque;
+	return vga_mem_readb(s, addr);
+}
+
+static uint32_t x3100_vga_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+	uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+	v = x3100_vga_mem_readb(opaque, addr) << 8;
+	v |= x3100_vga_mem_readb(opaque, addr + 1);
+#else
+	v = x3100_vga_mem_readb(opaque, addr);
+	v |= x3100_vga_mem_readb(opaque, addr + 1) << 8;
+#endif
+	return v;
+}
+
+static uint32_t x3100_vga_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+	uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+	v = x3100_vga_mem_readb(opaque, addr) << 24;
+	v |= x3100_vga_mem_readb(opaque, addr + 1) << 16;
+	v |= x3100_vga_mem_readb(opaque, addr + 2) << 8;
+	v |= x3100_vga_mem_readb(opaque, addr + 3);
+#else
+	v = x3100_vga_mem_readb(opaque, addr);
+	v |= x3100_vga_mem_readb(opaque, addr + 1) << 8;
+	v |= x3100_vga_mem_readb(opaque, addr + 2) << 16;
+	v |= x3100_vga_mem_readb(opaque, addr + 3) << 24;
+#endif
+	return v;
+}
+
+static void x3100_vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	X3100State *s = opaque;
+	vga_mem_writeb(s, addr, val);
+        return;
+}
+
+static void x3100_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+	x3100_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 1, val & 0xff);
+#else
+	x3100_vga_mem_writeb(opaque, addr, val & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+#endif
+}
+
+static void x3100_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+	x3100_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 3, val & 0xff);
+#else
+	x3100_vga_mem_writeb(opaque, addr, val & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+	x3100_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+#endif
+}
+
+CPUReadMemoryFunc *x3100_vga_mem_read[3] = {
+	x3100_vga_mem_readb, x3100_vga_mem_readw, x3100_vga_mem_readl,
+};
+
+CPUWriteMemoryFunc *x3100_vga_mem_write[3] = {
+	x3100_vga_mem_writeb, x3100_vga_mem_writew, x3100_vga_mem_writel,
+};
diff --git a/sysemu.h b/sysemu.h
index 0f18e04..fe6baf7 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -76,6 +76,8 @@ void do_info_slirp(void);
 extern int ram_size;
 extern int bios_size;
 extern int cirrus_vga_enabled;
+extern int x3100_enabled;
+extern int x3100_debug;
 extern int vmsvga_enabled;
 extern int graphic_width;
 extern int graphic_height;
diff --git a/vl.c b/vl.c
index 82f84db..b848873 100644
--- a/vl.c
+++ b/vl.c
@@ -183,6 +183,8 @@ int vm_running;
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
+int x3100_enabled = 0;
+int x3100_debug = 0;
 int vmsvga_enabled = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
@@ -7713,6 +7715,7 @@ static void help(int exitcode)
 #ifdef TARGET_I386
            "-std-vga        simulate a standard VGA card with VESA Bochs Extensions\n"
            "                (default is CL-GD5446 PCI VGA)\n"
+           "-x3100          simulate a x3100 graphic card\n"
            "-no-acpi        disable ACPI\n"
 #endif
 #ifdef CONFIG_CURSES
@@ -7805,6 +7808,8 @@ enum {
     QEMU_OPTION_vmsvga,
     QEMU_OPTION_g,
     QEMU_OPTION_std_vga,
+    QEMU_OPTION_x3100,
+    QEMU_OPTION_x3100_debug,
     QEMU_OPTION_echr,
     QEMU_OPTION_monitor,
     QEMU_OPTION_serial,
@@ -7904,6 +7909,8 @@ const QEMUOption qemu_options[] = {
 #endif
     { "localtime", 0, QEMU_OPTION_localtime },
     { "std-vga", 0, QEMU_OPTION_std_vga },
+    { "x3100", 0, QEMU_OPTION_x3100 },
+    { "x3100-dbg", 0, QEMU_OPTION_x3100_debug },
     { "echr", HAS_ARG, QEMU_OPTION_echr },
     { "monitor", HAS_ARG, QEMU_OPTION_monitor },
     { "serial", HAS_ARG, QEMU_OPTION_serial },
@@ -8598,6 +8605,14 @@ int main(int argc, char **argv)
                 cirrus_vga_enabled = 0;
                 vmsvga_enabled = 0;
                 break;
+            case QEMU_OPTION_x3100:
+                cirrus_vga_enabled = 0;
+                x3100_enabled = 1;
+		vga_ram_size += X3100_RAM_SIZE;
+                break;
+	    case QEMU_OPTION_x3100_debug:
+	        x3100_debug = 1;
+		break;
             case QEMU_OPTION_g:
                 {
                     const char *p;

             reply	other threads:[~2008-03-20 19:35 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-20 19:32 Vincent Hanquez [this message]
2008-07-01 11:47 ` [Qemu-devel] qemu X3100 project René Rebe
2008-07-02  9:54   ` Vincent Hanquez
2008-07-02 11:13     ` Alexey Eremenko
2008-07-02 11:51       ` René Rebe
2008-07-02 14:54       ` Vincent Hanquez
2008-07-18 13:37         ` Alexander Graf
2008-07-20 19:20           ` Vincent Hanquez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080320193240.GA1058@snarc.org \
    --to=tab@snarc.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).