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 +#include +#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;