From accf4997905b3763f7b7d3a353911022894470a5 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sat, 13 Sep 2025 22:55:01 +0100 Subject: [PATCH] RIVA TNT Video BIOS now runs. --- src/include/86box/nv/vid_nv4_defines.h | 10 ++- src/video/nv/nv3/nv3_core.c | 1 - src/video/nv/nv4/nv4_core.c | 88 +++++++++++++++++-- src/video/nv/nv4/nv4_core_io.c | 114 ++++++------------------- 4 files changed, 116 insertions(+), 97 deletions(-) diff --git a/src/include/86box/nv/vid_nv4_defines.h b/src/include/86box/nv/vid_nv4_defines.h index 21cf5739a..3bda4dc1c 100644 --- a/src/include/86box/nv/vid_nv4_defines.h +++ b/src/include/86box/nv/vid_nv4_defines.h @@ -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 diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index ec5fe5f92..01af9100d 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -137,7 +137,6 @@ uint32_t nv3_mmio_read32(uint32_t addr, void* priv) return ret; } - ret = nv3_mmio_arbitrate_read(addr); return ret; diff --git a/src/video/nv/nv4/nv4_core.c b/src/video/nv/nv4/nv4_core.c index c210b0424..285988800 100644 --- a/src/video/nv/nv4/nv4_core.c +++ b/src/video/nv/nv4/nv4_core.c @@ -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, diff --git a/src/video/nv/nv4/nv4_core_io.c b/src/video/nv/nv4/nv4_core_io.c index 87614b8c2..2849efac1 100644 --- a/src/video/nv/nv4/nv4_core_io.c +++ b/src/video/nv/nv4/nv4_core_io.c @@ -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 */