Move notifications to DMA code

This commit is contained in:
starfrost013
2025-08-12 22:07:19 +01:00
parent d470c90679
commit 0e439cf0ae
5 changed files with 155 additions and 120 deletions

View File

@@ -36,8 +36,7 @@
"name": "debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"NV_LOG": "ON",
"NV_LOG_ULTRA": "ON"
"NV_LOG": "ON"
},
"inherits": "base"
},

View File

@@ -75,7 +75,7 @@ extern const device_config_t nv3t_config[]; // Confi
#define NV3T_VBIOS_ASUS_V170 "roms/video/nvidia/nv3/A170D03T.rom" // ASUS AGP-V3000 ZXTV BIOS - V1.70D.03 (C) 1996-98 Nvidia Corporation
#define NV3T_VBIOS_REFERENCE_CEK_V171 "roms/video/nvidia/nv3/BIOS_49_Riva 128" // Reference BIOS: RIVA 128 ZX BIOS - V1.71B-N (C) 1996-98 NVidia Corporation
#define NV3T_VBIOS_REFERENCE_CEK_V172 "roms/video/nvidia/nv3/vgasgram.rom" // Reference(?) BIOS: RIVA 128 ZX BIOS - V1.72B (C) 1996-98 NVidia Corporation
#
// The default VBIOS to use
#define NV3_VBIOS_DEFAULT NV3_VBIOS_ERAZOR_V15403

View File

@@ -65,118 +65,3 @@ void nv3_generic_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t
return;
}
}
/* 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)
return;
uint32_t current_notification_object = nv3->pgraph.notifier;
uint32_t notification_type = ((current_notification_object >> NV3_PGRAPH_NOTIFY_REQUEST_TYPE) & 0x07);
// check for a software method (0 = hardware, 1 = software)
if (notification_type != 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;
notify.status = NV3_NOTIFICATION_STATUS_DONE_OK; // it should be fine to just signal that it's ok
// these are only nonzero when there is an error
notify.info32 = notify.info16 = 0;
// notify object base=grobj_1 >> 12
uint32_t notify_obj_base = grobj.grobj_1 >> 12;
uint32_t notify_obj_info = nv3_ramin_read32(notify_obj_base, nv3);
uint32_t notify_obj_limit = nv3_ramin_read32(notify_obj_base + 0x04, nv3);
uint32_t notify_obj_page = nv3_ramin_read32(notify_obj_base + 0x08, nv3);
/* extract some important information*/
uint32_t info_adjust = notify_obj_info & 0xFFF;
bool info_pt_present = (notify_obj_info >> NV3_NOTIFICATION_PT_PRESENT) & 0x01;
uint8_t info_notification_target = (notify_obj_info >> NV3_NOTIFICATION_TARGET) & 0x03;
/* paging information */
bool page_is_present = notify_obj_page & 0x01;
bool page_is_readwrite = (notify_obj_page >> NV3_NOTIFICATION_PAGE_ACCESS);
uint32_t frame_base = notify_obj_page & 0xFFFFF000;
// This code is temporary and will probably be moved somewhere else
// Print torns of debug info
#ifdef DEBUG
nv_log_verbose_only("******* WARNING: IF THIS OPERATION FUCKS UP, RANDOM MEMORY WILL BE CORRUPTED, YOUR ENTIRE SYSTEM MAY BE HOSED *******\n");
nv_log_verbose_only("Notification Information:\n");
nv_log_verbose_only("Adjust Value: 0x%08x\n", info_adjust);
(info_pt_present) ? nv_log_verbose_only("Pagetable Present: True\n") : nv_log_verbose_only("Pagetable Present: False\n");
switch (info_notification_target)
{
case NV3_NOTIFICATION_TARGET_NVM:
nv_log_verbose_only("Notification Target: VRAM\n");
break;
case NV3_NOTIFICATION_TARGET_CART:
nv_log_verbose_only("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_verbose_only("Notification Target: PCI Bus\n") : nv_log_verbose_only("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_verbose_only("Notification Target: AGP Bus\n") : nv_log_verbose_only("Notification Target: AGP Bus (On PCI card?)\n");
break;
}
nv_log_verbose_only("Limit: 0x%08x\n", notify_obj_limit);
(page_is_present) ? nv_log_verbose_only("Page is present\n") : nv_log_verbose_only("Page is not present\n");
(page_is_readwrite) ? nv_log_verbose_only("Page is read-write\n") : nv_log_verbose_only("Page is read-only\n");
nv_log_verbose_only("Pageframe Address: 0x%08x\n", frame_base);
#endif
// set up the dma transfer. we need to translate to a physical address.
uint32_t final_address = 0;
/* Simple case: hardware notification, we can just take the pte since it's based on the type */
if (notification_type == 0)
{
final_address = frame_base + info_adjust;
}
else
{
// for software we have to calculate the pte index
uint32_t pte_num = ((notification_type << 4) + info_adjust) >> 12;
/* ramin entries are sorted - 1 object for each pte entry...*/
final_address = nv3_ramin_read32(notify_obj_base + (0x10 * pte_num) + 8, nv3);
final_address += (info_adjust & 0xFFF);
}
/* send the notification off */
nv_log("About to send hardware notification to 0x%08x (Check target)\n", final_address);
switch (info_notification_target)
{
case NV3_NOTIFICATION_TARGET_NVM:
svga_writel_linear(final_address, (notify.nanoseconds & 0xFFFFFFFF), &nv3->nvbase.svga);
svga_writel_linear(final_address + 4, (notify.nanoseconds >> 32), &nv3->nvbase.svga);
svga_writel_linear(final_address + 8, notify.info32, &nv3->nvbase.svga);
svga_writel_linear(final_address + 0x0C, (notify.info16 | notify.status), &nv3->nvbase.svga);
break;
case NV3_NOTIFICATION_TARGET_PCI:
case NV3_NOTIFICATION_TARGET_AGP:
dma_bm_write(final_address, (uint8_t*)&notify, sizeof(nv3_notification_t), 4);
break;
}
// we're done
nv3->pgraph.notify_pending = false;
}

View File

@@ -315,7 +315,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv)
ret = (NV_PCI_DEVICE_NV3 & 0xFF);
break;
case NV3_PCI_CFG_DEVICE_ID+1:
case NV3_PCI_CFG_DEVICE_ID + 1:
ret = (NV_PCI_DEVICE_NV3 >> 8);
break;

View File

@@ -30,7 +30,158 @@
/* Nvidia DMA Engine */
void nv3_dma_translate_address(void)
void nv3_perform_dma_m2mf(nv3_grobj_t grobj)
{
switch (method_id)
{
/* mthdCreate in software(?)*/
case NV3_ROOT_HI_IM_OBJECT_MCOBJECTYFACE:
//nv_log("mthdCreate obj_name=0x%08x\n", param);
nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING);
break;
// set up the current notification request/object
// and 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_SOFTWARE_METHOD_PENDING);
return;
}
}
/* 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)
return;
uint32_t current_notification_object = nv3->pgraph.notifier;
uint32_t notification_type = ((current_notification_object >> NV3_PGRAPH_NOTIFY_REQUEST_TYPE) & 0x07);
// check for a software method (0 = hardware, 1 = software)
if (notification_type != 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;
notify.status = NV3_NOTIFICATION_STATUS_DONE_OK; // it should be fine to just signal that it's ok
// these are only nonzero when there is an error
notify.info32 = notify.info16 = 0;
// notify object base=grobj_1 >> 12
uint32_t notify_obj_base = grobj.grobj_1 >> 12;
uint32_t notify_obj_info = nv3_ramin_read32(notify_obj_base, nv3);
uint32_t notify_obj_limit = nv3_ramin_read32(notify_obj_base + 0x04, nv3);
uint32_t notify_obj_page = nv3_ramin_read32(notify_obj_base + 0x08, nv3);
/* extract some important information*/
uint32_t info_adjust = notify_obj_info & 0xFFF;
bool info_pt_present = (notify_obj_info >> NV3_NOTIFICATION_PT_PRESENT) & 0x01;
uint8_t info_notification_target = (notify_obj_info >> NV3_NOTIFICATION_TARGET) & 0x03;
/* paging information */
bool page_is_present = notify_obj_page & 0x01;
bool page_is_readwrite = (notify_obj_page >> NV3_NOTIFICATION_PAGE_ACCESS);
uint32_t frame_base = notify_obj_page & 0xFFFFF000;
// This code is temporary and will probably be moved somewhere else
// Print torns of debug info
#ifdef DEBUG
nv_log_verbose_only("******* WARNING: IF THIS OPERATION FUCKS UP, RANDOM MEMORY WILL BE CORRUPTED, YOUR ENTIRE SYSTEM MAY BE HOSED *******\n");
nv_log_verbose_only("Notification Information:\n");
nv_log_verbose_only("Adjust Value: 0x%08x\n", info_adjust);
(info_pt_present) ? nv_log_verbose_only("Pagetable Present: True\n") : nv_log_verbose_only("Pagetable Present: False\n");
switch (info_notification_target)
{
case NV3_NOTIFICATION_TARGET_NVM:
nv_log_verbose_only("Notification Target: VRAM\n");
break;
case NV3_NOTIFICATION_TARGET_CART:
nv_log_verbose_only("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_verbose_only("Notification Target: PCI Bus\n") : nv_log_verbose_only("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_verbose_only("Notification Target: AGP Bus\n") : nv_log_verbose_only("Notification Target: AGP Bus (On PCI card?)\n");
break;
}
nv_log_verbose_only("Limit: 0x%08x\n", notify_obj_limit);
(page_is_present) ? nv_log_verbose_only("Page is present\n") : nv_log_verbose_only("Page is not present\n");
(page_is_readwrite) ? nv_log_verbose_only("Page is read-write\n") : nv_log_verbose_only("Page is read-only\n");
nv_log_verbose_only("Pageframe Address: 0x%08x\n", frame_base);
#endif
// set up the dma transfer. we need to translate to a physical address.
uint32_t final_address = 0;
/* Simple case: hardware notification, we can just take the pte since it's based on the type */
if (notification_type == 0)
{
final_address = frame_base + info_adjust;
}
else
{
// for software we have to calculate the pte index
uint32_t pte_num = ((notification_type << 4) + info_adjust) >> 12;
/* ramin entries are sorted - 1 object for each pte entry...*/
final_address = nv3_ramin_read32(notify_obj_base + (0x10 * pte_num) + 8, nv3);
final_address += (info_adjust & 0xFFF);
}
/* send the notification off */
nv_log("About to send hardware notification to 0x%08x (Check target)\n", final_address);
switch (info_notification_target)
{
case NV3_NOTIFICATION_TARGET_NVM:
uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram;
// increment by 1 because each index increments by 4
vram_32[final_address] = (notify.nanoseconds & 0xFFFFFFFF);
vram_32[final_address + 1] = (notify.nanoseconds >> 32);
vram_32[final_address + 2] = notify.info32;
vram_32[final_address + 3] = (notify.info16 | notify.status);
break;
case NV3_NOTIFICATION_TARGET_PCI:
case NV3_NOTIFICATION_TARGET_AGP:
dma_bm_write(final_address, (uint8_t*)&notify, sizeof(nv3_notification_t), 4);
break;
}
// we're done
nv3->pgraph.notify_pending = false;
}