From d6388a825ce32eeaac0e232f002b1fcb7934308e Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sat, 13 Sep 2025 17:22:04 +0100 Subject: [PATCH] Initial port of core nv3 stuff to nv4 --- src/include/86box/nv/vid_nv.h | 12 +- src/include/86box/nv/vid_nv3.h | 11 +- src/include/86box/nv/vid_nv4.h | 74 +- src/include/86box/nv/vid_nv4_defines.h | 471 ++++----- src/video/CMakeLists.txt | 1 + src/video/nv/nv3/nv3_core.c | 84 +- src/video/nv/nv4/nv4_core.c | 173 +++- src/video/nv/nv4/nv4_core_io.c | 1310 ++++++++++++++++++++++++ 8 files changed, 1819 insertions(+), 317 deletions(-) create mode 100644 src/video/nv/nv4/nv4_core_io.c diff --git a/src/include/86box/nv/vid_nv.h b/src/include/86box/nv/vid_nv.h index 655fb3950..3d69f75c7 100644 --- a/src/include/86box/nv/vid_nv.h +++ b/src/include/86box/nv/vid_nv.h @@ -97,10 +97,19 @@ typedef enum nv_bus_generation_e } nv_bus_generation; +// PCI configuration +typedef struct nv_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; +} nv_pci_config_t; + // NV Base typedef struct nv_base_s { rom_t vbios; // NVIDIA/OEm VBIOS + nv_pci_config_t pci_config; // PCI configuration // move to nv3_cio_t? svga_t svga; // SVGA core (separate to nv3) - Weitek licensed uint32_t vram_amount; // The amount of VRAM @@ -113,7 +122,7 @@ typedef struct nv_base_s 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) + mem_mapping_t ramin_mapping_mirror; // RAM INput area mapping (mirrored) - NV3 ONLY 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 @@ -131,6 +140,7 @@ typedef struct nv_base_s void* i2c; // I2C for monitor EDID void* ddc; // Display Data Channel for EDID bool agp_enabled; // AGP Enabled (for debugging) + bool agp_sba_enabled; // AGP Sideband Addressing enabled // // DEBUG UI STUFF diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index b954355bb..3726ecc03 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -1013,15 +1013,7 @@ typedef struct nv3_pmc_s } 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 +// add enums for eac // Chip configuration typedef struct nv3_straps_s { @@ -1546,7 +1538,6 @@ typedef struct nv3_s // Config nv3_straps_t straps; // OEM Configuration - nv3_pci_config_t pci_config; // PCI Configuration // Subsystems nv3_pmc_t pmc; // Master Control diff --git a/src/include/86box/nv/vid_nv4.h b/src/include/86box/nv/vid_nv4.h index 3415f065b..7fda0fca4 100644 --- a/src/include/86box/nv/vid_nv4.h +++ b/src/include/86box/nv/vid_nv4.h @@ -20,11 +20,28 @@ #include #include <86Box/nv/vid_nv4_defines.h> -// Structures -typedef struct nv4_s + +// +// PBUS/RMA +// + +// Access the GPU from real-mode +typedef struct nv4_pbus_rma_s { - nv_base_t nvbase; // Base Nvidia structure -} nv4_t; + 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[NV4_RMA_NUM_REGS]; // The rma registers (saved) +} nv4_pbus_rma_t; + +// Bus Configuration +typedef struct nv4_pbus_s +{ + uint32_t debug_0; + uint32_t interrupt_status; // Interrupt status + uint32_t interrupt_enable; // Interrupt enable + nv4_pbus_rma_t rma; +} nv4_pbus_t; // // PTIMER @@ -40,6 +57,27 @@ typedef struct nv4_ptimer_s uint32_t alarm; // The value of time when there should be an alarm } nv4_ptimer_t; +// +// PRAMDAC +// +typedef struct nv4_pramdac_s +{ + uint32_t mclk; + uint32_t vclk; + uint32_t nvclk; + uint32_t cursor_address; +} nv4_pramdac_t; + +// Structures +typedef struct nv4_s +{ + nv_base_t nvbase; // Base Nvidia structure + uint32_t straps; // Straps. See defines + nv4_pbus_t pbus; + nv4_ptimer_t ptimer; + nv4_pramdac_t pramdac; +} nv4_t; + // // Globals @@ -58,4 +96,30 @@ void nv4_close(void* priv); void nv4_speed_changed(void *priv); void nv4_draw_cursor(svga_t* svga, int32_t drawline); void nv4_recalc_timings(svga_t* svga); -void nv4_force_redraw(void* priv); \ No newline at end of file +void nv4_force_redraw(void* priv); + +// I/o +uint8_t nv4_mmio_read8(uint32_t addr, void* priv); +uint16_t nv4_mmio_read16(uint32_t addr, void* priv); +uint32_t nv4_mmio_read32(uint32_t addr, void* priv); +void nv4_mmio_write8(uint32_t addr, uint8_t val, void* priv); +void nv4_mmio_write16(uint32_t addr, uint16_t val, void* priv); +void nv4_mmio_write32(uint32_t addr, uint32_t val, void* priv); +uint8_t nv4_dfb_read8(uint32_t addr, void* priv); +uint16_t nv4_dfb_read16(uint32_t addr, void* priv); +uint32_t nv4_dfb_read32(uint32_t addr, void* priv); +void nv4_dfb_write8(uint32_t addr, uint8_t val, void* priv); +void nv4_dfb_write16(uint32_t addr, uint16_t val, void* priv); +void nv4_dfb_write32(uint32_t addr, uint32_t val, void* priv); +uint8_t nv4_ramin_read8(uint32_t addr, void* priv); +uint16_t nv4_ramin_read16(uint32_t addr, void* priv); +uint32_t nv4_ramin_read32(uint32_t addr, void* priv); +void nv4_ramin_write8(uint32_t addr, uint8_t val, void* priv); +void nv4_ramin_write16(uint32_t addr, uint16_t val, void* priv); +void nv4_ramin_write32(uint32_t addr, uint32_t val, void* priv); + + +uint8_t nv4_svga_read(uint16_t addr, void* priv); +void nv4_svga_write(uint16_t addr, uint8_t val, void* priv); + +void nv4_update_mappings(); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv4_defines.h b/src/include/86box/nv/vid_nv4_defines.h index e27ff091e..21cf5739a 100644 --- a/src/include/86box/nv/vid_nv4_defines.h +++ b/src/include/86box/nv/vid_nv4_defines.h @@ -7,12 +7,12 @@ // General // #define NV4_VRAM_SIZE_2MB 0x200000 // 2MB (never used; NV4 only) -#define NV4_VRAM_SIZE_4MB 0x400000 // 4MB (never used) -#define NV4_VRAM_SIZE_8MB 0x800000 // 8MB -#define NV4_VRAM_SIZE_16MB 0x1000000 // 16MB -#define NV5_VRAM_SIZE_32MB 0x2000000 // NV5 only +#define NV4_VRAM_SIZE_4MB 0x400000 // 4MB (never used) +#define NV4_VRAM_SIZE_8MB 0x800000 // 8MB +#define NV4_VRAM_SIZE_16MB 0x1000000 // 16MB +#define NV5_VRAM_SIZE_32MB 0x2000000 // NV5 only -#define NV4_MMIO_SIZE 0x1000000 // not sure. May be larger!!!! +#define NV4_MMIO_SIZE 0x1000000 // not sure. May be larger!!!! // // VBIOS @@ -21,6 +21,12 @@ #define NV4_PRMIO_START 0x7000 #define NV4_PRMIO_END 0x7FFF + +// NV4 Legacy I/O space +#define NV4_RMA_REGISTER_START 0x3D0 +#define NV4_RMA_REGISTER_END 0x3D3 +#define NV4_RMA_NUM_REGS 4 + #define NV4_PRMIO_RMA_ID 0x7100 #define NV4_PRMIO_RMA_ID_CODE 0 #define NV4_PRMIO_RMA_ID_CODE_VALID 0x2B16D065 @@ -32,6 +38,7 @@ #define NV4_PRMIO_RMA_DATA32_BYTE2 16 #define NV4_PRMIO_RMA_DATA32_BYTE1 8 #define NV4_PRMIO_RMA_DATA32_BYTE0 0 +#define NV4_PRMIO_RMA_MODE_MAX 0x0F #define NV4_PRAMDAC_START 0x680300 #define NV4_PRAMDAC_END 0x680FFF @@ -261,6 +268,8 @@ #define NV4_USER_DAC_START 0x681200 #define NV4_USER_DAC_END 0x681FFF +#define NV4_USER_DAC_PALETTE_START 0x6813C6 +#define NV4_USER_DAC_PALETTE_END 0x6813C9 #define NV4_USER_DAC_PIXEL_MASK 0x6813C6 #define NV4_USER_DAC_PIXEL_MASK_VALUE 0 @@ -486,223 +495,181 @@ #define NV4_PBUS_INTR_EN_0_PCI_BUS_ERROR_ENABLED 0x1 #define NV4_PBUS_ROM_CONFIG 0x1200 #define NV4_PBUS_ROM_CONFIG_TW1 0 -#define NV4_PBUS_ROM_CONFIG_TW1_DEFAULT 0xF -#define NV4_PBUS_ROM_CONFIG_TW0 4 -#define NV4_PBUS_ROM_CONFIG_TW0_DEFAULT 0x3 -#define NV4_PBUS_PCI_NV_0 0x1800 -#define NV4_PBUS_PCI_NV_0_VENDOR_ID 0 -#define NV4_PBUS_PCI_NV_0_VENDOR_ID_NVIDIA_SGS 0x12D2 -#define NV4_PBUS_PCI_NV_0_VENDOR_ID_NVIDIA 0x10DE -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_FUNC 16 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_FUNC_VGA 0x0 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP 3 19 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP_NV0 0x0 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP_NV1 0x1 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP_NV2 0x2 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP_NV3 0x3 -#define NV4_PBUS_PCI_NV_0_DEVICE_ID_CHIP_NV4 0x4 -#define NV4_PBUS_PCI_NV_1 0x1804 -#define NV4_PBUS_PCI_NV_1_IO_SPACE 0 -#define NV4_PBUS_PCI_NV_1_IO_SPACE_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_1_MEMORY_SPACE 1 -#define NV4_PBUS_PCI_NV_1_MEMORY_SPACE_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_1_BUS_MASTER 2 -#define NV4_PBUS_PCI_NV_1_BUS_MASTER_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_1_WRITE_AND_INVAL 4 -#define NV4_PBUS_PCI_NV_1_WRITE_AND_INVAL_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_1_PALETTE_SNOOP 5 -#define NV4_PBUS_PCI_NV_1_PALETTE_SNOOP_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_1_CAPLIST 20 -#define NV4_PBUS_PCI_NV_1_CAPLIST_NOT_PRESENT 0x0 -#define NV4_PBUS_PCI_NV_1_CAPLIST_PRESENT 0x1 -#define NV4_PBUS_PCI_NV_1_66MHZ 21 -#define NV4_PBUS_PCI_NV_1_66MHZ_INCAPABLE 0x0 -#define NV4_PBUS_PCI_NV_1_66MHZ_CAPABLE 0x1 -#define NV4_PBUS_PCI_NV_1_FAST_BACK2BACK 23 -#define NV4_PBUS_PCI_NV_1_FAST_BACK2BACK_INCAPABLE 0x0 -#define NV4_PBUS_PCI_NV_1_FAST_BACK2BACK_CAPABLE 0x1 -#define NV4_PBUS_PCI_NV_1_DEVSEL_TIMING 25 -#define NV4_PBUS_PCI_NV_1_DEVSEL_TIMING_FAST 0x0 -#define NV4_PBUS_PCI_NV_1_DEVSEL_TIMING_MEDIUM 0x1 -#define NV4_PBUS_PCI_NV_1_DEVSEL_TIMING_SLOW 0x2 -#define NV4_PBUS_PCI_NV_1_SIGNALED_TARGET 27 -#define NV4_PBUS_PCI_NV_1_SIGNALED_TARGET_NO_ABORT 0x0 -#define NV4_PBUS_PCI_NV_1_SIGNALED_TARGET_ABORT 0x1 -#define NV4_PBUS_PCI_NV_1_SIGNALED_TARGET_CLEAR 0x1 -#define NV4_PBUS_PCI_NV_1_RECEIVED_TARGET 28 -#define NV4_PBUS_PCI_NV_1_RECEIVED_TARGET_NO_ABORT 0x0 -#define NV4_PBUS_PCI_NV_1_RECEIVED_TARGET_ABORT 0x1 -#define NV4_PBUS_PCI_NV_1_RECEIVED_TARGET_CLEAR 0x1 -#define NV4_PBUS_PCI_NV_1_RECEIVED_MASTER 29 -#define NV4_PBUS_PCI_NV_1_RECEIVED_MASTER_NO_ABORT 0x0 -#define NV4_PBUS_PCI_NV_1_RECEIVED_MASTER_ABORT 0x1 -#define NV4_PBUS_PCI_NV_1_RECEIVED_MASTER_CLEAR 0x1 -#define NV4_PBUS_PCI_NV_2 0x1808 -#define NV4_PBUS_PCI_NV_2_REVISION_ID 0 -#define NV4_PBUS_PCI_NV_2_REVISION_ID_A01 0x0 -#define NV4_PBUS_PCI_NV_2_REVISION_ID_B01 0x10 -#define NV4_PBUS_PCI_NV_2_CLASS_CODE 8 -#define NV4_PBUS_PCI_NV_2_CLASS_CODE_VGA 0x30000 -#define NV4_PBUS_PCI_NV_2_CLASS_CODE_MULTIMEDIA 0x48000 -#define NV4_PBUS_PCI_NV_3 0x180C -#define NV4_PBUS_PCI_NV_3_LATENCY_TIMER 11 -#define NV4_PBUS_PCI_NV_3_LATENCY_TIMER_0_CLOCKS 0x0 -#define NV4_PBUS_PCI_NV_3_LATENCY_TIMER_8_CLOCKS 0x1 -#define NV4_PBUS_PCI_NV_3_LATENCY_TIMER_240_CLOCKS 0x1E -#define NV4_PBUS_PCI_NV_3_LATENCY_TIMER_248_CLOCKS 0x1F -#define NV4_PBUS_PCI_NV_3_HEADER_TYPE 16 -#define NV4_PBUS_PCI_NV_3_HEADER_TYPE_SINGLEFUNC 0x0 -#define NV4_PBUS_PCI_NV_3_HEADER_TYPE_MULTIFUNC 0x80 -#define NV4_PBUS_PCI_NV_4 0x1810 -#define NV4_PBUS_PCI_NV_4_SPACE_TYPE 0 -#define NV4_PBUS_PCI_NV_4_SPACE_TYPE_MEMORY 0x0 -#define NV4_PBUS_PCI_NV_4_SPACE_TYPE_IO 0x1 -#define NV4_PBUS_PCI_NV_4_ADDRESS_TYPE 1 -#define NV4_PBUS_PCI_NV_4_ADDRESS_TYPE_32_BIT 0x0 -#define NV4_PBUS_PCI_NV_4_ADDRESS_TYPE_20_BIT 0x1 -#define NV4_PBUS_PCI_NV_4_ADDRESS_TYPE_64_BIT 0x2 -#define NV4_PBUS_PCI_NV_4_PREFETCHABLE 3 -#define NV4_PBUS_PCI_NV_4_PREFETCHABLE_NOT 0x0 -#define NV4_PBUS_PCI_NV_4_PREFETCHABLE_MERGABLE 0x1 -#define NV4_PBUS_PCI_NV_4_BASE_ADDRESS 24 -#define NV4_PBUS_PCI_NV_5 0x1814 -#define NV4_PBUS_PCI_NV_5_SPACE_TYPE 0 -#define NV4_PBUS_PCI_NV_5_SPACE_TYPE_MEMORY 0x0 -#define NV4_PBUS_PCI_NV_5_SPACE_TYPE_IO 0x1 -#define NV4_PBUS_PCI_NV_5_ADDRESS_TYPE 2:1 -#define NV4_PBUS_PCI_NV_5_ADDRESS_TYPE_32_BIT 0x0 -#define NV4_PBUS_PCI_NV_5_ADDRESS_TYPE_20_BIT 0x1 -#define NV4_PBUS_PCI_NV_5_ADDRESS_TYPE_64_BIT 0x2 -#define NV4_PBUS_PCI_NV_5_PREFETCHABLE 3 -#define NV4_PBUS_PCI_NV_5_PREFETCHABLE_NOT 0x0 -#define NV4_PBUS_PCI_NV_5_PREFETCHABLE_MERGABLE 0x1 -#define NV4_PBUS_PCI_NV_5_BASE_ADDRESS 24 -#define NV4_PBUS_PCI_NV_6(i) (0x1818+(i)*4) -#define NV4_PBUS_PCI_NV_6_SIZE_1 5 -#define NV4_PBUS_PCI_NV_6_RESERVED 0 -#define NV4_PBUS_PCI_NV_6_RESERVED_0 0x0 -#define NV4_PBUS_PCI_NV_11 0x182C -#define NV4_PBUS_PCI_NV_11_SUBSYSTEM_VENDOR_ID 0 -#define NV4_PBUS_PCI_NV_11_SUBSYSTEM_VENDOR_ID_NONE 0x0 -#define NV4_PBUS_PCI_NV_11_SUBSYSTEM_ID 16 -#define NV4_PBUS_PCI_NV_11_SUBSYSTEM_ID_NONE 0x0 -#define NV4_PBUS_PCI_NV_12 0x1830 -#define NV4_PBUS_PCI_NV_12_ROM_DECODE 0 -#define NV4_PBUS_PCI_NV_12_ROM_DECODE_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_12_ROM_BASE 16 -#define NV4_PBUS_PCI_NV_13 0x1834 -#define NV4_PBUS_PCI_NV_13_CAP_PTR 0 -#define NV4_PBUS_PCI_NV_13_CAP_PTR_AGP 0x44 -#define NV4_PBUS_PCI_NV_13_CAP_PTR_POWER_MGMT 0x60 -#define NV4_PBUS_PCI_NV_14 0x1838 -#define NV4_PBUS_PCI_NV_14_RESERVED 0 -#define NV4_PBUS_PCI_NV_14_RESERVED_0 0x0 -#define NV4_PBUS_PCI_NV_15 0x183C -#define NV4_PBUS_PCI_NV_15_INTR_LINE 0 -#define NV4_PBUS_PCI_NV_15_INTR_LINE_IRQ0 0x0 -#define NV4_PBUS_PCI_NV_15_INTR_LINE_IRQ1 0x1 -#define NV4_PBUS_PCI_NV_15_INTR_LINE_IRQ15 0xF -#define NV4_PBUS_PCI_NV_15_INTR_LINE_UNKNOWN 0xFF -#define NV4_PBUS_PCI_NV_15_INTR_PIN 8 -#define NV4_PBUS_PCI_NV_15_INTR_PIN_INTA 0x1 -#define NV4_PBUS_PCI_NV_15_MIN_GNT 16 -#define NV4_PBUS_PCI_NV_15_MIN_GNT_NO_REQUIREMENTS 0x0 -#define NV4_PBUS_PCI_NV_15_MIN_GNT_750NS 0x3 -#define NV4_PBUS_PCI_NV_15_MIN_GNT_1250NS 0x5 -#define NV4_PBUS_PCI_NV_15_MAX_LAT 24 -#define NV4_PBUS_PCI_NV_15_MAX_LAT_NO_REQUIREMENTS 0x0 -#define NV4_PBUS_PCI_NV_15_MAX_LAT_250NS 0x1 -#define NV4_PBUS_PCI_NV_16 0x1840 -#define NV4_PBUS_PCI_NV_16_SUBSYSTEM_VENDOR_ID 0 -#define NV4_PBUS_PCI_NV_16_SUBSYSTEM_VENDOR_ID_NONE 0x0 -#define NV4_PBUS_PCI_NV_16_SUBSYSTEM_ID 16 -#define NV4_PBUS_PCI_NV_16_SUBSYSTEM_ID_NONE 0x0 -#define NV4_PBUS_PCI_NV_17 0x1844 -#define NV4_PBUS_PCI_NV_17_AGP_REV_MAJOR 20 -#define NV4_PBUS_PCI_NV_17_AGP_REV_MAJOR_1 0x1 -#define NV4_PBUS_PCI_NV_17_AGP_REV_MINOR 16 -#define NV4_PBUS_PCI_NV_17_AGP_REV_MINOR_0 0x0 -#define NV4_PBUS_PCI_NV_17_NEXT_PTR 8 -#define NV4_PBUS_PCI_NV_17_NEXT_PTR_NULL 0x0 -#define NV4_PBUS_PCI_NV_17_CAP_ID 0 -#define NV4_PBUS_PCI_NV_17_CAP_ID_AGP 0x2 -#define NV4_PBUS_PCI_NV_18 0x1848 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RQ 24 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RQ_16 0xF -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_SBA 9 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_SBA_NONE 0x0 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_SBA_CAPABLE 0x1 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RATE 0 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RATE_1X 0x1 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RATE_2X 0x2 -#define NV4_PBUS_PCI_NV_18_AGP_STATUS_RATE_1X_AND_2X 0x3 -#define NV4_PBUS_PCI_NV_19 0x184C -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_RQ_DEPTH 24 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_RQ_DEPTH_0 0x0 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_SBA_ENABLE 9 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_SBA_ENABLE_OFF 0x0 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_SBA_ENABLE_ON 0x1 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_AGP_ENABLE 8 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_AGP_ENABLE_OFF 0x0 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_AGP_ENABLE_ON 0x1 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_DATA_RATE 0 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_DATA_RATE_OFF 0x0 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_DATA_RATE_1X 0x1 -#define NV4_PBUS_PCI_NV_19_AGP_COMMAND_DATA_RATE_2X 0x2 -#define NV4_PBUS_PCI_NV_20 0x1850 -#define NV4_PBUS_PCI_NV_20_ROM_SHADOW 0 -#define NV4_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_21 0x1854 -#define NV4_PBUS_PCI_NV_21_VGA 0 -#define NV4_PBUS_PCI_NV_21_VGA_ENABLED 0x1 -#define NV4_PBUS_PCI_NV_22 0x1858 -#define NV4_PBUS_PCI_NV_22_SCRATCH 0 -#define NV4_PBUS_PCI_NV_22_SCRATCH_DEFAULT 0x23D6CE -#define NV4_PBUS_PCI_NV_23 0x185C -#define NV4_PBUS_PCI_NV_23_DT_TIMEOUT 0 -#define NV4_PBUS_PCI_NV_23_DT_TIMEOUT_16 0xF -#define NV4_PBUS_PCI_NV_24 0x1860 -#define NV4_PBUS_PCI_NV_24_PME_D3_COLD 31 -#define NV4_PBUS_PCI_NV_24_PME_D3_COLD_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_PME_D3_HOT 30 -#define NV4_PBUS_PCI_NV_24_PME_D3_HOT_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_PME_D2 29 -#define NV4_PBUS_PCI_NV_24_PME_D2_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_PME_D1 28 -#define NV4_PBUS_PCI_NV_24_PME_D1_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_PME_D0 27 -#define NV4_PBUS_PCI_NV_24_PME_D0_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_D2 26 -#define NV4_PBUS_PCI_NV_24_D2_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_D2_NOT_SUPPORTED 0x0 -#define NV4_PBUS_PCI_NV_24_D1 25 -#define NV4_PBUS_PCI_NV_24_D1_SUPPORTED 0x1 -#define NV4_PBUS_PCI_NV_24_D1_NOT_SUPPORTED 0x0 -#define NV4_PBUS_PCI_NV_24_DSI 21 -#define NV4_PBUS_PCI_NV_24_DSI_NOT_REQUIRED 0x0 -#define NV4_PBUS_PCI_NV_24_PME_CLOCK 19 -#define NV4_PBUS_PCI_NV_24_PME_CLOCK_NOT_REQUIRED 0x0 -#define NV4_PBUS_PCI_NV_24_VERSION 16 -#define NV4_PBUS_PCI_NV_24_VERSION_1 0x1 -#define NV4_PBUS_PCI_NV_24_NEXT_PTR 8 -#define NV4_PBUS_PCI_NV_24_NEXT_PTR_NULL 0x0 -#define NV4_PBUS_PCI_NV_24_NEXT_PTR_AGP 0x44 -#define NV4_PBUS_PCI_NV_24_CAP_ID 0 -#define NV4_PBUS_PCI_NV_24_CAP_ID_POWER_MGMT 0x1 -#define NV4_PBUS_PCI_NV_25 0x1864 -#define NV4_PBUS_PCI_NV_25_POWER_STATE 0 -#define NV4_PBUS_PCI_NV_25_POWER_STATE_D3_HOT 0x3 -#define NV4_PBUS_PCI_NV_25_POWER_STATE_D2 0x2 -#define NV4_PBUS_PCI_NV_25_POWER_STATE_D1 0x1 -#define NV4_PBUS_PCI_NV_25_POWER_STATE_D0 0x0 -#define NV4_PBUS_PCI_NV_26(i) (0x1868+(i)*4) -#define NV4_PBUS_PCI_NV_26_SIZE_1 38 -#define NV4_PBUS_PCI_NV_26_RESERVED 0 -#define NV4_PBUS_PCI_NV_26_RESERVED_0 0x0 +#define NV4_PBUS_ROM_CONFIG_TW1_DEFAULT 0xF +#define NV4_PBUS_ROM_CONFIG_TW0 4 +#define NV4_PBUS_ROM_CONFIG_TW0_DEFAULT 0x3 +// 86Box uses 8-bit PCI registers so this section was rewritten +#define NV4_PBUS_PCI_VENDOR_ID 0x1800 +#define NV4_PBUS_PCI_DEVICE_VENDOR_NVIDIA 0x10DE +#define NV4_PBUS_PCI_DEVICE_ID 0x1802 +#define NV4_PBUS_PCI_DEVICE_ID_NV4 0x0020 // Chip (19:17)= NV4, Func = VGA +#define NV4_PBUS_PCI_COMMAND 0x1804 +#define NV4_PBUS_PCI_COMMAND_IO_SPACE 0 +#define NV4_PBUS_PCI_COMMAND_IO_SPACE_ENABLED 0x1 +#define NV4_PBUS_PCI_COMMAND_MEMORY_SPACE 1 +#define NV4_PBUS_PCI_COMMAND_MEMORY_SPACE_ENABLED 0x1 +#define NV4_PBUS_PCI_COMMAND_BUS_MASTER 2 +#define NV4_PBUS_PCI_COMMAND_BUS_MASTER_ENABLED 0x1 +#define NV4_PBUS_PCI_COMMAND_WRITE_AND_INVAL 4 +#define NV4_PBUS_PCI_COMMAND_WRITE_AND_INVAL_ENABLED 0x1 +#define NV4_PBUS_PCI_COMMAND_PALETTE_SNOOP 5 +#define NV4_PBUS_PCI_COMMAND_PALETTE_SNOOP_ENABLED 0x1 +#define NV4_PBUS_PCI_STATUS 0x1806 +#define NV4_PBUS_PCI_STATUS_CAPLIST 4 +#define NV4_PBUS_PCI_STATUS_CAPLIST_NOT_PRESENT 0x0 +#define NV4_PBUS_PCI_STATUS_CAPLIST_PRESENT 0x1 +#define NV4_PBUS_PCI_STATUS_66MHZ 5 +#define NV4_PBUS_PCI_STATUS_66MHZ_INCAPABLE 0x0 +#define NV4_PBUS_PCI_STATUS_66MHZ_CAPABLE 0x1 +#define NV4_PBUS_PCI_STATUS_FAST_BACK2BACK 7 +#define NV4_PBUS_PCI_STATUS_FAST_BACK2BACK_INCAPABLE 0x0 +#define NV4_PBUS_PCI_STATUS_FAST_BACK2BACK_CAPABLE 0x1 +#define NV4_PBUS_PCI_STATUS_2 0x1807 +#define NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING 1 +#define NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_FAST 0x0 +#define NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_MEDIUM 0x1 +#define NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_SLOW 0x2 +#define NV4_PBUS_PCI_STATUS_2_SIGNALED_TARGET 3 +#define NV4_PBUS_PCI_STATUS_2_SIGNALED_TARGET_NO_ABORT 0x0 +#define NV4_PBUS_PCI_STATUS_2_SIGNALED_TARGET_ABORT 0x1 +#define NV4_PBUS_PCI_STATUS_2_SIGNALED_TARGET_CLEAR 0x1 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_TARGET 4 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_TARGET_NO_ABORT 0x0 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_TARGET_ABORT 0x1 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_TARGET_CLEAR 0x1 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_MASTER 5 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_MASTER_NO_ABORT 0x0 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_MASTER_ABORT 0x1 +#define NV4_PBUS_PCI_STATUS_2_RECEIVED_MASTER_CLEAR 0x1 +#define NV4_PBUS_PCI_REVISION_ID 0x1808 +#define NV4_PBUS_PCI_REVISION_ID_A01 0x0 +#define NV4_PBUS_PCI_REVISION_ID_B01 0x1 +#define NV4_PBUS_PCI_CLASS_CODE 0x180B +#define NV4_PBUS_PCI_CLASS_CODE_VGA 0x30000 +#define NV4_PBUS_PCI_LATENCY_TIMER 0x180D +// Shift left by 3 to get the real value in clocks. 0x0 = 0, 0x1 = 8, 0x1E = 240, 0x1F = 248 are values used. +#define NV4_PBUS_PCI_LATENCY_TIMER_VALUE 3 +// 0x0 = single function (only value that matters) +#define NV4_PBUS_PCI_HEADER_TYPE 0x180E +#define NV4_PBUS_PCI_BAR_SPACE_TYPE 0 +#define NV4_PBUS_PCI_BAR_SPACE_TYPE_MEMORY 0x0 +#define NV4_PBUS_PCI_BAR_SPACE_TYPE_IO 0x1 +#define NV4_PBUS_PCI_BAR_ADDRESS_TYPE 1 +#define NV4_PBUS_PCI_BAR_ADDRESS_TYPE_32_BIT 0x0 +#define NV4_PBUS_PCI_BAR_ADDRESS_TYPE_20_BIT 0x1 +#define NV4_PBUS_PCI_BAR_ADDRESS_TYPE_64_BIT 0x2 +#define NV4_PBUS_PCI_BAR_PREFETCHABLE 3 +#define NV4_PBUS_PCI_BAR_PREFETCHABLE_NOT 0x0 +#define NV4_PBUS_PCI_BAR_PREFETCHABLE_MERGABLE 0x1 +// Bits 23:4 are resedrved +#define NV4_PBUS_PCI_BAR0_INFO 0x1810 +#define NV4_PBUS_PCI_BAR0_UNUSED1 0x1811 +#define NV4_PBUS_PCI_BAR0_UNUSED2 0x1812 +#define NV4_PBUS_PCI_BAR0_BASE_31_TO_24 0x1813 // Must align to 16MByte +#define NV4_PBUS_PCI_BAR1_INFO 0x1814 +#define NV4_PBUS_PCI_BAR1_UNUSED1 0x1814 +#define NV4_PBUS_PCI_BAR1_UNUSED2 0x1815 +#define NV4_PBUS_PCI_BAR1_BASE_31_TO_24 0x1816 // Must align to 16MByte +//BAR2-5 reserved +#define NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID 0x182C +#define NV4_PBUS_PCI_SUBSYSTEM_ID 0x182E +#define NV4_PBUS_PCI_ROM 0x1830 +#define NV4_PBUS_PCI_ROM_DECODE 0 +#define NV4_PBUS_PCI_ROM_DECODE_ENABLED 0x1 +#define NV4_PBUS_PCI_ROM_BASE 0x1832 +#define NV4_PBUS_PCI_NEXT_PTR 0x1834 +#define NV4_PBUS_PCI_CAP_PTR_AGP 0x44 +#define NV4_PBUS_PCI_CAP_PTR_POWER_MGMT 0x60 +// 0xFF = unknown, otherwise 0x0-0xF = IRQ0-15 +#define NV4_PBUS_PCI_INTR_LINE 0x183C +#define NV4_PBUS_PCI_INTR_LINE_IRQ_NUM 0 +#define NV4_PBUS_PCI_INTR_LINE_IRQ_NUM_UNKNOWN 0xFF +#define NV4_PBUS_PCI_INTR_PIN 0x183D +#define NV4_PBUS_PCI_INTR_PIN_INTA 0x1 +#define NV4_PBUS_PCI_MIN_GNT 0x183E +#define NV4_PBUS_PCI_MIN_GNT_NO_REQUIREMENTS 0x0 +#define NV4_PBUS_PCI_MIN_GNT_750NS 0x3 +#define NV4_PBUS_PCI_MIN_GNT_1250NS 0x5 +#define NV4_PBUS_PCI_MAX_LAT 0x183F +#define NV4_PBUS_PCI_MAX_LAT_NO_REQUIREMENTS 0x0 +#define NV4_PBUS_PCI_MAX_LAT_250NS 0x1 +#define NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID_WRITABLE 0x1840 +#define NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE 0x1842 +#define NV4_PBUS_AGP 0x44 +#define NV4_PBUS_AGP_CAPABILITIES 0x1844 +#define NV4_PBUS_AGP_CAPABILITY_AGP 0x2 +// Should be null! + +#define NV4_PBUS_AGP_NEXT_PTR 0x1845 +#define NV4_PBUS_AGP_REV 0x1846 +#define NV4_PBUS_AGP_REV_MINOR 0 +#define NV4_PBUS_AGP_REV_MINOR_0 0x0 +#define NV4_PBUS_AGP_REV_MAJOR 4 +#define NV4_PBUS_AGP_REV_MAJOR_1 0x1 +#define NV4_PBUS_AGP_STATUS_RATE 0x1848 +#define NV4_PBUS_AGP_STATUS_RATE_1X 0x1 +#define NV4_PBUS_AGP_STATUS_RATE_2X 0x2 +#define NV4_PBUS_AGP_STATUS_RATE_1X_AND_2X 0x3 +#define NV4_PBUS_AGP_STATUS_RQ 0x184B +#define NV4_PBUS_AGP_STATUS_RQ_16 0xF +#define NV4_PBUS_AGP_STATUS_SBA 0x1849 +#define NV4_PBUS_AGP_STATUS_SBA_STATUS 1 +#define NV4_PBUS_AGP_STATUS_SBA_STATUS_NONE 0x0 +#define NV4_PBUS_AGP_STATUS_SBA_STATUS_CAPABLE 0x1 +#define NV4_PBUS_AGP_COMMAND 0x184C +#define NV4_PBUS_AGP_COMMAND_DATA_RATE 0 +#define NV4_PBUS_AGP_COMMAND_DATA_RATE_OFF 0x0 +#define NV4_PBUS_AGP_COMMAND_DATA_RATE_1X 0x1 +#define NV4_PBUS_AGP_COMMAND_DATA_RATE_2X 0x2 +#define NV4_PBUS_AGP_COMMAND_2 0x184D +#define NV4_PBUS_AGP_COMMAND_2_AGP_ENABLED 0 // 1 = enabled, 0 = disabled +#define NV4_PBUS_AGP_COMMAND_2_SBA_ENABLED 1 // 1 = enabled, 0 = disabled +#define NV4_PBUS_AGP_COMMAND_RQ_DEPTH 0x184F //DEFAUlt 0 +#define NV4_PBUS_PCI_ROM_SHADOW 0x1850 +#define NV4_PBUS_PCI_ROM_SHADOW_IS_ENABLED 0 // 1 = enabled, 0 = disabled +#define NV4_PBUS_PCI_VGA 0x1854 +#define NV4_PBUS_PCI_VGA_IS_ENABLED 0 // 1 = enabled, 0 = disabled +#define NV4_PBUS_PCI_SCRATCH 0x1858 +#define NV4_PBUS_PCI_SCRATCH_DEFAULT 0x23D6CE +#define NV4_PBUS_PCI_DT 0x185C +#define NV4_PBUS_PCI_DT_TIMEOUT 0 +#define NV4_PBUS_PCI_DT_TIMEOUT_16 0xF +//TODO: Implement +#define NV4_PBUS_PCIPOWER 0x1860 +#define NV4_PBUS_PCIPOWER_CAP_ID 0 +#define NV4_PBUS_PCIPOWER_CAP_ID_POWER_MGMT 0x1 +#define NV4_PBUS_PCIPOWER_NEXT_PTR 0x1861 // should be 0x44=AGP +#define NV4_PBUS_PCIPOWER_2 0x1862 +#define NV4_PBUS_PCIPOWER_2_VERSION 0 +#define NV4_PBUS_PCIPOWER_2_VERSION_1 0x1 +#define NV4_PBUS_PCIPOWER_2_CLOCK 3 +#define NV4_PBUS_PCIPOWER_2_CLOCK_NOT_REQUIRED 0x0 +#define NV4_PBUS_PCIPOWER_2_DSI 5 +#define NV4_PBUS_PCIPOWER_2_DSI_NOT_REQUIRED 0x0 +#define NV4_PBUS_PCIPOWER_SUPPORTED_STATES 0x1863 +#define NV4_PBUS_PCIPOWER_D1 1 +#define NV4_PBUS_PCIPOWER_D1_SUPPORTED 0x1 // 1 = supported +#define NV4_PBUS_PCIPOWER_D2 2 +#define NV4_PBUS_PCIPOWER_D2_SUPPORTED 0x1 // 0 = not supported +#define NV4_PBUS_PCIPOWER_PME_D0 3 +#define NV4_PBUS_PCIPOWER_PME_D0_SUPPORTED 0x1 +#define NV4_PBUS_PCIPOWER_PME_D1 4 +#define NV4_PBUS_PCIPOWER_PME_D1_SUPPORTED 0x1 +#define NV4_PBUS_PCIPOWER_PME_D2 5 +#define NV4_PBUS_PCIPOWER_PME_D2_SUPPORTED 0x1 +#define NV4_PBUS_PCIPOWER_PME_D3_HOT 6 +#define NV4_PBUS_PCIPOWER_PME_D3_HOT_SUPPORTED 0x1 +#define NV4_PBUS_PCIPOWER_PME_D3_COLD 7 +#define NV4_PBUS_PCIPOWER_PME_D3_COLD_SUPPORTED 0x1 +#define NV4_PBUS_PCIPOWER_STATE_CURRENT 0x1864 +#define NV4_PBUS_PCIPOWER_STATE 0 +#define NV4_PBUS_PCIPOWER_STATE_D3_HOT 0x3 +#define NV4_PBUS_PCIPOWER_STATE_D2 0x2 +#define NV4_PBUS_PCIPOWER_STATE_D1 0x1 +#define NV4_PBUS_PCIPOWER_STATE_D0 0x0 #define NV4_PFIFO_START 0x2000 #define NV4_PFIFO_END 0x3FFF - #define NV4_PFIFO_DELAY_0 0x2040 #define NV4_PFIFO_DELAY_0_WAIT_RETRY 0 #define NV4_PFIFO_DELAY_0_WAIT_RETRY_0 0x0 @@ -3249,6 +3216,7 @@ #define NV4_CIO_START 0x3B0 #define NV4_CIO_END 0x3DF +#define NV4_CIO_SIZE NV4_CIO_END - NV4_CIO_START #define NV4_CIO_INP0 0x3c2 @@ -3403,7 +3371,7 @@ #define NV4_CIO_CRE_TREG_VCNTA_INDEX 0x6 #define NV4_CIO_CRE_TREG_VCNTB_INDEX 0x7 #define NV4_CIO_CRE_DDC_STATUS_INDEX 0x3E -#define NV4_CIO_CRE_DDC_WR_INDEX 0x3F +#define NV4_CIO_CRE_DDC_WR_INDEX 0x3F // Write to i2c for EDID/DDC #define NV4_CIO_CRE_PCI_TO_INDEX 0x40 #define NV4_CIO_CRE_PCI_TO_DELAY 0 @@ -3456,6 +3424,10 @@ #define NV4_PRMVIO_GX_READ_MAP_INDEX 0x4 #define NV4_PRMVIO_GX_MODE_INDEX 0x5 #define NV4_PRMVIO_GX_MISC_INDEX 0x6 +#define NV4_PRMVIO_GX_MISC_BANKED_128K_A0000 0x00 +#define NV4_PRMVIO_GX_MISC_BANKED_64K_A0000 0x04 +#define NV4_PRMVIO_GX_MISC_BANKED_32K_B0000 0x08 +#define NV4_PRMVIO_GX_MISC_BANKED_32K_B8000 0x0C #define NV4_PRMVIO_GX_DONT_CARE_INDEX 0x7 #define NV4_PRMVIO_GX_BIT_MASK_INDEX 0x8 @@ -3922,6 +3894,7 @@ // But this part may not work #define NV4_PRAMIN_START 0x700000 #define NV4_PRAMIN_END 0x7FFFFF +#define NV4_PRAMIN_SIZE 0xFFFFF #define NV4_PRAMIN_CONTEXT_0 ( 0*32+31):( 0*32+ 0) #define NV4_PRAMIN_CONTEXT_1 ( 1*32+31):( 1*32+ 0) @@ -4002,35 +3975,35 @@ // DFB is in BAR1. Access it as VRAM -#define NV4_PEXTDEV_BOOT_0 0x101000 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_SPEED 0 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_33MHZ 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_66MHZ 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR 1 -#define NV4_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_NO_BIOS 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_BIOS 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_TYPE 2 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_256K 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x2 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_1024K_2BANK 0x3 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH 4 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_64 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_128 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_TYPE 5 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_PCI 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_AGP 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_CRYSTAL 6 -#define NV4_PEXTDEV_BOOT_0_STRAP_CRYSTAL_13500K 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_CRYSTAL_14318180 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_TVMODE 7 -#define NV4_PEXTDEV_BOOT_0_STRAP_TVMODE_SECAM 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_TVMODE_NTSC 0x1 -#define NV4_PEXTDEV_BOOT_0_STRAP_TVMODE_PAL 0x2 -#define NV4_PEXTDEV_BOOT_0_STRAP_TVMODE_DISABLED 0x3 -#define NV4_PEXTDEV_BOOT_0_STRAP_OVERWRITE 11 -#define NV4_PEXTDEV_BOOT_0_STRAP_OVERWRITE_DISABLED 0x0 -#define NV4_PEXTDEV_BOOT_0_STRAP_OVERWRITE_ENABLED 0x1 +#define NV4_PEXTDEV_BOOT_0 0x101000 +#define NV4_STRAP_BUS_SPEED 0 +#define NV4_STRAP_BUS_SPEED_33MHZ 0x0 +#define NV4_STRAP_BUS_SPEED_66MHZ 0x1 +#define NV4_STRAP_SUB_VENDOR 1 +#define NV4_STRAP_SUB_VENDOR_NO_BIOS 0x0 +#define NV4_STRAP_SUB_VENDOR_BIOS 0x1 +#define NV4_STRAP_RAM_TYPE 2 +#define NV4_STRAP_RAM_TYPE_SGRAM_256K 0x0 +#define NV4_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x1 +#define NV4_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x2 +#define NV4_STRAP_RAM_TYPE_1024K_2BANK 0x3 +#define NV4_STRAP_RAM_WIDTH 4 +#define NV4_STRAP_RAM_WIDTH_64 0x0 +#define NV4_STRAP_RAM_WIDTH_128 0x1 +#define NV4_STRAP_BUS_TYPE 5 +#define NV4_STRAP_BUS_TYPE_PCI 0x0 +#define NV4_STRAP_BUS_TYPE_AGP 0x1 +#define NV4_STRAP_CRYSTAL 6 +#define NV4_STRAP_CRYSTAL_13500K 0x0 +#define NV4_STRAP_CRYSTAL_14318180 0x1 +#define NV4_STRAP_TVMODE 7 +#define NV4_STRAP_TVMODE_SECAM 0x0 +#define NV4_STRAP_TVMODE_NTSC 0x1 +#define NV4_STRAP_TVMODE_PAL 0x2 +#define NV4_STRAP_TVMODE_DISABLED 0x3 +#define NV4_STRAP_OVERWRITE 11 +#define NV4_STRAP_OVERWRITE_DISABLED 0x0 +#define NV4_STRAP_OVERWRITE_ENABLED 0x1 #define NV4_PDAC_START 0x680000 #define NV4_PDAC_END 0x680FFF diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 41ff22447..c03ac15c9 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -199,6 +199,7 @@ add_library(vid OBJECT # NVidia RIVA TNT/TNT2 - Core nv/nv4/nv4_core.c + nv/nv4/nv4_core_io.c nv/nv4/nv4_core_config.c # Generic diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index 46b6cf9c3..d051a8f15 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -197,9 +197,7 @@ void nv3_mmio_write16(uint32_t addr, uint16_t val, void* priv) nv_log_verbose_only("Redirected MMIO write16 to SVGA: addr=0x%04x val=0x%02x\n", addr, val); nv3_svga_write(real_address, val & 0xFF, nv3); - - if (val > 0xFF) - nv3_svga_write(real_address + 1, (val >> 8) & 0xFF, nv3); + nv3_svga_write(real_address + 1, (val >> 8) & 0xFF, nv3); return; } @@ -227,15 +225,9 @@ void nv3_mmio_write32(uint32_t addr, uint32_t val, void* priv) nv_log_verbose_only("Redirected MMIO write32 to SVGA: addr=0x%04x val=0x%02x\n", addr, val); nv3_svga_write(real_address, val & 0xFF, nv3); - - if (val > 0xFF) - nv3_svga_write(real_address + 1, (val >> 8) & 0xFF, nv3); - - if (val > 0xFFFF) - nv3_svga_write(real_address + 2, (val >> 16) & 0xFF, nv3); - - if (val > 0xFFFFFF) - nv3_svga_write(real_address + 3, (val >> 24) & 0xFF, nv3); + nv3_svga_write(real_address + 1, (val >> 8) & 0xFF, nv3); + nv3_svga_write(real_address + 2, (val >> 16) & 0xFF, nv3); + nv3_svga_write(real_address + 3, (val >> 24) & 0xFF, nv3); return; } @@ -276,7 +268,7 @@ uint8_t nv3_agp_read(int32_t func, int32_t addr) ret = nv3->nvbase.agp_enabled; break; default: - ret = nv3->pci_config.pci_regs[addr]; + ret = nv3->nvbase.pci_config.pci_regs[addr]; break; } @@ -329,25 +321,25 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) // 66Mhz FSB capable case PCI_REG_COMMAND_L: - ret = nv3->pci_config.pci_regs[PCI_REG_COMMAND_L]; + ret = nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L]; 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 + ret = nv3->nvbase.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); + ret = (nv3->nvbase.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]; + ret = nv3->nvbase.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); + ret = (nv3->nvbase.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: @@ -400,7 +392,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) break; case NV3_PCI_CFG_ENABLE_VBIOS: - ret = nv3->pci_config.vbios_enabled; + ret = nv3->nvbase.pci_config.vbios_enabled; break; case NV3_AGP_CAPABILITIES_POINTER: @@ -411,7 +403,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) break; case NV3_PCI_CFG_INT_LINE: - ret = nv3->pci_config.int_line; + ret = nv3->nvbase.pci_config.int_line; break; case NV3_PCI_CFG_INT_PIN: @@ -433,7 +425,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) 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)]; + ret = nv3->nvbase.pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)]; break; case NV3_AGP_START ... NV3_AGP_END: @@ -446,7 +438,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) default: // by default just return pci_config.pci_regs - ret = nv3->pci_config.pci_regs[addr]; + ret = nv3->nvbase.pci_config.pci_regs[addr]; break; } @@ -457,7 +449,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) void nv3_agp_write(int32_t func, int32_t addr, uint8_t val) { - nv3->pci_config.pci_regs[addr] = val; + nv3->nvbase.pci_config.pci_regs[addr] = val; switch (addr) { @@ -471,7 +463,6 @@ void nv3_agp_write(int32_t func, int32_t addr, uint8_t val) void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) { - // sanity check if (!nv3) return; @@ -484,29 +475,28 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) nv_log("nv3_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr, val); - nv3->pci_config.pci_regs[addr] = val; + nv3->nvbase.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; + nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L] = val; // actually update the mappings nv3_update_mappings(); break; case PCI_REG_COMMAND_H: - nv3->pci_config.pci_regs[PCI_REG_COMMAND_H] = val; + nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_H] = 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); + nv3->nvbase.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); + nv3->nvbase.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(); @@ -520,9 +510,9 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) // 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); + nv3->nvbase.pci_config.vbios_enabled = (val & 0x01); - if (nv3->pci_config.vbios_enabled) + if (nv3->nvbase.pci_config.vbios_enabled) { // First see if we simply wanted to change the VBIOS location @@ -533,8 +523,8 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) { 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; + uint32_t new_addr = nv3->nvbase.pci_config.pci_regs[NV3_PCI_CFG_VBIOS_BASE_H] << 24 | + nv3->nvbase.pci_config.pci_regs[NV3_PCI_CFG_VBIOS_BASE_L] << 16; // move it mem_mapping_set_addr(&nv3->nvbase.vbios.mapping, new_addr, 0x8000); @@ -555,7 +545,7 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) } break; case NV3_PCI_CFG_INT_LINE: - nv3->pci_config.int_line = val; + nv3->nvbase.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: @@ -564,7 +554,7 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) // 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; + nv3->nvbase.pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)] = val; break; case NV3_AGP_START ... NV3_AGP_END: @@ -855,16 +845,14 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) i2c_gpio_set(nv3->nvbase.i2c, scl, sda); break; } - /* [6:0] contains cursorAddr [23:17] */ + /* [6:0] contains cursorAddr [22:16] */ case NV3_CRTC_REGISTER_CURSOR_ADDR0: - nv3->pramdac.cursor_address |= val << 17; //bit7 technically ignored, but nv don't care, so neither do we + nv3->pramdac.cursor_address |= ((val & 0x7F) << 12); //bit7 technically ignored, but nv don't care, so neither do we break; /* [7:2] contains cursorAddr [16:11] */ case NV3_CRTC_REGISTER_CURSOR_ADDR1: - nv3->pramdac.cursor_address |= (val >> 2) << 13; // bit0 and 1 aren't part of the address + nv3->pramdac.cursor_address |= ((val & 0xF8) << 4); // bit0 and 1 aren't part of the address break; - - } /* Recalculate the timings if we actually changed them @@ -1130,7 +1118,6 @@ void nv3_init_mappings_mmio(void) nv3_ramin_write32, NULL, MEM_MAPPING_EXTERNAL, nv3); - mem_mapping_add(&nv3->nvbase.ramin_mapping_mirror, 0, 0, nv3_ramin_read8, nv3_ramin_read16, @@ -1140,14 +1127,11 @@ void nv3_init_mappings_mmio(void) nv3_ramin_write32, NULL, MEM_MAPPING_EXTERNAL, nv3); - } void nv3_init_mappings_svga(void) { nv_log("Initialising SVGA core memory mapping\n"); - - // setup the svga mappings mem_mapping_add(&nv3->nvbase.framebuffer_mapping, 0, 0, nv3_dfb_read8, @@ -1191,20 +1175,20 @@ void nv3_update_mappings(void) 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"); + (nv3->nvbase.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_read, NULL, NULL, nv3_svga_write, NULL, NULL, nv3); - if (nv3->pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + if (nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) io_sethandler(0x03c0, 0x0020, nv3_svga_read, NULL, NULL, nv3_svga_write, NULL, NULL, nv3); - if (!(nv3->pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + if (!(nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { nv_log("The memory was turned off, not much is going to happen.\n"); return; @@ -1412,8 +1396,8 @@ void* nv3_init(const device_t *info) 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; + nv3->nvbase.pci_config.int_line = 0xFF; // per datasheet + nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEM; // svga is done, so now initialise the real gpu diff --git a/src/video/nv/nv4/nv4_core.c b/src/video/nv/nv4/nv4_core.c index d020e44e6..58aba93b1 100644 --- a/src/video/nv/nv4/nv4_core.c +++ b/src/video/nv/nv4/nv4_core.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * NV3 bringup and device emulation. + * NV4 bringup and device emulation. * * * Authors: Connor Hyde, I need a better email address ;^) @@ -29,9 +29,178 @@ nv4_t* nv4; +// Initialise the MMIO mappings +void nv4_init_mappings_mmio(void) +{ + nv_log("Initialising MMIO mapping\n"); + + // 0x0 - 1000000: regs + // 0x1000000-2000000 + + // initialize the mmio mapping + mem_mapping_add(&nv4->nvbase.mmio_mapping, 0, 0, + nv4_mmio_read8, + nv4_mmio_read16, + nv4_mmio_read32, + nv4_mmio_write8, + nv4_mmio_write16, + nv4_mmio_write32, + NULL, MEM_MAPPING_EXTERNAL, nv4); + + // initialize the mmio mapping + mem_mapping_add(&nv4->nvbase.ramin_mapping, 0, 0, + nv4_ramin_read8, + nv4_ramin_read16, + nv4_ramin_read32, + nv4_ramin_write8, + nv4_ramin_write16, + nv4_ramin_write32, + NULL, MEM_MAPPING_EXTERNAL, nv4); + +} + +void nv4_init_mappings_svga(void) +{ + nv_log("Initialising SVGA core memory mapping\n"); + // setup the svga mappings + mem_mapping_add(&nv4->nvbase.framebuffer_mapping, 0, 0, + nv4_dfb_read8, + nv4_dfb_read16, + nv4_dfb_read32, + nv4_dfb_write8, + nv4_dfb_write16, + nv4_dfb_write32, + nv4->nvbase.svga.vram, 0, &nv4->nvbase.svga); + + // the SVGA/LFB mapping is also mirrored + mem_mapping_add(&nv4->nvbase.framebuffer_mapping_mirror, 0, 0, + nv4_dfb_read8, + nv4_dfb_read16, + nv4_dfb_read32, + nv4_dfb_write8, + nv4_dfb_write16, + nv4_dfb_write32, + nv4->nvbase.svga.vram, 0, &nv4->nvbase.svga); + + io_sethandler(NV4_CIO_START, NV4_CIO_SIZE, + nv4_svga_read, NULL, NULL, + nv4_svga_write, NULL, NULL, + nv4); +} + +void nv4_init_mappings(void) +{ + nv4_init_mappings_mmio(); + nv4_init_mappings_svga(); +} + +// Updates the mappings after initialisation. +void nv4_update_mappings(void) +{ + // sanity check + if (!nv4) + return; + + // setting this to 0 doesn't seem to disable it, based on the datasheet + + nv_log("\nMemory Mapping Config Change:\n"); + + (nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) ? nv_log("Enable I/O\n") : nv_log("Disable I/O\n"); + + io_removehandler(NV4_CIO_START, NV4_CIO_SIZE, + nv4_svga_read, NULL, NULL, + nv4_svga_write, NULL, NULL, + nv4); + + if (nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + io_sethandler(NV4_CIO_START, NV4_CIO_SIZE, + nv4_svga_read, NULL, NULL, + nv4_svga_write, NULL, NULL, + nv4); + + if (!(nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + nv_log("The memory was turned off, not much is going to happen.\n"); + return; + } + + // turn off bar0 and bar1 by defualt + mem_mapping_disable(&nv4->nvbase.mmio_mapping); + mem_mapping_disable(&nv4->nvbase.framebuffer_mapping); + mem_mapping_disable(&nv4->nvbase.framebuffer_mapping_mirror); + mem_mapping_disable(&nv4->nvbase.ramin_mapping); + + // Setup BAR0 (MMIO) + + nv_log("BAR0 (MMIO Base) = 0x%08x\n", nv4->nvbase.bar0_mmio_base); + + if (nv4->nvbase.bar0_mmio_base) + { + mem_mapping_set_addr(&nv4->nvbase.mmio_mapping, nv4->nvbase.bar0_mmio_base, NV4_MMIO_SIZE); + mem_mapping_set_addr(&nv4->nvbase.ramin_mapping, nv4->nvbase.bar0_mmio_base + NV4_PRAMIN_START, NV4_PRAMIN_SIZE); + } + + // if this breaks anything, remove it + nv_log("BAR1 (Linear Framebuffer & VRAM) = 0x%08x\n", nv4->nvbase.bar1_lfb_base); + + if (nv4->nvbase.bar1_lfb_base) + { + if (nv4->nvbase.vram_amount == NV4_VRAM_SIZE_16MB) + { + // we don't need this one in the case of 16mb, + mem_mapping_disable(&nv4->nvbase.framebuffer_mapping_mirror); + mem_mapping_set_addr(&nv4->nvbase.framebuffer_mapping, nv4->nvbase.bar1_lfb_base, NV4_VRAM_SIZE_16MB); + } + else if (nv4->nvbase.vram_amount == NV4_VRAM_SIZE_8MB) + { + mem_mapping_set_addr(&nv4->nvbase.framebuffer_mapping, nv4->nvbase.bar1_lfb_base, NV4_VRAM_SIZE_8MB); + mem_mapping_set_addr(&nv4->nvbase.framebuffer_mapping_mirror, nv4->nvbase.bar1_lfb_base + NV4_VRAM_SIZE_8MB, NV4_VRAM_SIZE_8MB); + } + } + + // Did we change the banked SVGA mode? + switch (nv4->nvbase.svga.gdcreg[NV4_PRMVIO_GX_MISC_INDEX] & 0x0c) + { + case NV4_PRMVIO_GX_MISC_BANKED_128K_A0000: + nv_log("SVGA Banked Mode = 128K @ A0000h\n"); + mem_mapping_set_addr(&nv4->nvbase.svga.mapping, 0xA0000, 0x20000); // 128kb @ 0xA0000 + nv4->nvbase.svga.banked_mask = 0x1FFFF; + break; + case NV4_PRMVIO_GX_MISC_BANKED_64K_A0000: + nv_log("SVGA Banked Mode = 64K @ A0000h\n"); + mem_mapping_set_addr(&nv4->nvbase.svga.mapping, 0xA0000, 0x10000); // 64kb @ 0xA0000 + nv4->nvbase.svga.banked_mask = 0xFFFF; + break; + case NV4_PRMVIO_GX_MISC_BANKED_32K_B0000: + nv_log("SVGA Banked Mode = 32K @ B0000h\n"); + mem_mapping_set_addr(&nv4->nvbase.svga.mapping, 0xB0000, 0x8000); // 32kb @ 0xB0000 + nv4->nvbase.svga.banked_mask = 0x7FFF; + break; + case NV4_PRMVIO_GX_MISC_BANKED_32K_B8000: + nv_log("SVGA Banked Mode = 32K @ B8000h\n"); + mem_mapping_set_addr(&nv4->nvbase.svga.mapping, 0xB8000, 0x8000); // 32kb @ 0xB8000 + nv4->nvbase.svga.banked_mask = 0x7FFF; + break; + } +} + + void nv4_init() { nv4 = calloc(1, sizeof(nv4_t)); + + if (!nv4->nvbase.vram_amount) + nv4->nvbase.vram_amount = device_get_config_int("vram_size"); + + /* Set log device name based on card model */ + const char* log_device_name = "NV4"; + + if (device_get_config_int("nv_debug_fulllog")) + nv4->nvbase.log = log_open("NV4"); + else + nv4->nvbase.log = log_open_cyclic("NV4"); + + nv_log_set_device(nv4->nvbase.log); } void* nv4_init_stb4400(const device_t *info) @@ -71,7 +240,7 @@ int32_t nv4_available(void) return (rom_present(NV4_VBIOS_STB_REVA)); } -// NV3 (RIVA 128) +// NV4 (RIVA 128) // AGP // 8MB or 16MB VRAM const device_t nv4_device_agp = diff --git a/src/video/nv/nv4/nv4_core_io.c b/src/video/nv/nv4/nv4_core_io.c new file mode 100644 index 000000000..a7fe0d0c8 --- /dev/null +++ b/src/video/nv/nv4/nv4_core_io.c @@ -0,0 +1,1310 @@ +/* + * 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. + * + * NV4 I/O, including Real-Mode Access (RMA), memory mapping, PCI, AGP, SVGA and MMIO via PCI BARs + * + * MMIO dumps are available at: https://nvwiki.org/misc/NVDumps/ + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + + +// Prototypes for functions only used in this translation unit + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv4.h> + + +void nv4_init_mappings_mmio(void); +void nv4_init_mappings_svga(void); +bool nv4_is_svga_redirect_address(uint32_t addr); + +uint8_t nv4_svga_read(uint16_t addr, void* priv); +void nv4_svga_write(uint16_t addr, uint8_t val, void* priv); + + +uint32_t nv4_mmio_arbitrate_read(uint32_t addr) +{ + +} + +void nv4_mmio_arbitrate_write(uint32_t addr, uint32_t val) +{ + +} + +// Determine if this address needs to be redirected to the SVGA subsystem. + +bool nv4_is_svga_redirect_address(uint32_t addr) +{ + return (addr >= NV4_PRMVIO_START && addr <= NV4_PRMVIO_END) // VGA + || (addr >= NV4_PRMCIO_START && addr <= NV4_PRMCIO_END) // CRTC + || (addr >= NV4_USER_DAC_START && addr <= NV4_USER_DAC_END); // Note: 6813c6-6813c9 are ignored somewhere else +} + +uint8_t nv4_rma_read(uint16_t addr) +{ + addr &= 0xFF; + uint32_t real_final_address = 0x0; + uint8_t ret = 0x0; + + switch (addr) + { + // signature so you know reads work + case 0x00: + ret = NV4_PRMIO_RMA_ID_CODE_VALID & 0xFF; + break; + case 0x01: + ret = (NV4_PRMIO_RMA_ID_CODE_VALID >> 8) & 0xFF; + break; + case 0x02: + ret = (NV4_PRMIO_RMA_ID_CODE_VALID >> 16) & 0xFF; + break; + case 0x03: + ret = (NV4_PRMIO_RMA_ID_CODE_VALID >> 24) & 0xFF; + break; + case 0x08 ... 0x0B: + // reads must be dword aligned + real_final_address = (nv4->pbus.rma.addr + (addr & 0x03)); + + if (nv4->pbus.rma.addr < NV4_MMIO_SIZE) + ret = nv4_mmio_read8(real_final_address, NULL); + else + { + /* Do we need to read RAMIN here? */ + ret = nv4->nvbase.svga.vram[real_final_address - NV4_MMIO_SIZE] & (nv4->nvbase.svga.vram_max - 1); + } + + // log current location for vbios RE + nv_log_verbose_only("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 nv4_rma_write(uint16_t addr, uint8_t val) +{ + // 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 + nv4->pbus.rma.addr &= ~0xff; + nv4->pbus.rma.addr |= val; + break; + case 0x01: // 2nd highest byte + nv4->pbus.rma.addr &= ~0xff00; + nv4->pbus.rma.addr |= (val << 8); + break; + case 0x02: // 3rd highest byte + nv4->pbus.rma.addr &= ~0xff0000; + nv4->pbus.rma.addr |= (val << 16); + break; + case 0x03: // 4th highest byte + nv4->pbus.rma.addr &= ~0xff000000; + nv4->pbus.rma.addr |= (val << 24); + break; + } + } + // Data to send to MMIO + else + { + switch (addr % 0x04) + { + case 0x00: // lowest byte + nv4->pbus.rma.data &= ~0xff; + nv4->pbus.rma.data |= val; + break; + case 0x01: // 2nd highest byte + nv4->pbus.rma.data &= ~0xff00; + nv4->pbus.rma.data |= (val << 8); + break; + case 0x02: // 3rd highest byte + nv4->pbus.rma.data &= ~0xff0000; + nv4->pbus.rma.data |= (val << 16); + break; + case 0x03: // 4th highest byte + nv4->pbus.rma.data &= ~0xff000000; + nv4->pbus.rma.data |= (val << 24); + + nv_log_verbose_only("MMIO Real Mode Access write transaction complete, initial address=0x%04x final RMA MMIO address=0x%08x data=0x%08x\n", + addr, nv4->pbus.rma.addr, nv4->pbus.rma.data); + + if (nv4->pbus.rma.addr < NV4_MMIO_SIZE) + nv4_mmio_write32(nv4->pbus.rma.addr, nv4->pbus.rma.data, NULL); + else // failsafe code, i don't think you will ever write outside of VRAM? + { + uint32_t* vram_32 = (uint32_t*)nv4->nvbase.svga.vram; + vram_32[(nv4->pbus.rma.addr - NV4_MMIO_SIZE) >> 2] = nv4->pbus.rma.data; + } + + + break; + } + } + + if (addr & 0x10) + nv4->pbus.rma.addr += 0x04; // Alignment +} + + + +// 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 nv4_mmio_read8(uint32_t addr, void* priv) +{ + uint32_t ret = 0x00; + + // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. + addr &= 0xFFFFFF; + + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV4_USER_DAC_PALETTE_START && addr <= NV4_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + return nv4_mmio_arbitrate_read(addr); + } + + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv4_svga_read(real_address, nv4); + + nv_log_verbose_only("Redirected MMIO read8 to SVGA: addr=0x%04x returned 0x%04x\n", addr, ret); + + return ret; + } + + // see if unaligned reads are a problem + ret = nv4_mmio_read32(addr, priv); + return (uint8_t)(ret >> ((addr & 3) << 3) & 0xFF); +} + +// Read 16-bit MMIO +uint16_t nv4_mmio_read16(uint32_t addr, void* priv) +{ + uint32_t ret = 0x00; + + // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. + addr &= 0xFFFFFF; + + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv4_svga_read(real_address, nv4) + | (nv4_svga_read(real_address + 1, nv4) << 8); + + nv_log_verbose_only("Redirected MMIO read16 to SVGA: addr=0x%04x returned 0x%04x\n", addr, ret); + + return ret; + } + + ret = nv4_mmio_read32(addr, priv); + return (uint8_t)(ret >> ((addr & 3) << 3) & 0xFFFF); +} + +// Read 32-bit MMIO +uint32_t nv4_mmio_read32(uint32_t addr, void* priv) +{ + uint32_t ret = 0x00; + + // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. + addr &= 0xFFFFFF; + + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv4_svga_read(real_address, nv4) + | (nv4_svga_read(real_address + 1, nv4) << 8) + | (nv4_svga_read(real_address + 2, nv4) << 16) + | (nv4_svga_read(real_address + 3, nv4) << 24); + + nv_log_verbose_only("Redirected MMIO read32 to SVGA: addr=0x%04x returned 0x%04x\n", addr, ret); + + return ret; + } + + ret = nv4_mmio_arbitrate_read(addr); + + return ret; +} + +// Write 8-bit MMIO +void nv4_mmio_write8(uint32_t addr, uint8_t val, void* priv) +{ + addr &= 0xFFFFFF; + + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV4_USER_DAC_PALETTE_START && addr <= NV4_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + nv4_mmio_arbitrate_write(addr, val); + return; + } + + // This is weitek vga stuff + // If we need to add more of these we can convert these to a switch statement + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + nv_log_verbose_only("Redirected MMIO write8 to SVGA: addr=0x%04x val=0x%02x\n", addr, val); + + nv4_svga_write(real_address, val & 0xFF, nv4); + + return; + } + + // overwrite first 8bits of a 32 bit value + uint32_t new_val = nv4_mmio_read32(addr, NULL); + + new_val &= (~0xFF << (addr & 3) << 3); + new_val |= (val << ((addr & 3) << 3)); + + nv4_mmio_write32(addr, new_val, priv); +} + +// Write 16-bit MMIO +void nv4_mmio_write16(uint32_t addr, uint16_t val, void* priv) +{ + addr &= 0xFFFFFF; + + // This is weitek vga stuff + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + nv_log_verbose_only("Redirected MMIO write16 to SVGA: addr=0x%04x val=0x%02x\n", addr, val); + + nv4_svga_write(real_address, val & 0xFF, nv4); + nv4_svga_write(real_address + 1, (val >> 8) & 0xFF, nv4); + + return; + } + + // overwrite first 16bits of a 32 bit value + uint32_t new_val = nv4_mmio_read32(addr, NULL); + + new_val &= (~0xFFFF << (addr & 3) << 3); + new_val |= (val << ((addr & 3) << 3)); + + nv4_mmio_write32(addr, new_val, priv); +} + +// Write 32-bit MMIO +void nv4_mmio_write32(uint32_t addr, uint32_t val, void* priv) +{ + addr &= 0xFFFFFF; + + // This is weitek vga stuff + if (nv4_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + nv_log_verbose_only("Redirected MMIO write32 to SVGA: addr=0x%04x val=0x%02x\n", addr, val); + + nv4_svga_write(real_address, val & 0xFF, nv4); + nv4_svga_write(real_address + 1, (val >> 8) & 0xFF, nv4); + nv4_svga_write(real_address + 2, (val >> 16) & 0xFF, nv4); + nv4_svga_write(real_address + 3, (val >> 24) & 0xFF, nv4); + + return; + } + + nv4_mmio_arbitrate_write(addr, val); +} + +// PCI stuff +// BAR0 Pointer to MMIO space & RAMIN +// BAR1 Pointer to Linear Framebuffer +uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv) +{ + uint8_t ret = 0x00; + + // sanity check + if (!nv4) + return ret; + + // Convert to the MMIO addresses + if (addr <= 0xFF) + addr += 0x1800; + + // Anything not listed is 0x00 + // PCI values extracted from https://nvwiki.org/misc/NVDumps/RivaMobileNV4/Nv4win_HL/nv4bar0.bin + // STB V4400 (running Half-Life) + switch (addr) + { + // Get the pci vendor id.. + + case NV4_PBUS_PCI_VENDOR_ID: + ret = (NV4_PBUS_PCI_DEVICE_VENDOR_NVIDIA & 0xFF); + break; + + case NV4_PBUS_PCI_VENDOR_ID + 1: // all access 8bit + ret = (NV4_PBUS_PCI_DEVICE_VENDOR_NVIDIA >> 8); + break; + + // device id + + case NV4_PBUS_PCI_DEVICE_ID: + ret = (NV_PCI_DEVICE_NV4 & 0xFF); + break; + + case NV4_PBUS_PCI_DEVICE_ID + 1: + ret = (NV_PCI_DEVICE_NV4 >> 8); + break; + + // various capabilities enabled by default + // IO space enabled + // Memory space enabled + // Bus master enabled + // Write/inval enabled + // Pal snoop enabled + // Capabiliies list enabled + // 66Mhz FSB capable + + case NV4_PBUS_PCI_COMMAND: + ret = nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L]; + break; + // COMMAND_L not used + + // pci status register + case NV4_PBUS_PCI_STATUS: + if (nv4->straps + & NV4_STRAP_BUS_SPEED_66MHZ) + ret = (nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] | NV4_PBUS_PCI_STATUS_66MHZ_CAPABLE); + else + ret = nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L]; + + break; + + case NV4_PBUS_PCI_STATUS_2: + ret = (nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_H]) & (NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_FAST << NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING); + break; + + case NV4_PBUS_PCI_REVISION_ID: + ret = nv4->nvbase.gpu_revision; // Commercial release + break; + + case PCI_REG_PROG_IF: + ret = 0x00; + break; + + // We only need to return 0x30 since the VGA class code is 0x30000 + case NV4_PBUS_PCI_CLASS_CODE: + ret = (NV4_PBUS_PCI_CLASS_CODE_VGA) >> 12; // CLASS_CODE_VGA + break; + + + case NV4_PBUS_PCI_LATENCY_TIMER: + case NV4_PBUS_PCI_HEADER_TYPE: + ret = 0x00; + break; + + // BARs are marked as prefetchable per the datasheet + case NV4_PBUS_PCI_BAR0_INFO: + case NV4_PBUS_PCI_BAR1_INFO: + // only bit that matters is bit 3 (prefetch bit) + ret = (NV4_PBUS_PCI_BAR_PREFETCHABLE_MERGABLE << NV4_PBUS_PCI_BAR_PREFETCHABLE); + break; + + // MMIO base address + case NV4_PBUS_PCI_BAR0_BASE_31_TO_24: + ret = nv4->nvbase.bar0_mmio_base >> 24;//8bit value + break; + + case NV4_PBUS_PCI_BAR1_BASE_31_TO_24: + ret = nv4->nvbase.bar1_lfb_base >> 24; //8bit value + break; + + case NV4_PBUS_PCI_ROM: + ret = nv4->nvbase.pci_config.vbios_enabled; + break; + + case NV4_PBUS_PCI_INTR_LINE: + ret = nv4->nvbase.pci_config.int_line; + break; + + case NV4_PBUS_PCI_INTR_PIN: + ret = PCI_INTA; + break; + + // + // Capabilities pointers + // + + case NV4_PBUS_PCI_NEXT_PTR: + ret = NV4_PBUS_PCI_CAP_PTR_POWER_MGMT; + break; + + case NV4_PBUS_PCIPOWER_NEXT_PTR: + ret = NV4_PBUS_PCI_CAP_PTR_AGP; + break; + + // AGP is the end of the chain + case NV4_PBUS_AGP_NEXT_PTR: + ret = 0x00; + break; + + case NV4_PBUS_PCI_MAX_LAT: + ret = NV4_PBUS_PCI_MAX_LAT_250NS; + break; + + // these map to the subsystem + // todo: port this bugfix to NV4 + case NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID_WRITABLE: + case NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID_WRITABLE + 1: + case NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE: + case NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE + 1: + ret = nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_SUBSYSTEM_ID + (addr & 0x03)]; + break; + case NV4_PBUS_AGP_CAPABILITIES: + ret = NV4_PBUS_AGP_CAPABILITY_AGP; // AGP capable device + break; + case NV4_PBUS_AGP_REV: + ret = (NV4_PBUS_AGP_REV_MAJOR_1 << NV4_PBUS_AGP_REV_MAJOR) | NV4_PBUS_AGP_REV_MINOR; + break; + case NV4_PBUS_AGP_STATUS_RATE: + ret = NV4_PBUS_AGP_STATUS_RATE_1X_AND_2X; + break; + case NV4_PBUS_AGP_STATUS_SBA: + ret = (NV4_PBUS_AGP_STATUS_SBA_STATUS_CAPABLE) << NV4_PBUS_AGP_STATUS_SBA_STATUS; // Sideband is supported on NV4 + break; + case NV4_PBUS_AGP_STATUS_RQ: + ret = NV4_PBUS_AGP_STATUS_RQ_16; + break; + case NV4_PBUS_AGP_COMMAND_2: + ret = (nv4->nvbase.agp_enabled) << NV4_PBUS_AGP_COMMAND_2_AGP_ENABLED + | (nv4->nvbase.agp_sba_enabled) << NV4_PBUS_AGP_COMMAND_2_SBA_ENABLED; + break; + default: // by default just return pci_config.pci_regs (default value for nonwritten registers is 0x00) + ret = nv4->nvbase.pci_config.pci_regs[addr]; + break; + + } + + nv_log("nv4_pci_read func=0x%04x addr=0x%04x ret=0x%04x\n", func, addr, ret); + return ret; +} + + +// nv4 pci/agp write +void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) +{ + // sanity check + if (!nv4) + return; + + // Convert to the MMIO addresses + if (addr <= 0xFF) + addr += 0x1800; + // some addresses are not writable so can't have any effect and can't be allowed to be modified using this code + // as an example, only the most significant byte of the PCI BARs can be modified + if (addr == NV4_PBUS_PCI_BAR0_UNUSED1 || addr == NV4_PBUS_PCI_BAR0_UNUSED2 + && addr == NV4_PBUS_PCI_BAR1_UNUSED1 || addr == NV4_PBUS_PCI_BAR1_UNUSED2) + return; + + nv_log("nv4_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr, val); + + nv4->nvbase.pci_config.pci_regs[addr] = val; + + switch (addr) + { + // standard pci command stuff + case PCI_REG_COMMAND_L: + nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L] = val; + // actually update the mappings + nv4_update_mappings(); + break; + case PCI_REG_COMMAND_H: + nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_H] = val; + // actually update the mappings + nv4_update_mappings(); + break; + // pci status register + case PCI_REG_STATUS_L: + nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] = val | (NV4_PBUS_PCI_STATUS_66MHZ_CAPABLE << NV4_PBUS_PCI_STATUS_66MHZ); + break; + case PCI_REG_STATUS_H: + nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_H] = val | (NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING_FAST << NV4_PBUS_PCI_STATUS_2_DEVSEL_TIMING); + break; + //TODO: ACTUALLY REMAP THE MMIO AND NV_USER + case NV4_PBUS_PCI_BAR0_BASE_31_TO_24: + nv4->nvbase.bar0_mmio_base = val << 24; + nv4_update_mappings(); + break; + case NV4_PBUS_PCI_BAR1_BASE_31_TO_24: + nv4->nvbase.bar1_lfb_base = val << 24; + nv4_update_mappings(); + break; + case NV4_PBUS_PCI_ROM: + case NV4_PBUS_PCI_ROM_BASE: + + // make sure we are actually toggling the vbios, not the rom base + if (addr == NV4_PBUS_PCI_ROM) + nv4->nvbase.pci_config.vbios_enabled = (val & 0x01); + + if (nv4->nvbase.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(&nv4->nvbase.vbios.mapping); + + if (addr != NV4_PBUS_PCI_ROM) + { + uint32_t old_addr = nv4->nvbase.vbios.mapping.base; + // 9bit register + uint32_t new_addr = nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM + 1] << 24 | + nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM] << 16; + + // move it + mem_mapping_set_addr(&nv4->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(&nv4->nvbase.vbios.mapping); + + } + break; + case NV4_PBUS_PCI_INTR_LINE: + nv4->nvbase.pci_config.int_line = val; + break; + // these are mirrored to the subsystem id and also stored in the ROMBIOS + //todo: port to pci + case NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE: + case NV4_PBUS_PCI_SUBSYSTEM_ID_WRITABLE + 1: + case NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID_WRITABLE: + case NV4_PBUS_PCI_SUBSYSTEM_VENDOR_ID_WRITABLE + 1: + nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_SUBSYSTEM_ID + (addr & 0x03)] = val; + break; + case NV4_PBUS_AGP_COMMAND_2: + nv4->nvbase.agp_enabled = (val >> NV4_PBUS_AGP_COMMAND_2_AGP_ENABLED) & 0x01; + nv4->nvbase.agp_sba_enabled = (val >> NV4_PBUS_AGP_COMMAND_2_SBA_ENABLED) & 0x01; + break; + default: + break; + } +} + + +// +// SVGA functions +// +void nv4_recalc_timings(svga_t* svga) +{ + // sanity check + if (!nv4) + return; + + + nv4_t* nv4 = (nv4_t*)svga->priv; + + // TODO: Everything, this code sucks, incl. NV4_PRAMDAC_GENERAL_CONTROL_BPC and the OFFSET register + uint32_t pixel_mode = svga->crtc[NV4_CIO_CRE_PIXEL_INDEX] & 0x03; + + svga->memaddr_latch += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0x1F) << 16; + + /* Turn off override if we are in VGA mode */ + svga->override = !(pixel_mode == NV4_CIO_CRE_PIXEL_FORMAT_VGA); + + /* NOTE: The RIVA 128 draws in a way almost completely separate to any other 86Box GPU. + + Basically, we only blit to buffer32 when something changes and we don't even bother using a timer. We only render when there is something to actually render. + + This is because there is no linear relationship between the contents of VRAM and the contents of the display which 86box's SVGA subsystem cannot tolerate. + In fact, the position in VRAM and pitch can be changed at any time via an NV_IMAGE_IN_MEMORY object. + + Therefore, we need to completely bypass it using svga->override and draw our own rendering functions. This allows us to use a neat optimisation trick + to only ever actually draw when we need to do something. This shouldn't be a problem in games, because the drivers will read the current refresh rate from + the Windows settings, and then, just submit objects at that pace for anything that changes on the screen. + */ + + // Set the pixel mode + switch (pixel_mode) + { + case NV4_CIO_CRE_PIXEL_FORMAT_8BPP: + svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 1; // ????? + svga->bpp = 8; + svga->lowres = 0; + svga->map8 = svga->pallook; + break; + case NV4_CIO_CRE_PIXEL_FORMAT_16BPP: + /* This is some sketchy shit that is an attempt at an educated guess + at pixel clock differences between 9x and NT only in 16bpp. If there is ever an error on 9x with "interlaced" looking graphics, + this is what's causing it. Possibly fucking up the drivers under *ReactOS* of all things */ + if ((svga->crtc[NV4_CIO_CR_VRS_INDEX] >> 1) & 0x01) + svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 2; + else + svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3; + + // 15bpp mode is removed on NV4 + // TODO: Not svga + svga->bpp = 16; + svga->lowres = 0; + + break; + case NV4_CIO_CRE_PIXEL_FORMAT_32BPP: + svga->rowoffset += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0xE0) << 3; + + svga->bpp = 32; + svga->lowres = 0; + //svga->render = nv4_render_32bpp; + break; + } + + + if (((svga->miscout >> 2) & 2) == 2) + { + // set clocks + //nv4_pramdac_set_pixel_clock(); + //nv4_pramdac_set_vram_clock(); + } +} + +void nv4_speed_changed(void* priv) +{ + // sanity check + if (!nv4) + return; + + nv4_recalc_timings(&nv4->nvbase.svga); +} + +// Force Redraw +// Reset etc. +void nv4_force_redraw(void* priv) +{ + // sanity check + if (!nv4) + return; + + nv4->nvbase.svga.fullchange = changeframecount; +} + +// CHECK that ramin is the smae as nv4 + +// Read 8-bit ramin +uint8_t nv4_ramin_read8(uint32_t addr, void* priv) +{ + if (!nv4) return 0x00; + + addr &= (nv4->nvbase.svga.vram_max - 1); + uint32_t raw_addr = addr; // saved after and + + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + + uint32_t val = 0x00; + + //if (!nv4_ramin_arbitrate_read(addr, &val)) // Oh well + //{ + val = (uint8_t)nv4->nvbase.svga.vram[addr]; + nv_log_verbose_only("Read byte from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + //} + + return (uint8_t)val; +} + +// Read 16-bit ramin +uint16_t nv4_ramin_read16(uint32_t addr, void* priv) +{ + if (!nv4) return 0x00; + + addr &= (nv4->nvbase.svga.vram_max - 1); + + // why does this not work in one line + svga_t* svga = &nv4->nvbase.svga; + uint16_t* vram_16bit = (uint16_t*)svga->vram; + uint32_t raw_addr = addr; // saved after and + + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + addr >>= 1; // what + + uint32_t val = 0x00; + + //if (!nv4_ramin_arbitrate_read(addr, &val)) + //{ + val = (uint16_t)vram_16bit[addr]; + nv_log_verbose_only("Read word from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr); + //} + + return val; +} + +// Read 32-bit ramin +uint32_t nv4_ramin_read32(uint32_t addr, void* priv) +{ + if (!nv4) + return 0x00; + + addr &= (nv4->nvbase.svga.vram_max - 1); + + // why does this not work in one line + uint32_t* vram_32bit = (uint32_t*)nv4->nvbase.svga.vram; + uint32_t raw_addr = addr; // saved after and logged + + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + addr >>= 2; // what + + uint32_t val = 0x00; + + //if (!nv4_ramin_arbitrate_read(addr, &val)) + //{ + val = vram_32bit[addr]; + nv_log_verbose_only("Read dword from PRAMIN 0x%08x <- 0x%08x (raw address=0x%08x)\n", val, addr, raw_addr); + //} + + return val; +} + +// Write 8-bit ramin +void nv4_ramin_write8(uint32_t addr, uint8_t val, void* priv) +{ + if (!nv4) return; + + addr &= (nv4->nvbase.svga.vram_max - 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/nv4t only and 2mb...i haven't found a 22mb card) + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + + uint32_t val32 = (uint32_t)val; + + //if (!nv4_ramin_arbitrate_write(addr, val32)) + //{ + nv4->nvbase.svga.vram[addr] = val; + nv_log_verbose_only("Write byte to PRAMIN addr=0x%08x val=0x%02x (raw address=0x%08x)\n", addr, val, raw_addr); + //} +} + +// Write 16-bit ramin +void nv4_ramin_write16(uint32_t addr, uint16_t val, void* priv) +{ + if (!nv4) return; + + addr &= (nv4->nvbase.svga.vram_max - 1); + + // why does this not work in one line + svga_t* svga = &nv4->nvbase.svga; + uint16_t* vram_16bit = (uint16_t*)svga->vram; + uint32_t raw_addr = addr; // saved after and + + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + addr >>= 1; // what + + uint32_t val32 = (uint32_t)val; + + //if (!nv4_ramin_arbitrate_write(addr, val32)) + //{ + vram_16bit[addr] = val; + nv_log_verbose_only("Write word to PRAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, val, raw_addr); + //} + + +} + +// Write 32-bit ramin +void nv4_ramin_write32(uint32_t addr, uint32_t val, void* priv) +{ + if (!nv4) return; + + addr &= (nv4->nvbase.svga.vram_max - 1); + + // why does this not work in one line + svga_t* svga = &nv4->nvbase.svga; + uint32_t* vram_32bit = (uint32_t*)svga->vram; + uint32_t raw_addr = addr; // saved after and + + addr ^= (nv4->nvbase.svga.vram_max - 0x10); + addr >>= 2; // what + + //if (!nv4_ramin_arbitrate_write(addr, val)) + //{ + vram_32bit[addr] = val; + nv_log_verbose_only("Write dword to PRAMIN addr=0x%08x val=0x%08x (raw address=0x%08x)\n", addr, val, raw_addr); + //} +} + +// Read from SVGA core memory +uint8_t nv4_svga_read(uint16_t addr, void* priv) +{ + // CR = CRTC Controller + // CRE = CRTC Controller Extended (weitek) + + nv4_t* nv4 = (nv4_t*)priv; + + uint8_t ret = 0x00; + + // sanity check + if (!nv4) + return ret; + + // If we need to RMA from GPU MMIO, go do that + if (addr >= NV4_RMA_REGISTER_START + && addr <= NV4_RMA_REGISTER_END) + { + if (!(nv4->pbus.rma.mode & 0x01)) + return ret; + + // must be dword aligned + uint32_t real_rma_read_addr = ((nv4->pbus.rma.mode & 0x0E) << 1) + (addr & 0x03); + ret = nv4_rma_read(real_rma_read_addr); + return ret; + } + + // mask off b0/d0 registers + if ((((addr & 0xFFF0) == 0x3D0 + || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) + && !(nv4->nvbase.svga.miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + // Alias for "get current SVGA CRTC register ID" + case NV4_CIO_CRX_COLOR: + ret = nv4->nvbase.svga.crtcreg; + break; + case NV4_CIO_CR_COLOR: + // Support the extended NVIDIA CRTC register range + switch (nv4->nvbase.svga.crtcreg) + { + case NV4_CIO_CRE_RL0_INDEX: + ret = nv4->nvbase.svga.displine & 0xFF; + break; + /* Is rl1?*/ + case NV4_CIO_CRE_RL1_INDEX: + ret = (nv4->nvbase.svga.displine >> 8) & 7; + break; + case NV4_CIO_CRE_DDC_STATUS_INDEX: + ret = i2c_gpio_get_sda(nv4->nvbase.i2c) << 3 + | i2c_gpio_get_scl(nv4->nvbase.i2c) << 2; + + break; + default: + ret = nv4->nvbase.svga.crtc[nv4->nvbase.svga.crtcreg]; + } + break; + default: + ret = svga_in(addr, &nv4->nvbase.svga); + break; + } + + return ret; //TEMP +} + +// Write to SVGA core memory +void nv4_svga_write(uint16_t addr, uint8_t val, void* priv) +{ + // sanity check + if (!nv4) + return; + + // If we need to RMA to GPU MMIO, go do that + if (addr >= NV4_RMA_REGISTER_START + && addr <= NV4_RMA_REGISTER_END) + { + // we don't need to store these registers... + nv4->pbus.rma.rma_regs[addr & 3] = val; + + if (!(nv4->pbus.rma.mode & 0x01)) // we are halfway through sending something + return; + + uint32_t real_rma_write_addr = ((nv4->pbus.rma.mode & (0x0E)) << 1) + (addr & 0x03); + + nv4_rma_write(real_rma_write_addr, nv4->pbus.rma.rma_regs[addr & 0x03]); + return; + } + + // mask off b0/d0 registers + if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) + && addr < 0x3de) + && !(nv4->nvbase.svga.miscout & 1))//miscout bit 7 controls mappping + addr ^= 0x60; + + uint8_t crtcreg = nv4->nvbase.svga.crtcreg; + uint8_t old_val = 0x00; + + // todo: + // Pixel formats (8bit vs 555 vs 565) + // VBE 3.0? + + switch (addr) + { + case NV4_CIO_CRX_COLOR: + // real mode access to GPU MMIO space... + nv4->nvbase.svga.crtcreg = val; + break; + // support the extended crtc regs and debug this out + case NV4_CIO_CR_COLOR: + + // Implements the VGA Protect register + if ((nv4->nvbase.svga.crtcreg < NV4_CIO_CR_OVL_INDEX) && (nv4->nvbase.svga.crtc[NV4_CIO_CR_VRE_INDEX] & 0x80)) + return; + + // Ignore certain bits when VGA Protect register set and we are writing to CRTC register=07h + if ((nv4->nvbase.svga.crtcreg == NV4_CIO_CR_OVL_INDEX) && (nv4->nvbase.svga.crtc[NV4_CIO_CR_VRE_INDEX] & 0x80)) + val = (nv4->nvbase.svga.crtc[NV4_CIO_CR_OVL_INDEX] & ~0x10) | (val & 0x10); + + // set the register value... + old_val = nv4->nvbase.svga.crtc[crtcreg]; + + nv4->nvbase.svga.crtc[crtcreg] = val; + // ...now act on it + + // Handle nvidia extended Bank0/Bank1 IDs + switch (crtcreg) + { + case NV4_CIO_CRE_PAGE0_INDEX: + nv4->nvbase.cio_read_bank = val; + if (nv4->nvbase.svga.chain4) // chain4 addressing (planar?) + nv4->nvbase.svga.read_bank = nv4->nvbase.cio_read_bank << 15; + else + nv4->nvbase.svga.read_bank = nv4->nvbase.cio_read_bank << 13; // extended bank numbers + break; + case NV4_CIO_CRE_PAGE1_INDEX: + nv4->nvbase.cio_write_bank = val; + if (nv4->nvbase.svga.chain4) + nv4->nvbase.svga.write_bank = nv4->nvbase.cio_write_bank << 15; + else + nv4->nvbase.svga.write_bank = nv4->nvbase.cio_write_bank << 13; + break; + case NV4_CIO_CRE_RMA_INDEX: + nv4->pbus.rma.mode = val & NV4_PRMIO_RMA_MODE_MAX; + break; + /* Handle some large screen stuff */ + case NV4_CIO_CRE_PIXEL_INDEX: + if (val & 1 << (NV4_CIO_CRE_LSR_VDT_10)) + nv4->nvbase.svga.vtotal += 0x400; + if (val & 1 << (NV4_CIO_CRE_LSR_VRS_10)) + nv4->nvbase.svga.vblankstart += 0x400; + if (val & 1 << (NV4_CIO_CRE_LSR_VBS_10)) + nv4->nvbase.svga.vsyncstart += 0x400; + if (val & 1 << (NV4_CIO_CRE_LSR_HBE_6)) + nv4->nvbase.svga.hdisp += 0x400; + + /* Make sure dispend and vblankstart are right if we are displaying above 1024 vert */ + if (nv4->nvbase.svga.crtc[NV4_CIO_CRE_PIXEL_INDEX] & 1 << (NV4_CIO_CRE_LSR_VDE_10)) + nv4->nvbase.svga.dispend += 0x400; + + break; + case NV4_CIO_CRE_HEB_INDEX: // large screen bit + if (val & 0x01) + nv4->nvbase.svga.hdisp += 0x100; + break; + case NV4_CIO_CRE_DDC_WR_INDEX: + { + uint8_t scl = !!(val & 0x20); + uint8_t sda = !!(val & 0x10); + // Set an I2C GPIO register + i2c_gpio_set(nv4->nvbase.i2c, scl, sda); + break; + } + /* [6:0] contains cursorAddr [23:17] */ + case NV4_CIO_CRE_HCUR_ADDR0_INDEX: + nv4->pramdac.cursor_address |= (val & 0x7F) << 13; //bit7 technically ignored, but nv don't care, so neither do we + break; + /* [7:2] contains cursorAddr [16:11] */ + case NV4_CIO_CRE_HCUR_ADDR1_INDEX: + nv4->pramdac.cursor_address |= (val & 0xFC) << 5; // bit0 and 1 aren't part of the address + break; + + + } + + /* Recalculate the timings if we actually changed them + Additionally only do it if the value actually changed*/ + if (old_val != val) + { + // Thx to Fuel who basically wrote most of the SVGA compatibility code already (although I fixed some issues), because VGA is boring + // and in the words of an ex-Rendition/3dfx/NVIDIA engineer, "VGA was basically an undocumented bundle of steaming you-know-what. + // And it was essential that any cores the PC 3D startups acquired had to work with all the undocumented modes and timing tweaks (mode X, etc.)" + if (nv4->nvbase.svga.crtcreg < 0xE + || nv4->nvbase.svga.crtcreg > 0x10) + { + nv4->nvbase.svga.fullchange = changeframecount; + nv4_recalc_timings(&nv4->nvbase.svga); + } + } + + break; + default: + svga_out(addr, val, &nv4->nvbase.svga); + break; + } + +} + +/* DFB, sets up a dumb framebuffer */ +uint8_t nv4_dfb_read8(uint32_t addr, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + return nv4->nvbase.svga.vram[addr]; +} + +uint16_t nv4_dfb_read16(uint32_t addr, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + return (nv4->nvbase.svga.vram[addr + 1] << 8) | nv4->nvbase.svga.vram[addr]; +} + +uint32_t nv4_dfb_read32(uint32_t addr, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + return (nv4->nvbase.svga.vram[addr + 3] << 24) | (nv4->nvbase.svga.vram[addr + 2] << 16) + + (nv4->nvbase.svga.vram[addr + 1] << 8) | nv4->nvbase.svga.vram[addr]; +} + +void nv4_dfb_write8(uint32_t addr, uint8_t val, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + nv4->nvbase.svga.vram[addr] = val; + nv4->nvbase.svga.changedvram[addr >> 12] = val; + //nv4_render_current_bpp_dfb_8(addr); +} + +void nv4_dfb_write16(uint32_t addr, uint16_t val, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + nv4->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; + nv4->nvbase.svga.vram[addr] = (val) & 0xFF; + nv4->nvbase.svga.changedvram[addr >> 12] = val; + + //nv4_render_current_bpp_dfb_16(addr); + +} + +void nv4_dfb_write32(uint32_t addr, uint32_t val, void* priv) +{ + addr &= (nv4->nvbase.svga.vram_mask); + nv4->nvbase.svga.vram[addr + 3] = (val >> 24) & 0xFF; + nv4->nvbase.svga.vram[addr + 2] = (val >> 16) & 0xFF; + nv4->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; + nv4->nvbase.svga.vram[addr] = (val) & 0xFF; + nv4->nvbase.svga.changedvram[addr >> 12] = val; + + //removed until there is a render pipeline + //nv4_render_current_bpp_dfb_32(addr); + +} + +/* Cursor shit */ +void nv4_draw_cursor(svga_t* svga, int32_t drawline) +{ + // sanity check + if (!nv4) + return; + + /* + Commented out until we have a real graphics pipeline going here + + // if cursor disabled is set, return + if ((nv4->nvbase.svga.crtc[NV4_CRTC_REGISTER_CURSOR_START] >> NV4_CRTC_REGISTER_CURSOR_START_DISABLED) & 0x01) + return; + + // NT GDI drivers: Load cursor using NV_IMAGE_FROM_MEMORY ("NV4LCD") + // 9x GDI drivers: Use H/W cursor in RAMIN + + // Do we need to emulate it? + + // THIS IS CORRECT. BUT HOW DO WE FIND IT? + uint32_t ramin_cursor_position = NV4_RAMIN_OFFSET_CURSOR; + + /* let's just assume buffer 0 here...that code needs to be totally rewritten + nv4_coord_16_t start_position = nv4->pramdac.cursor_start; + + /* refuse to draw if thge cursor is offscreen + if (start_position.x >= nv4->nvbase.svga.hdisp + || start_position.y >= nv4->nvbase.svga.dispend) + { + return; + } + + nv_log("nv4_draw_cursor start=0x%04x,0x%04x", start_position.x, start_position.y); + + uint32_t final_position = nv4_render_get_vram_address_for_buffer(start_position, 0); + + uint16_t* vram_16 = (uint16_t*)nv4->nvbase.svga.vram; + uint32_t* vram_32 = (uint32_t*)nv4->nvbase.svga.vram; + + /* + We have to get a 32x32, "A"1R5G5B5-format cursor + out of video memory. The alpha bit actually means - XOR with display pixel if 0, replace if 1 + + These are expanded to RGB10 only if they are XORed. We don't do this (we don't really need to + there is no grobj specified here so special casing + would be needed) so we just xor it with the current pixel format + + for (int32_t y = 0; y < NV4_PRAMDAC_CURSOR_SIZE_Y; y++) + { + for (int32_t x = 0; x < NV4_PRAMDAC_CURSOR_SIZE_X; x++) + { + uint16_t current_pixel = nv4_ramin_read16(ramin_cursor_position, nv4); + + // 0000 = transparent, so skip drawing + if (current_pixel) + { + bool replace_bit = (current_pixel & 0x8000); + + // use buffer 0 BPIXEL + uint32_t bpixel_format = (nv4->pgraph.bpixel[0]) & 0x03; + + switch (bpixel_format) + { + case bpixel_fmt_8bit: + if (replace_bit) + nv4->nvbase.svga.vram[final_position] = current_pixel; + else //xor + { + // not sure what to do here. we'd have to search through the palette to find the closest possible colour. + uint8_t final = current_pixel ^ nv4->nvbase.svga.vram[final_position]; + nv4->nvbase.svga.vram[final_position] = final; + } + case bpixel_fmt_16bit: // easy case (our cursor is 15bpp format) + uint32_t index_16 = final_position >> 1; + + if (replace_bit) // just replace + vram_16[index_16] = current_pixel; + else // xor + { + current_pixel &= ~0x8000; // mask off the xor bit + uint16_t final = current_pixel ^ vram_16[index_16]; + vram_16[index_16] = final; + } + case bpixel_fmt_32bit: + uint32_t index_32 = final_position >> 2; + + if (replace_bit) // just replace + vram_32[index_32] = nv4->nvbase.svga.conv_16to32(&nv4->nvbase.svga, current_pixel, 15); // 565_MODE doesn't seem to matter here + else //xor + { + current_pixel &= ~0x8000; // mask off the xor bit + uint32_t current_pixel_32 = nv4->nvbase.svga.conv_16to32(&nv4->nvbase.svga, current_pixel, 15); // 565_MODE doesn't seem to matter here + + uint32_t final = current_pixel_32 ^ vram_32[index_32]; + vram_32[index_32] = final; + } + break; + } + } + + // increment vram position + ramin_cursor_position += 2; + + // go + switch (nv4->nvbase.svga.bpp) + { + case 8: + final_position++; + case 15 ... 16: + final_position += 2; + break; + case 32: + final_position += 4; + break; + } + + start_position.x++; + } + + + start_position.y++; + start_position.x = nv4->pramdac.cursor_start.x; + + // reset at the end of each line so we "jump" to the start x + final_position = nv4_render_get_vram_address_for_buffer(start_position, 0); + }*/ +} + +// MMIO 0x110000->0x111FFF is mapped to a mirror of the VBIOS. +// Note this area is 64kb and the vbios is only 32kb. See below.. + +uint8_t nv4_prom_read(uint32_t address) +{ + // prom area is 64k, so... + // first see if we even have a rom of 64kb in size + uint32_t max_rom_size = NV4_PROM_END - NV4_PROM_START; + uint32_t real_rom_size = max_rom_size; + + // set it + if (nv4->nvbase.vbios.sz < max_rom_size) + real_rom_size = nv4->nvbase.vbios.sz; + + //get our real address + uint8_t rom_address = address & max_rom_size; + + // Does this mirror on real hardware? + if (rom_address >= real_rom_size) + { + nv_log("PROM VBIOS Read to INVALID address 0x%05x, returning 0xFF", rom_address); + return 0xFF; + } + else + { + uint8_t val = nv4->nvbase.vbios.rom[rom_address]; + nv_log("PROM VBIOS Read 0x%05x <- 0x%05x", val, rom_address); + return val; + } +} + +void nv4_prom_write(uint32_t address, uint32_t value) +{ + uint32_t real_addr = address & 0x1FFFF; + nv_log("What's going on here? Tried to write to the Video BIOS ROM? (Address=0x%05x, value=0x%02x)", real_addr, value); +}