From 1e8c804cfdda0c87ff101198cb77fc98fe69daf3 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Fri, 31 Jan 2025 01:21:28 +0000 Subject: [PATCH] Implement RAMIN lookup and start the pullers. I hate nvidia --- src/include/86box/nv/vid_nv3.h | 116 +++++++------ src/log.c | 17 +- src/video/nv/nv3/subsystems/nv3_pbus_dma.c | 2 +- src/video/nv/nv3/subsystems/nv3_pfifo.c | 14 ++ src/video/nv/nv3/subsystems/nv3_pramin.c | 163 +++++++++++++++++- .../nv/nv3/subsystems/nv3_pramin_ramht.c | 12 +- 6 files changed, 254 insertions(+), 70 deletions(-) diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index aa719a7d2..651693257 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -14,8 +14,8 @@ * Also check the doc folder for some more notres * * vid_nv3.h: NV3 Architecture Hardware Reference (open-source) - * Last updated: 28 January 2025 (STILL WORKING ON IT!!!) - * + * Last updated: 30 January 2025 (STILL WORKING ON IT!!!) + * * Authors: Connor Hyde * * Copyright 2024-2025 Connor Hyde @@ -43,9 +43,16 @@ extern const device_config_t nv3_config[]; #define NV3_86BOX_TIMER_SYSTEM_FIX_QUOTIENT 10 // The amount by which we have to ration out the memory clock because it's not fast enough... // Multiply by this value to get the real clock speed. +#define NV3_LAST_VALID_GRAPHICS_OBJECT_ID 0x1F + +// The class ids are represented with 5 bits in PGRAPH, but 7 bits in PFIFO! +// What... +#define NV3_PFIFO_FIRST_VALID_GRAPHICS_OBJECT_ID 0x40 +#define NV3_PFIFO_LAST_VALID_GRAPHICS_OBJECT_ID 0x5F + // Default value for the boot information register. // Depends on the chip -#define NV3_BOOT_REG_REV_A00 0x00030100 +#define NV3_BOOT_REG_REV_A00 0x00030100 // todo: format is wrong(?) for nv3a, fix it later #define NV3_BOOT_REG_REV_B00 0x00030110 #define NV3_BOOT_REG_REV_C00 0x00030120 @@ -72,7 +79,7 @@ extern const device_config_t nv3_config[]; #define VRAM_SIZE_2MB 0x200000 // 2MB #define VRAM_SIZE_4MB 0x400000 // 4MB #define VRAM_SIZE_8MB 0x800000 // NV3T only - +// There is also 1mb supported by the card but it was never used // PCI config #define NV3_PCI_CFG_VENDOR_ID 0x0 @@ -194,6 +201,7 @@ extern const device_config_t nv3_config[]; #define NV3_CIO_END 0x3df #define NV3_PBUS_START 0x1000 // Bus Control Subsystem #define NV3_PBUS_INTR 0x1100 // Bus Control - Interrupt Status + #define NV3_PBUS_INTR_EN 0x1140 // Bus Control - Interrupt Enable #define NV3_PBUS_PCI_START 0x1800 // PCI mirror start #define NV3_PBUS_PCI_END 0x18FF // PCI mirror end @@ -202,18 +210,25 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_DEBUG_0 0x2080 // PFIFO Debug Register #define NV3_PFIFO_CACHE0_ERROR_PENDING 0 -#define NV3_PFIFO_CACHE1_ERROR_PENDING 1 +#define NV3_PFIFO_CACHE1_ERROR_PENDING 4 #define NV3_PFIFO_INTR 0x2100 // FIFO - Interrupt Status #define NV3_PFIFO_INTR_EN 0x2140 // FIFO - Interrupt Enable +// PFIFO interrupts +#define NV3_PFIFO_INTR_CACHE_ERROR 0 +#define NV3_PFIFO_INTR_RUNOUT 4 +#define NV3_PFIFO_INTR_RUNOUT_OVERFLOW 8 +#define NV3_PFIFO_INTR_DMA_PUSHER 12 +#define NV3_PFIFO_INTR_DMA_PTE 16 + #define NV3_PFIFO_CONFIG_0 0x2200 #define NV3_PFIFO_CONFIG_0_DMA_FETCH 8 #define NV3_PFIFO_CONFIG_RAMHT 0x2210 // Hashtable for graphics objects config -#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS 12 +#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS 12 // 15:12 #define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS_DEFAULT 0x0 -#define NV3_PFIFO_CONFIG_RAMHT_SIZE 16 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE 16 // 17:16 #define NV3_PFIFO_CONFIG_RAMHT_SIZE_4K 0x0 #define NV3_PFIFO_CONFIG_RAMHT_SIZE_8K 0x1 #define NV3_PFIFO_CONFIG_RAMHT_SIZE_16K 0x2 @@ -231,8 +246,8 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_RUNOUT_STATUS 0x2400 #define NV3_PFIFO_RUNOUT_STATUS_RANOUT 0 // 1 if we fucked up -#define NV3_PFIFO_RUNOUT_STATUS_EMPTY 4 // 1 if ramro is empty -#define NV3_PFIFO_RUNOUT_STATUS_FULL 8 +#define NV3_PFIFO_RUNOUT_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_RUNOUT_STATUS_FULL 8 #define NV3_PFIFO_RUNOUT_PUT 0x2410 #define NV3_PFIFO_RUNOUT_PUT_ADDRESS 3 // 9:3 if small ramfc(?) otherwise 12:3 #define NV3_PFIFO_RUNOUT_GET 0x2420 @@ -243,17 +258,18 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_CACHE1_SIZE_REV_C 64 #define NV3_PFIFO_CACHE1_SIZE_MAX NV3_PFIFO_CACHE1_SIZE_REV_C #define NV3_PFIFO_CACHE_REASSIGNMENT 0x2500 + #define NV3_PFIFO_CACHE0_PUSH_ACCESS 0x3000 #define NV3_PFIFO_CACHE0_PUSH_CHANNEL_ID 0x3004 #define NV3_PFIFO_CACHE0_PUT 0x3010 #define NV3_PFIFO_CACHE0_STATUS 0x3014 -#define NV3_PFIFO_CACHE0_STATUS_EMPTY 4 // 1 if ramro is empty -#define NV3_PFIFO_CACHE0_STATUS_FULL 8 +#define NV3_PFIFO_CACHE0_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_CACHE0_STATUS_FULL 8 #define NV3_PFIFO_CACHE0_PUT_ADDRESS 2 // 1 bit #define NV3_PFIFO_CACHE0_PULLER_CONTROL 0x3040 #define NV3_PFIFO_CACHE0_PULLER_CONTROL_ENABLED 0 -#define NV3_PFIFO_CACHE0_PULLER_CONTROL_HASH_SUCCESS 4 -#define NV3_PFIFO_CACHE0_PULLER_CONTROL_DEVICE 8 +#define NV3_PFIFO_CACHE0_PULLER_CONTROL_HASH_FAILURE 4 +#define NV3_PFIFO_CACHE0_PULLER_CONTROL_SOFTWARE_METHOD 8 #define NV3_PFIFO_CACHE0_PULLER_CTX_IS_DIRTY 0x3050 #define NV3_PFIFO_CACHE0_PULLER_CTX_IS_DIRTY_BOOL 4 // 1=dirty 0=clean #define NV3_PFIFO_CACHE0_GET 0x3070 @@ -267,8 +283,8 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_CACHE1_PUT_ADDRESS 2 // 6:2 #define NV3_PFIFO_CACHE1_STATUS 0x3214 #define NV3_PFIFO_CACHE1_STATUS_RANOUT 0 // 1 if we fucked up -#define NV3_PFIFO_CACHE1_STATUS_EMPTY 4 // 1 if ramro is empty -#define NV3_PFIFO_CACHE1_STATUS_FULL 8 +#define NV3_PFIFO_CACHE1_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_CACHE1_STATUS_FULL 8 #define NV3_PFIFO_CACHE1_DMA_STATUS 0x3218 #define NV3_PFIFO_CACHE1_DMA_CONFIG_0 0x3220 #define NV3_PFIFO_CACHE1_DMA_CONFIG_1 0x3224 @@ -279,9 +295,10 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_CACHE1_DMA_TLB_PTE 0x3234 // Base of pagetableor DMA #define NV3_PFIFO_CACHE1_DMA_TLB_PT_BASE 0x3238 // Base of pagetable for DMA #define NV3_PFIFO_CACHE1_PULLER_CONTROL 0x3240 +//todo: merge stuff #define NV3_PFIFO_CACHE1_PULLER_CONTROL_ENABLED 0 -#define NV3_PFIFO_CACHE1_PULLER_CONTROL_HASH_SUCCESS 4 -#define NV3_PFIFO_CACHE1_PULLER_CONTROL_DEVICE 8 +#define NV3_PFIFO_CACHE1_PULLER_CONTROL_HASH_FAILURE 4 +#define NV3_PFIFO_CACHE1_PULLER_CONTROL_SOFTWARE_METHOD 8 // 0=software, 1=hardware #define NV3_PFIFO_CACHE1_PULLER_STATE1 0x3250 #define NV3_PFIFO_CACHE1_PULLER_CTX_IS_DIRTY 4 #define NV3_PFIFO_CACHE1_GET 0x3270 @@ -289,6 +306,7 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_CACHE1_METHOD 0x3300 #define NV3_PFIFO_CACHE1_METHOD_ADDRESS 2 // 12:2 #define NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL 13 // 15:13 + #define NV3_PFIFO_END 0x3FFF #define NV3_PRM_START 0x4000 // Real-Mode Device Support Subsystem #define NV3_PRM_INTR 0x4100 @@ -684,9 +702,8 @@ extern const device_config_t nv3_config[]; #define NV3_CRTC_BANKED_32K_B0000 0x08 #define NV3_CRTC_BANKED_32K_B8000 0x0C - - #define NV3_CRTC_REGISTER_NVIDIA_END 0x3F + // for 86box 8bit addressing // get rid of this asap, replace with 32->8 macros #define NV3_RMA_SIGNATURE_MSB 0x65 @@ -696,13 +713,11 @@ extern const device_config_t nv3_config[]; #define NV3_CRTC_REGISTER_RMA_MODE_MAX 0x0F - /* STRUCTURES FOR THE GPU START HERE OBJECT CLASS & RENDERING RELATED STUFF IS IN VID_NV3_CLASSES.H */ - //todo: pixel format // Master Control @@ -712,12 +727,15 @@ typedef struct nv3_pmc_s Holds chip manufacturing information at bootup. Current specification (may change later): pre-packed for convenience - FIB Revision 1, Mask Revision B0, Implementation 1 [NV3], Architecture 3 [NV3], Manufacturer Nvidia, Foundry SGS (seems to have been the most common?) - 31:28=0000, 27:24=0000, 23:16=0003, 15:8=0001, 7:4=0001, 3:0=0001 - little endian 00000000 00000011 00000001 00010001 = 0x00300111 + Revision A: + FIB Revision 1, Mask Revision B0, Implementation 1 [NV3], Architecture 3 [NV3], Manufacturer Nvidia, Foundry SGS (seems to have been the most common?) + 31:28=0000, 27:24=0000, 23:16=0003, 15:8=0001, 7:4=0001, 3:0=0001 + little endian 00000000 00000011 00000001 00010001 = 0x00300111# + Revision B/c: + write this later */ int32_t boot; - int32_t interrupt_status; // Determines if interrupts are pending for specific subsystems. + int32_t interrupt_status; // Determines if interrupts are pending for specific subsystems. int32_t interrupt_enable; // Determines if interrupts are actually enabled. int32_t enable; // Determines which subsystems are enabled. @@ -776,9 +794,9 @@ typedef struct nv3_pfifo_cache_s uint8_t get_address; // Trigger a DMA from the value you put here into where you were going. uint8_t channel_id; // The DMA channel ID of this cache. uint32_t status; - uint32_t status_puller; + uint32_t puller_control; uint32_t control; - uint32_t context[8]; + uint32_t context[NV3_DMA_SUBCHANNELS_PER_CHANNEL]; /* cache1 only do we even need to emulate this? @@ -1050,23 +1068,9 @@ typedef struct nv3_ptimer_s uint32_t alarm; // The value of time when there should be an alarm } nv3_ptimer_t; -typedef struct nv3_ramin_name_s -{ - union - { - uint32_t name; - - struct - { - uint8_t byte_high; - uint8_t byte_mid2; - uint8_t byte_mid1; - uint8_t byte_low; - }; - }; - -} nv3_ramin_name_t; - +// Object name is just a uint32_t identifier it doesn't need a struct +// This is howt he cotnext is represented in ramin +// IN PGRAPH IT IS DIFFERENT! ONLY 5 BITS FOR THE CLASS ID! WHY? typedef struct nv3_ramin_context_s { union @@ -1075,11 +1079,11 @@ typedef struct nv3_ramin_context_s struct { - - uint8_t dma_channel; - uint8_t render_object; //0=sw, 1=hw accelerated render - uint8_t class_id; - uint8_t ramin_offset; //find + bool reserved : 1; + uint8_t channel_id : 7; + bool is_rendering : 1; + uint8_t class_id : 7; + uint16_t ramin_offset; }; }; @@ -1088,7 +1092,7 @@ typedef struct nv3_ramin_context_s // Graphics object hashtable for specific DMA [channel, subchannel] pair typedef struct nv3_ramin_ramht_subchannel_s { - nv3_ramin_name_t name; // must be >4096 + uint32_t name; // must be >4096 // Contextual information. // See the above union. @@ -1193,10 +1197,13 @@ typedef struct nv3_s } nv3_t; -// device objects +// device object extern nv3_t* nv3; -// NV3 stuff +/* + *FUNCTIONS* for the GPU core start here + Functions for PGRAPH objects are in vid_nv3_classes.h +*/ // Device Core void* nv3_init(const device_t *info); @@ -1229,8 +1236,8 @@ bool nv3_ramin_arbitrate_read(uint32_t address, uint32_t* value); / bool nv3_ramin_arbitrate_write(uint32_t address, uint32_t value); // Write arbitration so we can read/write to the structures in the first 64k of ramin // RAMIN functions -uint32_t nv3_ramht_hash(nv3_ramin_name_t name, uint32_t channel); -void nv3_ramin_find_object(uint32_t name, uint32_t cache_id, uint32_t channel_id, uint32_t subchannel_id); +uint32_t nv3_ramht_hash(uint32_t name, uint32_t channel); +bool nv3_ramin_find_object(uint32_t name, uint32_t cache_num, uint32_t channel_id, uint32_t subchannel_id); uint32_t nv3_ramfc_read(uint32_t address); void nv3_ramfc_write(uint32_t address, uint32_t value); @@ -1310,6 +1317,7 @@ void nv3_pgraph_vblank_start(svga_t* svga); void nv3_pfifo_init(); uint32_t nv3_pfifo_read(uint32_t address); void nv3_pfifo_write(uint32_t address, uint32_t value); +void nv3_pfifo_interrupt(uint32_t id, bool fire_now); // NV3 PFIFO - Caches void nv3_pfifo_cache0_push(); diff --git a/src/log.c b/src/log.c index 129f2313f..fa39a6897 100644 --- a/src/log.c +++ b/src/log.c @@ -36,14 +36,15 @@ #include <86box/log.h> typedef struct log_t { - char buff[1024]; - char *dev_name; - int seen; - int suppr_seen; - char** cyclic_buff; - int32_t cyclic_last_line; - int32_t log_cycles; - int32_t last_repeat_order; + char buff[1024]; + char dev_name[1024]; + int seen; + int suppr_seen; + /* Cyclical log buffer. */ + char **cyclic_buff; + int32_t cyclic_last_line; + int32_t log_cycles; + int32_t last_repeat_order; } log_t; /* File to log output to. */ diff --git a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c index 57d19fc42..3aa1d497b 100644 --- a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c +++ b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * NV3 PBUS DMA: DMA Engine + * NV3 PBUS DMA: DMA & Notifier Engine * * * diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c index 4638b066e..b9e7e4cdd 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfifo.c +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -433,7 +433,15 @@ void nv3_pfifo_cache0_push() void nv3_pfifo_cache0_pull() { + // Do nothing if PFIFO CACHE0 is disabled + if (!nv3->pfifo.cache0_settings.puller_control & (1 >> NV3_PFIFO_CACHE0_PULLER_CONTROL_ENABLED)) + return; + // Do nothing if there is nothing in cache0 to pull + if (nv3->pfifo.cache0_settings.put_address == nv3->pfifo.cache0_settings.get_address) + return; + + // There is only one entry } void nv3_pfifo_cache1_push() @@ -443,7 +451,13 @@ void nv3_pfifo_cache1_push() void nv3_pfifo_cache1_pull() { + // Do nothing if PFIFO CACHE1 is disabled + if (!nv3->pfifo.cache1_settings.puller_control & (1 >> NV3_PFIFO_CACHE1_PULLER_CONTROL_ENABLED)) + return; + // Do nothing if there is nothing in cache1 to pull + if (nv3->pfifo.cache1_settings.put_address == nv3->pfifo.cache1_settings.get_address) + return; } bool nv3_pfifo_cache1_is_free() diff --git a/src/video/nv/nv3/subsystems/nv3_pramin.c b/src/video/nv/nv3/subsystems/nv3_pramin.c index f27ca0415..d9ab438d7 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin.c @@ -23,11 +23,17 @@ #include <86Box/86box.h> #include <86Box/device.h> #include <86Box/mem.h> -#include <86box/pci.h> +#include <86Box/pci.h> #include <86Box/rom.h> // DEPENDENT!!! #include <86Box/video.h> #include <86Box/nv/vid_nv.h> #include <86Box/nv/vid_nv3.h> +#include <86box/nv/classes/vid_nv3_classes.h> + +// Functions only used in this translation unit +#ifndef RELEASE_BUILD +void nv3_debug_ramin_print_context_info(uint32_t name, nv3_ramin_context_t context); +#endif // i believe the main loop is to walk the hashtable in RAMIN (last 0.5 MB of VRAM), // find the objects that were submitted from DMA @@ -190,6 +196,12 @@ void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv) } +void nv3_pfifo_interrupt(uint32_t id, bool fire_now) +{ + nv3->pfifo.interrupt_status |= (1 << id); + nv3_pmc_handle_interrupts(fire_now); +} + /* RAMIN access arbitration functions Arbitrates reads and writes to RAMFC (unused dma context storage), RAMRO (invalid object submission location), RAMHT (hashtable for graphics objectstorage) (RAMAU?) @@ -311,6 +323,7 @@ bool nv3_ramin_arbitrate_write(uint32_t address, uint32_t value) break; } + // send the addresses to the right part if (address >= ramht_start && address <= ramht_end) { @@ -334,7 +347,151 @@ bool nv3_ramin_arbitrate_write(uint32_t address, uint32_t value) } // THIS IS THE MOST IMPORTANT FUNCTION! -void nv3_ramin_find_object(uint32_t name, uint32_t cache_id, uint32_t channel_id, uint32_t subchannel_id) +bool nv3_ramin_find_object(uint32_t name, uint32_t cache_num, uint32_t channel_id, uint32_t subchannel_id) { // TODO: WRITE IT!!! -} \ No newline at end of file + // Set the number of entries to search based on the ramht size (2*(size+1)) + // Not a switch statement in case newer gpus have larger ramins + uint32_t bucket_entries = 2 * (((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03) + 1); + + // Calculate the address in the hashtable + uint32_t ramht_base = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS; + uint32_t ramht_cur_address = ramht_base; + + nv_log("NV3: Beginning search for graphics object at RAMHT base=0x%04x, Cache%d, channel=%d, subchannel=%d)", name, cache_num, channel_id, subchannel_id); + + bool found_object = false; + + // set up some variables + uint32_t found_obj_name; + nv3_ramin_context_t obj_context_struct; + + for (uint32_t bucket_entry = 0; bucket_entry < bucket_entries; bucket_entry++) + { + found_obj_name = nv3_ramin_read32(ramht_cur_address, NULL); + ramht_cur_address += 0x04; + uint32_t obj_context = nv3_ramin_read32(ramht_cur_address, NULL); + ramht_cur_address += 0x04; + obj_context_struct = *(nv3_ramin_context_t*)&obj_context; + + // see if the object is in the right channel + if (found_obj_name == name + && obj_context_struct.channel_id == channel_id) + { + found_object = true; + break; + } + } + + if (!found_object) + { + if (!cache_num) + { + nv3->pfifo.debug_0 |= NV3_PFIFO_CACHE0_ERROR_PENDING; + nv3->pfifo.cache0_settings.puller_control |= NV3_PFIFO_CACHE0_PULLER_CONTROL_HASH_FAILURE; + + //It turns itself off on failure, the drivers turn it back on + nv3->pfifo.cache0_settings.puller_control &= ~NV3_PFIFO_CACHE0_PULLER_CONTROL_ENABLED; + } + else + { + nv3->pfifo.debug_0 |= NV3_PFIFO_CACHE1_ERROR_PENDING; + nv3->pfifo.cache1_settings.puller_control |= NV3_PFIFO_CACHE1_PULLER_CONTROL_HASH_FAILURE; + + //It turns itself off on failure, the drivers turn it back on + nv3->pfifo.cache1_settings.puller_control &= ~NV3_PFIFO_CACHE1_PULLER_CONTROL_ENABLED; + } + + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + + return false; + } + + // So we did find an object. + // Now try to read some of this... + + // Class ID is 5 bits in all other parts of the gpu but 7 bits here. A move in a direction that didn't pan out? + // Represented as 0x40-0x5f? Some other meaning + + // Perform more validation + + if (obj_context_struct.class_id > NV3_PFIFO_FIRST_VALID_GRAPHICS_OBJECT_ID + || obj_context_struct.class_id < NV3_PFIFO_LAST_VALID_GRAPHICS_OBJECT_ID) + { + fatal("NV3: Invalid graphics object class ID name=0x%04x type=%04x, interpreted by pgraph as: %04x (Contact starfrost)", + name, obj_context_struct.class_id, obj_context_struct.class_id & 0x1F); + } + else if (obj_context_struct.channel_id > NV3_DMA_CHANNELS) + fatal("NV3: Super fucked up graphics object. Contact starfrost with the error string: DMA Channel ID=%d, it should be 0-8", obj_context_struct.channel_id); + + // Illegal accesses sent to RAMRO, so ignore here + // TODO: SEND THESE TO RAMRO!!!!! + + #ifndef RELEASE_BUILD + nv3_debug_ramin_print_context_info(name, obj_context_struct); + #endif + + // By definition we can't have a cache error by here so take it off + if (!cache_num) + nv3->pfifo.cache0_settings.puller_control &= ~NV3_PFIFO_CACHE0_PULLER_CONTROL_HASH_FAILURE; + else + nv3->pfifo.cache1_settings.puller_control &= ~NV3_PFIFO_CACHE1_PULLER_CONTROL_HASH_FAILURE; + + // Caches store all the subchannels for our current dma channel and basically get stale every context switch + // Also we have to check that a osftware object didn't end up in here... + + bool is_software = false; + if (!cache_num) + is_software = (nv3->pfifo.cache0_settings.context[subchannel_id] & 0x800000); + else + is_software = (nv3->pfifo.cache1_settings.context[subchannel_id] & 0x800000); + + // This isn't an error but it's sent as an interrupt so the drivers can sync + if (is_software) + { + // handle it as an error + if (!cache_num) + { + nv3->pfifo.cache0_settings.puller_control |= NV3_PFIFO_CACHE0_PULLER_CONTROL_SOFTWARE_METHOD; + nv3->pfifo.cache0_settings.puller_control &= ~NV3_PFIFO_CACHE0_PULLER_CONTROL_ENABLED; + } + else + { + nv3->pfifo.cache1_settings.puller_control |= NV3_PFIFO_CACHE1_PULLER_CONTROL_SOFTWARE_METHOD; + nv3->pfifo.cache0_settings.puller_control &= ~NV3_PFIFO_CACHE1_PULLER_CONTROL_ENABLED; + } + + // It's an error but it isn't lol + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + + } + else + { + // obviously turn off the "is software" if it's not + if (!cache_num) + nv3->pfifo.cache0_settings.puller_control &= ~NV3_PFIFO_CACHE0_PULLER_CONTROL_SOFTWARE_METHOD; + else + nv3->pfifo.cache1_settings.puller_control &= ~NV3_PFIFO_CACHE1_PULLER_CONTROL_SOFTWARE_METHOD; + } + + // Ok we found it. Lol + return true; + +} + +#ifndef RELEASE_BUILD +// Prints out some informaiton about the object +void nv3_debug_ramin_print_context_info(uint32_t name, nv3_ramin_context_t context) +{ + nv_log("NV3: Found object:"); + nv_log("Name: 0x%04x", name); + + nv_log("Context:"); + nv_log("DMA Channel %d (0-7 valid)", context.channel_id); + nv_log("Class ID: as repreesnted in ramin=%04x, Stupid 5 bit version (the actual id)=0x%04x (%s)", context.class_id, + context.class_id & 0x1F, nv3_class_names[context.class_id & 0x1F]); + nv_log("Render Engine %d (0=Software, also DMA? 1=Accelerated Renderer)", context.is_rendering); + nv_log("PRAMIN Offset 0x%08x", context.ramin_offset << 4); +} + +#endif \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c index 6568e6db4..fc0190c2e 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c @@ -22,7 +22,7 @@ #include <86Box/86box.h> #include <86Box/device.h> #include <86Box/mem.h> -#include <86box/pci.h> +#include <86Box/pci.h> #include <86Box/rom.h> // DEPENDENT!!! #include <86Box/video.h> #include <86Box/nv/vid_nv.h> @@ -32,10 +32,14 @@ It is used to get the offset within RAMHT of a graphics object. */ -uint32_t nv3_ramht_hash(nv3_ramin_name_t name, uint32_t channel) +uint32_t nv3_ramht_hash(uint32_t name, uint32_t channel) { - uint32_t hash = (name.byte_high ^ name.byte_mid2 ^ name.byte_mid1 ^ name.byte_low ^ (uint8_t)channel); - nv_log("NV3: Generating RAMHT hash (RAMHT slot=0x%04x (from name 0x%08x for DMA channel 0x%04x)\n)\n", name, channel); + // convert the name to an array of bytes + uint8_t* hash_bytes = (uint8_t*)name; + + // is this the right endianness? + uint32_t hash = (hash_bytes[0] ^ hash_bytes[1] ^ hash_bytes[2] ^ hash_bytes[3] ^ (uint8_t)channel); + nv_log("NV3: Generated RAMHT hash 0x%04x (RAMHT slot=0x%04x (from name 0x%08x for DMA channel 0x%04x)\n)\n", hash, name, channel); return hash; }