diff --git a/src/include/86box/nv/classes/vid_nv3_classes.h b/src/include/86box/nv/classes/vid_nv3_classes.h index 15f4d37f1..5106e5bff 100644 --- a/src/include/86box/nv/classes/vid_nv3_classes.h +++ b/src/include/86box/nv/classes/vid_nv3_classes.h @@ -124,12 +124,8 @@ typedef enum nv3_pgraph_class_e #define NV3_M2MF_FORMAT 0x0324 // M2MF formats (IN and OUT ORed together) -#define NV3_M2MF_FORMAT_INPUT_INC_1 0x1 -#define NV3_M2MF_FORMAT_INPUT_INC_2 0x2 -#define NV3_M2MF_FORMAT_INPUT_INC_4 0x4 -#define NV3_M2MF_FORMAT_OUTPUT_INC_1 0x100 -#define NV3_M2MF_FORMAT_OUTPUT_INC_2 0x200 -#define NV3_M2MF_FORMAT_OUTPUT_INC_4 0x400 +#define NV3_M2MF_FORMAT_INPUT 0 +#define NV3_M2MF_FORMAT_OUTPUT 8 #define NV3_M2MF_NOTIFY 0x0328 @@ -596,8 +592,8 @@ typedef struct nv3_object_class_00D uint32_t offset_out; uint32_t pitch_in; uint32_t pitch_out; - uint32_t line_length_in; // Stride? - uint32_t line_count; + uint32_t scanline_length; // Stride? + uint32_t num_scanlines; uint8_t format; // input increment 1 2 or 4, output increment 1 2 or 4 (represented by << 8) uint32_t buffer_notify; // Notify the Buffedr } nv3_memory_to_memory_format_t; diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index e0b28edd0..cca3761be 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -58,4 +58,7 @@ void nv3_render_blit_screen2screen(nv3_grobj_t grobj); /* GDI */ void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitmap_data, nv3_grobj_t grobj); -void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj); /* GDI Type-E: Clipped 1bpp colour-expanded bitmap */ \ No newline at end of file +void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj); /* GDI Type-E: Clipped 1bpp colour-expanded bitmap */ + +/* DMA */ +void nv3_perform_dma_m2mf(nv3_grobj_t grobj); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 05281a5ac..b954355bb 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -1054,10 +1054,10 @@ typedef struct nv3_pfb_s #define NV3_NOTIFICATION_INFO_ADJUST 0 // Wut #define NV3_NOTIFICATION_PT_PRESENT 16 // Determines if the pagetable exists. #define NV3_NOTIFICATION_TARGET 24 // Determines where this notification goes -#define NV3_NOTIFICATION_TARGET_NVM 0 // VRAM target for DMA -#define NV3_NOTIFICATION_TARGET_CART 1 // "Cartridge" target for dma, only mentioned in a few places, !!! NV2 LEFTOVER !!! -#define NV3_NOTIFICATION_TARGET_PCI 2 // Send the data to the host system over PCI -#define NV3_NOTIFICATION_TARGET_AGP 3 // Send the data to the host system over AGP +#define NV3_DMA_TARGET_NODE_VRAM 0 // VRAM target for DMA +#define NV3_DMA_TARGET_NODE_CART 1 // "Cartridge" target for dma, only mentioned in a few places, !!! NV2 LEFTOVER !!! +#define NV3_DMA_TARGET_NODE_PCI 2 // Send the data to the host system over PCI +#define NV3_DMA_TARGET_NODE_AGP 3 // Send the data to the host system over AGP #define NV3_NOTIFICATION_PAGE_IS_PRESENT 0 // Determines if the page really exists #define NV3_NOTIFICATION_PAGE_ACCESS 1 // Determines the page access type diff --git a/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c b/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c index 4a6d2e39c..f07aab737 100644 --- a/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c +++ b/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c @@ -49,16 +49,21 @@ void nv3_class_00d_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv_log("Method Execution: M2MF Pitch Out = 0x%08x", param); break; case NV3_M2MF_SCANLINE_LENGTH_IN_BYTES: - nv3->pgraph.m2mf.line_length_in = param; + nv3->pgraph.m2mf.scanline_length = param; nv_log("Method Execution: M2MF Scanline Length in Bytes = 0x%08x", param); break; case NV3_M2MF_NUM_SCANLINES: - nv3->pgraph.m2mf.line_count = param; + nv3->pgraph.m2mf.num_scanlines = param; nv_log("Method Execution: M2MF Num Scanlines = 0x%08x", param); break; case NV3_M2MF_FORMAT: nv3->pgraph.m2mf.format = param; nv_log("Method Execution: M2MF Format = 0x%08x", param); + + // Format Done - start m2mf + + nv3_perform_dma_m2mf(grobj); + break; case NV3_M2MF_NOTIFY: /* This is technically its own thing, but I don't know if it's ever a problem with how we've designed it */ diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c index db7bdb06d..c40fa84a9 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -803,7 +803,7 @@ uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop) uint32_t patch_config_rop = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG) & 0x1F; /* || patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0*/ - + // TODO: Blending if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS) // 0x00 is used for "nothing here" it seems. return VIDEO_ROP_SRC_COPY; @@ -864,28 +864,6 @@ uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop) res |= 1 << i; } } + return res; - - /* - uint32_t patch_config = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG) & 0x1F; - - // Wtf do these even do? - switch (patch_config) - { - // don't do anything - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD1: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD2: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD0: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD1: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD2: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD3: - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD4: - return src; - case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST: // S2SB - break; - - } - */ } \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c index 49c844404..3359e9079 100644 --- a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c +++ b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c @@ -21,6 +21,7 @@ #include #include <86box/86box.h> #include <86box/device.h> +#include <86box/dma.h> #include <86box/mem.h> #include <86box/pci.h> #include <86box/rom.h> // DEPENDENT!!! @@ -31,40 +32,126 @@ /* Nvidia DMA Engine */ void nv3_perform_dma_m2mf(nv3_grobj_t grobj) -{ - switch (method_id) +{ + // 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_dma_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("M2MF DMA 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_dma_target) { - /* 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); + case NV3_DMA_TARGET_NODE_VRAM: + nv_log_verbose_only("Notification Target: VRAM\n"); break; - // set up the current notification request/object - // and check for double notifiers. - case NV3_SET_NOTIFY: - if (nv3->pgraph.notify_pending) + case NV3_DMA_TARGET_NODE_CART: + nv_log_verbose_only("VERY BAD WARNING: Notification detected with Notification Target: Cartridge. THIS SHOULD NEVER HAPPEN!!!!!\n"); + break; + case NV3_DMA_TARGET_NODE_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_DMA_TARGET_NODE_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; + + /* M2MF DMA only uses HW type */ + + final_address = frame_base + info_adjust; + + /* send the notification off */ + nv_log("About to send M2MF DMA to 0x%08x (Check target)\n", final_address); + + uint32_t offset_in = (nv3->pgraph.m2mf.offset_in); + uint32_t offset_out = (nv3->pgraph.m2mf.offset_out); + + uint32_t pitch_in = nv3->pgraph.m2mf.pitch_in; + uint32_t pitch_out = nv3->pgraph.m2mf.pitch_out; + + // pitch out surely can't be 0 + if (pitch_out == 0) + pitch_out = pitch_in; + + uint32_t bytes_per_scanline = nv3->pgraph.m2mf.scanline_length; + + uint8_t increment_in = (nv3->pgraph.m2mf.format) & 0x07; + uint8_t increment_out = (nv3->pgraph.m2mf.format >> NV3_M2MF_FORMAT_INPUT) & 0x07; + + for (uint32_t scanline = 0; scanline < nv3->pgraph.m2mf.num_scanlines; scanline++) + { + for (uint32_t pixel = offset_in; pixel < (offset_in + bytes_per_scanline); pixel += increment_in) + { + nv3->nvbase.svga.vram[offset_out] = nv3->nvbase.svga.vram[offset_in]; + offset_out += increment_out; + } + + offset_in += pitch_in; + offset_out += pitch_out; + } + + /* + switch (info_dma_target) + { + // for M2MF only NVM target node is used. + + case NV3_DMA_TARGET_NODE_VRAM: + + + uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; + + break; + case NV3_DMA_TARGET_NODE_PCI: + case NV3_DMA_TARGET_NODE_AGP: + // Idk how to implement increments of more than 1 but only 1 increments seem to be used with these. + uint32_t size_in = nv3->pgraph.m2mf.num_scanlines * nv3->pgraph.m2mf.pitch_in; + uint32_t size_out = nv3->pgraph.m2mf.num_scanlines * nv3->pgraph.m2mf.pitch_out; + + uint8_t* page_in = calloc(1, size_in); + + for (uint32_t scanline = 0; scanline < nv3->pgraph.m2mf.num_scanlines; scanline++) { - 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; + dma_bm_read(offset_in, page_in, size_in, size_in); + dma_bm_write(offset_out, page_in, size_out, size_out); + 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; } +*/ + // we're done + nv3->pgraph.notify_pending = false; } @@ -121,16 +208,16 @@ void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t switch (info_notification_target) { - case NV3_NOTIFICATION_TARGET_NVM: + case NV3_DMA_TARGET_NODE_VRAM: nv_log_verbose_only("Notification Target: VRAM\n"); break; - case NV3_NOTIFICATION_TARGET_CART: + case NV3_DMA_TARGET_NODE_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: + case NV3_DMA_TARGET_NODE_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: + case NV3_DMA_TARGET_NODE_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; @@ -166,7 +253,7 @@ void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t switch (info_notification_target) { - case NV3_NOTIFICATION_TARGET_NVM: + case NV3_DMA_TARGET_NODE_VRAM: uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; @@ -176,8 +263,8 @@ void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t 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: + case NV3_DMA_TARGET_NODE_PCI: + case NV3_DMA_TARGET_NODE_AGP: dma_bm_write(final_address, (uint8_t*)¬ify, sizeof(nv3_notification_t), 4); break; }