mirror of
https://github.com/86Box/86Box.git
synced 2026-02-23 09:58:19 -07:00
Nvidia NV3 initial implementation from the old repo when it was a fork.
This commit is contained in:
@@ -138,6 +138,11 @@ option(GDBSTUB "Enable GDB stub server for debugging"
|
||||
option(DEV_BRANCH "Development branch" OFF)
|
||||
option(DISCORD "Discord Rich Presence support" ON)
|
||||
option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs" OFF)
|
||||
option(NV_LOG "NVidia RIVA 128 debug logging" OFF)
|
||||
|
||||
if (NV_LOG)
|
||||
add_compile_definitions(ENABLE_NV_LOG)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(QT ON)
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"NV_LOG": "ON"
|
||||
},
|
||||
"inherits": "base"
|
||||
},
|
||||
@@ -65,7 +66,7 @@
|
||||
"NEW_DYNAREC": "ON",
|
||||
"QT": "ON",
|
||||
"USE_QT6": "OFF",
|
||||
"Qt5_DIR": "/opt/homebrew/opt/qt@5/lib/cmake/Qt5",
|
||||
"Qt5_DIR": "/opt/homebrew/opt/qt@5/lSib/cmake/Qt5",
|
||||
"MOLTENVK_DIR": "/opt/homebrew/opt/molten-vk",
|
||||
"Qt5LinguistTools_DIR": "/opt/homebrew/opt/qt@5/lib/cmake/Qt5LinguistTools",
|
||||
"OpenAL_ROOT": "/opt/homebrew/opt/openal-soft"
|
||||
|
||||
494
src/include/86box/nv/vid_nv.h
Normal file
494
src/include/86box/nv/vid_nv.h
Normal file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* JENSEN HUANG APPROVED !!!!
|
||||
*
|
||||
* Credit to:
|
||||
*
|
||||
* - fuel (PCBox developer)
|
||||
* - Marcelina Kościelnicka (envytools)
|
||||
* - nouveau developers
|
||||
* - Utah GLX developers
|
||||
* - XFree86 developers
|
||||
* - xemu developers
|
||||
*
|
||||
* Authors: Connor Hyde / starfrost <mario64crashed@gmail.com>
|
||||
*
|
||||
* Copyright 2024 Connor Hyde
|
||||
*/
|
||||
#ifdef EMU_DEVICE_H // what
|
||||
|
||||
//TODO: split this all into nv1, nv3, nv4...
|
||||
|
||||
#include <86box/timer.h>
|
||||
#include <86box/vid_svga.h>
|
||||
#include <86box/vid_svga_render.h>
|
||||
|
||||
void nv_log(const char *fmt, ...);
|
||||
|
||||
// Defines common to all NV chip architectural generations
|
||||
|
||||
// PCI IDs
|
||||
#define PCI_VENDOR_NV 0x10DE // NVidia PCI ID
|
||||
#define PCI_VENDOR_SGS 0x104A // SGS-Thompson
|
||||
#define PCI_VENDOR_SGS_NV 0x12D2 // SGS-Thompson/NVidia joint venture
|
||||
|
||||
#define NV_PCI_NUM_CFG_REGS 256 // number of pci config registers
|
||||
|
||||
// 0x0000 was probably the NV0 'Nvidia Hardware Simulator'
|
||||
#define PCI_DEVICE_NV1 0x0008 // Nvidia NV1
|
||||
#define PCI_DEVICE_NV1_VGA 0x0009 // Nvidia NV1 VGA core
|
||||
#define PCI_DEVICE_NV2 0x0010 // Nvidia NV2 / Mutara V08 (cancelled)
|
||||
#define PCI_DEVICE_NV3 0x0018 // Nvidia NV3 (Riva 128)
|
||||
#define PCI_DEVICE_NV3T 0x0019 // Nvidia NV3T (Riva 128 ZX)
|
||||
#define PCI_DEVICE_NV4 0x0020 // Nvidia NV4 (RIVA TNT)
|
||||
|
||||
#define CHIP_REVISION_NV1_A0 0x0000
|
||||
#define CHIP_REVISION_NV1_B0 0x0010
|
||||
#define CHIP_REVISION_NV1_C0 0x0020
|
||||
|
||||
#define CHIP_REVISION_NV3_A0 0x0000 // January 1997
|
||||
#define CHIP_REVISION_NV3_B0 0x0010 // October 1997
|
||||
#define CHIP_REVISION_NV3_C0 0x0020 // 1998
|
||||
|
||||
// Architecture IDs
|
||||
#define NV_ARCHITECTURE_NV1 1
|
||||
#define NV_ARCHITECTURE_NV2 2
|
||||
#define NV_ARCHITECTURE_NV3 3
|
||||
|
||||
|
||||
typedef enum nv_bus_generation_e
|
||||
{
|
||||
// NV1
|
||||
// NV3
|
||||
nv_bus_pci = 0,
|
||||
|
||||
// NV3
|
||||
nv_bus_agp_1x = 1,
|
||||
|
||||
// NV3T
|
||||
// NV4
|
||||
nv_bus_agp_2x = 2,
|
||||
|
||||
} nv_bus_generation;
|
||||
|
||||
// NV Base
|
||||
typedef struct nv_base_s
|
||||
{
|
||||
rom_t vbios; // NVIDIA/OEm VBIOS
|
||||
// move to nv3_cio_t?
|
||||
svga_t svga; // SVGA core (separate to nv3)
|
||||
// stuff that doesn't fit in the svga structure
|
||||
uint32_t cio_read_bank; // SVGA read bank
|
||||
uint32_t cio_write_bank; // SVGA write bank
|
||||
|
||||
mem_mapping_t framebuffer_mapping; // Linear Framebuffer / NV_USER memory mapping
|
||||
mem_mapping_t mmio_mapping; // mmio mapping (32MB unified MMIO)
|
||||
mem_mapping_t framebuffer_mapping_mirror; // Mirror of LFB mapping
|
||||
mem_mapping_t ramin_mapping; // RAM INput area mapping
|
||||
mem_mapping_t ramin_mapping_mirror; // RAM INput area mapping (mirrored)
|
||||
uint8_t pci_slot; // pci slot number
|
||||
uint8_t pci_irq_state; // current PCI irq state
|
||||
uint32_t bar0_mmio_base; // PCI Base Address Register 0 - MMIO Base
|
||||
uint32_t bar1_lfb_base; // PCI Base Address Register 1 - Linear Framebuffer (NV_BASE)
|
||||
nv_bus_generation bus_generation; // current bus (see nv_bus_generation documentation)
|
||||
} nv_base_t;
|
||||
|
||||
#define NV_REG_LIST_END 0xD15EA5E
|
||||
|
||||
// The NV architectures are very complex.
|
||||
// There are hundreds of registers at minimum, and implementing these in a standard way would lead to
|
||||
// unbelievably large switch statements and horrifically unreadable code.
|
||||
// So this is used to abstract it and allow for more readable code.
|
||||
// This is mostly just used for logging and stuff.
|
||||
// Optionally, you can provide a function that is run when you read to and write from the register.
|
||||
// You can also implement this functionality in a traditional way such as a switch statement, for simpler registers. To do this, simply set both read and write functions to NULL.
|
||||
// Typically, unless they are for a special purpose (and handled specially) e.g. vga all register reads and writes are also 32-bit aligned
|
||||
typedef struct nv_register_s
|
||||
{
|
||||
int32_t address; // MMIO Address
|
||||
char* friendly_name; // Friendly name
|
||||
// reg_ptr not needed as a parameter, because we implicitly know which register si being tiwddled
|
||||
uint32_t (*on_read)(); // Optional on-read function
|
||||
void (*on_write)(uint32_t value);// Optional on-write fucntion
|
||||
} nv_register_t;
|
||||
|
||||
nv_register_t* nv_get_register(uint32_t address, nv_register_t* register_list, uint32_t num_regs);
|
||||
|
||||
#define NV3_BOOT_REG_DEFAULT 0x00300111
|
||||
|
||||
// Master Control
|
||||
typedef struct nv3_pmc_s
|
||||
{
|
||||
/*
|
||||
Holds chip manufacturing information at bootup.
|
||||
Current specification (may change later): pre-packed for convenience
|
||||
|
||||
FIB Revision 1, Mask Revision B0, Implementation 1 [NV3], Architecture 3 [NV3], Manufacturer Nvidia, Foundry SGS (seems to have been the most common?)
|
||||
31:28=0000, 27:24=0000, 23:16=0003, 15:8=0001, 7:4=0001, 3:0=0001
|
||||
little endian 00000000 00000011 00000001 00010001 = 0x00300111
|
||||
*/
|
||||
int32_t boot;
|
||||
int32_t interrupt_status; // Determines if interrupts are pending for specific subsystems.
|
||||
int32_t interrupt_enable; // Determines if interrupts are actually enabled.
|
||||
int32_t enable; // Determines which subsystems are enabled.
|
||||
|
||||
} nv3_pmc_t;
|
||||
|
||||
typedef struct nv3_pci_config_s
|
||||
{
|
||||
uint8_t pci_regs[NV_PCI_NUM_CFG_REGS]; // The actual pci register values (not really used, just so they can be stored - they aren't very good for code readability)
|
||||
bool vbios_enabled; // is the vbios enabled?
|
||||
uint8_t int_line;
|
||||
} nv3_pci_config_t;
|
||||
|
||||
// add enums for eac
|
||||
// Chip configuration
|
||||
typedef struct nv3_straps_s
|
||||
{
|
||||
uint32_t straps;
|
||||
} nv3_straps_t;
|
||||
|
||||
// Framebuffer
|
||||
typedef struct nv3_pfb_s
|
||||
{
|
||||
uint32_t boot;
|
||||
} nv3_pfb_t;
|
||||
|
||||
#define NV3_RMA_NUM_REGS 4
|
||||
// Access the GPU from real-mode
|
||||
typedef struct nv3_pbus_rma_s
|
||||
{
|
||||
uint32_t addr; // Address to RMA to
|
||||
uint32_t data; // Data to send to MMIO
|
||||
uint8_t mode; // the current state of the rma shifting engin
|
||||
uint8_t rma_regs[NV3_RMA_NUM_REGS]; // The rma registers (saved)
|
||||
} nv3_pbus_rma_t;
|
||||
|
||||
// Bus Configuration
|
||||
typedef struct nv3_pbus_s
|
||||
{
|
||||
uint32_t interrupt_status; // Interrupt status
|
||||
uint32_t interrupt_enable; // Interrupt enable
|
||||
nv3_pbus_rma_t rma;
|
||||
} nv3_pbus_t;
|
||||
|
||||
// Command submission to PGRAPH
|
||||
typedef struct nv_pfifo_s
|
||||
{
|
||||
uint32_t interrupt_status; // Interrupt status
|
||||
uint32_t interrupt_enable; // Interrupt enable
|
||||
} nv3_pfifo_t;
|
||||
|
||||
// RAMDAC
|
||||
typedef struct nv3_pramdac_s
|
||||
{
|
||||
// these should be uint8_t but C math is a lot better with this
|
||||
uint32_t memory_clock_m; // memory clock M-divider
|
||||
uint32_t memory_clock_n; // memory clock N-divider
|
||||
uint32_t memory_clock_p; // memory clock P-divider
|
||||
uint32_t pixel_clock_m; // pixel clock M-divider
|
||||
uint32_t pixel_clock_n; // pixel clock N-divider
|
||||
uint32_t pixel_clock_p; // pixel clock P-divider
|
||||
uint32_t coeff_select; // coefficient select
|
||||
|
||||
uint32_t general_control; // general control register
|
||||
|
||||
// this could duplicate SVGA state but I tihnk it's more readable,
|
||||
// we'll just modify both
|
||||
uint32_t vserr_width; // vertical sync error width
|
||||
uint32_t vequ_end; // vequ end (not sure what this is)
|
||||
uint32_t vbblank_end; // vbblank end (not sure what this is)
|
||||
uint32_t vblank_end; // vblank end
|
||||
uint32_t vblank_start; // vblank start
|
||||
uint32_t vequ_start; // vequ start (not sure what this is)
|
||||
uint32_t vtotal; // vertical total lines
|
||||
uint32_t hsync_width; // horizontal sync width
|
||||
uint32_t hburst_start; // horizontal burst signal start (in lines)
|
||||
uint32_t hburst_end; // horizontal burst signal end (in lines)
|
||||
uint32_t hblank_start; // horizontal blank start (in lines)
|
||||
uint32_t hblank_end; // horizontal blank end (in lines)
|
||||
uint32_t htotal; // horizontal total lines
|
||||
uint32_t hequ_width; // horizontal equ width (not sure what this is)
|
||||
uint32_t hserr_width; // horizontal sync error width
|
||||
} nv3_pramdac_t;
|
||||
|
||||
// Graphics Subsystem
|
||||
typedef struct nv3_pgraph_s
|
||||
{
|
||||
uint32_t interrupt_status_0; // Interrupt status 0
|
||||
uint32_t interrupt_enable_0; // Interrupt enable 0
|
||||
uint32_t interrupt_status_1; // Interrupt status 1
|
||||
uint32_t interrupt_enable_1; // Interrupt enable 1
|
||||
} nv3_pgraph_t;
|
||||
|
||||
// GPU Manufacturing Configuration (again)
|
||||
// In the future this will be configurable
|
||||
typedef struct nv3_pextdev_s
|
||||
{
|
||||
/*
|
||||
// Disabled 33Mhz
|
||||
// Enabled 66Mhz
|
||||
bool bus_speed;
|
||||
|
||||
// Disabled No BIOS
|
||||
// Enabled BIOS
|
||||
bool bios;
|
||||
|
||||
// RAM Type #1
|
||||
// Disabled 16Mbit (2MB) module size
|
||||
// Enabled 8Mbit (1MB) module size
|
||||
bool ram_type_1;
|
||||
|
||||
// NEC Mode
|
||||
bool nec_mode;
|
||||
|
||||
// Disabled 64-bit
|
||||
// Enabled 128-bit
|
||||
bool bus_width;
|
||||
|
||||
// Disabled PCI
|
||||
// Enabled AGP
|
||||
bool bus_type;
|
||||
|
||||
// Disabled 13500
|
||||
// Enabled 14318180
|
||||
bool crystal;
|
||||
|
||||
// TV Mode
|
||||
// 0 - SECAM, 1 - NTSC, 2 - PAL, 3 - none
|
||||
uint8_t tv_mode;
|
||||
|
||||
// AGP 2X mode
|
||||
// Disabled AGP 1X
|
||||
// Enabled AGP 2X
|
||||
bool agp_is_2x;
|
||||
|
||||
bool unused;
|
||||
|
||||
// Overwrite enable
|
||||
bool overwrite;
|
||||
|
||||
See defines in vid_nv3.h
|
||||
*/
|
||||
uint32_t straps;
|
||||
|
||||
// more ram type stuff here but not used?
|
||||
} nv3_pextdev_t;
|
||||
|
||||
typedef struct nv3_ptimer_s
|
||||
{
|
||||
uint32_t interrupt_status; // Interrupt status
|
||||
uint32_t interrupt_enable; // Interrupt enable
|
||||
} nv3_ptimer_t;
|
||||
|
||||
// Graphics object hashtable
|
||||
typedef struct nv3_pramin_ramht_s
|
||||
{
|
||||
|
||||
} nv3_pramin_ramht_t;
|
||||
|
||||
// Anti-fuckup device
|
||||
typedef struct nv3_pramin_ramro_s
|
||||
{
|
||||
|
||||
} nv3_pramin_ramro_t;
|
||||
|
||||
// context for unused channels
|
||||
typedef struct nv3_pramin_ramfc_s
|
||||
{
|
||||
|
||||
} nv3_pramin_ramfc_t;
|
||||
|
||||
// ????? ram auxillary
|
||||
typedef struct nv_pramin_ramau_s
|
||||
{
|
||||
|
||||
} nv3_pramin_ramau_t;
|
||||
|
||||
typedef struct nv3_pramin_s
|
||||
{
|
||||
|
||||
} nv3_pramin_t;
|
||||
|
||||
typedef struct nv3_pvideo_s
|
||||
{
|
||||
uint32_t interrupt_status; // Interrupt status
|
||||
uint32_t interrupt_enable; // Interrupt enable
|
||||
} nv3_pvideo_t;
|
||||
|
||||
typedef struct nv3_pme_s // Mediaport
|
||||
{
|
||||
uint32_t interrupt_status;
|
||||
uint32_t interrupt_enable;
|
||||
} nv3_pme_t;
|
||||
|
||||
typedef struct nv3_s
|
||||
{
|
||||
nv_base_t nvbase; // Base Nvidia structure
|
||||
|
||||
// Config
|
||||
nv3_straps_t straps;
|
||||
nv3_pci_config_t pci_config;
|
||||
|
||||
// Subsystems
|
||||
nv3_pmc_t pmc; // Master Control
|
||||
nv3_pfb_t pfb; // Framebuffer/VRAM
|
||||
nv3_pbus_t pbus; // Bus Control
|
||||
nv3_pfifo_t pfifo; // FIFO for command submisison
|
||||
|
||||
nv3_pramdac_t pramdac; // RAMDAC (CLUT etc)
|
||||
nv3_pgraph_t pgraph; // 2D/3D Graphics
|
||||
nv3_pextdev_t pextdev; // Chip configuration
|
||||
nv3_ptimer_t ptimer; // programmable interval timer
|
||||
nv3_pramin_ramht_t ramht; // hashtable for PGRAPH objects
|
||||
nv3_pramin_ramro_t ramro; // anti-fuckup mechanism for idiots who fucked up the FIFO submission
|
||||
nv3_pramin_ramfc_t ramfc; // context for unused channels
|
||||
nv3_pramin_ramau_t ramau; // auxillary weirdnes
|
||||
nv3_pramin_t pramin; // Ram for INput of DMA objects. Very important!
|
||||
nv3_pvideo_t pvideo; // Video overlay
|
||||
nv3_pme_t pme; // Mediaport - external MPEG decoder and video interface
|
||||
//more here
|
||||
|
||||
} nv3_t;
|
||||
|
||||
// device objects
|
||||
extern nv3_t* nv3;
|
||||
|
||||
// Address of this returned by unimplemented registers to prevent a crash
|
||||
extern uint32_t unimplemented_dummy;
|
||||
|
||||
// NV3 stuff
|
||||
|
||||
// Device Core
|
||||
void* nv3_init(const device_t *info);
|
||||
void nv3_close(void* priv);
|
||||
void nv3_speed_changed(void *priv);
|
||||
void nv3_force_redraw(void* priv);
|
||||
|
||||
// Memory Mapping
|
||||
void nv3_update_mappings();
|
||||
uint8_t nv3_mmio_read8(uint32_t addr, void* priv); // Read 8-bit MMIO
|
||||
uint16_t nv3_mmio_read16(uint32_t addr, void* priv); // Read 16-bit MMIO
|
||||
uint32_t nv3_mmio_read32(uint32_t addr, void* priv); // Read 32-bit MMIO
|
||||
void nv3_mmio_write8(uint32_t addr, uint8_t val, void* priv); // Write 8-bit MMIO
|
||||
void nv3_mmio_write16(uint32_t addr, uint16_t val, void* priv); // Write 16-bit MMIO
|
||||
void nv3_mmio_write32(uint32_t addr, uint32_t val, void* priv); // Write 32-bit MMIO
|
||||
|
||||
uint8_t nv3_svga_in(uint16_t addr, void* priv); // Read SVGA compatibility registers
|
||||
void nv3_svga_out(uint16_t addr, uint8_t val, void* priv); // Write SVGA registers
|
||||
uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv); // Read PCI configuration registers
|
||||
void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv); // Write PCI configuration registers
|
||||
|
||||
uint8_t nv3_ramin_read8(uint32_t addr, void* priv); // Read 8-bit RAMIN
|
||||
uint16_t nv3_ramin_read16(uint32_t addr, void* priv); // Read 16-bit RAMIN
|
||||
uint32_t nv3_ramin_read32(uint32_t addr, void* priv); // Read 32-bit RAMIN
|
||||
void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv); // Write 8-bit RAMIN
|
||||
void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv); // Write 16-bit RAMIN
|
||||
void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv); // Write 32-bit RAMIN
|
||||
|
||||
// MMIO Arbitration
|
||||
// Determine where the hell in this mess our reads or writes are going
|
||||
uint32_t nv3_mmio_arbitrate_read(uint32_t address);
|
||||
void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value);
|
||||
|
||||
// Read and Write functions for GPU subsystems
|
||||
// Remove the ones that aren't used here eventually, have all of htem for now
|
||||
uint32_t nv3_pmc_read(uint32_t address);
|
||||
void nv3_pmc_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_cio_read(uint32_t address);
|
||||
void nv3_cio_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pbus_read(uint32_t address);
|
||||
void nv3_pbus_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pfifo_read(uint32_t address);
|
||||
void nv3_pfifo_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_prm_read(uint32_t address);
|
||||
void nv3_prm_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_prmio_read(uint32_t address);
|
||||
void nv3_prmio_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_ptimer_read(uint32_t address);
|
||||
void nv3_ptimer_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pfb_read(uint32_t address);
|
||||
void nv3_pfb_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pextdev_read(uint32_t address);
|
||||
void nv3_pextdev_write(uint32_t address, uint32_t value);
|
||||
|
||||
// Special consideration for straps
|
||||
#define nv3_pstraps_read nv3_pextdev_read(NV3_PSTRAPS)
|
||||
#define nv3_pstraps_write(x) nv3_pextdev_write(NV3_PSTRAPS, x)
|
||||
|
||||
uint32_t nv3_prom_read(uint32_t address);
|
||||
void nv3_prom_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_palt_read(uint32_t address);
|
||||
void nv3_palt_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pme_read(uint32_t address);
|
||||
void nv3_pme_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pgraph_read(uint32_t address);
|
||||
void nv3_pgraph_write(uint32_t address, uint32_t value);
|
||||
|
||||
// TODO: PGRAPH class registers
|
||||
|
||||
uint32_t nv3_prmcio_read(uint32_t address);
|
||||
void nv3_prmcio_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pvideo_read(uint32_t address);
|
||||
void nv3_pvideo_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_pramdac_read(uint32_t address);
|
||||
void nv3_pramdac_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_vram_read(uint32_t address);
|
||||
void nv3_vram_write(uint32_t address, uint32_t value);
|
||||
#define nv3_nvm_read nv3_vram_read
|
||||
#define nv3_nvm_write nv3_vram_write
|
||||
uint32_t nv3_user_read(uint32_t address);
|
||||
void nv3_user_write(uint32_t address, uint32_t value);
|
||||
#define nv3_object_submit_start nv3_user_read
|
||||
#define nv3_object_submit_end nv3_user_write
|
||||
uint32_t nv3_pramin_read(uint32_t address);
|
||||
void nv3_pramin_write(uint32_t address, uint32_t value);
|
||||
// TODO: RAMHT, RAMFC...or maybe handle it inside of nv3_pramin_*
|
||||
|
||||
// GPU subsystems
|
||||
|
||||
// NV3 PMC
|
||||
void nv3_pmc_init();
|
||||
uint32_t nv3_pmc_clear_interrupts();
|
||||
uint32_t nv3_pmc_handle_interrupts(bool send_now);
|
||||
|
||||
// NV3 PGRAPH
|
||||
void nv3_pgraph_init();
|
||||
|
||||
// NV3 PFIFO
|
||||
void nv3_pfifo_init();
|
||||
|
||||
|
||||
// NV3 PFB
|
||||
void nv3_pfb_init();
|
||||
|
||||
// NV3 PEXTDEV/PSTRAPS
|
||||
void nv3_pextdev_init();
|
||||
|
||||
// NV3 PBUS
|
||||
void nv3_pbus_init();
|
||||
|
||||
// NV3 PBUS RMA - Real Mode Access for VBIOS
|
||||
uint8_t nv3_pbus_rma_read(uint16_t addr);
|
||||
void nv3_pbus_rma_write(uint16_t addr, uint8_t val);
|
||||
|
||||
// NV3 PRAMDAC
|
||||
void nv3_pramdac_init();
|
||||
void nv3_pramdac_set_vram_clock();
|
||||
void nv3_pramdac_set_pixel_clock();
|
||||
|
||||
// NV3 PTIMER
|
||||
void nv3_ptimer_init();
|
||||
|
||||
// NV3 PVIDEO
|
||||
void nv3_pvideo_init();
|
||||
|
||||
// NV3 PMEDIA
|
||||
void nv3_pmedia_init();
|
||||
#endif
|
||||
486
src/include/86box/nv/vid_nv3.h
Normal file
486
src/include/86box/nv/vid_nv3.h
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* JENSEN HUANG APPROVED !!!!
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde <mario64crashed@gmail.com>
|
||||
*
|
||||
* Copyright 2024 Connor Hyde
|
||||
*/
|
||||
|
||||
// vid_nv3.h: NV3 Architecture Hardware Reference (open-source)
|
||||
// Last updated 26 November 2024
|
||||
|
||||
// The GPU base structure
|
||||
extern nv3_t* nv3;
|
||||
|
||||
#define NV3_MMIO_SIZE 0x1000000 // Max MMIO size
|
||||
|
||||
// various vbioses for testing
|
||||
// Coming soon: MIROmagic Premium BIOS (when I get mine dumped)
|
||||
//todo: move to hash system
|
||||
|
||||
// Oldest one of these - September 6, 1997
|
||||
#define NV3_VBIOS_ERAZOR_V14700 "roms/video/nvidia/nv3/OLD_0000.BIN" // ELSA VICTORY Erazor VBE 3.0 DDC2B DPMS Video BIOS Ver. 1.47.01 (ZZ/ A/00)
|
||||
#define NV3_VBIOS_ERAZOR_V15403 "roms/video/nvidia/nv3/VCERAZOR.BIN" // ELSA VICTORY Erazor Ver. 1.54.03 [WD/VBE30/DDC2B/DPMS]
|
||||
#define NV3_VBIOS_ERAZOR_V15500 "roms/video/nvidia/nv3/Ver15500.rv_" // ELSA VICTORY Erazor Ver. 1.55.00 [WD/VBE30/DDC2B/DPMS]
|
||||
#define NV3_VBIOS_DIAMOND_V330_V162 "roms/video/nvidia/nv3/diamond_v330_rev-e.vbi" // Diamond Multimedia Systems, Inc. Viper V330 Version 1.62-CO
|
||||
#define NV3_VBIOS_ASUS_V3000_V151 "roms/video/nvidia/nv3/riva128_asus.vbi" // ASUS AGP/3DP-V3000 BIOS 1.51B
|
||||
#define NV3_VBIOS_STB_V128_V182 "roms/video/nvidia/nv3/riva128_stb.vbi" // STB Velocity 128 (RIVA 128) Ver.1.82
|
||||
|
||||
// Temporary, will be loaded from settings
|
||||
#define VRAM_SIZE_2MB 0x200000 // 2MB
|
||||
#define VRAM_SIZE_4MB 0x400000 // 4MB
|
||||
#define VRAM_SIZE_8MB 0x800000 // NV3T only
|
||||
|
||||
|
||||
// PCI config
|
||||
#define NV3_PCI_CFG_VENDOR_ID 0x0
|
||||
#define NV3_PCI_CFG_DEVICE_ID 0x2
|
||||
#define NV3_PCI_CFG_CAPABILITIES 0x4
|
||||
|
||||
#define NV3_PCI_COMMAND_L_IO 1
|
||||
#define NV3_PCI_COMMAND_L_IO_ENABLED 0x1
|
||||
#define NV3_PCI_COMMAND_L_MEMORY 2
|
||||
#define NV3_PCI_COMMAND_L_MEMORY_ENABLED 0x1
|
||||
|
||||
#define NV3_PCI_COMMAND_H_FAST_BACK2BACK 0x01
|
||||
|
||||
#define NV3_PCI_STATUS_L_66MHZ_CAPABLE 0x20
|
||||
#define NV3_PCI_STATUS_H_DEVSEL_TIMING 5
|
||||
#define NV3_PCI_STATUS_H_FAST_DEVSEL_TIMING 0x00
|
||||
|
||||
#define NV3_PCI_CFG_REVISION 0x8
|
||||
|
||||
#define NV3_PCI_CFG_REVISION_A00 0x00 // nv3a January 1997 - engineering sample, had NV1 PAUDIO and other minor incompatibilities
|
||||
#define NV3_PCI_CFG_REVISION_B00 0x10 // nv3b September 1997
|
||||
#define NV3_PCI_CFG_REVISION_C00 0x20 // todo: verify this - nv3c (nv3t?) / RIVA 128 ZX
|
||||
|
||||
#define NV3_PCI_CFG_PROGRAMMING_INTERFACE 0x9
|
||||
#define NV3_PCI_CFG_SUBCLASS_CODE 0x0A
|
||||
#define NV3_PCI_CFG_CLASS_CODE 0x0B
|
||||
#define NV3_PCI_CFG_CLASS_CODE_VGA 0x03
|
||||
|
||||
#define NV3_PCI_CFG_CACHE_LINE_SIZE 0x0C
|
||||
#define NV3_PCI_CFG_CACHE_LINE_SIZE_DEFAULT_FROM_VBIOS 0x40
|
||||
|
||||
#define NV3_PCI_CFG_LATENCY_TIMER 0x0D
|
||||
#define NV3_PCI_CFG_HEADER_TYPE 0x0E
|
||||
#define NV3_PCI_CFG_BIST 0x0F
|
||||
|
||||
// PCI Bars
|
||||
#define NV3_PCI_CFG_BAR_PREFETCHABLE 3
|
||||
#define NV3_PCI_CFG_BAR_PREFETCHABLE_ENABLED 0x1
|
||||
|
||||
#define NV3_PCI_CFG_BAR0_L 0x10
|
||||
#define NV3_PCI_CFG_BAR0_BYTE1 0x11
|
||||
#define NV3_PCI_CFG_BAR0_BYTE2 0x12
|
||||
#define NV3_PCI_CFG_BAR0_BASE_ADDRESS 0x13
|
||||
#define NV3_PCI_CFG_BAR1_L 0x14
|
||||
#define NV3_PCI_CFG_BAR1_BYTE1 0x15
|
||||
#define NV3_PCI_CFG_BAR1_BYTE2 0x16
|
||||
#define NV3_PCI_CFG_BAR1_BASE_ADDRESS 0x17
|
||||
#define NV3_PCI_CFG_BAR_INVALID_START 0x18
|
||||
#define NV3_PCI_CFG_BAR_INVALID_END 0x27
|
||||
#define NV3_PCI_CFG_SUBSYSTEM_ID 0x2C
|
||||
|
||||
#define NV3_PCI_CFG_ENABLE_VBIOS 0x30
|
||||
#define NV3_PCI_CFG_VBIOS_BASE 0x32 ... 0x33
|
||||
#define NV3_PCI_CFG_VBIOS_BASE_L 0x32
|
||||
#define NV3_PCI_CFG_VBIOS_BASE_H 0x33
|
||||
|
||||
#define NV3_PCI_CFG_INT_LINE 0x3C
|
||||
#define NV3_PCI_CFG_INT_PIN 0x3D
|
||||
|
||||
#define NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_START 0x40
|
||||
#define NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_END 0x43
|
||||
|
||||
#define NV3_PCI_CFG_MIN_GRANT 0x3E
|
||||
#define NV3_PCI_CFG_MIN_GRANT_DEFAULT 0x03
|
||||
#define NV3_PCI_CFG_MAX_LATENCY 0x3F
|
||||
#define NV3_PCI_CFG_MAX_LATENCY_DEFAULT 0x01
|
||||
|
||||
// GPU Subsystems
|
||||
// These most likely correspond to functional blocks in the original design
|
||||
|
||||
#define NV3_PMC_START 0x0 // Chip Master Control Subsystem
|
||||
|
||||
#define NV3_PMC_BOOT 0x0 // Boot Configuration
|
||||
#define NV3_PMC_INTERRUPT_STATUS 0x100 // Interrupt Control
|
||||
#define NV3_PMC_INTERRUPT_PAUDIO 0 // Unused, NV3A only
|
||||
#define NV3_PMC_INTERRUPT_PAUDIO_PENDING 0x1 // Unused, NV3A only
|
||||
#define NV3_PMC_INTERRUPT_PMEDIA 4
|
||||
#define NV3_PMC_INTERRUPT_PMEDIA_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PFIFO 8
|
||||
#define NV3_PMC_INTERRUPT_PFIFO_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PGRAPH0 12
|
||||
#define NV3_PMC_INTERRUPT_PGRAPH0_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PGRAPH1 13
|
||||
#define NV3_PMC_INTERRUPT_PGRAPH1_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PVIDEO 16
|
||||
#define NV3_PMC_INTERRUPT_PVIDEO_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PTIMER 20
|
||||
#define NV3_PMC_INTERRUPT_PTIMER_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PFB 24
|
||||
#define NV3_PMC_INTERRUPT_PFB_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_PBUS 28
|
||||
#define NV3_PMC_INTERRUPT_PBUS_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_SOFTWARE 31
|
||||
#define NV3_PMC_INTERRUPT_SOFTWARE_PENDING 0x1
|
||||
#define NV3_PMC_INTERRUPT_ENABLE 0x140 // Controls global interrupt enable state
|
||||
#define NV3_PMC_INTERRUPT_ENABLE_HARDWARE 0x1 // Determines if hardware interrupts are enabled
|
||||
#define NV3_PMC_INTERRUPT_ENABLE_SOFTWARE 0x2 // Determinse if software interrupts were enabled
|
||||
#define NV3_PMC_ENABLE 0x200 // Determines which gpu subsystems were enabled
|
||||
|
||||
#define NV3_PMC_END 0xfff // overlaps with CIO
|
||||
#define NV3_CIO_START 0x3b0 // Legacy SVGA Emulation Subsystem
|
||||
#define NV3_CIO_END 0x3df
|
||||
#define NV3_PBUS_START 0x1000 // Bus Control Subsystem
|
||||
#define NV3_PBUS_INTR 0x1100 // Bus Control - Interrupt Status
|
||||
#define NV3_PBUS_INTR_EN 0x1140 // Bus Control - Interrupt Enable
|
||||
#define NV3_PBUS_PCI_START 0x1800 // PCI mirror start
|
||||
#define NV3_PBUS_PCI_END 0x18FF // PCI mirror end
|
||||
#define NV3_PBUS_END 0x1FFF
|
||||
#define NV3_PFIFO_START 0x2000 // FIFO for DMA Object Submission (uses hashtable to store the objects)
|
||||
#define NV3_PFIFO_INTR 0x2100 // FIFO - Interrupt Status
|
||||
#define NV3_PFIFO_INTR_EN 0x2140 // FIFO - Interrupt Enable
|
||||
#define NV3_PFIFO_END 0x3FFF
|
||||
#define NV3_PRM_START 0x4000 // Real-Mode Device Support Subsystem
|
||||
#define NV3_PRM_INTR 0x4100
|
||||
#define NV3_PRM_INTR_EN 0x4140
|
||||
#define NV3_PRM_END 0x4FFF
|
||||
#define NV3_PRAM_START 0x6000 // Local ram/cache?
|
||||
#define NV3_PRAM_END 0x6FFF
|
||||
#define NV3_PRMIO_START 0x7000 // Real-Mode I/O Subsystem
|
||||
#define NV3_PRMIO_END 0x7FFF
|
||||
#define NV3_PTIMER_START 0x9000 // Programmable Interval Timer
|
||||
#define NV3_PTIMER_INTR 0x9100
|
||||
#define NV3_PTIMER_INTR_EN 0x9140
|
||||
#define NV3_PTIMER_END 0x9FFF
|
||||
#define NV3_VGA_VRAM_START 0xA0000 // VGA Emulation VRAM
|
||||
#define NV3_VGA_VRAM_END 0xBFFFF
|
||||
#define NV3_VGA_START 0xC0000 // VGA Emulation Registers
|
||||
#define NV3_VGA_END 0xC7FFF
|
||||
#define NV3_PRMVIO_START NV3_VGA_START
|
||||
#define NV3_PRMVIO_END NV3_VGA_END
|
||||
#define NV3_PFB_START 0x100000 // GPU Interface to VRAM
|
||||
#define NV3_PFB_BOOT 0x100000 // Boot registration
|
||||
#define NV3_PFB_BOOT_RAM_AMOUNT 0 // The amount of ram
|
||||
#define NV3_PFB_BOOT_RAM_AMOUNT_8MB 0x0 // 1mb in NV3A
|
||||
#define NV3_PFB_BOOT_RAM_AMOUNT_2MB 0x1
|
||||
#define NV3_PFB_BOOT_RAM_AMOUNT_4MB 0x2
|
||||
#define NV3_PFB_BOOT_RAM_AMOUNT_UNDEFINED 0x3 // i assume this is used for debug
|
||||
#define NV3_PFB_BOOT_RAM_WIDTH 2 // the bus width of the gpu's vram
|
||||
#define NV3_PFB_BOOT_RAM_WIDTH_64 0x0 // 64bit
|
||||
#define NV3_PFB_BOOT_RAM_WIDTH_128 0x1 // 128bit
|
||||
#define NV3_PFB_BOOT_RAM_BANKS 3 // the number of banks
|
||||
#define NV3_PFB_BOOT_RAM_BANKS_2 0x0 // 2 banks (seems to be used for 2mb)
|
||||
#define NV3_PFB_BOOT_RAM_BANKS_4 0x1 // 4 banks (seems to be used for 4mb)
|
||||
#define NV3_PFB_BOOT_RAM_DATA_TWIDDLE 4
|
||||
#define NV3_PFB_BOOT_RAM_DATA_TWIDDLE_OFF 0x0
|
||||
#define NV3_PFB_BOOT_RAM_DATA_TWIDDLE_ON 0x1
|
||||
#define NV3_PFB_BOOT_RAM_EXTENSION 5
|
||||
#define NV3_PFB_BOOT_RAM_EXTENSION_NONE 0x0
|
||||
#define NV3_PFB_BOOT_RAM_EXTENSION_8MB 0x1
|
||||
#define NV3_PFB_END 0x100FFF
|
||||
#define NV3_PEXTDEV_START 0x101000 // External Devices
|
||||
#define NV3_PSTRAPS 0x101000 // Straps Bits
|
||||
#define NV3_PSTRAPS_BUS_SPEED 0 // Configured bus speed
|
||||
#define NV3_PSTRAPS_BUS_SPEED_33MHZ 0x0
|
||||
#define NV3_PSTRAPS_BUS_SPEED_66MHZ 0x1
|
||||
#define NV3_PSTRAPS_BIOS 1 // Is a VBIOS present?
|
||||
#define NV3_PSTRAPS_BIOS_NOT_PRESENT 0x0
|
||||
#define NV3_PSTRAPS_BIOS_PRESENT 1
|
||||
#define NV3_PSTRAPS_RAM_TYPE 2 // Type of RAM module
|
||||
#define NV3_PSTRAPS_RAM_TYPE_16MBIT 0x0
|
||||
#define NV3_PSTRAPS_RAM_TYPE_8MBIT 0x1
|
||||
#define NV3_PSTRAPS_NEC_MODE 3 // PC98?
|
||||
#define NV3_PSTRAPS_NEC_MODE_DISABLED 0x0
|
||||
#define NV3_PSTRAPS_NEC_MODE_ENABLED 0x1
|
||||
#define NV3_PSTRAPS_BUS_WIDTH 4 // Bus width
|
||||
#define NV3_PSTRAPS_BUS_WIDTH_64BIT 0x0
|
||||
#define NV3_PSTRAPS_BUS_WIDTH_128BIT 0x0
|
||||
#define NV3_PSTRAPS_BUS_TYPE 5 // Determines if this is a PCI or AGP card
|
||||
#define NV3_PSTRAPS_BUS_TYPE_PCI 0x0
|
||||
#define NV3_PSTRAPS_BUS_TYPE_AGP 0x1
|
||||
#define NV3_PSTRAPS_CRYSTAL 6 // type of clock crystal
|
||||
#define NV3_PSTRAPS_CRYSTAL_13500K 0x0 // 13.5 Mhz
|
||||
#define NV3_PSTRAPS_CRYSTAL_14318180 0x1 // 14.318180 Mhz clock crystal
|
||||
#define NV3_PSTRAPS_TVMODE 7 // Type of TV signal to put out
|
||||
#define NV3_PSTRAPS_TVMODE_SECAM 0x0
|
||||
#define NV3_PSTRAPS_TVMODE_NTSC 0x1
|
||||
#define NV3_PSTRAPS_TVMODE_PAL 0x2
|
||||
#define NV3_PSTRAPS_TVMODE_NONE 0x3
|
||||
#define NV3_PSTRAPS_AGP2X 9
|
||||
#define NV3_PSTRAPS_AGP2X_ENABLED 0x0
|
||||
#define NV3_PSTRAPS_AGP2X_DISABLED 0x1
|
||||
#define NV3_PSTRAPS_UNUSED 10
|
||||
#define NV3_PSTRAPS_OVERWRITE 11
|
||||
#define NV3_PSTRAPS_OVERWRITE_DISABLED 0x0
|
||||
#define NV3_PSTRAPS_OVERWRITE_ENABLED 0x1
|
||||
#define NV3_PEXTDEV_END 0x101FFF
|
||||
#define NV3_PROM_START 0x110000 // VBIOS?
|
||||
#define NV3_PROM_END 0x110FFF
|
||||
#define NV3_PALT_START 0x120000 // ??? but it exists
|
||||
#define NV3_PALT_END 0x120FFF
|
||||
#define NV3_PME_START 0x200000 // Mediaport
|
||||
#define NV3_PME_INTR 0x200100 // Mediaport: Interrupt Pending?
|
||||
#define NV3_PME_INTR_EN 0x200140 // Mediaport: Interrupt Enable
|
||||
#define NV3_PME_END 0x200FFF
|
||||
#define NV3_PGRAPH_START 0x400000 // Scene graph for 2d/3d rendering...the most important part
|
||||
#define NV3_PGRAPH_INTR_0 0x400100
|
||||
#define NV3_PGRAPH_INTR_1 0x400104
|
||||
#define NV3_PGRAPH_INTR_EN_0 0x400140 // Interrupt Control for PGRAPH #1
|
||||
//todo: add what this does
|
||||
#define NV3_PGRAPH_INTR_EN_1 0x400180 // Interrupt Control for PGRAPH #2 (it can receive two at onc)
|
||||
|
||||
// not sure about the class ids
|
||||
// these are NOT what each class is, just uSed to manipulate it (there isn't a one to one class->reg mapping anyway)
|
||||
#define NV3_PGRAPH_CLASS18_BETA_START 0x410000 // Beta blending factor
|
||||
#define NV3_PGRAPH_CLASS18_BETA_END 0x411FFF
|
||||
#define NV3_PGRAPH_CLASS20_ROP_START 0x420000 // Blending render operation used at final pixel/fragment generation stage
|
||||
#define NV3_PGRAPH_CLASS20_ROP_END 0x421FFF
|
||||
#define NV3_PGRAPH_CLASS21_COLORKEY_START 0x430000 // Color key for image
|
||||
#define NV3_PGRAPH_CLASS21_COLORKEY_END 0x431FFF
|
||||
#define NV3_PGRAPH_CLASS22_PLANEMASK_START 0x440000 // Plane mask (for clipping?)
|
||||
#define NV3_PGRAPH_CLASS22_PLANEMASK_END 0x441FFF
|
||||
#define NV3_PGRAPH_CLASSXX_CLIP_START 0x450000 // clipping, probably class 23
|
||||
#define NV3_PGRAPH_CLASSXX_CLIP_END 0x451FFF
|
||||
#define NV3_PGRAPH_CLASS24_PATTERN_START 0x460000 // presumably a blend pattern
|
||||
#define NV3_PGRAPH_CLASS24_PATTERN_END 0x461FFF
|
||||
#define NV3_PGRAPH_CLASS30_RECTANGLE_START 0x470000 // also class 25 - that's black [NV1]
|
||||
#define NV3_PGRAPH_CLASS30_RECTANGLE_END 0x471FFF // also class 25 - that's black [NV1]
|
||||
#define NV3_PGRAPH_CLASS26_POINT_START 0x480000 // A single point
|
||||
#define NV3_PGRAPH_CLASS26_POINT_END 0x481FFF
|
||||
#define NV3_PGRAPH_CLASS27_LINE_START 0x490000 // A line
|
||||
#define NV3_PGRAPH_CLASS27_LINE_END 0x491FFF
|
||||
#define NV3_PGRAPH_CLASS28_LIN_START 0x4A0000 // A lin - a line without its starting or ending pixels
|
||||
#define NV3_PGRAPH_CLASS28_LIN_END 0x4A1FFF
|
||||
#define NV3_PGRAPH_CLASS29_TRIANGLE_START 0x4B0000 // A triangle [NV1 variant] - in NV1 this was converted to a quad patch
|
||||
#define NV3_PGRAPH_CLASS29_TRIANGLE_END 0x4B1FFF
|
||||
#define NV3_PGRAPH_CLASS75_GDITEXT_START 0x4C0000 // Windows 95/NT GDI text acceleration
|
||||
#define NV3_PGRAPH_CLASS75_GDITEXT_END 0x4C1FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASS61_MEM2MEM_XFER_START 0x4D0000 // memory to memory transfer (not sure about which class this is)
|
||||
#define NV3_PGRAPH_CLASS61_MEM2MEM_XFER_END 0x4D1FFF
|
||||
#define NV3_PGRAPH_CLASSXX_IMAGE2MEM_XFER_SCALED_START 0x4E0000 // class 55, 56
|
||||
#define NV3_PGRAPH_CLASSXX_IMAGE2MEM_XFER_SCALED_END 0x4E1FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASS31_BLIT_START 0x500000 // Blit 2d image from memory
|
||||
#define NV3_PGRAPH_CLASS31_BLIT_END 0x501FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASSXX_CPU2MEM_IMAGE_START 0x510000 // Used for class 33, 34, 54
|
||||
#define NV3_PGRAPH_CLASSXX_CPU2MEM_IMAGE_END 0x511FFF
|
||||
#define NV3_PGRAPH_CLASSXX_CPU2MEM_BITMAP_START 0x520000 // not sure, might depend on format
|
||||
#define NV3_PGRAPH_CLASSXX_CPU2MEM_BITMAP_END 0x521FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASSXX_IMAGE2MEM_XFER_START 0x540000 // send image to vram, not sure what class
|
||||
#define NV3_PGRAPH_CLASSXX_IMAGE2MEM_XFER_END 0x541FFF
|
||||
#define NV3_PGRAPH_CLASS54_CPU2MEM_STRETCHED_START 0x550000 // stretched cpu->vram transfer, 54
|
||||
#define NV3_PGRAPH_CLASS54_CPU2MEM_STRETCHED_END 0x551FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASS72_D3D5TRI_ZETA_START 0x570000 // [NV3] Copy a direct3d 5.0 accelerated triangle to the zeta buffer
|
||||
#define NV3_PGRAPH_CLASS72_D3D5TRI_ZETA_END 0x571FFF
|
||||
#define NV3_PGRAPH_CLASSXX_POINTZETA_START 0x580000 // possibly class 69
|
||||
#define NV3_PGRAPH_CLASSXX_POINTZETA_END 0x581FFF
|
||||
|
||||
#define NV3_PGRAPH_CLASS62_MEM2IMAGE_START 0x5C0000 // class 55, 56, 62, 63?
|
||||
#define NV3_PGRAPH_CLASS62_MEM2IMAGE_END 0x5C1FFF
|
||||
|
||||
#define NV3_PGRAPH_REGISTER_END 0x401FFF // end of pgraph registers
|
||||
#define NV3_PGRAPH_REAL_END 0x5C1FFF
|
||||
|
||||
#define NV3_PRMCIO_START 0x601000
|
||||
#define NV3_PRMCIO_END 0x601FFF
|
||||
|
||||
#define NV3_PDAC_START 0x680000 // OPTIONAL external DAC
|
||||
#define NV3_PVIDEO_START 0x680000 // Video Generation / overlay configuration
|
||||
#define NV3_PVIDEO_INTR 0x680100
|
||||
#define NV3_PVIDEO_INTR_EN 0x680140
|
||||
#define NV3_PVIDEO_END 0x6802FF
|
||||
#define NV3_PRAMDAC_START 0x680300
|
||||
|
||||
#define NV3_PRAMDAC_CLOCK_MEMORY 0x680504
|
||||
#define NV3_PRAMDAC_CLOCK_MEMORY_VDIV 7:0
|
||||
#define NV3_PRAMDAC_CLOCK_MEMORY_NDIV 15:8
|
||||
#define NV3_PRAMDAC_CLOCK_MEMORY_PDIV 18:16
|
||||
#define NV3_PRAMDAC_CLOCK_PIXEL 0x680508
|
||||
#define NV3_PRAMDAC_COEFF_SELECT 0x68050C
|
||||
|
||||
#define NV3_PRAMDAC_GENERAL_CONTROL 0x680600
|
||||
|
||||
// These are all 10-bit values, but aligned to 32bits
|
||||
// so treating them as 32bit should be fine
|
||||
#define NV3_PRAMDAC_VSERR_WIDTH 0x680700
|
||||
#define NV3_PRAMDAC_VEQU_END 0x680704
|
||||
#define NV3_PRAMDAC_VBBLANK_END 0x680708
|
||||
#define NV3_PRAMDAC_VBLANK_END 0x68070C
|
||||
#define NV3_PRAMDAC_VBLANK_START 0x680710
|
||||
#define NV3_PRAMDAC_VBBLANK_START 0x680714
|
||||
#define NV3_PRAMDAC_VEQU_START 0x680718
|
||||
#define NV3_PRAMDAC_VTOTAL 0x68071C
|
||||
#define NV3_PRAMDAC_HSYNC_WIDTH 0x680720
|
||||
#define NV3_PRAMDAC_HBURST_START 0x680724
|
||||
#define NV3_PRAMDAC_HBURST_END 0x680728
|
||||
#define NV3_PRAMDAC_HBLANK_START 0x68072C
|
||||
#define NV3_PRAMDAC_HBLANK_END 0x680730
|
||||
#define NV3_PRAMDAC_HTOTAL 0x680734
|
||||
#define NV3_PRAMDAC_HEQU_WIDTH 0x680738
|
||||
#define NV3_PRAMDAC_HSERR_WIDTH 0x68073C
|
||||
|
||||
#define NV3_PRAMDAC_END 0x680FFF
|
||||
#define NV3_PDAC_END 0x680FFF // OPTIONAL external DAC
|
||||
|
||||
|
||||
#define NV3_USER_START 0x800000 // Mapping for the area where objects are submitted into the FIFO
|
||||
#define NV3_USER_END 0xFFFFFF
|
||||
|
||||
// easier name
|
||||
#define NV3_OBJECT_SUBMIT_START NV3_USER_START
|
||||
#define NV3_OBJECT_SUBMIT_END NV3_USER_END
|
||||
|
||||
// also PDFB (Debug Framebuffer?)
|
||||
#define NV3_PNVM_START 0x1000000 // VRAM access (max 8MB)
|
||||
#define NV3_PNVM_END 0x17FFFFF
|
||||
|
||||
// to be less confusing - NVM = "NV Memory"
|
||||
#define NV3_VRAM_START NV3_PNVM_START
|
||||
#define NV3_VRAM_END NV3_PNVM_END
|
||||
|
||||
// control structures for dma'd in graphics objects from pfifo
|
||||
// these all have configurable sizes, define them here
|
||||
#define NV3_PRAMIN_START 0x1C00000
|
||||
|
||||
#define NV3_PRAMIN_RAMHT_START 0x1C00000 // Hashtable for storing submitted objects
|
||||
#define NV3_PRAMIN_RAMHT_END 0x1C00FFF
|
||||
#define NV3_PRAMIN_RAMHT_SIZE_0 0xFFF
|
||||
#define NV3_PRAMIN_RAMHT_SIZE_1 0x1FFF
|
||||
#define NV3_PRAMIN_RAMHT_SIZE_2 0x3FFF
|
||||
#define NV3_PRAMIN_RAMHT_SIZE_3 0x7FFF
|
||||
|
||||
#define NV3_PRAMIN_RAMAU_START 0x1C01000 // Auxillary area
|
||||
#define NV3_PRAMIN_RAMAU_END 0x1C01BFF
|
||||
#define NV3_PRAMIN_RAMFC_START 0x1C01C00 // context for unused PFIFO DMA channels
|
||||
#define NV3_PRAMIN_RAMFC_END 0x1C01DFF
|
||||
#define NV3_PRAMIN_RAMFC_SIZE_0 0x1FF
|
||||
#define NV3_PRAMIN_RAMFC_SIZE_1 0xFFF
|
||||
#define NV3_PRAMIN_RAMRO_START 0x1C01E00 // Runout area for invalid submissions
|
||||
#define NV3_PRAMIN_RAMRO_SIZE_0 0x1FF
|
||||
#define NV3_PRAMIN_RAMRO_SIZE_1 0x1FFF
|
||||
#define NV3_PRAMIN_RAMRO_END 0x1C01FFF
|
||||
#define NV3_PRAMIN_RAMRM_START 0x1C02000
|
||||
#define NV3_PRAMIN_RAMRM_END 0x1C02FFF
|
||||
|
||||
#define NV3_PRAMIN_END 0x1FFFFFF
|
||||
|
||||
// not done
|
||||
|
||||
// Master Control
|
||||
|
||||
#define NV3_PMC_BOOT 0x0
|
||||
#define NV3_PMC_INTERRUPT 0x100
|
||||
#define NV3_PMC_INTERRUPT_ENABLE 0x140
|
||||
#define NV3_PMC_ENABLE 0x200
|
||||
#define NV3_PMC_ENABLE_PAUDIO 0 // UNUSED - PAudio removed in NV3 Stepping B0
|
||||
#define NV3_PMC_ENABLE_PAUDIO_ENABLED 0x1 // UNUSED - PAudio removed in NV3 Stepping B0
|
||||
#define NV3_PMC_ENABLE_PMEDIA 4
|
||||
#define NV3_PMC_ENABLE_PMEDIA_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PFIFO 8
|
||||
#define NV3_PMC_ENABLE_PFIFO_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PGRAPH 12
|
||||
#define NV3_PMC_ENABLE_PGRAPH_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PPMI 16
|
||||
#define NV3_PMC_ENABLE_PPMI_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PFB 20
|
||||
#define NV3_PMC_ENABLE_PFB_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PCRTC 24
|
||||
#define NV3_PMC_ENABLE_PCRTC_ENABLED 0x1
|
||||
#define NV3_PMC_ENABLE_PVIDEO 28
|
||||
#define NV3_PMC_ENABLE_PVIDEO_ENABLED 0x1
|
||||
|
||||
// CRTC/CIO (0x3b0-0x3df)
|
||||
|
||||
#define NV3_CRTC_DATA_OUT 0x3C0
|
||||
#define NV3_CRTC_MISCOUT 0x3C2
|
||||
|
||||
// These are standard (0-18h)
|
||||
#define NV3_CRTC_REGISTER_HTOTAL 0x00
|
||||
#define NV3_CRTC_REGISTER_HDISPEND 0x01
|
||||
#define NV3_CRTC_REGISTER_HBLANKSTART 0x02
|
||||
#define NV3_CRTC_REGISTER_HBLANKEND 0x03
|
||||
#define NV3_CRTC_REGISTER_HRETRACESTART 0x04
|
||||
#define NV3_CRTC_REGISTER_HRETRACEEND 0x05
|
||||
#define NV3_CRTC_REGISTER_VTOTAL 0x06
|
||||
#define NV3_CRTC_REGISTER_OVERFLOW 0x07
|
||||
#define NV3_CRTC_REGISTER_PRESETROWSCAN 0x08
|
||||
#define NV3_CRTC_REGISTER_MAXSCAN 0x09
|
||||
#define NV3_CRTC_REGISTER_CURSOR_START 0x0A
|
||||
#define NV3_CRTC_REGISTER_CURSOR_END 0x0B
|
||||
#define NV3_CRTC_REGISTER_STARTADDR_HIGH 0x0C
|
||||
#define NV3_CRTC_REGISTER_STARTADDR_LOW 0x0D
|
||||
#define NV3_CRTC_REGISTER_CURSORLOCATION_HIGH 0x0E
|
||||
#define NV3_CRTC_REGISTER_CURSORLOCATION_LOW 0x0F
|
||||
#define NV3_CRTC_REGISTER_VRETRACESTART 0x10
|
||||
#define NV3_CRTC_REGISTER_VRETRACEEND 0x11
|
||||
#define NV3_CRTC_REGISTER_VDISPEND 0x12
|
||||
#define NV3_CRTC_REGISTER_OFFSET 0x13
|
||||
#define NV3_CRTC_REGISTER_UNDERLINELOCATION 0x14
|
||||
#define NV3_CRTC_REGISTER_STARTVBLANK 0x15
|
||||
#define NV3_CRTC_REGISTER_ENDVBLANK 0x16
|
||||
#define NV3_CRTC_REGISTER_CRTCCONTROL 0x17
|
||||
#define NV3_CRTC_REGISTER_LINECOMP 0x18
|
||||
#define NV3_CRTC_REGISTER_STANDARDVGA_END 0x18
|
||||
|
||||
|
||||
// These are nvidia (25-63)
|
||||
#define NV3_CRTC_REGISTER_RPC0 0x19 // What does this mean?
|
||||
#define NV3_CRTC_REGISTER_RPC1 0x1A // What does this mean?
|
||||
#define NV3_CRTC_REGISTER_READ_BANK 0x1D
|
||||
#define NV3_CRTC_REGISTER_WRITE_BANK 0x1E
|
||||
#define NV3_CRTC_REGISTER_FORMAT 0x25
|
||||
#define NV3_CRTC_REGISTER_FORMAT_VDT10 0 // Use 10 bit vtotal value instead of 8 bit
|
||||
#define NV3_CRTC_REGISTER_FORMAT_VDE10 1 // Use 10 bit dispend value instead of 8 bit
|
||||
#define NV3_CRTC_REGISTER_FORMAT_VRS10 2 // Use 10 bit vblank start value instead of 8 bit
|
||||
#define NV3_CRTC_REGISTER_FORMAT_VBS10 3 // Use 10 bit vsync start value instead of 8 bit
|
||||
#define NV3_CRTC_REGISTER_FORMAT_HBE6 4 // Use 6 bit hsync start value
|
||||
#define NV3_CRTC_REGISTER_PIXELMODE 0x28
|
||||
|
||||
#define NV3_CRTC_REGISTER_HEB 0x2D // HRS most significant bit
|
||||
|
||||
#define NV3_CRTC_REGISTER_PIXELMODE_VGA 0x00 // vga textmode
|
||||
#define NV3_CRTC_REGISTER_PIXELMODE_8BPP 0x01
|
||||
#define NV3_CRTC_REGISTER_PIXELMODE_16BPP 0x02
|
||||
#define NV3_CRTC_REGISTER_PIXELMODE_32BPP 0x03
|
||||
|
||||
#define NV3_CRTC_REGISTER_RMA 0x38 // REAL MODE ACCESS!
|
||||
|
||||
// where the fuck is GDC?
|
||||
#define NV3_CRTC_BANKED_128K_A0000 0x00
|
||||
#define NV3_CRTC_BANKED_64K_A0000 0x04
|
||||
#define NV3_CRTC_BANKED_32K_B0000 0x08
|
||||
#define NV3_CRTC_BANKED_32K_B8000 0x0C
|
||||
|
||||
|
||||
#define NV3_RMA_REGISTER_START 0x3D0
|
||||
#define NV3_RMA_REGISTER_END 0x3D3
|
||||
|
||||
#define NV3_CRTC_REGISTER_NVIDIA_END 0x3F
|
||||
// for 86box 8bit addressing
|
||||
// get rid of this asap, replace with 32->8 macros
|
||||
#define NV3_RMA_SIGNATURE_MSB 0x65
|
||||
#define NV3_RMA_SIGNATURE_BYTE2 0xD0
|
||||
#define NV3_RMA_SIGNATURE_BYTE1 0x16
|
||||
#define NV3_RMA_SIGNATURE_LSB 0x2B
|
||||
|
||||
#define NV3_CRTC_REGISTER_RMA_MODE_MAX 0x0F
|
||||
|
||||
|
||||
//todo: pixel format
|
||||
|
||||
@@ -589,6 +589,8 @@ extern const device_t voodoo_3_3500_se_agp_device;
|
||||
extern const device_t voodoo_3_3500_si_agp_device;
|
||||
extern const device_t velocity_100_agp_device;
|
||||
extern const device_t velocity_200_agp_device;
|
||||
extern const device_t nv3_device_pci;
|
||||
extern const device_t nv3_device_agp;
|
||||
|
||||
/* Wyse 700 */
|
||||
extern const device_t wy700_device;
|
||||
|
||||
@@ -27,7 +27,21 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c
|
||||
vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.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)
|
||||
vid_bochs_vbe.c
|
||||
nv/nv_base.c
|
||||
nv/nv3/nv3_core.c nv/nv3/nv3_core_arbiter.c nv/nv3/nv3_interrupt.c
|
||||
nv/nv3/subsystems/nv3_pramdac.c
|
||||
nv/nv3/subsystems/nv3_pfifo.c
|
||||
nv/nv3/subsystems/nv3_pgraph.c
|
||||
nv/nv3/subsystems/nv3_pmc.c
|
||||
nv/nv3/subsystems/nv3_pme.c
|
||||
nv/nv3/subsystems/nv3_pextdev.c
|
||||
nv/nv3/subsystems/nv3_pfb.c
|
||||
nv/nv3/subsystems/nv3_pbus.c nv/nv3/subsystems/nv3_pbus_dma.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
|
||||
)
|
||||
|
||||
if(G100)
|
||||
target_compile_definitions(vid PRIVATE USE_G100)
|
||||
|
||||
837
src/video/nv/nv3/nv3_core.c
Normal file
837
src/video/nv/nv3/nv3_core.c
Normal file
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* 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 bringup and device emulation.
|
||||
*
|
||||
* Notes:
|
||||
* xfree86 ref has INVERTED bit numbering? What?
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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/io.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>
|
||||
|
||||
nv3_t* nv3;
|
||||
|
||||
// Prototypes for functions only used in this translation unit
|
||||
void nv3_init_mappings_mmio();
|
||||
void nv3_init_mappings_svga();
|
||||
void nv3_shutdown_mappings_mmio();
|
||||
void nv3_shutdown_mappings_svga();
|
||||
|
||||
uint8_t nv3_svga_in(uint16_t addr, void* priv);
|
||||
void nv3_svga_out(uint16_t addr, uint8_t val, void* priv);
|
||||
|
||||
// All MMIO regs are 32-bit i believe internally
|
||||
// so we have to do some munging to get this to read
|
||||
|
||||
// Read 8-bit MMIO
|
||||
uint8_t nv3_mmio_read8(uint32_t addr, void* priv)
|
||||
{
|
||||
// see if unaligned reads are a problem
|
||||
uint32_t ret = nv3_mmio_read32(addr, priv);
|
||||
return (uint8_t)(ret >> ((addr & 3) << 3) & 0xFF);
|
||||
}
|
||||
|
||||
// Read 16-bit MMIO
|
||||
uint16_t nv3_mmio_read16(uint32_t addr, void* priv)
|
||||
{
|
||||
uint32_t ret = nv3_mmio_read32(addr, priv);
|
||||
return (uint8_t)(ret >> ((addr & 3) << 3) & 0xFFFF);
|
||||
}
|
||||
|
||||
// Read 32-bit MMIO
|
||||
uint32_t nv3_mmio_read32(uint32_t addr, void* priv)
|
||||
{
|
||||
return nv3_mmio_arbitrate_read(addr);
|
||||
}
|
||||
|
||||
// Write 8-bit MMIO
|
||||
void nv3_mmio_write8(uint32_t addr, uint8_t val, void* priv)
|
||||
{
|
||||
// overwrite first 8bits of a 32 bit value
|
||||
uint32_t new_val = nv3_mmio_read32(addr, NULL);
|
||||
|
||||
new_val &= (~0xFF << (addr & 3) << 3);
|
||||
new_val |= (val << ((addr & 3) << 3));
|
||||
|
||||
nv3_mmio_write32(addr, new_val, priv);
|
||||
}
|
||||
|
||||
// Write 16-bit MMIO
|
||||
void nv3_mmio_write16(uint32_t addr, uint16_t val, void* priv)
|
||||
{
|
||||
// overwrite first 16bits of a 32 bit value
|
||||
uint32_t new_val = nv3_mmio_read32(addr, NULL);
|
||||
|
||||
new_val &= (~0xFFFF << (addr & 3) << 3);
|
||||
new_val |= (val << ((addr & 3) << 3));
|
||||
|
||||
nv3_mmio_write32(addr, new_val, priv);
|
||||
}
|
||||
|
||||
// Write 32-bit MMIO
|
||||
void nv3_mmio_write32(uint32_t addr, uint32_t val, void* priv)
|
||||
{
|
||||
nv3_mmio_arbitrate_write(addr, val);
|
||||
}
|
||||
|
||||
// PCI stuff
|
||||
// BAR0 Pointer to MMIO space
|
||||
// BAR1 Pointer to Linear Framebuffer (NV_USER)
|
||||
|
||||
uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv)
|
||||
{
|
||||
uint8_t ret = 0x00;
|
||||
|
||||
// figure out what size this gets read as first
|
||||
// seems func does not matter at least here?
|
||||
switch (addr)
|
||||
{
|
||||
// Get the pci vendor id..
|
||||
|
||||
case NV3_PCI_CFG_VENDOR_ID:
|
||||
ret = (PCI_VENDOR_SGS_NV & 0xFF);
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_VENDOR_ID + 1: // all access 8bit
|
||||
ret = (PCI_VENDOR_SGS_NV >> 8);
|
||||
break;
|
||||
|
||||
// device id
|
||||
|
||||
case NV3_PCI_CFG_DEVICE_ID:
|
||||
ret = (PCI_DEVICE_NV3 & 0xFF);
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_DEVICE_ID+1:
|
||||
ret = (PCI_DEVICE_NV3 >> 8);
|
||||
break;
|
||||
|
||||
// various capabilities
|
||||
// IO space enabled
|
||||
// Memory space enabled
|
||||
// Bus master enabled
|
||||
// Write/inval enabled
|
||||
// Pal snoop enabled
|
||||
// Capabiliies list enabled
|
||||
// 66Mhz FSB capable
|
||||
|
||||
case PCI_REG_COMMAND_L:
|
||||
ret = nv3->pci_config.pci_regs[PCI_REG_COMMAND_L]; // we actually respond to the fucking
|
||||
break;
|
||||
|
||||
case PCI_REG_COMMAND_H:
|
||||
ret = nv3->pci_config.pci_regs[PCI_REG_COMMAND_H] | NV3_PCI_COMMAND_H_FAST_BACK2BACK; // always enable fast back2back
|
||||
break;
|
||||
|
||||
// pci status register
|
||||
case PCI_REG_STATUS_L:
|
||||
if (nv3->pextdev.straps
|
||||
& NV3_PSTRAPS_BUS_SPEED_66MHZ)
|
||||
ret = (nv3->pci_config.pci_regs[PCI_REG_STATUS_L] | NV3_PCI_STATUS_L_66MHZ_CAPABLE);
|
||||
else
|
||||
ret = nv3->pci_config.pci_regs[PCI_REG_STATUS_L];
|
||||
|
||||
break;
|
||||
|
||||
case PCI_REG_STATUS_H:
|
||||
ret = (nv3->pci_config.pci_regs[PCI_REG_STATUS_H]) & (NV3_PCI_STATUS_H_FAST_DEVSEL_TIMING << NV3_PCI_STATUS_H_DEVSEL_TIMING);
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_REVISION:
|
||||
ret = NV3_PCI_CFG_REVISION_B00; // Commercial release
|
||||
break;
|
||||
|
||||
case PCI_REG_PROG_IF:
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_SUBCLASS_CODE:
|
||||
ret = 0x00; // nothing
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_CLASS_CODE:
|
||||
ret = NV3_PCI_CFG_CLASS_CODE_VGA; // CLASS_CODE_VGA
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_CACHE_LINE_SIZE:
|
||||
ret = NV3_PCI_CFG_CACHE_LINE_SIZE_DEFAULT_FROM_VBIOS;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_LATENCY_TIMER:
|
||||
case NV3_PCI_CFG_HEADER_TYPE:
|
||||
case NV3_PCI_CFG_BIST:
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
// BARs are marked as prefetchable per the datasheet
|
||||
case NV3_PCI_CFG_BAR0_L:
|
||||
case NV3_PCI_CFG_BAR1_L:
|
||||
// only bit that matters is bit 3 (prefetch bit)
|
||||
ret =(NV3_PCI_CFG_BAR_PREFETCHABLE_ENABLED << NV3_PCI_CFG_BAR_PREFETCHABLE);
|
||||
break;
|
||||
|
||||
// These registers are hardwired to zero per the datasheet
|
||||
// Writes have no effect, we can just handle it here though
|
||||
case NV3_PCI_CFG_BAR0_BYTE1 ... NV3_PCI_CFG_BAR0_BYTE2:
|
||||
case NV3_PCI_CFG_BAR1_BYTE1 ... NV3_PCI_CFG_BAR1_BYTE2:
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
// MMIO base address
|
||||
case NV3_PCI_CFG_BAR0_BASE_ADDRESS:
|
||||
ret = nv3->nvbase.bar0_mmio_base >> 24;//8bit value
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_BAR1_BASE_ADDRESS:
|
||||
ret = nv3->nvbase.bar1_lfb_base >> 24; //8bit value
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_ENABLE_VBIOS:
|
||||
ret = nv3->pci_config.vbios_enabled;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_INT_LINE:
|
||||
ret = nv3->pci_config.int_line;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_INT_PIN:
|
||||
ret = PCI_INTA;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_MIN_GRANT:
|
||||
ret = NV3_PCI_CFG_MIN_GRANT_DEFAULT;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_MAX_LATENCY:
|
||||
ret = NV3_PCI_CFG_MAX_LATENCY_DEFAULT;
|
||||
break;
|
||||
|
||||
//bar2-5 are not used and hardwired to 0
|
||||
case NV3_PCI_CFG_BAR_INVALID_START ... NV3_PCI_CFG_BAR_INVALID_END:
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
case NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_START:
|
||||
case NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_END:
|
||||
ret = nv3->pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)];
|
||||
break;
|
||||
|
||||
default: // by default just return pci_config.pci_regs
|
||||
ret = nv3->pci_config.pci_regs[addr];
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
nv_log("NV3: nv3_pci_read func=0x%04x addr=0x%04x ret=0x%04x\n", func, addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv)
|
||||
{
|
||||
|
||||
// TOTAL IRRELEVANCY
|
||||
|
||||
// some addresses are not writable so can't have any effect and can't be allowed to be modified using this code
|
||||
// only the most significant byte of the PCI BARs can be modified
|
||||
if (addr >= NV3_PCI_CFG_BAR0_L && addr <= NV3_PCI_CFG_BAR0_BYTE2
|
||||
&& addr >= NV3_PCI_CFG_BAR1_L && addr <= NV3_PCI_CFG_BAR1_BYTE2)
|
||||
return;
|
||||
|
||||
nv_log("NV3: nv3_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr, val);
|
||||
|
||||
nv3->pci_config.pci_regs[addr] = val;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
// standard pci command stuff
|
||||
case PCI_REG_COMMAND_L:
|
||||
nv3->pci_config.pci_regs[PCI_REG_COMMAND_L] = val;
|
||||
// actually update the mappings
|
||||
nv3_update_mappings();
|
||||
break;
|
||||
// pci status register
|
||||
case PCI_REG_STATUS_L:
|
||||
nv3->pci_config.pci_regs[PCI_REG_STATUS_L] = val | (NV3_PCI_STATUS_L_66MHZ_CAPABLE);
|
||||
break;
|
||||
case PCI_REG_STATUS_H:
|
||||
nv3->pci_config.pci_regs[PCI_REG_STATUS_H] = val | (NV3_PCI_STATUS_H_FAST_DEVSEL_TIMING << NV3_PCI_STATUS_H_DEVSEL_TIMING);
|
||||
break;
|
||||
//TODO: ACTUALLY REMAP THE MMIO AND NV_USER
|
||||
case NV3_PCI_CFG_BAR0_BASE_ADDRESS:
|
||||
nv3->nvbase.bar0_mmio_base = val << 24;
|
||||
nv3_update_mappings();
|
||||
break;
|
||||
case NV3_PCI_CFG_BAR1_BASE_ADDRESS:
|
||||
nv3->nvbase.bar1_lfb_base = val << 24;
|
||||
nv3_update_mappings();
|
||||
break;
|
||||
case NV3_PCI_CFG_ENABLE_VBIOS:
|
||||
case NV3_PCI_CFG_VBIOS_BASE:
|
||||
|
||||
// make sure we are actually toggling the vbios, not the rom base
|
||||
if (addr == NV3_PCI_CFG_ENABLE_VBIOS)
|
||||
nv3->pci_config.vbios_enabled = (val & 0x01);
|
||||
|
||||
if (nv3->pci_config.vbios_enabled)
|
||||
{
|
||||
// First see if we simply wanted to change the VBIOS location
|
||||
|
||||
// Enable it in case it was disabled before
|
||||
mem_mapping_enable(&nv3->nvbase.vbios.mapping);
|
||||
|
||||
if (addr != NV3_PCI_CFG_ENABLE_VBIOS)
|
||||
{
|
||||
uint32_t old_addr = nv3->nvbase.vbios.mapping.base;
|
||||
// 9bit register
|
||||
uint32_t new_addr = nv3->pci_config.pci_regs[NV3_PCI_CFG_VBIOS_BASE_H] << 24 |
|
||||
nv3->pci_config.pci_regs[NV3_PCI_CFG_VBIOS_BASE_L] << 16;
|
||||
|
||||
// move it
|
||||
mem_mapping_set_addr(&nv3->nvbase.vbios.mapping, new_addr, 0x8000);
|
||||
|
||||
nv_log("...i like to move it move it (VBIOS Relocation) 0x%04x -> 0x%04x\n", old_addr, new_addr);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nv_log("...VBIOS Enable\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nv_log("...VBIOS Disable\n");
|
||||
mem_mapping_disable(&nv3->nvbase.vbios.mapping);
|
||||
|
||||
}
|
||||
break;
|
||||
case NV3_PCI_CFG_INT_LINE:
|
||||
nv3->pci_config.int_line = val;
|
||||
break;
|
||||
//bar2-5 are not used and can't be written to
|
||||
case NV3_PCI_CFG_BAR_INVALID_START ... NV3_PCI_CFG_BAR_INVALID_END:
|
||||
break;
|
||||
|
||||
// these are mirrored to the subsystem id and also stored in the ROMBIOS
|
||||
case NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_START:
|
||||
case NV3_PCI_CFG_SUBSYSTEM_ID_MIRROR_END:
|
||||
nv3->pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)] = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void nv3_close(void* priv)
|
||||
{
|
||||
svga_close(&nv3->nvbase.svga);
|
||||
free(nv3);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SVGA functions
|
||||
//
|
||||
void nv3_recalc_timings(svga_t* svga)
|
||||
{
|
||||
nv3_t* nv3 = (nv3_t*)svga->priv;
|
||||
|
||||
svga->ma_latch += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0x1F) << 16;
|
||||
svga->rowoffset += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0xE0) << 3;
|
||||
|
||||
// should these actually use separate values?
|
||||
// i don't we should force the top 2 bits to 1...
|
||||
|
||||
// required for VESA resolutions, force parameters higher
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) svga->vtotal += 0x400;
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) svga->dispend += 0x400;
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) svga->vblankstart += 0x400;
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) svga->vsyncstart += 0x400;
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) svga->hdisp += 0x400;
|
||||
|
||||
if (svga->crtc[NV3_CRTC_REGISTER_HEB] & 0x01)
|
||||
svga->hdisp += 0x100; // large screen bit
|
||||
|
||||
// Set the pixel mode
|
||||
switch (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 0x03)
|
||||
{
|
||||
///0x0 is VGA textmode
|
||||
case NV3_CRTC_REGISTER_PIXELMODE_8BPP:
|
||||
svga->bpp = 8;
|
||||
svga->lowres = 0;
|
||||
svga->render = svga_render_8bpp_highres;
|
||||
break;
|
||||
case NV3_CRTC_REGISTER_PIXELMODE_16BPP:
|
||||
svga->bpp = 16;
|
||||
svga->lowres = 0;
|
||||
svga->render = svga_render_16bpp_highres;
|
||||
break;
|
||||
case NV3_CRTC_REGISTER_PIXELMODE_32BPP:
|
||||
svga->bpp = 32;
|
||||
svga->lowres = 0;
|
||||
svga->render = svga_render_32bpp_highres;
|
||||
break;
|
||||
}
|
||||
|
||||
// from nv_riva128
|
||||
if (((svga->miscout >> 2) & 2) == 2)
|
||||
{
|
||||
// set clocks
|
||||
nv3_pramdac_set_pixel_clock();
|
||||
nv3_pramdac_set_vram_clock();
|
||||
}
|
||||
}
|
||||
|
||||
void nv3_speed_changed(void* priv)
|
||||
{
|
||||
nv3_recalc_timings(&nv3->nvbase.svga);
|
||||
}
|
||||
|
||||
// Force Redraw
|
||||
// Reset etc.
|
||||
void nv3_force_redraw(void* priv)
|
||||
{
|
||||
nv3->nvbase.svga.fullchange = changeframecount;
|
||||
}
|
||||
|
||||
// Read from SVGA core memory
|
||||
uint8_t nv3_svga_in(uint16_t addr, void* priv)
|
||||
{
|
||||
nv3_t* nv3 = (nv3_t*)priv;
|
||||
|
||||
uint8_t ret = 0x00;
|
||||
|
||||
// If we need to RMA from GPU MMIO, go do that
|
||||
if (addr >= NV3_RMA_REGISTER_START
|
||||
&& addr <= NV3_RMA_REGISTER_END)
|
||||
{
|
||||
if (!(nv3->pbus.rma.mode & 0x01))
|
||||
return ret;
|
||||
|
||||
// must be dword aligned
|
||||
uint32_t real_rma_read_addr = ((nv3->pbus.rma.mode & NV3_CRTC_REGISTER_RMA_MODE_MAX - 1) << 1) + (addr & 0x03);
|
||||
ret = nv3_pbus_rma_read(real_rma_read_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// mask off b0/d0 registers
|
||||
if ((((addr & 0xFFF0) == 0x3D0
|
||||
|| (addr & 0xFFF0) == 0x3B0) && addr < 0x3de)
|
||||
&& !(nv3->nvbase.svga.miscout & 1))
|
||||
addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
// Alias for "get current SVGA CRTC register ID"
|
||||
case 0x3D4:
|
||||
ret = nv3->nvbase.svga.crtcreg;
|
||||
break;
|
||||
case 0x3D5:
|
||||
// Support the extended NVIDIA CRTC register range
|
||||
switch (nv3->nvbase.svga.crtcreg)
|
||||
{
|
||||
default:
|
||||
ret = nv3->nvbase.svga.crtc[nv3->nvbase.svga.crtcreg];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = svga_in(addr, &nv3->nvbase.svga);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret; //TEMP
|
||||
}
|
||||
|
||||
// Write to SVGA core memory
|
||||
void nv3_svga_out(uint16_t addr, uint8_t val, void* priv)
|
||||
{
|
||||
|
||||
// If we need to RMA to GPU MMIO, go do that
|
||||
if (addr >= NV3_RMA_REGISTER_START
|
||||
&& addr <= NV3_RMA_REGISTER_END)
|
||||
{
|
||||
// we don't need to store these registers...
|
||||
nv3->pbus.rma.rma_regs[addr & 3] = val;
|
||||
|
||||
if (!(nv3->pbus.rma.mode & 0x01)) // we are halfway through sending something
|
||||
return;
|
||||
|
||||
uint32_t real_rma_write_addr = ((nv3->pbus.rma.mode & (NV3_CRTC_REGISTER_RMA_MODE_MAX - 1)) << 1) + (addr & 0x03);
|
||||
|
||||
nv3_pbus_rma_write(real_rma_write_addr, nv3->pbus.rma.rma_regs[addr & 3]);
|
||||
return;
|
||||
}
|
||||
|
||||
// mask off b0/d0 registers
|
||||
if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0)
|
||||
&& addr < 0x3de)
|
||||
&& !(nv3->nvbase.svga.miscout & 1))//miscout bit 7 controls mappping
|
||||
addr ^= 0x60;
|
||||
|
||||
uint8_t crtcreg = nv3->nvbase.svga.crtcreg;
|
||||
uint8_t old_value;
|
||||
|
||||
// todo:
|
||||
// RMA
|
||||
// Pixel formats (8bit vs 555 vs 565)
|
||||
// VBE 3.0?
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3D4:
|
||||
// real mode access to GPU MMIO space...
|
||||
nv3->nvbase.svga.crtcreg = val;
|
||||
break;
|
||||
// support the extended crtc regs and debug this out
|
||||
case 0x3D5:
|
||||
|
||||
// Implements the VGA Protect register
|
||||
if ((nv3->nvbase.svga.crtcreg < NV3_CRTC_REGISTER_OVERFLOW) && (nv3->nvbase.svga.crtc[0x11] & 0x80))
|
||||
return;
|
||||
|
||||
// Ignore certain bits when VGA Protect register set and we are writing to CRTC register=07h
|
||||
if ((nv3->nvbase.svga.crtcreg == NV3_CRTC_REGISTER_OVERFLOW) && (nv3->nvbase.svga.crtc[0x11] & 0x80))
|
||||
val = (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_OVERFLOW] & ~0x10) | (val & 0x10);
|
||||
|
||||
// set the register value...
|
||||
nv3->nvbase.svga.crtc[crtcreg] = val;
|
||||
// ...now act on it
|
||||
|
||||
// Handle nvidia extended Bank0/Bank1 IDs
|
||||
switch (crtcreg)
|
||||
{
|
||||
case NV3_CRTC_REGISTER_READ_BANK:
|
||||
nv3->nvbase.cio_read_bank = val;
|
||||
if (nv3->nvbase.svga.chain4) // chain4 addressing (planar?)
|
||||
nv3->nvbase.svga.read_bank = nv3->nvbase.cio_read_bank << 15;
|
||||
else
|
||||
nv3->nvbase.svga.read_bank = nv3->nvbase.cio_read_bank << 13; // extended bank numbers
|
||||
break;
|
||||
case NV3_CRTC_REGISTER_WRITE_BANK:
|
||||
nv3->nvbase.cio_write_bank = val;
|
||||
if (nv3->nvbase.svga.chain4)
|
||||
nv3->nvbase.svga.write_bank = nv3->nvbase.cio_write_bank << 15;
|
||||
else
|
||||
nv3->nvbase.svga.write_bank = nv3->nvbase.cio_write_bank << 13;
|
||||
break;
|
||||
case NV3_CRTC_REGISTER_RMA:
|
||||
nv3->pbus.rma.mode = val & NV3_CRTC_REGISTER_RMA_MODE_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
svga_out(addr, val, &nv3->nvbase.svga);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nv3_draw_cursor(svga_t* svga, int32_t drawline)
|
||||
{
|
||||
nv_log("nv3_draw_cursor drawline=0x%04x", drawline);
|
||||
}
|
||||
|
||||
// Initialise the MMIO mappings
|
||||
void nv3_init_mappings_mmio()
|
||||
{
|
||||
nv_log("NV3: Initialising 32MB MMIO area\n");
|
||||
|
||||
// 0x0 - 1000000: regs
|
||||
// 0x1000000-2000000
|
||||
|
||||
// initialize the mmio mapping
|
||||
mem_mapping_add(&nv3->nvbase.mmio_mapping, 0, 0,
|
||||
nv3_mmio_read8,
|
||||
nv3_mmio_read16,
|
||||
nv3_mmio_read32,
|
||||
nv3_mmio_write8,
|
||||
nv3_mmio_write16,
|
||||
nv3_mmio_write32,
|
||||
NULL, MEM_MAPPING_EXTERNAL, nv3);
|
||||
|
||||
// initialize the mmio mapping
|
||||
mem_mapping_add(&nv3->nvbase.ramin_mapping, 0, 0,
|
||||
nv3_ramin_read8,
|
||||
nv3_ramin_read16,
|
||||
nv3_ramin_read32,
|
||||
nv3_ramin_write8,
|
||||
nv3_ramin_write16,
|
||||
nv3_ramin_write32,
|
||||
NULL, MEM_MAPPING_EXTERNAL, nv3);
|
||||
|
||||
|
||||
mem_mapping_add(&nv3->nvbase.ramin_mapping_mirror, 0, 0,
|
||||
nv3_ramin_read8,
|
||||
nv3_ramin_read16,
|
||||
nv3_ramin_read32,
|
||||
nv3_ramin_write8,
|
||||
nv3_ramin_write16,
|
||||
nv3_ramin_write32,
|
||||
NULL, MEM_MAPPING_EXTERNAL, nv3);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void nv3_init_mappings_svga()
|
||||
{
|
||||
nv_log("NV3: Initialising SVGA core memory mapping\n");
|
||||
|
||||
// setup the svga mappings
|
||||
mem_mapping_set(&nv3->nvbase.framebuffer_mapping, 0, 0,
|
||||
svga_read_linear,
|
||||
svga_readw_linear,
|
||||
svga_readl_linear,
|
||||
svga_write_linear,
|
||||
svga_writew_linear,
|
||||
svga_writel_linear,
|
||||
NULL, 0, &nv3->nvbase.svga);
|
||||
|
||||
// the SVGA/LFB mapping is also mirrored
|
||||
mem_mapping_set(&nv3->nvbase.framebuffer_mapping_mirror, 0, 0,
|
||||
svga_read_linear,
|
||||
svga_readw_linear,
|
||||
svga_readl_linear,
|
||||
svga_write_linear,
|
||||
svga_writew_linear,
|
||||
svga_writel_linear,
|
||||
NULL, 0, &nv3->nvbase.svga);
|
||||
|
||||
io_sethandler(0x03c0, 0x0020,
|
||||
nv3_svga_in, NULL, NULL,
|
||||
nv3_svga_out, NULL, NULL,
|
||||
nv3);
|
||||
}
|
||||
|
||||
void nv3_init_mappings()
|
||||
{
|
||||
nv3_init_mappings_mmio();
|
||||
nv3_init_mappings_svga();
|
||||
}
|
||||
|
||||
// Updates the mappings after initialisation.
|
||||
void nv3_update_mappings()
|
||||
{
|
||||
|
||||
// setting this to 0 doesn't seem to disable it, based on the datasheet
|
||||
|
||||
nv_log("\nMemory Mapping Config Change:\n");
|
||||
|
||||
(nv3->pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) ? nv_log("Enable I/O\n") : nv_log("Disable I/O\n");
|
||||
|
||||
io_removehandler(0x03c0, 0x0020,
|
||||
nv3_svga_in, NULL, NULL,
|
||||
nv3_svga_out, NULL, NULL,
|
||||
nv3);
|
||||
|
||||
if (nv3->pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
||||
io_sethandler(0x03c0, 0x0020,
|
||||
nv3_svga_in, NULL, NULL,
|
||||
nv3_svga_out, NULL, NULL,
|
||||
nv3);
|
||||
|
||||
// turn off bar0 and bar1 by defualt
|
||||
mem_mapping_disable(&nv3->nvbase.mmio_mapping);
|
||||
mem_mapping_disable(&nv3->nvbase.framebuffer_mapping);
|
||||
mem_mapping_disable(&nv3->nvbase.framebuffer_mapping_mirror);
|
||||
mem_mapping_disable(&nv3->nvbase.ramin_mapping);
|
||||
mem_mapping_disable(&nv3->nvbase.ramin_mapping_mirror);
|
||||
|
||||
if (!(nv3->pci_config.pci_regs[PCI_REG_COMMAND]) & PCI_COMMAND_MEM)
|
||||
{
|
||||
nv_log("NV3: The memory was turned off, not much is going to happen.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mem_mapping_enable(&nv3->nvbase.mmio_mapping);
|
||||
mem_mapping_enable(&nv3->nvbase.framebuffer_mapping);
|
||||
mem_mapping_enable(&nv3->nvbase.framebuffer_mapping_mirror);
|
||||
mem_mapping_enable(&nv3->nvbase.ramin_mapping);
|
||||
mem_mapping_enable(&nv3->nvbase.ramin_mapping_mirror);
|
||||
|
||||
// first map bar0
|
||||
|
||||
nv_log("NV3: BAR0 (MMIO Base) = 0x%08x\n", nv3->nvbase.bar0_mmio_base);
|
||||
|
||||
//mem_mapping_enable(&nv3->nvbase.mmio_mapping); // should have no effect if already enabled
|
||||
|
||||
mem_mapping_set_addr(&nv3->nvbase.mmio_mapping, nv3->nvbase.bar0_mmio_base, NV3_MMIO_SIZE);
|
||||
|
||||
|
||||
// if this breaks anything, remove it
|
||||
// skeptical that 0 is used to disable...
|
||||
nv_log("NV3: BAR1 (Linear Framebuffer / NV_USER Base & RAMIN) = 0x%08x\n", nv3->nvbase.bar1_lfb_base);
|
||||
|
||||
// this is likely mirrored
|
||||
// 4x on 2mb cards
|
||||
// 2x on 4mb cards
|
||||
// and not at all on 8mb
|
||||
mem_mapping_enable(&nv3->nvbase.framebuffer_mapping);
|
||||
mem_mapping_enable(&nv3->nvbase.framebuffer_mapping_mirror);
|
||||
mem_mapping_enable(&nv3->nvbase.ramin_mapping);
|
||||
mem_mapping_enable(&nv3->nvbase.ramin_mapping_mirror);
|
||||
|
||||
mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping, nv3->nvbase.bar1_lfb_base, NV3_MMIO_SIZE);
|
||||
// 4MB VRAM memory map:
|
||||
// LFB_BASE+VRAM_SIZE=RAMIN Mirror(?) 0x1400000 (VERIFY PCBOX)
|
||||
// LFB_BASE+VRAM_SIZE*2=LFB Mirror(?) 0x1800000
|
||||
// LFB_BASE+VRAM_SIZE*3=Definitely RAMIN (then it ends, the total ram space is 16mb) 0x1C00000
|
||||
mem_mapping_set_addr(&nv3->nvbase.ramin_mapping_mirror, nv3->nvbase.bar1_lfb_base + VRAM_SIZE_4MB, VRAM_SIZE_4MB);
|
||||
mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping_mirror, nv3->nvbase.bar1_lfb_base + (VRAM_SIZE_4MB * 2), VRAM_SIZE_4MB);
|
||||
mem_mapping_set_addr(&nv3->nvbase.ramin_mapping, nv3->nvbase.bar1_lfb_base + (VRAM_SIZE_4MB * 3), VRAM_SIZE_4MB);
|
||||
// TODO: RAMIN and its mirror
|
||||
|
||||
// Did we change the banked SVGA mode?
|
||||
switch (nv3->nvbase.svga.gdcreg[0x06] & 0x0c)
|
||||
{
|
||||
case NV3_CRTC_BANKED_128K_A0000:
|
||||
nv_log("NV3: SVGA Banked Mode = 128K @ A0000h\n");
|
||||
mem_mapping_set_addr(&nv3->nvbase.svga.mapping, 0xA0000, 0x20000); // 128kb @ 0xA0000
|
||||
nv3->nvbase.svga.banked_mask = 0x1FFFF;
|
||||
break;
|
||||
case NV3_CRTC_BANKED_64K_A0000:
|
||||
nv_log("NV3: SVGA Banked Mode = 64K @ A0000h\n");
|
||||
mem_mapping_set_addr(&nv3->nvbase.svga.mapping, 0xA0000, 0x10000); // 64kb @ 0xA0000
|
||||
nv3->nvbase.svga.banked_mask = 0xFFFF;
|
||||
break;
|
||||
case NV3_CRTC_BANKED_32K_B0000:
|
||||
nv_log("NV3: SVGA Banked Mode = 32K @ B0000h\n");
|
||||
mem_mapping_set_addr(&nv3->nvbase.svga.mapping, 0xB0000, 0x8000); // 32kb @ 0xB0000
|
||||
nv3->nvbase.svga.banked_mask = 0x7FFF;
|
||||
break;
|
||||
case NV3_CRTC_BANKED_32K_B8000:
|
||||
nv_log("NV3: SVGA Banked Mode = 32K @ B8000h\n");
|
||||
mem_mapping_set_addr(&nv3->nvbase.svga.mapping, 0xB8000, 0x8000); // 32kb @ 0xB8000
|
||||
nv3->nvbase.svga.banked_mask = 0x7FFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Init code
|
||||
//
|
||||
void* nv3_init(const device_t *info)
|
||||
{
|
||||
nv_log("NV3: initialising core\n");
|
||||
|
||||
// currently using ELSA VICTORY Erazor Ver. 1.54.03 [WD/VBE30/DDC2B/DPMS]
|
||||
// ELSA VICTORY Erazor Ver. 1.55.00 [WD/VBE30/DDC2B/DPMS] seems to be broken :(
|
||||
|
||||
int32_t err = rom_init(&nv3->nvbase.vbios, NV3_VBIOS_ERAZOR_V15403, 0xC0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
if (err)
|
||||
nv_log("NV3: failed to load VBIOS err=%d\n", err);
|
||||
else
|
||||
nv_log("NV3: Successfully loaded VBIOS %s\n", NV3_VBIOS_ERAZOR_V15403);
|
||||
|
||||
// set up the bus and start setting up SVGA core
|
||||
if (nv3->nvbase.bus_generation == nv_bus_pci)
|
||||
{
|
||||
nv_log("NV3: using PCI bus\n");
|
||||
|
||||
pci_add_card(PCI_ADD_NORMAL, nv3_pci_read, nv3_pci_write, NULL, &nv3->nvbase.pci_slot);
|
||||
|
||||
svga_init(&nv3_device_pci, &nv3->nvbase.svga, nv3, VRAM_SIZE_4MB,
|
||||
nv3_recalc_timings, nv3_svga_in, nv3_svga_out, nv3_draw_cursor, NULL);
|
||||
}
|
||||
else if (nv3->nvbase.bus_generation == nv_bus_agp_1x)
|
||||
{
|
||||
nv_log("NV3: using AGP 1X bus\n");
|
||||
|
||||
pci_add_card(PCI_ADD_AGP, nv3_pci_read, nv3_pci_write, NULL, &nv3->nvbase.pci_slot);
|
||||
|
||||
svga_init(&nv3_device_agp, &nv3->nvbase.svga, nv3, VRAM_SIZE_4MB,
|
||||
nv3_recalc_timings, nv3_svga_in, nv3_svga_out, nv3_draw_cursor, NULL);
|
||||
}
|
||||
|
||||
// set vram
|
||||
nv_log("NV3: VRAM=%d bytes\n", nv3->nvbase.svga.vram_max);
|
||||
|
||||
// init memory mappings
|
||||
nv3_init_mappings();
|
||||
|
||||
// make us actually exist
|
||||
nv3->pci_config.int_line = 0xFF; // per datasheet
|
||||
nv3->pci_config.pci_regs[PCI_REG_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEM;
|
||||
|
||||
// svga is done, so now initialise the real gpu
|
||||
nv_log("NV3: Initialising GPU core...\n");
|
||||
|
||||
nv3_pextdev_init(); // Initialise Straps
|
||||
nv3_pmc_init(); // Initialise Master Control
|
||||
nv3_pbus_init(); // Initialise Bus (the 128 part of riva)
|
||||
nv3_pfb_init(); // Initialise Framebuffer Interface
|
||||
nv3_pramdac_init(); // Initialise RAMDAC (CLUT, final pixel presentation etc)
|
||||
nv3_pfifo_init(); // Initialise FIFO for graphics object submission
|
||||
nv3_pgraph_init(); // Initialise accelerated graphics engine
|
||||
nv3_ptimer_init(); // Initialise programmable interval timer
|
||||
nv3_pvideo_init(); // Initialise video overlay engines
|
||||
|
||||
return nv3;
|
||||
}
|
||||
|
||||
// This function simply allocates ram and sets the bus to pci before initialising.
|
||||
void* nv3_init_pci(const device_t* info)
|
||||
{
|
||||
nv3 = (nv3_t*)calloc(1, sizeof(nv3_t));
|
||||
nv3->nvbase.bus_generation = nv_bus_pci;
|
||||
nv3_init(info);
|
||||
}
|
||||
|
||||
// This function simply allocates ram and sets the bus to agp before initialising.
|
||||
void* nv3_init_agp(const device_t* info)
|
||||
{
|
||||
nv3 = (nv3_t*)calloc(1, sizeof(nv3_t));
|
||||
nv3->nvbase.bus_generation = nv_bus_agp_1x;
|
||||
nv3_init(info);
|
||||
}
|
||||
|
||||
// NV3 (RIVA 128)
|
||||
// PCI
|
||||
// 2MB or 4MB VRAM
|
||||
const device_t nv3_device_pci =
|
||||
{
|
||||
.name = "NVidia RIVA 128 (NV3) PCI",
|
||||
.internal_name = "nv3",
|
||||
.flags = DEVICE_PCI,
|
||||
.local = 0,
|
||||
.init = nv3_init_pci,
|
||||
.close = nv3_close,
|
||||
.speed_changed = nv3_speed_changed,
|
||||
.force_redraw = nv3_force_redraw
|
||||
};
|
||||
|
||||
// NV3 (RIVA 128)
|
||||
// AGP
|
||||
// 2MB or 4MB VRAM
|
||||
const device_t nv3_device_agp =
|
||||
{
|
||||
.name = "NVidia RIVA 128 (NV3) AGP",
|
||||
.internal_name = "nv3_agp",
|
||||
.flags = DEVICE_AGP,
|
||||
.local = 0,
|
||||
.init = nv3_init_agp,
|
||||
.close = nv3_close,
|
||||
.speed_changed = nv3_speed_changed,
|
||||
.force_redraw = nv3_force_redraw
|
||||
};
|
||||
198
src/video/nv/nv3/nv3_core_arbiter.c
Normal file
198
src/video/nv/nv3/nv3_core_arbiter.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* The insane NV3 MMIO arbiter.
|
||||
* Writes to ALL sections of the GPU based on the write position
|
||||
* All writes are internally considered to be 32-bit! Be careful...
|
||||
*
|
||||
* Also handles interrupt dispatch
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 starfrost
|
||||
*/
|
||||
|
||||
// STANDARD NV3 includes
|
||||
#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>
|
||||
|
||||
// Gets a register...
|
||||
// move this somewhere else when we have more models
|
||||
nv_register_t* nv_get_register(uint32_t address, nv_register_t* register_list, uint32_t num_regs)
|
||||
{
|
||||
for (int32_t reg_num = 0; reg_num < num_regs; reg_num++)
|
||||
{
|
||||
if (register_list[reg_num].address == NV_REG_LIST_END)
|
||||
break; //unimplemented
|
||||
|
||||
if (register_list[reg_num].address == address)
|
||||
return ®ister_list[reg_num];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Arbitrates an MMIO read
|
||||
uint32_t nv3_mmio_arbitrate_read(uint32_t address)
|
||||
{
|
||||
uint32_t ret = 0x00;
|
||||
|
||||
// note: some registers are byte aligned not dword aligned
|
||||
// only very few are though, so they can be handled specially, using the register list most likely
|
||||
address &= 0xFFFFFC;
|
||||
|
||||
// gigantic set of if statements to send the write to the right subsystem
|
||||
if (address >= NV3_PMC_START && address <= NV3_PMC_END)
|
||||
ret = nv3_pmc_read(address);
|
||||
else if (address >= NV3_CIO_START && address <= NV3_CIO_END)
|
||||
ret = nv3_cio_read(address);
|
||||
else if (address >= NV3_PBUS_PCI_START && address <= NV3_PBUS_PCI_END)
|
||||
ret = nv3_pci_read(0x00, address & 0xFF, NULL);
|
||||
else if (address >= NV3_PBUS_START && address <= NV3_PBUS_END)
|
||||
ret = nv3_pbus_read(address);
|
||||
else if (address >= NV3_PFB_START && address <= NV3_PFB_END)
|
||||
ret = nv3_pfb_read(address);
|
||||
else if (address >= NV3_PRM_START && address <= NV3_PRM_END)
|
||||
ret = nv3_prm_read(address);
|
||||
else if (address >= NV3_PRMIO_START && address <= NV3_PRMIO_END)
|
||||
ret = nv3_prmio_read(address);
|
||||
else if (address >= NV3_PTIMER_START && address <= NV3_PTIMER_END)
|
||||
ret = nv3_ptimer_read(address);
|
||||
else if (address >= NV3_PFB_START && address <= NV3_PFB_END)
|
||||
ret = nv3_pfb_read(address);
|
||||
else if (address >= NV3_PEXTDEV_START && address <= NV3_PEXTDEV_END)
|
||||
ret = nv3_pextdev_read(address);
|
||||
else if (address >= NV3_PROM_START && address <= NV3_PROM_END)
|
||||
ret = nv3_prom_read(address);
|
||||
else if (address >= NV3_PALT_START && address <= NV3_PALT_END)
|
||||
ret = nv3_palt_read(address);
|
||||
else if (address >= NV3_PME_START && address <= NV3_PME_END)
|
||||
ret = nv3_pme_read(address);
|
||||
else if (address >= NV3_PGRAPH_START && address <= NV3_PGRAPH_REAL_END) // what we're actually doing here determined by nv3_pgraph_* func
|
||||
ret = nv3_pgraph_read(address);
|
||||
else if (address >= NV3_PRMCIO_START && address <= NV3_PRMCIO_END)
|
||||
ret = nv3_prmcio_read(address);
|
||||
else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END)
|
||||
ret = nv3_pvideo_read(address);
|
||||
else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END)
|
||||
ret = nv3_pramdac_read(address);
|
||||
else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END)
|
||||
ret = nv3_vram_read(address);
|
||||
else if (address >= NV3_USER_START && address <= NV3_USER_END)
|
||||
ret = nv3_user_read(address);
|
||||
else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END)
|
||||
ret = nv3_pramin_read(address); // RAMHT, RAMFC, RAMRO etc dettermined by nv3_ramin_* function
|
||||
else
|
||||
{
|
||||
nv_log("NV3: MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
nv_log("NV3: MMIO read, 0x%08x <- 0x%08x\n", ret, address);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
// note: some registers are byte aligned not dword aligned
|
||||
// only very few are though, so they can be handled specially, using the register list most likely
|
||||
address &= 0xFFFFFC;
|
||||
|
||||
// gigantic set of if statements to send the write to the right subsystem
|
||||
if (address >= NV3_PMC_START && address <= NV3_PMC_END)
|
||||
nv3_pmc_write(address, value);
|
||||
else if (address >= NV3_CIO_START && address <= NV3_CIO_END)
|
||||
nv3_cio_write(address, value);
|
||||
else if (address >= NV3_PBUS_PCI_START && address <= NV3_PBUS_PCI_END) // PCI mirrored at 0x1800 in MMIO
|
||||
nv3_pci_write(0x00, address & 0xFF, value, NULL); // priv does not matter
|
||||
else if (address >= NV3_PBUS_START && address <= NV3_PBUS_END)
|
||||
nv3_pbus_write(address, value);
|
||||
else if (address >= NV3_PFIFO_START && address <= NV3_PFIFO_END)
|
||||
nv3_pfifo_write(address, value);
|
||||
else if (address >= NV3_PRM_START && address <= NV3_PRM_END)
|
||||
nv3_prm_write(address, value);
|
||||
else if (address >= NV3_PRMIO_START && address <= NV3_PRMIO_END)
|
||||
nv3_prmio_write(address, value);
|
||||
else if (address >= NV3_PTIMER_START && address <= NV3_PTIMER_END)
|
||||
nv3_ptimer_write(address, value);
|
||||
else if (address >= NV3_PFB_START && address <= NV3_PFB_END)
|
||||
nv3_pfb_write(address, value);
|
||||
else if (address >= NV3_PEXTDEV_START && address <= NV3_PEXTDEV_END)
|
||||
nv3_pextdev_write(address, value);
|
||||
else if (address >= NV3_PROM_START && address <= NV3_PROM_END)
|
||||
nv3_prom_write(address, value);
|
||||
else if (address >= NV3_PALT_START && address <= NV3_PALT_END)
|
||||
nv3_palt_write(address, value);
|
||||
else if (address >= NV3_PME_START && address <= NV3_PME_END)
|
||||
nv3_pme_write(address, value);
|
||||
else if (address >= NV3_PGRAPH_START && address <= NV3_PGRAPH_REAL_END) // what we're actually doing here is determined by the nv3_pgraph_* functions
|
||||
nv3_pgraph_write(address, value);
|
||||
else if (address >= NV3_PRMCIO_START && address <= NV3_PRMCIO_END)
|
||||
nv3_prmcio_write(address, value);
|
||||
else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END)
|
||||
nv3_pvideo_write(address, value);
|
||||
else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END)
|
||||
nv3_pramdac_write(address, value);
|
||||
else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END)
|
||||
nv3_vram_write(address, value);
|
||||
else if (address >= NV3_USER_START && address <= NV3_USER_END)
|
||||
nv3_user_write(address, value);
|
||||
else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END)
|
||||
nv3_pramin_write(address, value); // RAMHT, RAMFC, RAMRO etc is determined by the nv3_ramin_* functions
|
||||
else
|
||||
{
|
||||
nv_log("NV3: MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x\n", address);
|
||||
return;
|
||||
}
|
||||
|
||||
nv_log("NV3: MMIO write, 0x%08x -> 0x%08x\n", value, address);
|
||||
}
|
||||
|
||||
|
||||
// //
|
||||
// ******* DUMMY FUNCTIONS FOR UNIMPLEMENTED SUBSYSTEMS ******* //
|
||||
// //
|
||||
|
||||
// Read and Write functions for GPU subsystems
|
||||
// Remove the ones that aren't used here eventually, have all of htem for now
|
||||
uint32_t nv3_cio_read(uint32_t address) { return 0; };
|
||||
void nv3_cio_write(uint32_t address, uint32_t value) {};
|
||||
uint32_t nv3_prm_read(uint32_t address) { return 0; };
|
||||
void nv3_prm_write(uint32_t address, uint32_t value) {};
|
||||
uint32_t nv3_prmio_read(uint32_t address) { return 0; };
|
||||
void nv3_prmio_write(uint32_t address, uint32_t value) {};
|
||||
uint32_t nv3_ptimer_read(uint32_t address) { return 0; };
|
||||
void nv3_ptimer_write(uint32_t address, uint32_t value) {};
|
||||
uint32_t nv3_prom_read(uint32_t address) { return 0; };
|
||||
void nv3_prom_write(uint32_t address, uint32_t value) {};
|
||||
uint32_t nv3_palt_read(uint32_t address) { return 0; };
|
||||
void nv3_palt_write(uint32_t address, uint32_t value) {};
|
||||
|
||||
// TODO: PGRAPH class registers
|
||||
uint32_t nv3_prmcio_read(uint32_t address) { return 0; };
|
||||
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) {};
|
||||
uint32_t nv3_pramin_read(uint32_t address) { return 0; };
|
||||
void nv3_pramin_write(uint32_t address, uint32_t value) {};
|
||||
0
src/video/nv/nv3/nv3_interrupt.c
Normal file
0
src/video/nv/nv3/nv3_interrupt.c
Normal file
249
src/video/nv/nv3/subsystems/nv3_pbus.c
Normal file
249
src/video/nv/nv3/subsystems/nv3_pbus.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 PBUS: 128-bit unified bus
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email dataess ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// NV3 PBUS RMA - Real Mode Access for VBIOS
|
||||
// This basically works like a shifter, you write one byte at a time from [0x3d0...0x3d3] and it shifts it in to build a 32-bit MMIO address...
|
||||
// Putting this in pbus because imo it makes the most sense (related to memory access/memory interface)
|
||||
|
||||
nv_register_t pbus_registers[] = {
|
||||
{ NV3_PBUS_INTR, "PBUS - Interrupt Status", NULL, NULL},
|
||||
{ NV3_PBUS_INTR_EN, "PBUS - Interrupt Enable", NULL, NULL,},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
void nv3_pbus_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PBUS...");
|
||||
|
||||
nv_log("Done\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pbus_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pbus_registers, sizeof(pbus_registers)/sizeof(pbus_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PBUS Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PBUS_INTR:
|
||||
return nv3->pbus.interrupt_status;
|
||||
break;
|
||||
case NV3_PBUS_INTR_EN:
|
||||
return nv3->pbus.interrupt_enable;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pbus_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pbus_registers, sizeof(pbus_registers)/sizeof(pbus_registers[0]));
|
||||
|
||||
nv_log("NV3: PBUS Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
// Interrupt registers
|
||||
// Interrupt state:
|
||||
// Bit 0 - PCI Bus Error
|
||||
case NV3_PBUS_INTR:
|
||||
nv3->pbus.interrupt_status &= ~value;
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PBUS_INTR_EN:
|
||||
nv3->pbus.interrupt_enable = value & 0x00000001;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t nv3_pbus_rma_read(uint16_t addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
uint32_t real_final_address;
|
||||
uint8_t ret;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
// signature so you know reads work
|
||||
case 0x00:
|
||||
ret = NV3_RMA_SIGNATURE_MSB;
|
||||
break;
|
||||
case 0x01:
|
||||
ret = NV3_RMA_SIGNATURE_BYTE2;
|
||||
break;
|
||||
case 0x02:
|
||||
ret = NV3_RMA_SIGNATURE_BYTE1;
|
||||
break;
|
||||
case 0x03:
|
||||
ret = NV3_RMA_SIGNATURE_LSB;
|
||||
break;
|
||||
case 0x08 ... 0x0B:
|
||||
// reads must be dword aligned
|
||||
real_final_address = (nv3->pbus.rma.addr + (addr & 0x03));
|
||||
|
||||
if (nv3->pbus.rma.addr < NV3_MMIO_SIZE)
|
||||
ret = nv3_mmio_read8(real_final_address, NULL);
|
||||
else
|
||||
{
|
||||
// ABOVE CODE IS TEMPORARY UNTIL PNVM EXISTS!!!!!
|
||||
// would svga->fast work?
|
||||
nv3->nvbase.svga.chain4 = true;
|
||||
nv3->nvbase.svga.packed_chain4 = true;
|
||||
ret = svga_read_linear((real_final_address - NV3_MMIO_SIZE) & (VRAM_SIZE_4MB - 1), &nv3->nvbase.svga);
|
||||
nv3->nvbase.svga.chain4 = false;
|
||||
nv3->nvbase.svga.packed_chain4 = false;
|
||||
}
|
||||
|
||||
// log current location for vbios RE
|
||||
nv_log("NV3: MMIO Real Mode Access read, initial address=0x%04x final RMA MMIO address=0x%08x data=0x%08x\n",
|
||||
addr, real_final_address, ret);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Implements a 32-bit write using 16 bit port number
|
||||
void nv3_pbus_rma_write(uint16_t addr, uint8_t val)
|
||||
{
|
||||
uint8_t ret = 0x00;
|
||||
|
||||
// addresses are in reality 8bit so just mask it to be safe
|
||||
addr &= 0xFF;
|
||||
|
||||
// format:
|
||||
// 0x00 ID
|
||||
// 0x04 Pointer to data
|
||||
// 0x08 Data port(?)
|
||||
// 0x0B Data - 32bit. SENT IN THE RIGHT ORDER FOR ONCE WAHOO!
|
||||
// 0x10 Increment (?) data - implemented the same as data for now
|
||||
|
||||
if (addr < 0x08)
|
||||
{
|
||||
switch (addr % 0x04)
|
||||
{
|
||||
case 0x00: // lowest byte
|
||||
nv3->pbus.rma.addr &= ~0xff;
|
||||
nv3->pbus.rma.addr |= val;
|
||||
break;
|
||||
case 0x01: // 2nd highest byte
|
||||
nv3->pbus.rma.addr &= ~0xff00;
|
||||
nv3->pbus.rma.addr |= (val << 8);
|
||||
break;
|
||||
case 0x02: // 3rd highest byte
|
||||
nv3->pbus.rma.addr &= ~0xff0000;
|
||||
nv3->pbus.rma.addr |= (val << 16);
|
||||
break;
|
||||
case 0x03: // 4th highest byte
|
||||
nv3->pbus.rma.addr &= ~0xff000000;
|
||||
nv3->pbus.rma.addr |= (val << 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Data to send to MMIO
|
||||
else
|
||||
{
|
||||
switch (addr % 0x04)
|
||||
{
|
||||
case 0x00: // lowest byte
|
||||
nv3->pbus.rma.data &= ~0xff;
|
||||
nv3->pbus.rma.data |= val;
|
||||
break;
|
||||
case 0x01: // 2nd highest byte
|
||||
nv3->pbus.rma.data &= ~0xff00;
|
||||
nv3->pbus.rma.data |= (val << 8);
|
||||
break;
|
||||
case 0x02: // 3rd highest byte
|
||||
nv3->pbus.rma.data &= ~0xff0000;
|
||||
nv3->pbus.rma.data |= (val << 16);
|
||||
break;
|
||||
case 0x03: // 4th highest byte
|
||||
nv3->pbus.rma.data &= ~0xff000000;
|
||||
nv3->pbus.rma.data |= (val << 24);
|
||||
|
||||
nv_log("NV3: MMIO Real Mode Access write transaction complete, initial address=0x%04x final RMA MMIO address=0x%08x data=0x%08x\n",
|
||||
addr, nv3->pbus.rma.addr, nv3->pbus.rma.data);
|
||||
|
||||
if (nv3->pbus.rma.addr < NV3_MMIO_SIZE)
|
||||
nv3_mmio_write32(nv3->pbus.rma.addr, nv3->pbus.rma.data, NULL);
|
||||
else // failsafe code, i don't think you will ever write outside of VRAM?
|
||||
{
|
||||
nv3->nvbase.svga.chain4 = true;
|
||||
nv3->nvbase.svga.packed_chain4 = true;
|
||||
svga_writel_linear((nv3->pbus.rma.addr - NV3_MMIO_SIZE) & (VRAM_SIZE_4MB - 1), nv3->pbus.rma.data, &nv3->nvbase.svga);
|
||||
nv3->nvbase.svga.chain4 = false;
|
||||
nv3->nvbase.svga.packed_chain4 = false;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr & 0x10)
|
||||
nv3->pbus.rma.addr += 0x04; // Alignment
|
||||
}
|
||||
31
src/video/nv/nv3/subsystems/nv3_pbus_dma.c
Normal file
31
src/video/nv/nv3/subsystems/nv3_pbus_dma.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 PBUS DMA: DMA Engine
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
149
src/video/nv/nv3/subsystems/nv3_pextdev.c
Normal file
149
src/video/nv/nv3/subsystems/nv3_pextdev.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 PEXTDEV - External Devices
|
||||
* Including straps
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
void nv3_pextdev_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PEXTDEV....\n");
|
||||
|
||||
// Set the chip straps
|
||||
// Make these configurable in the future...
|
||||
|
||||
// Current settings
|
||||
// AGP2X Disabled
|
||||
// TV Mode NTSC
|
||||
// Crystal 13.5 Mhz
|
||||
// Bus width 128-Bit (some gpus were sold as 64bit for cost reduction)
|
||||
//
|
||||
|
||||
nv_log("NV3: Initialising straps...\n");
|
||||
|
||||
nv3->pextdev.straps =
|
||||
(NV3_PSTRAPS_AGP2X_DISABLED << NV3_PSTRAPS_AGP2X) |
|
||||
(NV3_PSTRAPS_TVMODE_NTSC << NV3_PSTRAPS_TVMODE) |
|
||||
(NV3_PSTRAPS_CRYSTAL_13500K << NV3_PSTRAPS_CRYSTAL);
|
||||
|
||||
// figure out the bus
|
||||
if (nv3->nvbase.bus_generation == nv_bus_pci)
|
||||
nv3->pextdev.straps |= (NV3_PSTRAPS_BUS_TYPE_PCI << NV3_PSTRAPS_BUS_TYPE);
|
||||
else
|
||||
nv3->pextdev.straps |= (NV3_PSTRAPS_BUS_TYPE_AGP << NV3_PSTRAPS_BUS_TYPE);
|
||||
|
||||
// now the lower bits
|
||||
nv3->pextdev.straps |=
|
||||
(NV3_PSTRAPS_BUS_WIDTH_128BIT << NV3_PSTRAPS_BUS_WIDTH) |
|
||||
(NV3_PSTRAPS_BIOS_PRESENT << NV3_PSTRAPS_BIOS) |
|
||||
(NV3_PSTRAPS_BUS_SPEED_66MHZ << NV3_PSTRAPS_BUS_SPEED);
|
||||
|
||||
nv_log("NV3: Straps = 0x%04x\n", nv3->pextdev.straps);
|
||||
nv_log("NV3: Initialising PEXTDEV: Done\n");
|
||||
}
|
||||
|
||||
//
|
||||
// ****** PEXTDEV register list START ******
|
||||
//
|
||||
|
||||
nv_register_t pextdev_registers[] = {
|
||||
{ NV3_PSTRAPS, "Straps - Chip Configuration", NULL, NULL },
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL }, // sentinel value
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// ****** Read/Write functions start ******
|
||||
//
|
||||
|
||||
uint32_t nv3_pextdev_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pextdev_registers, sizeof(pextdev_registers)/sizeof(pextdev_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
// special consideration for straps
|
||||
if (address == NV3_PSTRAPS)
|
||||
{
|
||||
nv_log("NV3: Straps Read (current value=0x%08x)\n", nv3->pextdev.straps);
|
||||
}
|
||||
else
|
||||
{
|
||||
nv_log("NV3: PEXTDEV Read from 0x%08x", address);
|
||||
|
||||
}
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PSTRAPS:
|
||||
return nv3->pextdev.straps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pextdev_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pextdev_registers, sizeof(pextdev_registers)/sizeof(pextdev_registers[0]));
|
||||
|
||||
nv_log("NV3: PEXTDEV Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// special consideration for straps
|
||||
if (address == NV3_PSTRAPS)
|
||||
{
|
||||
nv_log("NV3: Huh? Tried to write to the straps. Something is wrong...\n", nv3->pextdev.straps);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
}
|
||||
}
|
||||
109
src/video/nv/nv3/subsystems/nv3_pfb.c
Normal file
109
src/video/nv/nv3/subsystems/nv3_pfb.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 PFB: Framebuffer
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
nv_register_t pfb_registers[] = {
|
||||
{ NV3_PFB_BOOT, "PFB Boot Config", NULL, NULL},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
void nv3_pfb_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PFB...");
|
||||
|
||||
// initial configuration:
|
||||
// ram 4mb
|
||||
// bus width 128bit
|
||||
// extension ram none (was this ever used?)
|
||||
// ram banks 4 (based on observation of physical RIVA 128 with 4mb, does 1 bank = 1chip?)
|
||||
// twiddle off (check this on a real card once it's actually installed)
|
||||
nv3->pfb.boot = (NV3_PFB_BOOT_RAM_EXTENSION_NONE << (NV3_PFB_BOOT_RAM_EXTENSION)
|
||||
| (NV3_PFB_BOOT_RAM_DATA_TWIDDLE_OFF << NV3_PFB_BOOT_RAM_DATA_TWIDDLE)
|
||||
| (NV3_PFB_BOOT_RAM_BANKS_4 << NV3_PFB_BOOT_RAM_BANKS)
|
||||
| (NV3_PFB_BOOT_RAM_WIDTH_128 << NV3_PFB_BOOT_RAM_WIDTH)
|
||||
| (NV3_PFB_BOOT_RAM_AMOUNT_4MB << NV3_PFB_BOOT_RAM_AMOUNT)
|
||||
);
|
||||
|
||||
nv_log("Done\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pfb_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pfb_registers, sizeof(pfb_registers)/sizeof(pfb_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PFB Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PFB_BOOT:
|
||||
return nv3->pfb.boot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pfb_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pfb_registers, sizeof(pfb_registers)/sizeof(pfb_registers[0]));
|
||||
|
||||
nv_log("NV3: PFB Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
146
src/video/nv/nv3/subsystems/nv3_pfifo.c
Normal file
146
src/video/nv/nv3/subsystems/nv3_pfifo.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 pfifo (FIFO for graphics object submission)
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
|
||||
//
|
||||
// ****** pfifo register list START ******
|
||||
//
|
||||
|
||||
nv_register_t pfifo_registers[] = {
|
||||
{ NV3_PFIFO_INTR, "PFIFO - Interrupt Status", NULL, NULL},
|
||||
{ NV3_PFIFO_INTR_EN, "PFIFO - Interrupt Enable", NULL, NULL,},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
// PFIFO init code
|
||||
void nv3_pfifo_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PFIFO...");
|
||||
|
||||
nv_log("Done!\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pfifo_read(uint32_t address)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement state
|
||||
|
||||
if (!(nv3->pmc.enable >> NV3_PMC_ENABLE_PFIFO)
|
||||
& NV3_PMC_ENABLE_PFIFO_ENABLED)
|
||||
{
|
||||
nv_log("NV3: Repressing PFIFO read. The subsystem is disabled according to pmc_enable, returning 0\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, pfifo_registers, sizeof(pfifo_registers)/sizeof(pfifo_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PFIFO Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Cache Error
|
||||
// Bit 4 - RAMRO Triggered
|
||||
// Bit 8 - RAMRO Overflow (too many invalid dma objects)
|
||||
// Bit 12 - DMA Pusher
|
||||
// Bit 16 - DMA Page Table Entry (pagefault?)
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PFIFO_INTR:
|
||||
return nv3->pfifo.interrupt_status;
|
||||
case NV3_PFIFO_INTR_EN:
|
||||
return nv3->pfifo.interrupt_enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pfifo_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement
|
||||
|
||||
if (!(nv3->pmc.enable >> NV3_PMC_ENABLE_PFIFO)
|
||||
& NV3_PMC_ENABLE_PFIFO_ENABLED)
|
||||
{
|
||||
nv_log("NV3: Repressing PFIFO write. The subsystem is disabled according to pmc_enable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, pfifo_registers, sizeof(pfifo_registers)/sizeof(pfifo_registers[0]));
|
||||
|
||||
nv_log("NV3: pfifo Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Cache Error
|
||||
// Bit 4 - RAMRO Triggered
|
||||
// Bit 8 - RAMRO Overflow (too many invalid dma objects)
|
||||
// Bit 12 - DMA Pusher
|
||||
// Bit 16 - DMA Page Table Entry (pagefault?)
|
||||
case NV3_PFIFO_INTR:
|
||||
nv3->pfifo.interrupt_status &= ~value;
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PFIFO_INTR_EN:
|
||||
nv3->pbus.interrupt_enable = value & 0x00001111;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
151
src/video/nv/nv3/subsystems/nv3_pgraph.c
Normal file
151
src/video/nv/nv3/subsystems/nv3_pgraph.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 PGRAPH (Scene Graph for 2D/3D Accelerated Graphics)
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
|
||||
//
|
||||
// ****** PGRAPH register list START ******
|
||||
//
|
||||
|
||||
void nv3_pgraph_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PGRAPH...");
|
||||
|
||||
nv_log("Done!\n");
|
||||
}
|
||||
|
||||
nv_register_t pgraph_registers[] = {
|
||||
{ NV3_PGRAPH_INTR_0, "PGRAPH Interrupt Status 0", NULL, NULL },
|
||||
{ NV3_PGRAPH_INTR_EN_0, "PGRAPH Interrupt Enable 0", NULL, NULL },
|
||||
{ NV3_PGRAPH_INTR_1, "PGRAPH Interrupt Status 1", NULL, NULL },
|
||||
{ NV3_PGRAPH_INTR_EN_1, "PGRAPH Interrupt Enable 1", NULL, NULL },
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
uint32_t nv3_pgraph_read(uint32_t address)
|
||||
{
|
||||
// before doing anything, check that this is even enabled..
|
||||
|
||||
if (!(nv3->pmc.enable >> NV3_PMC_ENABLE_PGRAPH)
|
||||
& NV3_PMC_ENABLE_PGRAPH_ENABLED)
|
||||
{
|
||||
nv_log("NV3: Repressing PGRAPH read. The subsystem is disabled according to pmc_enable, returning 0\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, pgraph_registers, sizeof(pgraph_registers)/sizeof(pgraph_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PGRAPH Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
//interrupt status and enable regs
|
||||
case NV3_PGRAPH_INTR_0:
|
||||
return nv3->pgraph.interrupt_status_0;
|
||||
case NV3_PGRAPH_INTR_1:
|
||||
return nv3->pgraph.interrupt_status_1;
|
||||
case NV3_PGRAPH_INTR_EN_0:
|
||||
return nv3->pgraph.interrupt_enable_0;
|
||||
case NV3_PGRAPH_INTR_EN_1:
|
||||
return nv3->pgraph.interrupt_enable_1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pgraph_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
if (!(nv3->pmc.enable >> NV3_PMC_ENABLE_PGRAPH)
|
||||
& NV3_PMC_ENABLE_PGRAPH_ENABLED)
|
||||
{
|
||||
nv_log("NV3: Repressing PGRAPH write. The subsystem is disabled according to pmc_enable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, pgraph_registers, sizeof(pgraph_registers)/sizeof(pgraph_registers[0]));
|
||||
|
||||
nv_log("NV3: pgraph Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
//interrupt status and enable regs
|
||||
case NV3_PGRAPH_INTR_0:
|
||||
nv3->pgraph.interrupt_status_0 &= ~value;
|
||||
//we changed interrupt state
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PGRAPH_INTR_1:
|
||||
nv3->pgraph.interrupt_status_1 &= ~value;
|
||||
//we changed interrupt state
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
// Only bits divisible by 4 matter
|
||||
// and only bit0-16 is defined in intr_1
|
||||
case NV3_PGRAPH_INTR_EN_0:
|
||||
nv3->pgraph.interrupt_enable_0 = value & 0x11111111;
|
||||
break;
|
||||
case NV3_PGRAPH_INTR_EN_1:
|
||||
nv3->pgraph.interrupt_enable_1 = value & 0x00011111;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
236
src/video/nv/nv3/subsystems/nv3_pmc.c
Normal file
236
src/video/nv/nv3/subsystems/nv3_pmc.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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 PMC - Master control for the chip
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
|
||||
void nv3_pmc_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PMC....\n");
|
||||
|
||||
nv3->pmc.boot = NV3_BOOT_REG_DEFAULT;
|
||||
|
||||
nv_log("NV3: Initialising PMC: Done\n");
|
||||
}
|
||||
|
||||
//
|
||||
// ****** PMC register list START ******
|
||||
//
|
||||
|
||||
nv_register_t pmc_registers[] = {
|
||||
{ NV3_PMC_BOOT, "PMC: Boot Manufacturing Information", NULL, NULL },
|
||||
{ NV3_PMC_INTERRUPT_STATUS, "PMC: Current Pending Subsystem Interrupts", NULL, NULL},
|
||||
{ NV3_PMC_INTERRUPT_ENABLE, "PMC: Global Interrupt Enable", NULL, NULL,},
|
||||
{ NV3_PMC_ENABLE, "PMC: Global Subsystem Enable", NULL, NULL },
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
uint32_t nv3_pmc_clear_interrupts()
|
||||
{
|
||||
nv_log("NV3: Clearing IRQs\n");
|
||||
pci_set_irq(nv3->nvbase.pci_slot, PCI_INTA, &nv3->nvbase.pci_irq_state);
|
||||
}
|
||||
|
||||
// Handle hardware interrupts
|
||||
// We only clear when we need to, in other functions...
|
||||
uint32_t nv3_pmc_handle_interrupts(bool send_now)
|
||||
{
|
||||
// TODO:
|
||||
// PGRAPH DMA INTR_EN (there is no DMA engine yet)
|
||||
// PRM Real-Mode Compatibility Interrupts
|
||||
|
||||
uint32_t new_intr_value;
|
||||
|
||||
// set the new interrupt value
|
||||
// PAUDIO not used
|
||||
// IF NV3 REV A EMULATION IS ADDED, ADD THIS COMPONENT!
|
||||
|
||||
// the registers are designed to line up so you can enable specific interrupts
|
||||
|
||||
// Check Mediaport interrupts
|
||||
if (nv3->pme.interrupt_status & nv3->pme.interrupt_enable)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PMEDIA_PENDING << NV3_PMC_INTERRUPT_PMEDIA);
|
||||
|
||||
// Check FIFO interrupts
|
||||
if (nv3->pfifo.interrupt_status & nv3->pfifo.interrupt_enable)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PFIFO_PENDING << NV3_PMC_INTERRUPT_PFIFO);
|
||||
|
||||
// PFB interrupt is VBLANK PGRAPH interrupt...what nvidia...clean this up once we verify it
|
||||
if (nv3->pgraph.interrupt_status_0 & (1 << 8))
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PFB_PENDING << NV3_PMC_INTERRUPT_PFB);
|
||||
else if (nv3->pgraph.interrupt_status_0 & ~(1 << 8)) // otherwise PGRAPH-0 interurpt
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PGRAPH0_PENDING << NV3_PMC_INTERRUPT_PGRAPH0);
|
||||
|
||||
// Check second pgraph interrupt register
|
||||
if (nv3->pgraph.interrupt_status_1 & nv3->pgraph.interrupt_enable_1)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PGRAPH1_PENDING << NV3_PMC_INTERRUPT_PGRAPH1);
|
||||
|
||||
// check video overlay interrupts
|
||||
if (nv3->pvideo.interrupt_status & nv3->pvideo.interrupt_enable)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PVIDEO_PENDING << NV3_PMC_INTERRUPT_PVIDEO);
|
||||
|
||||
// check PIT interrupts
|
||||
if (nv3->ptimer.interrupt_status & nv3->ptimer.interrupt_enable)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PTIMER_PENDING << NV3_PMC_INTERRUPT_PTIMER);
|
||||
|
||||
// check bus interrupts
|
||||
if (nv3->pbus.interrupt_status & nv3->pbus.interrupt_enable)
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_PBUS_PENDING << NV3_PMC_INTERRUPT_PBUS);
|
||||
|
||||
// check SW interrupts
|
||||
if (nv3->pmc.interrupt_status & (1 << NV3_PMC_INTERRUPT_SOFTWARE))
|
||||
new_intr_value |= (NV3_PMC_INTERRUPT_SOFTWARE_PENDING << NV3_PMC_INTERRUPT_SOFTWARE);
|
||||
|
||||
nv3->pmc.interrupt_status = new_intr_value;
|
||||
|
||||
// ***TODO: DOes INTR still change if INTR_EN=0???***
|
||||
// If interrupts are disabled don't bother
|
||||
|
||||
if (!nv3->pmc.interrupt_enable)
|
||||
nv3_pmc_clear_interrupts();
|
||||
|
||||
// if we actually need to send the interrupt (i.e. this is a write) send it now
|
||||
if (send_now)
|
||||
{
|
||||
if (!(nv3->pmc.interrupt_status & 0x7FFFFFFF))
|
||||
{
|
||||
if (nv3->pmc.interrupt_enable & NV3_PMC_INTERRUPT_ENABLE_HARDWARE)
|
||||
{
|
||||
nv_log("NV3: Firing hardware-originated interrupt NV3_PMC_INTR_0=0x%08x\n", nv3->pmc.interrupt_status);
|
||||
pci_set_irq(nv3->nvbase.pci_slot, PCI_INTA, &nv3->nvbase.pci_irq_state);
|
||||
}
|
||||
else
|
||||
nv_log("NV3: NOT firing hardware-originated interrupt NV3_PMC_INTR_0=0x%08x, BECAUSE HARDWARE INTERRUPTS ARE DISABLED\n", nv3->pmc.interrupt_status);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nv3->pmc.interrupt_enable & NV3_PMC_INTERRUPT_ENABLE_SOFTWARE)
|
||||
{
|
||||
nv_log("NV3: Firing software-originated interrupt NV3_PMC_INTR_0=0x%08x\n", nv3->pmc.interrupt_status);
|
||||
pci_set_irq(nv3->nvbase.pci_slot, PCI_INTA, &nv3->nvbase.pci_irq_state);
|
||||
}
|
||||
else
|
||||
nv_log("NV3: NOT firing software-originated interrupt NV3_PMC_INTR_0=0x%08x, BECAUSE SOFTWARE INTERRUPTS ARE DISABLED\n", nv3->pmc.interrupt_status);
|
||||
}
|
||||
}
|
||||
|
||||
return nv3->pmc.interrupt_status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// ****** Read/Write functions start ******
|
||||
//
|
||||
|
||||
uint32_t nv3_pmc_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pmc_registers, sizeof(pmc_registers)/sizeof(pmc_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
nv_log("NV3: PMC Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PMC_BOOT:
|
||||
return nv3->pmc.boot;
|
||||
case NV3_PMC_INTERRUPT_STATUS:
|
||||
nv3_pmc_clear_interrupts();
|
||||
|
||||
return nv3_pmc_handle_interrupts(false);
|
||||
case NV3_PMC_INTERRUPT_ENABLE:
|
||||
//TODO: ACTUALLY CHANGE THE INTERRUPT STATE
|
||||
return nv3->pmc.interrupt_enable;
|
||||
case NV3_PMC_ENABLE:
|
||||
return nv3->pmc.enable;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pmc_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pmc_registers, sizeof(pmc_registers)/sizeof(pmc_registers[0]));
|
||||
|
||||
nv_log("NV3: PMC Write 0x%08x -> 0x%08x", value, address);
|
||||
|
||||
// if the register actually exists...
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// ... call its on-write function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
// if it doesn't have one fallback to a switch statement
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PMC_INTERRUPT_STATUS:
|
||||
// this
|
||||
if (!(nv3->pmc.interrupt_status & (NV3_PMC_INTERRUPT_SOFTWARE - 1)))
|
||||
{
|
||||
nv_log("Huh? This is a hardware interrupt...Please use the INTR_EN registers of the GPU subsystem you want to trigger "
|
||||
" an interrupt on, rather than writing to NV3_PMC_INTERRUPT_STATUS (Or this is a bug)...NV3_PMC_INTERRUPT_STATUS=0x%08x)\n", nv3->pmc.interrupt_enable);
|
||||
return;
|
||||
}
|
||||
|
||||
nv3_pmc_handle_interrupts(true);
|
||||
nv3->pmc.interrupt_status = value;
|
||||
break;
|
||||
case NV3_PMC_INTERRUPT_ENABLE:
|
||||
nv3->pmc.interrupt_enable = value;
|
||||
break;
|
||||
case NV3_PMC_ENABLE:
|
||||
nv3->pmc.enable = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
src/video/nv/nv3/subsystems/nv3_pme.c
Normal file
123
src/video/nv/nv3/subsystems/nv3_pme.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 pme: Nvidia Mediaport - External MPEG Decode Interface
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
nv_register_t pme_registers[] = {
|
||||
{ NV3_PME_INTR, "PME - Interrupt Status", NULL, NULL},
|
||||
{ NV3_PME_INTR_EN, "PME - Interrupt Enable", NULL, NULL,},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
void nv3_pme_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PME...");
|
||||
|
||||
nv_log("Done\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pme_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pme_registers, sizeof(pme_registers)/sizeof(pme_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PME Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Image Notifier
|
||||
// Bit 4 - Vertical Blank Interfal Notifier
|
||||
// Bit 8 - Video Notifier
|
||||
// Bit 12 - Audio Notifier
|
||||
// Bit 16 - VMI Notifer
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PME_INTR:
|
||||
return nv3->pme.interrupt_status;
|
||||
case NV3_PME_INTR_EN:
|
||||
return nv3->pme.interrupt_enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pme_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pme_registers, sizeof(pme_registers)/sizeof(pme_registers[0]));
|
||||
|
||||
nv_log("NV3: PME Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Image Notifier
|
||||
// Bit 4 - Vertical Blank Interfal Notifier
|
||||
// Bit 8 - Video Notifier
|
||||
// Bit 12 - Audio Notifier
|
||||
// Bit 16 - VMI Notifer
|
||||
|
||||
case NV3_PME_INTR:
|
||||
nv3->pme.interrupt_status &= ~value;
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PME_INTR_EN:
|
||||
nv3->pme.interrupt_enable = value & 0x00001111;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
307
src/video/nv/nv3/subsystems/nv3_pramdac.c
Normal file
307
src/video/nv/nv3/subsystems/nv3_pramdac.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* 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 bringup and device emulation.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 starfrost
|
||||
*/
|
||||
|
||||
// nv3_pramdac.c: NV3 RAMDAC
|
||||
// Todo: Allow overridability using 68050C register...
|
||||
|
||||
#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>
|
||||
|
||||
void nv3_pramdac_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PRAMDAC\n");
|
||||
|
||||
// defaults, these come from vbios in reality
|
||||
// driver defaults are nonsensical(?), or the algorithm is wrong
|
||||
// munged this to 100mhz for now
|
||||
nv3->pramdac.memory_clock_m = nv3->pramdac.pixel_clock_m = 0x07;
|
||||
nv3->pramdac.memory_clock_n = nv3->pramdac.pixel_clock_n = 0xc8;
|
||||
nv3->pramdac.memory_clock_p = nv3->pramdac.pixel_clock_p = 0x0c;
|
||||
|
||||
nv3_pramdac_set_pixel_clock();
|
||||
nv3_pramdac_set_vram_clock();
|
||||
|
||||
nv_log("NV3: Initialising PRAMDAC: Done\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pramdac_get_vram_clock_register()
|
||||
{
|
||||
// pack into 19 bits
|
||||
// M divisor [7-0]
|
||||
// N divisor [16-8]
|
||||
// P divisor [18-16]
|
||||
return (nv3->pramdac.memory_clock_m << 16) & 0xFF;
|
||||
+ (nv3->pramdac.memory_clock_n << 8) & 0xFF;
|
||||
+ (nv3->pramdac.memory_clock_p) & 0x07; // 0-3
|
||||
}
|
||||
|
||||
uint32_t nv3_pramdac_get_pixel_clock_register()
|
||||
{
|
||||
return (nv3->pramdac.pixel_clock_m << 16) & 0xFF;
|
||||
+ (nv3->pramdac.pixel_clock_n << 8) & 0xFF;
|
||||
+ (nv3->pramdac.pixel_clock_p) & 0x07; // 0-3
|
||||
}
|
||||
|
||||
void nv3_pramdac_set_vram_clock_register(uint32_t value)
|
||||
{
|
||||
nv3->pramdac.memory_clock_m = value & 0xFF;
|
||||
nv3->pramdac.memory_clock_n = (value >> 8) & 0xFF;
|
||||
nv3->pramdac.memory_clock_p = (value >> 16) & 0x07;
|
||||
|
||||
nv3_pramdac_set_vram_clock();
|
||||
}
|
||||
|
||||
void nv3_pramdac_set_pixel_clock_register(uint32_t value)
|
||||
{
|
||||
nv3->pramdac.pixel_clock_m = value & 0xFF;
|
||||
nv3->pramdac.pixel_clock_n = (value >> 8) & 0xFF;
|
||||
nv3->pramdac.pixel_clock_p = (value >> 16) & 0x07;
|
||||
|
||||
nv3_pramdac_set_pixel_clock();
|
||||
}
|
||||
|
||||
void nv3_pramdac_set_vram_clock()
|
||||
{
|
||||
// from driver and vbios source
|
||||
float frequency = 13500000.0f;
|
||||
|
||||
// prevent division by 0
|
||||
if (nv3->pramdac.memory_clock_m == 0)
|
||||
nv3->pramdac.memory_clock_m == 1;
|
||||
else
|
||||
frequency = (frequency * nv3->pramdac.memory_clock_n) / (nv3->pramdac.memory_clock_m << nv3->pramdac.memory_clock_p);
|
||||
|
||||
nv_log("NV3: Memory clock = %.2f MHz\n", frequency / 1000000.0f);
|
||||
}
|
||||
|
||||
void nv3_pramdac_set_pixel_clock()
|
||||
{
|
||||
// frequency divider algorithm from old varcem/86box/pcbox riva driver,
|
||||
// verified by reversing NT drivers v1.50e CalcMNP [symbols] function
|
||||
|
||||
// todo: actually implement it
|
||||
|
||||
// missing section
|
||||
// not really needed.
|
||||
// if (nv3->pfb.boot.clock_crystal == CLOCK_CRYSTAL_13500)
|
||||
// {
|
||||
// freq = 13500000.0f;
|
||||
// }
|
||||
// else
|
||||
//
|
||||
// {
|
||||
// freq = 14318000.0f;
|
||||
// }
|
||||
|
||||
float frequency = 13500000.0f;
|
||||
|
||||
// prevent division by 0
|
||||
if (nv3->pramdac.pixel_clock_m == 0)
|
||||
nv3->pramdac.pixel_clock_m == 1;
|
||||
else
|
||||
frequency = (frequency * nv3->pramdac.pixel_clock_n) / (nv3->pramdac.pixel_clock_m << nv3->pramdac.pixel_clock_p);
|
||||
|
||||
nv3->nvbase.svga.clock = cpuclock / frequency;
|
||||
|
||||
nv_log("NV3: Pixel clock = %.2f MHz\n", frequency / 1000000.0f);
|
||||
}
|
||||
|
||||
//
|
||||
// ****** PRAMDAC register list START ******
|
||||
//
|
||||
|
||||
// NULL means handle in read functions
|
||||
nv_register_t pramdac_registers[] =
|
||||
{
|
||||
{ NV3_PRAMDAC_CLOCK_PIXEL, "PRAMDAC - NV3 GPU Core - Pixel clock", nv3_pramdac_get_pixel_clock_register, nv3_pramdac_set_pixel_clock_register },
|
||||
{ NV3_PRAMDAC_CLOCK_MEMORY, "PRAMDAC - NV3 GPU Core - Memory clock", nv3_pramdac_get_vram_clock_register, nv3_pramdac_set_vram_clock_register },
|
||||
{ NV3_PRAMDAC_COEFF_SELECT, "PRAMDAC - PLL Clock Coefficient Select", NULL, NULL},
|
||||
{ NV3_PRAMDAC_GENERAL_CONTROL, "PRAMDAC - General Control", NULL, NULL },
|
||||
{ NV3_PRAMDAC_VSERR_WIDTH, "PRAMDAC - Vertical Sync Error Width", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VEQU_END, "PRAMDAC - VEqu End", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VBBLANK_END, "PRAMDAC - VBBlank End", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VBLANK_END, "PRAMDAC - Vertical Blanking Interval End", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VBLANK_START, "PRAMDAC - Vertical Blanking Interval Start", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VEQU_START, "PRAMDAC - VEqu Start", NULL, NULL},
|
||||
{ NV3_PRAMDAC_VTOTAL, "PRAMDAC - Total Vertical Lines", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HSYNC_WIDTH, "PRAMDAC - Horizontal Sync Pulse Width", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HBURST_START, "PRAMDAC - Horizontal Burst Signal Start", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HBURST_END, "PRAMDAC - Horizontal Burst Signal Start", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HTOTAL, "PRAMDAC - Total Horizontal Lines", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HEQU_WIDTH, "PRAMDAC - HEqu End", NULL, NULL},
|
||||
{ NV3_PRAMDAC_HSERR_WIDTH, "PRAMDAC - Horizontal Sync Error", NULL, NULL},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
//
|
||||
// ****** Read/Write functions start ******
|
||||
//
|
||||
|
||||
uint32_t nv3_pramdac_read(uint32_t address)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pramdac_registers, sizeof(pramdac_registers)/sizeof(pramdac_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PRAMDAC Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
//s hould be pretty easy to understand
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PRAMDAC_COEFF_SELECT:
|
||||
return nv3->pramdac.coeff_select;
|
||||
case NV3_PRAMDAC_GENERAL_CONTROL:
|
||||
return nv3->pramdac.general_control;
|
||||
case NV3_PRAMDAC_VSERR_WIDTH:
|
||||
return nv3->pramdac.vserr_width;
|
||||
case NV3_PRAMDAC_VBBLANK_END:
|
||||
return nv3->pramdac.vbblank_end;
|
||||
case NV3_PRAMDAC_VBLANK_END:
|
||||
return nv3->pramdac.vblank_end;
|
||||
case NV3_PRAMDAC_VBLANK_START:
|
||||
return nv3->pramdac.vblank_start;
|
||||
case NV3_PRAMDAC_VEQU_START:
|
||||
return nv3->pramdac.vequ_start;
|
||||
case NV3_PRAMDAC_VTOTAL:
|
||||
return nv3->pramdac.vtotal;
|
||||
case NV3_PRAMDAC_HSYNC_WIDTH:
|
||||
return nv3->pramdac.hsync_width;
|
||||
case NV3_PRAMDAC_HBURST_START:
|
||||
return nv3->pramdac.hburst_start;
|
||||
case NV3_PRAMDAC_HBURST_END:
|
||||
return nv3->pramdac.hburst_end;
|
||||
case NV3_PRAMDAC_HBLANK_START:
|
||||
return nv3->pramdac.hblank_start;
|
||||
case NV3_PRAMDAC_HBLANK_END:
|
||||
return nv3->pramdac.hblank_end;
|
||||
case NV3_PRAMDAC_HTOTAL:
|
||||
return nv3->pramdac.htotal;
|
||||
case NV3_PRAMDAC_HEQU_WIDTH:
|
||||
return nv3->pramdac.hequ_width;
|
||||
case NV3_PRAMDAC_HSERR_WIDTH:
|
||||
return nv3->pramdac.hserr_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pramdac_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_register_t* reg = nv_get_register(address, pramdac_registers, sizeof(pramdac_registers)/sizeof(pramdac_registers[0]));
|
||||
|
||||
nv_log("NV3: PRAMDAC Write 0x%08x -> 0x%08x", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
//s hould be pretty easy to understand
|
||||
// we also update the SVGA state here
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PRAMDAC_COEFF_SELECT:
|
||||
nv3->pramdac.coeff_select = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_GENERAL_CONTROL:
|
||||
nv3->pramdac.general_control = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VSERR_WIDTH:
|
||||
//vslines?
|
||||
nv3->pramdac.vserr_width = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VBBLANK_END:
|
||||
nv3->pramdac.vbblank_end = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VBLANK_END:
|
||||
nv3->pramdac.vblank_end = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VBLANK_START:
|
||||
nv3->nvbase.svga.vblankstart = value;
|
||||
nv3->pramdac.vblank_start = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VEQU_START:
|
||||
nv3->pramdac.vequ_start = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_VTOTAL:
|
||||
nv3->pramdac.vtotal = value;
|
||||
nv3->nvbase.svga.vtotal = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HSYNC_WIDTH:
|
||||
nv3->pramdac.hsync_width = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HBURST_START:
|
||||
nv3->pramdac.hburst_start = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HBURST_END:
|
||||
nv3->pramdac.hburst_end = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HBLANK_START:
|
||||
nv3->nvbase.svga.hblankstart = value;
|
||||
nv3->pramdac.hblank_start = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HBLANK_END:
|
||||
nv3->nvbase.svga.hblank_end_val = value;
|
||||
nv3->pramdac.hblank_end = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HTOTAL:
|
||||
nv3->pramdac.htotal = value;
|
||||
nv3->nvbase.svga.htotal = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HEQU_WIDTH:
|
||||
nv3->pramdac.hequ_width = value;
|
||||
break;
|
||||
case NV3_PRAMDAC_HSERR_WIDTH:
|
||||
nv3->pramdac.hserr_width = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
149
src/video/nv/nv3/subsystems/nv3_pramin.c
Normal file
149
src/video/nv/nv3/subsystems/nv3_pramin.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 PRAMIN - Basically, this is how we know what to render.
|
||||
* Has a giant hashtable of all the submitted DMA objects using a pseudo-C++ class system
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// i believe the main loop is to walk the hashtable in RAMIN (last 0.5 MB of VRAM),
|
||||
// find the objects that were submitted from DMA
|
||||
// (going from software -> nvidia d3d / ogl implementation -> resource manager client -> nvapi -> nvrm -> GPU PFIFO -> GPU PBUS -> GPU PFB RAMIN -> PGRAPH)
|
||||
// and then rendering each of those using PGRAPH
|
||||
|
||||
// Notes for all of these functions:
|
||||
// Structures in RAMIN are stored from the bottom of vram up in reverse order
|
||||
// this can be explained without bitwise math like so:
|
||||
// real VRAM address = VRAM_size - (ramin_address - (ramin_address % reversal_unit_size)) - reversal_unit_size + (ramin_address % reversal_unit_size)
|
||||
// reversal unit size in this case is 16 bytes, vram size is 2-8mb (but 8mb is zx/nv3t only and 2mb...i haven't found a 22mb card)
|
||||
|
||||
// Read 8-bit ramin
|
||||
uint8_t nv3_ramin_read8(uint32_t addr, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
|
||||
uint8_t val = nv3->nvbase.svga.vram[addr];
|
||||
|
||||
nv_log("NV3: Read byte from ramin addr=0x%08x (raw address=0x%08x)", addr, raw_addr);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// Read 16-bit ramin
|
||||
uint16_t nv3_ramin_read16(uint32_t addr, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
|
||||
// why does this not work in one line
|
||||
svga_t* svga = &nv3->nvbase.svga;
|
||||
uint16_t* vram_16bit = (uint16_t*)svga->vram;
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
addr >>= 1; // what
|
||||
|
||||
uint16_t val = vram_16bit[addr]; // what
|
||||
|
||||
nv_log("NV3: Read word from ramin addr=0x%08x (raw address=0x%08x)", addr, raw_addr);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// Read 32-bit ramin
|
||||
uint32_t nv3_ramin_read32(uint32_t addr, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
|
||||
// why does this not work in one line
|
||||
svga_t* svga = &nv3->nvbase.svga;
|
||||
uint32_t* vram_32bit = (uint32_t*)svga->vram;
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
addr >>= 2; // what
|
||||
|
||||
uint32_t val = vram_32bit[addr];
|
||||
|
||||
nv_log("NV3: Read dword from ramin addr=0x%08x (raw address=0x%08x)", addr, raw_addr);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// Write 8-bit ramin
|
||||
void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
// Structures in RAMIN are stored from the bottom of vram up in reverse order
|
||||
// this can be explained without bitwise math like so:
|
||||
// real VRAM address = VRAM_size - (ramin_address - (ramin_address % reversal_unit_size)) - reversal_unit_size + (ramin_address % reversal_unit_size)
|
||||
// reversal unit size in this case is 16 bytes, vram size is 2-8mb (but 8mb is zx/nv3t only and 2mb...i haven't found a 22mb card)
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
|
||||
nv3->nvbase.svga.vram[addr] = val;
|
||||
|
||||
nv_log("NV3: Write byte to ramin addr=0x%08x val=0x%08x (raw address=0x%08x)", addr, val, raw_addr);
|
||||
}
|
||||
|
||||
// Write 16-bit ramin
|
||||
void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
|
||||
// why does this not work in one line
|
||||
svga_t* svga = &nv3->nvbase.svga;
|
||||
uint16_t* vram_16bit = (uint16_t*)svga->vram;
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
addr >>= 1; // what
|
||||
|
||||
vram_16bit[addr] = val;
|
||||
|
||||
nv_log("NV3: Write word to ramin addr=0x%08x (raw address=0x%08x)", addr, raw_addr);
|
||||
}
|
||||
|
||||
// Write 32-bit ramin
|
||||
void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv)
|
||||
{
|
||||
addr &= (VRAM_SIZE_4MB - 1);
|
||||
|
||||
// why does this not work in one line
|
||||
svga_t* svga = &nv3->nvbase.svga;
|
||||
uint32_t* vram_32bit = (uint32_t*)svga->vram;
|
||||
uint32_t raw_addr = addr; // saved after and
|
||||
|
||||
addr ^= (VRAM_SIZE_4MB - 0x10);
|
||||
addr >>= 2; // what
|
||||
|
||||
vram_32bit[addr] = val;
|
||||
|
||||
nv_log("NV3: Write dword to ramin addr=0x%08x (raw address=0x%08x)", addr, raw_addr);
|
||||
}
|
||||
31
src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c
Normal file
31
src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 PFIFO RAMFC area: Stores context unused DMA channels
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
31
src/video/nv/nv3/subsystems/nv3_pramin_ramht.c
Normal file
31
src/video/nv/nv3/subsystems/nv3_pramin_ramht.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 PFIFO hashtable (Quickly access submitted DMA objects)
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
31
src/video/nv/nv3/subsystems/nv3_pramin_ramro.c
Normal file
31
src/video/nv/nv3/subsystems/nv3_pramin_ramro.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 PFIFO ram runout area (you fucked up)
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
// Single unified write function...
|
||||
120
src/video/nv/nv3/subsystems/nv3_ptimer.c
Normal file
120
src/video/nv/nv3/subsystems/nv3_ptimer.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 PTIMER - PIT emulation
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
|
||||
nv_register_t ptimer_registers[] = {
|
||||
{ NV3_PTIMER_INTR, "PTIMER - Interrupt Status", NULL, NULL},
|
||||
{ NV3_PTIMER_INTR_EN, "PTIMER - Interrupt Enable", NULL, NULL,},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
// ptimer init code
|
||||
void nv3_ptimer_init()
|
||||
{
|
||||
nv_log("NV3: Initialising PTIMER...");
|
||||
|
||||
nv_log("Done!\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_ptimer_read(uint32_t address)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, ptimer_registers, sizeof(ptimer_registers)/sizeof(ptimer_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PTIMER Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0: Alarm
|
||||
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PTIMER_INTR:
|
||||
return nv3->ptimer.interrupt_status;
|
||||
case NV3_PTIMER_INTR_EN:
|
||||
return nv3->ptimer.interrupt_enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void nv3_ptimer_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement
|
||||
nv_register_t* reg = nv_get_register(address, ptimer_registers, sizeof(ptimer_registers)/sizeof(ptimer_registers[0]));
|
||||
|
||||
nv_log("NV3: PTIMER Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Alarm
|
||||
|
||||
case NV3_PTIMER_INTR:
|
||||
nv3->ptimer.interrupt_status &= ~value;
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PTIMER_INTR_EN:
|
||||
nv3->ptimer.interrupt_enable = value & 0x00000001;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
src/video/nv/nv3/subsystems/nv3_pvideo.c
Normal file
121
src/video/nv/nv3/subsystems/nv3_pvideo.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 PVIDEO - Video Overlay
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 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>
|
||||
|
||||
|
||||
nv_register_t pvideo_registers[] = {
|
||||
{ NV3_PVIDEO_INTR, "PVIDEO - Interrupt Status", NULL, NULL},
|
||||
{ NV3_PVIDEO_INTR_EN, "PVIDEO - Interrupt Enable", NULL, NULL,},
|
||||
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
|
||||
};
|
||||
|
||||
// ptimer init code
|
||||
void nv3_pvideo_init()
|
||||
{
|
||||
nv_log("Initialising PVIDEO...");
|
||||
|
||||
nv_log("Done!\n");
|
||||
}
|
||||
|
||||
uint32_t nv3_pvideo_read(uint32_t address)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement
|
||||
|
||||
nv_register_t* reg = nv_get_register(address, pvideo_registers, sizeof(pvideo_registers)/sizeof(pvideo_registers[0]));
|
||||
|
||||
// todo: friendly logging
|
||||
|
||||
nv_log("NV3: PVIDEO Read from 0x%08x", address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_read)
|
||||
return reg->on_read();
|
||||
else
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Notifier
|
||||
|
||||
switch (reg->address)
|
||||
{
|
||||
case NV3_PVIDEO_INTR:
|
||||
return nv3->pvideo.interrupt_status;
|
||||
case NV3_PVIDEO_INTR_EN:
|
||||
return nv3->pvideo.interrupt_enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
void nv3_pvideo_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
// before doing anything, check the subsystem enablement
|
||||
nv_register_t* reg = nv_get_register(address, pvideo_registers, sizeof(pvideo_registers)/sizeof(pvideo_registers[0]));
|
||||
|
||||
nv_log("NV3: PVIDEO Write 0x%08x -> 0x%08x\n", value, address);
|
||||
|
||||
// if the register actually exists
|
||||
if (reg)
|
||||
{
|
||||
if (reg->friendly_name)
|
||||
nv_log(": %s\n", reg->friendly_name);
|
||||
else
|
||||
nv_log("\n");
|
||||
|
||||
// on-read function
|
||||
if (reg->on_write)
|
||||
reg->on_write(value);
|
||||
else
|
||||
{
|
||||
switch (reg->address)
|
||||
{
|
||||
// Interrupt state:
|
||||
// Bit 0 - Notifier
|
||||
|
||||
case NV3_PVIDEO_INTR:
|
||||
nv3->pvideo.interrupt_status &= ~value;
|
||||
nv3_pmc_clear_interrupts();
|
||||
break;
|
||||
case NV3_PVIDEO_INTR_EN:
|
||||
nv3->pvideo.interrupt_enable = value & 0x00000001;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
src/video/nv/nv_base.c
Normal file
47
src/video/nv/nv_base.c
Normal 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.
|
||||
*
|
||||
* Base file for emulation of NVidia video cards.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
|
||||
*
|
||||
* Copyright 2024 starfrost
|
||||
*/
|
||||
|
||||
// Common NV1/3/4... init
|
||||
#define HAVE_STDARG_H // wtf is this crap
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <86box/86box.h>
|
||||
#include <86box/nv/vid_nv.h>
|
||||
|
||||
|
||||
// Common logging
|
||||
#ifdef ENABLE_NV_LOG
|
||||
int nv_do_log = ENABLE_NV_LOG;
|
||||
|
||||
void nv_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (nv_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
nv_log(const char *fmt, ...)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -249,6 +249,9 @@ video_cards[] = {
|
||||
{ &compaq_voodoo_3_3500_agp_device },
|
||||
{ &voodoo_3_3500_se_agp_device },
|
||||
{ &voodoo_3_3500_si_agp_device },
|
||||
{ &nv3_device_agp },
|
||||
{ &nv3_device_pci },
|
||||
|
||||
{ NULL }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user