RIVA TNT Video BIOS now runs.

This commit is contained in:
starfrost013
2025-09-13 22:55:01 +01:00
parent 3f27fab2db
commit accf499790
4 changed files with 116 additions and 97 deletions

View File

@@ -505,6 +505,7 @@
#define NV4_PBUS_PCI_DEVICE_ID 0x1802
#define NV4_PBUS_PCI_DEVICE_ID_NV4 0x0020 // Chip (19:17)= NV4, Func = VGA
#define NV4_PBUS_PCI_COMMAND 0x1804
#define NV4_PBUS_PCI_COMMAND_H 0x1805
#define NV4_PBUS_PCI_COMMAND_IO_SPACE 0
#define NV4_PBUS_PCI_COMMAND_IO_SPACE_ENABLED 0x1
#define NV4_PBUS_PCI_COMMAND_MEMORY_SPACE 1
@@ -568,9 +569,12 @@
#define NV4_PBUS_PCI_BAR0_UNUSED2 0x1812
#define NV4_PBUS_PCI_BAR0_BASE_31_TO_24 0x1813 // Must align to 16MByte
#define NV4_PBUS_PCI_BAR1_INFO 0x1814
#define NV4_PBUS_PCI_BAR1_UNUSED1 0x1814
#define NV4_PBUS_PCI_BAR1_UNUSED2 0x1815
#define NV4_PBUS_PCI_BAR1_BASE_31_TO_24 0x1816 // Must align to 16MByte
#define NV4_PBUS_PCI_BAR1_UNUSED1 0x1815
#define NV4_PBUS_PCI_BAR1_UNUSED2 0x1816
#define NV4_PBUS_PCI_BAR1_BASE_31_TO_24 0x1817 // Must align to 16MByte
#define NV4_PBUS_PCI_BAR_RESERVED_START 0x1818
#define NV4_PBUS_PCI_BAR_RESERVED_END 0x182B
//BAR2-5 reserved
#define NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID 0x182C
#define NV4_PBUS_PCI_SUBSYSTEM_ID 0x182E

View File

@@ -137,7 +137,6 @@ uint32_t nv3_mmio_read32(uint32_t addr, void* priv)
return ret;
}
ret = nv3_mmio_arbitrate_read(addr);
return ret;

View File

@@ -66,6 +66,7 @@ void nv4_init_mappings_svga(void)
{
nv_log("Initialising SVGA core memory mapping\n");
// setup the svga mappings
mem_mapping_add(&nv4->nvbase.framebuffer_mapping, 0, 0,
nv4_dfb_read8,
nv4_dfb_read16,
@@ -198,14 +199,18 @@ bool nv4_init()
/* Set log device name based on card model */
const char* log_device_name = "NV4";
/* Just hardcode full logging */
if (device_get_config_int("nv_debug_fulllog"))
nv4->nvbase.log = log_open("NV4");
nv4->nvbase.log = log_open(log_device_name);
else
nv4->nvbase.log = log_open_cyclic("NV4");
nv4->nvbase.log = log_open_cyclic(log_device_name);
nv_log_set_device(nv4->nvbase.log);
nv4->nvbase.bus_generation = nv_bus_agp_2x;
nv_log_set_device(nv4->nvbase.log);
// Figure out which vbios the user selected
// This depends on the bus we are using and if the gpu is rev a/b or rev c
@@ -260,11 +265,82 @@ void nv4_draw_cursor(svga_t* svga, int32_t drawline)
}
void nv4_recalc_timings(svga_t* svga)
{
//
// SVGA functions
//
void nv4_recalc_timings(svga_t* svga)
{
// sanity check
if (!nv4)
return;
nv4_t* nv4 = (nv4_t*)svga->priv;
// TODO: Everything, this code sucks, incl. NV4_PRAMDAC_GENERAL_CONTROL_BPC and the OFFSET register
uint32_t pixel_mode = svga->crtc[NV4_CIO_CRE_PIXEL_INDEX] & 0x03;
svga->memaddr_latch += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0x1F) << 16;
/* Turn off override if we are in VGA mode */
svga->override = !(pixel_mode == NV4_CIO_CRE_PIXEL_FORMAT_VGA);
/* NOTE: The RIVA 128 draws in a way almost completely separate to any other 86Box GPU.
Basically, we only blit to buffer32 when something changes and we don't even bother using a timer. We only render when there is something to actually render.
This is because there is no linear relationship between the contents of VRAM and the contents of the display which 86box's SVGA subsystem cannot tolerate.
In fact, the position in VRAM and pitch can be changed at any time via an NV_IMAGE_IN_MEMORY object.
Therefore, we need to completely bypass it using svga->override and draw our own rendering functions. This allows us to use a neat optimisation trick
to only ever actually draw when we need to do something. This shouldn't be a problem in games, because the drivers will read the current refresh rate from
the Windows settings, and then, just submit objects at that pace for anything that changes on the screen.
*/
// Set the pixel mode
switch (pixel_mode)
{
case NV4_CIO_CRE_PIXEL_FORMAT_8BPP:
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 1; // ?????
svga->bpp = 8;
svga->lowres = 0;
svga->map8 = svga->pallook;
break;
case NV4_CIO_CRE_PIXEL_FORMAT_16BPP:
/* This is some sketchy shit that is an attempt at an educated guess
at pixel clock differences between 9x and NT only in 16bpp. If there is ever an error on 9x with "interlaced" looking graphics,
this is what's causing it. Possibly fucking up the drivers under *ReactOS* of all things */
if ((svga->crtc[NV4_CIO_CR_VRS_INDEX] >> 1) & 0x01)
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 2;
else
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3;
// 15bpp mode is removed on NV4
// TODO: Not svga
svga->bpp = 16;
svga->lowres = 0;
break;
case NV4_CIO_CRE_PIXEL_FORMAT_32BPP:
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3;
svga->bpp = 32;
svga->lowres = 0;
//svga->render = nv4_render_32bpp;
break;
}
if (((svga->miscout >> 2) & 2) == 2)
{
// set clocks
//nv4_pramdac_set_pixel_clock();
//nv4_pramdac_set_vram_clock();
}
}
void nv4_force_redraw(void* priv)
{
@@ -281,7 +357,7 @@ int32_t nv4_available(void)
// 8MB or 16MB VRAM
const device_t nv4_device_agp =
{
.name = "nVIDIA RIVA TNT [STB Velocity 4400]",
.name = "nVIDIA RIVA TNT (STB Velocity 4400)",
.internal_name = "nv4_stb4400",
.flags = DEVICE_AGP,
.local = 0,

View File

@@ -438,7 +438,7 @@ uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv)
// We only need to return 0x30 since the VGA class code is 0x30000
case NV4_PBUS_PCI_CLASS_CODE:
ret = (NV4_PBUS_PCI_CLASS_CODE_VGA) >> 12; // CLASS_CODE_VGA
ret = (NV4_PBUS_PCI_CLASS_CODE_VGA) >> 16; // CLASS_CODE_VGA
break;
@@ -462,6 +462,15 @@ uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv)
case NV4_PBUS_PCI_BAR1_BASE_31_TO_24:
ret = nv4->nvbase.bar1_lfb_base >> 24; //8bit value
break;
case NV4_PBUS_PCI_BAR_RESERVED_START ... NV4_PBUS_PCI_BAR_RESERVED_END:
case NV4_PBUS_PCI_BAR0_UNUSED1:
case NV4_PBUS_PCI_BAR0_UNUSED2:
case NV4_PBUS_PCI_BAR1_UNUSED1:
case NV4_PBUS_PCI_BAR1_UNUSED2:
ret = 0x00; // hard lock
break;
case NV4_PBUS_PCI_ROM:
ret = nv4->nvbase.pci_config.vbios_enabled;
@@ -504,6 +513,7 @@ uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv)
case NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE + 1:
ret = nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_SUBSYSTEM_ID + (addr & 0x03)];
break;
case NV4_PBUS_AGP_CAPABILITIES:
ret = NV4_PBUS_AGP_CAPABILITY_AGP; // AGP capable device
break;
@@ -529,7 +539,7 @@ uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv)
}
nv_log("nv4_pci_read func=0x%04x addr=0x%04x ret=0x%04x\n", func, addr, ret);
nv_log("nv4_pci_read func=0x%04x addr=0x%04x ret=0x%04x\n", func, addr & 0xFF, ret);
return ret;
}
@@ -550,28 +560,28 @@ void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv)
&& addr == NV4_PBUS_PCI_BAR1_UNUSED1 || addr == NV4_PBUS_PCI_BAR1_UNUSED2)
return;
nv_log("nv4_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr, val);
nv_log("nv4_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr & 0xFF, val);
nv4->nvbase.pci_config.pci_regs[addr] = val;
switch (addr)
{
// standard pci command stuff
case PCI_REG_COMMAND_L:
case NV4_PBUS_PCI_COMMAND:
nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L] = val;
// actually update the mappings
nv4_update_mappings();
break;
case PCI_REG_COMMAND_H:
case NV4_PBUS_PCI_COMMAND_H:
nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_H] = val;
// actually update the mappings
nv4_update_mappings();
break;
// pci status register
case PCI_REG_STATUS_L:
case NV4_PBUS_PCI_STATUS:
nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] = val | (NV4_PBUS_PCI_STATUS_66MHZ_CAPABLE << NV4_PBUS_PCI_STATUS_66MHZ);
break;
case PCI_REG_STATUS_H:
case NV4_PBUS_PCI_STATUS_2:
nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_H] = val | (NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_FAST << NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING);
break;
//TODO: ACTUALLY REMAP THE MMIO AND NV_USER
@@ -583,6 +593,7 @@ void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv)
nv4->nvbase.bar1_lfb_base = val << 24;
nv4_update_mappings();
break;
case NV4_PBUS_PCI_ROM:
case NV4_PBUS_PCI_ROM_BASE:
@@ -601,13 +612,16 @@ void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv)
{
uint32_t old_addr = nv4->nvbase.vbios.mapping.base;
// 9bit register
uint32_t new_addr = nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM + 1] << 24 |
nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM] << 16;
uint32_t new_addr = nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM + 3] << 24 |
nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM + 2] << 16;
// only bits 31;22 matter
//new_addr &= 0xFFC00000;
// move it
mem_mapping_set_addr(&nv4->nvbase.vbios.mapping, new_addr, 0x8000);
nv_log("...i like to move it move it (VBIOS Relocation) 0x%04x -> 0x%04x\n", old_addr, new_addr);
nv_log("...i like to move it move it (VBIOS Relocation) 0x%x -> 0x%x\n", old_addr, new_addr);
}
else
@@ -643,80 +657,6 @@ void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv)
}
//
// SVGA functions
//
void nv4_recalc_timings(svga_t* svga)
{
// sanity check
if (!nv4)
return;
nv4_t* nv4 = (nv4_t*)svga->priv;
// TODO: Everything, this code sucks, incl. NV4_PRAMDAC_GENERAL_CONTROL_BPC and the OFFSET register
uint32_t pixel_mode = svga->crtc[NV4_CIO_CRE_PIXEL_INDEX] & 0x03;
svga->memaddr_latch += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0x1F) << 16;
/* Turn off override if we are in VGA mode */
svga->override = !(pixel_mode == NV4_CIO_CRE_PIXEL_FORMAT_VGA);
/* NOTE: The RIVA 128 draws in a way almost completely separate to any other 86Box GPU.
Basically, we only blit to buffer32 when something changes and we don't even bother using a timer. We only render when there is something to actually render.
This is because there is no linear relationship between the contents of VRAM and the contents of the display which 86box's SVGA subsystem cannot tolerate.
In fact, the position in VRAM and pitch can be changed at any time via an NV_IMAGE_IN_MEMORY object.
Therefore, we need to completely bypass it using svga->override and draw our own rendering functions. This allows us to use a neat optimisation trick
to only ever actually draw when we need to do something. This shouldn't be a problem in games, because the drivers will read the current refresh rate from
the Windows settings, and then, just submit objects at that pace for anything that changes on the screen.
*/
// Set the pixel mode
switch (pixel_mode)
{
case NV4_CIO_CRE_PIXEL_FORMAT_8BPP:
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 1; // ?????
svga->bpp = 8;
svga->lowres = 0;
svga->map8 = svga->pallook;
break;
case NV4_CIO_CRE_PIXEL_FORMAT_16BPP:
/* This is some sketchy shit that is an attempt at an educated guess
at pixel clock differences between 9x and NT only in 16bpp. If there is ever an error on 9x with "interlaced" looking graphics,
this is what's causing it. Possibly fucking up the drivers under *ReactOS* of all things */
if ((svga->crtc[NV4_CIO_CR_VRS_INDEX] >> 1) & 0x01)
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 2;
else
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3;
// 15bpp mode is removed on NV4
// TODO: Not svga
svga->bpp = 16;
svga->lowres = 0;
break;
case NV4_CIO_CRE_PIXEL_FORMAT_32BPP:
svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3;
svga->bpp = 32;
svga->lowres = 0;
//svga->render = nv4_render_32bpp;
break;
}
if (((svga->miscout >> 2) & 2) == 2)
{
// set clocks
//nv4_pramdac_set_pixel_clock();
//nv4_pramdac_set_vram_clock();
}
}
void nv4_speed_changed(void* priv)
{
// sanity check
@@ -888,9 +828,6 @@ uint8_t nv4_svga_read(uint16_t addr, void* priv)
{
// CR = CRTC Controller
// CRE = CRTC Controller Extended (weitek)
nv4_t* nv4 = (nv4_t*)priv;
uint8_t ret = 0x00;
// sanity check
@@ -947,6 +884,8 @@ uint8_t nv4_svga_read(uint16_t addr, void* priv)
break;
}
nv_log("SVGA read 0x%04x value 0x%02x\n", addr, ret);
return ret; //TEMP
}
@@ -1090,6 +1029,7 @@ void nv4_svga_write(uint16_t addr, uint8_t val, void* priv)
break;
}
nv_log("SVGA write 0x%04x value 0x%02x\n", addr, val);
}
/* DFB, sets up a dumb framebuffer */