Virge FIFO waiting fixes - slots limit, and undocumented behavior to make Linux work.

This commit is contained in:
OBattler
2023-08-06 03:37:35 +02:00
parent 32c17a76de
commit a8578203cc

View File

@@ -279,6 +279,7 @@ typedef struct virge_t {
uint32_t dma_ptr;
uint64_t blitter_time;
volatile int fifo_slot;
int fifo_slots_num;
pc_timer_t tri_timer;
@@ -1031,6 +1032,8 @@ s3_virge_mmio_fifo_write_l(uint32_t addr, uint32_t val, virge_t *virge)
else
s3_virge_bitblt(virge, 32, val);
} else {
if (virge->fifo_slot >= virge->fifo_slots_num)
return;
virge->fifo_slot++;
switch (addr & 0xfffc) {
case 0x8590:
@@ -1480,16 +1483,25 @@ s3_virge_mmio_read(uint32_t addr, void *priv)
switch (addr & 0xffff) {
case 0x8505:
ret = 0;
if (virge->s3d_busy || virge->fifo_slot) {
ret = 0x10;
} else {
ret = 0x30;
}
ret = 0xc0;
if (!virge->s3d_busy && !virge->fifo_slot)
ret |= 0x20;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= (virge->fifo_slots_num - virge->fifo_slot);
return ret;
case 0x850c:
ret = virge->advfunc_cntl & 0x3f;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= (virge->fifo_slots_num - virge->fifo_slot) << 6;
ret &= 0xff;
break;
case 0x850d:
ret = (virge->fifo_slots_num - virge->fifo_slot) >> 2;
break;
case 0x83b0:
case 0x83b1:
case 0x83b2:
@@ -1564,15 +1576,25 @@ s3_virge_mmio_read_w(uint32_t addr, void *priv)
switch (addr & 0xfffe) {
case 0x8504:
ret = 0xc000;
if (!virge->s3d_busy && !virge->fifo_slot)
ret |= 0x2000;
if (!virge->fifo_slot)
virge->subsys_stat |= INT_FIFO_EMP;
ret |= virge->subsys_stat;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= 0x30; /*A bit of a workaround at the moment.*/
ret |= (virge->fifo_slots_num - virge->fifo_slot) << 8;
s3_virge_update_irqs(virge);
return ret;
case 0x850c:
ret = virge->advfunc_cntl & 0x3f;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= (virge->fifo_slots_num - virge->fifo_slot) << 6;
break;
case 0x859c:
return virge->cmd_dma;
@@ -1660,10 +1682,9 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv)
break;
case 0x8504:
if (virge->s3d_busy || virge->fifo_slot) {
ret = (0x10 << 8);
} else {
ret = (0x10 << 8) | (1 << 13);
ret = 0x0000c000;
if (!virge->s3d_busy && !virge->fifo_slot) {
ret |= 0x00002000;
if (!virge->s3d_busy)
virge->subsys_stat |= INT_3DF_EMP;
if (!virge->fifo_slot)
@@ -1672,9 +1693,17 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv)
ret |= virge->subsys_stat;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= (virge->fifo_slots_num - virge->fifo_slot) << 8;
s3_virge_update_irqs(virge);
break;
case 0x850c:
ret = virge->advfunc_cntl & 0x3f;
if (virge->fifo_slot)
virge->fifo_slot--;
ret |= (virge->fifo_slots_num - virge->fifo_slot) << 6;
break;
case 0x8590:
ret = virge->cmd_dma_base;
break;
@@ -3498,26 +3527,41 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine)
svga->hwcursor_latch.addr += 16;
switch (svga->bpp) {
default:
if (virge->chip != S3_VIRGEGX2) {
fg = svga->pallook[virge->hwc_fg_col & 0xff];
bg = svga->pallook[virge->hwc_bg_col & 0xff];
break;
}
#ifdef FALLTHROUGH_ANNOTATION
[[fallthrough]];
#endif
case 15:
fg = video_15to32[virge->hwc_fg_col & 0xffff];
bg = video_15to32[virge->hwc_bg_col & 0xffff];
break;
if (virge->chip != S3_VIRGEGX2) {
fg = video_15to32[virge->hwc_fg_col & 0xffff];
bg = video_15to32[virge->hwc_bg_col & 0xffff];
break;
}
#ifdef FALLTHROUGH_ANNOTATION
[[fallthrough]];
#endif
case 16:
fg = video_16to32[virge->hwc_fg_col & 0xffff];
bg = video_16to32[virge->hwc_bg_col & 0xffff];
break;
if (virge->chip != S3_VIRGEGX2) {
fg = video_16to32[virge->hwc_fg_col & 0xffff];
bg = video_16to32[virge->hwc_bg_col & 0xffff];
break;
}
#ifdef FALLTHROUGH_ANNOTATION
[[fallthrough]];
#endif
case 24:
case 32:
fg = virge->hwc_fg_col;
bg = virge->hwc_bg_col;
break;
default:
fg = svga->pallook[virge->hwc_fg_col & 0xff];
bg = svga->pallook[virge->hwc_bg_col & 0xff];
break;
}
for (uint8_t x = 0; x < 64; x += 16) {
@@ -3527,6 +3571,9 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine)
/*X11*/
for (xx = 0; xx < 16; xx++) {
if (offset >= 0) {
if (virge->chip == S3_VIRGEGX2)
dat[0] ^= 0x8000;
if (dat[0] & 0x8000)
buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg;
}
@@ -4086,24 +4133,29 @@ s3_virge_reset(void *priv)
switch (virge->local) {
case S3_VIRGE_325:
case S3_DIAMOND_STEALTH3D_2000:
virge->fifo_slots_num = 8;
virge->svga.crtc[0x59] = 0x70;
break;
case S3_DIAMOND_STEALTH3D_3000:
case S3_STB_VELOCITY_3D:
virge->fifo_slots_num = 8;
virge->svga.crtc[0x59] = 0x70;
break;
case S3_VIRGE_GX2:
case S3_DIAMOND_STEALTH3D_4000:
virge->fifo_slots_num = 16;
virge->svga.crtc[0x6c] = 1;
virge->svga.crtc[0x59] = 0x70;
break;
case S3_TRIO_3D2X:
virge->fifo_slots_num = 16;
virge->svga.crtc[0x6c] = 1;
virge->svga.crtc[0x59] = 0x70;
break;
default:
virge->fifo_slots_num = 8;
virge->svga.crtc[0x6c] = 1;
virge->svga.crtc[0x59] = 0x70;
break;
@@ -4262,6 +4314,7 @@ s3_virge_init(const device_t *info)
switch (info->local) {
case S3_VIRGE_325:
case S3_DIAMOND_STEALTH3D_2000:
virge->fifo_slots_num = 8;
virge->svga.decode_mask = (4 << 20) - 1;
virge->virge_id_high = 0x56;
virge->virge_id_low = 0x31;
@@ -4271,6 +4324,7 @@ s3_virge_init(const device_t *info)
break;
case S3_DIAMOND_STEALTH3D_3000:
case S3_STB_VELOCITY_3D:
virge->fifo_slots_num = 8;
virge->svga.decode_mask = (8 << 20) - 1;
virge->virge_id_high = 0x88;
virge->virge_id_low = 0x3d;
@@ -4280,6 +4334,7 @@ s3_virge_init(const device_t *info)
break;
case S3_VIRGE_GX2:
case S3_DIAMOND_STEALTH3D_4000:
virge->fifo_slots_num = 16;
virge->svga.decode_mask = (4 << 20) - 1;
virge->virge_id_high = 0x8a;
virge->virge_id_low = 0x10;
@@ -4291,6 +4346,7 @@ s3_virge_init(const device_t *info)
break;
case S3_TRIO_3D2X:
virge->fifo_slots_num = 16;
virge->svga.decode_mask = (8 << 20) - 1;
virge->virge_id_high = 0x8a;
virge->virge_id_low = 0x13;
@@ -4309,6 +4365,7 @@ s3_virge_init(const device_t *info)
#endif
default:
virge->fifo_slots_num = 8;
virge->svga.decode_mask = (4 << 20) - 1;
virge->virge_id_high = 0x8a;
virge->virge_id_low = 0x01;