ViRGE: Preliminary stream processor emulation - enough to fix double buffering in DirectX.

Implemented transparent blit mode with colour sources.
Implemented old style MMIO.
This commit is contained in:
TomW 2014-03-20 16:33:31 +00:00
commit 92c45591c7

View file

@ -70,6 +70,33 @@ typedef struct virge_t
uint32_t pattern_16[8*8];
uint32_t pattern_32[8*8];
} s3d;
struct
{
uint32_t pri_ctrl;
uint32_t chroma_ctrl;
uint32_t sec_ctrl;
uint32_t chroma_upper_bound;
uint32_t sec_filter;
uint32_t blend_ctrl;
uint32_t pri_fb0, pri_fb1;
uint32_t pri_stride;
uint32_t buffer_ctrl;
uint32_t sec_fb0, sec_fb1;
uint32_t sec_stride;
uint32_t overlay_ctrl;
uint32_t k1_vert_scale;
uint32_t k2_vert_scale;
uint32_t dda_vert_accumulator;
uint32_t fifo_ctrl;
uint32_t pri_start;
uint32_t pri_size;
uint32_t sec_start;
uint32_t sec_size;
int pri_x, pri_y, pri_w, pri_h;
int sec_x, sec_y, sec_w, sec_h;
} streams;
} virge_t;
static void s3_virge_updatemapping(virge_t *virge);
@ -83,13 +110,6 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p);
static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p);
static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p);
static uint8_t s3_virge_new_mmio_read(uint32_t addr, void *p);
static uint16_t s3_virge_new_mmio_read_w(uint32_t addr, void *p);
static uint32_t s3_virge_new_mmio_read_l(uint32_t addr, void *p);
static void s3_virge_new_mmio_write(uint32_t addr, uint8_t val, void *p);
static void s3_virge_new_mmio_write_w(uint32_t addr, uint16_t val, void *p);
static void s3_virge_new_mmio_write_l(uint32_t addr, uint32_t val, void *p);
enum
{
CMD_SET_AE = 1,
@ -159,7 +179,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
svga->crtcreg = val & 0x7f;
return;
case 0x3d5:
//pclog("Write CRTC R%02X %02X\n", svga->crtcreg, val);
// pclog("Write CRTC R%02X %02X\n", svga->crtcreg, val);
if (svga->crtcreg <= 7 && svga->crtc[0x11] & 0x80)
return;
if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48)
@ -218,7 +238,6 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
case 0x46: case 0x47: case 0x48: case 0x49:
case 0x4c: case 0x4d: case 0x4e: case 0x4f:
svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff;
if (svga->bpp == 32) svga->hwcursor.x >>= 1;
svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff;
svga->hwcursor.xoff = svga->crtc[0x4e] & 63;
svga->hwcursor.yoff = svga->crtc[0x4f] & 63;
@ -235,8 +254,8 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
{
case 3: svga->bpp = 15; break;
case 5: svga->bpp = 16; break;
// case 7: svga->bpp = 24; break;
case 13: svga->bpp = 24; break;
case 7: svga->bpp = 24; break;
case 13: svga->bpp = 32; break;
default: svga->bpp = 8; break;
}
break;
@ -301,61 +320,86 @@ static uint8_t s3_virge_in(uint16_t addr, void *p)
static void s3_virge_recalctimings(svga_t *svga)
{
virge_t *virge = (virge_t *)svga->p;
// pclog("recalctimings\n");
svga->ma_latch |= (virge->ma_ext << 16);
// pclog("SVGA_MA %08X\n", svga_ma);
// if (gdcreg[5] & 0x40) svga_lowres = !(crtc[0x3a] & 0x10);
if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
{
switch (svga->bpp)
{
case 8:
svga->render = svga_render_8bpp_highres;
break;
case 15:
svga->render = svga_render_15bpp_highres;
break;
case 16:
svga->render = svga_render_16bpp_highres;
break;
case 24:
svga->render = svga_render_24bpp_highres;
break;
case 32:
svga->render = svga_render_32bpp_highres;
break;
}
}
if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100;
if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100;
if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400;
if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400;
if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400;
if (svga->crtc[0x5e] & 0x40) svga->split += 0x400;
if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4;
else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100;
if (!svga->rowoffset) svga->rowoffset = 256;
svga->interlace = svga->crtc[0x42] & 0x20;
// pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp);
if (svga->bpp == 15 || svga->bpp == 16)
if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/
{
svga->htotal >>= 1;
svga->hdisp >>= 1;
svga->ma_latch |= (virge->ma_ext << 16);
if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4;
else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100;
if (!svga->rowoffset) svga->rowoffset = 256;
if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
{
switch (svga->bpp)
{
case 8:
svga->render = svga_render_8bpp_highres;
break;
case 15:
svga->render = svga_render_15bpp_highres;
break;
case 16:
svga->render = svga_render_16bpp_highres;
break;
case 24:
svga->render = svga_render_24bpp_highres;
break;
case 32:
svga->render = svga_render_32bpp_highres;
break;
}
}
// pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp);
if (svga->bpp == 15 || svga->bpp == 16)
{
svga->htotal >>= 1;
svga->hdisp >>= 1;
}
if (svga->bpp == 24)
{
svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/
}
}
if (svga->bpp == 24)
else /*Streams mode*/
{
svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/
if (virge->streams.buffer_ctrl & 1)
svga->ma_latch = virge->streams.pri_fb1 >> 2;
else
svga->ma_latch = virge->streams.pri_fb0 >> 2;
svga->rowoffset = virge->streams.pri_stride >> 3;
switch ((virge->streams.pri_ctrl >> 24) & 0x7)
{
case 0: /*RGB-8 (CLUT)*/
svga->render = svga_render_8bpp_highres;
break;
case 3: /*KRGB-16 (1.5.5.5)*/
svga->render = svga_render_15bpp_highres;
break;
case 5: /*RGB-16 (5.6.5)*/
svga->render = svga_render_16bpp_highres;
break;
case 6: /*RGB-24 (8.8.8)*/
svga->render = svga_render_24bpp_highres;
break;
case 7: /*XRGB-32 (X.8.8.8)*/
svga->render = svga_render_32bpp_highres;
break;
}
}
/* if (svga->bpp == 32)
{
svga->htotal <<= 2;
svga->hdisp <<= 2;
}*/
//svga_clock = cpuclock / sdac_getclock((svga_miscout >> 2) & 3);
// pclog("SVGA_CLOCK = %f %02X %f\n", svga_clock, svga_miscout, cpuclock);
//if (bpp > 8) svga_clock /= 2;
}
static void s3_virge_updatemapping(virge_t *virge)
@ -433,7 +477,7 @@ static void s3_virge_updatemapping(virge_t *virge)
if (svga->crtc[0x53] & 0x20)
mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000);
else
mem_mapping_set_addr(&virge->mmio_mapping, 0xa8000, 0x8000);
mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000);
}
else
mem_mapping_disable(&virge->mmio_mapping);
@ -448,34 +492,6 @@ static void s3_virge_updatemapping(virge_t *virge)
static uint8_t s3_virge_mmio_read(uint32_t addr, void *p)
{
// pclog("MMIO readb %08X\n", addr);
return 0xff;
}
static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p)
{
// pclog("MMIO readw %08X\n", addr);
return 0xffff;
}
static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p)
{
// pclog("MMIO readl %08X\n", addr);
return 0xffffffff;
}
static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
{
// pclog("MMIO writeb %08X %02X\n", addr, val);
}
static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p)
{
// pclog("MMIO writew %08X %04X\n", addr, val);
}
static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p)
{
// pclog("MMIO writel %08X %08X\n", addr, val);
}
static uint8_t s3_virge_new_mmio_read(uint32_t addr, void *p)
{
// pclog("New MMIO readb %08X\n", addr);
switch (addr & 0xffff)
{
@ -495,23 +511,90 @@ static uint8_t s3_virge_new_mmio_read(uint32_t addr, void *p)
}
return 0xff;
}
static uint16_t s3_virge_new_mmio_read_w(uint32_t addr, void *p)
static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p)
{
// pclog("New MMIO readw %08X\n", addr);
switch (addr & 0xfffe)
{
default:
return s3_virge_new_mmio_read(addr, p) | (s3_virge_new_mmio_read(addr + 1, p) << 8);
return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8);
}
return 0xffff;
}
static uint32_t s3_virge_new_mmio_read_l(uint32_t addr, void *p)
static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p)
{
virge_t *virge = (virge_t *)p;
uint32_t ret = 0xffffffff;
// pclog("New MMIO readl %08X\n", addr);
switch (addr & 0xfffc)
{
case 0x8180:
ret = virge->streams.pri_ctrl;
break;
case 0x8184:
ret = virge->streams.chroma_ctrl;
break;
case 0x8190:
ret = virge->streams.sec_ctrl;
break;
case 0x8194:
ret = virge->streams.chroma_upper_bound;
break;
case 0x8198:
ret = virge->streams.sec_filter;
break;
case 0x81a0:
ret = virge->streams.blend_ctrl;
break;
case 0x81c0:
ret = virge->streams.pri_fb0;
break;
case 0x81c4:
ret = virge->streams.pri_fb1;
break;
case 0x81c8:
ret = virge->streams.pri_stride;
break;
case 0x81cc:
ret = virge->streams.buffer_ctrl;
break;
case 0x81d0:
ret = virge->streams.sec_fb0;
break;
case 0x81d4:
ret = virge->streams.sec_fb1;
break;
case 0x81d8:
ret = virge->streams.sec_stride;
break;
case 0x81dc:
ret = virge->streams.overlay_ctrl;
break;
case 0x81e0:
ret = virge->streams.k1_vert_scale;
break;
case 0x81e4:
ret = virge->streams.k2_vert_scale;
break;
case 0x81e8:
ret = virge->streams.dda_vert_accumulator;
break;
case 0x81ec:
ret = virge->streams.fifo_ctrl;
break;
case 0x81f0:
ret = virge->streams.pri_start;
break;
case 0x81f4:
ret = virge->streams.pri_size;
break;
case 0x81f8:
ret = virge->streams.sec_start;
break;
case 0x81fc:
ret = virge->streams.sec_size;
break;
case 0x8504:
ret = (0x1f << 8) | (1 << 13);
break;
@ -562,11 +645,11 @@ static uint32_t s3_virge_new_mmio_read_l(uint32_t addr, void *p)
break;
default:
return s3_virge_new_mmio_read_w(addr, p) | (s3_virge_new_mmio_read_w(addr + 2, p) << 16);
return s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16);
}
return ret;
}
static void s3_virge_new_mmio_write(uint32_t addr, uint8_t val, void *p)
static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
{
virge_t *virge = (virge_t *)p;
svga_t *svga = &virge->svga;
@ -595,7 +678,7 @@ static void s3_virge_new_mmio_write(uint32_t addr, uint8_t val, void *p)
}
static void s3_virge_new_mmio_write_w(uint32_t addr, uint16_t val, void *p)
static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p)
{
virge_t *virge = (virge_t *)p;
// pclog("New MMIO writew %08X %04X\n", addr, val);
@ -609,15 +692,15 @@ static void s3_virge_new_mmio_write_w(uint32_t addr, uint16_t val, void *p)
else switch (addr & 0xfffe)
{
case 0x83d4:
s3_virge_new_mmio_write(addr, val, p);
s3_virge_new_mmio_write(addr + 1, val >> 8, p);
s3_virge_mmio_write(addr, val, p);
s3_virge_mmio_write(addr + 1, val >> 8, p);
break;
}
}
static void s3_virge_new_mmio_write_l(uint32_t addr, uint32_t val, void *p)
static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p)
{
virge_t *virge = (virge_t *)p;
svga_t *svga = &virge->svga;
// if ((addr & 0xfffc) >= 0x8000)
// pclog("New MMIO writel %08X %08X\n", addr, val);
@ -630,6 +713,94 @@ static void s3_virge_new_mmio_write_l(uint32_t addr, uint32_t val, void *p)
}
else switch (addr & 0xfffc)
{
case 0x8180:
virge->streams.pri_ctrl = val;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x8184:
virge->streams.chroma_ctrl = val;
break;
case 0x8190:
virge->streams.sec_ctrl = val;
break;
case 0x8194:
virge->streams.chroma_upper_bound = val;
break;
case 0x8198:
virge->streams.sec_filter = val;
break;
case 0x81a0:
virge->streams.blend_ctrl = val;
break;
case 0x81c0:
virge->streams.pri_fb0 = val & 0x3fffff;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x81c4:
virge->streams.pri_fb1 = val & 0x3fffff;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x81c8:
virge->streams.pri_stride = val & 0xfff;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x81cc:
virge->streams.buffer_ctrl = val;
s3_virge_recalctimings(svga);
break;
case 0x81d0:
virge->streams.sec_fb0 = val;
break;
case 0x81d4:
virge->streams.sec_fb1 = val;
break;
case 0x81d8:
virge->streams.sec_stride = val;
break;
case 0x81dc:
virge->streams.overlay_ctrl = val;
break;
case 0x81e0:
virge->streams.k1_vert_scale = val;
break;
case 0x81e4:
virge->streams.k2_vert_scale = val;
break;
case 0x81e8:
virge->streams.dda_vert_accumulator = val;
break;
case 0x81ec:
virge->streams.fifo_ctrl = val;
break;
case 0x81f0:
virge->streams.pri_start = val;
virge->streams.pri_x = (val >> 16) & 0x7ff;
virge->streams.pri_y = val & 0x7ff;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x81f4:
virge->streams.pri_size = val;
virge->streams.pri_w = (val >> 16) & 0x7ff;
virge->streams.pri_h = val & 0x7ff;
s3_virge_recalctimings(svga);
svga->fullchange = changeframecount;
break;
case 0x81f8:
virge->streams.sec_start = val;
virge->streams.sec_x = (val >> 16) & 0x7ff;
virge->streams.sec_y = val & 0x7ff;
break;
case 0x81fc:
virge->streams.sec_size = val;
virge->streams.sec_w = (val >> 16) & 0x7ff;
virge->streams.sec_h = val & 0x7ff;
break;
case 0xa000: case 0xa004: case 0xa008: case 0xa00c:
case 0xa010: case 0xa014: case 0xa018: case 0xa01c:
case 0xa020: case 0xa024: case 0xa028: case 0xa02c:
@ -931,6 +1102,8 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat)
case 0:
case CMD_SET_MS:
READ(src_addr, source);
if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr)
update = 0;
break;
case CMD_SET_IDS:
if (virge->s3d.data_left_count)
@ -960,6 +1133,8 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat)
count = 0;
}
}
if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr)
update = 0;
break;
case CMD_SET_IDS | CMD_SET_MS:
source = (cpu_dat & (1 << 31)) ? virge->s3d.src_fg_clr : virge->s3d.src_bg_clr;
@ -1287,12 +1462,12 @@ static void *s3_virge_init()
NULL,
0,
virge);
mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_new_mmio_read,
s3_virge_new_mmio_read_w,
s3_virge_new_mmio_read_l,
s3_virge_new_mmio_write,
s3_virge_new_mmio_write_w,
s3_virge_new_mmio_write_l,
mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read,
s3_virge_mmio_read_w,
s3_virge_mmio_read_l,
s3_virge_mmio_write,
s3_virge_mmio_write_w,
s3_virge_mmio_write_l,
NULL,
0,
virge);