850 lines
35 KiB
C
850 lines
35 KiB
C
/*Cirrus Logic CL-GD5429 emulation*/
|
|
#include "ibm.h"
|
|
#include "io.h"
|
|
#include "mem.h"
|
|
#include "video.h"
|
|
#include "vid_svga.h"
|
|
#include "vid_svga_render.h"
|
|
#include "vid_unk_ramdac.h"
|
|
|
|
struct
|
|
{
|
|
uint32_t bank[2];
|
|
|
|
struct
|
|
{
|
|
uint16_t bg_col, fg_col;
|
|
uint16_t width, height;
|
|
uint16_t dst_pitch, src_pitch;
|
|
uint32_t dst_addr, src_addr;
|
|
uint8_t mask, mode, rop;
|
|
|
|
uint32_t dst_addr_backup, src_addr_backup;
|
|
uint16_t width_backup, height_internal;
|
|
int x_count;
|
|
} blt;
|
|
|
|
} gd5429;
|
|
|
|
void gd5429_write(uint32_t addr, uint8_t val, void *priv);
|
|
uint8_t gd5429_read(uint32_t addr, void *priv);
|
|
|
|
void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv);
|
|
uint8_t gd5429_mmio_read(uint32_t addr, void *priv);
|
|
|
|
void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv);
|
|
void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv);
|
|
|
|
void gd5429_recalc_banking();
|
|
void gd5429_recalc_mapping();
|
|
|
|
void gd5429_out(uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
uint8_t old;
|
|
|
|
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
|
|
|
pclog("gd5429 out %04X %02X\n", addr, val);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x3c4:
|
|
seqaddr = val;
|
|
break;
|
|
case 0x3c5:
|
|
if (seqaddr > 5)
|
|
{
|
|
seqregs[seqaddr & 0x1f] = val;
|
|
switch (seqaddr & 0x1f)
|
|
{
|
|
case 0x10: case 0x30: case 0x50: case 0x70:
|
|
case 0x90: case 0xb0: case 0xd0: case 0xf0:
|
|
svga_hwcursor.x = (val << 3) | ((seqaddr >> 5) & 7);
|
|
pclog("svga_hwcursor.x = %i\n", svga_hwcursor.x);
|
|
break;
|
|
case 0x11: case 0x31: case 0x51: case 0x71:
|
|
case 0x91: case 0xb1: case 0xd1: case 0xf1:
|
|
svga_hwcursor.y = (val << 3) | ((seqaddr >> 5) & 7);
|
|
pclog("svga_hwcursor.y = %i\n", svga_hwcursor.y);
|
|
break;
|
|
case 0x12:
|
|
svga_hwcursor.ena = val & 1;
|
|
pclog("svga_hwcursor.ena = %i\n", svga_hwcursor.ena);
|
|
break;
|
|
case 0x13:
|
|
svga_hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256);
|
|
pclog("svga_hwcursor.addr = %x\n", svga_hwcursor.addr);
|
|
break;
|
|
|
|
case 0x17:
|
|
gd5429_recalc_mapping();
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 0x3cf:
|
|
if (gdcaddr == 5)
|
|
{
|
|
gdcreg[5] = val;
|
|
if (gdcreg[0xb] & 0x04)
|
|
writemode = gdcreg[5] & 7;
|
|
else
|
|
writemode = gdcreg[5] & 3;
|
|
readmode = val & 8;
|
|
pclog("writemode = %i\n", writemode);
|
|
return;
|
|
}
|
|
if (gdcaddr == 6)
|
|
{
|
|
if ((gdcreg[6] & 0xc) != (val & 0xc))
|
|
{
|
|
gdcreg[6] = val;
|
|
gd5429_recalc_mapping();
|
|
}
|
|
gdcreg[6] = val;
|
|
return;
|
|
}
|
|
if (gdcaddr > 8)
|
|
{
|
|
gdcreg[gdcaddr & 0x3f] = val;
|
|
switch (gdcaddr)
|
|
{
|
|
case 0x09: case 0x0a: case 0x0b:
|
|
gd5429_recalc_banking();
|
|
if (gdcreg[0xb] & 0x04)
|
|
writemode = gdcreg[5] & 7;
|
|
else
|
|
writemode = gdcreg[5] & 3;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 0x3D4:
|
|
crtcreg = val & 0x3f;
|
|
return;
|
|
case 0x3D5:
|
|
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
|
old=crtc[crtcreg];
|
|
crtc[crtcreg]=val;
|
|
|
|
if (old!=val)
|
|
{
|
|
if (crtcreg<0xE || crtcreg>0x10)
|
|
{
|
|
fullchange=changeframecount;
|
|
svga_recalctimings();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
svga_out(addr, val, NULL);
|
|
}
|
|
|
|
uint8_t gd5429_in(uint16_t addr, void *priv)
|
|
{
|
|
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
|
|
|
if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x3c5:
|
|
if (seqaddr > 5)
|
|
{
|
|
switch (seqaddr)
|
|
{
|
|
case 6:
|
|
return ((seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f;
|
|
}
|
|
return seqregs[seqaddr & 0x3f];
|
|
}
|
|
break;
|
|
|
|
case 0x3cf:
|
|
if (gdcaddr > 8)
|
|
{
|
|
return gdcreg[seqaddr & 0x3f];
|
|
}
|
|
break;
|
|
|
|
case 0x3D4:
|
|
return crtcreg;
|
|
case 0x3D5:
|
|
switch (crtcreg)
|
|
{
|
|
case 0x27: /*ID*/
|
|
return 0x9c; /*GD5429*/
|
|
}
|
|
return crtc[crtcreg];
|
|
}
|
|
return svga_in(addr, NULL);
|
|
}
|
|
|
|
void gd5429_recalc_banking()
|
|
{
|
|
if (gdcreg[0xb] & 0x20)
|
|
gd5429.bank[0] = (gdcreg[0x09] & 0x7f) << 14;
|
|
else
|
|
gd5429.bank[0] = gdcreg[0x09] << 12;
|
|
|
|
if (gdcreg[0xb] & 0x01)
|
|
{
|
|
if (gdcreg[0xb] & 0x20)
|
|
gd5429.bank[1] = (gdcreg[0x0a] & 0x7f) << 14;
|
|
else
|
|
gd5429.bank[1] = gdcreg[0x0a] << 12;
|
|
}
|
|
else
|
|
gd5429.bank[1] = gd5429.bank[0] + 0x8000;
|
|
}
|
|
|
|
void gd5429_recalc_mapping()
|
|
{
|
|
mem_removehandler(0xa0000, 0x20000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
|
mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
|
mem_removehandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL);
|
|
pclog("Write mapping %02X %i\n", gdcreg[6], seqregs[0x17] & 0x04);
|
|
switch (gdcreg[6] & 0x0C)
|
|
{
|
|
case 0x0: /*128k at A0000*/
|
|
mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
|
break;
|
|
case 0x4: /*64k at A0000*/
|
|
mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
|
if (seqregs[0x17] & 0x04)
|
|
mem_sethandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL);
|
|
break;
|
|
case 0x8: /*32k at B0000*/
|
|
mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
|
break;
|
|
case 0xC: /*32k at B8000*/
|
|
mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gd5429_recalctimings()
|
|
{
|
|
if (seqregs[7] & 0x01)
|
|
{
|
|
svga_render = svga_render_8bpp_highres;
|
|
}
|
|
|
|
svga_ma |= ((crtc[0x1b] & 0x01) << 16) | ((crtc[0x1b] & 0xc) << 15);
|
|
pclog("MA now %05X %02X\n", svga_ma, crtc[0x1b]);
|
|
}
|
|
|
|
void gd5429_hwcursor_draw(int displine)
|
|
{
|
|
int x;
|
|
uint8_t dat[2];
|
|
int xx;
|
|
int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff;
|
|
|
|
pclog("HWcursor %i %i %i %i %x %02X %02X\n", svga_hwcursor_latch.x, svga_hwcursor_latch.y, offset, displine, svga_hwcursor_latch.addr, vram[svga_hwcursor_latch.addr], vram[svga_hwcursor_latch.addr + 0x80]);
|
|
for (x = 0; x < 32; x += 8)
|
|
{
|
|
dat[0] = vram[svga_hwcursor_latch.addr];
|
|
dat[1] = 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])[offset + 32] = 0;
|
|
if (dat[0] & 0x80)
|
|
((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
|
|
}
|
|
|
|
offset++;
|
|
dat[0] <<= 1;
|
|
dat[1] <<= 1;
|
|
}
|
|
svga_hwcursor_latch.addr++;
|
|
}
|
|
}
|
|
|
|
int gd5429_init()
|
|
{
|
|
svga_recalctimings_ex = gd5429_recalctimings;
|
|
svga_hwcursor_draw = gd5429_hwcursor_draw;
|
|
svga_vram_limit = 2 << 20; /*2mb*/
|
|
vrammask = 0x1fffff;
|
|
|
|
svga_hwcursor.yoff = 32;
|
|
svga_hwcursor.xoff = 0;
|
|
|
|
memset(&gd5429, 0, sizeof(gd5429));
|
|
|
|
gd5429.bank[1] = 0x8000;
|
|
|
|
return svga_init();
|
|
}
|
|
|
|
static uint8_t la, lb, lc, ld;
|
|
|
|
uint8_t gd5429_read_linear(uint32_t addr, void *priv);
|
|
void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv);
|
|
|
|
void gd5429_write(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
// pclog("gd5429_write : %05X %02X ", addr, val);
|
|
addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1];
|
|
// pclog("%08X\n", addr);
|
|
gd5429_write_linear(addr, val, priv);
|
|
}
|
|
|
|
uint8_t gd5429_read(uint32_t addr, void *priv)
|
|
{
|
|
uint8_t ret;
|
|
// pclog("gd5429_read : %05X ", addr);
|
|
addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1];
|
|
ret = gd5429_read_linear(addr, priv);
|
|
// pclog("%08X %02X\n", addr, ret);
|
|
return ret;
|
|
}
|
|
|
|
void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
uint8_t vala,valb,valc,vald,wm=writemask;
|
|
int writemask2 = writemask;
|
|
|
|
cycles -= video_timing_b;
|
|
cycles_lost += video_timing_b;
|
|
|
|
egawrites++;
|
|
|
|
// if (svga_output) pclog("Write LFB %08X %02X ", addr, val);
|
|
if (!(gdcreg[6]&1)) fullchange=2;
|
|
if (chain4 && (writemode < 4))
|
|
{
|
|
writemask2=1<<(addr&3);
|
|
addr&=~3;
|
|
}
|
|
else
|
|
{
|
|
addr<<=2;
|
|
}
|
|
addr &= 0x7fffff;
|
|
// if (svga_output) pclog("%08X\n", addr);
|
|
changedvram[addr>>10]=changeframecount;
|
|
|
|
switch (writemode)
|
|
{
|
|
case 4:
|
|
pclog("Writemode 4 : %X ", addr);
|
|
addr <<= 1;
|
|
changedvram[addr>>10]=changeframecount;
|
|
pclog("%X %X\n", addr, val);
|
|
if (val & 0x80)
|
|
vram[addr + 0] = gdcreg[1];
|
|
if (val & 0x40)
|
|
vram[addr + 1] = gdcreg[1];
|
|
if (val & 0x20)
|
|
vram[addr + 2] = gdcreg[1];
|
|
if (val & 0x10)
|
|
vram[addr + 3] = gdcreg[1];
|
|
if (val & 0x08)
|
|
vram[addr + 4] = gdcreg[1];
|
|
if (val & 0x04)
|
|
vram[addr + 5] = gdcreg[1];
|
|
if (val & 0x02)
|
|
vram[addr + 6] = gdcreg[1];
|
|
if (val & 0x01)
|
|
vram[addr + 7] = gdcreg[1];
|
|
break;
|
|
|
|
case 5:
|
|
pclog("Writemode 5 : %X ", addr);
|
|
addr <<= 1;
|
|
changedvram[addr>>10]=changeframecount;
|
|
pclog("%X %X\n", addr, val);
|
|
vram[addr + 0] = (val & 0x80) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 1] = (val & 0x40) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 2] = (val & 0x20) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 3] = (val & 0x10) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 4] = (val & 0x08) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 5] = (val & 0x04) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 6] = (val & 0x02) ? gdcreg[1] : gdcreg[0];
|
|
vram[addr + 7] = (val & 0x01) ? gdcreg[1] : gdcreg[0];
|
|
break;
|
|
|
|
case 1:
|
|
if (writemask2&1) vram[addr]=la;
|
|
if (writemask2&2) vram[addr|0x1]=lb;
|
|
if (writemask2&4) vram[addr|0x2]=lc;
|
|
if (writemask2&8) vram[addr|0x3]=ld;
|
|
break;
|
|
case 0:
|
|
if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val];
|
|
if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1])
|
|
{
|
|
if (writemask2&1) vram[addr]=val;
|
|
if (writemask2&2) vram[addr|0x1]=val;
|
|
if (writemask2&4) vram[addr|0x2]=val;
|
|
if (writemask2&8) vram[addr|0x3]=val;
|
|
}
|
|
else
|
|
{
|
|
if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0;
|
|
else vala=val;
|
|
if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0;
|
|
else valb=val;
|
|
if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0;
|
|
else valc=val;
|
|
if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0;
|
|
else vald=val;
|
|
|
|
switch (gdcreg[3]&0x18)
|
|
{
|
|
case 0: /*Set*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
|
break;
|
|
case 8: /*AND*/
|
|
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
|
break;
|
|
case 0x10: /*OR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
|
break;
|
|
case 0x18: /*XOR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
|
break;
|
|
}
|
|
// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!(gdcreg[3]&0x18) && !gdcreg[1])
|
|
{
|
|
if (writemask2&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]);
|
|
if (writemask2&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]);
|
|
if (writemask2&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]);
|
|
if (writemask2&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]);
|
|
}
|
|
else
|
|
{
|
|
vala=((val&1)?0xFF:0);
|
|
valb=((val&2)?0xFF:0);
|
|
valc=((val&4)?0xFF:0);
|
|
vald=((val&8)?0xFF:0);
|
|
switch (gdcreg[3]&0x18)
|
|
{
|
|
case 0: /*Set*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
|
break;
|
|
case 8: /*AND*/
|
|
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
|
break;
|
|
case 0x10: /*OR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
|
break;
|
|
case 0x18: /*XOR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val];
|
|
wm=gdcreg[8];
|
|
gdcreg[8]&=val;
|
|
|
|
vala=(gdcreg[0]&1)?0xFF:0;
|
|
valb=(gdcreg[0]&2)?0xFF:0;
|
|
valc=(gdcreg[0]&4)?0xFF:0;
|
|
vald=(gdcreg[0]&8)?0xFF:0;
|
|
switch (gdcreg[3]&0x18)
|
|
{
|
|
case 0: /*Set*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
|
break;
|
|
case 8: /*AND*/
|
|
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
|
break;
|
|
case 0x10: /*OR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
|
break;
|
|
case 0x18: /*XOR*/
|
|
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
|
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
|
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
|
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
|
break;
|
|
}
|
|
gdcreg[8]=wm;
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8_t gd5429_read_linear(uint32_t addr, void *priv)
|
|
{
|
|
uint8_t temp,temp2,temp3,temp4;
|
|
|
|
cycles -= video_timing_b;
|
|
cycles_lost += video_timing_b;
|
|
|
|
egareads++;
|
|
|
|
if (chain4)
|
|
{
|
|
addr &= 0x7fffff;
|
|
if (addr >= svga_vram_limit)
|
|
return 0xff;
|
|
return vram[addr & 0x7fffff];
|
|
}
|
|
else addr<<=2;
|
|
|
|
addr &= 0x7fffff;
|
|
|
|
if (addr >= svga_vram_limit)
|
|
return 0xff;
|
|
|
|
la=vram[addr];
|
|
lb=vram[addr|0x1];
|
|
lc=vram[addr|0x2];
|
|
ld=vram[addr|0x3];
|
|
if (readmode)
|
|
{
|
|
temp= (colournocare&1) ?0xFF:0;
|
|
temp&=la;
|
|
temp^=(colourcompare&1)?0xFF:0;
|
|
temp2= (colournocare&2) ?0xFF:0;
|
|
temp2&=lb;
|
|
temp2^=(colourcompare&2)?0xFF:0;
|
|
temp3= (colournocare&4) ?0xFF:0;
|
|
temp3&=lc;
|
|
temp3^=(colourcompare&4)?0xFF:0;
|
|
temp4= (colournocare&8) ?0xFF:0;
|
|
temp4&=ld;
|
|
temp4^=(colourcompare&8)?0xFF:0;
|
|
return ~(temp|temp2|temp3|temp4);
|
|
}
|
|
//printf("Read %02X %04X %04X\n",vram[addr|readplane],addr,readplane);
|
|
return vram[addr|readplane];
|
|
}
|
|
|
|
void gd5429_start_blit(uint32_t cpu_dat, int count)
|
|
{
|
|
pclog("gd5429_start_blit %i\n", count);
|
|
if (count == -1)
|
|
{
|
|
gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr;
|
|
gd5429.blt.src_addr_backup = gd5429.blt.src_addr;
|
|
gd5429.blt.width_backup = gd5429.blt.width;
|
|
gd5429.blt.height_internal = gd5429.blt.height;
|
|
gd5429.blt.x_count = gd5429.blt.mask & 7;
|
|
pclog("gd5429_start_blit : size %i, %i\n", gd5429.blt.width, gd5429.blt.height);
|
|
|
|
if (gd5429.blt.mode & 0x04)
|
|
{
|
|
// pclog("blt.mode & 0x04\n");
|
|
mem_removehandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
|
mem_sethandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
|
gd5429_recalc_mapping();
|
|
}
|
|
}
|
|
|
|
while (count)
|
|
{
|
|
uint8_t src, dst;
|
|
int mask;
|
|
|
|
if (gd5429.blt.mode & 0x04)
|
|
{
|
|
if (gd5429.blt.mode & 0x80)
|
|
{
|
|
src = (cpu_dat & 0x80) ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
|
mask = cpu_dat & 0x80;
|
|
cpu_dat <<= 1;
|
|
count--;
|
|
}
|
|
else
|
|
{
|
|
src = cpu_dat & 0xff;
|
|
cpu_dat >>= 8;
|
|
count -= 8;
|
|
mask = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (gd5429.blt.mode & 0xc0)
|
|
{
|
|
case 0x00:
|
|
src = vram[gd5429.blt.src_addr & vrammask];
|
|
gd5429.blt.src_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1);
|
|
mask = 1;
|
|
break;
|
|
case 0x40:
|
|
src = vram[(gd5429.blt.src_addr & (vrammask & ~7)) | (gd5429.blt.dst_addr & 7)];
|
|
mask = 1;
|
|
break;
|
|
case 0x80:
|
|
mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> gd5429.blt.x_count);
|
|
src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
|
gd5429.blt.x_count++;
|
|
if (gd5429.blt.x_count == 8)
|
|
{
|
|
gd5429.blt.x_count = 0;
|
|
gd5429.blt.src_addr++;
|
|
}
|
|
break;
|
|
case 0xc0:
|
|
mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> (gd5429.blt.dst_addr & 7));
|
|
src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
|
break;
|
|
}
|
|
count--;
|
|
}
|
|
dst = vram[gd5429.blt.dst_addr & vrammask];
|
|
changedvram[(gd5429.blt.dst_addr & vrammask) >> 10] = changeframecount;
|
|
|
|
pclog("Blit %i,%i %06X %06X %06X %02X %02X %02X %02X ", gd5429.blt.width, gd5429.blt.height_internal, gd5429.blt.src_addr, gd5429.blt.dst_addr, gd5429.blt.src_addr & vrammask, vram[gd5429.blt.src_addr & vrammask], 0x80 >> (gd5429.blt.dst_addr & 7), src, dst);
|
|
switch (gd5429.blt.rop)
|
|
{
|
|
case 0x00: dst = 0; break;
|
|
case 0x05: dst = src & dst; break;
|
|
case 0x06: dst = dst; break;
|
|
case 0x09: dst = src & ~dst; break;
|
|
case 0x0b: dst = ~ dst; break;
|
|
case 0x0d: dst = src; break;
|
|
case 0x0e: dst = 0xff; break;
|
|
case 0x50: dst = ~ src & dst; break;
|
|
case 0x59: dst = src ^ dst; break;
|
|
case 0x6d: dst = src | dst; break;
|
|
case 0x90: dst = ~(src | dst); break;
|
|
case 0x95: dst = ~(src ^ dst); break;
|
|
case 0xad: dst = src | ~dst; break;
|
|
case 0xd0: dst = ~src; break;
|
|
case 0xd6: dst = ~src | dst; break;
|
|
case 0xda: dst = ~(src & dst); break;
|
|
}
|
|
pclog("%02X %02X\n", dst, mask);
|
|
|
|
if ((gd5429.blt.width_backup - gd5429.blt.width) >= (gd5429.blt.mask & 7) &&
|
|
!((gd5429.blt.mode & 0x08) && !mask))
|
|
vram[gd5429.blt.dst_addr & vrammask] = dst;
|
|
|
|
gd5429.blt.dst_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1);
|
|
|
|
gd5429.blt.width--;
|
|
|
|
if (gd5429.blt.width == 0xffff)
|
|
{
|
|
gd5429.blt.width = gd5429.blt.width_backup;
|
|
|
|
gd5429.blt.dst_addr = gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.dst_pitch : gd5429.blt.dst_pitch);
|
|
|
|
switch (gd5429.blt.mode & 0xc0)
|
|
{
|
|
case 0x00:
|
|
gd5429.blt.src_addr = gd5429.blt.src_addr_backup = gd5429.blt.src_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.src_pitch : gd5429.blt.src_pitch);
|
|
break;
|
|
case 0x40:
|
|
gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -8 : 8)) & 0x38) | (gd5429.blt.src_addr & ~0x38);
|
|
break;
|
|
case 0x80:
|
|
if (gd5429.blt.x_count != 0)
|
|
{
|
|
gd5429.blt.x_count = 0;
|
|
gd5429.blt.src_addr++;
|
|
}
|
|
break;
|
|
case 0xc0:
|
|
gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -1 : 1)) & 7) | (gd5429.blt.src_addr & ~7);
|
|
break;
|
|
}
|
|
|
|
gd5429.blt.height_internal--;
|
|
if (gd5429.blt.height_internal == 0xffff)
|
|
{
|
|
if (gd5429.blt.mode & 0x04)
|
|
{
|
|
mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
|
gd5429_recalc_mapping();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (gd5429.blt.mode & 0x04)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
pclog("MMIO write %08X %02X\n", addr, val);
|
|
switch (addr & 0xff)
|
|
{
|
|
case 0x00:
|
|
gd5429.blt.bg_col = (gd5429.blt.bg_col & 0xff00) | val;
|
|
break;
|
|
case 0x01:
|
|
gd5429.blt.bg_col = (gd5429.blt.bg_col & 0x00ff) | (val << 8);
|
|
break;
|
|
|
|
case 0x04:
|
|
gd5429.blt.fg_col = (gd5429.blt.fg_col & 0xff00) | val;
|
|
break;
|
|
case 0x05:
|
|
gd5429.blt.fg_col = (gd5429.blt.fg_col & 0x00ff) | (val << 8);
|
|
break;
|
|
|
|
case 0x08:
|
|
gd5429.blt.width = (gd5429.blt.width & 0xff00) | val;
|
|
break;
|
|
case 0x09:
|
|
gd5429.blt.width = (gd5429.blt.width & 0x00ff) | (val << 8);
|
|
break;
|
|
case 0x0a:
|
|
gd5429.blt.height = (gd5429.blt.height & 0xff00) | val;
|
|
break;
|
|
case 0x0b:
|
|
gd5429.blt.height = (gd5429.blt.height & 0x00ff) | (val << 8);
|
|
break;
|
|
case 0x0c:
|
|
gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0xff00) | val;
|
|
break;
|
|
case 0x0d:
|
|
gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0x00ff) | (val << 8);
|
|
break;
|
|
case 0x0e:
|
|
gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0xff00) | val;
|
|
break;
|
|
case 0x0f:
|
|
gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0x00ff) | (val << 8);
|
|
break;
|
|
|
|
case 0x10:
|
|
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xffff00) | val;
|
|
break;
|
|
case 0x11:
|
|
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xff00ff) | (val << 8);
|
|
break;
|
|
case 0x12:
|
|
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0x00ffff) | (val << 16);
|
|
break;
|
|
|
|
case 0x14:
|
|
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xffff00) | val;
|
|
break;
|
|
case 0x15:
|
|
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xff00ff) | (val << 8);
|
|
break;
|
|
case 0x16:
|
|
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0x00ffff) | (val << 16);
|
|
break;
|
|
|
|
case 0x17:
|
|
gd5429.blt.mask = val;
|
|
break;
|
|
case 0x18:
|
|
gd5429.blt.mode = val;
|
|
break;
|
|
|
|
case 0x1a:
|
|
gd5429.blt.rop = val;
|
|
break;
|
|
|
|
case 0x40:
|
|
if (val & 0x02)
|
|
gd5429_start_blit(0, -1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8_t gd5429_mmio_read(uint32_t addr, void *priv)
|
|
{
|
|
pclog("MMIO read %08X\n", addr);
|
|
switch (addr & 0xff)
|
|
{
|
|
case 0x40: /*BLT status*/
|
|
return 0;
|
|
}
|
|
return 0xff; /*All other registers read-only*/
|
|
}
|
|
|
|
void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
pclog("gd5429_blt_write_w %08X %08X\n", addr, val);
|
|
gd5429_start_blit(val, 16);
|
|
}
|
|
|
|
void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
pclog("gd5429_blt_write_l %08X %08X %04X %04X\n", addr, val, ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00));
|
|
if ((gd5429.blt.mode & 0x84) == 0x84)
|
|
{
|
|
gd5429_start_blit( val & 0xff, 8);
|
|
gd5429_start_blit((val >> 8) & 0xff, 8);
|
|
gd5429_start_blit((val >> 16) & 0xff, 8);
|
|
gd5429_start_blit((val >> 24) & 0xff, 8);
|
|
}
|
|
else
|
|
gd5429_start_blit(val, 32);
|
|
}
|
|
|
|
GFXCARD vid_gd5429 =
|
|
{
|
|
gd5429_init,
|
|
/*IO at 3Cx/3Dx*/
|
|
gd5429_out,
|
|
gd5429_in,
|
|
/*IO at 3Ax/3Bx*/
|
|
video_out_null,
|
|
video_in_null,
|
|
|
|
svga_poll,
|
|
svga_recalctimings,
|
|
|
|
svga_write,
|
|
video_write_null,
|
|
video_write_null,
|
|
|
|
svga_read,
|
|
video_read_null,
|
|
video_read_null
|
|
};
|