Actually add basic read and write to those pgraph registers so we can debug them, add PFIFO definitions and add the PFIFO CACHE1 gray code conversion functions as preparation for future work

This commit is contained in:
starfrost013
2025-01-20 01:09:32 +00:00
parent 28f5ecb1f8
commit 7ba088a5eb
8 changed files with 336 additions and 34 deletions

View File

@@ -1043,9 +1043,12 @@ typedef struct nv3_object_class_017
/* No placeholder needed, it really is that long. */
} nv3_d3d5_accelerated_triangle_with_zeta_buffer_t;
/* 0x18, 0x19, 0x1A, 0x1B don't exist */
/* 0x19, 0x1A, 0x1B don't exist */
typedef struct nv3_object_class_018
{
} nv3_point_with_zeta_buffer_t;
/* WHY IS THE FORMAT DIFFERENT TO THE REST OF THE GPU?
They are making it look like a bitfield but it's hex?

View File

@@ -14,7 +14,7 @@
* Also check the doc folder for some more notres
*
* vid_nv3.h: NV3 Architecture Hardware Reference (open-source)
* Last updated: 12 January 2025 (STILL WORKING ON IT!!!)
* Last updated: 20 January 2025 (STILL WORKING ON IT!!!)
*
* Authors: Connor Hyde <mario64crashed@gmail.com>
*
@@ -218,7 +218,6 @@ extern const device_config_t nv3_config[];
#define NV3_PFIFO_CONFIG_RAMFC 0x2214
#define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS 9
#define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS_DEFAULT 0x1C00 // Hardcoded in silicon?
#define NV3_PFIFO_CONFIG_RAMRO 0x2218
#define NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS 9
#define NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS_DEFAULT 0x1E00 // Hardcoded in silicon?
@@ -226,6 +225,44 @@ extern const device_config_t nv3_config[];
#define NV3_PFIFO_CONFIG_RAMRO_SIZE_512B 0x0
#define NV3_PFIFO_CONFIG_RAMRO_SIZE_8K 0x1
#define NV3_PFIFO_RUNOUT_STATUS 0x2400
#define NV3_PFIFO_RUNOUT_STATUS_RANOUT 0 // 1 if we fucked up
#define NV3_PFIFO_RUNOUT_STATUS_LOW_MARK 4 // 1 if ramro is empty
#define NV3_PFIFO_RUNOUT_STATUS_HIGH_MARK 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
#define NV3_PFIFO_RUNOUT_GET_ADDRESS 3 // 13:3
#define NV3_PFIFO_CACHE0_SIZE 1 // This is for software-injected notified only!
#define NV3_PFIFO_CACHE1_SIZE_REV_AB 32
#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_ACCESS 0x3000
#define NV3_PFIFO_CACHE0_DMA_CHANNEL_ID 0x3004
#define NV3_PFIFO_CACHE0_PUT 0x3010
#define NV3_PFIFO_CACHE0_PUT_ADDRESS 2 // 1 bit
#define NV3_PFIFO_CACHE0_PULLER 0x3040
#define NV3_PFIFO_CACHE0_GET 0x3070
#define NV3_PFIFO_CACHE0_GET_ADDRESS 2 // 1 bit
#define NV3_PFIFO_CACHE1_ACCESS 0x3200
#define NV3_PFIFO_CACHE1_DMA_CHANNEL_ID 0x3204
#define NV3_PFIFO_CACHE1_PUT 0x3210
#define NV3_PFIFO_CACHE1_PUT_ADDRESS 2 // 6:2
#define NV3_PFIFO_CACHE1_DMA_STATUS 0x3218
#define NV3_PFIFO_CACHE1_DMA_CONFIG_0 0x3220
#define NV3_PFIFO_CACHE1_DMA_CONFIG_1 0x3224
#define NV3_PFIFO_CACHE1_DMA_CONFIG_2 0x3228
#define NV3_PFIFO_CACHE1_DMA_CONFIG_3 0x322C
// Why does a gpu need its own translation lookaside buffer and pagetable format. Are they crazy
#define NV3_PFIFO_CACHE1_DMA_TLB_TAG 0x3230
#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 0x3240
#define NV3_PFIFO_CACHE1_PULLER_CONTEXT_IS_CLEAN 0x3250
#define NV3_PFIFO_CACHE1_GET 0x3270
#define NV3_PFIFO_CACHE1_GET_ADDRESS 2 // 6:2
#define NV3_PFIFO_END 0x3FFF
#define NV3_PRM_START 0x4000 // Real-Mode Device Support Subsystem
#define NV3_PRM_INTR 0x4100
@@ -750,7 +787,7 @@ typedef struct nv3_pramdac_s
uint32_t hserr_width; // horizontal sync error width
} nv3_pramdac_t;
/* Holds DMA context channel information */
/* Holds DMA channel context information */
typedef struct nv3_pgraph_context_switch_s
{
/* TODO */
@@ -766,12 +803,20 @@ typedef struct nv3_pgraph_context_control_s
*/
typedef struct nv3_pgraph_context_user_s
{
bool reserved3 : 1;
uint8_t channel : 7;
uint8_t reserved2 : 4;
uint8_t class : 5;
uint8_t subchannel : 3;
uint16_t reserved : 12;
union
{
uint32_t value;
struct
{
bool reserved3 : 1;
uint8_t channel : 7;
uint8_t reserved2 : 3;
uint8_t class : 5;
uint8_t subchannel : 3;
uint16_t reserved : 13;
};
};
} nv3_pgraph_context_user_t;
typedef struct nv3_pgraph_dma_settings_s
@@ -819,6 +864,7 @@ typedef struct nv3_pgraph_s
uint32_t interrupt_status_1; // Interrupt status 1
uint32_t interrupt_enable_1; // Interrupt enable 1
uint32_t context_switch; // TODO: Make this a struct, it's just going to be enormous lol.
nv3_pgraph_context_control_t context_control;
nv3_pgraph_context_switch_t context_user_submit;
nv3_pgraph_context_user_t context_user;
@@ -923,16 +969,21 @@ typedef struct nv3_ptimer_s
uint32_t alarm; // The value of time when there should be an alarm
} nv3_ptimer_t;
typedef struct nv3_pramin_name_sd
typedef struct nv3_pramin_name_s
{
union
{
uint32_t name;
uint8_t byte_high;
uint8_t byte_mid2;
uint8_t byte_mid1;
uint8_t byte_low;
struct
{
uint8_t byte_high;
uint8_t byte_mid2;
uint8_t byte_mid1;
uint8_t byte_low;
};
};
} nv3_pramin_name_t;
typedef struct nv3_pramin_context_s
@@ -940,10 +991,16 @@ typedef struct nv3_pramin_context_s
union
{
uint32_t context;
uint8_t dma_channel;
uint8_t render_object; //0=sw, 1=hw accelerated render
uint8_t class_id;
uint8_t ramin_offset; //find
struct
{
uint8_t dma_channel;
uint8_t render_object; //0=sw, 1=hw accelerated render
uint8_t class_id;
uint8_t ramin_offset; //find
};
};
} nv3_pramin_context_t;
@@ -1110,8 +1167,6 @@ uint32_t nv3_cio_read(uint32_t address);
void nv3_cio_write(uint32_t address, uint32_t value);
uint32_t nv3_pbus_read(uint32_t address);
void nv3_pbus_write(uint32_t address, uint32_t value);
uint32_t nv3_pfifo_read(uint32_t address);
void nv3_pfifo_write(uint32_t address, uint32_t value);
uint32_t nv3_prm_read(uint32_t address);
void nv3_prm_write(uint32_t address, uint32_t value);
uint32_t nv3_prmio_read(uint32_t address);
@@ -1133,8 +1188,6 @@ uint32_t nv3_palt_read(uint32_t address);
void nv3_palt_write(uint32_t address, uint32_t value);
uint32_t nv3_pme_read(uint32_t address);
void nv3_pme_write(uint32_t address, uint32_t value);
uint32_t nv3_pgraph_read(uint32_t address);
void nv3_pgraph_write(uint32_t address, uint32_t value);
// TODO: PGRAPH class registers
@@ -1163,11 +1216,18 @@ uint32_t nv3_pmc_handle_interrupts(bool send_now);
// NV3 PGRAPH
void nv3_pgraph_init();
uint32_t nv3_pgraph_read(uint32_t address);
void nv3_pgraph_write(uint32_t address, uint32_t value);
void nv3_pgraph_vblank_start(svga_t* svga);
// NV3 PFIFO
void nv3_pfifo_init();
uint32_t nv3_pfifo_read(uint32_t address);
void nv3_pfifo_write(uint32_t address, uint32_t value);
// NV3 PFIFO - Caches
uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val);
uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val);
// NV3 PFB
void nv3_pfb_init();

View File

@@ -56,7 +56,7 @@ const char* nv3_class_names[] =
"NV3 class 0x15: Stretched image from CPU",
"NV3 INVALID class 0x16",
"NV3 class 0x17: Direct3D 5.0 accelerated textured triangle w/zeta buffer",
"NV3 INVALID class 0x18",
"NV3 class 0x18: Point with zeta buffer",
"NV3 INVALID class 0x19",
"NV3 INVALID class 0x1A",
"NV3 INVALID class 0x1B",

View File

@@ -28,8 +28,6 @@
#include <86Box/nv/vid_nv.h>
#include <86Box/nv/vid_nv3.h>
//
// ****** pfifo register list START ******
//
@@ -206,4 +204,32 @@ void nv3_pfifo_write(uint32_t address, uint32_t value)
}
}
}
/*
https://en.wikipedia.org/wiki/Gray_code
WHY?????? IT'S NOT A TELEGRAPH IT'S A GPU?????
Convert from a normal number to a total insanity number which is only used in PFIFO CACHE1 for ungodly and totally unknowable reasons
*/
uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val)
{
return (val) ^ (val >> 1);
}
/*
Back to sanity
*/
uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val)
{
uint32_t mask = val >> 1;
// shift right until we have our normla number again
while (mask)
{
val ^= mask;
mask >>= 1;
}
return val;
}

View File

@@ -120,6 +120,17 @@ uint32_t nv3_pgraph_read(uint32_t address)
{
switch (reg->address)
{
case NV3_PGRAPH_DEBUG_0:
ret = nv3->pgraph.debug_0;
break;
case NV3_PGRAPH_DEBUG_1:
ret = nv3->pgraph.debug_1;
break;
case NV3_PGRAPH_DEBUG_2:
ret = nv3->pgraph.debug_2;
break;
case NV3_PGRAPH_DEBUG_3:
ret = nv3->pgraph.debug_3;
//interrupt status and enable regs
case NV3_PGRAPH_INTR_0:
ret = nv3->pgraph.interrupt_status_0;
@@ -133,6 +144,101 @@ uint32_t nv3_pgraph_read(uint32_t address)
case NV3_PGRAPH_INTR_EN_1:
ret = nv3->pgraph.interrupt_enable_1;
break;
// A lot of this is currently a temporary implementation so that we can just debug what the current state looks like
// during the driver initialisation process
// In the future, these will most likely have their own functions...
// Context Swithcing (THIS IS CONTROLLED BY PFIFO!)
case NV3_PGRAPH_CONTEXT_SWITCH:
ret = nv3->pgraph.context_switch;
break;
case NV3_PGRAPH_CONTEXT_CONTROL:
ret = *(uint32_t*)&nv3->pgraph.context_control;
break;
case NV3_PGRAPH_CONTEXT_USER:
ret = *(uint32_t*)&nv3->pgraph.context_user;
break;
// Clip
case NV3_PGRAPH_ABS_UCLIP_XMIN:
ret = nv3->pgraph.abs_uclip_xmin;
break;
case NV3_PGRAPH_ABS_UCLIP_XMAX:
ret = nv3->pgraph.abs_uclip_xmax;
break;
case NV3_PGRAPH_ABS_UCLIP_YMIN:
ret = nv3->pgraph.abs_uclip_ymin;
break;
case NV3_PGRAPH_ABS_UCLIP_YMAX:
ret = nv3->pgraph.abs_uclip_ymax;
break;
// Canvas
case NV3_PGRAPH_SRC_CANVAS_MIN:
ret = *(uint32_t*)&nv3->pgraph.src_canvas_min;
break;
case NV3_PGRAPH_SRC_CANVAS_MAX:
ret = *(uint32_t*)&nv3->pgraph.src_canvas_max;
break;
// Pattern
case NV3_PGRAPH_PATTERN_COLOR_0_0:
ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_0;
break;
case NV3_PGRAPH_PATTERN_COLOR_0_1:
ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_1;
break;
case NV3_PGRAPH_PATTERN_COLOR_1_0:
ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_0;
break;
case NV3_PGRAPH_PATTERN_COLOR_1_1:
ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_1;
break;
case NV3_PGRAPH_PATTERN_BITMAP_HIGH:
ret = nv3->pgraph.pattern_bitmap_high;
break;
case NV3_PGRAPH_PATTERN_BITMAP_LOW:
ret = nv3->pgraph.pattern_bitmap_low;
break;
// Beta factor
case NV3_PGRAPH_BETA:
ret = nv3->pgraph.beta_factor;
break;
// DMA
case NV3_PGRAPH_DMA:
ret = *(uint32_t*)&nv3->pgraph.dma_settings;
break;
case NV3_PGRAPH_NOTIFY:
ret = *(uint32_t*)&nv3->pgraph.notifier;
break;
// More clip
case NV3_PGRAPH_CLIP0_MIN:
ret = *(uint32_t*)&nv3->pgraph.clip0_min;
break;
case NV3_PGRAPH_CLIP0_MAX:
ret = *(uint32_t*)&nv3->pgraph.clip0_max;
break;
case NV3_PGRAPH_CLIP1_MIN:
ret = *(uint32_t*)&nv3->pgraph.clip1_min;
break;
case NV3_PGRAPH_CLIP1_MAX:
ret = *(uint32_t*)&nv3->pgraph.clip1_max;
break;
case NV3_PGRAPH_CLIP_MISC:
ret = *(uint32_t*)&nv3->pgraph.clip_misc_settings;
break;
// Overall Status
case NV3_PGRAPH_STATUS:
ret = *(uint32_t*)&nv3->pgraph.status;
break;
// Trapped Address
case NV3_PGRAPH_TRAPPED_ADDRESS:
ret = nv3->pgraph.trapped_address;
break;
case NV3_PGRAPH_TRAPPED_DATA:
ret = nv3->pgraph.trapped_data;
break;
case NV3_PGRAPH_TRAPPED_INSTANCE:
ret = nv3->pgraph.trapped_instance;
break;
}
}
@@ -189,6 +295,18 @@ void nv3_pgraph_write(uint32_t address, uint32_t value)
{
switch (reg->address)
{
case NV3_PGRAPH_DEBUG_0:
nv3->pgraph.debug_0 = value;
break;
case NV3_PGRAPH_DEBUG_1:
nv3->pgraph.debug_1 = value;
break;
case NV3_PGRAPH_DEBUG_2:
nv3->pgraph.debug_2 = value;
break;
case NV3_PGRAPH_DEBUG_3:
nv3->pgraph.debug_3 = value;
break;
//interrupt status and enable regs
case NV3_PGRAPH_INTR_0:
nv3->pgraph.interrupt_status_0 &= ~value;
@@ -210,6 +328,101 @@ void nv3_pgraph_write(uint32_t address, uint32_t value)
nv3->pgraph.interrupt_enable_1 = value & 0x00011111;
nv3_pmc_handle_interrupts(true);
break;
// A lot of this is currently a temporary implementation so that we can just debug what the current state looks like
// during the driver initialisation process
// In the future, these will most likely have their own functions...
// Context Swithcing (THIS IS CONTROLLED BY PFIFO!)
case NV3_PGRAPH_CONTEXT_SWITCH:
nv3->pgraph.context_switch = value;
break;
case NV3_PGRAPH_CONTEXT_CONTROL:
*(uint32_t*)&nv3->pgraph.context_control = value;
break;
case NV3_PGRAPH_CONTEXT_USER:
*(uint32_t*)&nv3->pgraph.context_user = value;
break;
// Clip
case NV3_PGRAPH_ABS_UCLIP_XMIN:
nv3->pgraph.abs_uclip_xmin = value;
break;
case NV3_PGRAPH_ABS_UCLIP_XMAX:
nv3->pgraph.abs_uclip_xmax = value;
break;
case NV3_PGRAPH_ABS_UCLIP_YMIN:
nv3->pgraph.abs_uclip_ymin = value;
break;
case NV3_PGRAPH_ABS_UCLIP_YMAX:
nv3->pgraph.abs_uclip_ymax = value;
break;
// Canvas
case NV3_PGRAPH_SRC_CANVAS_MIN:
*(uint32_t*)&nv3->pgraph.src_canvas_min = value;
break;
case NV3_PGRAPH_SRC_CANVAS_MAX:
*(uint32_t*)&nv3->pgraph.src_canvas_max = value;
break;
// Pattern
case NV3_PGRAPH_PATTERN_COLOR_0_0:
*(uint32_t*)&nv3->pgraph.pattern_color_0_0 = value;
break;
case NV3_PGRAPH_PATTERN_COLOR_0_1:
*(uint32_t*)&nv3->pgraph.pattern_color_0_1 = value;
break;
case NV3_PGRAPH_PATTERN_COLOR_1_0:
*(uint32_t*)&nv3->pgraph.pattern_color_1_0 = value;
break;
case NV3_PGRAPH_PATTERN_COLOR_1_1:
*(uint32_t*)&nv3->pgraph.pattern_color_1_1 = value;
break;
case NV3_PGRAPH_PATTERN_BITMAP_HIGH:
nv3->pgraph.pattern_bitmap_high = value;
break;
case NV3_PGRAPH_PATTERN_BITMAP_LOW:
nv3->pgraph.pattern_bitmap_low = value;
break;
// Beta factor
case NV3_PGRAPH_BETA:
nv3->pgraph.beta_factor = value;
break;
// DMA
case NV3_PGRAPH_DMA:
*(uint32_t*)&nv3->pgraph.dma_settings = value;
break;
case NV3_PGRAPH_NOTIFY:
*(uint32_t*)&nv3->pgraph.notifier = value;
break;
// More clip
case NV3_PGRAPH_CLIP0_MIN:
*(uint32_t*)&nv3->pgraph.clip0_min = value;
break;
case NV3_PGRAPH_CLIP0_MAX:
*(uint32_t*)&nv3->pgraph.clip0_max = value;
break;
case NV3_PGRAPH_CLIP1_MIN:
*(uint32_t*)&nv3->pgraph.clip1_min = value;
break;
case NV3_PGRAPH_CLIP1_MAX:
*(uint32_t*)&nv3->pgraph.clip1_max = value;
break;
case NV3_PGRAPH_CLIP_MISC:
*(uint32_t*)&nv3->pgraph.clip_misc_settings = value;
break;
// Overall Status
case NV3_PGRAPH_STATUS:
*(uint32_t*)&nv3->pgraph.status = value;
break;
// Trapped Address
case NV3_PGRAPH_TRAPPED_ADDRESS:
nv3->pgraph.trapped_address = value;
break;
case NV3_PGRAPH_TRAPPED_DATA:
nv3->pgraph.trapped_data = value;
break;
case NV3_PGRAPH_TRAPPED_INSTANCE:
nv3->pgraph.trapped_instance = value;
break;
}
}

View File

@@ -6,7 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* NV3 PFIFO RAMFC area: Stores context unused DMA channels
* NV3 PFIFO RAMFC area: Stores context for unused DMA channels
*
*
*
@@ -30,10 +30,10 @@
uint32_t nv3_ramfc_read(uint32_t address)
{
nv_log("NV3: RAMFC (Unused DMA channel context) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address);
nv_log("NV3: RAMFC (Unused DMA channel context) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00\n", 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);
nv_log("NV3: RAMFC (Unused DMA channel context) Write (0x%04x -> 0x%04x), UNIMPLEMENTED\n", value, address);
}

View File

@@ -35,17 +35,17 @@ It is used to get the offset within RAMHT of a graphics object.
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);
nv_log("NV3: Generating RAMHT hash (RAMHT slot=0x%04x (from name 0x%08x for DMA channel 0x%04x)\n)\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);
nv_log("NV3: RAMHT (Graphics object storage hashtable) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00\n", 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);
nv_log("NV3: RAMHT (Graphics object storage hashtable) Write (0x%04x -> 0x%04x), UNIMPLEMENTED\n", value, address);
}

View File

@@ -30,10 +30,10 @@
uint32_t nv3_ramro_read(uint32_t address)
{
nv_log("NV3: RAM Runout (invalid dma object submission) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address);
nv_log("NV3: RAM Runout (invalid dma object submission) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00\n", 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);
nv_log("NV3: RAM Runout WRITE, OH CRAP!!!! (0x%04x -> 0x%04x), UNIMPLEMENTED\n (Todo: Read the entries...)\n", value, address);
}