pcem/src/vid_cl5429.c
2013-05-27 19:56:33 +01:00

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
};