Implement generic method execution. Implement unknown register write code

This commit is contained in:
starfrost013
2025-03-20 00:40:29 +00:00
parent 1d54a3af6b
commit ac63ad436f
15 changed files with 181 additions and 102 deletions

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: 17 March 2025 (STILL WORKING ON IT!!!)
* Last updated: 20 March 2025 (STILL WORKING ON IT!!!)
*
* Authors: Connor Hyde <mario64crashed@gmail.com>
*
@@ -521,9 +521,11 @@ extern const device_config_t nv3_config[];
#define NV3_PGRAPH_DEBUG_3_FORMAT_CHECK 22
#define NV3_PGRAPH_DEBUG_3_ALPHA_CHECK 24
// Interrupt stuff
#define NV3_PGRAPH_INTR_0 0x400100
#define NV3_PGRAPH_INTR_0_VBLANK 8 // Fired every frame
#define NV3_PGRAPH_INTR_0_VBLANK_ENABLED 0x1 // Is the vblank interrupt enabled?
#define NV3_PGRAPH_INTR_0_SOFTWARE_NOTIFY 28 // Fired on software notification
#define NV3_PGRAPH_INTR_1 0x400104
#define NV3_PGRAPH_INTR_1_INVALID_METHOD 0 // Invalid method
@@ -578,7 +580,14 @@ extern const device_config_t nv3_config[];
#define NV3_PGRAPH_CHROMA_KEY 0x40062C
#define NV3_PGRAPH_BETA 0x400640 // Beta factor (30:23 fractional, 22:0 before fraction)
#define NV3_PGRAPH_DMA 0x400680
#define NV3_PGRAPH_NOTIFY 0x400684 // Notifier for PGRAPH
// Current notification object for pgraph
#define NV3_PGRAPH_NOTIFY 0x400684 // Notifier for PGRAPH
#define NV3_PGRAPH_NOTIFY_INSTANCE 0
#define NV3_PGRAPH_NOTIFY_REQUEST_PENDING 16
#define NV3_PGRAPH_NOTIFY_REQUEST_TYPE 20
#define NV3_PGRAPH_NOTIFY_REQUEST_TYPE_HARDWARE 0x0 // anything else is software
#define NV3_PGRAPH_CLIP0_MIN 0x400690 // Clip for Blitting 0 Min
#define NV3_PGRAPH_CLIP0_MAX 0x400694 // Clip for Blitting 0 Max
#define NV3_PGRAPH_CLIP1_MIN 0x400698 // Clip for Blitting 1 Min
@@ -882,11 +891,6 @@ typedef struct nv3_pci_config_s
uint8_t int_line;
} nv3_pci_config_t;
/* Notifier Engine */
typedef struct nv3_notifier_s
{
/* TODO */
} nv3_notifier_t;
// add enums for eac
// Chip configuration
@@ -1187,7 +1191,7 @@ typedef struct nv3_pgraph_s
uint32_t bpixel[NV3_PGRAPH_MAX_BUFFERS]; // Pixel format for each possible surfaces.
// CLIP
nv3_pgraph_clip_misc_settings_t clip_misc_settings;
nv3_notifier_t notifier;
uint32_t notifier;
bool notify_pending; // Determines if a notification is pending.
nv3_position_16_bigy_t clip0_min;
nv3_position_16_bigy_t clip0_max;

View File

@@ -1525,7 +1525,7 @@ emu8k_outw(uint16_t addr, uint16_t val, void *priv)
default:
break;
}
emu8k_log("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice,
emu8k_log("EMU8K WRITE: : Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice,
emu8k->cur_reg, emu8k->cur_voice, val);
}

View File

@@ -798,7 +798,7 @@ sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *priv)
break;
default:
sb_log("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
sb_log("sb_ct1335: : Unknown register write: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
break;
}
}
@@ -899,7 +899,7 @@ sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *priv)
break;
default:
sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
sb_log("sb_ct1345: : Unknown register write: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
break;
}
}

View File

@@ -29,10 +29,31 @@
#include <86box/nv/vid_nv.h>
#include <86box/nv/vid_nv3.h>
void nv3_generic_method(uint32_t name, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj)
void nv3_generic_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj)
{
switch (method_id)
{
// set up the current notification request/object]
// check for double notifiers.
case NV3_SET_NOTIFY:
if (nv3->pgraph.notify_pending)
{
nv_log("Executed method NV3_SET_NOTIFY with nv3->pgraph.notify_pending already set. param=0x%08x, method=0x%04x, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n");
nv_log("IF THIS IS A DEBUG BUILD, YOU SHOULD SEE A CONTEXT BELOW");
nv3_debug_ramin_print_context_info(param, context);
nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY);
// disable
nv3->pgraph.notify_pending = false;
nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY);
/* may need to disable fifo in this state */
return;
}
// set a notify as pending.
nv3->pgraph.notifier = param;
nv3->pgraph.notify_pending = true;
break;
default:
nv_log("Shared Generic Methods: Invalid or Unimplemented method 0x%04x", method_id);
nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_INVALID_METHOD);
@@ -44,18 +65,19 @@ void nv3_generic_method(uint32_t name, uint32_t method_id, nv3_ramin_context_t c
/* Sees if any notification is required after an object method is executed. If so, executes it... */
void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj)
{
if (nv3->pgraph.notify_pending)
{
nv_log("Called nv3_notify_if_needed with nv3->pgraph.notify_pending already set. name=0x%08x, method=0x%04x, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n");
nv_log("IF THIS IS A DEBUG BUILD, YOU SHOULD SEE A CONTEXT BELOW");
nv3_debug_ramin_print_context_info(name, context);
nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY);
// disable
nv3->pgraph.notify_pending = false;
if (!nv3->pgraph.notify_pending)
return;
}
uint32_t current_notification_object = nv3->pgraph.notifier;
// check for a software method (0 = hardware, 1 = software)
if (((current_notification_object >> NV3_PGRAPH_NOTIFY_REQUEST_TYPE) & 0x07) != 0)
{
nv_log("Software Notification, firing interrupt");
nv3_pgraph_interrupt_valid(NV3_PGRAPH_INTR_0_SOFTWARE_NOTIFY);
return;
}
// set up the NvNotification structure
nv3_notification_t notify = {0};
notify.nanoseconds = nv3->ptimer.time;
@@ -79,7 +101,8 @@ void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t
/* paging information */
bool page_is_present = notify_obj_page & 0x01;
bool page_is_readwrite = (notify_obj_page >> NV3_NOTIFICATION_PAGE_ACCESS);
uint32_t frame_value = (notify_obj_page >> NV3_NOTIFICATION_PAGE_FRAME_ADDRESS) & 0xFFFFF;
//uint32_t frame_value = (notify_obj_page >> NV3_NOTIFICATION_PAGE_FRAME_ADDRESS) & 0xFFFFF;
uint32_t frame_value = (notify_obj_page >> NV3_NOTIFICATION_PAGE_FRAME_ADDRESS) & 0xFFFFF000;
// This code is temporary and will probably be moved somewhere else
// Print torns of debug info
@@ -99,18 +122,18 @@ void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t
nv_log("VERY BAD WARNING: Notification detected with Notification Target: Cartridge. THIS SHOULD NEVER HAPPEN!!!!!\n");
break;
case NV3_NOTIFICATION_TARGET_PCI:
(nv3->nvbase.bus_generation == nv_bus_pci) ? nv_log("Notification Target: PCI Bus\n") : nv_log("Notification Target: PCI Bus (On AGP card???)\n");
(nv3->nvbase.bus_generation == nv_bus_pci) ? nv_log("Notification Target: PCI Bus\n") : nv_log("Notification Target: PCI Bus (On AGP card?)\n");
break;
case NV3_NOTIFICATION_TARGET_AGP:
(nv3->nvbase.bus_generation == nv_bus_agp_1x
|| nv3->nvbase.bus_generation == nv_bus_agp_2x) ? nv_log("Notification Target: AGP Bus\n") : nv_log("Notification Target: AGP Bus (On PCI card???)\n");
|| nv3->nvbase.bus_generation == nv_bus_agp_2x) ? nv_log("Notification Target: AGP Bus\n") : nv_log("Notification Target: AGP Bus (On PCI card?)\n");
break;
}
nv_log("Limit: 0x%08x", notify_obj_limit);
nv_log("Limit: 0x%08x\n", notify_obj_limit);
(page_is_present) ? nv_log("Page is present\n") : nv_log("Page is not present\n");
(page_is_readwrite) ? nv_log("Page is read-write\n") : nv_log("Page is read-only\n");
nv_log("Pageframe Address: 0x%08x", frame_value);
nv_log("Pageframe Address: 0x%08x\n", frame_value);
#endif
// set up the dma transfer. we need to translate to a physical address.

View File

@@ -122,6 +122,10 @@ void nv3_pbus_write(uint32_t address, uint32_t value)
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}
uint8_t nv3_pbus_rma_read(uint16_t addr)

View File

@@ -150,4 +150,8 @@ void nv3_pextdev_write(uint32_t address, uint32_t value)
if (reg->on_write)
reg->on_write(value);
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -152,6 +152,10 @@ void nv3_pfb_write(uint32_t address, uint32_t value)
}
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}
uint32_t nv3_pfb_config0_read()

View File

@@ -599,7 +599,6 @@ void nv3_pfifo_write(uint32_t address, uint32_t val)
nv3->pfifo.cache1_entries[real_entry].subchannel = (val >> NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL) & 0x07;
nv_log("Subchannel = 0x%08x, method = 0x%04x\n", nv3->pfifo.cache1_entries[real_entry].subchannel, nv3->pfifo.cache1_entries[real_entry].method);
}
}
/* Handle some special memory areas */
else if (address >= NV3_PFIFO_CACHE1_CTX_START && address <= NV3_PFIFO_CACHE1_CTX_END)
@@ -609,6 +608,10 @@ void nv3_pfifo_write(uint32_t address, uint32_t val)
nv_log("PFIFO Cache1 CTX Write Entry=%d value=0x%04x\n", ctx_entry_id, val);
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
/* Trigger DMA for notifications if we need to */
nv3_pfifo_trigger_dma_if_required();
@@ -620,6 +623,7 @@ 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
(Possibly it just makes it easier to implement in logic)
I decided to use a lookup table to save everyone's time, also the numbers generated from the function
that existed here before didn't make any sense

View File

@@ -472,6 +472,10 @@ void nv3_pgraph_write(uint32_t address, uint32_t value)
nv_log("PGRAPH Context Cache Write (Entry=%04x Value=0x%08x)\n", entry, value);
nv3->pgraph.context_cache[entry] = value;
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}
}
@@ -506,6 +510,7 @@ void nv3_pgraph_arbitrate_method(uint32_t param, uint16_t method, uint8_t channe
// we need to shift left by 4 to get the real address, something to do with the 16 byte unit of reversal
uint32_t real_ramin_base = context.ramin_offset << 4;
// readin our grobj
grobj.grobj_0 = nv3_ramin_read32(real_ramin_base, nv3);
grobj.grobj_1 = nv3_ramin_read32(real_ramin_base + 4, nv3);
grobj.grobj_2 = nv3_ramin_read32(real_ramin_base + 8, nv3);
@@ -514,80 +519,90 @@ void nv3_pgraph_arbitrate_method(uint32_t param, uint16_t method, uint8_t channe
nv_log("**** About to execute method **** method=0x%04x param=0x%08x, channel=%d.%d, class=%s, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n",
method, param, channel, subchannel, nv3_class_names[class_id], grobj.grobj_0, grobj.grobj_1, grobj.grobj_2, grobj.grobj_3);
// By this point, we already ANDed the class ID to 0x1F.
// Send the grobj, the context, the method and the name off to actually be acted upon.
switch (class_id)
/* Methods below 0x104 are shared across all classids, so call generic_method for that*/
if (method <= NV3_SET_NOTIFY)
{
case nv3_pgraph_class01_beta_factor:
nv3_class_001_method(param, method, context, grobj);
break;
case nv3_pgraph_class02_rop:
nv3_class_002_method(param, method, context, grobj);
break;
case nv3_pgraph_class03_chroma_key:
nv3_class_003_method(param, method, context, grobj);
break;
case nv3_pgraph_class04_plane_mask:
nv3_class_004_method(param, method, context, grobj);
break;
case nv3_pgraph_class05_clipping_rectangle:
nv3_class_005_method(param, method, context, grobj);
break;
case nv3_pgraph_class06_pattern:
nv3_class_006_method(param, method, context, grobj);
break;
case nv3_pgraph_class07_rectangle:
nv3_class_007_method(param, method, context, grobj);
break;
case nv3_pgraph_class08_point:
nv3_class_008_method(param, method, context, grobj);
break;
case nv3_pgraph_class09_line:
nv3_class_009_method(param, method, context, grobj);
break;
case nv3_pgraph_class0a_lin:
nv3_class_00a_method(param, method, context, grobj);
break;
case nv3_pgraph_class0b_triangle:
nv3_class_00b_method(param, method, context, grobj);
break;
case nv3_pgraph_class0c_w95txt:
nv3_class_00c_method(param, method, context, grobj);
break;
case nv3_pgraph_class0d_m2mf:
nv3_class_00d_method(param, method, context, grobj);
break;
case nv3_pgraph_class0e_scaled_image_from_memory:
nv3_class_00e_method(param, method, context, grobj);
break;
case nv3_pgraph_class10_blit:
nv3_class_010_method(param, method, context, grobj);
break;
case nv3_pgraph_class11_image:
nv3_class_011_method(param, method, context, grobj);
break;
case nv3_pgraph_class12_bitmap:
nv3_class_012_method(param, method, context, grobj);
break;
case nv3_pgraph_class14_transfer2memory:
nv3_class_014_method(param, method, context, grobj);
break;
case nv3_pgraph_class15_stretched_image_from_cpu:
nv3_class_015_method(param, method, context, grobj);
break;
case nv3_pgraph_class17_d3d5tri_zeta_buffer:
nv3_class_017_method(param, method, context, grobj);
break;
case nv3_pgraph_class18_point_zeta_buffer:
nv3_class_018_method(param, method, context, grobj);
break;
case nv3_pgraph_class1c_image_in_memory:
nv3_class_01c_method(param, method, context, grobj);
break;
default:
fatal("NV3 (nv3_pgraph_arbitrate_method): Attempted to execute method on invalid, or unimplemented, class ID %s", nv3_class_names[class_id]);
return;
nv3_generic_method(param, method, context, grobj);
}
else
{
// By this point, we already ANDed the class ID to 0x1F.
// Send the grobj, the context, the method and the name off to actually be acted upon.
switch (class_id)
{
case nv3_pgraph_class01_beta_factor:
nv3_class_001_method(param, method, context, grobj);
break;
case nv3_pgraph_class02_rop:
nv3_class_002_method(param, method, context, grobj);
break;
case nv3_pgraph_class03_chroma_key:
nv3_class_003_method(param, method, context, grobj);
break;
case nv3_pgraph_class04_plane_mask:
nv3_class_004_method(param, method, context, grobj);
break;
case nv3_pgraph_class05_clipping_rectangle:
nv3_class_005_method(param, method, context, grobj);
break;
case nv3_pgraph_class06_pattern:
nv3_class_006_method(param, method, context, grobj);
break;
case nv3_pgraph_class07_rectangle:
nv3_class_007_method(param, method, context, grobj);
break;
case nv3_pgraph_class08_point:
nv3_class_008_method(param, method, context, grobj);
break;
case nv3_pgraph_class09_line:
nv3_class_009_method(param, method, context, grobj);
break;
case nv3_pgraph_class0a_lin:
nv3_class_00a_method(param, method, context, grobj);
break;
case nv3_pgraph_class0b_triangle:
nv3_class_00b_method(param, method, context, grobj);
break;
case nv3_pgraph_class0c_w95txt:
nv3_class_00c_method(param, method, context, grobj);
break;
case nv3_pgraph_class0d_m2mf:
nv3_class_00d_method(param, method, context, grobj);
break;
case nv3_pgraph_class0e_scaled_image_from_memory:
nv3_class_00e_method(param, method, context, grobj);
break;
case nv3_pgraph_class10_blit:
nv3_class_010_method(param, method, context, grobj);
break;
case nv3_pgraph_class11_image:
nv3_class_011_method(param, method, context, grobj);
break;
case nv3_pgraph_class12_bitmap:
nv3_class_012_method(param, method, context, grobj);
break;
case nv3_pgraph_class14_transfer2memory:
nv3_class_014_method(param, method, context, grobj);
break;
case nv3_pgraph_class15_stretched_image_from_cpu:
nv3_class_015_method(param, method, context, grobj);
break;
case nv3_pgraph_class17_d3d5tri_zeta_buffer:
nv3_class_017_method(param, method, context, grobj);
break;
case nv3_pgraph_class18_point_zeta_buffer:
nv3_class_018_method(param, method, context, grobj);
break;
case nv3_pgraph_class1c_image_in_memory:
nv3_class_01c_method(param, method, context, grobj);
break;
default:
fatal("NV3 (nv3_pgraph_arbitrate_method): Attempted to execute method on invalid, or unimplemented, class ID %s", nv3_class_names[class_id]);
return;
}
}
nv3_notify_if_needed(param, method, context, grobj);
}

View File

@@ -269,4 +269,8 @@ void nv3_pmc_write(uint32_t address, uint32_t value)
nv_log("\n");
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -128,4 +128,9 @@ void nv3_pme_write(uint32_t address, uint32_t value)
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -377,4 +377,9 @@ void nv3_pramdac_write(uint32_t address, uint32_t value)
}
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -222,4 +222,8 @@ void nv3_ptimer_write(uint32_t address, uint32_t value)
}
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -152,5 +152,8 @@ void nv3_pvideo_write(uint32_t address, uint32_t value)
}
}
}
else /* Completely unknown */
{
nv_log(": Unknown register write (address=0x%08x)\n", address);
}
}

View File

@@ -676,7 +676,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv)
default:
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) {
voodoo_log("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val);
voodoo_log(": Unknown register write in CMDFIFO mode %08x %08x\n", addr, val);
} else {
voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
}