All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bob Breuer <breuerr@mc.net>
To: qemu-devel@nongnu.org
Cc: Blue Swirl <blauwirbel@gmail.com>,
	Artyom Tarasenko <atar4qemu@googlemail.com>
Subject: Re: [Qemu-devel] cg14
Date: Tue, 13 Jul 2010 11:26:31 -0500	[thread overview]
Message-ID: <4C3C93B7.9020804@mc.net> (raw)
In-Reply-To: <AANLkTimDsHuyuK1Ul-L8N_Uh7o-11_xzcVe-dLhH5SPV@mail.gmail.com>

Another preview of the cg14 framebuffer.

Activate by selecting SS-20 machine and setting width > 1024, i.e. "-M SS-20 -g 1152x900".
Note that NetBSD assumes 1152x900, while OBP also supports 1024x768, 1280x1024, and 1600x1280.

New since last time:
- All video memory accesses implemented
    X under linux now works (uses RGB instead of XRGB space)
- Hooked into qdev

Todo:
- fix NetBSD display
- add draw_line templates to handle other than 32-bit RGB host displays
- use VGA_DIRTY tracking
    - What's the equivalent of stb_p that also sets the dirty bits?
- inform OpenBIOS of cg14 framebuffer
    - Can we pass "nvalias screen /obio/cgfourteen" to the firmware?

Bob

---
 Makefile.target |    1 +
 hw/cg14.c       |  850 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/sun4m.c      |   22 ++
 3 files changed, 873 insertions(+), 0 deletions(-)
 create mode 100644 hw/cg14.c

diff --git a/Makefile.target b/Makefile.target
index 3ef4666..54a2ae4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -255,6 +255,7 @@ else
 obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
 obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
+obj-sparc-y += cg14.o
 endif
 
 obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
diff --git a/hw/cg14.c b/hw/cg14.c
new file mode 100644
index 0000000..533dc04
--- /dev/null
+++ b/hw/cg14.c
@@ -0,0 +1,850 @@
+/*
+ * QEMU CG14 Frame buffer
+ *
+ * Copyright (c) 2010 Bob Breuer  <breuerr@mc.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "console.h"
+#include "sysbus.h"
+#include "qdev-addr.h"
+
+//#define DEBUG_CG14
+//#define DEBUG_DAC
+//#define DEBUG_CONFIG
+
+/*
+ * Sun CG14 framebuffer (without SX)
+ *   CG14 = vsimm framebuffer (video ram and dac)
+ *   SX = pixel processor (acceleration) built into chipset
+ *
+ * Documentation: not publicly documented by Sun
+ *   linux driver: drivers/video/cg14.c
+ *   NetBSD/OpenBSD: src/sys/arch/sparc/dev/cgfourteen*
+ *
+ * Takes up one memory slot:
+ *   A[28:26] = slot number (4 to 7)
+ *   regs: size   0x10000 @ 0x09c000000  (0x80000000 + slot * 64M)
+ *   vmem: size upto 16MB @ 0x0fc000000  (0xE0000000 + slot * 64M)
+ *
+ * SS-20 OBP only supports slots 7 (onboard output) and 4 (AVB output)
+ *
+ * memory map:
+ * reg+0x0000 = control registers
+ * reg+0x1000 = cursor registers
+ * reg+0x2000 = dac registers (ADV7152)
+ * reg+0x3000 = xlut
+ * reg+0x4000 = clut1
+ * reg+0x5000 = clut2
+ * reg+0x6000 = clut3 (if implemented)
+ * reg+0xf000 = autoinc
+ *
+ * mem+0x0000000 = XBGR (01234567)
+ * mem+0x1000000 = BGR  (.123.567)  writes to X are blocked, reads are ok
+ * mem+0x2000000 = X16  (0246)
+ * mem+0x2800000 = C16  (1357)
+ * mem+0x3000000 = X32  (04)
+ * mem+0x3400000 = B32  (15)
+ * mem+0x3800000 = G32  (26)
+ * mem+0x3c00000 = R32  (37)
+ */
+
+#define CG14_REG_SIZE         0x10000
+#define CG14_VMEM_SLOTSIZE    (64<<20)
+
+#define CG14_MONID_1024x768   0
+#define CG14_MONID_1600x1280  1
+#define CG14_MONID_1280x1024  2
+#define CG14_MONID_1152x900   7
+
+#define CG14_MONID_DEFAULT    CG14_MONID_1024x768
+
+
+#define CG14_MCR_INTENABLE     0x80
+#define CG14_MCR_VIDENABLE     0x40
+#define CG14_MCR_PIXMODE_MASK  0x30
+#define   CG14_MCR_PIXMODE_8     0x00
+#define   CG14_MCR_PIXMODE_16    0x20  /* 8+8 (X16,C16) */
+#define   CG14_MCR_PIXMODE_32    0x30  /* XBGR */
+
+
+#ifdef DEBUG_CG14
+#define DPRINTF(fmt, ...)                                       \
+    printf("CG14: " fmt , ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#ifdef DEBUG_DAC
+#define DPRINTF_DAC(fmt, ...)                                   \
+    printf("CG14 dac: " fmt , ## __VA_ARGS__)
+#else
+#define DPRINTF_DAC(fmt, ...)
+#endif
+
+#ifdef DEBUG_CONFIG
+#define DPRINTF_CONFIG(fmt, ...)                                \
+    printf("CG14: " fmt , ## __VA_ARGS__)
+#else
+#define DPRINTF_CONFIG(fmt, ...)
+#endif
+
+#define CG14_INFO(fmt, ...)                                     \
+    do { printf("CG14: " fmt , ## __VA_ARGS__); } while (0)
+#define CG14_ERROR(fmt, ...)                                    \
+    do { printf("CG14: " fmt , ## __VA_ARGS__); } while (0)
+
+
+struct dac_state {
+    uint8_t mode;
+    uint8_t address;
+    int rgb_seq;
+};
+
+typedef struct CG14State {
+    SysBusDevice busdev;
+    DisplayState *ds;
+
+    target_phys_addr_t vram_addr;
+    uint8_t *vram;
+    uint32_t vram_size;
+    uint32_t vram_amask;
+    uint16_t width, height;
+    int dirty, size_changed;
+    struct {
+        uint8_t mcr;
+        uint8_t ppr;
+        uint8_t msr;
+    } ctrl;
+    struct dac_state dac;
+    struct {
+        uint16_t hblank_start;
+        uint16_t hblank_clear;
+        uint16_t vblank_start;
+        uint16_t vblank_clear;
+    } timing;
+    uint8_t xlut[256];
+    uint32_t clut1[256];
+    uint32_t clut2[256];
+} CG14State;
+
+static void cg14_screen_dump(void *opaque, const char *filename);
+static void cg14_invalidate_display(void *opaque);
+
+static inline uint32_t bgr_to_rgb(uint32_t bgr)
+{
+    uint32_t rgb;
+
+    /* swap r & b */
+    rgb = (bgr & 0x00FF00)
+        | (bgr & 0x0000FF) << 16
+        | (bgr & 0xFF0000) >> 16;
+    return rgb;
+}
+
+typedef void draw_line_func(const CG14State *s, void *dst, const uint8_t *src);
+
+// TODO: draw_line templates
+static void cg14_draw_line32_rgb32(const CG14State *s, void *dst, const uint8_t *src)
+{
+    unsigned int i;
+    unsigned int x, r, g, b;
+    uint8_t xlut_val;
+    uint32_t dval;
+
+    for (i=0; i<s->width; i++) {
+        x = src[0];
+        b = src[1];
+        g = src[2];
+        r = src[3];
+        xlut_val = s->xlut[x];
+        src += 4;
+
+        if (xlut_val == 0x40) {
+            dval = bgr_to_rgb(s->clut1[x]);
+        } else {
+            /* xlut = 0x00 for true-color */
+            /* possible blending between 2 colors */
+            /* fallback to true-color just to display something if unimplemented */
+            dval = r << 16 | g << 8 | b;
+        }
+        /* dac lookup ? */
+
+        /* to surface format */
+        //dval = is_bgr ? (abgr & 0xFFFFFF) : bgr_to_rgb(abgr);
+        ((uint32_t*)dst)[i] = dval;
+    }
+}
+
+static void cg14_draw_line16_rgb32(const CG14State *s, void *dst, const uint8_t *src)
+{
+    unsigned int i;
+    unsigned int x, c;
+    uint8_t xlut_val;
+    uint32_t dval;
+
+    for (i=0; i<s->width; i++) {
+        x = src[0];
+        c = src[1];
+        xlut_val = s->xlut[x];
+        src += 2;
+
+        if (xlut_val == 0x40) {
+            dval = bgr_to_rgb(s->clut1[x]);
+        } else {
+            /* possible blending between 2 colors */
+            /* fallback to green/blue just to display something if unimplemented */
+            dval = x << 8 | c;
+        }
+        /* dac lookup ? */
+
+        ((uint32_t*)dst)[i] = dval;
+    }
+}
+
+static void cg14_draw_line8_rgb32(const CG14State *s, void *dst, const uint8_t *src)
+{
+    int i;
+    const uint32_t *clut;
+    uint32_t *dst32 = dst;
+
+    if (s->ctrl.ppr == 0x40) {
+        clut = s->clut1;
+        for (i=0; i<s->width; i++) {
+            dst32[i] = bgr_to_rgb(clut[src[i]]);
+        }
+    } else {
+        /* FIXME: other xlut modes, just use grayscale ramp for now */
+        for (i=0; i<s->width; i++) {
+            dst32[i] = 0x010101 * src[i];
+        }
+    }
+}
+
+/* TODO: use VGA_DIRTY_FLAG */
+static void cg14_update_display(void *opaque)
+{
+    CG14State *s = opaque;
+    int h, src_linesize;
+    uint8_t *pix;
+    uint8_t *data;
+    int new_width, new_height;
+    draw_line_func * draw_line;
+
+    if (s->size_changed) {
+        new_width = 4 * (s->timing.hblank_start - s->timing.hblank_clear);
+        new_height = s->timing.vblank_start - s->timing.vblank_clear;
+        s->size_changed = 0;
+        if ((new_width != s->width || new_height != s->height) && new_width > 0 && new_height > 0) {
+            s->width = new_width;
+            s->height = new_height;
+            CG14_INFO("new resolution = %d x %d\n", new_width, new_height);
+            qemu_console_resize(s->ds, s->width, s->height);
+            s->dirty = 1;
+        }
+    }
+
+    if (!s->dirty || !s->width || !s->height) {
+        return;
+    }
+
+    if (ds_get_bits_per_pixel(s->ds) != 32) {
+        CG14_ERROR("cg14_update: FIXME: bpp (%d) != 32, linesize %d\n",
+            ds_get_bits_per_pixel(s->ds), ds_get_linesize(s->ds));
+        return;
+    }
+    // if (is_surface_bgr(s->ds->surface))
+
+    draw_line = NULL;
+    src_linesize = s->width;
+    if (s->ctrl.mcr & CG14_MCR_VIDENABLE) {
+        switch (s->ctrl.mcr & CG14_MCR_PIXMODE_MASK) {
+        case CG14_MCR_PIXMODE_32:
+            src_linesize *= 4;
+            draw_line = cg14_draw_line32_rgb32;
+            break;
+        case CG14_MCR_PIXMODE_16:
+            src_linesize *= 2;
+            draw_line = cg14_draw_line16_rgb32;
+            break;
+        case CG14_MCR_PIXMODE_8:
+            draw_line = cg14_draw_line8_rgb32;
+            break;
+        }
+    }
+    if (!draw_line) {
+        /* blank */
+        memset(ds_get_data(s->ds), 0, ds_get_linesize(s->ds)*ds_get_height(s->ds));
+        s->dirty = 0;
+        return;
+    }
+
+    pix = s->vram;
+    data = ds_get_data(s->ds);
+
+    for (h=0; h<s->height; h++) {
+        draw_line(s, data, pix);
+        pix += src_linesize;
+        data += ds_get_linesize(s->ds);
+    }
+    dpy_update(s->ds, 0, 0, s->width, s->height);
+    s->dirty = 0;
+}
+
+static void cg14_invalidate_display(void *opaque)
+{
+    CG14State *s = opaque;
+
+    s->dirty = 1;
+}
+
+static uint32_t dac_read(struct dac_state *s, unsigned int reg)
+{
+    uint32_t val = 0;
+
+    switch (reg) {
+    case 0:
+        val = s->address;
+        break;
+    case 1: /* lookup table */
+        s->rgb_seq++;
+        break;
+    case 2: /* control registers */
+        break;
+    case 3:
+        val = s->mode;
+        break;
+    }
+    DPRINTF_DAC("read %02x from dac reg %d\n", val, reg);
+    return val;
+}
+
+static void dac_write(struct dac_state *s, unsigned int reg, unsigned int val)
+{
+    switch (reg) {
+    case 0: /* address register */
+        DPRINTF_DAC("write address %02x\n", val);
+        s->address = val;
+        s->rgb_seq = 0;
+        break;
+    case 1: /* lookup table */
+        DPRINTF_DAC("write %02x to lookup table\n", val);
+        s->rgb_seq++;
+        break;
+    case 2: /* control registers */
+        DPRINTF_DAC("write %02x to control reg %d\n", val, s->address);
+        switch (s->address) {
+        default:
+            break;
+        }
+        break;
+    case 3: /* mode register */
+        DPRINTF_DAC("write mode %02x (%d bit DAC, %d bit bus)\n",
+            val, (val & 2) ? 10 : 8, (val & 4) ? 10 : 8);
+        if (!val & 0x01) {
+            // reset the dac
+            s->rgb_seq = 0;
+        }
+        s->mode = val;
+        break;
+    }
+}
+
+static uint32_t cg14_reg_readb(void *opaque, target_phys_addr_t addr)
+{
+    CG14State *s = opaque;
+    uint32_t val;
+    uint32_t i;
+
+    if ((addr & 0xfc00) == 0x2000) {
+        i = (addr & 0x300) >> 8;
+        return dac_read(&s->dac, i);
+    }
+
+    switch (addr) {
+    case 0x0000:
+        val = s->ctrl.mcr;
+        break;
+    case 0x0001:
+        val = s->ctrl.ppr;
+        break;
+    case 0x0004: /* status ? */
+        val = s->ctrl.msr;
+        break;
+    case 0x0006: /* hw version */
+        //val = 0x00; /* old version */
+        val = 0x30;
+        break;
+    default:
+        val = 0;
+        CG14_INFO("readb from reg %x\n", (int)addr);
+        break;
+    }
+
+    return val;
+}
+
+static void cg14_reg_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CG14State *s = opaque;
+    uint32_t i;
+
+    if ((addr & 0xfc00) == 0x2000) {
+        i = (addr & 0x300) >> 8;
+        dac_write(&s->dac, i, val);
+        return;
+    }
+    if ((addr & 0xff00) == 0x3000) {
+        /* xlut */
+        i = addr & 0xff;
+        if (s->xlut[i] != val) {
+            s->dirty = 1;
+            s->xlut[i] = val;
+            if (val && val != 0x40)
+                CG14_ERROR("writeb xlut[%d] = %02x\n", i, val);
+        }
+        return;
+    }
+
+    s->dirty = 1;
+
+    switch (addr) {
+    case 0x0000:
+        s->ctrl.mcr = val;
+        DPRINTF_CONFIG("write %02x to MCR\n", val);
+        break;
+    case 0x0001:
+        s->ctrl.ppr = val & 0xF0;
+        break;
+    case 0x0007:
+        /* clock control (ICS1562AM-001) */
+        DPRINTF("write %02x to clock control\n", val);
+        break;
+    default:
+        CG14_ERROR("writeb %02x to reg %x\n", val, (int)addr);
+        break;
+    }
+}
+
+static uint32_t cg14_reg_readw(void *opaque, target_phys_addr_t addr)
+{
+    CG14State *s = opaque;
+    uint32_t val;
+
+    switch (addr) {
+    case 0x0018:
+        val = s->timing.hblank_start;
+        break;
+    case 0x001a:
+        val = s->timing.hblank_clear;
+        break;
+    case 0x0022:
+        val = s->timing.vblank_start;
+        break;
+    case 0x0024:
+        val = s->timing.vblank_clear;
+        break;
+    default:
+        val = 0;
+        CG14_INFO("readw from reg %x\n", (int)addr);
+        break;
+    }
+
+    return val;
+}
+
+static void cg14_reg_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CG14State *s = opaque;
+
+    DPRINTF_CONFIG("writew %04x to reg %x\n", val, (int)addr);
+
+    /* timing registers are 16bit */
+
+    switch (addr) {
+    case 0x0018:
+        s->timing.hblank_start = val;
+        break;
+    case 0x001a:
+        s->timing.hblank_clear = val;
+	s->size_changed = 1;
+        break;
+    case 0x0022:
+        s->timing.vblank_start = val;
+        break;
+    case 0x0024:
+        s->timing.vblank_clear = val;
+	s->size_changed = 1;
+        break;
+    case 0x001c: /* hsync_start */
+    case 0x001e: /* hsync_clear */
+    case 0x0020: /* csync_clear */
+    case 0x0026: /* vsync_start */
+    case 0x0028: /* vsync_clear */
+    default:
+        break;
+    }
+}
+
+static uint32_t cg14_reg_readl(void *opaque, target_phys_addr_t addr)
+{
+    CG14State *s = opaque;
+    uint32_t val;
+    uint32_t i;
+
+    i = (addr & 0x3ff) >> 2;
+    switch (addr & 0xfc00) {
+    case 0x4000:
+        val = s->clut1[i];
+        break;
+    case 0x5000:
+        val = s->clut2[i];
+        break;
+    default:
+        val = 0;
+        CG14_ERROR("readl %08x from reg %x\n", val, (int)addr);
+        break;
+    }
+
+    return val;
+}
+
+static void cg14_reg_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CG14State *s = opaque;
+    uint32_t i;
+
+    s->dirty = 1;
+
+    i = addr & 0x3ff;
+    switch (addr & 0xfc00) {
+    case 0x3000:
+        if (i < 256) {
+            s->xlut[i+0] = (uint8_t)(val >> 24);
+            s->xlut[i+1] = (uint8_t)(val >> 16);
+            s->xlut[i+2] = (uint8_t)(val >> 8);
+            s->xlut[i+3] = (uint8_t)val;
+        }
+        break;
+    case 0x4000:
+        s->clut1[i >> 2] = val;
+        break;
+    case 0x5000:
+        s->clut2[i >> 2] = val;
+        break;
+    default:
+        CG14_ERROR("writel %08x to reg %x\n", val, (int)addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *cg14_reg_read[3] = {
+    cg14_reg_readb,
+    cg14_reg_readw,
+    cg14_reg_readl,
+};
+
+static CPUWriteMemoryFunc *cg14_reg_write[3] = {
+    cg14_reg_writeb,
+    cg14_reg_writew,
+    cg14_reg_writel,
+};
+
+static uint32_t cg14_vram_readb(void *opaque, target_phys_addr_t addr)
+{
+    CG14State *s = opaque;
+    uint32_t offset;
+    uint32_t val = 0;
+
+    switch (addr & 0x3000000) {
+    case 0x0000000:
+    case 0x1000000:
+        offset = addr & s->vram_amask;
+        val = ldub_p(s->vram+offset);
+        break;
+    case 0x2000000:
+        offset = ((addr << 1) & s->vram_amask) + ((addr >> 23) & 1);
+        val = ldub_p(s->vram+offset);
+        break;
+    case 0x3000000:
+        offset = ((addr << 2) & s->vram_amask) + ((addr >> 22) & 3);
+        val = ldub_p(s->vram+offset);
+        break;
+    }
+
+    return val;
+}
+
+static void cg14_vram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CG14State *s = opaque;
+    uint32_t offset;
+
+    s->dirty = 1;
+
+    switch (addr & 0x3000000) {
+    case 0x0000000:
+        offset = addr & s->vram_amask;
+        stb_p(s->vram+offset, val);
+        break;
+    case 0x1000000:
+        offset = addr & s->vram_amask;
+        /* block writes to X */
+        if (offset & 3) {
+            stb_p(s->vram+offset, val);
+        }
+        break;
+    case 0x2000000:
+        offset = ((addr << 1) & s->vram_amask) + ((addr >> 23) & 1);
+        stb_p(s->vram+offset, val);
+        break;
+    case 0x3000000:
+        offset = ((addr << 2) & s->vram_amask) + ((addr >> 22) & 3);
+        stb_p(s->vram+offset, val);
+        break;
+    }
+}
+
+static uint32_t cg14_vram_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+
+    val = cg14_vram_readb(opaque, addr) << 8;
+    val |= cg14_vram_readb(opaque, addr+1);
+
+    return val;
+}
+
+static void cg14_vram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cg14_vram_writeb(opaque, addr, val >> 8);
+    cg14_vram_writeb(opaque, addr+1, val & 0xff);
+}
+
+static uint32_t cg14_vram_readl(void *opaque, target_phys_addr_t addr)
+{
+    CG14State *s = opaque;
+    uint32_t offset;
+    uint32_t val = 0;
+
+    switch (addr & 0x3000000) {
+    case 0x0000000:
+    case 0x1000000:
+        offset = addr & s->vram_amask;
+        val = ldl_be_p(s->vram+offset);
+        break;
+    case 0x2000000:
+        offset = ((addr << 1) & s->vram_amask) + ((addr >> 23) & 1);
+        val =  ldub_p(s->vram+offset+0) << 24;
+        val |= ldub_p(s->vram+offset+2) << 16;
+        val |= ldub_p(s->vram+offset+4) << 8;
+        val |= ldub_p(s->vram+offset+6);
+        break;
+    case 0x3000000:
+        offset = ((addr << 2) & s->vram_amask) + ((addr >> 22) & 3);
+        val =  ldub_p(s->vram+offset+0) << 24;
+        val |= ldub_p(s->vram+offset+4) << 16;
+        val |= ldub_p(s->vram+offset+8) << 8;
+        val |= ldub_p(s->vram+offset+12);
+        break;
+    }
+
+    return val;
+}
+
+static void cg14_vram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CG14State *s = opaque;
+    uint32_t offset;
+
+    s->dirty = 1;
+
+    switch (addr & 0x3000000) {
+    case 0x0000000:
+        offset = addr & s->vram_amask;
+        stl_be_p(s->vram+offset, val);
+        break;
+    case 0x1000000:
+        offset = addr & s->vram_amask;
+        /* block writes to X */
+        stb_p(s->vram+offset+1, val >> 16);
+        stb_p(s->vram+offset+2, val >> 8);
+        stb_p(s->vram+offset+3, val);
+        break;
+    case 0x2000000:
+        offset = ((addr << 1) & s->vram_amask) + ((addr >> 23) & 1);
+        stb_p(s->vram+offset+0, val >> 24);
+        stb_p(s->vram+offset+2, val >> 16);
+        stb_p(s->vram+offset+4, val >> 8);
+        stb_p(s->vram+offset+6, val);
+        break;
+    case 0x3000000:
+        offset = ((addr << 2) & s->vram_amask) + ((addr >> 22) & 3);
+        stb_p(s->vram+offset+0,  val >> 24);
+        stb_p(s->vram+offset+4,  val >> 16);
+        stb_p(s->vram+offset+8,  val >> 8);
+        stb_p(s->vram+offset+12, val);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *cg14_vram_read[3] = {
+    cg14_vram_readb,
+    cg14_vram_readw,
+    cg14_vram_readl,
+};
+
+static CPUWriteMemoryFunc *cg14_vram_write[3] = {
+    cg14_vram_writeb,
+    cg14_vram_writew,
+    cg14_vram_writel,
+};
+
+
+static void cg14_set_monitor_id(CG14State *s)
+{
+    uint8_t id;
+
+    /* pick something close, used as a default by Sun's OBP */
+    if (s->width >= 1600) {
+        id = CG14_MONID_1600x1280;
+    } else if (s->width >= 1280) {
+        id = CG14_MONID_1280x1024;
+    } else if (s->width >= 1152) {
+        id = CG14_MONID_1152x900;
+    } else if (s->width >= 1024) {
+        id = CG14_MONID_1024x768;
+    } else {
+        id = CG14_MONID_DEFAULT;
+    }
+
+    /* monitor code in bits 1..3 */
+    s->ctrl.msr = id << 1;
+}
+
+static int cg14_init1(SysBusDevice *dev)
+{
+    CG14State *s = FROM_SYSBUS(CG14State, dev);
+    ram_addr_t vram_offset;
+    uint8_t *vram;
+    int ctrl_memory, vram_memory;
+
+    vram_offset = qemu_ram_alloc(NULL, "cg14.vram", s->vram_size);
+    vram = qemu_get_ram_ptr(vram_offset);
+
+    s->vram = vram;
+    s->vram_amask = s->vram_size - 1;
+
+    ctrl_memory = cpu_register_io_memory(cg14_reg_read, cg14_reg_write, s);
+    sysbus_init_mmio(dev, CG14_REG_SIZE, ctrl_memory);
+
+    /* TODO: register first vram mapping as ram with dirty tracking */
+    vram_memory = cpu_register_io_memory(cg14_vram_read, cg14_vram_write, s);
+    sysbus_init_mmio(dev, CG14_VMEM_SLOTSIZE, vram_memory);
+
+    s->ds = graphic_console_init(cg14_update_display,
+                                 cg14_invalidate_display,
+                                 cg14_screen_dump, NULL, s);
+
+    cg14_set_monitor_id(s);
+
+    qemu_console_resize(s->ds, s->width, s->height);
+    return 0;
+}
+
+/* save to file */
+static void cg14_screen_dump(void *opaque, const char *filename)
+{
+    CG14State *s = opaque;
+    FILE *f;
+    int y, src_linesize, dst_linesize;
+    void *buf;
+    uint8_t *pix;
+    draw_line_func * draw_line = NULL;
+
+    switch (s->ctrl.mcr & CG14_MCR_PIXMODE_MASK) {
+    case CG14_MCR_PIXMODE_32:
+        src_linesize = s->width * 4;
+        // draw_line = cg14_draw_line32_bgr24;
+        break;
+    case CG14_MCR_PIXMODE_16:
+        src_linesize = s->width * 2;
+        // draw_line = cg14_draw_line16_bgr24;
+        break;
+    case CG14_MCR_PIXMODE_8:
+        src_linesize = s->width;
+        // draw_line = cg14_draw_line8_bgr24;
+        break;
+    default:
+        /* blank */
+        return;
+    }
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        return;
+    }
+    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+
+    dst_linesize = s->width * 3;
+    buf = qemu_mallocz(dst_linesize);
+    pix = s->vram;
+
+    for (y=0; y<s->height; y++) {
+        if (draw_line)
+            draw_line(s, buf, pix);
+        fwrite(buf, 1, dst_linesize, f);
+        pix += src_linesize;
+    }
+
+    qemu_free(buf);
+    fclose(f);
+}
+
+static void cg14_reset(DeviceState *d)
+{
+    CG14State *s = container_of(d, CG14State, busdev.qdev);
+
+    /* set to 8bpp so last prom output might be visible */
+    s->ctrl.mcr = CG14_MCR_VIDENABLE | CG14_MCR_PIXMODE_8;
+    s->dirty = 1;
+}
+
+static SysBusDeviceInfo cg14_info = {
+    .init = cg14_init1,
+    .qdev.name = "cg14",
+    .qdev.desc = "Sun CG14 Framebuffer",
+    .qdev.size = sizeof(CG14State),
+    .qdev.reset = cg14_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_TADDR("vram_addr", CG14State, vram_addr, -1),
+        DEFINE_PROP_HEX32("vram_size", CG14State, vram_size, 0x800000),
+        DEFINE_PROP_UINT16("width",    CG14State, width,     0),
+        DEFINE_PROP_UINT16("height",   CG14State, height,    0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void cg14_register_devices(void)
+{
+    sysbus_register_withprop(&cg14_info);
+}
+
+device_init(cg14_register_devices)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index e7a4cf6..0665e1f 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -577,6 +577,23 @@ static void tcx_init(target_phys_addr_t addr, int vram_size, int width,
     }
 }
 
+static void cg14_init(target_phys_addr_t ctrl_base,
+                      target_phys_addr_t vram_base,
+                      int width, int height)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "cg14");
+    qdev_prop_set_taddr(dev, "vram_addr", vram_base);
+    qdev_prop_set_uint16(dev, "width", width);
+    qdev_prop_set_uint16(dev, "height", height);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, ctrl_base);
+    sysbus_mmio_map(s, 1, vram_base);
+}
+
 /* NCR89C100/MACIO Internal ID register */
 static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 };
 
@@ -879,6 +896,11 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
         exit (1);
     }
     num_vsimms = 0;
+    if (hwdef->vsimm[0].vram_base && (graphic_width > 1024 || !hwdef->tcx_base)) {
+        cg14_init(hwdef->vsimm[0].reg_base, hwdef->vsimm[0].vram_base,
+                  graphic_width, graphic_height);
+        num_vsimms++;
+    }
     if (num_vsimms == 0) {
         tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
                  graphic_depth);
-- 
1.6.2.2.1669.g7eaf8

  reply	other threads:[~2010-07-13 16:23 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-27 21:57 [Qemu-devel] cg14 Artyom Tarasenko
2010-05-28  7:54 ` Bob Breuer
2010-05-28 21:06   ` Blue Swirl
2010-05-28 22:48     ` Artyom Tarasenko
2010-05-29  5:15       ` Bob Breuer
2010-05-29  8:55         ` Blue Swirl
2010-07-13 16:26           ` Bob Breuer [this message]
2010-07-13 20:34             ` Artyom Tarasenko
2010-07-20 21:39             ` Blue Swirl
2010-05-29 13:26         ` Artyom Tarasenko

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=4C3C93B7.9020804@mc.net \
    --to=breuerr@mc.net \
    --cc=atar4qemu@googlemail.com \
    --cc=blauwirbel@gmail.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.