From patchwork Sat Sep 13 10:10:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Cave-Ayland X-Patchwork-Id: 388890 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0C7D7140114 for ; Sat, 13 Sep 2014 20:11:16 +1000 (EST) Received: from localhost ([::1]:49130 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSkIT-00084b-8P for incoming@patchwork.ozlabs.org; Sat, 13 Sep 2014 06:11:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50389) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSkI6-0007oC-DF for qemu-devel@nongnu.org; Sat, 13 Sep 2014 06:10:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XSkI0-0002Hp-VM for qemu-devel@nongnu.org; Sat, 13 Sep 2014 06:10:50 -0400 Received: from s16892447.onlinehome-server.info ([82.165.15.123]:40385) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSkI0-0002G5-Ct for qemu-devel@nongnu.org; Sat, 13 Sep 2014 06:10:44 -0400 Received: from 4e567435.skybroadband.com ([78.86.116.53] helo=kentang.lan) by s16892447.onlinehome-server.info with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1XSkHc-0004Zw-Gp; Sat, 13 Sep 2014 11:10:30 +0100 From: Mark Cave-Ayland To: qemu-devel@nongnu.org, odanet@caramail.com Date: Sat, 13 Sep 2014 11:10:07 +0100 Message-Id: <1410603007-21371-1-git-send-email-mark.cave-ayland@ilande.co.uk> X-Mailer: git-send-email 1.7.10.4 X-SA-Exim-Connect-IP: 78.86.116.53 X-SA-Exim-Mail-From: mark.cave-ayland@ilande.co.uk X-SA-Exim-Version: 4.2.1 (built Sun, 08 Jan 2012 02:45:44 +0000) X-SA-Exim-Scanned: Yes (on s16892447.onlinehome-server.info) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 82.165.15.123 Subject: [Qemu-devel] [PATCH] tcx: Implement hardware acceleration X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The S24/TCX framebuffer is a mildly accelerated video card with blitter, stippler and hardware cursor. * Solaris and NetBSD 6.x use all the hardware acceleration features * The Xorg driver (used by Linux) can use the hardware cursor only This patch implements hardware acceleration in both 8 bit and 24 bit modes. It is based on the NetBSD driver sources and from tests with Solaris. Signed-off-by: Olivier Danet Signed-off-by: Mark Cave-Ayland --- hw/display/tcx.c | 677 ++++++++++++++++++++++++++++++++++++++++++++---------- hw/sparc/sun4m.c | 56 +++-- 2 files changed, 596 insertions(+), 137 deletions(-) diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 28c742c..d6bb56f 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -33,10 +33,20 @@ #define MAXX 1024 #define MAXY 768 -#define TCX_DAC_NREGS 16 -#define TCX_THC_NREGS_8 0x081c -#define TCX_THC_NREGS_24 0x1000 +#define TCX_DAC_NREGS 16 +#define TCX_THC_NREGS 0x1000 +#define TCX_DHC_NREGS 0x4000 #define TCX_TEC_NREGS 0x1000 +#define TCX_ALT_NREGS 0x8000 +#define TCX_STIP_NREGS 0x800000 +#define TCX_BLIT_NREGS 0x800000 +#define TCX_RSTIP_NREGS 0x800000 +#define TCX_RBLIT_NREGS 0x800000 + +#define TCX_THC_MISC 0x818 +#define TCX_THC_CURSXY 0x8fc +#define TCX_THC_CURSMASK 0x900 +#define TCX_THC_CURSBITS 0x980 #define TYPE_TCX "SUNW,tcx" #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) @@ -45,6 +55,7 @@ typedef struct TCXState { SysBusDevice parent_obj; QemuConsole *con; + qemu_irq irq; uint8_t *vram; uint32_t *vram24, *cplane; hwaddr prom_addr; @@ -52,17 +63,30 @@ typedef struct TCXState { MemoryRegion vram_mem; MemoryRegion vram_8bit; MemoryRegion vram_24bit; + MemoryRegion stip; + MemoryRegion blit; MemoryRegion vram_cplane; - MemoryRegion dac; + MemoryRegion rstip; + MemoryRegion rblit; MemoryRegion tec; + MemoryRegion dac; + MemoryRegion thc; + MemoryRegion dhc; + MemoryRegion alt; MemoryRegion thc24; - MemoryRegion thc8; + ram_addr_t vram24_offset, cplane_offset; + uint32_t tmpblit; uint32_t vram_size; - uint32_t palette[256]; - uint8_t r[256], g[256], b[256]; + uint32_t palette[260]; + uint8_t r[260], g[260], b[260]; uint16_t width, height, depth; uint8_t dac_index, dac_state; + uint32_t thcmisc; + uint32_t cursmask[32]; + uint32_t cursbits[32]; + uint16_t cursx; + uint16_t cursy; } TCXState; static void tcx_set_dirty(TCXState *s) @@ -70,10 +94,36 @@ static void tcx_set_dirty(TCXState *s) memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); } -static void tcx24_set_dirty(TCXState *s) +static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page, + ram_addr_t page24, ram_addr_t cpage) { - memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4); - memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4); + int ret; + + ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); + return ret; +} + +static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min, + ram_addr_t page_max, ram_addr_t page24, + ram_addr_t cpage) +{ + memory_region_reset_dirty(&ts->vram_mem, + page_min, + (page_max - page_min) + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + page24 + page_min * 4, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + memory_region_reset_dirty(&ts->vram_mem, + cpage + page_min * 4, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); } static void update_palette_entries(TCXState *s, int start, int end) @@ -102,11 +152,7 @@ static void update_palette_entries(TCXState *s, int start, int end) break; } } - if (s->depth == 24) { - tcx24_set_dirty(s); - } else { - tcx_set_dirty(s); - } + tcx_set_dirty(s); } static void tcx_draw_line32(TCXState *s1, uint8_t *d, @@ -116,7 +162,7 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, uint8_t val; uint32_t *p = (uint32_t *)d; - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { val = *s++; *p++ = s1->palette[val]; } @@ -129,7 +175,7 @@ static void tcx_draw_line16(TCXState *s1, uint8_t *d, uint8_t val; uint16_t *p = (uint16_t *)d; - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { val = *s++; *p++ = s1->palette[val]; } @@ -147,6 +193,83 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, } } +static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + uint32_t *p = (uint32_t *)d; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + p = &p[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *p = s1->palette[259]; + } else { + *p = s1->palette[258]; + } + } + p++; + mask <<= 1; + bits <<= 1; + } +} + +static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + uint16_t *p = (uint16_t *)d; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + p = &p[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *p = s1->palette[259]; + } else { + *p = s1->palette[258]; + } + } + p++; + mask <<= 1; + bits <<= 1; + } +} + +static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, + int y, int width) +{ + int x, len; + uint32_t mask, bits; + + y = y - s1->cursy; + mask = s1->cursmask[y]; + bits = s1->cursbits[y]; + len = MIN(width - s1->cursx, 32); + d = &d[s1->cursx]; + for (x = 0; x < len; x++) { + if (mask & 0x80000000) { + if (bits & 0x80000000) { + *d = s1->palette[259]; + } else { + *d = s1->palette[258]; + } + } + d++; + mask <<= 1; + bits <<= 1; + } +} + /* XXX Could be much more optimal: * detect if line/page/whole screen is in 24 bit mode @@ -162,11 +285,10 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, uint8_t val, *p8; uint32_t *p = (uint32_t *)d; uint32_t dval; - bgr = is_surface_bgr(surface); for(x = 0; x < width; x++, s++, s24++) { - if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { - // 24-bit direct, BGR order + if (be32_to_cpu(*cplane) & 0x03000000) { + /* 24-bit direct, BGR order */ p8 = (uint8_t *)s24; p8++; b = *p8++; @@ -177,47 +299,18 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, else dval = rgb_to_pixel32(r, g, b); } else { + /* 8-bit pseudocolor */ val = *s; dval = s1->palette[val]; } *p++ = dval; + cplane++; } } -static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24, - ram_addr_t cpage) -{ - int ret; - - ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, - DIRTY_MEMORY_VGA); - ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, - DIRTY_MEMORY_VGA); - return ret; -} - -static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, - ram_addr_t page_max, ram_addr_t page24, - ram_addr_t cpage) -{ - memory_region_reset_dirty(&ts->vram_mem, - page_min, - (page_max - page_min) + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - memory_region_reset_dirty(&ts->vram_mem, - page24 + page_min * 4, - (page_max - page_min) * 4 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - memory_region_reset_dirty(&ts->vram_mem, - cpage + page_min * 4, - (page_max - page_min) * 4 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); -} - /* Fixed line length 1024 allows us to do nice tricks not possible on VGA... */ + static void tcx_update_display(void *opaque) { TCXState *ts = opaque; @@ -226,6 +319,7 @@ static void tcx_update_display(void *opaque) int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); + void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); if (surface_bits_per_pixel(surface) == 0) { return; @@ -243,20 +337,23 @@ static void tcx_update_display(void *opaque) switch (surface_bits_per_pixel(surface)) { case 32: f = tcx_draw_line32; + fc = tcx_draw_cursor32; break; case 15: case 16: f = tcx_draw_line16; + fc = tcx_draw_cursor16; break; default: case 8: f = tcx_draw_line8; + fc = tcx_draw_cursor8; break; case 0: return; } - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { + for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA)) { if (y_start < 0) @@ -265,18 +362,38 @@ static void tcx_update_display(void *opaque) page_min = page; if (page > page_max) page_max = page; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; + f(ts, d, s, ts->width); + if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { + fc(ts, d, y, ts->width); + } d += dd; s += ds; + y++; } else { if (y_start >= 0) { /* flush to display */ @@ -286,6 +403,7 @@ static void tcx_update_display(void *opaque) } d += dd * 4; s += ds * 4; + y += 4; } } if (y_start >= 0) { @@ -328,9 +446,9 @@ static void tcx24_update_display(void *opaque) dd = surface_stride(surface); ds = 1024; - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, + for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { - if (check_dirty(ts, page, page24, cpage)) { + if (tcx24_check_dirty(ts, page, page24, cpage)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -338,25 +456,41 @@ static void tcx24_update_display(void *opaque) if (page > page_max) page_max = page; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { + tcx_draw_cursor32(ts, d, y, ts->width); + } d += dd; s += ds; cptr += ds; s24 += ds; + y++; } else { if (y_start >= 0) { /* flush to display */ @@ -368,6 +502,7 @@ static void tcx24_update_display(void *opaque) s += ds * 4; cptr += ds * 4; s24 += ds * 4; + y += 4; } } if (y_start >= 0) { @@ -377,7 +512,7 @@ static void tcx24_update_display(void *opaque) } /* reset modified pages */ if (page_max >= page_min) { - reset_dirty(ts, page_min, page_max, page24, cpage); + tcx24_reset_dirty(ts, page_min, page_max, page24, cpage); } } @@ -394,7 +529,6 @@ static void tcx24_invalidate_display(void *opaque) TCXState *s = opaque; tcx_set_dirty(s); - tcx24_set_dirty(s); qemu_console_resize(s->con, s->width, s->height); } @@ -403,12 +537,7 @@ static int vmstate_tcx_post_load(void *opaque, int version_id) TCXState *s = opaque; update_palette_entries(s, 0, 256); - if (s->depth == 24) { - tcx24_set_dirty(s); - } else { - tcx_set_dirty(s); - } - + tcx_set_dirty(s); return 0; } @@ -435,56 +564,87 @@ static void tcx_reset(DeviceState *d) TCXState *s = TCX(d); /* Initialize palette */ - memset(s->r, 0, 256); - memset(s->g, 0, 256); - memset(s->b, 0, 256); + memset(s->r, 0, 260); + memset(s->g, 0, 260); + memset(s->b, 0, 260); s->r[255] = s->g[255] = s->b[255] = 255; - update_palette_entries(s, 0, 256); + s->r[256] = s->g[256] = s->b[256] = 255; + s->r[258] = s->g[258] = s->b[258] = 255; + update_palette_entries(s, 0, 260); memset(s->vram, 0, MAXX*MAXY); memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), DIRTY_MEMORY_VGA); s->dac_index = 0; s->dac_state = 0; + s->cursx = 0xf000; /* Put cursor off screen */ + s->cursy = 0xf000; } static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, unsigned size) { - return 0; + TCXState *s = opaque; + uint32_t val = 0; + + switch (s->dac_state) { + case 0: + val = s->r[s->dac_index] << 24; + s->dac_state++; + break; + case 1: + val = s->g[s->dac_index] << 24; + s->dac_state++; + break; + case 2: + val = s->b[s->dac_index] << 24; + s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ + default: + s->dac_state = 0; + break; + } + + return val; } static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TCXState *s = opaque; + unsigned index; switch (addr) { - case 0: + case 0: /* Address */ s->dac_index = val >> 24; s->dac_state = 0; break; - case 4: + case 4: /* Pixel colours */ + case 12: /* Overlay (cursor) colours */ + if (addr & 8) { + index = (s->dac_index & 3) + 256; + } else { + index = s->dac_index; + } switch (s->dac_state) { case 0: - s->r[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); + s->r[index] = val >> 24; + update_palette_entries(s, index, index + 1); s->dac_state++; break; case 1: - s->g[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); + s->g[index] = val >> 24; + update_palette_entries(s, index, index + 1); s->dac_state++; break; case 2: - s->b[s->dac_index] = val >> 24; - update_palette_entries(s, s->dac_index, s->dac_index + 1); - s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement + s->b[index] = val >> 24; + update_palette_entries(s, index, index + 1); + s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ default: s->dac_state = 0; break; } break; - default: + default: /* Control registers */ break; } } @@ -499,20 +659,266 @@ static const MemoryRegionOps tcx_dac_ops = { }, }; -static uint64_t dummy_readl(void *opaque, hwaddr addr, +static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void tcx_stip_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + int i; + uint32_t col; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + col = cpu_to_be32(s->tmpblit); + if (s->depth == 24) { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + s->vram24[addr + i] = col; + } + val <<= 1; + } + } else { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + } + val <<= 1; + } + } + memory_region_set_dirty(&s->vram_mem, addr, 32); + } +} + +static void tcx_rstip_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + int i; + uint32_t col; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + col = cpu_to_be32(s->tmpblit); + if (s->depth == 24) { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + s->vram24[addr + i] = col; + s->cplane[addr + i] = col; + } + val <<= 1; + } + } else { + for (i = 0; i < 32; i++) { + if (val & 0x80000000) { + s->vram[addr + i] = s->tmpblit; + } + val <<= 1; + } + } + memory_region_set_dirty(&s->vram_mem, addr, 32); + } +} + +static const MemoryRegionOps tcx_stip_ops = { + .read = tcx_stip_readl, + .write = tcx_stip_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps tcx_rstip_ops = { + .read = tcx_stip_readl, + .write = tcx_rstip_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void tcx_blit_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + uint32_t adsr, len; + int i; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + adsr = val & 0xffffff; + len = ((val >> 24) & 0x1f) + 1; + if (adsr == 0xffffff) { + memset(&s->vram[addr], s->tmpblit, len); + if (s->depth == 24) { + val = s->tmpblit & 0xffffff; + val = cpu_to_be32(val); + for (i = 0; i < len; i++) { + s->vram24[addr + i] = val; + } + } + } else { + memcpy(&s->vram[addr], &s->vram[adsr], len); + if (s->depth == 24) { + memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); + } + } + memory_region_set_dirty(&s->vram_mem, addr, len); + } +} + +static void tcx_rblit_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + uint32_t adsr, len; + int i; + + if (!(addr & 4)) { + s->tmpblit = val; + } else { + addr = (addr >> 3) & 0xfffff; + adsr = val & 0xffffff; + len = ((val >> 24) & 0x1f) + 1; + if (adsr == 0xffffff) { + memset(&s->vram[addr], s->tmpblit, len); + if (s->depth == 24) { + val = s->tmpblit & 0xffffff; + val = cpu_to_be32(val); + for (i = 0; i < len; i++) { + s->vram24[addr + i] = val; + s->cplane[addr + i] = val; + } + } + } else { + memcpy(&s->vram[addr], &s->vram[adsr], len); + if (s->depth == 24) { + memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); + memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); + } + } + memory_region_set_dirty(&s->vram_mem, addr, len); + } +} + +static const MemoryRegionOps tcx_blit_ops = { + .read = tcx_blit_readl, + .write = tcx_blit_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps tcx_rblit_ops = { + .read = tcx_blit_readl, + .write = tcx_rblit_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void tcx_invalidate_cursor_position(TCXState *s) +{ + int ymin, ymax, start, end; + + /* invalidate only near the cursor */ + ymin = s->cursy; + if (ymin >= s->height) { + return; + } + ymax = MIN(s->height, ymin + 32); + start = ymin * 1024; + end = ymax * 1024; + + memory_region_set_dirty(&s->vram_mem, start, end-start); +} + +static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, + unsigned size) +{ + TCXState *s = opaque; + uint64_t val; + + if (addr == TCX_THC_MISC) { + val = s->thcmisc | 0x02000000; + } else { + val = 0; + } + return val; +} + +static void tcx_thc_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + TCXState *s = opaque; + + if (addr == TCX_THC_CURSXY) { + tcx_invalidate_cursor_position(s); + s->cursx = val >> 16; + s->cursy = val; + tcx_invalidate_cursor_position(s); + } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { + s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; + tcx_invalidate_cursor_position(s); + } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { + s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; + tcx_invalidate_cursor_position(s); + } else if (addr == TCX_THC_MISC) { + s->thcmisc = val; + } + +} + +static const MemoryRegionOps tcx_thc_ops = { + .read = tcx_thc_readl, + .write = tcx_thc_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, unsigned size) { return 0; } -static void dummy_writel(void *opaque, hwaddr addr, +static void tcx_dummy_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { + return; } -static const MemoryRegionOps dummy_ops = { - .read = dummy_readl, - .write = dummy_writel, +static const MemoryRegionOps tcx_dummy_ops = { + .read = tcx_dummy_readl, + .write = tcx_dummy_writel, .endianness = DEVICE_NATIVE_ENDIAN, .valid = { .min_access_size = 4, @@ -539,20 +945,50 @@ static void tcx_initfn(Object *obj) memory_region_set_readonly(&s->rom, true); sysbus_init_mmio(sbd, &s->rom); - /* DAC */ + /* 2/STIP : Stippler */ + memory_region_init_io(&s->stip, OBJECT(s), &tcx_stip_ops, s, "tcx.stip", + TCX_STIP_NREGS); + sysbus_init_mmio(sbd, &s->stip); + + /* 3/BLIT : Blitter */ + memory_region_init_io(&s->blit, OBJECT(s), &tcx_blit_ops, s, "tcx.blit", + TCX_BLIT_NREGS); + sysbus_init_mmio(sbd, &s->blit); + + /* 5/RSTIP : Raw Stippler */ + memory_region_init_io(&s->rstip, OBJECT(s), &tcx_rstip_ops, s, "tcx.rstip", + TCX_RSTIP_NREGS); + sysbus_init_mmio(sbd, &s->rstip); + + /* 6/RBLIT : Raw Blitter */ + memory_region_init_io(&s->rblit, OBJECT(s), &tcx_rblit_ops, s, "tcx.rblit", + TCX_RBLIT_NREGS); + sysbus_init_mmio(sbd, &s->rblit); + + /* 7/TEC : ??? */ + memory_region_init_io(&s->tec, OBJECT(s), &tcx_dummy_ops, s, + "tcx.tec", TCX_TEC_NREGS); + sysbus_init_mmio(sbd, &s->tec); + + /* 8/CMAP : DAC */ memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS); sysbus_init_mmio(sbd, &s->dac); - /* TEC (dummy) */ - memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, - "tcx.tec", TCX_TEC_NREGS); - sysbus_init_mmio(sbd, &s->tec); + /* 9/THC : Cursor */ + memory_region_init_io(&s->thc, OBJECT(s), &tcx_thc_ops, s, "tcx.thc", + TCX_THC_NREGS); + sysbus_init_mmio(sbd, &s->thc); - /* THC: NetBSD writes here even with 8-bit display: dummy */ - memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", - TCX_THC_NREGS_24); - sysbus_init_mmio(sbd, &s->thc24); + /* 11/DHC : ??? */ + memory_region_init_io(&s->dhc, OBJECT(s), &tcx_dummy_ops, s, "tcx.dhc", + TCX_DHC_NREGS); + sysbus_init_mmio(sbd, &s->dhc); + + /* 12/ALT : ??? */ + memory_region_init_io(&s->alt, OBJECT(s), &tcx_dummy_ops, s, "tcx.alt", + TCX_ALT_NREGS); + sysbus_init_mmio(sbd, &s->alt); return; } @@ -571,7 +1007,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) vmstate_register_ram_global(&s->vram_mem); vram_base = memory_region_get_ram_ptr(&s->vram_mem); - /* FCode ROM */ + /* 10/ROM : FCode ROM */ vmstate_register_ram_global(&s->rom); fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); if (fcode_filename) { @@ -582,7 +1018,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) } } - /* 8-bit plane */ + /* 0/DFB8 : 8-bit plane */ s->vram = vram_base; size = s->vram_size; memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", @@ -591,34 +1027,39 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) vram_offset += size; vram_base += size; - if (s->depth == 24) { - /* 24-bit plane */ - size = s->vram_size * 4; - s->vram24 = (uint32_t *)vram_base; - s->vram24_offset = vram_offset; - memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", - &s->vram_mem, vram_offset, size); - sysbus_init_mmio(sbd, &s->vram_24bit); - vram_offset += size; - vram_base += size; - - /* Control plane */ - size = s->vram_size * 4; - s->cplane = (uint32_t *)vram_base; - s->cplane_offset = vram_offset; - memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", - &s->vram_mem, vram_offset, size); - sysbus_init_mmio(sbd, &s->vram_cplane); + /* 1/DFB24 : 24bit plane */ + size = s->vram_size * 4; + s->vram24 = (uint32_t *)vram_base; + s->vram24_offset = vram_offset; + memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio(sbd, &s->vram_24bit); + vram_offset += size; + vram_base += size; + + /* 4/RDFB32 : Raw Framebuffer */ + size = s->vram_size * 4; + s->cplane = (uint32_t *)vram_base; + s->cplane_offset = vram_offset; + memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", + &s->vram_mem, vram_offset, size); + sysbus_init_mmio(sbd, &s->vram_cplane); - s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); - } else { - /* THC 8 bit (dummy) */ - memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8", - TCX_THC_NREGS_8); - sysbus_init_mmio(sbd, &s->thc8); + /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ + if (s->depth == 8) { + memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, + "tcx.thc24", TCX_THC_NREGS); + sysbus_init_mmio(sbd, &s->thc24); + } + + sysbus_init_irq(sbd, &s->irq); + if (s->depth == 8) { s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); + } else { + s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); } + s->thcmisc = 0; qemu_console_resize(s->con, s->width, s->height); } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 67e3663..b0d1ded 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -527,7 +527,7 @@ static void apc_init(hwaddr power_base, qemu_irq cpu_halt) sysbus_connect_irq(s, 0, cpu_halt); } -static void tcx_init(hwaddr addr, int vram_size, int width, +static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width, int height, int depth) { DeviceState *dev; @@ -541,25 +541,43 @@ static void tcx_init(hwaddr addr, int vram_size, int width, qdev_prop_set_uint64(dev, "prom_addr", addr); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); - /* FCode ROM */ + + /* 10/ROM : FCode ROM */ sysbus_mmio_map(s, 0, addr); - /* DAC */ - sysbus_mmio_map(s, 1, addr + 0x00200000ULL); - /* TEC (dummy) */ - sysbus_mmio_map(s, 2, addr + 0x00700000ULL); - /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */ - sysbus_mmio_map(s, 3, addr + 0x00301000ULL); - /* 8-bit plane */ - sysbus_mmio_map(s, 4, addr + 0x00800000ULL); - if (depth == 24) { - /* 24-bit plane */ - sysbus_mmio_map(s, 5, addr + 0x02000000ULL); - /* Control plane */ - sysbus_mmio_map(s, 6, addr + 0x0a000000ULL); + /* 2/STIP : Stipple */ + sysbus_mmio_map(s, 1, addr + 0x04000000ULL); + /* 3/BLIT : Blitter */ + sysbus_mmio_map(s, 2, addr + 0x06000000ULL); + /* 5/RSTIP : Raw Stipple */ + sysbus_mmio_map(s, 3, addr + 0x0c000000ULL); + /* 6/RBLIT : Raw Blitter */ + sysbus_mmio_map(s, 4, addr + 0x0e000000ULL); + /* 7/TEC : Transform Engine */ + sysbus_mmio_map(s, 5, addr + 0x00700000ULL); + /* 8/CMAP : DAC */ + sysbus_mmio_map(s, 6, addr + 0x00200000ULL); + /* 9/THC : */ + if (depth == 8) { + sysbus_mmio_map(s, 7, addr + 0x00300000ULL); } else { - /* THC 8 bit (dummy) */ - sysbus_mmio_map(s, 5, addr + 0x00300000ULL); + sysbus_mmio_map(s, 7, addr + 0x00301000ULL); } + /* 11/DHC : */ + sysbus_mmio_map(s, 8, addr + 0x00240000ULL); + /* 12/ALT : */ + sysbus_mmio_map(s, 9, addr + 0x00280000ULL); + /* 0/DFB8 : 8-bit plane */ + sysbus_mmio_map(s, 10, addr + 0x00800000ULL); + /* 1/DFB24 : 24bit plane */ + sysbus_mmio_map(s, 11, addr + 0x02000000ULL); + /* 4/RDFB32: Raw framebuffer. Control plane */ + sysbus_mmio_map(s, 12, addr + 0x0a000000ULL); + /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ + if (depth == 8) { + sysbus_mmio_map(s, 13, addr + 0x00301000ULL); + } + + sysbus_connect_irq(s, 0, irq); } static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width, @@ -974,8 +992,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, exit(1); } - tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height, - graphic_depth); + tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, + graphic_width, graphic_height, graphic_depth); } }