Voodoo: Implement missing AGP CMDFIFO features

Note that the reproduction cases for command 6 currently appear to be a result of CMDFIFO corruption instead of actual usage.
This commit is contained in:
RichardG867
2025-02-20 18:24:38 -03:00
parent baae4c15d6
commit 6c933dd157
4 changed files with 148 additions and 9 deletions

View File

@@ -18,6 +18,7 @@
#ifndef VIDEO_VOODOO_BANSHEE_H
#define VIDEO_VOODOO_BANSHEE_H
void banshee_cmd_write(void *priv, uint32_t addr, uint32_t val);
void banshee_set_overlay_addr(void *priv, uint32_t addr);
#endif /*VIDEO_VOODOO_BANSHEE_H*/

View File

@@ -420,6 +420,7 @@ typedef struct voodoo_t {
int cmdfifo_rp;
int cmdfifo_ret_addr;
int cmdfifo_in_sub;
int cmdfifo_in_agp;
atomic_int cmdfifo_depth_rd;
atomic_int cmdfifo_depth_wr;
atomic_int cmdfifo_enabled;
@@ -433,6 +434,7 @@ typedef struct voodoo_t {
int cmdfifo_rp_2;
int cmdfifo_ret_addr_2;
int cmdfifo_in_sub_2;
int cmdfifo_in_agp_2;
atomic_int cmdfifo_depth_rd_2;
atomic_int cmdfifo_depth_wr_2;
atomic_int cmdfifo_enabled_2;

View File

@@ -30,6 +30,7 @@
#include <86box/device.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/dma.h>
#include <86box/pci.h>
#include <86box/rom.h>
#include <86box/timer.h>
@@ -43,9 +44,11 @@
#include <86box/vid_svga_render.h>
#include <86box/vid_voodoo_common.h>
#include <86box/vid_voodoo_display.h>
#include <86box/vid_voodoo_fb.h>
#include <86box/vid_voodoo_fifo.h>
#include <86box/vid_voodoo_regs.h>
#include <86box/vid_voodoo_render.h>
#include <86box/vid_voodoo_texture.h>
#define ROM_BANSHEE "roms/video/voodoo/Pci_sg.rom"
#define ROM_CREATIVE_BANSHEE "roms/video/voodoo/BlasterPCI.rom"
@@ -220,6 +223,7 @@ enum {
Agp_agpHostAddressHigh = 0x08,
Agp_agpGraphicsAddress = 0x0C,
Agp_agpGraphicsStride = 0x10,
Agp_agpMoveCMD = 0x14,
};
#define VGAINIT0_RAMDAC_8BIT (1 << 2)
@@ -1365,6 +1369,10 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr)
case cmdBaseSize0:
ret = voodoo->cmdfifo_size;
if (voodoo->cmdfifo_enabled)
ret |= 0x100;
if (voodoo->cmdfifo_in_agp)
ret |= 0x200;
break;
case cmdBaseAddr1:
@@ -1394,6 +1402,10 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr)
case cmdBaseSize1:
ret = voodoo->cmdfifo_size_2;
if (voodoo->cmdfifo_enabled_2)
ret |= 0x100;
if (voodoo->cmdfifo_in_agp_2)
ret |= 0x200;
break;
case 0x108:
@@ -1613,10 +1625,11 @@ banshee_reg_writew(uint32_t addr, uint16_t val, void *priv)
}
}
static void
banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
void
banshee_cmd_write(void *priv, uint32_t addr, uint32_t val)
{
voodoo_t *voodoo = banshee->voodoo;
banshee_t *banshee = (banshee_t *) priv;
voodoo_t *voodoo = banshee->voodoo;
#if 0
banshee_log("banshee_cmd_write: addr=%03x val=%08x\n", addr & 0x1fc, val);
#endif
@@ -1641,6 +1654,62 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
banshee->agpReqSize = val;
break;
case Agp_agpMoveCMD: {
uint32_t src_addr = banshee->agpHostAddressLow;
uint32_t src_width = banshee->agpHostAddressHigh & 0x3fff;
uint32_t src_stride = (banshee->agpHostAddressHigh >> 14) & 0x3fff;
uint32_t src_end = src_addr + (banshee->agpReqSize & 0xfffff); /* don't know whether or not stride is accounted for! */
uint32_t dest_addr = banshee->agpGraphicsAddress & 0x3ffffff;
uint32_t dest_stride = banshee->agpGraphicsStride & 0x7fff;
#if 0
banshee_log("AGP: %d bytes W%d from %08x S%d to %d:%08x S%d\n", src_end - src_addr, src_width, src_addr, src_stride, (val >> 3) & 3, dest_addr, dest_stride);
#endif
switch ((val >> 3) & 3) {
case 0: /*Linear framebuffer (Banshee)*/
case 1: /*Planar YUV*/
if (voodoo->texture_present[0][(dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) {
#if 0
banshee_log("texture_present at %08x %i\n", dest_addr, (dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
#endif
flush_texture_cache(voodoo, dest_addr & voodoo->texture_mask, 0);
}
if (voodoo->texture_present[1][(dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) {
#if 0
banshee_log("texture_present at %08x %i\n", dest_addr, (dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
#endif
flush_texture_cache(voodoo, dest_addr & voodoo->texture_mask, 1);
}
while ((src_addr < src_end) && (dest_addr <= voodoo->fb_mask)) {
dma_bm_read(src_addr, &voodoo->fb_mem[dest_addr], MIN(src_width, voodoo->fb_mask - dest_addr), 4);
src_addr += src_stride;
dest_addr += dest_stride;
}
break;
case 2: /*Framebuffer*/
src_width &= ~3;
while (src_addr < src_end) {
for (uint32_t i = 0; i < src_width; i += 4)
voodoo_fb_writel(dest_addr + i, mem_readl_phys(src_addr + i), voodoo);
src_addr += src_stride;
dest_addr += dest_stride;
}
break;
case 3: /*Texture*/
src_width &= ~3;
while (src_addr < src_end) {
for (uint32_t i = 0; i < src_width; i += 4)
voodoo_tex_writel(dest_addr + i, mem_readl_phys(src_addr + i), voodoo);
src_addr += src_stride;
dest_addr += dest_stride;
}
break;
default:
break;
}
break;
}
case cmdBaseAddr0:
voodoo->cmdfifo_base = (val & 0xfff) << 12;
voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12);
@@ -1655,6 +1724,7 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
voodoo->cmdfifo_enabled = val & 0x100;
if (!voodoo->cmdfifo_enabled)
voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/
voodoo->cmdfifo_in_agp = val & 0x200;
#if 0
banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
#endif
@@ -1694,6 +1764,7 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
voodoo->cmdfifo_enabled_2 = val & 0x100;
if (!voodoo->cmdfifo_enabled_2)
voodoo->cmdfifo_in_sub_2 = 0; /*Not sure exactly when this should be reset*/
voodoo->cmdfifo_in_agp_2 = val & 0x200;
#if 0
banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
#endif

View File

@@ -35,6 +35,7 @@
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/vid_voodoo_common.h>
#include <86box/vid_voodoo_banshee.h>
#include <86box/vid_voodoo_banshee_blitter.h>
#include <86box/vid_voodoo_fb.h>
#include <86box/vid_voodoo_fifo.h>
@@ -166,7 +167,10 @@ cmdfifo_get(voodoo_t *voodoo)
}
}
val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask];
if (voodoo->cmdfifo_in_agp)
val = mem_readl_phys(voodoo->cmdfifo_rp);
else
val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask];
if (!voodoo->cmdfifo_in_sub)
voodoo->cmdfifo_depth_rd++;
@@ -200,7 +204,10 @@ cmdfifo_get_2(voodoo_t *voodoo)
}
}
val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask];
if (voodoo->cmdfifo_in_agp_2)
val = mem_readl_phys(voodoo->cmdfifo_rp_2);
else
val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask];
if (!voodoo->cmdfifo_in_sub_2)
voodoo->cmdfifo_depth_rd_2++;
@@ -362,9 +369,21 @@ voodoo_fifo_thread(void *param)
break;
case 3: /*JMP local frame buffer*/
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_in_agp = 0;
#if 0
voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header);
voodoo_fifo_log("JMP LFB to %08x %04x\n", voodoo->cmdfifo_rp, header);
#endif
break;
case 4: /*JMP AGP*/
if (UNLIKELY(voodoo->type < VOODOO_BANSHEE))
fatal("CMDFIFO0: Not Banshee %08x\n", header);
voodoo->cmdfifo_rp = ((header >> 4) & 0x1fffffc) | (cmdfifo_get(voodoo) << 25);
voodoo->cmdfifo_in_agp = 1;
#if 0
voodoo_fifo_log("JMP AGP to %08x %04x\n", voodoo->cmdfifo_rp, header);
#endif
break;
@@ -573,6 +592,23 @@ voodoo_fifo_thread(void *param)
}
break;
case 6:
if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) {
fatal("CMDFIFO6: Not Banshee %08x %08x\n", header, voodoo->cmdfifo_rp);
} else {
uint32_t val = cmdfifo_get(voodoo);
banshee_cmd_write(voodoo->priv, 0x00, val >> 5); /* agpReqSize */
banshee_cmd_write(voodoo->priv, 0x04, cmdfifo_get(voodoo)); /* agpHostAddressLow */
banshee_cmd_write(voodoo->priv, 0x08, cmdfifo_get(voodoo)); /* agpHostAddressHigh */
banshee_cmd_write(voodoo->priv, 0x0c, cmdfifo_get(voodoo)); /* agpGraphicsAddress */
banshee_cmd_write(voodoo->priv, 0x10, cmdfifo_get(voodoo)); /* agpGraphicsStride */
banshee_cmd_write(voodoo->priv, 0x14, (val & 0x18) | 0x00); /* agpMoveCMD - start transfer */
#if 0
voodoo_fifo_log("CMDFIFO6 addr=%08x num=%i\n", addr, banshee->agpReqSize);
#endif
}
break;
default:
fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp);
}
@@ -624,9 +660,21 @@ voodoo_fifo_thread(void *param)
break;
case 3: /*JMP local frame buffer*/
voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_in_agp_2 = 0;
#if 0
voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header);
voodoo_fifo_log("JMP LFB to %08x %04x\n", voodoo->cmdfifo_rp_2, header);
#endif
break;
case 4: /*JMP AGP*/
if (UNLIKELY(voodoo->type < VOODOO_BANSHEE))
fatal("CMDFIFO0: Not Banshee %08x\n", header);
voodoo->cmdfifo_rp_2 = ((header >> 4) & 0x1fffffc) | (cmdfifo_get_2(voodoo) << 25);
voodoo->cmdfifo_in_agp_2 = 1;
#if 0
voodoo_fifo_log("JMP AGP to %08x %04x\n", voodoo->cmdfifo_rp_2, header);
#endif
break;
@@ -835,6 +883,23 @@ voodoo_fifo_thread(void *param)
}
break;
case 6:
if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) {
fatal("CMDFIFO6: Not Banshee %08x %08x\n", header, voodoo->cmdfifo_rp);
} else {
uint32_t val = cmdfifo_get_2(voodoo);
banshee_cmd_write(voodoo->priv, 0x00, val >> 5); /* agpReqSize */
banshee_cmd_write(voodoo->priv, 0x04, cmdfifo_get_2(voodoo)); /* agpHostAddressLow */
banshee_cmd_write(voodoo->priv, 0x08, cmdfifo_get_2(voodoo)); /* agpHostAddressHigh */
banshee_cmd_write(voodoo->priv, 0x0c, cmdfifo_get_2(voodoo)); /* agpGraphicsAddress */
banshee_cmd_write(voodoo->priv, 0x10, cmdfifo_get_2(voodoo)); /* agpGraphicsStride */
banshee_cmd_write(voodoo->priv, 0x14, (val & 0x18) | 0x20); /* agpMoveCMD - start transfer */
#if 0
voodoo_fifo_log("CMDFIFO6 addr=%08x num=%i\n", addr, banshee->agpReqSize);
#endif
}
break;
default:
fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp);
}