diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 2df06a68d..0b4813cd1 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -254,6 +254,8 @@ extern const device_config_t nv3_config[]; #define NV3_PFIFO_RUNOUT_GET 0x2420 #define NV3_PFIFO_RUNOUT_GET_ADDRESS 3 // 13:3 +#define NV3_PFIFO_RUNOUT_RAMIN_ERR 28 + #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 @@ -589,6 +591,8 @@ extern const device_config_t nv3_config[]; // easier name #define NV3_OBJECT_SUBMIT_START NV3_USER_START +#define NV3_OBJECT_SUBMIT_SUBCHANNEL 13 +#define NV3_OBJECT_SUBMIT_CHANNEL 16 #define NV3_OBJECT_SUBMIT_END NV3_USER_END // also PDFB (Debug Framebuffer?) @@ -850,12 +854,8 @@ typedef struct nv3_pfifo_s nv3_pfifo_cache_entry_t cache0_entry; // It only has 1 entry nv3_pfifo_cache_entry_t cache1_entries[NV3_PFIFO_CACHE1_SIZE_MAX]; // ONLY 32 USED ON REVISION A/B CARDS - - } nv3_pfifo_t; -// create_object(uint32_t type) here - // RAMDAC typedef struct nv3_pramdac_s { @@ -1328,7 +1328,7 @@ void nv3_pfifo_interrupt(uint32_t id, bool fire_now); // NV3 PFIFO - Caches void nv3_pfifo_cache0_push(); void nv3_pfifo_cache0_pull(); -void nv3_pfifo_cache1_push(); +void nv3_pfifo_cache1_push(uint32_t addr, uint32_t val); void nv3_pfifo_cache1_pull(); uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val); uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val); diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 2135213fb..2a90957b2 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -31,8 +31,13 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c vid_bochs_vbe.c + nv/nv_base.c nv/nv_rivatimer.c - nv/nv3/nv3_core.c nv/nv3/nv3_core_config.c nv/nv3/nv3_core_arbiter.c + + nv/nv3/nv3_core.c + nv/nv3/nv3_core_config.c + nv/nv3/nv3_core_arbiter.c + nv/nv3/subsystems/nv3_pramdac.c nv/nv3/subsystems/nv3_pfifo.c nv/nv3/subsystems/nv3_pgraph.c @@ -44,8 +49,10 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c nv/nv3/subsystems/nv3_ptimer.c nv/nv3/subsystems/nv3_pramin.c nv/nv3/subsystems/nv3_pramin_ramht.c nv/nv3/subsystems/nv3_pramin_ramfc.c nv/nv3/subsystems/nv3_pramin_ramro.c nv/nv3/subsystems/nv3_pvideo.c + nv/nv3/subsystems/nv3_user.c nv/nv3/classes/nv3_class_names.c + nv/nv3/classes/nv3_class_shared_methods.c nv/nv3/classes/nv3_class_001_beta_factor.c nv/nv3/classes/nv3_class_002_rop.c nv/nv3/classes/nv3_class_003_chroma_key.c diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index 2022625fd..e10382feb 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -200,5 +200,3 @@ void nv3_prmcio_write(uint32_t address, uint32_t value) {}; uint32_t nv3_vram_read(uint32_t address) { return 0; }; void nv3_vram_write(uint32_t address, uint32_t value) {}; -uint32_t nv3_user_read(uint32_t address) { return 0; }; -void nv3_user_write(uint32_t address, uint32_t value) {}; \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c index f399b919d..1d9543fd9 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfifo.c +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -462,11 +462,13 @@ uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val) return val; } +// Submits graphics objects INTO cache0 void nv3_pfifo_cache0_push() { - + } +// Pulls graphics objects OUT of cache0 void nv3_pfifo_cache0_pull() { // Do nothing if PFIFO CACHE0 is disabled @@ -511,11 +513,98 @@ void nv3_pfifo_cache0_pull() } -void nv3_pfifo_cache1_push() +void nv3_pfifo_context_switch(uint32_t new_channel) { - + /* Send our contexts to RAMFC. Load the new ones from RAMFC. */ } +// NV_USER writes go here! +// Pushes graphics objects into cache1 +void nv3_pfifo_cache1_push(uint32_t addr, uint32_t val) +{ + bool oh_shit = false; // RAMRO needed + nv3_ramin_ramro_reason oh_shit_reason = 0x00; // It's all good for now + + // bit 23 of a ramin dword means it's a write... + uint32_t new_address = 0; + + uint32_t method_offset = (addr & 0x1FFC); // size of dma object is 0x2000 and some universal methods are implemented at this point, like free + + // Up to 128 per envytools? + uint32_t channel = (addr >> NV3_OBJECT_SUBMIT_CHANNEL) & 0x7F; + uint32_t subchannel = (addr >> NV3_OBJECT_SUBMIT_SUBCHANNEL) & 0x07; + + // first make sure there is even any cache available + if (!nv3->pfifo.cache1_settings.access_enabled) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_no_cache_available; + } + + // Check if runout is full + if (nv3->pfifo.runout_get != nv3->pfifo.runout_put) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_cache_ran_out; // ? really ? I guess this means we already ran out.. + new_address |= (nv3_runout_reason_cache_ran_out << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + + if (!nv3_pfifo_cache1_is_free()) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_free_count_overrun; + new_address |= (nv3_runout_reason_free_count_overrun << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + + if (method_offset > 0 && method_offset <= 0x100) + { + // Reserved NVIDIA Objects + oh_shit = true; + oh_shit_reason = nv3_runout_reason_reserved_access; + new_address |= (nv3_runout_reason_free_count_overrun << NV3_PFIFO_RUNOUT_RAMIN_ERR); + + } + + // Now check for context switching + + if (channel != nv3->pfifo.cache1_settings.channel) + { + if (!nv3->pfifo.cache_reassignment + || (nv3->pfifo.cache0_settings.get_address != nv3->pfifo.cache0_settings.get_address)) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_no_cache_available; + new_address |= (nv3_runout_reason_no_cache_available << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + } + + // Did we fuck up? + if (oh_shit) + { + nv_log("NV3: WE ARE FUCKED Runout Error=%d Channel=%d Subchannel=%d Method=0x%04x IMPLEMENT THIS OR DIE!!!", oh_shit_reason, channel, subchannel, method_offset); + return; + } + + // We didn't. Let's put it in CACHE1 + uint32_t current_put_address = nv3->pfifo.cache1_settings.put_address >> 2; + nv3->pfifo.cache1_entries[current_put_address].subchannel = subchannel; + nv3->pfifo.cache1_entries[current_put_address].method = method_offset; + nv3->pfifo.cache1_entries[current_put_address].data = val; + + // now we have to recalculate the cache1 put address + uint32_t next_put_address = nv3_pfifo_cache1_gray2normal(current_put_address); + + if (nv3->nvbase.gpu_revision >= NV3_BOOT_REG_REV_C00) // RIVA 128ZX# + next_put_address &= NV3_PFIFO_CACHE1_SIZE_REV_C; + else + next_put_address &= NV3_PFIFO_CACHE1_SIZE_REV_AB; + + nv3->pfifo.cache1_settings.put_address = nv3_pfifo_cache1_normal2gray(next_put_address); + + // Now we're done. Phew! +} + +// Pulls graphics objects OUT of cache1 void nv3_pfifo_cache1_pull() { // Do nothing if PFIFO CACHE1 is disabled diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c index b7d8f4f57..a206343c9 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c @@ -36,4 +36,9 @@ uint32_t nv3_ramro_read(uint32_t 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...)\n", value, address); +} + +void nv3_ramro_send() +{ + } \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_user.c b/src/video/nv/nv3/subsystems/nv3_user.c new file mode 100644 index 000000000..eee994208 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_user.c @@ -0,0 +1,47 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * NV3 User Submission Area (NV_USER, conceptually considered "Cache1 Pusher") + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86Box/86box.h> +#include <86Box/device.h> +#include <86Box/mem.h> +#include <86box/pci.h> +#include <86Box/rom.h> // DEPENDENT!!! +#include <86Box/video.h> +#include <86Box/nv/vid_nv.h> +#include <86Box/nv/vid_nv3.h> + +// 128 channels conceptually supported - a hangover from nv1 where multiple windows all directly programming the gpu were supported? total lunacy. +uint32_t nv3_user_read(uint32_t address) +{ + uint8_t method_offset = (address & 0x1FFC); + + nv_log("NV3: User Submission Area method_offset=0x%04x OH SHIT!! NOT IMPLEMENTED!!!", method_offset); + + // 0x10 is free CACHE1 object, other stuff? + return 0x00; +}; + +// Although NV3 doesn't have DMA mode unlike NV4 and later, it's conceptually similar to a "pusher" that pushes graphics commands that you write into CACHE1 that are then pulled out. +// So we send the writes here. This might do other stuff, so we keep this function +void nv3_user_write(uint32_t address, uint32_t value) +{ + nv3_pfifo_cache1_push(address, value); +} \ No newline at end of file