diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index f2d28eaf9..e831de61f 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -7,7 +7,7 @@ * This file is part of the 86Box distribution. * * vid_nv3.h: NV3 Architecture Hardware Reference (open-source) - * Last updated 2 January 2025 (STILL WORKING ON IT) + * Last updated 9 January 2025 (STILL WORKING ON IT) * * * @@ -204,10 +204,10 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS 12 #define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS_DEFAULT 0x0 #define NV3_PFIFO_CONFIG_RAMHT_SIZE 16 -#define NV3_PFIFO_CONFIG_RAMHT_4K 0x0 -#define NV3_PFIFO_CONFIG_RAMHT_8K 0x1 -#define NV3_PFIFO_CONFIG_RAMHT_16K 0x2 -#define NV3_PFIFO_CONFIG_RAMHT_32K 0x3 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_4K 0x0 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_8K 0x1 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_16K 0x2 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_32K 0x3 #define NV3_PFIFO_CONFIG_RAMFC 0x2214 #define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS 9 @@ -578,7 +578,7 @@ extern const device_config_t nv3_config[]; #define NV3_CRTC_REGISTER_STANDARDVGA_END 0x18 -// These are nvidia (25-63) +// These are nvidia, licensed from weitek (25-63) #define NV3_CRTC_REGISTER_RPC0 0x19 // What does this mean? #define NV3_CRTC_REGISTER_RPC1 0x1A // What does this mean? #define NV3_CRTC_REGISTER_READ_BANK 0x1D @@ -865,7 +865,7 @@ typedef struct nv3_pramin_ramht_s nv3_pramin_ramht_subchannel_t subchannels[NV3_DMA_CHANNELS][NV3_DMA_SUBCHANNELS_PER_CHANNEL]; } nv3_pramin_ramht_t; -uint32_t nv3_pramin_ramht_hash(nv3_pramin_name_t name, uint32_t channel); +uint32_t nv3_ramht_hash(nv3_pramin_name_t name, uint32_t channel); // Anti-fuckup device typedef struct nv3_pramin_ramro_s @@ -963,6 +963,16 @@ void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv); void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv); // Write 16-bit RAMIN void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv); // Write 32-bit RAMIN +bool nv3_pramin_arbitrate_read(uint32_t address, uint32_t* value); // Read arbitration so we can read/write to the structures in the first 64k of ramin +bool nv3_pramin_arbitrate_write(uint32_t address, uint32_t value); // Write arbitration so we can read/write to the structures in the first 64k of ramin + +uint32_t nv3_ramfc_read(uint32_t address); +void nv3_ramfc_write(uint32_t address, uint32_t value); +uint32_t nv3_ramro_read(uint32_t address); +void nv3_ramro_write(uint32_t address, uint32_t value); +uint32_t nv3_ramht_read(uint32_t address); +void nv3_ramht_write(uint32_t address, uint32_t value); + // MMIO Arbitration // Determine where the hell in this mess our reads or writes are going uint32_t nv3_mmio_arbitrate_read(uint32_t address); @@ -1018,8 +1028,6 @@ uint32_t nv3_user_read(uint32_t address); void nv3_user_write(uint32_t address, uint32_t value); #define nv3_object_submit_start nv3_user_read #define nv3_object_submit_end nv3_user_write -uint32_t nv3_pramin_arbitrate_read(uint32_t address); -void nv3_pramin_arbitrate_write(uint32_t address, uint32_t value); // TODO: RAMHT, RAMFC...or maybe handle it inside of nv3_pramin_* // GPU subsystems diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index 22da49b20..bab378b9f 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -103,8 +103,9 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) ret = nv3_vram_read(address); else if (address >= NV3_USER_START && address <= NV3_USER_END) ret = nv3_user_read(address); - else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END) - ret = nv3_pramin_arbitrate_read(address); // RAMHT, RAMFC, RAMRO etc dettermined by nv3_ramin_* function + // RAMIN is handled by a separate memory mapping in PCI BAR1 + //else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END) + //ret = nv3_pramin_arbitrate_read(address); // RAMHT, RAMFC, RAMRO etc dettermined by nv3_ramin_* function else { nv_log("NV3: MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c index 931244b20..1838faef5 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfifo.c +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -179,14 +179,14 @@ void nv3_pfifo_write(uint32_t address, uint32_t value) nv_log("NV3: RAMHT Reconfiguration\n" "Base Address in RAMIN: %d\n" - "Size: 0x%08x bytes\n", (value >> 12) & 0x1f, new_size_ramht); + "Size: 0x%08x bytes\n", ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12, new_size_ramht); #endif break; case NV3_PFIFO_CONFIG_RAMFC: nv3->pfifo.ramfc_config = value; nv_log("NV3: RAMFC Reconfiguration\n" - "Base Address in RAMIN: %d\n", (value >> 12) & 0x1f); + "Base Address in RAMIN: %d\n", ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9); break; case NV3_PFIFO_CONFIG_RAMRO: nv3->pfifo.ramro_config = value; @@ -200,7 +200,7 @@ void nv3_pfifo_write(uint32_t address, uint32_t value) nv_log("NV3: RAMRO Reconfiguration\n" "Base Address in RAMIN: %d\n" - "Size: 0x%08x bytes\n", (value >> 12) & 0x1f, new_size_ramro); + "Size: 0x%08x bytes\n", ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9, new_size_ramro); break; } } diff --git a/src/video/nv/nv3/subsystems/nv3_pramin.c b/src/video/nv/nv3/subsystems/nv3_pramin.c index c5093a175..35fa80603 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin.c @@ -48,11 +48,15 @@ uint8_t nv3_ramin_read8(uint32_t addr, void* priv) addr ^= (nv3->nvbase.svga.vram_max- 0x10); - uint8_t val = nv3->nvbase.svga.vram[addr]; + uint32_t val = 0x00; - nv_log("NV3: Read byte from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + if (!nv3_pramin_arbitrate_read(addr, &val)) // Oh well + { + val = (uint8_t)nv3->nvbase.svga.vram[addr]; + nv_log("NV3: Read byte from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + } - return val; + return (uint8_t)val; } // Read 16-bit ramin @@ -68,9 +72,13 @@ uint16_t nv3_ramin_read16(uint32_t addr, void* priv) addr ^= (nv3->nvbase.svga.vram_max - 0x10); addr >>= 1; // what - uint16_t val = vram_16bit[addr]; // what + uint32_t val = 0x00; - nv_log("NV3: Read word from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + if (!nv3_pramin_arbitrate_read(addr, &val)) + { + val = (uint16_t)vram_16bit[addr]; + nv_log("NV3: Read word from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + } return val; } @@ -88,9 +96,14 @@ uint32_t nv3_ramin_read32(uint32_t addr, void* priv) addr ^= (nv3->nvbase.svga.vram_max - 0x10); addr >>= 2; // what - uint32_t val = vram_32bit[addr]; + uint32_t val = 0x00; - nv_log("NV3: Read dword from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + if (!nv3_pramin_arbitrate_read(addr, &val)) + { + val = vram_32bit[addr]; + + nv_log("NV3: Read dword from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + } return val; } @@ -107,9 +120,15 @@ void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv) // reversal unit size in this case is 16 bytes, vram size is 2-8mb (but 8mb is zx/nv3t only and 2mb...i haven't found a 22mb card) addr ^= (nv3->nvbase.svga.vram_max - 0x10); - nv3->nvbase.svga.vram[addr] = val; + uint32_t val32 = 0x00; + + if (!nv3_pramin_arbitrate_write(addr, val32)) + { + nv3->nvbase.svga.vram[addr] = val; + nv_log("NV3: Write byte to PRAMIN addr=0x%08x val=0x%02x (raw address=0x%08x)\n", addr, val, raw_addr); + } + - nv_log("NV3: Write byte to RAMIN addr=0x%08x val=0x%02x (raw address=0x%08x)\n", addr, val, raw_addr); } // Write 16-bit ramin @@ -125,9 +144,15 @@ void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv) addr ^= (nv3->nvbase.svga.vram_max - 0x10); addr >>= 1; // what - vram_16bit[addr] = val; + uint32_t val32 = 0x00; + + if (!nv3_pramin_arbitrate_write(addr, val32)) + { + vram_16bit[addr] = val; + nv_log("NV3: Write word to PRAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr); + } + - nv_log("NV3: Write word to RAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr); } // Write 32-bit ramin @@ -143,20 +168,155 @@ void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv) addr ^= (nv3->nvbase.svga.vram_max - 0x10); addr >>= 2; // what - vram_32bit[addr] = val; + uint32_t val32 = 0x00; + + if (!nv3_pramin_arbitrate_write(addr, val32)) + { + vram_32bit[addr] = val; + nv_log("NV3: Write dnv3_pramin_arbitrate_readword to PRAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr); + } - nv_log("NV3: Write dword to RAMIN addr=0x%08x val=0x%08x (raw address=0x%08x)\n", addr, val, raw_addr); } /* -Arbitrates reads and writes to RAMFC, RAMRO, RAMHT and generic RAMIN +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?) +and generic RAMIN + +Takes a pointer to a result integer. This is because we need to check its result in our normal write function. +Returns true if a valid "non-generic" address was found (e.g. RAMFC/RAMRO/RAMHT). False if the specified address is a generic RAMIN address */ -uint32_t nv3_pramin_arbitrate_read(uint32_t address) +bool nv3_pramin_arbitrate_read(uint32_t address, uint32_t* value) { - return 0; + if (!nv3) return 0x00; + + uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03); + uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + // Get the addresses of RAMHT, RAMFC, RAMRO + // They must be within first 64KB of PRAMIN! + uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned + uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + + // Calculate the RAMHT and RAMRO end points. + // (RAMFC is always 0x1000 bytes on NV3.) + uint32_t ramht_end = ramht_start; + uint32_t ramfc_end = ramfc_start + 0x1000; + uint32_t ramro_end = ramro_start; + + switch (ramht_size) + { + case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_1; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_2; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_3; + break; + } + + switch (ramro_size) + { + case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B: + ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K: + ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_1; + break; + } + + if (address >= ramht_start + && address <= ramht_end) + { + *value = nv3_ramht_read(address); + return true; + } + else if (address >= ramfc_start + && address <= ramfc_end) + { + *value = nv3_ramfc_read(address); + return true; + } + else if (address >= ramro_start + && address <= ramro_end) + { + *value = nv3_ramro_read(address); + return true; + } + + /* temp */ + return false; } -void nv3_pramin_arbitrate_write(uint32_t address, uint32_t value) +bool nv3_pramin_arbitrate_write(uint32_t address, uint32_t value) { - + if (!nv3) return 0x00; + + uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03); + uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + // Get the addresses of RAMHT, RAMFC, RAMRO + // They must be within first 64KB of PRAMIN! + uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned + uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + + // Calculate the RAMHT and RAMRO end points. + // (RAMFC is always 0x1000 bytes on NV3.) + uint32_t ramht_end = ramht_start; + uint32_t ramfc_end = ramfc_start + 0x1000; + uint32_t ramro_end = ramro_start; + + switch (ramht_size) + { + case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_1; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_2; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K: + ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_3; + break; + } + + switch (ramro_size) + { + case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B: + ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K: + ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_1; + break; + } + + if (address >= ramht_start + && address <= ramht_end) + { + nv3_ramht_write(address, value); + return true; + } + else if (address >= ramfc_start + && address <= ramfc_end) + { + nv3_ramfc_write(address, value); + return true; + } + else if (address >= ramro_start + && address <= ramro_end) + { + nv3_ramro_write(address, value); + return true; + } + + return false; } \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c index 5c6d3a54c..e06445755 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c @@ -28,3 +28,12 @@ #include <86Box/nv/vid_nv.h> #include <86Box/nv/vid_nv3.h> +uint32_t nv3_ramfc_read(uint32_t address) +{ + nv_log("NV3: RAMFC (Unused DMA channel context) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address); +} + +void nv3_ramfc_write(uint32_t address, uint32_t value) +{ + nv_log("NV3: RAMFC (Unused DMA channel context) Write (0x%04x -> 0x%04x), UNIMPLEMENTED", value, address); +} \ 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 b77f18729..ff72e811c 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c @@ -32,9 +32,20 @@ It is used to get the offset within RAMHT of a graphics object. */ -uint32_t nv3_pramin_ramht_hash(nv3_pramin_name_t name, uint32_t channel) +uint32_t nv3_ramht_hash(nv3_pramin_name_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)", name, channel); return hash; -} \ No newline at end of file +} + + +uint32_t nv3_ramht_read(uint32_t address) +{ + nv_log("NV3: RAMHT (Graphics object storage hashtable) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address); +} + +void nv3_ramht_write(uint32_t address, uint32_t value) +{ + nv_log("NV3: RAMHT (Graphics object storage hashtable) Write (0x%04x -> 0x%04x), UNIMPLEMENTED", value, address); +} diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c index 865bc46ec..6176e191a 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c @@ -28,3 +28,12 @@ #include <86Box/nv/vid_nv.h> #include <86Box/nv/vid_nv3.h> +uint32_t nv3_ramro_read(uint32_t address) +{ + nv_log("NV3: RAM Runout (invalid dma object submission) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address); +} + +void nv3_ramro_write(uint32_t address, uint32_t value) +{ + nv_log("NV3: RAM Runout WRITE, OH CRAP!!!! (0x%04x -> 0x%04x), UNIMPLEMENTED\n (Todo: Read the entries...)", value, address); +} \ No newline at end of file