From 48c44b53832ee474fbfec770bc0ccff3266233c8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 23 Mar 2018 04:40:49 +0100 Subject: [PATCH] Implemented support for the special Cirrus Logic extended DAC color palette; Slightly reworked the Cirrus Logic hardware cursor handler, it now loads the foreground and background colors from the special color palette; Implemented Cirrus Logic SR 0x12 bit 7 that if set, makes the card use special color palette entry 2 for the overscan border color instead of attribute register 0x11. --- src/video/vid_cl54xx.c | 220 +++++++++++++++++++++++++++++++++-------- src/video/vid_svga.c | 24 +++-- src/video/vid_svga.h | 3 +- 3 files changed, 196 insertions(+), 51 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index d590d291c..576d4eeea 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.14 2018/03/23 + * Version: @(#)vid_cl_54xx.c 1.0.15 2018/03/23 * * Authors: Sarah Walker, * Barry Rodewald, @@ -163,16 +163,20 @@ typedef struct gd54xx_t uint16_t pixel_cnt; uint16_t scan_cnt; } blt; - - int pci, vlb; - - uint8_t pci_regs[256]; - uint8_t int_line; - int card; - - uint32_t lfb_base; - - int mmio_vram_overlap; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; } gd54xx_t; static void @@ -203,16 +207,57 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; uint8_t old; + int c; + uint8_t o; + uint32_t o32; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; case 0x3c4: svga->seqaddr = val; break; case 0x3c5: if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; svga->seqregs[svga->seqaddr & 0x1f] = val; switch (svga->seqaddr & 0x1f) { case 6: @@ -237,18 +282,30 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); break; case 0x12: - svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; - svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; - if (val & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); - else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); + if ((o ^ val) & 0x80) { + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + } + if ((o ^ val) & CIRRUS_CURSOR_SHOW) + svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; + if ((o ^ val) & CIRRUS_CURSOR_LARGE) { + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; + if (val & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); + } break; case 0x13: - if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3c) * 256)); - else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + if (o != val) { + if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + } break; case 0x07: svga->set_reset_disabled = svga->seqregs[7] & 1; @@ -268,6 +325,42 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } gd54xx->ramdac.state = 0; break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + gd54xx->extpal[svga->dac_write].r = svga->dac_r; + gd54xx->extpal[svga->dac_write].g = svga->dac_g; + gd54xx->extpal[svga->dac_write].b = val; + gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_write = (svga->dac_write + 1) & 15; + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_write = (svga->dac_write + 1) & 255; + } + svga->dac_pos = 0; + break; + } + return; case 0x3cf: if (svga->gdcaddr == 0) gd543x_mmio_write(0xb8000, val, gd54xx); @@ -487,6 +580,32 @@ gd54xx_in(uint16_t addr, void *p) return svga->seqregs[svga->seqaddr & 0x3f]; } break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].r & 0x3f; + else + return svga->vgapal[svga->dac_read].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].g & 0x3f; + else + return svga->vgapal[svga->dac_read].g & 0x3f; + case 2: + svga->dac_pos=0; + if (svga->seqregs[0x12] & 2) { + svga->dac_read = (svga->dac_read + 1) & 15; + return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; + } else { + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + } + return 0xFF; case 0x3C6: if (gd54xx->ramdac.state == 4) { gd54xx->ramdac.state = 0; @@ -740,18 +859,20 @@ gd54xx_recalctimings(svga_t *svga) static void gd54xx_hwcursor_draw(svga_t *svga, int displine) { - int x; - uint8_t dat[2]; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; - int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; - - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += pitch; - - for (x = 0; x < svga->hwcursor.xsize; x += 8) { + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb; + uint8_t dat[2]; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { dat[0] = svga->vram[svga->hwcursor_latch.addr]; if (svga->hwcursor.xsize == 64) dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; @@ -759,10 +880,25 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; for (xx = 0; xx < 8; xx++) { if (offset >= svga->hwcursor_latch.x) { - if (dat[1] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = 0; - if (dat[0] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + comb = ((dat[0] & 0x80) >> 6) | ((dat[1] & 0x80) >> 7); + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } } offset++; @@ -770,12 +906,12 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) dat[1] <<= 1; } svga->hwcursor_latch.addr++; - } - - if (svga->hwcursor.xsize == 64) + } + + if (svga->hwcursor.xsize == 64) svga->hwcursor_latch.addr += 8; - - if (svga->interlace && !svga->hwcursor_oddeven) + + if (svga->interlace && !svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index f09b99f6d..cb03307a2 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.26 2018/03/16 + * Version: @(#)vid_svga.c 1.0.27 2018/03/23 * * Authors: Sarah Walker, * Miran Grca, @@ -69,7 +69,7 @@ void svga_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3C0: - case 0x3C1: + case 0x3C1: if (!svga->attrff) { svga->attraddr = val & 31; @@ -95,9 +95,16 @@ void svga_out(uint16_t addr, uint8_t val, void *p) } } /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ - if ((svga->attraddr == 0x10) || (svga->attraddr == 0x11)) + if (svga->attraddr == 0x10) + { if (o != val) svga_recalctimings(svga); - if (svga->attraddr == 0x12) + } + else if (svga->attraddr == 0x11) + { + svga->overscan_color = svga->pallook[svga->overscan_color]; + if (o != val) svga_recalctimings(svga); + } + else if (svga->attraddr == 0x12) { if ((val & 0xf) != svga->plane_mask) svga->fullchange = changeframecount; @@ -687,6 +694,7 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->readmode = 0; svga->attrregs[0x11] = 0; + svga->overscan_color = 0x000000; overscan_x = 16; overscan_y = 32; @@ -1270,7 +1278,7 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < (xsize + x_add); j++) - p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + p[j] = svga_color_transform(svga->overscan_color); } /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ @@ -1278,15 +1286,15 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; for (j = 0; j < (xsize + x_add); j++) - p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + p[j] = svga_color_transform(svga->overscan_color); } for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < 8; j++) { - p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); - p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); + p[j] = svga->pallook[svga->overscan_color]; + p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->overscan_color); } } } diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index bf1189ed4..b2811995b 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -8,7 +8,7 @@ * * Generic SVGA handling. * - * Version: @(#)vid_svga.h 1.0.9 2018/03/01 + * Version: @(#)vid_svga.h 1.0.10 2018/03/23 * * Authors: Sarah Walker, * Miran Grca, @@ -153,6 +153,7 @@ typedef struct svga_t void *p; uint32_t linear_base; + uint32_t overscan_color; } svga_t; extern int svga_init(svga_t *svga, void *p, int memsize,