Initial progress at RAMRO, RAMHT and RAMFC

This commit is contained in:
starfrost013
2025-01-11 02:24:12 +00:00
parent 4f3412908c
commit 4778e86273
7 changed files with 232 additions and 34 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}
}
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);
}

View File

@@ -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);
}