From 984db93947f019b73c88b600732f33d3e0e82662 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 29 Sep 2019 08:37:33 +0200 Subject: [PATCH] Implemented video to CPU (mem sys dest) blits on the Cirrus Logic CL-GD 54xx graphic card, fixes #329. --- src/video/vid_cl54xx.c | 305 +++++++++++++++++++++++++++++++++-------- 1 file changed, 245 insertions(+), 60 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index fee260cfc..7f7cc0252 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.28 2019/07/05 + * Version: @(#)vid_cl_54xx.c 1.0.29 2019/09/29 * * Authors: TheCollector1995, * Miran Grca, @@ -157,9 +157,11 @@ typedef struct gd54xx_t uint16_t dst_pitch, src_pitch; uint16_t trans_col, trans_mask; uint16_t height_internal; + uint16_t msd_buf_pos, msd_buf_cnt; - uint8_t status, pad; + uint8_t status; uint8_t mask, mode, rop, modeext; + uint8_t ms_is_dest, msd_buf[16]; uint32_t fg_col, bg_col; uint32_t dst_addr_backup, src_addr_backup; @@ -1184,11 +1186,15 @@ gd54xx_mem_sys_src_write(gd54xx_t *gd54xx, uint8_t val) !(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { gd54xx_start_blit(val, 8, gd54xx, &gd54xx->svga); } else { - gd54xx->blt.sys_src32 &= ~(0xff << (gd54xx->blt.sys_cnt << 3)); - gd54xx->blt.sys_src32 |= (val << (gd54xx->blt.sys_cnt << 3)); - gd54xx->blt.sys_cnt = (gd54xx->blt.sys_cnt + 1) & 3; - if (gd54xx->blt.sys_cnt == 0) - gd54xx_start_blit(gd54xx->blt.sys_src32, 32, gd54xx, &gd54xx->svga); + if (gd54xx->blt.ms_is_dest) + gd54xx_start_blit(0xffffffff, 32, gd54xx, &gd54xx->svga); + else { + gd54xx->blt.sys_src32 &= ~(0xff << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_src32 |= (val << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_cnt = (gd54xx->blt.sys_cnt + 1) & 3; + if (gd54xx->blt.sys_cnt == 0) + gd54xx_start_blit(gd54xx->blt.sys_src32, 32, gd54xx, &gd54xx->svga); + } } } @@ -1199,7 +1205,8 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_mem_sys_src_write(gd54xx, val); return; } @@ -1222,7 +1229,8 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_write(addr, val, gd54xx); gd54xx_write(addr + 1, val >> 8, gd54xx); return; @@ -1251,7 +1259,8 @@ gd54xx_writel(uint32_t addr, uint32_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_write(addr, val, gd54xx); gd54xx_write(addr + 1, val >> 8, gd54xx); gd54xx_write(addr + 2, val >> 16, gd54xx); @@ -1342,11 +1351,30 @@ gd54xx_get_aperture(uint32_t addr) } +static int +gd54xx_aperture2_enabled(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + return 0; + + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + return 0; + + if (!(gd54xx->blt.status & CIRRUS_BLT_APERTURE2)) + return 0; + + return 1; +} + + static uint8_t gd54xx_readb_linear(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint8_t ret = 0xff; uint8_t ap = gd54xx_get_aperture(addr); addr &= 0x003fffff; /* 4 MB mask */ @@ -1359,6 +1387,19 @@ gd54xx_readb_linear(uint32_t addr, void *p) return gd543x_mmio_read(addr & 0x000000ff, gd54xx); } + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->blt.msd_buf_cnt != 0) { + ret = gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos++]; + gd54xx->blt.msd_buf_cnt--; + } + ret = ret; /* Need to put a dummy line so the compiler doesn't mess up. */ + if (gd54xx->blt.msd_buf_cnt == 0) + gd54xx_mem_sys_src_write(gd54xx, 0xff); + return ret; + } + switch (ap) { case 0: default: @@ -1400,6 +1441,14 @@ gd54xx_readw_linear(uint32_t addr, void *p) } } + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + temp = gd54xx_readb_linear(addr, p); + temp |= gd54xx_readb_linear(addr + 1, p) << 8; + return temp; + } + switch (ap) { case 0: default: @@ -1442,6 +1491,16 @@ gd54xx_readl_linear(uint32_t addr, void *p) } } + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + temp = gd54xx_readb_linear(addr, p); + temp |= gd54xx_readb_linear(addr + 1, p) << 8; + temp |= gd54xx_readb_linear(addr + 2, p) << 16; + temp |= gd54xx_readb_linear(addr + 3, p) << 24; + return temp; + } + switch (ap) { case 0: default: @@ -1472,21 +1531,58 @@ gd54xx_readl_linear(uint32_t addr, void *p) } -static int -gd54xx_aperture2_enabled(gd54xx_t *gd54xx) +static uint8_t +gd5436_aperture2_readb(uint32_t addr, void *p) { - svga_t *svga = &gd54xx->svga; + gd54xx_t *gd54xx = (gd54xx_t *)p; + uint8_t ret = 0xff; - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) - return 0; + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->blt.msd_buf_cnt != 0) { + ret = gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos++]; + gd54xx->blt.msd_buf_cnt--; + } + ret = ret; /* Need to put a dummy line so the compiler doesn't mess up. */ + if (gd54xx->blt.msd_buf_cnt == 0) + gd54xx_mem_sys_src_write(gd54xx, 0xff); + } - if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) - return 0; + return ret; +} - if (!(gd54xx->blt.status & CIRRUS_BLT_APERTURE2)) - return 0; - return 1; +static uint16_t +gd5436_aperture2_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + uint16_t ret = 0xffff; + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd5436_aperture2_readb(addr, p); + ret |= gd5436_aperture2_readb(addr + 1, p) << 8; + } + + return ret; +} + + +static uint32_t +gd5436_aperture2_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + uint32_t ret = 0xffffffff; + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd5436_aperture2_readb(addr, p); + ret |= gd5436_aperture2_readb(addr + 1, p) << 8; + ret |= gd5436_aperture2_readb(addr + 2, p) << 16; + ret |= gd5436_aperture2_readb(addr + 3, p) << 24; + } + + return ret; } @@ -1495,8 +1591,8 @@ gd5436_aperture2_writeb(uint32_t addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) gd54xx_mem_sys_src_write(gd54xx, val); } @@ -1506,8 +1602,8 @@ gd5436_aperture2_writew(uint32_t addr, uint16_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd5436_aperture2_writeb(addr, val, gd54xx); gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); } @@ -1519,8 +1615,8 @@ gd5436_aperture2_writel(uint32_t addr, uint32_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd5436_aperture2_writeb(addr, val, gd54xx); gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); gd5436_aperture2_writeb(addr + 2, val >> 16, gd54xx); @@ -1552,8 +1648,8 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) } /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ - if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_mem_sys_src_write(gd54xx, val); return; } @@ -1601,8 +1697,8 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) } /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ - if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_writeb_linear(addr, val, gd54xx); gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); return; @@ -1667,8 +1763,8 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) } /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ - if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_writeb_linear(addr, val, gd54xx); gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); gd54xx_writeb_linear(addr + 2, val >> 16, gd54xx); @@ -1731,12 +1827,22 @@ gd54xx_read(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint8_t ret = 0xff; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_read(addr, svga); - if (gd54xx->countminusone) - return 0xff; + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->blt.msd_buf_cnt != 0) { + ret = gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos++]; + gd54xx->blt.msd_buf_cnt--; + } + ret = ret; /* Need to put a dummy line so the compiler doesn't mess up. */ + if (gd54xx->blt.msd_buf_cnt == 0) + gd54xx_mem_sys_src_write(gd54xx, 0xff); + return ret; + } addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; @@ -1749,12 +1855,17 @@ gd54xx_readw(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint16_t ret; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readw(addr, svga); - if (gd54xx->countminusone) - return 0xffff; + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd54xx_read(addr, p); + ret |= gd54xx_read(addr + 1, p) << 8; + return ret; + } addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; @@ -1767,12 +1878,19 @@ gd54xx_readl(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint32_t ret; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readl(addr, svga); - if (gd54xx->countminusone) - return 0xffffffff; + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd54xx_read(addr, p); + ret |= gd54xx_read(addr + 1, p) << 8; + ret |= gd54xx_read(addr + 2, p) << 16; + ret |= gd54xx_read(addr + 3, p) << 24; + return ret; + } addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; @@ -1964,8 +2082,8 @@ gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if (!gd543x_do_mmio(svga, addr) && gd54xx->countminusone && - !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (!gd543x_do_mmio(svga, addr) && !gd54xx->blt.ms_is_dest && + gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd54xx_mem_sys_src_write(gd54xx, val); return; } @@ -1984,7 +2102,8 @@ gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr + 1, val >> 8, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr + 1, val >> 8, gd54xx); } else { @@ -2007,7 +2126,8 @@ gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) gd543x_mmio_write(addr+2, val >> 16, gd54xx); gd543x_mmio_write(addr+3, val >> 24, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr+1, val >> 8, gd54xx); gd543x_mmio_write(addr+2, val >> 16, gd54xx); @@ -2154,6 +2274,16 @@ gd543x_mmio_read(uint32_t addr, void *p) } } else if (gd54xx->mmio_vram_overlap) ret = gd54xx_read(addr, gd54xx); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + if (gd54xx->blt.msd_buf_cnt != 0) { + ret = gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos++]; + gd54xx->blt.msd_buf_cnt--; + } + ret = ret; /* Need to put a dummy line so the compiler doesn't mess up. */ + if (gd54xx->blt.msd_buf_cnt == 0) + gd54xx_mem_sys_src_write(gd54xx, 0xff); + } return ret; } @@ -2164,12 +2294,19 @@ gd543x_mmio_readw(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint16_t ret = 0xffff; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); - return 0xffff; + ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd543x_mmio_read(addr, p); + ret |= gd543x_mmio_read(addr + 1, p) << 8; + } + + return ret; } @@ -2178,12 +2315,21 @@ gd543x_mmio_readl(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint32_t ret = 0xffffffff; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); - return 0xffffffff; + ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd543x_mmio_read(addr, p); + ret |= gd543x_mmio_read(addr + 1, p) << 8; + ret |= gd543x_mmio_read(addr + 2, p) << 16; + ret |= gd543x_mmio_read(addr + 3, p) << 24; + } + + return ret; } @@ -2350,17 +2496,20 @@ gd54xx_reset_blit(gd54xx_t *gd54xx) static void -gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) +gd54xx_mem_sys(gd54xx_t *gd54xx, int dest, uint32_t cpu_dat, uint32_t count) { uint8_t *dst, exp, target; int mask_shift; uint32_t byte_pos, bitmask = 0; svga_t *svga = &gd54xx->svga; + gd54xx->blt.ms_is_dest = dest; + if (gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_PATTERNCOPY)) gd54xx_reset_blit(gd54xx); else if (count == 0xffffffff) { gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + gd54xx->blt.msd_buf_pos = gd54xx->blt.msd_buf_cnt = 0; gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; gd54xx->blt.x_count = gd54xx->blt.xx_count = 0; gd54xx->blt.y_count = 0; @@ -2369,6 +2518,9 @@ gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) gd54xx->blt.sys_cnt = 0; return; } else if (gd54xx->countminusone) { + if (dest) + cpu_dat = svga->vram[gd54xx->blt.src_addr_backup & svga->vram_mask]; + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) || (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { if (!gd54xx->blt.xx_count && !gd54xx->blt.x_count) byte_pos = (((gd54xx->blt.mask >> 5) & 3) << 3); @@ -2389,7 +2541,10 @@ gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) bitmask = gd54xx_transparent_comp(gd54xx, gd54xx->blt.xx_count, exp); } - dst = &(svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); + if (dest) + dst = &(gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos & 15]); + else + dst = &(svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); target = *dst; gd54xx_rop(gd54xx, &target, &target, &exp); if ((gd54xx->blt.pixel_width == 3) && (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) @@ -2397,14 +2552,23 @@ gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) else gd54xx_blit(gd54xx, bitmask, dst, target, (gd54xx->blt.x_count < gd54xx->blt.pattern_x)); - gd54xx->blt.dst_addr_backup += gd54xx->blt.dir; + if (dest && (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + gd54xx->blt.src_addr_backup += gd54xx->blt.dir; + gd54xx->blt.msd_buf_pos++; + + if (!dest) + gd54xx->blt.dst_addr_backup += gd54xx->blt.dir; if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) gd54xx->blt.xx_count = (gd54xx->blt.xx_count + 1) % gd54xx->blt.pixel_width; - svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; + if (!dest) + svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; if (!gd54xx->blt.xx_count) { + if (dest && (gd54xx->blt.mode & !CIRRUS_BLTMODE_COLOREXPAND)) + gd54xx->blt.src_addr_backup += gd54xx->blt.dir; + /* 1 mask bit = 1 blitted pixel */ if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) mask_shift--; @@ -2420,17 +2584,27 @@ gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) if (!gd54xx->blt.x_count) { gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1); - if (gd54xx->blt.y_count) - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); - else { + if (gd54xx->blt.y_count) { + if (dest) + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr + (gd54xx->blt.src_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); + else + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); + } else { /* If we're here, the blit is over, reset. */ gd54xx_reset_blit(gd54xx); } /* Stop blitting and request new data if end of line reached. */ - return; + goto request_more_data; } } } + /* End of while. */ +request_more_data: + if (dest) { + gd54xx->blt.msd_buf_cnt = gd54xx->blt.msd_buf_pos; + gd54xx->blt.msd_buf_pos = 0; + } + return; } } @@ -2548,7 +2722,9 @@ gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *sv gd54xx->blt.pattern_x = 0; /* No skip in normal blit mode. */ if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) - gd54xx_mem_sys_src(gd54xx, cpu_dat, count); + gd54xx_mem_sys(gd54xx, 0, cpu_dat, count); + else if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) + gd54xx_mem_sys(gd54xx, 1, cpu_dat, count); else if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) { gd54xx_pattern_copy(gd54xx); gd54xx_reset_blit(gd54xx); @@ -2747,11 +2923,20 @@ static void mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); mem_mapping_set_p(&svga->mapping, gd54xx); - mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_writeb, gd543x_mmio_writew, gd543x_mmio_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, + gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, + gd543x_mmio_writeb, gd543x_mmio_writew, gd543x_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); mem_mapping_disable(&gd54xx->mmio_mapping); - mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, + gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, + gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); mem_mapping_disable(&gd54xx->linear_mapping); - mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0, NULL, NULL, NULL, gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0, + gd5436_aperture2_readb, gd5436_aperture2_readw, gd5436_aperture2_readl, + gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); mem_mapping_disable(&gd54xx->aperture2_mapping); io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);