NV_USER and the other half of submitting (to cache1)

This commit is contained in:
starfrost013
2025-02-01 23:43:00 +00:00
parent 7909c5e1b9
commit 5ebc5f5505
6 changed files with 157 additions and 11 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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) {};

View File

@@ -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

View File

@@ -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()
{
}

View File

@@ -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, <mario64crashed@gmail.com> I need a better email address ;^)
*
* Copyright 2024-2025 starfrost
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#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);
}