diff --git a/CMakeLists.txt b/CMakeLists.txt index 29fedd6ad..7ba7e9a75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,15 @@ option(DISCORD "Discord Rich Presence support" option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs" OFF) option(LIBASAN "Enable compilation with the addresss sanitizer" OFF) -if((ARCH STREQUAL "arm64")) +if (NV_LOG) + add_compile_definitions(ENABLE_NV_LOG) +endif() + +if (NV_LOG_ULTRA) + add_compile_definitions(ENABLE_NV_LOG_ULTRA) +endif() + +if((ARCH STREQUAL "arm64") OR (ARCH STREQUAL "arm")) set(NEW_DYNAREC ON) else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) @@ -184,9 +192,12 @@ cmake_dependent_option(PCL "Generic PCL5e Printer" cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF) cmake_dependent_option(WACOM "Wacom Input Devices" ON "DEV_BRANCH" OFF) cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF) +cmake_dependent_option(NV3 "NVidia RIVA 128/128ZX (NV3/NV3T)" ON "DEV_BRANCH" OFF) + cmake_dependent_option(NETSWITCH "Network Switch Support" ON "DEV_BRANCH" OFF) cmake_dependent_option(VFIO "Virtual Function I/O" ON "DEV_BRANCH" OFF) + # Ditto but for Qt if(QT) option(USE_QT6 "Use Qt6 instead of Qt5" OFF) diff --git a/CMakePresets.json b/CMakePresets.json index be6615088..53ddffc74 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -35,7 +35,10 @@ { "name": "debug", "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" + "CMAKE_BUILD_TYPE": "Debug", + "NV_LOG": "ON", + "NV_LOG_ULTRA": "ON" + }, "inherits": "base" }, diff --git a/doc/nvidia_notes/2025-01-24.txt b/doc/nvidia_notes/2025-01-24.txt new file mode 100644 index 000000000..e35818dc0 --- /dev/null +++ b/doc/nvidia_notes/2025-01-24.txt @@ -0,0 +1 @@ +THIS IS FIFOSERVICE!!!!!!!!!!!! \ No newline at end of file diff --git a/doc/nvidia_notes/B = BUFFER. REMEMBER THESE!!!.txt b/doc/nvidia_notes/B = BUFFER. REMEMBER THESE!!!.txt new file mode 100644 index 000000000..e8f183240 --- /dev/null +++ b/doc/nvidia_notes/B = BUFFER. REMEMBER THESE!!!.txt @@ -0,0 +1 @@ +B = BUFFER. REMEMBER THESE!!! \ No newline at end of file diff --git a/doc/nvidia_notes/How to optimise riva 128 applications.txt b/doc/nvidia_notes/How to optimise riva 128 applications.txt new file mode 100644 index 000000000..004593a21 --- /dev/null +++ b/doc/nvidia_notes/How to optimise riva 128 applications.txt @@ -0,0 +1,6 @@ +How to optimise riva 128 applications: +* Ensure any set of polygons with one texture is close to a multiple of 128 polygons. +* Try to sort areas of a model with one texture to as close to 128 polygons as possible for efficient submission due to the lack of texturing. +* Try to have around (32*128) for nv3 or (64*128) for nv3t polygons +* Get coding +* Alcohol \ No newline at end of file diff --git a/doc/nvidia_notes/Memory map (RIVA 128).txt b/doc/nvidia_notes/Memory map (RIVA 128).txt new file mode 100644 index 000000000..fbfe9074f --- /dev/null +++ b/doc/nvidia_notes/Memory map (RIVA 128).txt @@ -0,0 +1,81 @@ +Memory map (RIVA 128) + +32 megabytes of MMIO starting at 0x0000000-0x01FFFFFF + +MC (Master Control) 0x00000000-0x00000FFF + Config/Boot 0x00000000-0x000000FF + Master Config 0x00000100-0x00000FFF + Also used to define DMA channel IDs? + +MPU-401 I/O 0x00000330-0x00000331 Probably NV1 leftover, NV1 has mpu401 emulation -- no audio in nv3 +VGA emulated ports 0x000003B0-0x000003DF Emulated I/O ports for VGA + +Bus Control (PBUS) 0x00001000-0x00001FFF +FIFO (PFIFO) 0x00002000-0x00003FFF Submit starting at 0x00800000. Used to configure RAMHT,RAMFC,RAMRO structures & cache + +PRM 0x00004000-0x00005FFF Realmode DOS device support + +PRMIO 0x00007000-0x00007FFF Realmode access to PCI BAR (Base Address Register) + PCI I/O +PTIMER 0x00009000-0x00009FFF Timer + +VGA emulation 0x0000A000-0x0000BFFF + +VGA vram emulation 0x000A0000-0x000BFFFF (PRMVGA) +VGA 0x000C0000-0x000C7FFF VGA sequencer + graph controller registers (PRMVIO) + +(All of this up to 0x0000FFFF can be traced) + +PFB (Framebuffer) 0x00100000-0x00100FFF Interface to vram +PEXTDEV 0x00101000-0x00101FFF External device interface - contains straps + Straps 0x00101000 11 bits of cfg + +ROM (VBIOS?) 0x00110000-0x0011FFFF +PALT (?) 0x00120000-0x00120FFF + +PEXTDEV 0x00101000-0x00101FFF External Devices + +Media Engine (PME) 0x00200000-0x00200FFF Allows for external video capture according to envytools? + +PGRAPH (3D rendering) 0x00400000-0x00401FFF + +PGRAPH objects (using RAMHT???) +*i assume that when you submit an object these are the registers used to actually draw the current object + +Beta blending factor 0x00410000-0x00411FFF +ROP 0x00420000-0x00421FFF Global bitwise operation (Render OPeration) for filtering the final pixel +Color Key 0x00430000-0x00431FFF +Plane Switch 0x00440000-0x00441FFF Something to do with color formats and objects? +Clipping 0x00450000-0x00451FFF +Blend Pattern 0x00460000-0x00461FFF Used for specific blending modes +Quad [OBSOLETE] 0x00470000-0x00471FFF A rectangle. NV1 LEFTOVER, OBSOLETE +Point 0x00480000-0x00481FFF A single point +Line 0x00490000-0x00491FFF A line (with an optional colour). Can also draw a polygon made out of lines - polyline +Lin 0x004A0000-0x004A1FFF A line, without starting or ending pixel (with an optional colour). Can also draw a "polylin" +Triangle [OBSOLETE] 0x004B0000-0x004B1FFF A triangle. NV1 LEFTOVER, OBSOLETE? +Win95 GDI text 0x004C0000-0x004C1FFF Win95 text acceleration +Memory to memory xfer 0x004D0000-0x004D1FFF Represents a memory to memory transfer +Scaled image from vram 0x004E0000-0x004E1FFF Scaled image from GPU VRAM +Image blit from vram 0x00500000-0x00501FFF Image from GPU VRAM +Image blit from cpu 0x00510000-0x00511FFF Image from CPU +Bitmap from cpu 0x00520000-0x00521FFF Bitmap from CPU +Image to memory 0x00540000-0x00541FFF Image to GPU VRAM +Stretch image from cpu 0x00550000-0x00551FFF Stretched image from CPU +Direct3D 5.0 triangle 0x00570000-0x00571FFF A triangle optimised explicitly for directx3/directx5 rendering - supercedes UTRI +PointZ 0x00580000-0x00581FFF A single point with "zeta factor" (not sure what this is yet) +Image in memory 0x005C0000-0x005C0FFF Image in vram(?) + +PVIDEO (Video Control) 0x00680000-0x006802FF +External DAC 0x00680000-0x006800FF + +PRMCIO 0x00601000-0x00601FFF VGA emulation - CRTC + attribute controller + +PRAMDAC 0x00680300-0x00680FFF (used for color lookup tables, hardware cursor, video overlay, PLL for clocking and pixel generation) +"USER" DAC 0x00681200-0x00681FFF + +DMA submission w/FIFO 0x00800000-0x00FFFFFF NV_USER - uses FIFO buffer + +PNVM / PDFB / VRAM 0x01000000-0x017FFFFF (actual VRAM amount depends on card, but max is 8MB) + +RAMIN 0x01C00000-0x01FFFFFF (note that this is actually mapped in the last 1mb of vram) + +contains ramht that has obj parameters for submission, configurable \ No newline at end of file diff --git a/doc/nvidia_notes/NV3 DMA Engine.txt b/doc/nvidia_notes/NV3 DMA Engine.txt new file mode 100644 index 000000000..380e0281e --- /dev/null +++ b/doc/nvidia_notes/NV3 DMA Engine.txt @@ -0,0 +1,54 @@ +NV3 DMA Engine +(DirectDraw Driver) + +Initially set CACHES, CACHE1_PULL0, CACHE1_PULL1, CACHE1_DMA0 to 1 + +Same for other areas + +CACHE1_PUSH1 contains CHID + +If it's different: + +If RmFifoFlushContext failed: Do nothing + +Set PULL0, PUSH0, Caches to 1, return false + + +If it's not: +DMA TLB PTE seems to be 1 for direct programming, maybe RM does it differently +Tag=FFFFFFFF +CACHE1_DMA1 - Number of bytes to send +CACHE1_DMA2 - Get offset +CACHE1_DMA3 - Bus address space (Area BAR0 mapped to? Or bar1?) + +TO START: +To set up DMA for for Cache1 Puller: CACHE1_PULL0 -> 1, changes to 0 when done +To set up DMA Cache1 Push: CACHE1_PUsh0 -> 1, changes to 0 when done +Set CACHES to 1 + +GO: Set DMA0 to 1 + +***** Implementation in Driver ****** + +You can dma to "localvidmem:", "sysvidmem:" or "sysmem:", this is represented by a driver + +CAUSE OF FAILURE: +the pfifo is never free because it never processes the submitted objects +which means that the FIFO is never free +which means that the drivers spin forever waiting for the fifo to be free + +DMA_OBJECT STRUCTURE IN RESOURCE MANAGER: +0x328: Valid +0x34c: base address? +0x374: actually do the transfer + +some objects don't actually need to do dma, for example, video patchcord, it just creates a structure in the driver, and rop just allocate ssome memory to put the data for the patchcord/rop thing + +dma start=nv3_mini dc67 +call of mthdCreate for ***DRIVER*** CLASS ID: a7b44, check ptr + + + + + + diff --git a/doc/nvidia_notes/NV_PFB_CONFIG_0.txt b/doc/nvidia_notes/NV_PFB_CONFIG_0.txt new file mode 100644 index 000000000..dee3b646c --- /dev/null +++ b/doc/nvidia_notes/NV_PFB_CONFIG_0.txt @@ -0,0 +1,29 @@ +NV_PFB_CONFIG_0 + +Observed Valus: +Drivers 0x1000 +BIOS 0x1114 + +Bits +5:0 Resolution +9:8 Pixel depth +12:12 Tiling +13:13 Tiling Debug +14:14 Tiling Debug Tile Size +17:15 "Tetris" tiling +19:18 "Tetris" tiling shift +22:20 Bank Swap +23 Unused + +NV_PFB_CONFIG_1 +2:0 CAS Latency +3:3 NEC Mode (PC-98?) +7:4 RAS Default / 9 Cycles +10:8 RAS PCHG +14:12 RAS Low +18:16 MRS to RAS +22:20 Write to Read +26:24 RAS to CAS +30:28 Read to Write +31:31 Read to PCFg + diff --git a/doc/nvidia_notes/PFIFO RAMHT RAMRO.txt b/doc/nvidia_notes/PFIFO RAMHT RAMRO.txt new file mode 100644 index 000000000..9b4c94718 --- /dev/null +++ b/doc/nvidia_notes/PFIFO RAMHT RAMRO.txt @@ -0,0 +1,38 @@ +PIO VS dma + +driver is DIRECTLY modifying pfifo + +8X8 channel setup + +Names are 32-bit integers >4096 + +RAMFC - DMA Context object 0,0 to 8,8 + +context = channel, render object, object type, offset in instance memory + +for a rectangle (type 0x47), object render = 1, channel 0, at 0x0400 in the ramht memory + +=0x00c70400 as the context + +the ramht hash : + +xor every byte of the hash individually and then xor that with the channel number + +so obj id 01020304 in channel 0 is 1 xor 2 xor 3 xor 4 xor 0 + +Store in RAMHT at + 4*16 = name +Store in RAMHT at + 4*16 + 4 = context + +then the ramin stuff starts at *0xc04000 since c00000 is the start of ramin [PCI BAR1] which is where you put the contents of the class struct + +nv_user + +Consider the 8x8 channels as 64 subchannels. +Now you can do: + +They seem to end at 0x880000 + +(0x880000)/64 = 0x2000 for each channel + +FAILURE -> RAMRO! + diff --git a/doc/nvidia_notes/RIVA fansites.txt b/doc/nvidia_notes/RIVA fansites.txt new file mode 100644 index 000000000..d1cfaeb90 --- /dev/null +++ b/doc/nvidia_notes/RIVA fansites.txt @@ -0,0 +1,26 @@ +RIVA fansites (?????): +RIVA User's Group http://tiger.tnstate.edu:8080/ +RIVA 128 Homepage http://pages.prodigy.net/babblin5/Main.html -> Riva3D (riva3d.com) +Zone 128 http://www.tc.umn.edu/~reda0003/zone128/ +RIVAZone https://web.archive.org/web/19981212032348/http://www.rivazone.com/ (Launched January 2, 1998) +Dimension 128 http://dimension128.smartcom.net (early domain name that was mostly not archived) -> d128.com (1999-2001) +Riva3D https://web.archive.org/web/20000525110305/http://riva3d.gxnetwork.com/s3.html +nVNews https://web.archive.org/web/20001205171202/http://www.nvnews.net/ (1999-2015) + +BluesNews has stuff https://www.bluesnews.com/archives/ +(July 1996-present!) + +https://www.bluesnews.com/archives/july97-3.html July 21, 1997 ("unreleased nvidia RIVA chipset is indeed faster than 3dfx" (carmack) + +"However, using the nvidia RIVA 128 chip it runs 1 f/s faster" + +https://web.archive.org/web/19980615024744/http://www.ogr.com/columns/techtalk/technology_talk_0611_2.shtml First mention of NV10 (June 1998) + +"RIVA 128 Turbo" early ZX name +"Riva4" early TNT name + +https://web.archive.org/web/20001002193706/http://www.rivazone.com/files/rivalog.txt + +https://web.archive.org/web/20010422044820/http://www.rivazone.com/finger/finger.cgi?nick@finger.nvidia.com nvidia .plan files + +WAVE Report - april 1997 date for tapeout \ No newline at end of file diff --git a/doc/nvidia_notes/Versions.txt b/doc/nvidia_notes/Versions.txt new file mode 100644 index 000000000..052de854f --- /dev/null +++ b/doc/nvidia_notes/Versions.txt @@ -0,0 +1,8 @@ +Name Base Version Notes Date API Support Platform +0.75_nt4 Version 0.75 No Resource Manager (miniport) 1997-08-15 GDI NT4.0 +0.77_win9x Version 0.77 Symbols (COFF/VXD) 1997-09-02 GDI, D3D5 +nv3quake.zip Version 1.21 OpenGL Alpha 1 1997-11-14 GDI, D3D5, OpenGL 1.1 (alpha; Build 151) Win9x +quakea2f.zip Version 1.21 OpenGL Alpha 2 1997-12-02 GDI, D3D5, OpenGL 1.1 (alpha; Build 258) Win9x +win95_131.zip Version 1.31 OpenGL Beta 1 1998-02-04 GDI, D3D5, OpenGL 1.1 (beta; Build 661) Win9x + + diff --git a/doc/nvidia_notes/gpucompanies.txt b/doc/nvidia_notes/gpucompanies.txt new file mode 100644 index 000000000..08a6c61c5 --- /dev/null +++ b/doc/nvidia_notes/gpucompanies.txt @@ -0,0 +1,63 @@ +GPU companies (the period they made gpus) + +DEC 19xx-1998 +HP 19xx-2000+ (possibly until present) +IBM 19xx-2002+ (possibly until present) +E&S 1968-2006 +Intergraph 1969-2000 +Apple 1976-present (some break) +Motorola 1977-1994+ (???) +TI 1979-1988+ +Matrox 1979-2014 +Hitachi 1981-1986 +SGI 1981-2009 +Intel 1983-present +Number Nine 1983-2000 +Tseng Labs 1983-1997 +Cirrus Logic 1984-1998 +Video 7 1985-1991 +C&T 1985-1999 +Imagination 1985-present +NCR 1986-1993 +Paradise/WD 1986-1996 +Gemini 1987-1990 +Genoa Systems 1987-1991 +Trident 1987-2003 +Oak Technology 1988-1997 +Realtek 1988-1997 +Compaq 1989-1991 +Sun 1989-2002(+?) +S3 Graphics 1989-2010 +Macronix 1989-1998 +Winbond 1989-1996+ +Tamarack 198x-1991+ +UMC 198x-1993 +Sigma Designs 198x-1996 +Acer 198x-1998 (roughly) +Fujitsu 198x-1998 +AMD 1991-present (really starting in 2006) +HMC 1991-1994 +Avance Logic 1991-1995 +Weitek <1991-1996 +Bitboys 1991-2006 +IIT 1992-1994 +Weitek 1992-1996(?) +Rendition 1993-1998 +ARK Logic 1993-1999 +S-MOS/Stellar 1994-1999 +Nvidia 1993-present +Alliance 1994-1997 +iGS 1994-1999 +3dfx 1994-2000 +3dlabs 1994-2006 +Silicon Motion 1995-200? +SiS 1995-2007 +Dynamic Pictures1996-1997 +NeoMagic 1996-2000 +GigaPixel 1997-2000 +Philips 1997-199x +Tatung 199x-199x +ASPEED 2004-present +Jingjia 2006-present + + diff --git a/doc/nvidia_notes/hardware cursor.txt b/doc/nvidia_notes/hardware cursor.txt new file mode 100644 index 000000000..0845778f4 --- /dev/null +++ b/doc/nvidia_notes/hardware cursor.txt @@ -0,0 +1,21 @@ +NV3/NV3T/NV4 hardware cursor + +Unlock extended CRTC registers + +CIO_CRE_HCUR_ADDR0 + Bits [6:0] = Address + +CIO_CRE_HCUR_ADDR1 + Bits [7:3] = Bits [11:7] of address + Bit 1 = Cursor Doubling + Bit 0 = Enable + +PRAMDAC_CU_START_POS (MMIO 0x680300) + Bits [11:0] = X Pos + Bits [27:16] = Y Pos + +CursorAddress >> 16 written to addr0 +(((CursorAddress >> 11) & 0x1F) << 3) | 1 (for enable) written to addr1 + +Lock extended CRTC registers +Enable - write \ No newline at end of file diff --git a/doc/nvidia_notes/multithreading.pdn b/doc/nvidia_notes/multithreading.pdn new file mode 100644 index 000000000..427d4bab8 Binary files /dev/null and b/doc/nvidia_notes/multithreading.pdn differ diff --git a/doc/nvidia_notes/multithreading.png b/doc/nvidia_notes/multithreading.png new file mode 100644 index 000000000..592fe64e9 Binary files /dev/null and b/doc/nvidia_notes/multithreading.png differ diff --git a/doc/nvidia_notes/nv3 driver init status.txt b/doc/nvidia_notes/nv3 driver init status.txt new file mode 100644 index 000000000..d0d13bacd --- /dev/null +++ b/doc/nvidia_notes/nv3 driver init status.txt @@ -0,0 +1,112 @@ +Driver version: Windows 2000 Version 3.37 (23 March 1999) - SDK: Windows 2000 build 1996.1 +Features: + +Resource Manager Yes +DirectDraw Yes +OpenGL Yes +Direct3D No + + +get started: +MUST USE X86 WINDBG +Does older windbg support coff??? + +sxe ld nv3_mini.sys +bp nv3_mini + 0x409ac - 0x10000 (nv3_mini+0x309ac) + +offset purpose +30a1a RmInitRm call + +6be7 initClientInfo call +6878 initClientInfo +6bec Check for initClientInfo success +6bf4 initGrPatchPool call +6bf9 Check for initGrPatchPool success +6c01 initDmaListElementPool call +6c06 Check for initDmaListElementPool +6c1c initDisplayInfo call + +6c26 rmInitRm End + Success: eax=FFFFFFFFh / -1 +6c26 Fail eax=0 + +30c8b NvFindAdapter +30cb6 NvFindAdapter -> NVIsPresent call +1010 NVIsPresent function +102f NVIsPresent VideoPortGetAccessRanges call +103b NVIsPresent VideoPortGetAccessRanges call success check (only possible way to fail) +127c NVIsPresent end +30cbb NvFindAdapter -> NVIsPresent success check + Success: al=1 + Failure: al=0 +30cca NVIsPresent NVMapMemoryRanges call +e9e NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #1 [PCI Space] +ea4 NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #1 success check [PCI Space] +ebd NVIsPresent NVMapMemoryRanges VideoPortFreeDeviceBase [conditional] +ec3 NVIsPresent NVMapMemoryRanges VideoPortFreeDeviceBase [conditional] success check +ed6 NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #2 [MMIO] +edc NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #2 success check [MMIO] +f0c NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #3 [LFB/RAMIN?] +f12 NVIsPresent NVMapMemoryRanges VideoPortGetDeviceBase call #3 success check [LFB/RAMIN?] + +30ccf NvFindAdapter NVMapMemoryRanges success check + Success: eax=0 + Failure: eax=87 +30cf1 NvFindAdapter RmInitNvMapping call +6ce6 NvFindAdapter RmInitNvMapping +30cf6 NVIsPresent RmInitNvMapping success check + Success: eax!=0 (in practice 0xFFFFFFFF/-1) + Failure: eax=0 +30d5c NvFindAdapter +30d64 NvFindAdapter RmPostNvDevice call +6d88 RmPostNvDevice function +6d91 NvFindAdapter DevinitInitializeDevice call +6d96 NvFindAdapter DevinitInitializeDevice success check + Success: eax=0 (?) + Failure: eax=1 +e546 DevinitInitializeDevice function + [very complicated] + [several register reads] +e61d DevinitPrepDeviceForInit call +e641 DevinitPrepDeviceForInit function +e627 InitNV call +e67a InitNV function + +30d64 NVIsPresent RmPostNvDevice success check + Success: eax=0 (?) + Failure: eax=1 +30d78 NVIsPresent NVGetNVInfo call +30d7d NVIsPresent NVGetNVInfo success check + +3e9a NvFindAdapter end + Success: eax=0 + Fail eax=55 (RmInitNvMapping or NVIsPresent failed) + Fail eax=87 (NVMapMemoryRanges or NVMapFrameBuffer failed) + +30ea3 NVInitialize +30f02 NVStartIO +2aa6 NVInterrupt +30a2d NVGetChildDescriptor +30a9c NVGetPowerState +30b20 NVSetPowerState + + +Driver Init Status: +DriverEntry Success +rmInitRm -> initClientInfo Success +rmInitRm -> initGrPatchPool Success +rmInitRm -> initDmaListElementPool Success +rmInitRm -> initDisplayInfo Success +rmInitRm overall Success +NvFindAdapter Success 17:32 27/11/2024 +NvFindAdapter -> NvIsPresent Success 16:19 24/11/2024 +NvFindAdapter -> NvMapMemoryRanges Success 19:15 26/11/2024 +NvFindAdapter -> RmInitNvMapping Success 19:18 26/11/2024 +NvFindAdapter -> RmPostNvDevice Success 17:32 27/11/2024 +NvFindAdapter -> NVGetNVInfo Success 17:32 27/11/2024 +NvFindAdapter -> NVMapFrameBuffer Success 17:32 27/11/2024 + +00:00 30/12/2024: stateGr -> i2c_Write +22:31 31/12/2024: fifoService + +fix ptimer issue \ No newline at end of file diff --git a/doc/nvidia_notes/nv3 driver init status_2025-02-10.txt b/doc/nvidia_notes/nv3 driver init status_2025-02-10.txt new file mode 100644 index 000000000..b5643a2ea --- /dev/null +++ b/doc/nvidia_notes/nv3 driver init status_2025-02-10.txt @@ -0,0 +1,90 @@ +nv3_disp: + +0x10fe -> DrvBitBlt +0x19be -> DrvCopyBits +0x597c -> DrvCreateDeviceBitmap +0x5a6e -> DrvDeleteDeviceBitmap +0x60b8 -> DrvTextOut +0x6248 -> DrvDestroyFont +0x64b8 -> DrvRealizeBrush +0x6a46 -> DrvDitherColor +0x797a -> DrvGetDirectDrawInfo +0x7b14 -> DrvEnableDirectDraw +0x7b70 -> DrvDisableDirectDraw +0x817c -> DrvPaint +0x81c2 -> DrvResetPDEV +0x82dc -> DrvEnableDriver +0x8312 -> DrvEnablePDEV +0x83ee -> DrvDisablePDEV +0x840a -> DrvCompletePDEV +0x8418 -> DrvSynchronise +0x845a -> DrvEnableSurface +0x851a -> DrvDisableSurface +0x8554 -> DrvAssertMode +0x8690 -> DrvGetModes +0xe59a -> DrvEscape +0xf3ee -> DrvFillPath +0xf3f6 -> DrvStrokePath +0xfa08 -> DrvLineTo +0x12fee -> DrvSetPalette +0x132a4 -> DrvMovePointer +0x13d20 -> DrvSetPointerShape +0x13dea -> DrvStretchBlt +0x147f2 -> DrvSetPixelFormat +0x1483c -> DrvDescribePixelFormat +0x1495a -> DrvClipChanged +0x255b8 -> DrvSwapBuffers + +DrvEnableDriver SUCCESS +DrvEnablePDEV SUCCESS 23:28 09/02/2025 + Check for cjCaps >= 0x130 && cjDevInfo >= 0x12C SUCCESS 23:31 09/02/2025 + EngAllocMem call SUCCESS 23:38 09/02/2025 + CreateOglGlobalMemory call SUCCESS 23:40 09/02/2025 + bInitializeModeFields call SUCCESS 23:41 09/02/2025 + bInitializePalette call SUCCESS 23:42 09/02/2025 + EngDeviceIoControl IOCTL 0x232020 (CHECK mini) SUCCESS + EngDeviceIoControl IOCTL 0x232044 (CHECK mini) SUCCESS (eax=0) +DrvCompletePDEV SUCCESS 23:52 09/02/2025 +DrvEnableSurface + bEnableHardware call SUCCESS 22:36 13/02/2025 + EngCreateSemaphore call #1 csCrtc SUCCESS 00:55 10/02/2025 + EngCreateSemaphore call #2 csFifo SUCCESS 00:57 10/02/2025 + EngDeviceIoControl IOCTL 0x230460 SUCCESS 00:57 10/02/2025 + EngDeviceIoControl IOCTL 0x230458 SUCCESS 00:57 10/02/2025 + NvAllocRoot SUCCESS 01:03 10/02/2025 + NvAllocDevice SUCCESS 01:04 10/02/2025 + NV3/NV4 architecture check SUCCESS 01:14 10/02/2025 + bAssertModeHardware call (bEnable=1) SUCCESS Passing starting with build at 02:23 10/02/2025 + EngDeviceIoControl IOCTL 0x23040C] SUCCESS Passing starting with build at 02:23 10/02/2025 + nv3_mini NVStartIO ioctlcode=0x23040C + NVSetMode + NV3SetMode SUCCESS 01:53 10/02/2025 + RmUnloadState SUCCESS 01:48 10/02/2025 + VBESetModeEx SUCCESS 01:51 10/02/2025 + NV_OEMEnableExtensions SUCCESS 01:52 10/02/2025 + UpdateArbitrationSettings SUCCESS 01:52 10/02/2025 + RmLoadState SUCCESS 01:53 10/02/2025 + NV3EnableCursor SUCCESS 01:54 10/02/2025 + NV3WaitUntilFinished SUCCESS 02:23 10/02/2025 + EngDeviceIoControl IOCTL 0x230408 SUCCESS 02:26 10/02/2025 + EngDeviceIoControl IOCTL 0x232024 SUCCESS 02:26 10/02/2025 + NvAllocHardware SUCCESS 02:29 10/02/2025 + bCreateStdPatches(?) SUCCESS (EAX=1!!!) 22:24 13/02/2025 + CHECK - NV4 N/A + vDestroyStdPatches(?) N/A + NV3_WaitForOneVerticalRefresh SUCCESS + EngDeviceIoControl IOCTL 0x230410 SUCCESS + + + SET UP CORRECT FUNCTION POINTERS + Indirect call (call dword [edi]) to NV3_WaitWhileGraphicsEngineBusy HANG 22:14 16/02/2025 + _heap_init call + bEnableOffscreenHeap call + bEnablePointer call + bEnableText call + bEnablePalette call + bEnableDirectDraw call + EngCreateBitmap call + EngAssociateBitmap call + +DrvDisableSurface: ONLY IN THE CASE OF FAILURE diff --git a/doc/nvidia_notes/nv3_object_classes.txt b/doc/nvidia_notes/nv3_object_classes.txt new file mode 100644 index 000000000..05d1d9bf3 --- /dev/null +++ b/doc/nvidia_notes/nv3_object_classes.txt @@ -0,0 +1,37 @@ +Object classes as understood by the GPU. + +(May be represented, in RAMFC, as 0x40+ 22:16) + +0x00 = Invalid +0x01 = beta factor +0x02 = ROP5 operation +0x03 = Chroma key +0x04 = Plane mask +0x05 = Clipping rectangle +0x06 = Pattern +0x07 = Rectangle +0x08 = Point +0x09 = Line +0x0A = Lin (line without starting or ending pixel) +0x0B = Triangle +0x0C = Windows 95 GDI text acceleration +0x0D = Memory to memory format +0x0E = Scaled image from memory +0x0F = INVALID +0x10 = Blit +0x11 = Image +0x12 = Bitmap +0x13 = INVALID +0x14 = Transfer to Memory +0x15 = Stretched image from CPU +0x16 = INVALID +0x17 = Direct3D 5.0 accelerated textured triangle w/zeta buffer +0x18 = Point w/zeta buffer +0x19 = INVALID +0x1A = INVALID +0x1B = INVALID +0x1C = Image in memory +0x1D = INVALID +0x1E = INVALID +0x1F = INVALID + \ No newline at end of file diff --git a/doc/nvidia_notes/nv3d3d_t.txt b/doc/nvidia_notes/nv3d3d_t.txt new file mode 100644 index 000000000..c8579fd6c --- /dev/null +++ b/doc/nvidia_notes/nv3d3d_t.txt @@ -0,0 +1,161 @@ +12=unk_int12 +16=unk_short16 +22=unk_short22 (seems to determine if nv_sys_ptr is valid) +24=unk_short24 +26=unk_short26 +44=unk_int44 +56=unk_int56 +60=unk_int60 +64=unk_short64 +66=unk_short66 + +82=unk_short82 + +362..822: + big_struct + (weird alignment?) + 477 + 489 + 505 + +1140=nv_sys_ptr + + +1156=unk_int1156 [start of structure] +1160=unk_int1160 + +1168=unk_int1168 [possibly a byte array of up to 16 bytes) + +1184=unk_int1184 + +1208=unk_int1208 +1212=unk_int1212 +1216=unk_int1216 +1220=unk_int1220 +1224=unk_int1224 + +1236=unk_int1236 +1240=unk_int1240 +1244=unk_int1244 +1248=unk_int1248 + +1256=unk_int1256 +1260=fog_table_enable +1264=unk_int1264 +1270=unk_int1270 +1272=unk_byte1272 +1273=unk_byte1273 +1274=unk_byte1274 (?) +1275=unk_byte1275 + +1316=unk_int1316 +1320=unk_int1320 + +1332=unk_int1332 + +1340=unk_int1340 +1344=unk_int1344 + +1356=unk_int1356 +1360=d3d_clear_enabled +1364=texture_enabled +1368=mipmap_size_max +1372=mipmap_levels +1376=user_mipmaps +1380=zoh_mode (bool) +1384=tex_heap +1388=text_size +1392=video_texture +1396=min_video_tex_size +1400=draw_prim +1404=spread_x +1408=spread_y +1412=size_adj +1416=turbo_adj +1420=dma_min_push_count +1424=dma_push_enable + +1436=unk_int1436 +1440=unk_int1440 + +1448=unk_int1448 +1452=unk_int1452 (set to value of unk_int1908) +1456=unk_int1456 (set to value of unk_int1956) +1460=unk_int1460 (set to value of unk_int2020) + +1516=unk_int1516 +1520=unk_int1520 +1524=unk_int1524 +1528=unk_int1528 +1532=unk_int1532 + +1548=unk_int1548 +1552=unk_int1552 +1556=unk_int1556 +1560=unk_int1560 +1564=unk_int1564 + +1600=unk_int1600 + +1612=unk_int1612 +1616=unk_int1616 +1620=unk_int1620 + +1632=unk_int1632 + +1640=unk_int1640 +1644=unk_ptr1644 + +1676=unk_int1676 +1680=unk_int1680 +1684=unk_int1684 +1688=unk_int1688 +1692=unk_int1692 +1696=unk_int1696 +1700=unk_int1700 + +1716=unk_int1716 +1720=unk_int1720 +1724=unk_int1724 +1728=unk_ptr1728 + +1848=unk_int1848 +1852=unk_int1852 +1856=unk_int1856 (unk_int1552 | 0x800) +1864=unk_func_ptr1864 +1868=unk_int1868 + +1884=unk_int1884 +1888=ptr_to_start_of_structure? +1892=hInstDll +1896=unk_int1896 +1900=unk_int1900 + +1908=unk_int1908 +1912=unk_int1912 +1916=unk_func_ptr1916 +1920=unk_func_ptr1920 + +1932=unk_func_ptr1932 +1936=unk_func_ptr1936 +1944=unk_func_ptr1944 + +1956..2020: Set of function pointrs + 1956=unk_int1956 + 1960=unk_int1960 + 1960=unk_func_ptr1960 + 1964=unk_func_ptr1964 + 1968=unk_func_ptr1968 + 1976=unk_func_ptr1976 + 1980=unk_func_ptr1980 + 1988=unk_func_ptr1988 + 1996=unk_func_ptr1996 + 2000=unk_func_ptr2000 + 2004=unk_func_ptr2004 + 2008=unk_func_ptr2008 + + 2020=unk_int2020 + +2024=unk_int2024 +2028=unk_int2028 +2032=unk_int2032 diff --git a/doc/nvidia_notes/old nouveau wiki.txt b/doc/nvidia_notes/old nouveau wiki.txt new file mode 100644 index 000000000..c875954fd --- /dev/null +++ b/doc/nvidia_notes/old nouveau wiki.txt @@ -0,0 +1,9 @@ +old nouveau wiki: +real VRAM address = VRAM_size - (ramin_address - (ramin_address % reversal_unit_size)) - reversal_unit_size + (ramin_address % reversal_unit_size) + +nv3=16 bytes + +0x400000 - ((0x100000) - (0x100000 % 16)) - 16 + (0x100000 % 16) = 2ffff0 + + + \ No newline at end of file diff --git a/doc/nvidia_notes/rivatv_riva128.txt b/doc/nvidia_notes/rivatv_riva128.txt new file mode 100644 index 000000000..780ad5edd --- /dev/null +++ b/doc/nvidia_notes/rivatv_riva128.txt @@ -0,0 +1,2238 @@ + + +Riva 128 documentation +====================== + +This document is based on kernel sources, XFree86 sources, open sources +released by nVidia and pure deduction. To make nVidia happy: + + /***************************************************************************\ +|* *| +|* Copyright (c) 1996-1998 NVIDIA, Corp. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. NVIDIA, Corp. of Sunnyvale, California owns *| +|* the copyright and as design patents pending on the design and *| +|* interface of the NV chips. Users and possessors of this source *| +|* code are hereby granted a nonexclusive, royalty-free copyright *| +|* and design patent license to use this code in individual and *| +|* commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright (c) 1996-1998 NVIDIA, Corp. NVIDIA design patents *| +|* pending in the U.S. and foreign countries. *| +|* *| +|* NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF *| +|* THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT *| +|* EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS *| +|* ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL *| +|* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *| +|* PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE *| +|* FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, *| +|* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR *| +|* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER *| +|* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR *| +|* PERFORMANCE OF THIS SOURCE CODE. *| +|* *| + \***************************************************************************/ + +Feel free to send me corrections, updates, suggestions about this document to: +fero@drama.obuda.kando.hu or rivatv-devel@lists.sourceforge.net +Any kind of info, hint or idea may be helpful. +Please visit the rivatv homepage at: +http://fero.koli.kando.hu/rivatv/ + + + +Rendering +========= + +DMA vs PIO +---------- + +Theese two methods are used to program the hardware. DMA method provides +better performance but it is harder to implement. Almost all of the released +sources uses PIO method. The rest of this document describes the PIO method. + + +Objects +------- + +The Riva rendering engine is an object-oriented hardware. (See the nVidia +docs at https://www.nvidia.com/nv/nvarch.nsf/Home?OpenView -> Documents -> +NV Programmer's Reference Manual) Do not take it serious, it's simplified +for the hardware, it is not like C++. +Each object has a name. The name is 32 bits long and should be unique. + + +FIFO Channels +------------- + +There are 8 channels for submitting graphical objects to the rendering engine. +Each channel contains 8 subchannels. The rules how channels and subchannels +are working is not clear for me yet. Channel 0 is usable without extra coding. +Other channels can not be used until the 'context switching' code is done. +FIFO channels are located in the CTRL memory at 0x00800000-0x0087FFFF. Each +channel is 64 kbytes long, each subchannel is 8 kbytes long. Registers of +subchannels are variable: their function depends on the type of the submitted +object. Registers are write only and 32 bits long except the 'Free' register. + +Offset Name(s) Valid object types +------ ----------------------------- ------------------ +0000 Object all +0010 Free (2 bytes, read only!) all +0100 Synchronize t V s3 +0100 NoOperation BKPCLTRbISMr DG +0104 StopAlarm t +0104 Notify BKPCLTRbISMr DG +0104 StopImage V +0108 StopCursor V +010c StopDac V +0180 DmaNotifies tBKPCLTRbISMrVDGs3 +0184 ClipRectangle LTR +0184 ColorKey bIS +0184 DmaImage M V +0184 DmaTexture D +0184 Pattern G +0184 DmaSource s +0184 DmaSurfaces 3 +0188 Pattern LTR SM +0188 ClipRectangle bI D +0188 Rop G +0188 DmaDestin s +018c Rop LTR SM +018c Pattern bI +018c DmaLut V +018c Surfaces3D D +018c Beta1 G +0190 Beta1 LTR SM +0190 Rop bI +0190 Surfaces G +0194 Surfaces LTR SM +0194 Beta1 bI +0194 DmaCursor V +0198 Surfaces I +019c Surfaces b +02fc Operation LTRbIS G +02fc Get V +0300 Time0 t +0300 Beta1d31 B +0300 ColorFormat KP LTR ISM G +0300 Point C +0300 ControlPointIn b +0300 Rop r +0300 Image V +0300 Format s +0300 Pitch 3 +0304 Time1 t +0304 Color K LTR +0304 MonochromeFormat P G +0304 Size C +0304 ControlPointOut b +0304 Point I +0304 SizeIn S +0304 TextureOffset D +0304 Pitch s +0304 OffsetColor 3 +0300 Operation M +0308 AlarmNotify t +0308 MonochromeShape P +0308 Size b +0308 SizeOut I +0308 DxDu S +0308 ClipPoint M +0308 TextureFormat D +0308 OffsetSource s +0308 OffsetZeta 3 +030c SizeIn I +030c DyDv S +030c ClipSize M +030c TextureFilter D +030c OffsetDestin s +0310 MonochromeColor0 P +0310 TrianglePoint0 T +0310 ClipPoint S +0310 ImageOutPoint M +0310 FogColor D +0314 MonochromeColor1 P +0314 TrianglePoint1 T +0314 ClipSize S +0314 ImageOutSize M +0314 Control0 D +0318 MonochromePattern0 P +0318 TrianglePoint2 T +0318 Point12d4 S +0318 DxDu M +0318 Control1 D +031c MonochromePattern1 P +031c DyDv M +0320 Triangle32Point0X T +0324 Triangle32Point0Y T +0328 Triangle32Point1X T +032c Triangle32Point1Y T +0330 Triangle32Point2X T +0334 Triangle32Point2Y T +0340 Cursor V +0358 CursorPointOutA V +0380 Dac V +03a0 PixelClock V +03fc Color1A G +0400 Lin L +0400 Trimesh T +0400 Rectangle R +0400 Color IS +0400 ImageInSize M +0400 UnclippedRectangle G +0404 ImageInFormat M +0408 ImageInOffset M +040c ImageInPoint M +0480 Lin32 L +0480 Trimesh32 T +0500 PolyLin L +0500 ColorTriangle T +0580 PolyLin32 L +0580 ColorTrimesh T +0600 ColorPolyLin L +07f4 ClipPoint0B G +07f8 ClipPoint0B G +07fc Color1B G +0800 ClippedRectangle G +0bec ClipPoint0C G +0bf0 ClipPoint1C G +0bf4 Color1C G +0bf8 SizeC G +0bfc PointC G +0c00 MonochromeColor1C G +0fe8 ClipPoint0D G +0fec ClipPoint1D G +0ff0 Color1D G +0ff4 SizeInD G +0ff8 SizeOutD G +0ffc PointD G +1000 Tlvertex D +1000 MonochromeColor1D G +13e4 ClipPoint0E G +13e8 ClipPoint1E G +13ec Color0E G +13f0 Color1E G +13f4 SizeInE G +13f8 SizeOutE G +13fc PointE G +1400 MonochromeColor01E G + +t=timer +B=beta1 (0x41) +K=color key (0x43) +P=pattern (0x46) +C=clip rectangle (0x45) +L=solid line (0x4a) +T=solid triangle (0x4b) +R=solid rectangle (0x47) +b=image blit (0x50) +I=image from CPU (0x51) +S=stretched image from CPU (0x55) +M=scaled image from memory (0x4e) +r=raster operation (0x42) +V=video lut cursor dac +D=DX3 textured triangle (0x57) +G=GDI rectangle text (0x4c?) +s=Surfaces 2D +3=Surfaces 3D + +Contexts +-------- + +Context is a 32 bit record of channel id, object type and pointer to the +object. + +Bits 24-30: channel id +Bit 23: rendering + 0x0 other object (DMA?) + 0x1 renderable object +Bits 16-22: object type + 0x41 beta1 + 0x42 raster operation + 0x43 color key + 0x44 plane + 0x45 clipping rectangle + 0x46 pattern + 0x47 solid rectangle + 0x49 unknown line + 0x4A solid line + 0x4B solid triangle + 0x4C GDI rectangle + 0x4E scaled image from memory + 0x50 blit + 0x51 image from CPU + 0x52 bitmap + 0x55 streched image from CPU + 0x57 DX3 textured triangle + 0x?? Surfaces 2D + 0x?? Surfaces 3D + 0x?? Timer + 0x?? Video lut cursor dac + and many more... +Bits 0-15: offset in instance memory (RAMIN) / 16 + +Each graphic object has a context. Context determines the type (triangle, +raster operation, bitmap, etc) of the object. Don't ask me why this thingy +is called context: I really don't know. + + +Hash table +---------- + +The hash table (HT) is located in the instance memory area (RAMIN). +See RAMHT register in section FIFO registers. +The HT contains 8 byte length records of object names and contexts. Each +record is placed in the table by it's hash key. The key is computed as +follows: each byte of the object's name and the channel id are XOR-ed +together, and this value is multiplied by the hash depth. More explanation +on hash tables can be found in database books. +The purpose of HT is to provide connection between object names and contexts +for the graphic hardware. But it may be useful for your software driver too. + + +FIFO context table +------------------ + +The FIFO context table (FC) is located in the instance memory area (RAMIN). +See RAMFC register in section FIFO registers. +FC contains the context values for each subchannel. E.g. if FC begins +at 0x1C00: +0x1C00 Context of object in channel 0, subchannel 0 +0x1C04 Context of object in channel 0, subchannel 1 +0x1C08 Context of object in channel 0, subchannel 2 +... +0x1C1C Context of object in channel 0, subchannel 7 +0x1C20 Context of object in channel 1, subchannel 0 +0x1C24 Context of object in channel 1, subchannel 1 +... +0x1CFC Context of object in channel 7, subchannel 7 + + +Example: How to render a solid rectangle? +----------------------------------------- + +- Choose a name for your rectangle. E.g.: 0x01020304 +- Select an unused area in the instance memory. Let it be 0x00c04000 +- Calculate the context: + Channel = 0x00 + Render object = 1 + Object type = 0x47 (rectangle) + Offset in intance memory = 0x4000 / 16 = 0x0400 + Context = 0x00c70400 +- Place the name - context pair in the hash table (HT begins at 0x00c00000): + Hash key = 01 xor 02 xor 03 xor 04 xor 00 = 0x04 + (each byte of the name) (channel id) + *(0x00c00000 + 0x04 * 16) = 0x00000001; // name + *(0x00c00000 + 0x04 * 16) + 4 = 0x00c70400; // context +- Fill in the instace ram: + *(0x00c04000) = 0x00100000; // 15bpp (TODO: decode this magic) + *(0x00c04004) = 0x00000000; // not used yet + *(0x00c04008) = 0x00000000; // not used yet + *(0x00c0400c) = 0x00000000; // not used yet +- At this point the FIFO channel is ready for submitting rectangles. +- Submit the first rectangle: + write the object's name to channel 0 (subchannel 0): + *(0x00800000) = 0x00000001; +- At this point subchannel 0 becomes a rectangle. +- Submit the attributes of the rectangle: + write x,y coordinates: + (0x00800400) = 0x01000200; // x=0x100 y=0x200 + size: + (0x00800404) = 0x00100020; // width=0x10 height=0x20 +- After size is submitted, our rectangle appears on the screen. +- Subsequent rectangles may be submitted by re-sending new attributes. + + +Speculation: How to make video in working? +------------------------------------------ + +V4L stuff and hardware rendered rectangles have some similarities: +- both have color keys +- both have clipping rectangles +- both are stretchable +I suppose video in feature is implemented by rendered objects. A chroma-keyed +and clipped rectangle with 'live texture' is blitted on the screen. +Thats all. :) + + + +Memory layout +============= + +Three memory regions are accessible via the PCI (or AGP) interface: +- CTRL region (PCI base 0) +- FB region (PCI base 1) +- BIOS ROM (PCI base 2) + + +CTRL region +----------- + +The CTRL region contains memory mapped IO ports. Most of them are 32-bit +registers. The registers are grouped by functionality: + +- MC: master control (0x00000000-0x00000FFF) +- BUS: (0x00001000-0x00001FFF) +- FIFO: for DMA and PIO stuff (0x00002000-0x00003FFF) +- TIMER: built-in timer (0x00009000-0x00009FFF) +- VIO: 8 bit SVGA (MISC, GRAPH, SEQ) registers (0x000C0000-0x00C00FFF) +- FB: framebuffer properties (0x00100000-0x00100FFF) +- EXTDEV: external devices (0x00101000-0x00101FFF) +- GRAPH: (0x00400000-0x00401FFF) +- PCIO: 8 bit SVGA (CRTC, ATTR) registers (0x00601000-0x00601FFF) +- RAMDAC: RAMDAC timings (0x00680000-0x00680FFF) +- PDIO: 8 bit registers (0x00681000-0x00681FFF) +- FIFO channels: (0x00800000-0x0087FFFF) +(List in not complete.) + + +FB region +--------- + +This region contains the video memory and the instance memory. +Video memory begins at offset 0x00000000. Instance memory (RAMIN) +begins at offset 0x00C00000. (Note: Riva TNT (and higher) cards have +their instance memory in the CTRL region.) + + + +Master control +============== + +The MC registers begin at 0x00000000 in the CTRL region. They control the +master IRQ. + +Interrupt 0 register +-------------------- +Name: INTR_0 +Offset: 0x00000100 +4 bytes, read-write + +Bit 0: PAUDIO (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 4: PMEDIA (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 8: PFIFO (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 12: PGRAPH0 (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 13: PGRAPH1 (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 16: PVIDEO (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 20: PTIMER (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 24: PFB (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 28: PBUS (-V, read-only) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + +Bit 31: SOFTWARE (IV, read-write) + NOT_PENDING 0x0 (default, read-write) + PENDING 0x1 (read-write) + +Interrupt 0 enable register +--------------------------- +Name: INTR_EN_0 +Offset: 0x00000140 +4 bytes, read-write + +Bits 0-1: INTA (IV, read-write) + DISABLED 0x0 (default, read-write) + HARDWARE 0x1 (read-write) + SOFTWARE 0x2 (read-write) + +Enable (what?) register +----------------------- +Name: ENABLE +Offset: 0x00000200 +4 bytes, read-write + + + +Bus +=== + +The BUS registers begin at 0x00001000 in the CTRL region. They are +undiscovered. + +Debug 0 register +---------------- +Name: DEBUG_0 +Offset: 0x00001080 +4 bytes, read-write + +Bit 0: MODE (IV, read-write) + MODE_DISABLED 0x0 (default, read-write) + MODE_ENABLED 0x1 (read-write) + +Bit 4: DESKEWER (IV, read-write) + ENABLED 0x0 (default, read-write) + +Bits 8-11: FBIO_SCLK_DELAY (IV, read-write) + 0x0 (default, read-write) + +Bits 12-15: FBIO_FBCLK_DELAY (IV, read-write) + 0x3 (default, read-write) + +Debug 1 register +---------------- +Name: DEBUG_1 +Offset: 0x00001084 +4 bytes, read-write + +Bit 0: PCIM_THROTTLE (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 1: PCIM_CMD (IV, read-write) + SIZE_BASED 0x0 (default, read-write) + MRL_ONLY 0x1 (read-write) + +Bit 2: PCIM_AGP (IV, read-write) + IS_AGP 0x0 (default, read-write) + IS_PCI 0x1 (read-write) + +Bits 3-4: AGPM_CMD (IV, read-write) + HP_ON_1ST 0x0 (read-write) + LP_ONLY 0x1 (default, read-write) + HP_ONLY 0x2 (read-write) + +Bit 5: PCIS_WRITE (IV, read-write) + 0_CYCLE 0x0 (read-write) + 1_CYCLE 0x1 (default, read-write) + +Bit 6: PCIS_2_1 (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 7: PCIS_RETRY (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 8: PCIS_RD_BURST (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 9: PCIS_WR_BURST (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 10: PCIS_EARLY_RTY (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 11: PCIS_RMAIO (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 12: PCIS_CPUQ (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +Bit 13: DPSH_PIPE (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 14: SPARE1 (IV, read-write) + ZERO 0x0 (default, read-write) + ONE 0x1 (read-write) + +Bit 15: SPARE2 (IV, read-write) + ZERO 0x0 (default, read-write) + ONE 0x1 (read-write) + +Bit 16: SPARE3 (IV, read-write) + ZERO 0x0 (default, read-write) + ONE 0x1 (read-write) + + + +FIFO +==== + +The BUS registers begin at 0x00002000 in the CTRL region. + +Interrupt 0 register +-------------------- + +Name: INTR_0 +Offset: 0x00002100 +4 bytes, read-write + +Bit 0: CACHE_ERROR (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 4: RUNOUT (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 8: RUNOUT_OVERFLOW (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 12: DMA_PUSHER (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 16: DMA_PTE (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Interrupt 0 enable register +--------------------------- + +Name: INTR_EN_0 +Offset: 0x00002140 +4 bytes, read-write + +Bit 0: CACHE_ERROR (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 4: RUNOUT (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 8: RUNOUT_OVERFLOW (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Config 0 register +----------------- + +Name: CONFIG_0 +Offset: 0x00002200 +4 bytes, read-write + +Hash table register +------------------- + +Hardware hash table offset (in instance memory) and size. + +Name: RAMHT +Offset: 0x00002210 +4 bytes, read-write + +Bits 12-15: BASE_ADDRESS (XV, read-write) + +Bits 16-17: SIZE (XV, read-write) + 4K 0x0 (default, read-write) + 8K 0x1 (read-write) + 16K 0x2 (read-write) + 32K 0x3 (read-write) + +FIFO context table offset +------------------------- + +Name: RAMFC +Offset: 0x00002214 +4 bytes, read-write + +Bits 9-15: BASE_ADDRESS (XV, read-write) + +Runout table register +--------------------- + +FIFO runout table offset and size. + +Name: RAMRO +Offset: 0x00002218 +4 bytes, read-write + +Bits 9-15: BASE_ADDRESS (XV, read-write) + +Bit 16: SIZE (XV, read-write) + 512 0x0 (default, read-write) + 8K 0x1 (read-write) + +Runout status register +---------------------- + +Name: RUNOUT_STATUS +Offset: 0x00002400 +4 bytes, read-only + +Runout put register +------------------- + +Index in runout table. + +Name: RUNOUT_PUT +Offset: 0x00002410 +4 bytes, read-write + +Runout get register +------------------- + +Index in runout table. + +Name: RUNOUT_GET +Offset: 0x00002420 +4 bytes, read-write + +Caches register +--------------- + +Name: CACHES +Offset: 0x00002500 +4 bytes, read-write + +Bit 0: REASSIGN (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Cache 0 push 0 register +----------------------- + +Name: CACHE0_PUSH0 +Offset: 0x00003000 +4 bytes, read-write + +Bit 0: ACCESS (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Cache 0 push 1 register +----------------------- + +Name: CACHE0_PUSH1 +Offset: 0x00003004 +4 bytes, read-write + +Bits 0-6: CHID (XU, read-write) + +Cache 0 pull 0 register +----------------------- + +Name: CACHE0_PULL0 +Offset: 0x00003040 +4 bytes, read-write + +Bit 0: ACCESS (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Cache 1 push 0 register +----------------------- + +Name: CACHE1_PUSH0 +Offset: 0x00003200 +4 bytes, read-write + +Bit 0: ACCESS (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Cache 1 push 1 register +----------------------- + +Name: CACHE1_PUSH1 +Offset: 0x00003204 +4 bytes, read-write + +Bits 0-6: CHID (XU, read-write) + +Cache 1 put register +-------------------- + +Name: CACHE1_PUT +Offset: 0x00003210 +4 bytes, read-write + +Bits 2-6: ADDRESS (XU, read-write) + +Cache 1 DMA 0 register +----------------------- + +Name: CACHE1_DMA0 +Offset: 0x00003220 +4 bytes, read-write + +Cache 1 DMA 1 register +----------------------- + +Name: CACHE1_DMA1 +Offset: 0x00003224 +4 bytes, read-write + +Cache 1 DMA 2 register +----------------------- + +Name: CACHE1_DMA2 +Offset: 0x00003228 +4 bytes, read-write + +Cache 1 pull 0 register +----------------------- + +Name: CACHE1_PULL0 +Offset: 0x00003240 +4 bytes, read-write + +Bit 0: ACCESS (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Cache 1 pull 1 register +----------------------- + +Name: CACHE1_PULL1 +Offset: 0x00003250 +4 bytes, read-write + +Bit 4: CTX (XV, read-write) + CLEAN 0x0 (read-write) + DIRTY 0x1 (read-write) + +Cache 1 get register +-------------------- + +Name: CACHE1_GET +Offset: 0x00003270 +4 bytes, read-write + +Bits 2-6: ADDRESS (XU, read-write) + +Cache 1 context registers +------------------------- + +8 context registers for each channel (I guess). + +Name: CACHE1_CTX +Offset: 0x00003280+i*16 (0 <= i < 8) +8*16(4?) bytes, read-write + + + +Framebuffer properties +====================== + +The FB registers begin at 0x00100000 in the CTRL region. + +Boot 0 register +--------------- + +Name: BOOT_0 +Offset: 0x00100000 +4 bytes, read-write + +Bits 0-1: RAM_AMOUNT (IV, read-write) + 1MB 0x0 (read-write) + 2MB 0x1 (read-write) + 4MB 0x2 (read-write) + 8MB 0x0 (read-write) + UNDEFINED 0x3 (read-write) + DEFAULT 0x2 (default, read-write) + +Bit 2: RAM_WIDTH_128 (-V, read-write) + OFF 0x0 (read-write) + ON 0x1 (read-write) + +Bit 3: RAM_BANKS (IV, read-write) + 2BANK 0x0 (default, read-write) + 4BANK 0x1 (read-write) + +Bit 4: RAMDATA_TWIDDLE (IV, read-write) + OFF 0x0 (default, read-write) + ON 0x1 (read-write) + +Bit 5: RAM_AMOUNT_EXTENSION (IV, read-write) + OFF 0x0 (default, read-write) + 8MB 0x1 (read-write) + +Delay 1 register +---------------- + +Name: DELAY_1 +Offset: 0x00100044 +4 bytes, read-write + +Bits 0-1: WRITE_ENABLE_RISE (IU, read-write) + WRITE_ENABLE_RISE_0 0x0 (default, read-write) + +Bits 4-5: WRITE_ENABLE_FALL (IU, read-write) + WRITE_ENABLE_FALL_0 0x0 (default, read-write) + +Bits 8-9: CAS_ENABLE_RISE (IU, read-write) + CAS_ENABLE_RISE_0 0x0 (default, read-write) + +Bits 12-13: CAS_ENABLE_FALL (IU, read-write) + CAS_ENABLE_FALL_0 0x0 (default, read-write) + +Bits 16-17: OUTPUT_DATA (IU, read-write) + OUTPUT_DATA_0 0x0 (default, read-write) + +Bits 20-21: RAS_ENABLE (IU, read-write) + RAS_ENABLE_0 0x0 (default, read-write) + +Debug 0 register +---------------- + +Name: DEBUG_0 +Offset: 0x00100080 +4 bytes, read-write + +Bit 4: REFRESH (IV, read-write) + ENABLED 0x0 (default, read-write) + DISABLED 0x1 (read-write) + +Green 0 register +---------------- + +Name: GREEN_0 +Offset: 0x001000C0 +4 bytes, read-write + +Bits 0-1: LEVEL (IV, read-write) + VIDEO_ENABLED 0x0 (read-write) + VIDEO_DISABLED 0x1 (read-write) + TIMING_DISABLED 0x2 (read-write) + MEMORY_DISABLED 0x3 (default, read-write) + +Config 0 register +----------------- + +Name: CONFIG_0 +Offset: 0x00100200 +4 bytes, read-write + +Bits 0-5: RESOLUTION (IV, read-write) + 320_PIXELS 0x0a (read-write) + 400_PIXELS 0x0d (read-write) + 480_PIXELS 0x0f (read-write) + 512_PIXELS 0x10 (read-write) + 640_PIXELS 0x14 (read-write) + 800_PIXELS 0x19 (read-write) + 960_PIXELS 0x1e (read-write) + 1024_PIXELS 0x20 (read-write) + 1152_PIXELS 0x24 (read-write) + 1280_PIXELS 0x28 (read-write) + 1600_PIXELS 0x32 (read-write) + DEFAULT 0x14 (default, read-write) + +Bits 8-9: PIXEL_DEPTH (IV, read-write) + 8_BITS 0x1 (read-write) + 16_BITS 0x2 (read-write) + 32_BITS 0x3 (read-write) + DEFAULT 0x1 (default, read-write) + +Bit 12: TILING (IV, read-write) + ENABLED 0x0 (read-write) + DISABLED 0x1 (default, read-write) + + +Bits 13-23: TILING_DEBUG (IV, read-write) + DISABLED 0x0 (read-write) + +RTL(?) register +--------------- + +Name: RTL +Offset: 0x00100??? +4 bytes, read-write + +Bits 0-1: S (IU, read-write) + DEFAULT 0x2 (default, read-write) + +Bits 4-5: V (IU, read-write) + DEFAULT 0x2 (default, read-write) + +Bits 8-9: M (IU, read-write) + DEFAULT 0x2 (default, read-write) + +Bits 12-13: H (IU, read-write) + DEFAULT 0x1 (default, read-write) + +Bits 16-17: A (IU, read-write) + DEFAULT 0x1 (default, read-write) + +Bits 20-21: G (IU, read-write) + DEFAULT 0x1 (default, read-write) + +Bit 24: ARB_GR_HI_PRIOR (IU, read-write) + DEFAULT 0x0 (default, read-write) + +Bit 28: ARB_MEDIA_HI_PRIOR (IU, read-write) + DEFAULT 0x0 (default, read-write) + + + +External devices +================ + +The EXTDEV registers begin at 0x00101000 in the CTRL region. + +Boot 0 register +--------------- + +Name: BOOT_0 +Offset: 0x00101000 +4 bytes, read-write + +Bit 2: STRAP_RAM_TYPE (XV, read-write) + SGRAM_8MBIT 0x1 (read-write) + SGRAM_16MBIT 0x0 (read-write) + +Bit 11: STRAP_OVERWRITE (IV, read-write) + ENABLED 0x1 (read-write) + +Bit 4: STRAP_RAM_WIDTH (XV, read-write) + 64 0x0 (read-write) + 128 0x1 (read-write) + + + +GRAPH +===== + +The GRAPH registers begin at 0x00400000 in the CTRL region. + +Debug 0 register +---------------- + +Name: DEBUG_0 +Offset: 0x00400080 +4 bytes, read-write + +Bit 0: STATE (-V, clear(check?)-write) + NORMAL 0x0 (clear(check?)-write) + RESET 0x1 (write-only) + +Bit 4: BULK_READS (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 20: WRITE_ONLY_ROPS_2D (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 24: DRAWDIR_AUTO (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Debug 1 register +---------------- + +Name: DEBUG_1 +Offset: 0x00400084 +4 bytes, read-write + +Bit 0: VOLATILE_RESET (IV, read-write) + NOT_LAST 0x0 (default, read-write) + LAST 0x1 (read-write) + +Bit 16: INSTANCE (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 20: CTX (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Debug 2 register +---------------- + +Name: DEBUG_2 +Offset: 0x00400088 +4 bytes, read-write + +Bit 0: AVOID_RMW_BLEND (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 8: DPWR_FIFO (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Bit 28: VOLATILE_RESET (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Debug 3 register +---------------- + +Name: DEBUG_3 +Offset: 0x0040008C +4 bytes, read-write + +Bit 24: HONOR_ALPHA (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Interrupt 0 register +-------------------- + +Name: INTR_0 +Offset: 0x00400100 +4 bytes, read-write + +Bit 0: RESERVED (-V, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 4: CONTEXT_SWITCH (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 8: VBLANK (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 12: RANGE (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 16: METHOD_COUNT (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 20: FORMAT (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 24: COMPLEX_CLIP (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 28: NOTIFY (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Interrupt 1 register +-------------------- + +Name: INTR_1 +Offset: 0x00400104 +4 bytes, read-write + +Bit 0: METHOD (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 4: DATA (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 12: DOUBLE_NOTIFY (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 16: CTXSW_NOTIFY (IV, read-write) + NOT_PENDING 0x0 (default, read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Interrupt 0 enable register +--------------------------- + +Name: INTR_EN_0 +Offset: 0x00400140 +4 bytes, read-write + +Interrupt 1 enable register +--------------------------- + +Name: INTR_EN_1 +Offset: 0x00400144 +4 bytes, read-write + +Context switch register +----------------------- + +Name: CTX_SWITCH +Offset: 0x00400180 +4 bytes, read-write + +Context control register +------------------------ + +Name: CTX_CONTROL +Offset: 0x00400190 +4 bytes, read-write + +Bits 0-1: MINIMUM_TIME (IV, read-write) + 33US 0x0 (default, read-write) + 262US 0x1 (read-write) + 2MS 0x2 (read-write) + 17MS 0x3 (read-write) + +Bit 8: TIME (IV, read-write) + EXPIRED 0x0 (default, read-write) + NOT_EXPIRED 0x1 (read-write) + +Bit 16: CHID (IV, read-write) + INVALID 0x0 (default, read-write) + VALID 0x1 (read-write) + +Bit 20: SWITCH (-V, read-only) + UNAVAILABLE 0x0 (read-only) + AVAILABLE 0x1 (read-only) + +Bit 24: SWITCHING (IV, read-write) + IDLE 0x0 (default, read-write) + BUSY 0x1 (read-write) + +Bit 28: DEVICE (IV, read-write) + DISABLED 0x0 (default, read-write) + ENABLED 0x1 (read-write) + +Context user register +--------------------- + +Name: CTX_USER +Offset: 0x00400194 +4 bytes, read-write + +Context cache registers +----------------------- + +8 context registers for each channel (I guess). + +Name: CTX_CACHE +Offset: 0x004001a0+i*4 (0 <= i Í8) +8*4 bytes, read-write + +Absolute X RAM registers +------------------------ + +Name: ABS_X_RAM +Offset: 0x00400400+i*4 (0 <= i < 32) +32*4 bytes, read-write + +Absolute Y RAM registers +------------------------ + +Name: ABS_Y_RAM +Offset: 0x00400480+i*4 (0 <= i < 32) +32*4 bytes, read-write + +X misc register +--------------- + +Name: X_MISC +Offset: 0x00400500 +4 bytes, read-write + +Y misc register +--------------- + +Name: Y_MISC +Offset: 0x00400504 +4 bytes, read-write + +Exceptions register +------------------- + +Name: EXCEPTIONS +Offset: 0x00400508 +4 bytes, read-write + +Source color register +--------------------- + +Name: SOURCE_COLOR +Offset: 0x0040050C +4 bytes, read-write + +XY logic misc 0 register +------------------------ + +Name: XY_LOGIC_MISC0 +Offset: 0x00400514 +4 bytes, read-write + +XY logic misc 1 register +------------------------ + +Name: XY_LOGIC_MISC1 +Offset: 0x00400518 +4 bytes, read-write + + DVDY_VALUE 0x0 (default, read-write) (???) + +XY logic misc 2 register +------------------------ + +Name: XY_LOGIC_MISC2 +Offset: 0x0040051C +4 bytes, read-write + +XY logic misc 3 register +------------------------ + +Name: XY_LOGIC_MISC3 +Offset: 0x00400520 +4 bytes, read-write + +Clip X 0 register +----------------- + +Name: CLIPX_0 +Offset: 0x00400524 +4 bytes, read-write + +Clip X 1 register +----------------- + +Name: CLIPX_1 +Offset: 0x00400528 +4 bytes, read-write + +Clip Y 0 register +----------------- + +Name: CLIPY_0 +Offset: 0x0040052c +4 bytes, read-write + +Clip Y 1 register +----------------- + +Name: CLIPY_1 +Offset: 0x00400530 +4 bytes, read-write + +Absolute iclip X max. register +------------------------------ + +Name: ABS_ICLIP_XMAX +Offset: 0x00400534 +4 bytes, read-write + +Absolute iclip Y max. register +------------------------------ + +Name: ABS_ICLIP_YMAX +Offset: 0x00400538 +4 bytes, read-write + +Absolute uclip X min. register +------------------------------ + +Name: ABS_UCLIP_XMIN +Offset: 0x0040053C +4 bytes, read-write + +Absolute uclip Y min. register +------------------------------ + +Name: ABS_UCLIP_YMIN +Offset: 0x00400540 +4 bytes, read-write + +Absolute uclip X max. register +------------------------------ + +Name: ABS_UCLIP_XMAX +Offset: 0x00400544 +4 bytes, read-write + +Absolute uclip Y max. register +------------------------------ + +Name: ABS_UCLIP_YMAX +Offset: 0x00400548 +4 bytes, read-write + +Absolute uclipa X min. register +------------------------------ + +Name: ABS_UCLIPA_XMIN +Offset: 0x00400560 +4 bytes, read-write + +Absolute uclipa Y min. register +------------------------------ + +Name: ABS_UCLIPA_YMIN +Offset: 0x00400564 +4 bytes, read-write + +Absolute uclipa X max. register +------------------------------ + +Name: ABS_UCLIPA_XMAX +Offset: 0x00400568 +4 bytes, read-write + +Absolute uclipa Y max. register +------------------------------ + +Name: ABS_UCLIPA_YMAX +Offset: 0x0040056C +4 bytes, read-write + +Source canvas min. register +--------------------------- + +Name: SRC_CANVAS_MIN +Offset: 0x00400550 +4 bytes, read-write + +Source canvas max. register +--------------------------- + +Name: SRC_CANVAS_MAX +Offset: 0x00400554 +4 bytes, read-write + +Destination canvas min. register +-------------------------------- + +Name: DST_CANVAS_MIN +Offset: 0x00400558 +4 bytes, read-write + +Destination canvas max. register +-------------------------------- + +Name: DST_CANVAS_MAX +Offset: 0x0040055C +4 bytes, read-write + +Pattern color 0 0 register +-------------------------- + +Name: PATT_COLOR0_0 +Offset: 0x00400600 +4 bytes, read-write + +Pattern color 0 1 register +-------------------------- + +Name: PATT_COLOR0_1 +Offset: 0x00400604 +4 bytes, read-write + +Pattern color 1 0 register +-------------------------- + +Name: PATT_COLOR1_0 +Offset: 0x00400608 +4 bytes, read-write + +Pattern color 1 1 register +-------------------------- + +Name: PATT_COLOR1_1 +Offset: 0x0040060C +4 bytes, read-write + +Pattern registers +----------------- + +Name: PATTERN +Offset: 0x00400610+i*4 (0 <=i < 2) +2*4 bytes, read-write + +Pattern shape register +---------------------- + +Name: PATTERN_SHAPE +Offset: 0x00400618 +4 bytes, read-write + +Bits 0-1: VALUE (XV, read-write) + 8X8 0x0 (read-write) + 64X1 0x1 (read-write) + 1X64 0x2 (read-write) + +Monochrome color 0 register +--------------------------- + +Name: MONO_COLOR0 +Offset: 0x0040061C +4 bytes, read-write + +Raster operation register +------------------------- + +Name: ROP3 +Offset: 0x00400624 +4 bytes, read-write + +Plane mask register +------------------- + +Name: PLANE_MASK +Offset: 0x00400628 +4 bytes, read-write + +Chroma register +--------------- + +Name: CHROMA +Offset: 0x0040062C +4 bytes, read-write + +B(?) offset 0 register +---------------------- + +Name: BOFFSET0 +Offset: 0x00400630 +4 bytes, read-write + +B(?) offset 1 register +---------------------- + +Name: BOFFSET1 +Offset: 0x00400634 +4 bytes, read-write + +B(?) offset 2 register +---------------------- + +Name: BOFFSET2 +Offset: 0x00400638 +4 bytes, read-write + +B(?) offset 3 register +---------------------- + +Name: BOFFSET3 +Offset: 0x0040063C +4 bytes, read-write + +Beta register +------------- + +Name: BETA +Offset: 0x00400640 +4 bytes, read-write + +Control out register +-------------------- + +Name: CONTROL_OUT +Offset: 0x00400644 +4 bytes, read-write + +B(?) pitch 0 register +--------------------- + +Name: BPITCH0 +Offset: 0x00400650 +4 bytes, read-write + +B(?) pitch 1 register +--------------------- + +Name: BPITCH1 +Offset: 0x00400654 +4 bytes, read-write + +B(?) pitch 2 register +--------------------- + +Name: BPITCH2 +Offset: 0x00400658 +4 bytes, read-write + +B(?) pitch 3 register +--------------------- + +Name: BPITCH3 +Offset: 0x0040065C +4 bytes, read-write + +DMA register +------------ + +Name: DMA +Offset: 0x00400680 +4 bytes, read-write + +Notify register +--------------- + +Name: NOTIFY +Offset: 0x00400684 +4 bytes, read-write + +Bits 0-15: INST_MEM_LOC ??? + +Instance register +----------------- + +Name: INSTANCE +Offset: 0x00400688 +4 bytes, read-write + +Memory format register +---------------------- + +Name: MEMFMT +Offset: 0x0040068C +4 bytes, read-write + +Clip 0 min. register +-------------------- + +Name: CLIP0_MIN +Offset: 0x00400690 +4 bytes, read-write + +Clip 0 max. register +-------------------- + +Name: CLIP0_MAX +Offset: 0x00400694 +4 bytes, read-write + +Clip 1 min. register +-------------------- + +Name: CLIP1_MIN +Offset: 0x00400698 +4 bytes, read-write + +Clip 1 max. register +-------------------- + +Name: CLIP1_MAX +Offset: 0x0040069C +4 bytes, read-write + +Clip misc register +------------------ + +Name: CLIP_MISC +Offset: 0x004006A0 +4 bytes, read-write + +FIFO register +------------- + +Name: FIFO +Offset: 0x004006A4 +4 bytes, read-write + +Bit 0: ACCESS (IV, read-write) + DISABLED 0x0 (read-write) + ENABLED 0x1 (default, read-write) + +B(?) pixel register +------------------- + +Name: BPIXEL +Offset: 0x004006A8 +4 bytes, read-write + +Bits 0-1: DEPTH0_FMT (XV, read-write) + Y16_BITS 0x0 (read-write) + BITS_8 0x1 (read-write) + BITS_16 0x2 (read-write) + BITS_32 0x3 (read-write) + +Bit 2: DEPTH0 (XV, read-write) + NOT_VALID 0x0 (read-write) + VALID 0x1 (read-write) + +Bits 4-5: DEPTH1_FMT (XV, read-write) + Y16_BITS 0x0 (read-write) + BITS_8 0x1 (read-write) + BITS_16 0x2 (read-write) + BITS_32 0x3 (read-write) + +Bit 6: DEPTH1 (XV, read-write) + NOT_VALID 0x0 (read-write) + VALID 0x1 (read-write) + +Bits 8-9: DEPTH2_FMT (XV, read-write) + Y16_BITS 0x0 (read-write) + BITS_8 0x1 (read-write) + BITS_16 0x2 (read-write) + BITS_32 0x3 (read-write) + +Bit 10: DEPTH2 (XV, read-write) + NOT_VALID 0x0 (read-write) + VALID 0x1 (read-write) + +Bits 12-13: DEPTH3_FMT (XV, read-write) + Y16_BITS 0x0 (read-write) + BITS_8 0x1 (read-write) + BITS_16 0x2 (read-write) + BITS_32 0x3 (read-write) + +Bit 14: DEPTH3 (XV, read-write) + NOT_VALID 0x0 (read-write) + VALID 0x1 (read-write) + +Status register +--------------- + +Name: STATUS +Offset: 0x004006B0 +4 bytes, read-only + +DMA interrupt 0 register +------------------------ + +Name: DMA_INTR_0 +Offset: 0x00401100 +4 bytes, read-write + +Bit 0: INSTANCE (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 4: PRESENT (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 8: PROTECTION (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 12: LINEAR (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +Bit 16: NOTIFY (XV, read-write) + NOT_PENDING 0x0 (read-only) + PENDING 0x1 (read-only) + RESET 0x1 (write-only) + +DMA interrupt 0 enable register +------------------------------- + +Name: DMA_INTR_EN_0 +Offset: 0x00401140 +4 bytes, read-write + +DMA control register +-------------------- + +Name: DMA_CONTROL +Offset: 0x00401210 +4 bytes, read-write + + + +RAMDAC +====== + +The RAMDAC registers begin at 0x00680000 in the CTRL region. + +Graphic cursor starting position register +----------------------------------------- + +Name: GRCURSOR_START_POS +Offset: 0x00680300 +4 bytes, read-write + +Bits 0-11: X (XS, read-write) + +Bits 16-27: Y (XS, read-write) + +MPLL coeff register +------------------- + +Name: MPLL_COEFF +Offset: 0x00680504 +4 bytes, read-write + +Bits 0-7: MDIV (IU, read-write) + +Bits 8-15: NDIV (IU, read-write) + +Bits 16-18: PDIV (IV, read-write) + +VPLL coeff register +------------------- + +Name: VPLL_COEFF +Offset: 0x00680508 +4 bytes, read-write + +Bits 0-7: MDIV (IU, read-write) + +Bits 8-15: NDIV (IU, read-write) + +Bits 16-18: PDIV (IV, read-write) + +PLL coeff select register +------------------------- + +Name: PLL_COEFF_SELECT +Offset: 0x0068050C +4 bytes, read-write + +Bit 4: DLL_BYPASS (IV, read-write) + FALSE 0x0 (default, read-write) + TRUE 0x1 (read-write) + +Bit 8: MPLL_SOURCE (IV, read-write) + DEFAULT 0x0 (default, read-write) + PROG 0x1 (read-write) + +Bit 12: MPLL_BYPASS (IV, read-write) + FALSE 0x0 (default, read-write) + TRUE 0x1 (read-write) + +Bit 16: VPLL_SOURCE (IV, read-write) + DEFAULT 0x0 (default, read-write) + PROG 0x1 (read-write) + +Bit 20: VPLL_BYPASS (IV, read-write) + FALSE 0x0 (default, read-write) + TRUE 0x1 (read-write) + +Bits 24-25: PCLK_SOURCE (IV, read-write) + VPLL 0x0 (default, read-write) + VIP 0x1 (read-write) + XTALOSC 0x2 (read-write) + +Bit 28: VCLK_RATIO (IV, read-write) + DB1 0x0 (default, read-write) + DB2 0x1 (read-write) + +General control register +------------------------ + +Various flags for DAC. BPC controls the width of the palette. + +Name: GENERAL_CONTROL +Offset: 0x00680600 +4 bytes, read-write + +Bits 0-1: FF_COEFF (IV, read-write) + DEF 0x0 (default, read-write) + +Bit 4: IDC_MODE (IV, read-write) + GAMMA 0x0 (default, read-write) + INDEX 0x1 (read-write) + +Bit 8: VGA_STATE (IV, read-write) + NOTSEL 0x0 (default, read-write) + SEL 0x1 (read-write) + +Bit 12: 565_MODE (IV, read-write) + NOTSEL 0x0 (default, read-write) + SEL 0x1 (read-write) + +Bit 16: BLK_PEDSTL (IV, read-write) + OFF 0x0 (default, read-write) + ON 0x1 (read-write) + +Bit 17: TERMINATION (IV, read-write) + 37OHM 0x0 (default, read-write) + 75OHM 0x1 (read-write) + +Bit 20: BPC (IV, read-write) + 6BITS 0x0 (default, read-write) + 8BITS 0x1 (read-write) + +Bit 24: DAC_SLEEP (IV, read-write) + DIS 0x0 (default, read-write) + EN 0x1 (read-write) + +Bit 28: PALETTE_CLK (IV, read-write) + EN 0x0 (default, read-write) + DIS 0x1 (read-write) + +VSERR width register +-------------------- + +Name: VSERR_WIDTH +Offset: 0x00680700 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +VEQU end register +----------------- + +Name: VEQU_END +Offset: 0x00680704 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Vertical B(?) blank end register +-------------------------------- + +Name: VBBLANK_END +Offset: 0x00680708 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Vertical blank end register +--------------------------- + +Name: VBLANK_END +Offset: 0x0068070C +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Vertical blank start register +----------------------------- + +Name: VBLANK_START +Offset: 0x00680710 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Vertical (B?) blank start register +---------------------------------- + +Name: VBBLANK_START +Offset: 0x00680714 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +VEQU start register +------------------- + +Name: VEQU_START +Offset: 0x00680718 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Vertical total register +----------------------- + +Name: VTOTAL +Offset: 0x0068071C +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal sync width register +------------------------------ + +Name: HSYNC_WIDTH +Offset: 0x00680720 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal burst start register +------------------------------- + +Name: HBURST_START +Offset: 0x00680724 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal burst end register +----------------------------- + +Name: HBURST_END +Offset: 0x00680728 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal blank start register +------------------------------- + +Name: HBLANK_START +Offset: 0x0068072C +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal blank end register +----------------------------- + +Name: HBLANK_END +Offset: 0x00680730 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +Horizontal total register +------------------------- + +Name: HTOTAL +Offset: 0x00680734 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +HEQU width register +------------------- + +Name: HEQU_WIDTH +Offset: 0x00680738 +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + +HSERR width register +-------------------- + +Name: HSERR_WIDTH +Offset: 0x0068073C +4 bytes, read-write + +Bits 0-10: VAL (IV, read-write) + + + +'Standard' SVGA registers +========================= + +ATTR, CTRC, GRAPH, SEQ and MISC registers are available throught MMIO too. + +Name: ATTR_REG_INDEX +Offset: 0x006013c0 +1 byte, read-write + +Name: ATTR_REG_DATA +Offset: 0x006013c1 +1 byte, read-write + +Name: CRTC_REG_INDEX +Offset: 0x006013d4 +1 byte, read-write + +Name: CRTC_REG_DATA +Offset: 0x006013d5 +1 byte, read-write + +Name: GRA_REG_INDEX +Offset: 0x000C03ce +1 byte, read-write + +Name: GRA_REG_DATA +Offset: 0x000C03cf +1 byte, read-write + +Name: SEQ_REG_INDEX +Offset: 0x000C03c4 +1 byte, read-write + +Name: SEQ_REG_DATA +Offset: 0x000C03c5 +1 byte, read-write + +Name: MISC_REG +Offset: 0x000C03c2 +1 byte, read-write + + + +Extra CRTC registers +==================== + +Repaint 0 register +------------------ + +Extended offset and start address. + +Name: REPAINT0 +Index: 0x19 +1 byte + +Bits 0-4: START_ADDR_20_16 + +Bits 5-7: OFFSET_10_8 + +Repaint 1 register +------------------ + +Various flags. + +Name: REPAINT1 +Index: 0x1a +1 byte + +Bit 1: PALETTE_WIDTH + 8BITS 0x0 + 6BITS 0x1 + +Bit 2: LARGE_SCREEN + DISABLE 0x1 + ENABLE 0x0 ( >= 1280 ) + +Bit 4: COMPATIBLE_TEXT + ENABLE 0x1 + DISABLE 0x0 + +Bit 6: VSYNC + DISABLE 0x1 + ENABLE 0x0 + +Bit 7: HSYNC + DISABLE 0x1 + ENABLE 0x0 + +FIFO control register +--------------------- + +Controls how much data the refresh fifo requests. + +Name: FIFO_CONTROL +Index: 0x1b +1 byte + +Bits 0-2: BURST_LENGTH + BURST_LENGTH_8 0x0 + BURST_LENGTH_32 0x1 + BURST_LENGTH_64 0x2 + BURST_LENGTH_128 0x3 + BURST_LENGTH_256 0x4 + +Bit 7: UNDERFLOW_WARN + +FIFO register +------------- + +When the fifo occupancy falls below *twice* the watermark, +the refresh fifo will start to be refilled. If this value is +too low, you will get junk on the screen. Too high, and performance +will suffer. Watermark in units of 8 bytes. + +Name: FIFO +Index: 0x20 +1 byte + +Bits 0-5: WATERMARK + +Bit 7: RESET + +Extra register +-------------- + +Assorted extra bits. + +Name: EXTRA +Index: 0x25 +1 byte + +Bit 0: VERT_TOTAL_10 + +Bit 1: VERT_DISPLAY_END_10 + +Bit 2: VERT_RETRACE_START_10 + +Bit 3: VERT_BLANK_START_10 + +Bit 4: HORIZ_BLANK_END_6 + +Bit 5: OFFSET_11 + +Pixel register +-------------- + +Controls what the format of the framebuffer is. + +Name: PIXEL +Index: 0x28 +1 byte + +Bits 0-1: FORMAT + VGA 0x0 + 8BPP 0x1 + 16BPP 0x2 + 32BPP 0x3 + +Bits 3-5: TV_HORIZ_ADJUST + +Bit 6: TV_MODE + NTSC 0x0 + PAL 0x1 + +Bit 7: MODE + TV 0x1 + VGA 0x0 + +Horizontal extra register +------------------------- + +Horizonal extended bits. + +Name: HORIZ_EXTRA +Index: 0x2d +1 byte + +Bit 0: DISPLAY_TOTAL_8 + +Bit 1: DISPLAY_END_8 + +Bit 2: HORIZ_BLANK_START_8 + +Bit 3: HORIZ_RETRACE_START_8 + +Bit 4: INTER_HALF_START_8 + +Graphic cursor 0 register +------------------------- + +Name: GRCURSOR0 +Index: 0x30 +1 byte + +Bits 0-5: START_ADDR_21_16 + +Graphic cursor 1 register +------------------------- + +Name: GRCURSOR1 +Index: 0x31 +1 byte + +Bit 0: CURSOR + DISABLE 0x0 + ENABLE 0x1 + +Bit 1: SCAN_DBL + DISABLE 0x0 + ENABLE 0x1 + +Bits 3-7: START_ADDR_15_11 + +EOF diff --git a/doc/nvidia_notes/status.xlsx b/doc/nvidia_notes/status.xlsx new file mode 100644 index 000000000..bfeeb1452 Binary files /dev/null and b/doc/nvidia_notes/status.xlsx differ diff --git a/src/include/86box/nv/classes/vid_nv3_classes.h b/src/include/86box/nv/classes/vid_nv3_classes.h new file mode 100644 index 000000000..5106e5bff --- /dev/null +++ b/src/include/86box/nv/classes/vid_nv3_classes.h @@ -0,0 +1,1179 @@ +/* + * 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. + * + * Defines graphics objects for Nvidia NV3 architecture-based GPU (RIVA 128/RIVA 128 ZX), + * as well as for later GPUs if they use the same objects. + * Note: These uint32_ts are basically object methods that are being submitted + * They have different names so the user can use them more easily but different versions of the same class can be distinguished + * ALL of these structures HAVE(?) to be a size of exactly 0x2000 bytes because that's what the hashtable expects and they need to actually map into the vram address space + * (they are converted to pointers). In the case of NV3, these map directly to the PHYSICAL PGRAPH REGISTERS while sitting in RAMHT!!!!. + * + * Also, these class IDs don't relate to the internal architecture of the GPU. + * Effectively, the NVIDIA drivers are faking shit. There are only 22 classes but the drivers recognise many more and have a different naming scheme. See nv3_object_classes_driver.txt for the list of + * classes recognised by the driver. + * This is why the Class IDs you see here are not the same as you may see in other places. + * + * Todo: Is reserved* actually needed? + * + * + * Authors: Connor Hyde + * + * Copyright 2024-2025 Connor Hyde + */ + +#pragma once +#include +#include +#include +#include + +// CLass names for debugging +extern const char* nv3_class_names[]; + +/* Defines valid classes. */ +typedef enum nv3_pgraph_class_e +{ + nv3_pgraph_class01_beta_factor = 0x01, + nv3_pgraph_class02_rop = 0x02, + nv3_pgraph_class03_chroma_key = 0x03, + nv3_pgraph_class04_plane_mask = 0x04, + nv3_pgraph_class05_clipping_rectangle = 0x05, + nv3_pgraph_class06_pattern = 0x06, + nv3_pgraph_class07_rectangle = 0x07, + nv3_pgraph_class08_point = 0x08, + nv3_pgraph_class09_line = 0x09, + nv3_pgraph_class0a_lin = 0x0a, + nv3_pgraph_class0b_triangle = 0x0b, + nv3_pgraph_class0c_w95txt = 0x0c, + nv3_pgraph_class0d_m2mf = 0x0d, + nv3_pgraph_class0e_scaled_image_from_memory = 0x0e, + nv3_pgraph_class10_blit = 0x10, + nv3_pgraph_class11_image = 0x11, + nv3_pgraph_class12_bitmap = 0x12, + nv3_pgraph_class14_transfer2memory = 0x14, + nv3_pgraph_class15_stretched_image_from_cpu = 0x15, + nv3_pgraph_class17_d3d5tri_zeta_buffer = 0x17, + nv3_pgraph_class18_point_zeta_buffer = 0x18, + nv3_pgraph_class1c_image_in_memory = 0x1c, +} nv3_pgraph_class; + +/* + OBJECT METHODS +*/ + +// Global stuff +#define NV3_ROOT_HI_IM_OBJECT_MCOBJECTYFACE 0x0 // I'm going insane at 00:48 14/02/2025 +#define NV3_SET_NOTIFY_CONTEXT_FOR_DMA 0x0100 // Set object ctx for dma...see nv3_dma_context_t structure +#define NV3_SET_NOTIFY 0x0104 + +// Crap e.g. "OS name", that sometimes gets submitted, for some reason. So we just suppress the warning messages for them +#define NV3_NVCLASS_CRAP_START 0x0310 +#define NV3_NVCLASS_CRAP_END 0x0324 + +// Render OPeration +#define NV3_ROP_SET_ROP 0x0300 // Set GDI standard rop + +// Beta Factor +#define NV3_BETA_FACTOR 0x0300 + +// Chroma Key +// Can't figure out what this is, used in 9x but certainly software, can't find anywhere... +#define NV3_CHROMA_UNKNOWN_0200 0x0200 +#define NV3_CHROMA_KEY 0x0304 + +// Clip +#define NV3_CLIP_POSITION 0x0300 // S16:S16, 0=topleft +#define NV3_CLIP_SIZE 0x0304 // U16:U16 + +// Blit Pattern +#define NV3_PATTERN_FORMAT 0x0304 +#define NV3_PATTERN_SHAPE 0x0308 +#define NV3_PATTERN_SHAPE_8X8 0 +#define NV3_PATTERN_SHAPE_64X1 1 +#define NV3_PATTERN_SHAPE_1X64 2 +#define NV3_PATTERN_SHAPE_LAST_VALID NV3_PATTERN_SHAPE_1X64 + +#define NV3_PATTERN_UNUSED_DRIVER_BUG 0x030C +#define NV3_PATTERN_COLOR0 0x0310 +#define NV3_PATTERN_COLOR1 0x0314 +#define NV3_PATTERN_BITMAP_HIGH 0x0318 +#define NV3_PATTERN_BITMAP_LOW 0x031C + +// Rect + +#define NV3_RECTANGLE_COLOR 0x0304 + +// 16 possible rectangles. 8 byte structure, first 4 bytes = position, second 2 = size. +#define NV3_RECTANGLE_START 0x0400 + +#define NV3_RECTANGLE_MAX 16 +#define NV3_RECTANGLE_END 0x0480 + +// M2MF +#define NV3_M2MF_IN_CTXDMA_OFFSET 0x030C +#define NV3_M2MF_OUT_CTXDMA_OFFSET 0x0310 +#define NV3_M2MF_IN_PITCH 0x0314 +#define NV3_M2MF_OUT_PITCH 0x0318 +#define NV3_M2MF_SCANLINE_LENGTH_IN_BYTES 0x031C +#define NV3_M2MF_NUM_SCANLINES 0x0320 +#define NV3_M2MF_FORMAT 0x0324 + +// M2MF formats (IN and OUT ORed together) +#define NV3_M2MF_FORMAT_INPUT 0 +#define NV3_M2MF_FORMAT_OUTPUT 8 + +#define NV3_M2MF_NOTIFY 0x0328 + +// blit +#define NV3_BLIT_POSITION_IN 0x0300 +#define NV3_BLIT_POSITION_OUT 0x0304 +#define NV3_BLIT_SIZE 0x0308 + +// image_from_cpu +#define NV3_IMAGE_START_POSITION 0x0304 // starting position of image from cpu +#define NV3_IMAGE_SIZE 0x0308 +#define NV3_IMAGE_SIZE_IN 0x030C +#define NV3_IMAGE_COLOR_START 0x0400 +#define NV3_IMAGE_COLOR_MAX 32 +#define NV3_IMAGE_COLOR_END 0x0480 + +#define NV3_IMAGE_IN_MEMORY_COLOR_FORMAT 0x0300 +#define NV3_IMAGE_IN_MEMORY_IN_MEMORY_DMA_CTX_TYPE 0x0304 +#define NV3_IMAGE_IN_MEMORY_PITCH 0x0308 +#define NV3_IMAGE_IN_MEMORY_TOP_LEFT_OFFSET 0x030C +#define NV3_IMAGE_IN_MEMORY_TOP_LEFT_OFFSET_END 22 + +/* GDI */ + +/* Type A: Unclipped Rectangle */ +#define NV3_W95TXT_A_COLOR 0x03FC // It's the colour of the text. This is used to submit a dummy object so the notifier can be used to sync in Win2000 DDraw6 drivers. +#define NV3_W95TXT_A_RECT_START 0x0400 +#define NV3_W95TXT_A_RECT_SIZE 64 // Number of rects +#define NV3_W95TXT_A_RECT_END 0x05FF + +/* Type B: Clipped Rectangle */ +#define NV3_W95TXT_B_CLIP_TOPLEFT 0x07F4 +#define NV3_W95TXT_B_CLIP_BOTTOMRIGHT 0x07F8 +#define NV3_W95TXT_B_COLOR 0x07FC +#define NV3_W95TXT_B_CLIP_CLIPRECT_START 0x0800 +#define NV3_W95TXT_B_CLIP_CLIPRECT_SIZE 128 // Number of rects +#define NV3_W95TXT_B_CLIP_CLIPRECT_END 0x09FF + +/* Type C: Unscaled Single-Colour Text (filled in from mono bitmap) */ +#define NV3_W95TXT_C_CLIP_TOPLEFT 0x0BEC +#define NV3_W95TXT_C_CLIP_BOTTOMRIGHT 0x0BF0 +#define NV3_W95TXT_C_CLIP_COLOR 0x0BF4 +#define NV3_W95TXT_C_CLIP_SIZE 0x0BF8 +#define NV3_W95TXT_C_CLIP_POSITION 0x0BFC /* TOP LEFT */ +#define NV3_W95TXT_C_CLIP_CLIPRECT_START 0x0C00 +#define NV3_W95TXT_C_CLIP_CLIPRECT_SIZE 64 // Number of rects +#define NV3_W95TXT_C_CLIP_CLIPRECT_END 0x0DFF + +/* Type D: Scaled Single-Colour Text (filled in from mono bitmap) */ +#define NV3_W95TXT_D_CLIP_TOPLEFT 0x0FE8 +#define NV3_W95TXT_D_CLIP_BOTTOMRIGHT 0x0FEC +#define NV3_W95TXT_D_CLIP_COLOR 0x0FF0 +#define NV3_W95TXT_D_CLIP_SIZE_IN 0x0FF4 +#define NV3_W95TXT_D_CLIP_SIZE_OUT 0x0FF8 +#define NV3_W95TXT_D_CLIP_POSITION 0x0FFC /* TOP LEFT */ +#define NV3_W95TXT_D_CLIP_CLIPRECT_START 0x1000 +#define NV3_W95TXT_D_CLIP_CLIPRECT_SIZE 128 // Number of rects +#define NV3_W95TXT_D_CLIP_CLIPRECT_END 0x11FF + +/* Type E: Scaled Pattern-type Bitmap Text (filled) */ +#define NV3_W95TXT_E_CLIP_TOPLEFT 0x13E4 +#define NV3_W95TXT_E_CLIP_BOTTOMRIGHT 0x13E8 +#define NV3_W95TXT_E_CLIP_COLOR_0 0x13EC +#define NV3_W95TXT_E_CLIP_COLOR_1 0x13F0 +#define NV3_W95TXT_E_CLIP_SIZE_IN 0x13F4 +#define NV3_W95TXT_E_CLIP_SIZE_OUT 0x13F8 +#define NV3_W95TXT_E_CLIP_POSITION 0x13FC /* TOP LEFT */ +#define NV3_W95TXT_E_CLIP_CLIPRECT_START 0x1400 +#define NV3_W95TXT_E_CLIP_CLIPRECT_SIZE 128 // Number of rects +#define NV3_W95TXT_E_CLIP_CLIPRECT_END 0x15FF + + +/* Class context switch method */ +typedef struct nv3_class_ctx_switch_method_s +{ + union + { + uint32_t data; + + uint16_t instance; + uint8_t channel : 6; + uint16_t reserved : 9; + bool reset_if_volatile; // ???? + } set_notify_ctx_dma; // Set notifier context for DMA (context switch) + +} nv3_class_ctx_switch_method_t; + +/* +enumerates color formats +there are some other colour formats that are only used in certain areas which are defined below +*/ +typedef enum nv3_pgraph_pixel_format_e +{ + nv3_pgraph_pixel_format_r5g5b5 = 0, + nv3_pgraph_pixel_format_r8g8b8 = 1, + nv3_pgraph_pixel_format_r10g10b10 = 2, + nv3_pgraph_pixel_format_y8 = 3, + nv3_pgraph_pixel_format_y16 = 4, + nv3_pgraph_pixel_format_v8y8u8y18 = 5, // "18"? NV wtf? + nv3_pgraph_pixel_format_y18v8y8u8 = 6, // "18"? NV wtf? + nv3_pgraph_pixel_format_y420 = 7, // YUV 420 +} nv3_pgraph_pixel_format; + +/* Main color format */ +typedef struct nv3_color_expanded_s +{ + uint8_t a; + + /* WARNING: The internal format is 10-bit RGB! */ + uint16_t r; + uint16_t g; + uint16_t b; + + // YUV stuff + float y; + float u; + float v; + + // Indexed colour + union + { + uint16_t i16; + + uint8_t i16_high; + uint8_t i8; + }; + + // the pixel format + nv3_pgraph_pixel_format pixel_format; +} nv3_color_expanded_t; + +/* A simple ARGB format colour */ +typedef struct nv3_color_argb_s +{ + uint8_t a; + uint8_t r; + uint8_t g; + uint8_t b; +} nv3_color_argb_t; + +/* Generic 16-bit coordinate*/ +typedef struct nv3_coord_16_s +{ + uint16_t x; + uint16_t y; +} nv3_coord_16_t; + +/* A big position format with 30:16 = y, 15:11 = nothing, 10:0 = x */ +typedef struct nv3_coord_16_bigy_s +{ + // WHOSE IDEA WAS THIS? + uint16_t x : 11; + uint8_t reserved : 5; + uint16_t y : 15; + bool reserved2 : 1; +} nv3_coord_16_bigy_t; + +/* Generic 32-bit colour + 16-bit position */ +typedef struct nv3_color_and_coord_16_s +{ + nv3_color_expanded_t color; + nv3_coord_16_t points; +} nv3_color_and_coord_16_t; + +/* "UTRI" type triangle */ +typedef struct nv3_utri_s +{ + uint32_t color; // use nv3_color_expanded_t but changed for alignment reasons + nv3_coord_16_t point0; + nv3_coord_16_t point1; + nv3_coord_16_t point2; +} nv3_utri_t; + +/* Generic 16-bit clip region */ +typedef struct nv3_clip_16_s +{ + // The bounds of the clipping area. + uint16_t left; + uint16_t top; + uint16_t right; + uint16_t bottom; +} nv3_clip_16_t; + +/* In case your positions weren't HIGH PRECISION enough */ +typedef struct nv3_coord_32_s +{ + uint32_t x; + uint32_t y; +} nv3_coord_32_t; + +// COLOUR FORMATS + +/* + Object Class 0x01 (real hardware, also 0x41) + 0x12 (drivers) + Beta factor +*/ +typedef struct nv3_object_class_001 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; + uint32_t set_beta_factor_1d31; // 31:31 (?) value, 30:21 fraction + // Put the rest of it here +} nv3_beta_factor_t; + +/* + Object class 0x02 (real hardware) + 0x14/0x43 (drivers) + Also 0x42 in context IDs + Render operation used for things like blending. Appears to be 8-bit i.e. a ROP3 with 256 possible operations. +*/ +typedef struct nv3_object_class_002 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint8_t rop; // ROP3 (ID = ????????) +} nv3_render_operation_t; + +/* + Object class 0x03 (real hardware) + 0x15 (drivers) + Also 0x43 in context IDs + A chroma/color key, like in video editing +*/ +typedef struct nv3_object_class_003 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t color; // ROP3 (ID = ????????) +} nv3_chroma_key_t; + +/* + Object class 0x04 (real hardware) + 0x15 (drivers) + Also 0x44 in context IDs + Plane mask +*/ +typedef struct nv3_object_class_004 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t color; // Plane mask +} nv3_plane_mask_t; + +/* + Object class 0x05 (real hardware) + 0x19/0x1E/0x47 (drivers) + Also 0x45 in context IDs + Clipping rectangle used for various blitting operations +*/ +typedef struct nv3_object_class_005 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + + /* 16-bit precision */ + nv3_coord_16_t position; + nv3_coord_16_t size; + +} nv3_clipping_rectangle_t; + +/* + Object Class 0x06 (real hardware) + 0x?? (drivers) + Also 0x46 in context IDs + A pattern used for blits. Wahey! +*/ +typedef struct nv3_object_class_006 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t shape; // 0 = 8x8, 1 = 64x1, 2 = 1x64 + uint32_t color0; // Some 32-bit format (argb?) + uint32_t color1; // bit0=color0, bit1=color1 + uint32_t pattern[2]; // bit0=color0, bit1=color1 +} nv3_pattern_t; + +/* + Object Class 0x07 (real hardware) + 0x1E (drivers) + Also 0x47 in context IDs + A rectangle. Wahey! +*/ +typedef struct nv3_object_class_007 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t color; // The colour of the object. + nv3_coord_16_t position[16]; // The positions of up to 16 rectangles. + nv3_coord_16_t size[16]; // The sizes of up to 16 rectangles +} nv3_rectangle_t; + + +/* In case your points weren't colourful enough */ +typedef struct nv3_object_class_008_cpoint_s +{ + nv3_color_expanded_t color; // argb-format 32-bit color + nv3_coord_16_t position; // position +} nv3_object_class_008_cpoint_t; + +/* + Object Class 0x08 (real hardware) + 0x1A (drivers) + Also 0x48 in context IDs + A point: the revolutionary 3d graphics technique... +*/ +typedef struct nv3_object_class_008 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + nv3_color_expanded_t color; // argb? + nv3_coord_16_t point[16]; // Boring points + nv3_coord_32_t point32[16]; // Allows you to have points with full 32-bit precision + nv3_object_class_008_cpoint_t cpoint[16]; // Allows you to have c o l o r f u l points! +} nv3_point_t; + +/* Normal line... */ +typedef struct nv3_object_class_009_line_s +{ + nv3_coord_16_t start; // presumably unless it's in reverse order...TODO: check the order + nv3_coord_16_t end; + +} nv3_object_class_009_line_t; + +/* THIRTY TWO BIT PRECISION line */ +typedef struct nv3_object_class_009_line32_s +{ + uint32_t x0; + uint32_t x1; + uint32_t y0; + uint32_t y1; +} nv3_object_class_009_line32_t; + +/* nv3_object_class_009_polyline_t not implemented because it's just a duplicate of nv3_object_class_009_line */ +/* nv3_object_class_009_polyline32_t not implemented because it's just a duplicate of nv3_object_class_009_line32 */ + + +/* + Object Class 0x09 (real hardware) + 0x1B (drivers) + Also 0x49 in context IDs + It's a line, but also a polygon... +*/ +typedef struct nv3_object_class_009 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + nv3_color_expanded_t color; // argb? + nv3_object_class_009_line_t line[16]; // List of line points (...) + nv3_object_class_009_line32_t line32[8]; + nv3_object_class_009_line_t polyline[32]; + nv3_object_class_009_line32_t polyline32[16]; + nv3_color_and_coord_16_t cpolyline[16]; // List of line points and colours. +} nv3_line_t; + +/* + Object Class 0x0A (real hardware) + 0x1c (drivers) + Also 0x4a in context IDs + + This one is where nvidia reinvents the line, but without the starting or ending pixel. + Seriously. +*/ +typedef struct nv3_object_class_00A +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + + uint32_t set_notify; // Set notifier + + nv3_color_expanded_t color; // argb? + nv3_object_class_009_line_t line[16]; // List of line points (...) + nv3_object_class_009_line32_t line32[8]; + nv3_object_class_009_line_t polyline[32]; + nv3_object_class_009_line32_t polyline32[16]; + nv3_color_and_coord_16_t cpolyline[16]; // List of line points and colours. + +} nv3_lin_t; + +/* + Object Class 0x0B (real hardware) + 0x?? (drivers) + Also 0x4b in context IDs. + + This is a triangle but seems to be obsolete. It's replaced with UD3D0Z / D3D5 Accelerated Triangle with Zeta Buffer. Does it even exist? +*/ +typedef struct nv3_object_class_00B +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + nv3_color_expanded_t color; // argb? + // The points of the triangle. + nv3_coord_16_t points[3]; + + // Another way of filling out the points of the triangle + uint32_t x0; + uint32_t y0; + uint32_t x1; + uint32_t y1; + uint32_t x2; + uint32_t y2; + + nv3_coord_16_t mesh[32]; // Some kind of mesh format. I guess a list of vertex positions? + nv3_coord_32_t mesh32[16]; // Mesh with 32-bit format + nv3_utri_t ctriangle[8]; // Triangles with colour + nv3_color_and_coord_16_t ctrimesh[16]; // Some kind of mesh format. I guess a list of vertex positions? with colours + +} nv3_triangle_t; + +/* + Object Class 0x0C (real hardware) + 0x0C (drivers) + Also 0x4C in context IDs. + + GDI text acceleration for Windows 95. +*/ +typedef struct nv3_object_class_00C +{ + /* Unclipped rect (basically class 0x07 )*/ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t color_a; // Color for Clip A + nv3_coord_16_t rect_a_position[64]; + nv3_coord_16_t rect_a_size[64]; + /* Clipped rect */ + nv3_clip_16_t clip_b; + uint32_t color_b; // Color for Clip B + nv3_clip_16_t clipped_rect[64]; + /* Unclipped transparent bitmap */ + nv3_clip_16_t clip_c; + uint32_t color1_c; + nv3_coord_16_t size_c; + nv3_coord_16_t point_c; + uint32_t bitmap_c[128]; + /* Clipped transparent bitmap */ + nv3_clip_16_t clip_d; + uint32_t color1_d; + nv3_coord_16_t size_in_d; + nv3_coord_16_t size_out_d; + nv3_coord_16_t point_d; + uint32_t bitmap_d[128]; + /* Clipped 1bpp bitmap */ + nv3_clip_16_t clip_e; + uint32_t color0_e; + uint32_t color1_e; + nv3_coord_16_t size_in_e; + nv3_coord_16_t size_out_e; + nv3_coord_16_t point_e; + uint32_t bitmap_e[128]; +} nv3_win95_text_t; + + +/* + Object Class 0x0D (real hardware) + 0x?? (drivers) + Also 0x4D in context IDs. + + Represents reformatting of an image in memory. +*/ +typedef struct nv3_object_class_00D +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t offset_in; + uint32_t offset_out; + uint32_t pitch_in; + uint32_t pitch_out; + uint32_t scanline_length; // Stride? + uint32_t num_scanlines; + uint8_t format; // input increment 1 2 or 4, output increment 1 2 or 4 (represented by << 8) + uint32_t buffer_notify; // Notify the Buffedr +} nv3_memory_to_memory_format_t; + +/* + Object Class 0x0E (real hardware) + 0x?? (drivers) + Also 0x4E in context IDs. + + Represents a scaled image coming from memory. +*/ +typedef struct nv3_object_class_00E +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_coord_16_t clip_0; + nv3_coord_16_t clip_1; + nv3_coord_16_t rectangle_out_0; + nv3_coord_16_t rectangle_out_1; + // Calculus in a graphics card + uint32_t delta_du_dx; + uint32_t delta_dv_dy; + nv3_coord_16_t size; // can be size_y if YUV420 + uint32_t pitch; + uint32_t offset; + uint32_t point; + // YUV420 stuff + uint32_t pitch_yuv420; + uint32_t offset_y; + uint32_t offset_u; + uint32_t offset_v; + uint32_t point_yuv420; +} nv3_scaled_image_from_memory_t; + +// (0x0F does not exist) + +/* + Object Class 0x10 (real hardware) + 0x?? (drivers) + Also 0x50 in context IDs. + + Represents a screen to screen blit. I'm still figuring it out. +*/ + +typedef struct nv3_object_class_010 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_coord_16_t point_in; + nv3_coord_16_t point_out; + nv3_coord_16_t size; +} nv3_blit_t; + +/* + Object Class 0x11 (real hardware) + 0x?? (drivers) + Also 0x51 in context IDs. + + Represents an image from the cpu (i guess from system memory) +*/ +typedef struct nv3_object_class_011 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_coord_16_t point; + nv3_coord_16_t size; + nv3_coord_16_t size_in; + nv3_color_expanded_t color[32]; // The colour to use +} nv3_image_t; + +/* + Object Class 0x12 (real hardware) + 0x?? (drivers) + Also 0x52 in context IDs. + + Bitmap from CPU. + It seems the difference is that an image is colour but a +*/ +typedef struct nv3_object_class_012 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_color_expanded_t color_0; + nv3_color_expanded_t color_1; + nv3_coord_16_t point; // Top left(?) of the bitmap + nv3_coord_16_t size; + nv3_coord_16_t size_in; + uint32_t monochrome_bitmap[32]; +} nv3_bitmap_t; + +// 0x13 doesn't exist + +/* + Object Class 0x14 (real hardware) + 0x?? (drivers) + Also 0x54 in context IDs. + + Image Transfer to Memory + It seems the difference is that an image is colour but a bitmap is b&w +*/ +typedef struct nv3_object_class_014 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_coord_16_t point; + nv3_coord_16_t size; + uint32_t image_pitch; // bytes per row + uint32_t image_start; +} nv3_image_to_memory_t; + +/* + Object Class 0x15 (real hardware) + 0x?? (drivers) + Also 0x55 in context IDs. + + Stretched Image from CPU + Seems to be, by the very large color array, the main class used in 2d acceleration. +*/ +typedef struct nv3_object_class_015 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_coord_16_t size_in; + uint32_t delta_dx_du; + uint32_t delta_dy_dv; + nv3_coord_16_t clip_0; + nv3_coord_16_t clip_1; + uint32_t point12d4; /* todo: fraction struct */ + // no reserve needed +} nv3_stretched_image_from_cpu_t; + +// 0x16 invalid + +/* + Object Class 0x17 (real hardware) + 0x?? (drivers) + Also 0x57 in context IDs. + + Direct3D 5.0 accelerated triangle with zeta buffer (combined z buffer and stencil buffer) + This is the final boss of this GPU. True horror stands below. +*/ + +// +// NV3 D3D5: TEXTURING & PIXEL FORMATS +// + +typedef enum nv3_d3d5_texture_pixel_format_e +{ + /* + 16-Bit Pixel Format + 5 bits red, 5 bits green, 5 bits alpha, "boolean" alpha + */ + nv3_d3d5_pixel_format_le_a1r5g5b5 = 0, + + /* + 15-Bit Pixel Format (represented as 16) + 1 bit irrelevant, 5 bits red, 5 bits green, 5 bits alpha + */ + nv3_d3d5_pixel_format_le_x1r5g5b5 = 1, + + /* + 16-Bit Pixel Format + 4 bits alpha, 4 bits red, 4 bits green, 4 bits blue + */ + nv3_d3d5_pixel_format_le_a4r4g4b4 = 2, + + /* + 16-Bit Pixel Format + 5 bits red, 6 bits green, 5 bits blue + (Required nv3tweak...) + */ + nv3_d3d5_pixel_format_le_r5g6b5 = 3, + +} nv3_d3d5_texture_pixel_format; + +/* Output format + + The output pixel format...I +*/ +typedef enum nv3_d3d5_output_pixel_format_e +{ + /* + 32-Bit Pixel Format + 8 bits irrelevant, 8 bits red, 8 bits green, 8 bits blue + */ + nv3_d3d5_output_pixel_format_le_x8r8g8b8 = 0, + + /* + 32-Bit Pixel Format + 8 bits irrelevant, 8 bits red, 8 bits green, 8 bits blue + Is this even used?? The riva can't even do 32 bit colour in 3d... + */ + nv3_d3d5_output_pixel_format_le_a8r8g8b8 = 1, + + +} nv3_d3d5_output_pixel_format; + + +/* Texture size + + NOTE: ONLY 256X256 OR LOWER ARE SUPPORTED! 2048X2048X16 TAKES UP ENTIRE VRAM OF RIVA 128 ZX... + I ASSUME THESE ARE INTERNALLY SCALED DOWN +*/ +typedef enum nv3_d3d5_texture_size_e +{ + nv3_d3d5_texture_size_1x1 = 0, + + nv3_d3d5_texture_size_2x2 = 1, + + nv3_d3d5_texture_size_4x4 = 2, + + nv3_d3d5_texture_size_8x8 = 3, + + nv3_d3d5_texture_size_16x16 = 4, + + nv3_d3d5_texture_size_32x32 = 5, + + nv3_d3d5_texture_size_64x64 = 6, + + nv3_d3d5_texture_size_128x128 = 7, + + nv3_d3d5_texture_size_256x256 = 8, + + nv3_d3d5_texture_size_512x512 = 9, + + nv3_d3d5_texture_size_1024x1024 = 10, + + // Kind of infeasible considering hardware VRAM size limitations + nv3_d3d5_texture_size_2048x2048 = 11, + + +} nv3_d3d5_texture_size; + +/* Texture Wrapping Mode for U/V Coordinate Overflow + +*/ +typedef enum nv3_d3d5_texture_wrap_mode_e +{ + // Map textures in a cylindrical fashion. + nv3_d3d5_texture_wrap_mode_cylindrical = 0, + + // Simply wrap back to the start. + nv3_d3d5_texture_wrap_mode_wrap = 1, + + // Mirror the texture. + nv3_d3d5_texture_wrap_mode_mirror = 2, + + // Clamp to the last border pixel. + nv3_d3d5_texture_wrap_mode_clamp = 3, +} nv3_d3d5_texture_wrap_mode; + + +/* This is blending but isn't really considered to be it in the GPU for some reason + What do we do with out input texel BEFORE processing it? + */ +typedef enum nv3_d3d5_dest_color_interpretation_e +{ + // Do nothing + nv3_d3d5_source_color_normal = 0, + + // Invert Colour + nv3_d3d5_source_color_inverse = 1, + + // Invert Alpha before Processing + nv3_d3d5_source_color_alpha_inverse = 2, + + // Take Alpha as 1 + nv3_d3d5_source_color_alpha_one = 3, + +} nv3_d3d5_dest_color_interpretation; + +// The full texture format structure +typedef struct nv3_d3d5_texture_format_s +{ + uint16_t color_key_color_mask; + bool color_key_enabled : 1; + nv3_d3d5_texture_pixel_format color_format : 2; + nv3_d3d5_texture_size size_min : 4; + nv3_d3d5_texture_size size_max : 4; +} nv3_d3d5_texture_format_t; + +// +// NV3 D3D5: INTERPOLATION +// + +/* + ?????? + Interpolating between mip levels? (or for texture blending) +*/ +typedef enum nv3_d3d5_interpolator_algorithm_e +{ + // Zero-order hold interpolation? + nv3_d3d5_interpolator_zoh = 0, + + // Zero-order hold (microsoft variant)? + nv3_d3d5_interpolator_zoh_ms = 1, + + // Full-order hold interpolation? + nv3_d3d5_interpolator_foh = 2, + +} nv3_d3d5_interpolator_algorithm; + +// +// NV3 D3D5: Z-BUFFER +// + +/* Probably the sorting algorithm */ +typedef enum nv3_d3d5_zbuffer_type_e +{ + // Sort based on linear distance + nv3_d3d5_zbuffer_linear = 0, + + // Sort based on distance from view frustum + nv3_d3d5_zbuffer_screen = 1, + +} nv3_d3d5_zbuffer_type; + +// NV3 D3D5: WRITE CONTROL (SHARED BETWEEN ZETA BUFFER AND ALPHA) +typedef enum nv3_d3d5_buffer_write_control_e +{ + // Never write. + nv3_d3d5_buffer_write_control_never = 0, + + // Only write the alpha. + nv3_d3d5_buffer_write_control_alpha = 1, + + // Write both alpha and the zeta-buffer. + nv3_d3d5_buffer_write_control_alpha_zeta = 2, + + // Write only the zeta-buffer + nv3_d3d5_buffer_write_control_zeta = 3, + + // Write everything (alpha+z+zeta?) + nv3_d3d5_buffer_write_control_always = 4, + + +} nv3_d3d5_buffer_write_control; + +// +// NV3 D3D5: BUFFER COMPARISON (SHARED BETWEEN ZETA BUFFER AND ALPHA CONTROL) +// + +// Todo: Which direction? (i.e. is less than p1 < p2 or p2 < p1!) +typedef enum nv3_d3d5_buffer_comparison_type_e +{ + // !!!ILLEGAL COMPARISON TYPE!!!! + nv3_d3d5_buffer_comparison_illegal = 0, + + // The (depth?) test always fails. + nv3_d3d5_buffer_comparison_always_false = 1, + + // True if less than fail. + nv3_d3d5_buffer_comparison_less_than = 2, + + // The test succeeds if equal. + nv3_d3d5_buffer_comparison_equal = 3, + + // The test succeeds if less or equal. + nv3_d3d5_buffer_comparison_less_or_equal = 4, + + // The test succeeds if greater. + nv3_d3d5_buffer_comparison_greater = 5, + + // The test succeeds if the two elements are equal. + nv3_d3d5_buffer_comparison_not_equal = 6, + + // The test succeeds if greater or equal + nv3_d3d5_buffer_comparison_greater_or_equal = 7, + + // The test always succeeds. + nv3_d3d5_buffer_comparison_always_true = 8, + +} nv3_d3d5_buffer_comparison_type; + +// +// NV3 D3D5: BLENDING +// + +/* Render Operation for Blending */ +typedef enum nv3_d3d5_blend_render_operation_e +{ + nv3_d3d5_blend_render_operation_and = 0, + + nv3_d3d5_blend_add_with_saturation = 1, + +} nv3_d3d5_blend_render_operation; + +typedef enum nv3_d3d5_blend_beta_factor_e +{ + nv3_d3d5_blend_beta_factor_srcalpha = 0, + + nv3_d3d5_blend_beta_factor_zero = 1, + +} nv3_d3d5_blend_beta_factor; + +typedef enum nv3_d3d5_blend_input0_e +{ + nv3_d3d5_blend_input0_srcalpha = 0, + + nv3_d3d5_blend_input0_zero = 1, + +} nv3_d3d5_blend_input0; + +typedef enum nv3_d3d5_blend_input1_e +{ + nv3_d3d5_blend_input1_destalpha = 0, + + nv3_d3d5_blend_input1_zero = 1, + +} nv3_d3d5_blend_input1; + +// +// NV3 D3D5: CULLING +// + +typedef enum nv3_d3d5_culling_algorithm_e +{ + // Don't cull + nv3_d3d5_culling_algorithm_none = 0, + + // Cull Clockwise around view frustum? + nv3_d3d5_culling_algorithm_clockwise = 1, + + // Cull counterclockwise around view frustum? + nv3_d3d5_culling_algorithm_counterclockwise = 2, + +} nv3_d3d5_culling_algorithm; + +/* Specular reflection parameters */ +typedef struct nv3_d3d5_specular_s +{ + uint8_t i0 : 4; + uint8_t i1 : 4; + uint8_t i2 : 4; + uint8_t i3 : 4; + uint8_t i4 : 4; + uint8_t i5 : 4; + uint8_t fog; //table fog emulation? +} nv3_d3d5_specular_t; + +// +// NV3 D3D5: MISC +// +typedef struct nv3_d3d5_texture_filter_s +{ + uint8_t spread_x; + uint8_t spread_y; + uint8_t mipmap; + uint8_t turbo; +} nv3_d3d5_texture_filter_t; + +// +// NV3 D3D5: OUTPUT CONTROL STRUCTURE +// + +/* Output Control for D3D5 Triangles */ +typedef struct nv3_d3d5_control_out_s +{ + nv3_d3d5_interpolator_algorithm ctrl_out_interpolator : 2; + uint8_t reserved : 2; + nv3_d3d5_texture_wrap_mode wrap_u : 2; // Controls wrapping mode of U texture coordinate + nv3_d3d5_texture_wrap_mode wrap_v : 2; // Controls wrapping move of V texture coordinate + nv3_d3d5_output_pixel_format output_pixel_format : 1; + bool reserved2 : 1; + nv3_d3d5_dest_color_interpretation dest_color_interpretation : 2; + nv3_d3d5_culling_algorithm culling_algorithm : 2; + bool reserved3 : 1; + nv3_d3d5_zbuffer_type zbuffer_type : 1; + nv3_d3d5_buffer_comparison_type zeta_buffer_compare : 4; + nv3_d3d5_buffer_write_control zeta_write : 3; + bool reserved4 : 1; + nv3_d3d5_buffer_write_control color_write : 3; + bool reserved5 : 1; + nv3_d3d5_blend_render_operation blend_rop : 1; + nv3_d3d5_blend_input0 blend_input0 : 1; + nv3_d3d5_blend_input1 blend_input1 : 1; +} nv3_d3d5_control_out_t; + +typedef struct nv3_d3d5_alpha_control_s +{ + uint8_t alpha_key; + nv3_d3d5_buffer_comparison_type zeta_buffer_compare : 4; + uint32_t reserved : 20; +} nv3_d3d5_alpha_control_t; + +// +// NV3 D3D5: Triangle Coordinates +// +typedef struct nv3_d3d5_coordinate_s +{ + nv3_d3d5_specular_t specular_reflection_parameters; + nv3_color_expanded_t color; // YOU HAVE TO FLIP THE ENDIANNESS. NVIDIA??? WHAT??? + + // Seems more plausible for these specifically to be floats. + // Also makes my life easier... + float x; // X coordinate in 3d space of the triangle + float y; // Y coordinate in 3d space of the triangle + float z; // Z coordinate in 3d space of the triangle + float m; // 1/W for projection + float u; // U coordinate within texture for the (top left?) of the triangle where sampling starts. + float v; // V coordinate within texture for the (top left?) of the triangle where sampling starts. +} nv3_d3d5_coordinate_t; + +typedef struct nv3_object_class_017 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + uint32_t texture_offset; + nv3_d3d5_texture_format_t texture_format; + nv3_d3d5_texture_filter_t texture_filter; + nv3_color_expanded_t fog_color; // Alpha is ignored here! + nv3_d3d5_control_out_t control_out; + nv3_d3d5_alpha_control_t alpha_control; + + nv3_d3d5_coordinate_t coordinate_points[128]; // The points we are rendering. + /* No placeholder needed, it really is that long. */ +} nv3_d3d5_accelerated_triangle_with_zeta_buffer_t; + + +// Color and Zeta Buffer algorithm +typedef struct nv3_zeta_buffer_s +{ + nv3_color_expanded_t color; + uint32_t zeta; // 16 bits z, 8 bits stenciul +} nv3_zeta_buffer_t; + +typedef struct nv3_object_class_018 +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; + uint32_t set_notify; + nv3_d3d5_control_out_t control_out; + nv3_d3d5_alpha_control_t alpha_control; + nv3_coord_16_t point; + nv3_zeta_buffer_t zeta[8]; +} nv3_point_with_zeta_buffer_t; + +/* 0x19, 0x1A, 0x1B don't exist */ + +/* WHY IS THE FORMAT DIFFERENT TO THE REST OF THE GPU? + They are making it look like a bitfield but it's hex? + + THEY ARE ALL LITTLE ENDIAN +*/ +typedef enum nv3_object_class_01C_pixel_format_e +{ + // Y8P4 + // 12-bits (Y8 - Planar YUV 8 bits (Y value only), 4 bits of indexed colour too? + nv3_image_in_memory_pixel_format_le_y8_p4 = 0x1010000, + + // Y16P2 + // 16-bits (Y16) - Planar YUV 16 bits (Y value only), 2 bits of indexed colour too? + nv3_image_in_memory_pixel_format_le_y16_p2 = 0x1010101, + + /* 1 unused bit, 555 15-bit format, p2(?) */ + nv3_image_in_memory_pixel_format_x1r5g5b5_p2 = 0x1000000, + + // X8G8B8R8, 24-bit colour (or 24-bit colour with alpha) + nv3_image_in_memory_pixel_format_x8g8b8r8 = 0x1, +} nv3_object_class_01C_pixel_format; + +typedef struct nv3_object_class_01C +{ + nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) + uint32_t set_notify; // Set notifier + nv3_object_class_01C_pixel_format format; // Completely different from everything else + uint32_t pitch; // 16-bit + uint32_t linear_address; // 22-bit: Linear address in vram. +} nv3_image_in_memory_t; + +// See envytools. This is where we finally end up after this mess, it allows parameters to be passed to the methods. +typedef struct nv3_grobj_s +{ + uint32_t grobj_0; + uint32_t grobj_1; + uint32_t grobj_2; + uint32_t grobj_3; +} nv3_grobj_t; +// TODO: PATCHCORDS!!!! TO LINK ALL OF THIS TOGETHER!!! + +// PIO Subchannel info +#define NV3_SUBCHANNEL_PIO_IS_PFIFO_FREE 0x0010 +#define NV3_SUBCHANNEL_PIO_ALWAYS_ZERO_START 0x0012 +#define NV3_SUBCHANNEL_PIO_ALWAYS_ZERO_END 0x0017 \ No newline at end of file diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h new file mode 100644 index 000000000..cca3761be --- /dev/null +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -0,0 +1,64 @@ +/* + * 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 headers for rendering + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#pragma once + +/* Core */ +void nv3_render_current_bpp(); +void nv3_render_current_bpp_dfb_8(uint32_t address); +void nv3_render_current_bpp_dfb_16(uint32_t address); +void nv3_render_current_bpp_dfb_32(uint32_t address); + +/* Pixel */ +void nv3_render_write_pixel(nv3_coord_16_t position, uint32_t color, nv3_grobj_t grobj); +uint8_t nv3_render_read_pixel_8(nv3_coord_16_t position, nv3_grobj_t grobj); +uint16_t nv3_render_read_pixel_16(nv3_coord_16_t position, nv3_grobj_t grobj); +uint32_t nv3_render_read_pixel_32(nv3_coord_16_t position, nv3_grobj_t grobj); + +/* Address */ +uint32_t nv3_render_get_vram_address(nv3_coord_16_t position, nv3_grobj_t grobj); +uint32_t nv3_render_get_vram_address_for_buffer(nv3_coord_16_t position, uint32_t buffer); + +/* Colour Conversion */ +uint32_t nv3_render_get_palette_index(uint8_t index); // Get a colour for a palette index. (The colours are 24 bit RGB888 with a 0xFF alpha added for some purposes.) +uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); // Convert a colour to A1R10G10B10 for chroma key purposes. +nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj); // Convert a colour to full RGB10 format from the current working format. +uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t color); // Convert a colour from the current working format to RGB10 format. + +/* ROP */ +uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop); + +/* Pattern */ +void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); + +/* Primitives */ +void nv3_render_rect(nv3_coord_16_t position, nv3_coord_16_t size, uint32_t color, nv3_grobj_t grobj); // Render an A (unclipped) GDI rect +void nv3_render_rect_clipped(nv3_clip_16_t clip, uint32_t color, nv3_grobj_t grobj); // Render a B (clipped) GDI rect. + +/* Chroma */ +bool nv3_render_chroma_test(uint32_t color, nv3_grobj_t grobj); + +/* Blit */ +void nv3_render_blit_image(uint32_t color, nv3_grobj_t grobj); +void nv3_render_blit_screen2screen(nv3_grobj_t grobj); + +/* GDI */ +void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitmap_data, nv3_grobj_t grobj); +void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj); /* GDI Type-E: Clipped 1bpp colour-expanded bitmap */ + +/* DMA */ +void nv3_perform_dma_m2mf(nv3_grobj_t grobj); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv.h b/src/include/86box/nv/vid_nv.h new file mode 100644 index 000000000..83f94c167 --- /dev/null +++ b/src/include/86box/nv/vid_nv.h @@ -0,0 +1,178 @@ +/* + * 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 real Nvidia driver. + * Implements components shared by all variants of the Nvidia GPUs (hopefully to be) supported by 86Box. + * + * This driver draws on collaborative work by many people over many years. + * + * Credit to: + * + * - Marcelina KoÅ›cielnicka (envytools) https://envytools.readthedocs.io/en/latest/ + * - fuel (PCBox developer) https://github.com/PCBox/PCBox + * - nouveau developers https://nouveau.freedesktop.org/ + * - Utah GLX developers https://utah-glx.sourceforge.net/ + * - XFree86 developers https://www.xfree86.org/ + * - xemu developers https://github.com/xemu-project/xemu + * - RivaTV developers https://rivatv.sourceforge.net (esp. https://rivatv.sourceforge.net/stuff/riva128.txt) + * - Nvidia for leaking their driver symbols numerous times ;^) https://nvidia.com + * - Vort (Bochs GeForce fork) https://github.com/Vort/Bochs/tree/geforce + * - People who prevented me from giving up (various) + * + * Authors: Connor Hyde / starfrost + * + * Copyright 2024-2025 Connor Hyde + */ +#ifdef EMU_DEVICE_H // what + +//TODO: split this all into nv1, nv3, nv4... +#include <86box/log.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> +#include <86box/timer.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include <86box/nv/vid_nv_rivatimer.h> + +void nv_log_set_device(void* device); +void nv_log(const char *fmt, ...); + +// Verbose logging level. +void nv_log_verbose_only(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 NV_PCI_DEVICE_NV1 0x0008 // Nvidia NV1 +#define NV_PCI_DEVICE_NV1_VGA 0x0009 // Nvidia NV1 VGA core +#define NV_PCI_DEVICE_NV2 0x0010 // Nvidia NV2 / Mutara V08 (cancelled) +#define NV_PCI_DEVICE_NV3 0x0018 // Nvidia NV3 (Riva 128) +#define NV_PCI_DEVICE_NV3T 0x0019 // Nvidia NV3T (Riva 128 ZX) +#define NV_PCI_DEVICE_NV4 0x0020 // Nvidia NV4 (RIVA TNT) + +#define NV_CHIP_REVISION_NV1_A0 0x0000 // 1994 +#define NV_CHIP_REVISION_NV1_B0 0x0010 // 1995 +#define NV_CHIP_REVISION_NV1_C0 0x0020 // 1995-96? + +#define NV_CHIP_REVISION_NV3_A0 0x0000 // January 1997 +#define NV_CHIP_REVISION_NV3_B0 0x0010 // October 1997 +#define NV_CHIP_REVISION_NV3_C0 0x0020 // 1998 + +// Architecture IDs +#define NV_ARCHITECTURE_NV1 1 // NV1/STG2000 +#define NV_ARCHITECTURE_NV2 2 // Nvidia 'Mutara V08' +#define NV_ARCHITECTURE_NV3 3 // Riva 128 +#define NV_ARCHITECTURE_NV4 4 // Riva TNT and later + +#define NV_MAX_BUF_SIZE_X 1920 // Maximum buffer size, X +#define NV_MAX_BUF_SIZE_Y 1200 // Maximum buffer size, Y + +typedef enum nv_bus_generation_e +{ + // NV1 - Prototype version + nv_bus_vlb = 0, + + // NV1 + // NV3 + nv_bus_pci = 1, + + // NV3 + nv_bus_agp_1x = 2, + + // NV3T + // NV4 + nv_bus_agp_2x = 3, + +} 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 + void* log; // new logging engine + // 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) - 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 + 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) + uint32_t gpu_revision; // GPU Stepping + double pixel_clock_frequency; // Frequency used for pixel clock# + double refresh_time; // Rough estimation of refresh rate, for when we can present the screen + double refresh_clock; // Time since the last refresh + rivatimer_t* pixel_clock_timer; // Timer for measuring pixel clock + bool pixel_clock_enabled; // Pixel Clock Enabled - stupid crap used to prevent us enabling the timer multiple times + double memory_clock_frequency; // Source Frequency for PTIMER + rivatimer_t* memory_clock_timer; // Timer for measuring memory/gpu clock + + // VCLK / NVCLK do not have timers set here. + pc_timer_t* nv4_vclk_timer; // NV4+ MCLK (Video RAM) timer + + bool memory_clock_enabled; // Memory Clock Enabled - stupid crap used to prevent us eanbling the timer multiple times + 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 + // + bool debug_dba_enabled; // Debug DBA override + uint32_t debug_dba; // Debug DBA +} 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)(void); // 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); + + +#endif \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv1.h b/src/include/86box/nv/vid_nv1.h new file mode 100644 index 000000000..be6895c8b --- /dev/null +++ b/src/include/86box/nv/vid_nv1.h @@ -0,0 +1,167 @@ +/* + * 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. + * + * Quadratic Heaven + * + * Authors: Connor Hyde + * + * Copyright 2024-2025 Connor Hyde + */ + +#pragma once + +#include +#include + +extern const device_config_t nv1_config[]; // Config for RIVA 128 (revision A/B) + +// +// PCI Bus Information +// + +#define NV1_PCI_BAR0_SIZE 0xFFFFFF + +// +// VRAM +// +#define NV1_VRAM_SIZE_1MB 0x100000 +#define NV1_VRAM_SIZE_2MB 0x200000 +#define NV1_VRAM_SIZE_4MB 0x400000 + +// Video BIOS +#define NV1_VBIOS_E3D_2X00 "roms/video/nvidia/nv1/Diamond_Edge_3D_2x00.BIN" +#define NV1_VBIOS_E3D_3X00 "roms/video/nvidia/nv1/Diamond_Edge_3D_3400_BIOS_M27C256.BIN" + +// +// PMC +// +#define NV1_PMC_BOOT_0 0x0 +#define NV1_PMC_BOOT_0_REVISION 0 + +#define NV1_PMC_BOOT_0_REVISION_A 0x0 // Prototype (1994) +#define NV1_PMC_BOOT_0_REVISION_B1 0x0 // Prototype (early 1995) +#define NV1_PMC_BOOT_0_REVISION_B2 0x0 // Prototype (mid 1995) +#define NV1_PMC_BOOT_0_REVISION_B3 0x0 // Final? +#define NV1_PMC_BOOT_0_REVISION_C 0x0 // Final? + +#define NV1_PMC_BOOT_0_IMPLEMENTATION 8 +#define NV1_PMC_BOOT_0_IMPLEMENTATION_NV0 0x1 // Nvidia Hardware Simulator (1993-1994) +#define NV1_PMC_BOOT_0_IMPLEMENTATION_NV1_D32 0x2 // NV1 + DRAM + SGS-Thomson STG-1732/1764 DAC +#define NV1_PMC_BOOT_0_IMPLEMENTATION_NV1_V32 0x3 // NV1 + VRAM + SGS-Thomson STG-1732/1764 DAC +#define NV1_PMC_BOOT_0_IMPLEMENTATION_PICASSO 0x4 // NV1 + VRAM + NV 128-bit DAC + + +// Defines the NV architecture version (NV1/NV2/...) +#define NV1_PMC_BOOT_0_ARCHITECTURE 16 +#define NV1_PMC_BOOT_0_ARCHITECTURE_NV0 0x0 // Nvidia Hardware Simulator (1993-1994) +#define NV1_PMC_BOOT_0_ARCHITECTURE_NV1 0x1 // NV1 (1995) +#define NV1_PMC_BOOT_0_ARCHITECTURE_NV2 0x2 // Mutara (1996, cancelled) + +#define NV1_PMC_DEBUG_0 0x80 + +#define NV1_PMC_INTR_0 0x100 +#define NV1_PMC_INTR_EN_0 0x140 + +#define NV1_PMC_INTR_EN_0_INTA 0 +#define NV1_PMC_INTR_EN_0_INTB 4 +#define NV1_PMC_INTR_EN_0_INTC 8 +#define NV1_PMC_INTR_EN_0_INTD 12 + +#define NV1_PMC_INTR_EN_0_DISABLED 0x0 +#define NV1_PMC_INTR_EN_0_HARDWARE 0x1 +#define NV1_PMC_INTR_EN_0_SOFTWARE 0x2 +#define NV1_PMC_INTR_EN_0_ALL 0x3 // (HARDWARE | SOFTWARE) + +#define NV1_PMC_INTR_READ 0x160 + +//TODO: DEFINE bits +#define NV1_PMC_ENABLE 0x200 + +// +// PRAMIN +// + +#define NV1_RAMIN_START 0x100000 + +// +// PAUTH +// Scary nvidia mode +// + +// Read only +#define NV1_PAUTH_DEBUG_0 0x605080 +#define NV1_PAUTH_DEBUG_0_BREACH_DETECTED 0 +#define NV1_PAUTH_DEBUG_0_EEPROM_INVALID 4 + +#define NV1_PAUTH_CHIP_TOKEN_0 0x605400 +#define NV1_PAUTH_CHIP_TOKEN_1 0x605404 +#define NV1_PAUTH_PASSWORD_0(i) 0x605800+(i*16) +#define NV1_PAUTH_PASSWORD_1(i) 0x605804+(i*16) +#define NV1_PAUTH_PASSWORD_2(i) 0x605808+(i*16) +#define NV1_PAUTH_PASSWORD_3(i) 0x60580C+(i*16) + +#define NV1_PAUTH_PASSWORD_SIZE 128 + +// +// PFB +// + +#define NV1_PFB_BOOT_0 0x600000 + +#define NV1_PFB_BOOT_0_RAM_AMOUNT 0 +#define NV1_PFB_BOOT_0_RAM_AMOUNT_1MB 0x0 +#define NV1_PFB_BOOT_0_RAM_AMOUNT_2MB 0x1 +#define NV1_PFB_BOOT_0_RAM_AMOUNT_4MB 0x2 + +// +// PEXTDEV +// + +#define NV1_STRAPS 0x608000 +#define NV1_STRAPS_STRAP_VENDOR 0 + +// +// PRAM+RAMIN +// + +#define NV1_PRAM_CONFIG 0x602200 +#define NV1_PRAM_CONFIG_SIZE 0 +#define NV1_PRAM_CONFIG_12KB 0 +#define NV1_PRAM_CONFIG_20KB 1 +#define NV1_PRAM_CONFIG_36KB 2 +#define NV1_PRAM_CONFIG_68KB 3 + +// Position of RAMPW in RAMIN +#define NV1_RAMPW_POSITION_CONFIG0 0x2c00 +#define NV1_RAMPW_POSITION_CONFIG1 0x4c00 +#define NV1_RAMPW_POSITION_CONFIG2 0x8c00 +#define NV1_RAMPW_POSITION_CONFIG3 0x10c00 + +// Static RAMPW mirror +#define NV1_PRAMPW 0x606000 +#define NV1_RAMPW_SIZE 0x400 + +// +// PROM +// +#define NV1_PROM 0x601000 +#define NV1_PROM_SIZE 32768 + +// Structures +typedef struct nv1_s +{ + nv_base_t nvbase; // Base Nvidia structure +} nv1_t; + +// Device Core +void nv1_init(); +void nv1_close(void* priv); +void nv1_speed_changed(void *priv); +void nv1_draw_cursor(svga_t* svga, int32_t drawline); +void nv1_recalc_timings(svga_t* svga); +void nv1_force_redraw(void* priv); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h new file mode 100644 index 000000000..3726ecc03 --- /dev/null +++ b/src/include/86box/nv/vid_nv3.h @@ -0,0 +1,1764 @@ +/* + * 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. + * + * Welcome to what happens when a single person demands that their overly complicated "vision" of a design be implemented + * with absolutely no compromise. This is true lunacy. + * + * Explanation of what is being done here, and how this all works, hopefully posted on the 86Box blog. + * Notes specific to a subsystem in the header or c file for that subsystem + * Also check the doc folder for some more notres + * + * vid_nv3.h: NV3 Architecture Hardware Reference (open-source) + * Last updated: 12 April 2025 (STILL WORKING ON IT!!!) + * + * Authors: Connor Hyde + * + * Copyright 2024-2025 Connor Hyde + */ + +#pragma once +#include <86box/nv/classes/vid_nv3_classes.h> +#include <86box/nv/render/vid_nv3_render.h> + +// The GPU base structure +extern const device_config_t nv3_config[]; // Config for RIVA 128 (revision A/B) +extern const device_config_t nv3t_config[]; // Config for RIVA 128 ZX (revision C) + +#define NV3_MMIO_SIZE 0x1000000 // Max MMIO size + +#define NV3_LFB_RAMIN_MIRROR_START 0x400000 // Mirror of ramin (VERIFY ON HARDWARE) +#define NV3_LFB_MIRROR_START 0x800000 // The second half of LFB(?) +#define NV3_LFB_RAMIN_START 0xC00000 // RAMIN mapping start +#define NV3_LFB_MAPPING_SIZE 0x400000 // Size of RAMIN + +// THere are 64 DMA channels grouped into 8 "channels" with 8 "subchannels" each. You can only use one channel at a time. An arbitrary number of 8 objects can be submitted. +// Channel 0 is always taken up by NV drivers. + +#define NV3_DMA_CHANNELS 8 +#define NV3_DMA_SUBCHANNELS_PER_CHANNEL 8 + +#define NV3_DMA_CHANNELS_TOTAL 0x7F // This is also used somewhere despite there only being 8*8 = 64 channels + +#define NV3_LAST_VALID_GRAPHICS_OBJECT_ID 0x1F + +// The class ids are represented with 5 bits in PGRAPH, but 7 bits in PFIFO! +// What... +#define NV3_PFIFO_FIRST_VALID_GRAPHICS_OBJECT_ID 0x40 +#define NV3_PFIFO_LAST_VALID_GRAPHICS_OBJECT_ID 0x5F + +// Default value for the boot information register. +// Depends on the chip +#define NV3_BOOT_REG_REV_A00 0x00030100 // todo: format is wrong(?) for nv3a, fix it later +#define NV3_BOOT_REG_REV_B00 0x00030110 +#define NV3_BOOT_REG_REV_C00 0x00030120 + +// various vbioses for testing +// Coming soon: MIROmagic Premium BIOS (when I get mine dumped) +//todo: move to hash system + +// Oldest one of these - August 8, 1997 + +// This particular VBIOS is very early and has certain bugs +#define NV3_VBIOS_STB_V128_V160 "roms/video/nvidia/nv3/stb-velocity128-1.6.bin" // STB Velocity 128 3D (Riva 128) Ver.1.60 +#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 +#define NV3T_VBIOS_DIAMOND_V330_V182B "roms/video/nvidia/nv3/nv3t182b.rom" // Diamond Multimedia Viper V330 8M BIOS - Version 1.82B +#define NV3T_VBIOS_ASUS_V170 "roms/video/nvidia/nv3/A170D03T.rom" // ASUS AGP-V3000 ZXTV BIOS - V1.70D.03 (C) 1996-98 Nvidia Corporation +#define NV3T_VBIOS_REFERENCE_CEK_V171 "roms/video/nvidia/nv3/BIOS_49_Riva 128" // Reference BIOS: RIVA 128 ZX BIOS - V1.71B-N (C) 1996-98 NVidia Corporation +#define NV3T_VBIOS_REFERENCE_CEK_V172 "roms/video/nvidia/nv3/vgasgram.rom" // Reference(?) BIOS: RIVA 128 ZX BIOS - V1.72B (C) 1996-98 NVidia Corporation + +// The default VBIOS to use +#define NV3_VBIOS_DEFAULT NV3_VBIOS_ERAZOR_V15403 + +// Temporary, will be loaded from settings +#define NV3_VRAM_SIZE_2MB 0x200000 // 2MB +#define NV3_VRAM_SIZE_4MB 0x400000 // 4MB +#define NV3_VRAM_SIZE_8MB 0x800000 // NV3T only +// There is also 1mb supported by the card but it was never used + +// 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_AGP_CAPABILITIES_POINTER 0x34 + +#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 + +// +// AGP configuration +// + +#define NV3_AGP_START 0x44 + +// stupid stupid pci system +#define NV3_AGP_CAPABILITIES_START 0x44 +#define NV3_AGP_CAPABILITIES_CAP_ID 0x44 +#define NV3_AGP_CAPABILITIES_CAP_ID_AGP 0x02 // "AGP" +#define NV3_AGP_CAPABILITIES_NEXT_PTR 0x45 +#define NV3_AGP_CAPABILITIES_AGP_VERSION 0x46 +#define NV3_AGP_CAPABILITIES_AGP_VERSION_MINOR 0 +#define NV3_AGP_CAPABILITIES_AGP_VERSION_MAJOR 4 +#define NV3_AGP_CAPABILITIES_H 0x47 + +#define NV3_AGP_STATUS_RATE 0x48 +#define NV3_AGP_STATUS_RATE_1X_SUPPORTED 0x1 +#define NV3_AGP_STATUS_RATE_2X_SUPPORTED 0x2 + +#define NV3_AGP_STATUS_BYTE1 0x49 +#define NV3_AGP_STATUS_BYTE1_SBA 1 +#define NV3_AGP_STATUS_SBA_SUPPORTED 0x0 +#define NV3_AGP_STATUS_SBA_UNSUPPORTED 0x1 +#define NV3_AGP_STATUS_MAX_REQUESTS 0x4B +#define NV3_AGP_STATUS_MAX_REQUESTS_AMOUNT 4 + +#define NV3_AGP_COMMAND 0x4C +#define NV3_AGP_COMMAND_DATA_RATE 0 +#define NV3_AGP_COMMAND_DATA_RATE_1X 0x1 +#define NV3_AGP_COMMAND_DATA_RATE_2X 0x2 +#define NV3_AGP_COMMAND_BYTE1 0x4D +#define NV3_AGP_COMMAND_BYTE1_ENABLE 0 +#define NV3_AGP_COMMAND_BYTE1_ENABLE_DISABLED 0x0 +#define NV3_AGP_COMMAND_BYTE1_ENABLE_ENABLED 0x1 +#define NV3_AGP_COMMAND_SBA_ENABLE 1 +#define NV3_AGP_COMMAND_SBA_ENABLE_DISABLED 0x0 +#define NV3_AGP_COMMAND_SBA_ENABLE_ENABLED 0x1 +#define NV3_AGP_COMMAND_REQUEST_DEPTH 0x4F + +#define NV3_AGP_END 0x4F + +// +// ACPI (NV3T only) +// TODO: IMPLEMENT THIS!!!!!! +// +#define NV3_POWER_CAP_ID 0x60 +#define NV3_POWER_NEXT_PTR 0x61 +#define NV3_POWER_VERSION 0x62 + +// "The RIVA128ZX does not physically change its power consumption when +// POWER_STATE is modified." +#define NV3_POWER_STATE 0x64 + +#define NV3_POWER_STATE_D0 0x0 +#define NV3_POWER_STATE_D3HOT 0x3 + +// 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_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 // Determines if PGRAPH is enabled. +#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 + +#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_DEBUG_0 0x1084 // Bus Control Debug +#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_MINIMUM_GUARANTEED_DEPTH 0x7C + +#define NV3_PFIFO_DELAY_0 0x2040 // PFIFO Config Register +#define NV3_PFIFO_DEBUG_0 0x2080 // PFIFO Debug Register +#define NV3_PFIFO_CACHE0_ERROR_PENDING 0 +#define NV3_PFIFO_CACHE1_ERROR_PENDING 4 + +#define NV3_PFIFO_INTR 0x2100 // FIFO - Interrupt Status +#define NV3_PFIFO_INTR_EN 0x2140 // FIFO - Interrupt Enable + +// PFIFO interrupts +#define NV3_PFIFO_INTR_CACHE_ERROR 0 +#define NV3_PFIFO_INTR_RUNOUT 4 +#define NV3_PFIFO_INTR_RUNOUT_OVERFLOW 8 +#define NV3_PFIFO_INTR_DMA_PUSHER 12 +#define NV3_PFIFO_INTR_DMA_PTE 16 + +#define NV3_PFIFO_CONFIG_0 0x2200 +#define NV3_PFIFO_CONFIG_0_DMA_FETCH 8 + +#define NV3_PFIFO_CONFIG_RAMHT 0x2210 // Hashtable for graphics objects config +#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS 12 // 15:12 +#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS_DEFAULT 0x0 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE 16 // 17:16 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_4K 0x0 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_8K 0x1 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_16K 0x2 +#define NV3_PFIFO_CONFIG_RAMHT_SIZE_32K 0x3 + +#define NV3_PFIFO_CONFIG_RAMFC 0x2214 +#define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS 9 +#define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS_DEFAULT 0x1C00 // Hardcoded in silicon? +#define NV3_PFIFO_CONFIG_RAMRO 0x2218 +#define NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS 9 +#define NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS_DEFAULT 0x1E00 // Hardcoded in silicon? +#define NV3_PFIFO_CONFIG_RAMRO_SIZE 16 +#define NV3_PFIFO_CONFIG_RAMRO_SIZE_512B 0x0 +#define NV3_PFIFO_CONFIG_RAMRO_SIZE_8K 0x1 + +#define NV3_PFIFO_RUNOUT_STATUS 0x2400 +#define NV3_PFIFO_RUNOUT_STATUS_RANOUT 0 // 1 if we fucked up +#define NV3_PFIFO_RUNOUT_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_RUNOUT_STATUS_FULL 8 +#define NV3_PFIFO_RUNOUT_PUT 0x2410 +#define NV3_PFIFO_RUNOUT_PUT_ADDRESS 3 // 9:3 if small ramfc(?) otherwise 12:3 +#define NV3_PFIFO_RUNOUT_GET 0x2420 +#define NV3_PFIFO_RUNOUT_GET_ADDRESS 3 // 13:3 + +#define NV3_PFIFO_RUNOUT_RAMIN_ERR 28 // bit to or with + +#define NV3_PFIFO_CACHE0_SIZE 1 // This is for software-injected notified only! +#define NV3_PFIFO_CACHE1_SIZE_REV_AB 32 +#define NV3_PFIFO_CACHE1_SIZE_REV_C 64 +#define NV3_PFIFO_CACHE1_SIZE_MAX NV3_PFIFO_CACHE1_SIZE_REV_C +#define NV3_PFIFO_CACHE_REASSIGNMENT 0x2500 + +#define NV3_PFIFO_CACHE0_PUSH_ENABLED 0x3000 +#define NV3_PFIFO_CACHE0_PUSH_CHANNEL_ID 0x3004 +#define NV3_PFIFO_CACHE0_PUT 0x3010 +#define NV3_PFIFO_CACHE0_STATUS 0x3014 +#define NV3_PFIFO_CACHE0_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_CACHE0_STATUS_FULL 8 +#define NV3_PFIFO_CACHE0_PUT_ADDRESS 2 // 1 bit +#define NV3_PFIFO_CACHE0_PULL0 0x3040 +#define NV3_PFIFO_CACHE0_PULL0_ENABLED 0 +#define NV3_PFIFO_CACHE0_PULL0_HASH_FAILURE 4 +#define NV3_PFIFO_CACHE0_PULL0_SOFTWARE_METHOD 8 +#define NV3_PFIFO_CACHE0_PULLER_CTX_STATE 0x3050 +#define NV3_PFIFO_CACHE0_PULLER_CTX_STATE_DIRTY 4 // 1=dirty 0=clean +#define NV3_PFIFO_CACHE0_GET 0x3070 +#define NV3_PFIFO_CACHE0_GET_ADDRESS 2 // 1 bit +// Current channel context - cache1 +#define NV3_PFIFO_CACHE0_CTX 0x3080 + +#define NV3_PFIFO_CACHE0_METHOD_START 0x3100 +#define NV3_PFIFO_CACHE0_METHOD_END 0x3200 +#define NV3_PFIFO_CACHE0_METHOD_ADDRESS 2 // 12:2 +#define NV3_PFIFO_CACHE0_METHOD_SUBCHANNEL 13 // 15:13 +#define NV3_PFIFO_CACHE1_PUSH_ENABLED 0x3200 +#define NV3_PFIFO_CACHE1_PUSH_CHANNEL_ID 0x3204 +#define NV3_PFIFO_CACHE1_PUT 0x3210 +#define NV3_PFIFO_CACHE1_PUT_ADDRESS 2 // 6:2 +#define NV3_PFIFO_CACHE1_STATUS 0x3214 +#define NV3_PFIFO_CACHE1_STATUS_RANOUT 0 // 1 if we fucked up +#define NV3_PFIFO_CACHE1_STATUS_EMPTY 4 // 1 if ramro is empty +#define NV3_PFIFO_CACHE1_STATUS_FULL 8 +#define NV3_PFIFO_CACHE1_DMA_STATUS 0x3218 +#define NV3_PFIFO_CACHE1_DMA_STATUS_STATE 0 +#define NV3_PFIFO_CACHE1_DMA_STATUS_STATE_IDLE 0x00 +#define NV3_PFIFO_CACHE1_DMA_STATUS_STATE_RUNNING 0x01 +#define NV3_PFIFO_CACHE1_DMA_CONFIG_0 0x3220 +#define NV3_PFIFO_CACHE1_DMA_CONFIG_1 0x3224 +#define NV3_PFIFO_CACHE1_DMA_CONFIG_2 0x3228 +#define NV3_PFIFO_CACHE1_DMA_CONFIG_3 0x322C +#define NV3_PFIFO_CACHE1_DMA_CONFIG_3_TARGET_NODE 0 // The type of bus we are sending over +#define NV3_PFIFO_CACHE1_DMA_CONFIG_3_TARGET_NODE_PCI 0x02 // The type of bus we are sending over +#define NV3_PFIFO_CACHE1_DMA_CONFIG_3_TARGET_NODE_AGP 0x03 // The type of bus we are sending over + +// Why does a gpu need its own translation lookaside buffer and pagetable format. Are they crazy +// Seems to be the same format as the notifier engine +#define NV3_PFIFO_CACHE1_DMA_TLB_TAG 0x3230 +#define NV3_PFIFO_CACHE1_DMA_TLB_PTE 0x3234 // pagetable entry for dma +#define NV3_PFIFO_CACHE1_DMA_TLB_PTE_IS_PRESENT 1 +#define NV3_PFIFO_CACHE1_DMA_TLB_FRAME_ADDRESS 12 // 31:12 +#define NV3_PFIFO_CACHE1_DMA_TLB_PT_BASE 0x3238 // Base of pagetable for DMA +#define NV3_PFIFO_CACHE1_PULL0 0x3240 +//todo: merge stuff +#define NV3_PFIFO_CACHE1_PULL0_ENABLED 0 +#define NV3_PFIFO_CACHE1_PULL0_HASH_FAILURE 4 +#define NV3_PFIFO_CACHE1_PULL0_SOFTWARE_METHOD 8 // 0=software, 1=hardware +#define NV3_PFIFO_CACHE1_PULLER_CTX_STATE 0x3250 +#define NV3_PFIFO_CACHE1_PULLER_CTX_STATE_DIRTY 4 +#define NV3_PFIFO_CACHE1_GET 0x3270 +#define NV3_PFIFO_CACHE1_GET_ADDRESS 2 // 6:2 + +// Current channel context - cache1 +#define NV3_PFIFO_CACHE1_CTX_START 0x3280 +#define NV3_PFIFO_CACHE1_CTX_END 0x32F0 + +#define NV3_PFIFO_CACHE1_METHOD_START 0x3300 +#define NV3_PFIFO_CACHE1_METHOD_END 0x3400 +#define NV3_PFIFO_CACHE1_METHOD_ADDRESS 2 // 12:2 +#define NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL 13 // 15:13 + + +#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_ALARM 0 // Alarm interrupt +#define NV3_PTIMER_INTR_EN 0x9140 +#define NV3_PTIMER_NUMERATOR 0x9200 +#define NV3_PTIMER_DENOMINATOR 0x9210 +#define NV3_PTIMER_TIME_0_NSEC 0x9400 // nanoseconds [31:5] +#define NV3_PTIMER_TIME_1_NSEC 0x9410 // nanoseconds [28:0] +#define NV3_PTIMER_ALARM_NSEC 0x9420 // nanoseconds [31:5] +#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 // VGA stuff written from main GPU +#define NV3_PRMVIO_END 0xC0400 +#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_DELAY 0x100044 +#define NV3_PFB_DEBUG_0 0x100080 // Debug register for pfb +#define NV3_PFB_GREEN_0 0x1000C0 + +#define NV3_PFB_CONFIG_0 0x100200 // Framebuffer interface config register 0 + +// What is this lol +// ??? Part of the memory timings +#define NV3_PFB_RTL 0x100300 +#define NV3_PFB_CONFIG_0_RESOLUTION 0 +// 1=40 horiz. resolution +// i assume it can be divided by some kind of divisor to produce the vertical resolution (e.g. 3/2 or multiply by 2/3) to get the final +// horiz is 32*value +// theoretically it should support resolutions from 40-2560 horiz + +// WHAT ARE THE TIMINGS: ARE THEY IN THE VBIOS? +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_320 0xA +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_400 0xD +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_480 0xF +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_512 0x10 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_640 0x14 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_800 0x19 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_960 0x1E +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_1024 0x20 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_1152 0x24 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_1280 0x28 +#define NV3_PFB_CONFIG_0_HORIZ_RESOLUTION_1600 0x32 + +#define NV3_PFB_CONFIG_0_PIXEL_DEPTH 8 +#define NV3_PFB_CONFIG_0_DEPTH_8BPP 0x1 +#define NV3_PFB_CONFIG_0_DEPTH_16BPP 0x2 +#define NV3_PFB_CONFIG_0_DEPTH_32BPP 0x3 + +#define NV3_PFB_CONFIG_1 0x100204 // Framebuffer interface config register 1 +#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 0x11FFFF +#define NV3_PALT_START 0x120000 // ??? but it exists +#define NV3_PALT_END 0x12FFFF +#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 +// PGRAPH Core + +#define NV3_PGRAPH_MAX_BUFFERS 4 + +// For these debug registers, 0=Disabled, 1=Enabled + +// Debug 0: General +#define NV3_PGRAPH_DEBUG_0 0x400080 +#define NV3_PGRAPH_DEBUG_0_STATE_IN_RESET 0 +#define NV3_PGRAPH_DEBUG_0_AP_PIPE_IN_RESET 1 +#define NV3_PGRAPH_DEBUG_0_CACHE_IN_RESET 2 +#define NV3_PGRAPH_DEBUG_0_3D_PIPE_IN_RESET 3 +#define NV3_PGRAPH_DEBUG_0_BULK_READS 4 +#define NV3_PGRAPH_DEBUG_0_TILING 16 +#define NV3_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_2D 20 +#define NV3_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_3D 21 +#define NV3_PGRAPH_DEBUG_0_DRAWDIR_AUT 24 +#define NV3_PGRAPH_DEBUG_0_DRAWDIR_Y 25 +#define NV3_PGRAPH_DEBUG_0_ALPHA_ABORT 28 + +// Debug 1: Registers +#define NV3_PGRAPH_DEBUG_1 0x400084 +#define NV3_PGRAPH_DEBUG_1_VOLATILE_RESET_LAST 0 +#define NV3_PGRAPH_DEBUG_1_DMA_ACTIVITY_CANCEL 4 +#define NV3_PGRAPH_DEBUG_1_TURBO3D_2X 8 +#define NV3_PGRAPH_DEBUG_1_TURBO3D_4X 9 +#define NV3_PGRAPH_DEBUG_1_TRIANGLE_OPS 12 +#define NV3_PGRAPH_DEBUG_1_TRIANGLE_CLIP_OPS 13 +#define NV3_PGRAPH_DEBUG_1_INSTANCE 16 +#define NV3_PGRAPH_DEBUG_1_CONTEXT 20 +#define NV3_PGRAPH_DEBUG_1_CACHE_FLUSH 24 +#define NV3_PGRAPH_DEBUG_1_ZCLAMP 28 + +// Debug 2: 3D Pipeline +#define NV3_PGRAPH_DEBUG_2 0x400088 +#define NV3_PGRAPH_DEBUG_2_AVOID_READMODIFYWRITE_BLEND 0 +#define NV3_PGRAPH_DEBUG_2_DPWR_FIFO 8 +#define NV3_PGRAPH_DEBUG_2_BILINEAR_FILTERING_3D 12 +#define NV3_PGRAPH_DEBUG_2_ANISOTROPIC_FILTERING_3D 13 +#define NV3_PGRAPH_DEBUG_2_FOG 14 +#define NV3_PGRAPH_DEBUG_2_LIGHTING 15 // Not sure what this does, maybe hardware t&l was planned +#define NV3_PGRAPH_DEBUG_2_BILINEAR_FILTERING_2D 16 +#define NV3_PGRAPH_DEBUG_2_ANISOTROPIC_FILTERING_2D 17 +#define NV3_PGRAPH_DEBUG_2_D3D_COALESCE 20 // coalesce reads/writes for d3d class 0x17 +#define NV3_PGRAPH_DEBUG_2_D3D_COALESCE_POINT_ZETA 22 // class 0x18 coalesce +#define NV3_PGRAPH_DEBUG_2_PREFETCH 24 +#define NV3_PGRAPH_DEBUG_2_VOLATILE_RESET 28 + +// Debug 3: Zeta & Alpha Buffer +#define NV3_PGRAPH_DEBUG_3 0x40008C +#define NV3_PGRAPH_DEBUG_3_CULLING 0 +#define NV3_PGRAPH_DEBUG_3_FAST_DATA_D3D 4 +#define NV3_PGRAPH_DEBUG_3_FAST_DATA_STRETCH 5 +#define NV3_PGRAPH_DEBUG_3_ZFLUSH 7 +#define NV3_PGRAPH_DEBUG_3_AUTOZFLUSH_POINT_ZETA 8 +#define NV3_PGRAPH_DEBUG_3_AUTOZFLUSH_D3D 9 +#define NV3_PGRAPH_DEBUG_3_SLOT_CONFLICT_POINT_ZETA 10 // Slot conflict handling for POINT_ZETA (class 0x18) +#define NV3_PGRAPH_DEBUG_3_SLOT_CONFLICT_D3D 11 // Slot conflict handling for D3D5_TRI (class 0x17) +#define NV3_PGRAPH_DEBUG_3_EARLY_ZABORT 12 +#define NV3_PGRAPH_DEBUG_3_TRIANGLE_END_FLUSH 13 +#define NV3_PGRAPH_DEBUG_3_ZFIFO_NOOP 14 // ??? +#define NV3_PGRAPH_DEBUG_3_DITHER 15 +#define NV3_PGRAPH_DEBUG_3_FORCE_COLOR_BUFFER_READ 16 +#define NV3_PGRAPH_DEBUG_3_FORCE_ZETA_BUFFER_READ 17 +#define NV3_PGRAPH_DEBUG_3_DATA_CHECK 20 +#define NV3_PGRAPH_DEBUG_3_DATA_CHECK_FAIL 21 +#define NV3_PGRAPH_DEBUG_3_FORMAT_CHECK 22 +#define NV3_PGRAPH_DEBUG_3_ALPHA_CHECK 24 + +// Interrupt stuff +#define NV3_PGRAPH_INTR_0 0x400100 +#define NV3_PGRAPH_INTR_0_VBLANK 8 // Fired every frame +#define NV3_PGRAPH_INTR_0_VBLANK_ENABLED 0x1 // Is the vblank interrupt enabled? +#define NV3_PGRAPH_INTR_0_SOFTWARE_NOTIFY 28 // Fired on software notification + +#define NV3_PGRAPH_INTR_1 0x400104 +#define NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING 0 // Software or invalid method +#define NV3_PGRAPH_INTR_1_INVALID_DATA 4 // Invalid data. Not sure when this would be triggered. +#define NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY 12 // Tried to notify while a notify was pending. +#define NV3_PGRAPH_INTR_1_CTXSW_NOTIFY 16 // Notify fired for software context + +#define NV3_PGRAPH_INTR_EN_0 0x400140 // Interrupt Control for PGRAPH #1 +//todo: add what this does +#define NV3_PGRAPH_INTR_EN_1 0x400144 // Interrupt Control for PGRAPH #2 (it can receive two at onc) +#define NV3_PGRAPH_CTX_SWITCH 0x400180 // Holds the current PGRAPH context, switched by context switching + +/* Contextual information for pgraph */ +#define NV3_PGRAPH_CTX_SWITCH_COLOR_FORMAT 0 // Holds the current color format used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_ALPHA 3 // Holds a boolean indicating in if alpha transparency is currently enabled in drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_MONO_FORMAT 8 // Holds the current color format used for monochome drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_DAC_BYPASS 9 // Holds if PRAMDAC should be bypassed, and an external DAC drawn. +#define NV3_PGRAPH_CTX_SWITCH_Z_WRITE 12 // Holds if we should write back to the zbuffer. +#define NV3_PGRAPH_CTX_SWITCH_CHROMA_KEY 13 // Holds the current chroma mask used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_PLANE_MASK 14 // Holds the current plane mask used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_USER_CLIP 15 // Holds the user-specified clipping information used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER 16 // Holds the buffer ID used for drawing operation (i.e. which bpixel/bpitch/boffset index to use) +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER0_ENABLED 20 // Holds a boolean indicating if buffer 0 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER1_ENABLED 21 // Holds a boolean indicating if buffer 1 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER2_ENABLED 22 // Holds a boolean indicating if buffer 2 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER3_ENABLED 23 // Holds a boolean indicating if buffer 3 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG 24 // ROP type + +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0 0x0 // Reserved +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_DST_SRC 0x1 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_DST 0x2 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_SRC 0x3 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_DST 0x4 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_SRC 0x5 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_DST 0x6 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_SRC0 0x7 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_SRC1 0x8 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_PAT 0x9 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_SRC 0xA +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_PAT 0xB +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_SRC 0xC +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_PAT 0xD +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_PAT_SRC 0xE +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD1 0xF +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST 0x10 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_DST_SRC 0x11 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_DST 0x12 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_PAT 0x13 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_PAT_SRC 0x14 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_PAT 0x15 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD2 0x16 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS 0x17 // Ignore +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD0 0x18 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_SRC_DST 0x19 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_DST_SRC 0x1A +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD1 0x1B +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD2 0x1C +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_SRC 0x1D +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD3 0x1E +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD4 0x1F + +#define NV3_PGRAPH_CTX_SWITCH_VOLATILE 31 // HUH + +#define NV3_PGRAPH_CONTEXT_CONTROL 0x400190 // DMA context control +#define NV3_PGRAPH_CONTEXT_USER 0x400194 // Current DMA context state, may rename +#define NV3_PGRAPH_CONTEXT_CACHE(i) 0x4001A0+(i*4) // Context Cache +#define NV3_PGRAPH_CONTEXT_CACHE_SIZE 8 +// TODO: CLIP0/CLIP1 (8 clips min/max in 32bits) +#define NV3_PGRAPH_ABS_UCLIP_XMIN 0x40053C // Clip X minimum +#define NV3_PGRAPH_ABS_UCLIP_XMAX 0x400540 // Clip X maximum +#define NV3_PGRAPH_ABS_UCLIP_YMIN 0x400544 // Clip Y minimum +#define NV3_PGRAPH_ABS_UCLIP_YMAX 0x400548 // Clip Y maximum +#define NV3_PGRAPH_SRC_CANVAS_MIN 0x400550 // Minimum Source Canvas for Blit, Y=30:16, X=10:0 +#define NV3_PGRAPH_SRC_CANVAS_MAX 0x400554 // Maximum Source Canvas for Blit, Y=30:16, X=10:0 +#define NV3_PGRAPH_DST_CANVAS_MIN 0x400558 // Minimum Destination Canvas for Blit, Y=30:16, X=10:0 +#define NV3_PGRAPH_DST_CANVAS_MAX 0x40055C // Maximum Destination Canvas for Blit, Y=30:16, X=10:0 +#define NV3_PGRAPH_PATTERN_COLOR_0_RGB 0x400600 +#define NV3_PGRAPH_PATTERN_COLOR_0_ALPHA 0x400604 +#define NV3_PGRAPH_PATTERN_COLOR_1_RGB 0x400608 +#define NV3_PGRAPH_PATTERN_COLOR_1_ALPHA 0x40060C // pattern color +#define NV3_PGRAPH_PATTERN_BITMAP_HIGH 0x400610 // pattern bitmap [31:0] +#define NV3_PGRAPH_PATTERN_BITMAP_LOW 0x400614 // pattern bitmap [63:32] +#define NV3_PGRAPH_PATTERN_SHAPE 0x400618 +#define NV3_PGRAPH_ROP3 0x400624 // ROP3 +#define NV3_PGRAPH_PLANE_MASK 0x400628 +#define NV3_PGRAPH_CHROMA_KEY 0x40062C +#define NV3_PGRAPH_BETA 0x400640 // Beta factor (30:23 fractional, 22:0 before fraction) +#define NV3_PGRAPH_DMA 0x400680 +#define NV3_PGRAPH_INSTANCE 0x400688 // Current instance (?) + +// Current notification object for pgraph +#define NV3_PGRAPH_NOTIFY 0x400684 // Notifier for PGRAPH +#define NV3_PGRAPH_NOTIFY_INSTANCE 0 +#define NV3_PGRAPH_NOTIFY_REQUEST_PENDING 16 +#define NV3_PGRAPH_NOTIFY_REQUEST_TYPE 20 +#define NV3_PGRAPH_NOTIFY_REQUEST_TYPE_HARDWARE 0x0 // anything else is software + +#define NV3_PGRAPH_CLIP0_MIN 0x400690 // Clip for Blitting 0 Min +#define NV3_PGRAPH_CLIP0_MAX 0x400694 // Clip for Blitting 0 Max +#define NV3_PGRAPH_CLIP1_MIN 0x400698 // Clip for Blitting 1 Min +#define NV3_PGRAPH_CLIP1_MAX 0x40069C // Clip for Blitting 1 Max +#define NV3_PGRAPH_CLIP_MISC 0x4006A0 // Regions/Render/Complex mode +#define NV3_PGRAPH_FIFO_ACCESS 0x4006A4 // Is PGRAPH enabled? +#define NV3_PGRAPH_FIFO_ACCESS_DISABLED 0x0 +#define NV3_PGRAPH_FIFO_ACCESS_ENABLED 0x1 +#define NV3_PGRAPH_CLIP_MISC 0x4006A0 // Miscellaneous clipping information +#define NV3_PGRAPH_STATUS 0x4006B0 // Current PGRAPH status +#define NV3_PGRAPH_TRAPPED_ADDRESS 0x4006B4 +#define NV3_PGRAPH_TRAPPED_DATA 0x4006B8 +#define NV3_PGRAPH_TRAPPED_INSTANCE 0x4006BC + +#define NV3_PGRAPH_DMA_INTR_0 0x401100 // PGRAPH DMA Interrupt Status +#define NV3_PGRAPH_DMA_INTR_INSTANCE 0 +#define NV3_PGRAPH_DMA_INTR_PRESENT 4 +#define NV3_PGRAPH_DMA_INTR_PROTECTION 8 +#define NV3_PGRAPH_DMA_INTR_LINEAR 12 +#define NV3_PGRAPH_DMA_INTR_NOTIFY 16 +#define NV3_PGRAPH_DMA_INTR_EN_0 0x401140 // PGRAPH DMA Interrupt Enable 0 + +#define NV3_PGRAPH_DPRAM_SIZE 12288 // Size of the internal texture cache + +// 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_CLASS01_BETA_START 0x410000 // Beta blending factor +#define NV3_PGRAPH_CLASS01_BETA_END 0x411FFF +#define NV3_PGRAPH_CLASS02_ROP_START 0x420000 // Blending render operation used at final pixel/fragment generation stage +#define NV3_PGRAPH_CLASS02_ROP_END 0x421FFF +#define NV3_PGRAPH_CLASS03_COLORKEY_START 0x430000 // Color key for image +#define NV3_PGRAPH_CLASS03_COLORKEY_END 0x431FFF +#define NV3_PGRAPH_CLASS04_PLANEMASK_START 0x440000 // Plane mask (for clipping?) +#define NV3_PGRAPH_CLASS04_PLANEMASK_END 0x441FFF +#define NV3_PGRAPH_CLASS05_CLIP_START 0x450000 // clipping, probably class 23 +#define NV3_PGRAPH_CLASS05_CLIP_END 0x451FFF +#define NV3_PGRAPH_CLASS06_PATTERN_START 0x460000 // presumably a blend pattern +#define NV3_PGRAPH_CLASS06_PATTERN_END 0x461FFF +#define NV3_PGRAPH_CLASS07_RECTANGLE_START 0x470000 // also class 25 - that's black [NV1] +#define NV3_PGRAPH_CLASS07_RECTANGLE_END 0x471FFF // also class 25 - that's black [NV1] +#define NV3_PGRAPH_CLASS08_POINT_START 0x480000 // A single point +#define NV3_PGRAPH_CLASS08_POINT_END 0x481FFF +#define NV3_PGRAPH_CLASS09_LINE_START 0x490000 // A line +#define NV3_PGRAPH_CLASS09_LINE_END 0x491FFF +#define NV3_PGRAPH_CLASS0A_LIN_START 0x4A0000 // A lin - a line without its starting or ending pixels +#define NV3_PGRAPH_CLASS0A_LIN_END 0x4A1FFF +#define NV3_PGRAPH_CLASS0B_TRIANGLE_START 0x4B0000 // A triangle [NV1 variant] - in NV1 this was converted to a quad patch +#define NV3_PGRAPH_CLASS0B_TRIANGLE_END 0x4B1FFF +#define NV3_PGRAPH_CLASS0C_GDITEXT_START 0x4C0000 // Windows 95/NT GDI text acceleration +#define NV3_PGRAPH_CLASS0C_GDITEXT_END 0x4C1FFF + +#define NV3_PGRAPH_CLASS0D_MEM2MEM_XFER_START 0x4D0000 // memory to memory transfer (not sure about which class this is) +#define NV3_PGRAPH_CLASS0D_MEM2MEM_XFER_END 0x4D1FFF +#define NV3_PGRAPH_CLASS0E_IMAGE2MEM_XFER_SCALED_START 0x4E0000 // class 55, 56 +#define NV3_PGRAPH_CLASS0F_IMAGE2MEM_XFER_SCALED_END 0x4E1FFF + +#define NV3_PGRAPH_CLASS10_BLIT_START 0x500000 // Blit 2d image from memory +#define NV3_PGRAPH_CLASS10_BLIT_END 0x501FFF + +#define NV3_PGRAPH_CLASS11_CPU2MEM_IMAGE_START 0x510000 // Used for class 33, 34, 54 +#define NV3_PGRAPH_CLASS11_CPU2MEM_IMAGE_END 0x511FFF +#define NV3_PGRAPH_CLASS12_CPU2MEM_BITMAP_START 0x520000 // not sure, might depend on format +#define NV3_PGRAPH_CLASS12_CPU2MEM_BITMAP_END 0x521FFF + +#define NV3_PGRAPH_CLASS14_IMAGE2MEM_XFER_START 0x540000 // send image to vram, not sure what class +#define NV3_PGRAPH_CLASS14_IMAGE2MEM_XFER_END 0x541FFF +#define NV3_PGRAPH_CLASS15_CPU2MEM_STRETCHED_START 0x550000 // stretched cpu->vram transfer, 54 +#define NV3_PGRAPH_CLASS15_CPU2MEM_STRETCHED_END 0x551FFF + +#define NV3_PGRAPH_CLASS17_D3D5TRI_ZETA_START 0x570000 // [NV3] Copy a direct3d 5.0 accelerated triangle to the zeta buffer +#define NV3_PGRAPH_CLASS17_D3D5TRI_ZETA_END 0x571FFF +#define NV3_PGRAPH_CLASS18_POINTZETA_START 0x580000 // possibly class 69 +#define NV3_PGRAPH_CLASS18_POINTZETA_END 0x581FFF + +#define NV3_PGRAPH_CLASS1C_MEM2IMAGE_START 0x5C0000 // class 55, 56, 62, 63? +#define NV3_PGRAPH_CLASS1C_MEM2IMAGE_END 0x5C1FFF + + +#define NV3_PGRAPH_REGISTER_END 0x401FFF // end of pgraph registers +#define NV3_PGRAPH_REAL_END 0x5C1FFF + +// PRMCIO is redirected to SVGA subsystem +#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_FIFO_THRESHOLD 0x680238 +#define NV3_PVIDEO_FIFO_BURST_LENGTH 0x68023C +#define NV3_PVIDEO_OVERLAY 0x680244 +#define NV3_PVIDEO_OVERLAY_VIDEO_IS_ON 0 +#define NV3_PVIDEO_OVERLAY_KEY_ENABLED 4 +#define NV3_PVIDEO_OVERLAY_FORMAT 8 // 0 = CCIR, 1 = YUY2 + +#define NV3_PVIDEO_END 0x6802FF +#define NV3_PRAMDAC_START 0x680300 + +#define NV3_PRAMDAC_CURSOR_START 0x680300 + +#define NV3_PRAMDAC_CURSOR_SIZE_X 32 +#define NV3_PRAMDAC_CURSOR_SIZE_Y 32 + +#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 +#define NV3_PRAMDAC_GENERAL_CONTROL_565_MODE 12 + +// 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_DAC_START 0x681200 +#define NV3_USER_DAC_PALETTE_START 0x6813C6 +#define NV3_USER_DAC_PIXEL_MASK 0x6813C6 +#define NV3_USER_DAC_READ_MODE_ADDRESS 0x6813C7 //bit0=read/write mode? +#define NV3_USER_DAC_WRITE_MODE_ADDRESS 0x6813C8 +#define NV3_USER_DAC_PALETTE_DATA 0x6813C9 +#define NV3_USER_DAC_PALETTE_SIZE 768 +#define NV3_USER_DAC_PALETTE_END 0x6813C9 +#define NV3_USER_DAC_END 0x681FFF + +#define NV3_USER_START 0x800000 // Mapping for the area where objects are submitted into the FIFO (up to 0x880000?) +#define NV3_USER_END 0xFFFFFF + +// easier name +#define NV3_OBJECT_SUBMIT_START NV3_USER_START +#define NV3_OBJECT_SUBMIT_SUBCHANNEL 13 +#define NV3_OBJECT_SUBMIT_CHANNEL 16 +#define NV3_OBJECT_SUBMIT_END NV3_USER_END + +// also PDFB (Debug Framebuffer?) +#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_RAMIN_START 0x1C00000 + +#define NV3_RAMIN_RAMHT_START 0x1C00000 // Hashtable for storing submitted objects +#define NV3_RAMIN_RAMHT_END 0x1C00FFF +#define NV3_RAMIN_RAMHT_SIZE_0 0xFFF +#define NV3_RAMIN_RAMHT_SIZE_1 0x1FFF +#define NV3_RAMIN_RAMHT_SIZE_2 0x3FFF +#define NV3_RAMIN_RAMHT_SIZE_3 0x7FFF + +/* OBSOLETE AREA for AUDIO probably. DO NOT USE! */ +#define NV3_RAMIN_RAMAU_START 0x1C01000 +#define NV3_RAMIN_RAMAU_END 0x1C01BFF +#define NV3_RAMIN_RAMFC_START 0x1C01C00 // context for unused PFIFO DMA channels +#define NV3_RAMIN_RAMFC_END 0x1C01DFF +#define NV3_RAMIN_RAMFC_SIZE_0 0x1FF +#define NV3_RAMIN_RAMFC_SIZE_1 0xFFF +#define NV3_RAMIN_RAMRO_START 0x1C01E00 // Runout area for invalid submissions +#define NV3_RAMIN_RAMRO_SIZE_0 0x1FF +#define NV3_RAMIN_RAMRO_SIZE_1 0x1FFF +#define NV3_RAMIN_RAMRO_END 0x1C01FFF +#define NV3_RAMIN_RAMRM_START 0x1C02000 +#define NV3_RAMIN_RAMRM_END 0x1C02FFF + +// I'm not sure if this can be moved. +// 4K of "PRAM" is listed at 0x6000. +#define NV3_RAMIN_OFFSET_CURSOR 0x6000 + +#define NV3_RAMIN_END 0x1FFFFFF + +// not done + +// CRTC/CIO (0x3b0-0x3df) + +#define NV3_CRTC_REGISTER_INDEX_MONO 0x3B4 +#define NV3_CRTC_REGISTER_MONO 0x3B5 // Currently Selected CRTC Register - Monochrome + +#define NV3_CRTC_DATA_OUT 0x3C0 +#define NV3_CRTC_MISCOUT 0x3C2 + +#define NV3_RMA_REGISTER_START 0x3D0 +#define NV3_RMA_REGISTER_END 0x3D3 + +#define NV3_CRTC_REGISTER_INDEX 0x3D4 +#define NV3_CRTC_REGISTER_CURRENT 0x3D5 + +#define NV3_CRTC_REGISTER_WTF 0x3D8 + +// 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_START_DISABLED 5 +#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, licensed from weitek (25-63) +#define NV3_CRTC_REGISTER_RPC0 0x19 // 7:5 - [10:8] of CRTC. 4:0 - [20:16] of 21-bit display buffer address +#define NV3_CRTC_REGISTER_RPC1 0x1A // bit7=hsync enabled, bit6=vsync enabled, bit4="compatible text", bit2=large screen, bit1=6bit palette width (>1280) +#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_CURSOR_ADDR0 0x30 // Cursor high 21:16 +#define NV3_CRTC_REGISTER_CURSOR_ADDR1 0x31 // Cursor low (1:0 = enable) 15:11 + +#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_RL0 0x34 +#define NV3_CRTC_REGISTER_RL1 0x35 +#define NV3_CRTC_REGISTER_RMA 0x38 // REAL MODE ACCESS! +#define NV3_CRTC_REGISTER_I2C 0x3E +#define NV3_CRTC_REGISTER_I2C_GPIO 0x3F + +#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_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 + +/* + STRUCTURES FOR THE GPU START HERE + OBJECT CLASS & RENDERING RELATED STUFF IS IN VID_NV3_CLASSES.H +*/ + +//todo: pixel format + +// Master Control +typedef struct nv3_pmc_s +{ + /* + Holds chip manufacturing information at bootup. + Current specification (may change later): pre-packed for convenience + + Revision A: + 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# + Revision B/c: + write this later + */ + 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; + +// 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; + uint32_t debug_0; // debug stuff + uint32_t config_0; // Framebuffer width, etc. + uint32_t config_1; + uint32_t green; + uint32_t delay; + uint32_t rtl; // Part of the memory timings +} nv3_pfb_t; + +// +// DMA & Notifier Engine +// All singing all dancing all happy happy bullshit to send dma transfers literally anywhere in your computer +// + +// Not a notification status, because it's a 16-bit enum +// C23 fixes this +#define NV3_NOTIFICATION_STATUS_DONE_OK 0x0 +#define NV3_NOTIFICATION_STATUS_IN_PROGRESS 0xFF +#define NV3_NOTIFICATION_STATUS_ERROR 0x100 + +#define NV3_NOTIFICATION_INFO_ADJUST 0 // Wut +#define NV3_NOTIFICATION_PT_PRESENT 16 // Determines if the pagetable exists. +#define NV3_NOTIFICATION_TARGET 24 // Determines where this notification goes +#define NV3_DMA_TARGET_NODE_VRAM 0 // VRAM target for DMA +#define NV3_DMA_TARGET_NODE_CART 1 // "Cartridge" target for dma, only mentioned in a few places, !!! NV2 LEFTOVER !!! +#define NV3_DMA_TARGET_NODE_PCI 2 // Send the data to the host system over PCI +#define NV3_DMA_TARGET_NODE_AGP 3 // Send the data to the host system over AGP + +#define NV3_NOTIFICATION_PAGE_IS_PRESENT 0 // Determines if the page really exists +#define NV3_NOTIFICATION_PAGE_ACCESS 1 // Determines the page access type +#define NV3_NOTIFICATION_PAGE_ACCESS_READ 0x0 // If this is set, the page is read only +#define NV3_NOTIFICATION_PAGE_ACCESS_READ_WRITE 0x1 // If this is set, the page is read/write +#define NV3_NOTIFICATION_PAGE_FRAME_ADDRESS 12 // The pageframe to use + + + +// Core notification structure +typedef struct nv3_notification_s +{ + uint64_t nanoseconds; + uint32_t info32; + uint16_t info16; + uint16_t status; +} nv3_notification_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 debug_0; + uint32_t interrupt_status; // Interrupt status + uint32_t interrupt_enable; // Interrupt enable + nv3_pbus_rma_t rma; +} nv3_pbus_t; + +typedef struct nv3_pfifo_cache_s +{ + bool push0; // Can we even access this cache? + uint8_t put_address; // Trigger a DMA into the value you put here. + uint8_t get_address; // Trigger a DMA from the value you put here into where you were going. + uint8_t channel; // The DMA channel ID of this cache. + uint32_t status; + uint32_t pull0; + uint32_t context[NV3_DMA_SUBCHANNELS_PER_CHANNEL]; // Only one of these exists for cache0 + + /* cache1 only + do we even need to emulate this? + */ + uint32_t dma_status; // 0x3218 + bool dma_enabled; // 0x3220 bit0 + bool dma_is_busy; // 0x3220 bit4 + + uint32_t dma_state; // Corresponds to PFIFO_CACHE1_DMA0 + uint32_t dma_length; // Corresponds to PFIFO_CACHE1_DMA1 + uint32_t dma_address; // Corresponds to PFIFO_CACHE1_DMA2 + uint8_t dma_target_node; // Corresponds to PFIFO_CACHE1_DMA3 depends on card bus + uint8_t dma_tlb_tag; + uint8_t dma_tlb_pte; // DMA Engine - Translation Lookaside Buffer + uint8_t dma_tlb_pt_base; // DMA Engine - TLB Pagetable Base Addres + uint16_t method_address; // address of the method (i.e. what method it is) + uint16_t method_subchannel; // subchannel + bool context_is_dirty; + + /* TODO */ +} nv3_pfifo_cache_t; + +typedef struct nv3_pfifo_cache_entry_s +{ + uint16_t method; // method id depending on class (offset from entry channel start in ramin) + uint8_t subchannel; + uint32_t data; // is this the context + +} nv3_pfifo_cache_entry_t; + +// Command submission to PGRAPH +typedef struct nv3_pfifo_s +{ + uint32_t interrupt_status; // Interrupt status + uint32_t interrupt_enable; // Interrupt enable + uint32_t dma_delay_retry; // DMA Delay/Retry + uint32_t debug_0; // Cache Debug register + uint32_t config_0; + uint32_t ramht_config; // RAMHT config + uint32_t ramfc_config; // RAMFC config + uint32_t ramro_config; // RAMRO config + // Runout stuff + uint32_t runout_put; // 8:3 if RAMRO=512b, otherwise 12:3 + uint32_t runout_get; // 8:3 if RAMRO=512b, otherwise 12:3 + + // Cache stuff + uint32_t cache_reassignment; // Allow context switching + nv3_pfifo_cache_t cache0_settings; + nv3_pfifo_cache_t cache1_settings; + + nv3_pfifo_cache_entry_t cache0_entry; // It only has 1 entry + nv3_pfifo_cache_entry_t cache1_entries[NV3_PFIFO_CACHE1_SIZE_MAX]; // ONLY 32 USED ON REVISION A/B CARDS +} nv3_pfifo_t; + +// 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 + + uint8_t user_pixel_mask; // pixel mask for DAC lookup + uint32_t user_read_mode_address; // user read mode address + uint32_t user_write_mode_address; // user write mode address + uint8_t palette[NV3_USER_DAC_PALETTE_SIZE]; // Palette Info/CLUT - 256 entries, 1 byte for r,g,b = 768 bytes + + uint32_t cursor_address; // cursor address start + nv3_coord_16_t cursor_start; +} nv3_pramdac_t; + +/* Holds DMA channel context information */ +typedef struct NV3_PGRAPH_CTX_SWITCH_s +{ + /* TODO */ +} NV3_PGRAPH_CTX_SWITCH_t; + +typedef struct nv3_pgraph_context_control_s +{ + /* TODO */ +} nv3_pgraph_context_control_t; + +/* DMA object context info + Context uploaded from CACHE0/CACHE1 by DMA Puller +*/ +typedef struct nv3_pgraph_context_user_s +{ + union + { + uint32_t value; + + struct + { + bool reserved3 : 1; + uint8_t channel : 7; + uint8_t reserved2 : 3; + uint8_t class_id : 5; + uint8_t subchannel : 3; + uint16_t reserved : 13; + }; + }; +} nv3_pgraph_context_user_t; + +typedef struct nv3_pgraph_dma_settings_s +{ + /* TODO */ +} nv3_pgraph_dma_settings_t; + +typedef struct nv3_pgraph_clip_misc_settings_s +{ + /* TODO */ +} nv3_pgraph_clip_misc_settings_t; + +typedef struct nv3_pgraph_status_s +{ + bool overall_busy : 1; // Is anything busy? + uint8_t reserved : 3; + bool xy_logic_busy : 1; // Determines if the line drawing/xy/vector stuff is busy. + uint8_t reserved2 : 3; + bool port_notify_busy : 1; // Mediaport?/PIO? notifier engine busy + uint8_t reserved3 : 3; + bool port_register_busy : 1; + uint8_t reserved4 : 3; + bool port_dma_busy : 1; // Mediaport?/PIO? DMA engine busy + bool dma_engine_busy : 1; // DMA engine busy + uint8_t reserved5 : 2; + bool dma_notify_busy : 1; // Are the notifiers busy? + uint8_t reserved6 : 3; + bool engine_3d_busy : 1; // 3d engine busy? + bool engine_cache_busy : 1; // PFIFO CACHE0/CACHE1 busy? + bool engine_zfifo_busy : 1; // ZFIFO (zeta buffer? z buffer?) busy? + bool port_user_busy : 1; // User context switch? + uint8_t reserved7 : 3; + +} nv3_pgraph_status_t; + +/* All of this B* stuff is registers at 400630..40065c and 4006a8 in reality, easier to implement it like this + BPixel = Buffer Pixel Format +*/ +#define NV3_BPIXEL_FORMAT 0 +#define NV3_BPIXEL_FORMAT_IS_VALID 2 +#define NV3_BPIXEL_DEPTH 4 + +typedef enum nv3_pgraph_bpixel_format_e +{ + // Y16 + bpixel_fmt_y16 = 0, + // 8-bit colour + bpixel_fmt_8bit = 1, + // 16-bit colour + bpixel_fmt_16bit = 2, + // 32-bit colour (ARGB) + bpixel_fmt_32bit = 3, +} nv3_pgraph_bpixel_format; + +typedef enum nv3_pgraph_destination_buffer_e +{ + pgraph_dest_buffer0 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER0_ENABLED), + pgraph_dest_buffer1 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER1_ENABLED), + pgraph_dest_buffer2 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER2_ENABLED), + pgraph_dest_buffer3 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER3_ENABLED), +} nv3_pgraph_destination_buffer; + +// Graphics Subsystem +typedef struct nv3_pgraph_s +{ + uint32_t debug_0; + uint32_t debug_1; + uint32_t debug_2; + uint32_t debug_3; + 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 + uint32_t interrupt_status_dma; // Interrupt status for DMA + uint32_t interrupt_enable_dma; // Interrupt enable for DMA + + uint32_t context_switch; // TODO: Make this a struct, it's just going to be enormous lol. + nv3_pgraph_context_control_t context_control; + NV3_PGRAPH_CTX_SWITCH_t context_user_submit; + nv3_pgraph_context_user_t context_user; + uint32_t context_cache[NV3_PGRAPH_CONTEXT_CACHE_SIZE]; // DMA context cache (nv3_pgraph_context_user_t array?) + + // UCLIP stuff + uint32_t abs_uclip_xmin; + uint32_t abs_uclip_xmax; + uint32_t abs_uclip_ymin; + uint32_t abs_uclip_ymax; + // Canvas stuff + nv3_coord_16_bigy_t src_canvas_min; + nv3_coord_16_bigy_t src_canvas_max; + nv3_coord_16_bigy_t dst_canvas_min; + nv3_coord_16_bigy_t dst_canvas_max; + // Pattern stuff + nv3_color_expanded_t pattern_color_0_rgb; // ignore alpha + uint32_t pattern_color_0_alpha; // only 7:0 relevant + nv3_color_expanded_t pattern_color_1_rgb; // ignore alpha + uint32_t pattern_color_1_alpha; // only 7:0 relevant + uint64_t pattern_bitmap; // pattern bitmap for blit. it's alwaus 64 bits to simplify pixel rendering code + uint32_t pattern_shape; // may need to be an enum - 0=8x8, 1=64x1, 2=1x64 + uint32_t plane_mask; // only 7:0 relevant + uint32_t chroma_key; // color key + uint32_t beta_factor; + nv3_pgraph_dma_settings_t dma_settings; + uint8_t rop; // Current GDI Ternary Render Operation + // SURFACE STUFF - PGRAPH CAN OPERATE ON 4 SURFACES/BUFFERS AT A TIME + uint32_t boffset[NV3_PGRAPH_MAX_BUFFERS]; // 22-bit linear VRAM offset for the start of a buffer. + uint16_t bpitch[NV3_PGRAPH_MAX_BUFFERS]; // 12-bit linear VRAM offset for the pitch of a buffer + uint32_t bpixel[NV3_PGRAPH_MAX_BUFFERS]; // Pixel format for each possible surfaces. + // CLIP + nv3_pgraph_clip_misc_settings_t clip_misc_settings; + uint32_t notifier; + bool notify_pending; // Determines if a notification is pending. + /* Are these even used */ + nv3_coord_16_bigy_t clip0_min; + nv3_coord_16_bigy_t clip0_max; + nv3_coord_16_bigy_t clip1_min; + nv3_coord_16_bigy_t clip1_max; + /* idk */ + nv3_coord_16_t clip_start; // Start of the clipping region + nv3_coord_16_t clip_size; // Size of the clipping region. + bool fifo_access; // Determines if PGRAPH can access PFIFO. + nv3_pgraph_status_t status; // Current status of the 3D engine. + uint32_t trapped_address; + uint32_t trapped_data; + uint32_t instance; // no idea what this is but possibly an object context + uint32_t trapped_instance; + uint8_t dpram[NV3_PGRAPH_DPRAM_SIZE]; // Internal vertex/texturea cache. + + /* This area is used for holding universal representations of the U* registers, which are actually mapped into MMIO */ + struct nv3_object_class_001 beta_factor_class; + struct nv3_object_class_002 rop_class; + struct nv3_object_class_003 chroma_key_class; + struct nv3_object_class_004 plane_mask_class; + struct nv3_object_class_005 clipping_rectangle; + struct nv3_object_class_006 pattern; + struct nv3_object_class_007 rectangle; + struct nv3_object_class_008 point; + struct nv3_object_class_009 line; + struct nv3_object_class_00A lin; + struct nv3_object_class_00B triangle; + struct nv3_object_class_00C win95_gdi_text; + /* These are here so we can hold the current state of the image draw */ + uint32_t win95_gdi_text_bit_count; + nv3_coord_16_t win95_gdi_text_current_position; + struct nv3_object_class_00D m2mf; + struct nv3_object_class_00E scaled_image_from_memory; + struct nv3_object_class_010 blit; + struct nv3_object_class_011 image; + nv3_coord_16_t image_current_position; /* This is here so we can hold the current state of the image */ + struct nv3_object_class_012 bitmap; + struct nv3_object_class_014 transfer2memory; + struct nv3_object_class_015 stretched_image_from_cpu; + struct nv3_object_class_017 d3d5_tri; + struct nv3_object_class_018 point_zeta_buffer; + struct nv3_object_class_01C image_in_memory; +} 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; // PTIMER Interrupt status + uint32_t interrupt_enable; // PTIMER Interrupt enable + uint32_t clock_numerator; // PTIMER (tick?) numerator + uint32_t clock_denominator; // PTIMER (tick?) denominator + uint64_t time; // time + uint32_t alarm; // The value of time when there should be an alarm +} nv3_ptimer_t; + +// Object name is just a uint32_t identifier it doesn't need a struct +// This is how the context is represented in ramin +// IN PGRAPH IT IS DIFFERENT! ONLY 5 BITS FOR THE CLASS ID! WHY? +typedef struct nv3_ramin_context_s +{ + union + { + uint32_t context; + + struct + { + uint16_t ramin_offset; + uint8_t class_id : 7; + bool is_rendering : 1; + uint8_t channel : 7; + bool reserved : 1; + }; + }; +} nv3_ramin_context_t; + +// Graphics object hashtable for specific DMA [channel, subchannel] pair +typedef struct nv3_ramin_ramht_subchannel_s +{ + uint32_t name; // must be >4096 + + // Contextual information. + // See the above union. + nv3_ramin_context_t context; +} nv3_ramin_ramht_subchannel_t; + +// Graphics object hashtable +typedef struct nv3_ramin_ramht_s +{ + nv3_ramin_ramht_subchannel_t subchannels[NV3_DMA_CHANNELS][NV3_DMA_SUBCHANNELS_PER_CHANNEL]; +} nv3_ramin_ramht_t; + + +typedef enum nv3_ramin_ramro_reason_e +{ + nv3_runout_reason_illegal_access = 0, + + // PFIFO CACHE0/CACHE1 were turned off, so the graphics object could not be processed. + nv3_runout_reason_no_cache_available = 1, + + // Ran out of CACHE0 & CACHE1 space. + nv3_runout_reason_cache_ran_out = 2, + + nv3_runout_reason_free_count_overrun = 3, + + nv3_runout_reason_caught_lying = 4, + + // Access reserved by pagetable + nv3_runout_reason_reserved_access = 5, + +} nv3_ramin_ramro_reason; + +// context for unused channels +typedef struct nv3_ramin_ramfc_s +{ + +} nv3_ramin_ramfc_t; + +// RAM for AUDIO - RevisionA ONLY +typedef struct nv_ramin_ramau_s +{ + +} nv3_ramin_ramau_t; + +typedef struct nv3_ramin_s +{ + +} nv3_ramin_t; + + +typedef struct nv3_pvideo_s +{ + uint32_t interrupt_status; // Interrupt status + uint32_t interrupt_enable; // Interrupt enable + uint32_t fifo_threshold; // FIFO threshold + uint32_t fifo_burst_size; // FIFO burst size + uint32_t overlay_settings; // Overlay settings +} 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; // OEM Configuration + + // 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 submission + + 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_ramin_ramht_t ramht; // hashtable for PGRAPH objects + // (ramro does not need a struct) + nv3_ramin_ramfc_t ramfc; // context for unused channels + nv3_ramin_ramau_t ramau; // auxillary weirdnes + nv3_ramin_t pramin; // INstance memory for graphics 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 object +extern nv3_t* nv3; + +/* + *FUNCTIONS* for the GPU core start here + Functions for PGRAPH objects are in vid_nv3_classes.h +*/ + +// Device Core +void* nv3_init(const device_t *info); +void nv3_close(void* priv); +void nv3_speed_changed(void *priv); +void nv3_draw_cursor(svga_t* svga, int32_t drawline); +void nv3_recalc_timings(svga_t* svga); +void nv3_force_redraw(void* priv); + +/* BAR0 GPU MMIO read */ +void nv3_update_mappings(void); // Update memory 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 + +/* BAR1 Dumb Framebuffer Read */ +uint8_t nv3_dfb_read8(uint32_t addr, void* priv); // Write 8-bit DFB +uint16_t nv3_dfb_read16(uint32_t addr, void* priv); // Write 16-bit DFB +uint32_t nv3_dfb_read32(uint32_t addr, void* priv); // Write 32-bit DFB +void nv3_dfb_write8(uint32_t addr, uint8_t val, void* priv); // Write 8-bit DFB +void nv3_dfb_write16(uint32_t addr, uint16_t val, void* priv); // Write 16-bit DFB +void nv3_dfb_write32(uint32_t addr, uint32_t val, void* priv); // Write 32-bit DFB + +uint8_t nv3_svga_read(uint16_t addr, void* priv); // Read SVGA compatibility registers +void nv3_svga_write(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 + +bool nv3_ramin_arbitrate_read(uint32_t address, uint32_t* value); // Read arbitration so we can read/write to the structures in the first 64k of ramin +bool nv3_ramin_arbitrate_write(uint32_t address, uint32_t value); // Write arbitration so we can read/write to the structures in the first 64k of ramin + +// RAMIN functions +uint32_t nv3_ramht_hash(uint32_t name, uint32_t channel); +bool nv3_ramin_find_object(uint32_t name, uint32_t cache_num, uint8_t channel_id, uint8_t subchannel_id); +#ifndef RELEASE_BUILD +void nv3_debug_ramin_print_context_info(uint32_t name, nv3_ramin_context_t context); +#endif + +uint32_t nv3_ramfc_read(uint32_t address); +void nv3_ramfc_write(uint32_t address, uint32_t value); +uint32_t nv3_ramro_read(uint32_t address); +void nv3_ramro_write(uint32_t address, uint32_t value); +uint32_t nv3_ramht_read(uint32_t address); +void nv3_ramht_write(uint32_t address, uint32_t value); + +// 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_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) + +// Reads from vbios are 8bit +uint8_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); + +// 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_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 +// TODO: RAMHT, RAMFC...or maybe handle it inside of nv3_ramin_* + +// GPU subsystems + +// NV3 PMC +void nv3_pmc_init(void); +void nv3_pmc_clear_interrupts(void); +uint32_t nv3_pmc_handle_interrupts(bool send_now); + +// NV3 PGRAPH +void nv3_pgraph_init(void); +uint32_t nv3_pgraph_read(uint32_t address); +void nv3_pgraph_write(uint32_t address, uint32_t value); +void nv3_pgraph_vblank_start(svga_t* svga); +void nv3_pgraph_interrupt_valid(uint32_t num); +void nv3_pgraph_interrupt_invalid(uint32_t num); +void nv3_pgraph_submit(uint32_t param, uint16_t method, uint8_t channel, uint8_t subchannel, uint8_t class_id, nv3_ramin_context_t context); + +// PGRAPH class methods +// this should be in "vid_nv3_classes.h", but before that can happen, some things need to be rejigged +void nv3_generic_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_001_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_002_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_003_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_004_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_005_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_006_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_007_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_008_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_009_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_00a_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_00b_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_00d_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_00e_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_010_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_011_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_012_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_014_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_015_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_017_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_018_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); +void nv3_class_01c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj); + +// Notification Engine +void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t context,nv3_grobj_t grobj); + +// NV3 PFIFO +void nv3_pfifo_init(void); +uint32_t nv3_pfifo_read(uint32_t address); +void nv3_pfifo_write(uint32_t address, uint32_t value); +void nv3_pfifo_interrupt(uint32_t id, bool fire_now); + +// NV3 PFIFO - Caches +//cache0_push not a thing +void nv3_pfifo_cache0_pull(void); +void nv3_pfifo_cache1_push(uint32_t addr, uint32_t val); +void nv3_pfifo_cache1_pull(void); +uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val); +uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val); +uint32_t nv3_pfifo_cache1_num_free_spaces(void); + +// NV3 PFB +void nv3_pfb_init(void); + +// NV3 PEXTDEV/PSTRAPS +void nv3_pextdev_init(void); + +// NV3 PBUS +void nv3_pbus_init(void); + +// 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 (Final presentation) +void nv3_pramdac_init(void); +void nv3_pramdac_set_vram_clock(void); +void nv3_pramdac_set_pixel_clock(void); +void nv3_pramdac_pixel_clock_poll(double real_time); +void nv3_pramdac_memory_clock_poll(double real_time); + +// NV3 PTIMER +void nv3_ptimer_init(void); +void nv3_ptimer_tick(double real_time); + +// NV3 PVIDEO +void nv3_pvideo_init(void); + +// NV3 PME (Mediaport) +void nv3_pme_init(void); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv4.h b/src/include/86box/nv/vid_nv4.h new file mode 100644 index 000000000..0f2aad285 --- /dev/null +++ b/src/include/86box/nv/vid_nv4.h @@ -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. + * + * Riva TNT hardware defines + * + * Authors: Connor Hyde + * + * Copyright 2024-2025 Connor Hyde + */ + + +#pragma once + +#include +#include +#include <86Box/nv/vid_nv4_defines.h> + +// +// Structures +// + + +// PBUS +// RMA: Access the GPU from real-mode +typedef struct nv4_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[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 +typedef struct nv4_ptimer_s +{ + uint32_t interrupt_status; // PTIMER Interrupt status + uint32_t interrupt_enable; // PTIMER Interrupt enable + uint32_t clock_numerator; // PTIMER (tick?) numerator + uint32_t clock_denominator; // PTIMER (tick?) denominator + uint64_t time; // time + 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 clk_coeff_select; // Clock coefficient selection + uint32_t cursor_address; +} nv4_pramdac_t; + +// Device Core +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 +// + +extern const device_config_t nv4_config[]; + +extern nv4_t* nv4; // Allocated at device startup + +#ifdef NV_LOG + +// Debug register list +extern nv_register_t nv4_registers[]; + +#endif + +// +// Functions +// + +// Device Core +bool nv4_init(); + +void* nv4_init_stb4400(const device_t* info); + +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); + +// 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_pci_read(int32_t func, int32_t addr, void* priv); +void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv); + +// SVGA +uint8_t nv4_svga_read(uint16_t addr, void* priv); +void nv4_svga_write(uint16_t addr, uint8_t val, void* priv); + +// Memory +void nv4_update_mappings(); + +// PRAMDAC +uint32_t nv4_pramdac_read(uint32_t address); +void nv4_pramdac_write(uint32_t address, uint32_t data); + +// We don't implement NVCLK/VCLK because they are too fast +void nv4_pramdac_set_vclk(); + +void nv4_vclk_tick(); + +// PTIMER +uint32_t nv4_ptimer_read(uint32_t address); +void nv4_ptimer_write(uint32_t address, uint32_t data); \ 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 new file mode 100644 index 000000000..2a959670c --- /dev/null +++ b/src/include/86box/nv/vid_nv4_defines.h @@ -0,0 +1,4291 @@ +#pragma once + +#include +#include + +// +// 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_MMIO_SIZE 0x1000000 // not sure. May be larger!!!! + +// +// VBIOS +// +#define NV4_VBIOS_STB_REVA "roms/video/nvidia/nv4/NV4_STB_velocity.rom" + +#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 +#define NV4_PRMIO_RMA_PTR 0x7104 +#define NV4_PRMIO_RMA_PTR_ADDRESS 2 +#define NV4_PRMIO_RMA_DATA 0x7108 +#define NV4_PRMIO_RMA_DATA_PORT 0 +#define NV4_PRMIO_RMA_DATA32 0x710C +#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 + +#define NV4_PRAMDAC_CU_START_POS 0x680300 +#define NV4_PRAMDAC_CU_START_POS_X 0 +#define NV4_PRAMDAC_CU_START_POS_Y 16 +#define NV4_PRAMDAC_NVPLL_COEFF 0x680500 +#define NV4_PRAMDAC_NVPLL_COEFF_MDIV 0 +#define NV4_PRAMDAC_NVPLL_COEFF_NDIV 8 +#define NV4_PRAMDAC_NVPLL_COEFF_PDIV 16 // 18:16 +#define NV4_PRAMDAC_MPLL_COEFF 0x680504 +#define NV4_PRAMDAC_MPLL_COEFF_MDIV 0 +#define NV4_PRAMDAC_MPLL_COEFF_NDIV 8 +#define NV4_PRAMDAC_MPLL_COEFF_PDIV 16 // 18:16 +#define NV4_PRAMDAC_VPLL_COEFF 0x680508 +#define NV4_PRAMDAC_VPLL_COEFF_MDIV 0 +#define NV4_PRAMDAC_VPLL_COEFF_NDIV 8 +#define NV4_PRAMDAC_VPLL_COEFF_PDIV 16 // 18:16 +#define NV4_PRAMDAC_PLL_COEFF_SELECT 0x68050C +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE 0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_XTAL 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_VIP 0x1 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE 8 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE_DEFAULT 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_MPLL 0x1 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_VPLL 0x2 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_NVPLL 0x4 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_ALL 0x7 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VS_PCLK_TV 16 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VS_PCLK_TV_NONE 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VS_PCLK_TV_VSCLK 0x1 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VS_PCLK_TV_PCLK 0x2 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VS_PCLK_TV_BOTH 0x3 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_SOURCE 20 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_SOURCE_EXT 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_SOURCE_VIP 0x1 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_RATIO 24 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_RATIO_DB1 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_TVCLK_RATIO_DB2 0x1 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO 28 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB1 0x0 +#define NV4_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2 0x1 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL 0x680510 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_VALUE 0 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_VAL 0x44E +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN 12 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN_ON 0x0 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN_MPLL 0x1 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN_VPLL 0x2 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN_NVPLL 0x4 +#define NV4_PRAMDAC_PLL_SETUP_CONTROL_PWRDWN_OFF 0x7 +#define NV4_PRAMDAC_PLL_TEST_COUNTER 0x680514 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_NOOFIPCLKS 0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_VALUE 0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_ENABLE 16 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_ENABLE_DEASSERTED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_ENABLE_ASSERTED 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_RESET 20 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_RESET_DEASSERTED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_RESET_ASSERTED 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_SOURCE 24 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_SOURCE_MCLK 0x2 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_SOURCE_VCLK 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_SOURCE_NVCLK 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_PDIV_RST 28 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_PDIVRST_DEASSERTED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_PDIVRST_ASSERTED 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK 29 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_NVPLL_NOTLOCKED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCKED 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK 30 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_MPLL_NOTLOCKED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCKED 0x1 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK 31 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_VPLL_NOTLOCKED 0x0 +#define NV4_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCKED 0x1 +#define NV4_PRAMDAC_PALETTE_TEST 0x680518 +#define NV4_PRAMDAC_PALETTE_TEST_BLUE_DATA 0 +#define NV4_PRAMDAC_PALETTE_TEST_GREEN_DATA 8 +#define NV4_PRAMDAC_PALETTE_TEST_RED_DATA 16 +#define NV4_PRAMDAC_PALETTE_TEST_MODE 24 +#define NV4_PRAMDAC_PALETTE_TEST_MODE_8BIT 0x0 +#define NV4_PRAMDAC_PALETTE_TEST_MODE_24BIT 0x1 +#define NV4_PRAMDAC_PALETTE_TEST_ADDRINC 28 +#define NV4_PRAMDAC_PALETTE_TEST_ADDRINC_READWRITE 0x0 +#define NV4_PRAMDAC_PALETTE_TEST_ADDRINC_WRITEONLY 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL 0x680600 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX32_BIT 0 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX32_BIT_24 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX32_BIT_31 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX 4 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX_OFF 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX_POS 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX_NEG 0x2 +#define NV4_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON 0x3 +#define NV4_PRAMDAC_GENERAL_CONTROL_VGA_STATE 8 +#define NV4_PRAMDAC_GENERAL_CONTROL_VGA_STATE_NOTSEL 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE 12 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_NOTSEL 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_15 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_16 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_24 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_ALT_MODE_30 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL 16 +#define NV4_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_OFF 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_ON 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_TERMINATION 17 +#define NV4_PRAMDAC_GENERAL_CONTROL_TERMINATION_37OHM 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_BPC 20 +#define NV4_PRAMDAC_GENERAL_CONTROL_BPC_6BITS 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_BPC_8BITS 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP 24 +#define NV4_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_DIS 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_EN 0x1 +#define NV4_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK 28 +#define NV4_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_EN 0x0 +#define NV4_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_DIS 0x1 +#define NV4_PRAMDAC_PALETTE_RECOVERY 0x680604 +#define NV4_PRAMDAC_PALETTE_RECOVERY_ACTIVE_ADDRESS 0 +#define NV4_PRAMDAC_PALETTE_RECOVERY_RGB_POINTER 8 +#define NV4_PRAMDAC_PALETTE_RECOVERY_RGB_POINTER_RED 0x1 +#define NV4_PRAMDAC_PALETTE_RECOVERY_RGB_POINTER_GREEN 0x2 +#define NV4_PRAMDAC_PALETTE_RECOVERY_RGB_POINTER_BLUE 0x4 +#define NV4_PRAMDAC_PALETTE_RECOVERY_DAC_STATE 12 +#define NV4_PRAMDAC_PALETTE_RECOVERY_DAC_STATE_WRITE 0x0 +#define NV4_PRAMDAC_PALETTE_RECOVERY_DAC_STATE_READ 0x3 +#define NV4_PRAMDAC_PALETTE_RECOVERY_RED_DATA 16 +#define NV4_PRAMDAC_PALETTE_RECOVERY_GREEN_DATA 24 +#define NV4_PRAMDAC_TEST_CONTROL 0x680608 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_RESET 0 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_RESET_DEASSERTED 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_RESET_ASSERTED 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_ENABLE 4 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_ENABLE_DEASSERTED 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_ENABLE_ASSERTED 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_CHANNEL 8 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_CHANNEL_BLUE 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_CHANNEL_GREEN 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_CRC_CHANNEL_RED 0x2 +#define NV4_PRAMDAC_TEST_CONTROL_TP_INS_EN 12 +#define NV4_PRAMDAC_TEST_CONTROL_TP_INS_EN_DEASSERTED 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_PWRDWN_DAC 16 +#define NV4_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_ON 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_DACTM 20 +#define NV4_PRAMDAC_TEST_CONTROL_DACTM_NORMAL 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_DACTM_TEST 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH1 24 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH1_CLEAR 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH1_SET 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH31 25 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH31_CLEAR 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_TPATH31_SET 0x1 +#define NV4_PRAMDAC_TEST_CONTROL_SENSEB 28 +#define NV4_PRAMDAC_TEST_CONTROL_SENSEB_SOMELO 0x0 +#define NV4_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI 0x1 +#define NV4_PRAMDAC_CHECKSUM 0x68060C +#define NV4_PRAMDAC_CHECKSUM_VALUE 0 +#define NV4_PRAMDAC_TESTPOINT_DATA 0x680610 +#define NV4_PRAMDAC_TESTPOINT_DATA_RED 0 +#define NV4_PRAMDAC_TESTPOINT_DATA_GREEN 10 +#define NV4_PRAMDAC_TESTPOINT_DATA_BLUE 20 +#define NV4_PRAMDAC_TESTPOINT_DATA_BLACK 30 +#define NV4_PRAMDAC_TESTPOINT_DATA_NOTBLANK 31 +#define NV4_PRAMDAC_TV_SETUP 0x680700 +#define NV4_PRAMDAC_TV_SETUP_DEV_TYPE 0 +#define NV4_PRAMDAC_TV_SETUP_DEV_TYPE_SLAVE 0x0 +#define NV4_PRAMDAC_TV_SETUP_DEV_TYPE_MASTER 0x1 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT 4 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT_555 0x0 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT_565 0x1 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT_888 0x2 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT_101010 0x3 +#define NV4_PRAMDAC_TV_SETUP_VS_PIXFMT_YUV 0x4 +#define NV4_PRAMDAC_TV_SETUP_DATA_SRC 8 +#define NV4_PRAMDAC_TV_SETUP_DATA_SRC_COMP 0x0 +#define NV4_PRAMDAC_TV_SETUP_DATA_SRC_SCALER 0x1 +#define NV4_PRAMDAC_TV_SETUP_DATA_SRC_VIP 0x2 +#define NV4_PRAMDAC_TV_SETUP_COMP_SRC 12 +#define NV4_PRAMDAC_TV_SETUP_COMP_SRC_SCALER 0x0 +#define NV4_PRAMDAC_TV_SETUP_COMP_SRC_NO_SCALER 0x1 +#define NV4_PRAMDAC_TV_SETUP_SYNC_POL 16 +#define NV4_PRAMDAC_TV_SETUP_SYNC_POL_NEG_NONE 0x0 +#define NV4_PRAMDAC_TV_SETUP_SYNC_POL_NEG_HSYNC 0x1 +#define NV4_PRAMDAC_TV_SETUP_SYNC_POL_NEG_VSYNC 0x2 +#define NV4_PRAMDAC_TV_SETUP_SYNC_POL_NEG_BOTH 0x3 +#define NV4_PRAMDAC_TV_SETUP_VIP_VSYNC 20 +#define NV4_PRAMDAC_TV_SETUP_VIP_VSYNC_LEAD 0x0 +#define NV4_PRAMDAC_TV_SETUP_VIP_VSYNC_TRAIL 0x1 +#define NV4_PRAMDAC_TV_SETUP_VIP_DATAPOS 24 +#define NV4_PRAMDAC_TV_SETUP_VIP_DATAPOS_7_0 0x0 +#define NV4_PRAMDAC_TV_SETUP_VIP_DATAPOS_11_4 0x1 +#define NV4_PRAMDAC_TV_SETUP_VIP_FIELD 28 +#define NV4_PRAMDAC_TV_SETUP_VIP_FIELD_0 0x0 +#define NV4_PRAMDAC_TV_SETUP_VIP_FIELD_1 0x1 +#define NV4_PRAMDAC_TV_VBLANK_START 0x680704 +#define NV4_PRAMDAC_TV_VBLANK_START_VAL 0 +#define NV4_PRAMDAC_TV_VBLANK_END 0x680708 +#define NV4_PRAMDAC_TV_VBLANK_END_VAL 0 +#define NV4_PRAMDAC_TV_HBLANK_START 0x68070C +#define NV4_PRAMDAC_TV_HBLANK_START_VAL 0 +#define NV4_PRAMDAC_TV_HBLANK_END 0x680710 +#define NV4_PRAMDAC_TV_HBLANK_END_VAL 0 +#define NV4_PRAMDAC_BLANK_COLOR 0x680714 +#define NV4_PRAMDAC_BLANK_COLOR_VAL 0 +#define NV4_PRAMDAC_TV_CHECKSUM 0x680718 +#define NV4_PRAMDAC_TV_CHECKSUM_VAL 0 +#define NV4_PRAMDAC_TV_VSYNC 28 +#define NV4_PRAMDAC_TV_VSYNC_ACTIVE 0x0 +#define NV4_PRAMDAC_TV_VSYNC_INACTIVE 0x1 +#define NV4_PRAMDAC_TV_TEST_CONTROL 0x68071c +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_RESET 0 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_RESET_DEASSERTED 0x0 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_RESET_ASSERTED 0x1 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_ENABLE 4 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_ENABLE_DEASSERTED 0x0 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_ENABLE_ASSERTED 0x1 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_CHANNEL 8 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_CHANNEL_7_0 0x0 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_CHANNEL_15_8 0x1 +#define NV4_PRAMDAC_TV_TEST_CONTROL_CRC_CHANNEL_23_16 0x2 + +#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 +#define NV4_USER_DAC_PIXEL_MASK_MASK 0xFF +#define NV4_USER_DAC_READ_MODE_ADDRESS 0x6813C7 +#define NV4_USER_DAC_READ_MODE_ADDRESS_VALUE 0 +#define NV4_USER_DAC_READ_MODE_ADDRESS_WO_VALUE 0 +#define NV4_USER_DAC_READ_MODE_ADDRESS_RW_STATE 0 +#define NV4_USER_DAC_READ_MODE_ADDRESS_RW_STATE_WRITE 0x0 +#define NV4_USER_DAC_READ_MODE_ADDRESS_RW_STATE_READ 0x3 +#define NV4_USER_DAC_WRITE_MODE_ADDRESS 0x6813C8 +#define NV4_USER_DAC_WRITE_MODE_ADDRESS_VALUE 0 +#define NV4_USER_DAC_PALETTE_DATA 0x6813C9 +#define NV4_USER_DAC_PALETTE_DATA_VALUE 0 + +#define NV4_PRMDIO_START 0x681000 +#define NV4_PRMDIO_END 0x681FFF + +#define NV4_IO_MPU_401_DATA 0x330 +#define NV4_IO_MPU_401_DATA_ALIAS_1 0x300 +#define NV4_IO_MPU_401_DATA_ALIAS_2 0x230 +#define NV4_IO_MPU_401_DATA_VALUE 0 +#define NV4_IO_MPU_401_DATA_ACK 0xFE +#define NV4_IO_MPU_401_STATUS 0x331 +#define NV4_IO_MPU_401_STATUS_ALIAS_1 0x301 +#define NV4_IO_MPU_401_STATUS_ALIAS_2 0x231 +#define NV4_IO_MPU_401_STATUS_DATA 0 +#define NV4_IO_MPU_401_STATUS_WRITE 6 +#define NV4_IO_MPU_401_STATUS_WRITE_EMPTY 0x0 +#define NV4_IO_MPU_401_STATUS_WRITE_FULL 0x1 +#define NV4_IO_MPU_401_STATUS_READ 7 +#define NV4_IO_MPU_401_STATUS_READ_FULL 0x0 +#define NV4_IO_MPU_401_STATUS_READ_EMPTY 0x1 +#define NV4_IO_MPU_401_COM 0x331 +#define NV4_IO_MPU_401_COM_ALIAS_1 0x301 +#define NV4_IO_MPU_401_COM_ALIAS_2 0x231 +#define NV4_IO_MPU_401_COM_UART_MODE 0 +#define NV4_IO_MPU_401_COM_UART_MODE_COMPLEX 0xff +#define NV4_IO_MPU_401_COM_UART_MODE_SIMPLE 0x3f + +#define NV4_PMC_START 0x0 +#define NV4_PMC_END 0xFFF + +#define NV4_PMC_BOOT_0 0x0 +#define NV4_PMC_BOOT_0_MINOR_REVISION 0 +#define NV4_PMC_BOOT_0_MINOR_REVISION_0 0x0 +#define NV4_PMC_BOOT_0_MAJOR_REVISION 4 +#define NV4_PMC_BOOT_0_MAJOR_REVISION_A 0x0 +#define NV4_PMC_BOOT_0_MAJOR_REVISION_B 0x1 +#define NV4_PMC_BOOT_0_IMPLEMENTATION 8 +#define NV4_PMC_BOOT_0_IMPLEMENTATION_NV4_0 0x0 +#define NV4_PMC_BOOT_0_ARCHITECTURE 12 +#define NV4_PMC_BOOT_0_ARCHITECTURE_NV0 0x0 +#define NV4_PMC_BOOT_0_ARCHITECTURE_NV1 0x1 +#define NV4_PMC_BOOT_0_ARCHITECTURE_NV2 0x2 +#define NV4_PMC_BOOT_0_ARCHITECTURE_NV3 0x3 +#define NV4_PMC_BOOT_0_ARCHITECTURE_NV4 0x4 +#define NV4_PMC_BOOT_0_FIB_REVISION 16 +#define NV4_PMC_BOOT_0_FIB_REVISION_0 0x0 +#define NV4_PMC_BOOT_0_MASK_REVISION 20 +#define NV4_PMC_BOOT_0_MASK_REVISION_A 0x0 +#define NV4_PMC_BOOT_0_MASK_REVISION_B 0x1 +#define NV4_PMC_BOOT_0_MASK_REVISION_C 0x2 +#define NV4_PMC_BOOT_0_MANUFACTURER 24 +#define NV4_PMC_BOOT_0_MANUFACTURER_NVIDIA 0x0 +#define NV4_PMC_BOOT_0_FOUNDRY 28 +#define NV4_PMC_BOOT_0_FOUNDRY_SGS 0x0 +#define NV4_PMC_BOOT_0_FOUNDRY_HELIOS 0x1 +#define NV4_PMC_BOOT_0_FOUNDRY_TSMC 0x2 +#define NV4_PMC_INTR_0 0x100 +#define NV4_PMC_INTR_0_PMEDIA 4 +#define NV4_PMC_INTR_0_PMEDIA_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PMEDIA_PENDING 0x1 +#define NV4_PMC_INTR_0_PFIFO 8 +#define NV4_PMC_INTR_0_PFIFO_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PFIFO_PENDING 0x1 +#define NV4_PMC_INTR_0_PGRAPH 12 +#define NV4_PMC_INTR_0_PGRAPH_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PGRAPH_PENDING 0x1 +#define NV4_PMC_INTR_0_PVIDEO 16 +#define NV4_PMC_INTR_0_PVIDEO_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PVIDEO_PENDING 0x1 +#define NV4_PMC_INTR_0_PTIMER 20 +#define NV4_PMC_INTR_0_PTIMER_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PTIMER_PENDING 0x1 +#define NV4_PMC_INTR_0_PCRTC 24 +#define NV4_PMC_INTR_0_PCRTC_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PCRTC_PENDING 0x1 +#define NV4_PMC_INTR_0_PBUS 28 +#define NV4_PMC_INTR_0_PBUS_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_PBUS_PENDING 0x1 +#define NV4_PMC_INTR_0_SOFTWARE 31 +#define NV4_PMC_INTR_0_SOFTWARE_NOT_PENDING 0x0 +#define NV4_PMC_INTR_0_SOFTWARE_PENDING 0x1 +#define NV4_PMC_INTR_EN_0 0x140 +#define NV4_PMC_INTR_EN_0_INTA 0 +#define NV4_PMC_INTR_EN_0_INTA_DISABLED 0x0 +#define NV4_PMC_INTR_EN_0_INTA_HARDWARE 0x1 +#define NV4_PMC_INTR_EN_0_INTA_SOFTWARE 0x2 +#define NV4_PMC_INTR_READ_0 0x160 +#define NV4_PMC_INTR_READ_0_INTA 0 +#define NV4_PMC_INTR_READ_0_INTA_LOW 0x0 +#define NV4_PMC_INTR_READ_0_INTA_HIGH 0x1 +#define NV4_PMC_ENABLE 0x200 +#define NV4_PMC_ENABLE_PMEDIA 4 +#define NV4_PMC_ENABLE_PMEDIA_ENABLED 0x1 +#define NV4_PMC_ENABLE_PFIFO 8 +#define NV4_PMC_ENABLE_PFIFO_ENABLED 0x1 +#define NV4_PMC_ENABLE_PGRAPH 12 +#define NV4_PMC_ENABLE_PGRAPH_ENABLED 0x1 +#define NV4_PMC_ENABLE_PPMI 16 +#define NV4_PMC_ENABLE_PPMI_ENABLED 0x1 +#define NV4_PMC_ENABLE_PFB 20 +#define NV4_PMC_ENABLE_PFB_ENABLED 0x1 +#define NV4_PMC_ENABLE_PCRTC 24 +#define NV4_PMC_ENABLE_PCRTC_ENABLED 0x1 +#define NV4_PMC_ENABLE_PVIDEO 28 +#define NV4_PMC_ENABLE_PVIDEO_ENABLED 0x1 + +#define NV4_PBUS_START 0x1000 +#define NV4_PBUS_END 0x1FFF + +#define NV4_PBUS_DEBUG_0 0x1080 +#define NV4_PBUS_DEBUG_0_FBIO_SCLK_DELAY 0 +#define NV4_PBUS_DEBUG_0_FBIO_SCLK_DELAY_8 0x8 +#define NV4_PBUS_DEBUG_0_FBIO_SCLK_PC 4 +#define NV4_PBUS_DEBUG_0_FBIO_SCLK_PC_NORMAL 0x0 +#define NV4_PBUS_DEBUG_0_FBIO_SCLK_PC_OVERRIDE 0x1 +#define NV4_PBUS_DEBUG_0_FBIO_FBCLK_DELAY 8 +#define NV4_PBUS_DEBUG_0_FBIO_FBCLK_DELAY_8 0x8 +#define NV4_PBUS_DEBUG_0_FBIO_FBCLK_PC 12 +#define NV4_PBUS_DEBUG_0_FBIO_FBCLK_PC_NORMAL 0x0 +#define NV4_PBUS_DEBUG_0_FBIO_FBCLK_PC_OVERRIDE 0x1 +#define NV4_PBUS_DEBUG_0_FBIO_ACLK_DELAY 16 +#define NV4_PBUS_DEBUG_0_FBIO_ACLK_DELAY_8 0x8 +#define NV4_PBUS_DEBUG_0_FBIO_ACLK_PC 20 +#define NV4_PBUS_DEBUG_0_FBIO_ACLK_PC_NORMAL 0x0 +#define NV4_PBUS_DEBUG_0_FBIO_ACLK_PC_OVERRIDE 0x1 +#define NV4_PBUS_DEBUG_0_FBIO_RCLK_DELAY 24 +#define NV4_PBUS_DEBUG_0_FBIO_RCLK_DELAY_8 0x8 +#define NV4_PBUS_DEBUG_0_FBIO_RCLK_PC 28 +#define NV4_PBUS_DEBUG_0_FBIO_RCLK_PC_NORMAL 0x0 +#define NV4_PBUS_DEBUG_0_FBIO_RCLK_PC_OVERRIDE 0x1 +#define NV4_PBUS_DEBUG_1 0x1084 +#define NV4_PBUS_DEBUG_1_PCIM_THROTTLE 0 +#define NV4_PBUS_DEBUG_1_PCIM_THROTTLE_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIM_CMD 1 +#define NV4_PBUS_DEBUG_1_PCIM_CMD_SIZE_BASED 0x0 +#define NV4_PBUS_DEBUG_1_PCIM_CMD_MRL_ONLY 0x1 +#define NV4_PBUS_DEBUG_1_HASH_DECODE 2 +#define NV4_PBUS_DEBUG_1_HASH_DECODE_1FF 0x0 +#define NV4_PBUS_DEBUG_1_HASH_DECODE_2FF 0x1 +#define NV4_PBUS_DEBUG_1_AGPM_CMD 3 +#define NV4_PBUS_DEBUG_1_AGPM_CMD_HP_ON_1ST 0x0 +#define NV4_PBUS_DEBUG_1_AGPM_CMD_LP_ONLY 0x1 +#define NV4_PBUS_DEBUG_1_AGPM_CMD_HP_ONLY 0x2 +#define NV4_PBUS_DEBUG_1_PCIS_WRITE 5 +#define NV4_PBUS_DEBUG_1_PCIS_WRITE_0_CYCLE 0x0 +#define NV4_PBUS_DEBUG_1_PCIS_WRITE_1_CYCLE 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_2_1 6 +#define NV4_PBUS_DEBUG_1_PCIS_2_1_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_RETRY 7 +#define NV4_PBUS_DEBUG_1_PCIS_RETRY_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_RD_BURST 8 +#define NV4_PBUS_DEBUG_1_PCIS_RD_BURST_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_WR_BURST 9 +#define NV4_PBUS_DEBUG_1_PCIS_WR_BURST_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_EARLY_RTY 10 +#define NV4_PBUS_DEBUG_1_PCIS_EARLY_RTY_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_PCIS_CPUQ 12 +#define NV4_PBUS_DEBUG_1_PCIS_CPUQ_ENABLED 0x1 +#define NV4_PBUS_DEBUG_1_DPSH_DECODE 13 +#define NV4_PBUS_DEBUG_1_DPSH_DECODE_NV4 0x0 +#define NV4_PBUS_DEBUG_1_DPSH_DECODE_NV3 0x1 +#define NV4_PBUS_DEBUG_1_SPARE1 14 +#define NV4_PBUS_DEBUG_1_SPARE2 15 +#define NV4_PBUS_DEBUG_1_SPARE3 16 +#define NV4_PBUS_DEBUG_1_SPARE4 17 +#define NV4_PBUS_DEBUG_1_SPARE5 18 +#define NV4_PBUS_DEBUG_1_SPARE6 19 +#define NV4_PBUS_DEBUG_1_SPARE7 20 +#define NV4_PBUS_DEBUG_1_SPARE8 21 +#define NV4_PBUS_DEBUG_1_SPARE9 22 +#define NV4_PBUS_DEBUG_1_SPARE10 23 +#define NV4_PBUS_DEBUG_2 0x1088 +#define NV4_PBUS_DEBUG_2_AGP_DIFFERENTIAL 0 +#define NV4_PBUS_DEBUG_2_AGP_DIFFERENTIAL_ENABLED 0x1 +#define NV4_PBUS_DEBUG_2_AGP_SB_STB_DELAY 9:4 +#define NV4_PBUS_DEBUG_2_AGP_SB_STB_DELAY_34 0x22 +#define NV4_PBUS_DEBUG_2_AGP_SB_STB_PC 12 +#define NV4_PBUS_DEBUG_2_AGP_SB_STB_PC_NORMAL 0x0 +#define NV4_PBUS_DEBUG_2_AGP_SB_STB_PC_OVERRIDE 0x1 +#define NV4_PBUS_DEBUG_3 0x108C +#define NV4_PBUS_DEBUG_3_AGP_MAX_SIZE 0 +#define NV4_PBUS_DEBUG_3_AGP_MAX_SIZE_UNLIMITED 0x0 +#define NV4_PBUS_DEBUG_3_AGP_MAX_SIZE_32_BYTES 0x1 +#define NV4_PBUS_DEBUG_3_AGP_MAX_SIZE_64_BYTES 0x2 +#define NV4_PBUS_DEBUG_CTL 0x1090 +#define NV4_PBUS_DEBUG_CTL_MODE 0 +#define NV4_PBUS_DEBUG_CTL_MODE_ENABLED 0x1 +#define NV4_PBUS_DEBUG_CTL_READ_SELECT 4 +#define NV4_PBUS_DEBUG_CTL_READ_SELECT_0 0x0 +#define NV4_PBUS_DEBUG_CTL_READ_SELECT_1 0x1 +#define NV4_PBUS_DEBUG_READ 0x1094 +#define NV4_PBUS_DEBUG_READ_DATA 0 +#define NV4_PBUS_DEBUG_HOST 0x109C +#define NV4_PBUS_DEBUG_HOST_SEL 0 +#define NV4_PBUS_DEBUG_SEL_0 0x10A0 +#define NV4_PBUS_DEBUG_SEL_0_X 0 +#define NV4_PBUS_DEBUG_SEL_1 0x10A4 +#define NV4_PBUS_DEBUG_SEL_1_X 0 +#define NV4_PBUS_DEBUG_SEL_2 0x10A8 +#define NV4_PBUS_DEBUG_SEL_2_X 0 +#define NV4_PBUS_DEBUG_SEL_3 0x10AC +#define NV4_PBUS_DEBUG_SEL_3_X 0 +#define NV4_PBUS_INTR_0 0x1100 +#define NV4_PBUS_INTR_0_PCI_BUS_ERROR 0 +#define NV4_PBUS_INTR_0_PCI_BUS_ERROR_NOT_PENDING 0x0 +#define NV4_PBUS_INTR_0_PCI_BUS_ERROR_PENDING 0x1 +#define NV4_PBUS_INTR_0_PCI_BUS_ERROR_RESET 0x1 +#define NV4_PBUS_INTR_EN_0 0x1140 +#define NV4_PBUS_INTR_EN_0_PCI_BUS_ERROR 0 +#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 + +// 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_H 0x1805 +#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 0x1815 +#define NV4_PBUS_PCI_BAR1_UNUSED2 0x1816 +#define NV4_PBUS_PCI_BAR1_BASE_31_TO_24 0x1817 // Must align to 16MByte +#define NV4_PBUS_PCI_BAR_RESERVED_START 0x1818 +#define NV4_PBUS_PCI_BAR_RESERVED_END 0x182B + +//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 +#define NV4_PFIFO_DMA_TIMESLICE 0x2044 +#define NV4_PFIFO_DMA_TIMESLICE_SELECT 0 +#define NV4_PFIFO_DMA_TIMESLICE_SELECT_1 0x0 +#define NV4_PFIFO_DMA_TIMESLICE_SELECT_16K 0x3fff +#define NV4_PFIFO_DMA_TIMESLICE_SELECT_32K 0x7fff +#define NV4_PFIFO_DMA_TIMESLICE_SELECT_64K 0xffff +#define NV4_PFIFO_DMA_TIMESLICE_SELECT_128K 0x1ffff +#define NV4_PFIFO_DMA_TIMESLICE_TIMEOUT 24 +#define NV4_PFIFO_DMA_TIMESLICE_TIMEOUT_ENABLED 0x1 +#define NV4_PFIFO_PIO_TIMESLICE 0x2048 +#define NV4_PFIFO_PIO_TIMESLICE_SELECT 0 +#define NV4_PFIFO_PIO_TIMESLICE_SELECT_1 0x0 +#define NV4_PFIFO_PIO_TIMESLICE_SELECT_16K 0x3fff +#define NV4_PFIFO_PIO_TIMESLICE_SELECT_32K 0x7fff +#define NV4_PFIFO_PIO_TIMESLICE_SELECT_64K 0xffff +#define NV4_PFIFO_PIO_TIMESLICE_SELECT_128K 0x1ffff +#define NV4_PFIFO_PIO_TIMESLICE_TIMEOUT 24 +#define NV4_PFIFO_PIO_TIMESLICE_TIMEOUT_ENABLED 0x1 +#define NV4_PFIFO_TIMESLICE 0x204C +#define NV4_PFIFO_TIMESLICE_TIMER 0 +#define NV4_PFIFO_TIMESLICE_TIMER_EXPIRED 0x3FFFF +#define NV4_PFIFO_NEXT_CHANNEL 0x2050 +#define NV4_PFIFO_NEXT_CHANNEL_CHID 0 +#define NV4_PFIFO_NEXT_CHANNEL_MODE 8 +#define NV4_PFIFO_NEXT_CHANNEL_MODE_PIO 0x0 +#define NV4_PFIFO_NEXT_CHANNEL_MODE_DMA 0x1 +#define NV4_PFIFO_NEXT_CHANNEL_SWITCH 12 +#define NV4_PFIFO_NEXT_CHANNEL_SWITCH_NOT_PENDING 0x0 +#define NV4_PFIFO_NEXT_CHANNEL_SWITCH_PENDING 0x1 +#define NV4_PFIFO_DEBUG_0 0x2080 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR0 0 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR0_NOT_PENDING 0x0 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR0_PENDING 0x1 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR1 4 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR1_NOT_PENDING 0x0 +#define NV4_PFIFO_DEBUG_0_CACHE_ERROR1_PENDING 0x1 +#define NV4_PFIFO_INTR_0 0x2100 +#define NV4_PFIFO_INTR_0_CACHE_ERROR 0 +#define NV4_PFIFO_INTR_0_CACHE_ERROR_NOT_PENDING 0x0 +#define NV4_PFIFO_INTR_0_CACHE_ERROR_PENDING 0x1 +#define NV4_PFIFO_INTR_0_CACHE_ERROR_RESET 0x1 +#define NV4_PFIFO_INTR_0_RUNOUT 4 +#define NV4_PFIFO_INTR_0_RUNOUT_NOT_PENDING 0x0 +#define NV4_PFIFO_INTR_0_RUNOUT_PENDING 0x1 +#define NV4_PFIFO_INTR_0_RUNOUT_RESET 0x1 +#define NV4_PFIFO_INTR_0_RUNOUT_OVERFLOW 8 +#define NV4_PFIFO_INTR_0_RUNOUT_OVERFLOW_NOT_PENDING 0x0 +#define NV4_PFIFO_INTR_0_RUNOUT_OVERFLOW_PENDING 0x1 +#define NV4_PFIFO_INTR_0_RUNOUT_OVERFLOW_RESET 0x1 +#define NV4_PFIFO_INTR_0_DMA_PUSHER 12 +#define NV4_PFIFO_INTR_0_DMA_PUSHER_NOT_PENDING 0x0 +#define NV4_PFIFO_INTR_0_DMA_PUSHER_PENDING 0x1 +#define NV4_PFIFO_INTR_0_DMA_PUSHER_RESET 0x1 +#define NV4_PFIFO_INTR_0_DMA_PT 16 +#define NV4_PFIFO_INTR_0_DMA_PT_NOT_PENDING 0x0 +#define NV4_PFIFO_INTR_0_DMA_PT_PENDING 0x1 +#define NV4_PFIFO_INTR_0_DMA_PT_RESET 0x1 +#define NV4_PFIFO_INTR_EN_0 0x2140 +#define NV4_PFIFO_INTR_EN_0_CACHE_ERROR 0 +#define NV4_PFIFO_INTR_EN_0_CACHE_ERROR_ENABLED 0x1 +#define NV4_PFIFO_INTR_EN_0_RUNOUT 4 +#define NV4_PFIFO_INTR_EN_0_RUNOUT_ENABLED 0x1 +#define NV4_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW 8 +#define NV4_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_ENABLED 0x1 +#define NV4_PFIFO_INTR_EN_0_DMA_PUSHER 12 +#define NV4_PFIFO_INTR_EN_0_DMA_PUSHER_ENABLED 0x1 +#define NV4_PFIFO_INTR_EN_0_DMA_PT 16 +#define NV4_PFIFO_INTR_EN_0_DMA_PT_ENABLED 0x1 +#define NV4_PFIFO_RAMHT 0x2210 +#define NV4_PFIFO_RAMHT_BASE_ADDRESS 4 +#define NV4_PFIFO_RAMHT_BASE_ADDRESS_10000 0x10 +#define NV4_PFIFO_RAMHT_SIZE 16 +#define NV4_PFIFO_RAMHT_SIZE_4K 0x0 +#define NV4_PFIFO_RAMHT_SIZE_8K 0x1 +#define NV4_PFIFO_RAMHT_SIZE_16K 0x2 +#define NV4_PFIFO_RAMHT_SIZE_32K 0x3 +#define NV4_PFIFO_RAMHT_SEARCH 24 +#define NV4_PFIFO_RAMHT_SEARCH_16 0x0 +#define NV4_PFIFO_RAMHT_SEARCH_32 0x1 +#define NV4_PFIFO_RAMHT_SEARCH_64 0x2 +#define NV4_PFIFO_RAMHT_SEARCH_128 0x3 +#define NV4_PFIFO_RAMFC 0x2214 +#define NV4_PFIFO_RAMFC_BASE_ADDRESS 1 +#define NV4_PFIFO_RAMFC_BASE_ADDRESS_11000 0x88 +#define NV4_PFIFO_RAMRO 0x2218 +#define NV4_PFIFO_RAMRO_BASE_ADDRESS 1 +#define NV4_PFIFO_RAMRO_BASE_ADDRESS_11200 0x89 +#define NV4_PFIFO_RAMRO_BASE_ADDRESS_12000 0x90 +#define NV4_PFIFO_RAMRO_SIZE 16 +#define NV4_PFIFO_RAMRO_SIZE_512 0x0 +#define NV4_PFIFO_RAMRO_SIZE_8K 0x1 +#define NV4_PFIFO_CACHES 0x2500 +#define NV4_PFIFO_CACHES_REASSIGN 0 +#define NV4_PFIFO_CACHES_REASSIGN_ENABLED 0x1 +#define NV4_PFIFO_CACHES_DMA_SUSPEND 4 +#define NV4_PFIFO_CACHES_DMA_SUSPEND_IDLE 0x0 +#define NV4_PFIFO_CACHES_DMA_SUSPEND_BUSY 0x1 +#define NV4_PFIFO_MODE 0x2504 +// Valid for all 16 channels. Do we need thees at all? +#define NV4_PFIFO_MODE_CHANNEL_IS_PIO 0x0 +#define NV4_PFIFO_MODE_CHANNEL_IS_DMA 0x1 +#define NV4_PFIFO_MODE_CHANNEL_0 0 +#define NV4_PFIFO_MODE_CHANNEL_1 1 +#define NV4_PFIFO_MODE_CHANNEL_2 2 +#define NV4_PFIFO_MODE_CHANNEL_3 3 +#define NV4_PFIFO_MODE_CHANNEL_4 4 +#define NV4_PFIFO_MODE_CHANNEL_5 5 +#define NV4_PFIFO_MODE_CHANNEL_6 6 +#define NV4_PFIFO_MODE_CHANNEL_7 7 +#define NV4_PFIFO_MODE_CHANNEL_8 8 +#define NV4_PFIFO_MODE_CHANNEL_9 9 +#define NV4_PFIFO_MODE_CHANNEL_10 10 +#define NV4_PFIFO_MODE_CHANNEL_11 11 +#define NV4_PFIFO_MODE_CHANNEL_12 12 +#define NV4_PFIFO_MODE_CHANNEL_13 13 +#define NV4_PFIFO_MODE_CHANNEL_14 14 +#define NV4_PFIFO_MODE_CHANNEL_15 15 +#define NV4_PFIFO_DMA 0x2508 +// 0 = not pending (Valid for all channels) +#define NV4_PFIFO_DMA_CHANNEL_IS_PENDING 0x1 +#define NV4_PFIFO_DMA_CHANNEL_0 0 +#define NV4_PFIFO_DMA_CHANNEL_1 1 +#define NV4_PFIFO_DMA_CHANNEL_2 2 +#define NV4_PFIFO_DMA_CHANNEL_3 3 +#define NV4_PFIFO_DMA_CHANNEL_4 4 +#define NV4_PFIFO_DMA_CHANNEL_5 5 +#define NV4_PFIFO_DMA_CHANNEL_6 6 +#define NV4_PFIFO_DMA_CHANNEL_7 7 +#define NV4_PFIFO_DMA_CHANNEL_8 8 +#define NV4_PFIFO_DMA_CHANNEL_9 9 +#define NV4_PFIFO_DMA_CHANNEL_10 10 +#define NV4_PFIFO_DMA_CHANNEL_11 11 +#define NV4_PFIFO_DMA_CHANNEL_12 12 +#define NV4_PFIFO_DMA_CHANNEL_13 13 +#define NV4_PFIFO_DMA_CHANNEL_14 14 +#define NV4_PFIFO_DMA_CHANNEL_15 15 +#define NV4_PFIFO_SIZE 0x250C +// Valid for all channels +#define NV4_PFIFO_SIZE_CHANNEL_SIZE_IS_124_BYTES 0x0 +#define NV4_PFIFO_SIZE_CHANNEL_SIZE_IS_512_BYTES 0x1 +#define NV4_PFIFO_SIZE_CHANNEL_0 0 +#define NV4_PFIFO_SIZE_CHANNEL_1 1 +#define NV4_PFIFO_SIZE_CHANNEL_2 2 +#define NV4_PFIFO_SIZE_CHANNEL_3 3 +#define NV4_PFIFO_SIZE_CHANNEL_4 4 +#define NV4_PFIFO_SIZE_CHANNEL_5 5 +#define NV4_PFIFO_SIZE_CHANNEL_6 6 +#define NV4_PFIFO_SIZE_CHANNEL_7 7 +#define NV4_PFIFO_SIZE_CHANNEL_8 8 +#define NV4_PFIFO_SIZE_CHANNEL_9 9 +#define NV4_PFIFO_SIZE_CHANNEL_10 10 +#define NV4_PFIFO_SIZE_CHANNEL_11 11 +#define NV4_PFIFO_SIZE_CHANNEL_12 12 +#define NV4_PFIFO_SIZE_CHANNEL_13 13 +#define NV4_PFIFO_SIZE_CHANNEL_14 14 +#define NV4_PFIFO_SIZE_CHANNEL_15 15 +#define NV4_PFIFO_CACHE0_PUSH0 0x3000 +#define NV4_PFIFO_CACHE0_PUSH0_ACCESS 0 +#define NV4_PFIFO_CACHE0_PUSH0_ACCESS_ENABLED 0x1 +#define NV4_PFIFO_CACHE1_PUSH0 0x3200 +#define NV4_PFIFO_CACHE1_PUSH0_ACCESS 0 +#define NV4_PFIFO_CACHE1_PUSH0_ACCESS_ENABLED 0x1 +#define NV4_PFIFO_CACHE0_PUSH1 0x3004 +#define NV4_PFIFO_CACHE0_PUSH1_CHID 0 +#define NV4_PFIFO_CACHE1_PUSH1 0x3204 +#define NV4_PFIFO_CACHE1_PUSH1_CHID 0 +#define NV4_PFIFO_CACHE1_PUSH1_MODE 8 +#define NV4_PFIFO_CACHE1_PUSH1_MODE_PIO 0x0 +#define NV4_PFIFO_CACHE1_PUSH1_MODE_DMA 0x1 +#define NV4_PFIFO_CACHE1_DMA_PUSH 0x3220 +#define NV4_PFIFO_CACHE1_DMA_PUSH_ACCESS 0 +#define NV4_PFIFO_CACHE1_DMA_PUSH_ACCESS_ENABLED 0x1 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATE 4 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATE_IDLE 0x0 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATE_BUSY 0x1 +#define NV4_PFIFO_CACHE1_DMA_PUSH_BUFFER 8 +#define NV4_PFIFO_CACHE1_DMA_PUSH_BUFFER_NOT_EMPTY 0x0 +#define NV4_PFIFO_CACHE1_DMA_PUSH_BUFFER_EMPTY 0x1 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATUS 12 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATUS_RUNNING 0x0 +#define NV4_PFIFO_CACHE1_DMA_PUSH_STATUS_SUSPENDED 0x1 +#define NV4_PFIFO_CACHE1_DMA_FETCH 0x3224 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG 7:3 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x0 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x1 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x2 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x3 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x4 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x5 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x6 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x7 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x8 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x9 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0xA +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0xB +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0xC +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0xD +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0xE +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0xF +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x10 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x11 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x12 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x13 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x14 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x15 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x16 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x17 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x18 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x19 +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x1A +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x1B +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x1C +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x1D +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x1E +#define NV4_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x1F +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE 13 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x0 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x1 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x2 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x3 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x4 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x5 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x6 +#define NV4_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x7 +// This is a count. 0x0-0xF = number of requests +#define NV4_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 16 +#define NV4_PFIFO_CACHE1_DMA_PUT 0x3240 +#define NV4_PFIFO_CACHE1_DMA_PUT_OFFSET 2 +#define NV4_PFIFO_CACHE1_DMA_GET 0x3244 +#define NV4_PFIFO_CACHE1_DMA_GET_OFFSET 2 +#define NV4_PFIFO_CACHE1_DMA_DCOUNT 0x32A0 +#define NV4_PFIFO_CACHE1_DMA_DCOUNT_VALUE 2 +#define NV4_PFIFO_CACHE1_DMA_GET_JMP_SHADOW 0x32A4 +#define NV4_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET 2 +#define NV4_PFIFO_CACHE1_DMA_RSVD_SHADOW 0x32A8 +#define NV4_PFIFO_CACHE1_DMA_RSVD_SHADOW_CMD 0 +#define NV4_PFIFO_CACHE1_DMA_DATA_SHADOW 0x32AC +#define NV4_PFIFO_CACHE1_DMA_DATA_SHADOW_VALUE 0 +#define NV4_PFIFO_CACHE1_DMA_STATE 0x3228 +#define NV4_PFIFO_CACHE1_DMA_STATE_METHOD 2 +#define NV4_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL 13 +#define NV4_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT 18 +#define NV4_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT_0 0x0 +#define NV4_PFIFO_CACHE1_DMA_STATE_ERROR 30 +#define NV4_PFIFO_CACHE1_DMA_STATE_ERROR_NONE 0x0 +#define NV4_PFIFO_CACHE1_DMA_STATE_ERROR_NON_CACHE 0x1 +#define NV4_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD 0x2 +#define NV4_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION 0x3 +#define NV4_PFIFO_CACHE1_DMA_INSTANCE 0x322C +#define NV4_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 0 +#define NV4_PFIFO_CACHE1_DMA_CTL 0x3230 +#define NV4_PFIFO_CACHE1_DMA_CTL_ADJUST 11:2 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE 12 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_NOT_PRESENT 0x0 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_PRESENT 0x1 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY 13 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_NOT_LINEAR 0x0 +#define NV4_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_LINEAR 0x1 +#define NV4_PFIFO_CACHE1_DMA_CTL_TARGET_NODE 16 +#define NV4_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_PCI 0x2 +#define NV4_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_AGP 0x3 +#define NV4_PFIFO_CACHE1_DMA_CTL_AT_INFO 31 +#define NV4_PFIFO_CACHE1_DMA_CTL_AT_INFO_INVALID 0x0 +#define NV4_PFIFO_CACHE1_DMA_CTL_AT_INFO_VALID 0x1 +#define NV4_PFIFO_CACHE1_DMA_LIMIT 0x3234 +#define NV4_PFIFO_CACHE1_DMA_LIMIT_OFFSET 2 +#define NV4_PFIFO_CACHE1_DMA_TLB_TAG 0x3238 +#define NV4_PFIFO_CACHE1_DMA_TLB_TAG_ADDRESS 28:12 +#define NV4_PFIFO_CACHE1_DMA_TLB_TAG_STATE 0 +#define NV4_PFIFO_CACHE1_DMA_TLB_TAG_STATE_INVALID 0x0 +#define NV4_PFIFO_CACHE1_DMA_TLB_TAG_STATE_VALID 0x1 +#define NV4_PFIFO_CACHE1_DMA_TLB_PTE 0x323C +#define NV4_PFIFO_CACHE1_DMA_TLB_PTE_FRAME_ADDRESS 12 +#define NV4_PFIFO_CACHE0_PULL0 0x3050 +#define NV4_PFIFO_CACHE0_PULL0_ACCESS 0 +#define NV4_PFIFO_CACHE0_PULL0_ACCESS_ENABLED 0x1 +#define NV4_PFIFO_CACHE0_PULL0_HASH 4 +#define NV4_PFIFO_CACHE0_PULL0_HASH_SUCCEEDED 0x0 +#define NV4_PFIFO_CACHE0_PULL0_HASH_FAILED 0x1 +#define NV4_PFIFO_CACHE0_PULL0_DEVICE 8 +#define NV4_PFIFO_CACHE0_PULL0_DEVICE_HARDWARE 0x0 +#define NV4_PFIFO_CACHE0_PULL0_DEVICE_SOFTWARE 0x1 +#define NV4_PFIFO_CACHE0_PULL0_HASH_STATE 12 +#define NV4_PFIFO_CACHE0_PULL0_HASH_STATE_IDLE 0x0 +#define NV4_PFIFO_CACHE0_PULL0_HASH_STATE_BUSY 0x1 +#define NV4_PFIFO_CACHE1_PULL0 0x3250 +#define NV4_PFIFO_CACHE1_PULL0_ACCESS 0 +#define NV4_PFIFO_CACHE1_PULL0_ACCESS_ENABLED 0x1 +#define NV4_PFIFO_CACHE1_PULL0_HASH 4 +#define NV4_PFIFO_CACHE1_PULL0_HASH_SUCCEEDED 0x0 +#define NV4_PFIFO_CACHE1_PULL0_HASH_FAILED 0x1 +#define NV4_PFIFO_CACHE1_PULL0_DEVICE 8 +#define NV4_PFIFO_CACHE1_PULL0_DEVICE_HARDWARE 0x0 +#define NV4_PFIFO_CACHE1_PULL0_DEVICE_SOFTWARE 0x1 +#define NV4_PFIFO_CACHE1_PULL0_HASH_STATE 12 +#define NV4_PFIFO_CACHE1_PULL0_HASH_STATE_IDLE 0x0 +#define NV4_PFIFO_CACHE1_PULL0_HASH_STATE_BUSY 0x1 +#define NV4_PFIFO_CACHE0_PULL1 0x3054 +#define NV4_PFIFO_CACHE0_PULL1_ENGINE 0 +#define NV4_PFIFO_CACHE0_PULL1_ENGINE_SW 0x0 +#define NV4_PFIFO_CACHE0_PULL1_ENGINE_GRAPHICS 0x1 +#define NV4_PFIFO_CACHE0_PULL1_ENGINE_DVD 0x2 +#define NV4_PFIFO_CACHE1_PULL1 0x3254 +#define NV4_PFIFO_CACHE1_PULL1_ENGINE 0 +#define NV4_PFIFO_CACHE1_PULL1_ENGINE_SW 0x0 +#define NV4_PFIFO_CACHE1_PULL1_ENGINE_GRAPHICS 0x1 +#define NV4_PFIFO_CACHE1_PULL1_ENGINE_DVD 0x2 +#define NV4_PFIFO_CACHE0_HASH 0x3058 +#define NV4_PFIFO_CACHE0_HASH_INSTANCE 0 +#define NV4_PFIFO_CACHE0_HASH_VALID 16 +#define NV4_PFIFO_CACHE1_HASH 0x3258 +#define NV4_PFIFO_CACHE1_HASH_INSTANCE 0 +#define NV4_PFIFO_CACHE1_HASH_VALID 16 +#define NV4_PFIFO_CACHE0_STATUS 0x3014 +#define NV4_PFIFO_CACHE0_STATUS_LOW_MARK 4 +#define NV4_PFIFO_CACHE0_STATUS_LOW_MARK_NOT_EMPTY 0x0 +#define NV4_PFIFO_CACHE0_STATUS_LOW_MARK_EMPTY 0x1 +#define NV4_PFIFO_CACHE0_STATUS_HIGH_MARK 8 +#define NV4_PFIFO_CACHE0_STATUS_HIGH_MARK_NOT_FULL 0x0 +#define NV4_PFIFO_CACHE0_STATUS_HIGH_MARK_FULL 0x1 +#define NV4_PFIFO_CACHE1_STATUS 0x3214 +#define NV4_PFIFO_CACHE1_STATUS_LOW_MARK 4 +#define NV4_PFIFO_CACHE1_STATUS_LOW_MARK_NOT_EMPTY 0x0 +#define NV4_PFIFO_CACHE1_STATUS_LOW_MARK_EMPTY 0x1 +#define NV4_PFIFO_CACHE1_STATUS_HIGH_MARK 8 +#define NV4_PFIFO_CACHE1_STATUS_HIGH_MARK_NOT_FULL 0x0 +#define NV4_PFIFO_CACHE1_STATUS_HIGH_MARK_FULL 0x1 +#define NV4_PFIFO_CACHE1_STATUS1 0x3218 +#define NV4_PFIFO_CACHE1_STATUS1_RANOUT 0 +#define NV4_PFIFO_CACHE1_STATUS1_RANOUT_TRUE 0x1 +#define NV4_PFIFO_CACHE0_PUT 0x3010 +#define NV4_PFIFO_CACHE0_PUT_ADDRESS 2 +#define NV4_PFIFO_CACHE1_PUT 0x3210 +#define NV4_PFIFO_CACHE1_PUT_ADDRESS 2 +#define NV4_PFIFO_CACHE0_GET 0x3070 +#define NV4_PFIFO_CACHE0_GET_ADDRESS 2 +#define NV4_PFIFO_CACHE1_GET 0x3270 +#define NV4_PFIFO_CACHE1_GET_ADDRESS 2 +#define NV4_PFIFO_ENGINE_SW 0x0 +#define NV4_PFIFO_ENGINE_GRAPHICS 0x1 +#define NV4_PFIFO_ENGINE_DVD 0x2 +#define NV4_PFIFO_CACHE0_ENGINE 0x3080 +// For these, see above +#define NV4_PFIFO_CACHE0_SUBCHANNEL_0_ENGINE 0 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_1_ENGINE 4 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_2_ENGINE 8 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_3_ENGINE 12 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_4_ENGINE 16 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_5_ENGINE 20 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_6_ENGINE 24 +#define NV4_PFIFO_CACHE0_SUBCHANNEL_7_ENGINE 28 +#define NV4_PFIFO_CACHE1_ENGINE 0x3280 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_0_ENGINE 0 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_1_ENGINE 4 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_2_ENGINE 8 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_3_ENGINE 12 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_4_ENGINE 16 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_5_ENGINE 20 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_6_ENGINE 24 +#define NV4_PFIFO_CACHE1_SUBCHANNEL_7_ENGINE 28 +#define NV4_PFIFO_CACHE0_METHOD(i) (0x3100+(i)*8) +#define NV4_PFIFO_CACHE0_METHOD_SIZE_1 1 +#define NV4_PFIFO_CACHE0_METHOD_ADDRESS 2 +#define NV4_PFIFO_CACHE0_METHOD_SUBCHANNEL 13 +#define NV4_PFIFO_CACHE1_METHOD(i) (0x3800+(i)*8) +#define NV4_PFIFO_CACHE1_METHOD_SIZE_1 128 +#define NV4_PFIFO_CACHE1_METHOD_ADDRESS 2 +#define NV4_PFIFO_CACHE1_METHOD_SUBCHANNEL 13 +#define NV4_PFIFO_CACHE1_METHOD_ALIAS(i) (0x3C00+(i)*8) +#define NV4_PFIFO_CACHE1_METHOD_ALIAS_SIZE_1 128 +#define NV4_PFIFO_CACHE0_DATA(i) (0x3104+(i)*8) +#define NV4_PFIFO_CACHE0_DATA_SIZE_1 1 +#define NV4_PFIFO_CACHE0_DATA_VALUE 0 +#define NV4_PFIFO_CACHE1_DATA(i) (0x3804+(i)*8) +#define NV4_PFIFO_CACHE1_DATA_SIZE_1 128 +#define NV4_PFIFO_CACHE1_DATA_VALUE 0 +#define NV4_PFIFO_CACHE1_DATA_ALIAS(i) (0x3C04+(i)*8) +#define NV4_PFIFO_CACHE1_DATA_ALIAS_SIZE_1 128 +#define NV4_PFIFO_DEVICE(i) (0x2800+(i)*4) +#define NV4_PFIFO_DEVICE_SIZE_1 128 +#define NV4_PFIFO_DEVICE_CHID 0 +#define NV4_PFIFO_DEVICE_SWITCH 24 +#define NV4_PFIFO_DEVICE_SWITCH_AVAILABLE 0x1 +#define NV4_PFIFO_RUNOUT_STATUS 0x2400 +#define NV4_PFIFO_RUNOUT_STATUS_RANOUT 0 +#define NV4_PFIFO_RUNOUT_STATUS_RANOUT_TRUE 0x1 +#define NV4_PFIFO_RUNOUT_STATUS_LOW_MARK 4 +#define NV4_PFIFO_RUNOUT_STATUS_LOW_MARK_NOT_EMPTY 0x0 +#define NV4_PFIFO_RUNOUT_STATUS_LOW_MARK_EMPTY 0x1 +#define NV4_PFIFO_RUNOUT_STATUS_HIGH_MARK 8 +#define NV4_PFIFO_RUNOUT_STATUS_HIGH_MARK_NOT_FULL 0x0 +#define NV4_PFIFO_RUNOUT_STATUS_HIGH_MARK_FULL 0x1 +#define NV4_PFIFO_RUNOUT_PUT 0x2410 +#define NV4_PFIFO_RUNOUT_PUT_ADDRESS 3 // if size=0, 8:3, otherwise 12:3 +#define NV4_PFIFO_RUNOUT_GET 0x2420 +#define NV4_PFIFO_RUNOUT_GET_ADDRESS 3 // 13:3 + +#define NV4_PGRAPH_START 0x400000 +#define NV4_PGRAPH_END 0x401FFF + +#define NV4_PGRAPH_DEBUG_0 0x400080 +#define NV4_PGRAPH_DEBUG_0_STATE 0 +#define NV4_PGRAPH_DEBUG_0_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_FE_STATE 1 +#define NV4_PGRAPH_DEBUG_0_FE_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_FE_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_CACHE_STATE 2 +#define NV4_PGRAPH_DEBUG_0_CACHE_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_CACHE_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_D3D_PIPE_STATE 3 +#define NV4_PGRAPH_DEBUG_0_D3D_PIPE_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_D3D_PIPE_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_PREROP_STATE 4 +#define NV4_PGRAPH_DEBUG_0_PREROP_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_PREROP_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_ROP_STATE 5 +#define NV4_PGRAPH_DEBUG_0_ROP_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_ROP_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_RSTR_STATE 6 +#define NV4_PGRAPH_DEBUG_0_RSTR_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_RSTR_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_LIGHT_STATE 7 +#define NV4_PGRAPH_DEBUG_0_LIGHT_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_LIGHT_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_DMA_STATE 8 +#define NV4_PGRAPH_DEBUG_0_DMA_STATE_NORMAL 0x0 +#define NV4_PGRAPH_DEBUG_0_DMA_STATE_RESET 0x1 +#define NV4_PGRAPH_DEBUG_0_SPARE1 12 +#define NV4_PGRAPH_DEBUG_0_SPARE2 13 +#define NV4_PGRAPH_DEBUG_0_MINUSD5 14 +#define NV4_PGRAPH_DEBUG_0_MINUSD5_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_BLIT_DST_LIMIT 15 +#define NV4_PGRAPH_DEBUG_0_BLIT_DST_LIMIT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_LIMIT_CHECK 16 +#define NV4_PGRAPH_DEBUG_0_LIMIT_CHECK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_LIMIT_INT 17 +#define NV4_PGRAPH_DEBUG_0_LIMIT_INT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_OVRFLW_INT 18 +#define NV4_PGRAPH_DEBUG_0_OVRFLW_INT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_2D 20 +#define NV4_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_2D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_3D 21 +#define NV4_PGRAPH_DEBUG_0_WRITE_ONLY_ROPS_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_DRAWDIR_AUTO 24 +#define NV4_PGRAPH_DEBUG_0_DRAWDIR_AUTO_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_0_DRAWDIR_Y 25 +#define NV4_PGRAPH_DEBUG_0_DRAWDIR_Y_DECR 0x0 +#define NV4_PGRAPH_DEBUG_0_DRAWDIR_Y_INCR 0x1 +#define NV4_PGRAPH_DEBUG_0_ALPHA_ABORT 28 +#define NV4_PGRAPH_DEBUG_0_ALPHA_ABORT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1 0x400084 +#define NV4_PGRAPH_DEBUG_1_VOLATILE_RESET 0 +#define NV4_PGRAPH_DEBUG_1_VOLATILE_RESET_NOT_LAST 0x0 +#define NV4_PGRAPH_DEBUG_1_VOLATILE_RESET_LAST 0x1 +#define NV4_PGRAPH_DEBUG_1_DMA_ACTIVITY 4 +#define NV4_PGRAPH_DEBUG_1_DMA_ACTIVITY_IGNORE 0x0 +#define NV4_PGRAPH_DEBUG_1_DMA_ACTIVITY_CANCEL 0x1 +#define NV4_PGRAPH_DEBUG_1_PATCH_INV 8 +#define NV4_PGRAPH_DEBUG_1_PATCH_INV_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_ALT_RW_SEQ 10 +#define NV4_PGRAPH_DEBUG_1_ALT_RW_SEQ_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_TRI_OPTS 12 +#define NV4_PGRAPH_DEBUG_1_TRI_OPTS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_TRICLIP_OPTS 13 +#define NV4_PGRAPH_DEBUG_1_TRICLIP_OPTS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_INSTANCE 16 +#define NV4_PGRAPH_DEBUG_1_INSTANCE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_ALOM_BURST 17 +#define NV4_PGRAPH_DEBUG_1_ALOM_BURST_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_BIDIR_DRAIN 18 +#define NV4_PGRAPH_DEBUG_1_BIDIR_DRAIN_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_EARLY_POST 19 +#define NV4_PGRAPH_DEBUG_1_EARLY_POST_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_CTX 20 +#define NV4_PGRAPH_DEBUG_1_CTX_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_FIXED_ADRS 21 +#define NV4_PGRAPH_DEBUG_1_FIXED_ADRS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_DITHER_RANGE_ADJ_2D 22 +#define NV4_PGRAPH_DEBUG_1_DITHER_RANGE_ADJ_2D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_DITHER_RANGE_ADJ_3D 23 +#define NV4_PGRAPH_DEBUG_1_DITHER_RANGE_ADJ_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_CACHE 24 +#define NV4_PGRAPH_DEBUG_1_CACHE_IGNORE 0x0 +#define NV4_PGRAPH_DEBUG_1_CACHE_FLUSH 0x1 +#define NV4_PGRAPH_DEBUG_1_CACHE_MODE 25 +#define NV4_PGRAPH_DEBUG_1_CACHE_MODE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_ZCLAMP 28 +#define NV4_PGRAPH_DEBUG_1_ZCLAMP_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_UCLAMP 29 +#define NV4_PGRAPH_DEBUG_1_UCLAMP_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_RCLAMP 30 +#define NV4_PGRAPH_DEBUG_1_RCLAMP_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_1_DX6_2PIXMODE 31 +#define NV4_PGRAPH_DEBUG_1_DX6_2PIXMODE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2 0x400088 +#define NV4_PGRAPH_DEBUG_2_HONOR_SRCFMT 0 +#define NV4_PGRAPH_DEBUG_2_HONOR_SRCFMT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_PINGPONG 0 +#define NV4_PGRAPH_DEBUG_2_PINGPONG_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_SPARE1 4 +#define NV4_PGRAPH_DEBUG_2_SPARE2 5 +#define NV4_PGRAPH_DEBUG_2_SPARE3 6 +#define NV4_PGRAPH_DEBUG_2_SPARE4 7 +#define NV4_PGRAPH_DEBUG_2_SPARE5 8 +#define NV4_PGRAPH_DEBUG_2_SPARE6 9 +#define NV4_PGRAPH_DEBUG_2_SPARE7 10 +#define NV4_PGRAPH_DEBUG_2_MCLK_RECTS 11 +#define NV4_PGRAPH_DEBUG_2_MCLK_RECTS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_BILINEAR_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_ANISOTROPIC_3D 13 +#define NV4_PGRAPH_DEBUG_2_ANISOTROPIC_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_FOG_3D 14 +#define NV4_PGRAPH_DEBUG_2_FOG_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_SPECULAR_3D 15 +#define NV4_PGRAPH_DEBUG_2_SPECULAR_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_ALPHA_3D 16 +#define NV4_PGRAPH_DEBUG_2_ALPHA_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_ZBUF_SEQ 17 +#define NV4_PGRAPH_DEBUG_2_ZBUF_SEQ_CRZRWCW 0x0 +#define NV4_PGRAPH_DEBUG_2_ZBUF_SEQ_ZRWCRW 0x1 +#define NV4_PGRAPH_DEBUG_2_ZBUF_SEQ_AUTO 0x2 +#define NV4_PGRAPH_DEBUG_2_COELESCE_D3D 20 +#define NV4_PGRAPH_DEBUG_2_COELESCE_D3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_COELESCE_2D 22 +#define NV4_PGRAPH_DEBUG_2_COELESCE_2D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_FAST_VERTEX_LOAD 23 +#define NV4_PGRAPH_DEBUG_2_FAST_VERTEX_LOAD_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_BLIT_MULTILINE 24 +#define NV4_PGRAPH_DEBUG_2_BLIT_MULTILINE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_2_VOLATILE_RESET 28 +#define NV4_PGRAPH_DEBUG_2_VOLATILE_RESET_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3 0x40008C +#define NV4_PGRAPH_DEBUG_3_CULLING 0 +#define NV4_PGRAPH_DEBUG_3_CULLING_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_CULLING_TYPE 1 +#define NV4_PGRAPH_DEBUG_3_CULLING_TYPE_DX3 0x0 +#define NV4_PGRAPH_DEBUG_3_CULLING_TYPE_DX5 0x1 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_STRTCH 4 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_STRTCH_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_D3D 5 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_D3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_IMAGE 6 +#define NV4_PGRAPH_DEBUG_3_FAST_DATA_IMAGE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_ZFLUSH 7 +#define NV4_PGRAPH_DEBUG_3_ZFLUSH_IGNORE 0x0 +#define NV4_PGRAPH_DEBUG_3_ZFLUSH_ACTIVATE 0x1 +#define NV4_PGRAPH_DEBUG_3_AUTOZFLUSH_PTZ 8 +#define NV4_PGRAPH_DEBUG_3_AUTOZFLUSH_PTZ_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_AUTOZFLUSH_D3D 9 +#define NV4_PGRAPH_DEBUG_3_AUTOZFLUSH_D3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_SLOT_CONFLICT_PTZ 10 +#define NV4_PGRAPH_DEBUG_3_SLOT_CONFLICT_PTZ_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_SLOT_CONFLICT_D3D 11 +#define NV4_PGRAPH_DEBUG_3_SLOT_CONFLICT_D3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_POSTDITHER_2D 12 +#define NV4_PGRAPH_DEBUG_3_POSTDITHER_2D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_POSTDITHER_3D 13 +#define NV4_PGRAPH_DEBUG_3_POSTDITHER_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_PREDITHER_2D 14 +#define NV4_PGRAPH_DEBUG_3_PREDITHER_2D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_PREDITHER_3D 15 +#define NV4_PGRAPH_DEBUG_3_PREDITHER_3D_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_FORCE_CREAD 16 +#define NV4_PGRAPH_DEBUG_3_FORCE_CREAD_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_FORCE_ZREAD 17 +#define NV4_PGRAPH_DEBUG_3_FORCE_ZREAD_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_EARLYZ_ABORT 18 +#define NV4_PGRAPH_DEBUG_3_EARLYZ_ABORT_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_TRIEND_FLUSH 19 +#define NV4_PGRAPH_DEBUG_3_TRIEND_FLUSH_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_DATA_CHECK 20 +#define NV4_PGRAPH_DEBUG_3_DATA_CHECK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_DATA_CHECK_FAIL 21 +#define NV4_PGRAPH_DEBUG_3_DATA_CHECK_FAIL_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_FORMAT_CHECK 22 +#define NV4_PGRAPH_DEBUG_3_FORMAT_CHECK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_DMA_CHECK 23 +#define NV4_PGRAPH_DEBUG_3_DMA_CHECK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_RAMREADBACK 24 +#define NV4_PGRAPH_DEBUG_3_RAMREADBACK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_CLIP_METHODS 25 +#define NV4_PGRAPH_DEBUG_3_CLIP_METHODS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_EXCLUDE_ROP_IN_IDLE 27 +#define NV4_PGRAPH_DEBUG_3_EXCLUDE_ROP_IN_IDLE_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_STATE_CHECK 28 +#define NV4_PGRAPH_DEBUG_3_STATE_CHECK_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_CONTEXT_METHODS 29 +#define NV4_PGRAPH_DEBUG_3_CONTEXT_METHODS_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_OPERATION_METHOD 30 +#define NV4_PGRAPH_DEBUG_3_OPERATION_METHOD_ENABLED 0x1 +#define NV4_PGRAPH_DEBUG_3_IGNORE_PATCHVALID 31 +#define NV4_PGRAPH_DEBUG_3_IGNORE_PATCHVALID_ENABLED 0x1 +#define NV4_PGRAPH_INTR 0x400100 +#define NV4_PGRAPH_INTR_NOTIFY 0 +#define NV4_PGRAPH_INTR_NOTIFY_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_NOTIFY_PENDING 0x1 +#define NV4_PGRAPH_INTR_NOTIFY_RESET 0x1 +#define NV4_PGRAPH_INTR_MISSING_HW 4 +#define NV4_PGRAPH_INTR_MISSING_HW_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_MISSING_HW_PENDING 0x1 +#define NV4_PGRAPH_INTR_MISSING_HW_RESET 0x1 +#define NV4_PGRAPH_INTR_TLB_PRESENT_A 8 +#define NV4_PGRAPH_INTR_TLB_PRESENT_A_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_TLB_PRESENT_A_PENDING 0x1 +#define NV4_PGRAPH_INTR_TLB_PRESENT_A_RESET 0x1 +#define NV4_PGRAPH_INTR_TLB_PRESENT_B 9 +#define NV4_PGRAPH_INTR_TLB_PRESENT_B_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_TLB_PRESENT_B_PENDING 0x1 +#define NV4_PGRAPH_INTR_TLB_PRESENT_B_RESET 0x1 +#define NV4_PGRAPH_INTR_CONTEXT_SWITCH 12 +#define NV4_PGRAPH_INTR_CONTEXT_SWITCH_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_CONTEXT_SWITCH_PENDING 0x1 +#define NV4_PGRAPH_INTR_CONTEXT_SWITCH_RESET 0x1 +#define NV4_PGRAPH_INTR_BUFFER_NOTIFY 16 +#define NV4_PGRAPH_INTR_BUFFER_NOTIFY_NOT_PENDING 0x0 +#define NV4_PGRAPH_INTR_BUFFER_NOTIFY_PENDING 0x1 +#define NV4_PGRAPH_INTR_BUFFER_NOTIFY_RESET 0x1 +#define NV4_PGRAPH_NSTATUS 0x400104 +#define NV4_PGRAPH_NSTATUS_STATE_IN_USE 11 +#define NV4_PGRAPH_NSTATUS_STATE_IN_USE_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSTATUS_STATE_IN_USE_PENDING 0x1 +#define NV4_PGRAPH_NSTATUS_INVALID_STATE 12 +#define NV4_PGRAPH_NSTATUS_INVALID_STATE_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSTATUS_INVALID_STATE_PENDING 0x1 +#define NV4_PGRAPH_NSTATUS_BAD_ARGUMENT 13 +#define NV4_PGRAPH_NSTATUS_BAD_ARGUMENT_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSTATUS_BAD_ARGUMENT_PENDING 0x1 +#define NV4_PGRAPH_NSTATUS_PROTECTION_FAULT 14 +#define NV4_PGRAPH_NSTATUS_PROTECTION_FAULT_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSTATUS_PROTECTION_FAULT_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE 0x400108 +#define NV4_PGRAPH_NSOURCE_NOTIFICATION 0 +#define NV4_PGRAPH_NSOURCE_NOTIFICATION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_NOTIFICATION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_DATA_ERROR 1 +#define NV4_PGRAPH_NSOURCE_DATA_ERROR_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_DATA_ERROR_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_PROTECTION_ERROR 2 +#define NV4_PGRAPH_NSOURCE_PROTECTION_ERROR_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_PROTECTION_ERROR_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_RANGE_EXCEPTION 3 +#define NV4_PGRAPH_NSOURCE_RANGE_EXCEPTION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_RANGE_EXCEPTION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_LIMIT_COLOR 4 +#define NV4_PGRAPH_NSOURCE_LIMIT_COLOR_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_LIMIT_COLOR_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_LIMIT_ZETA_ 5 +#define NV4_PGRAPH_NSOURCE_LIMIT_ZETA_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_LIMIT_ZETA_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_ILLEGAL_MTHD 6 +#define NV4_PGRAPH_NSOURCE_ILLEGAL_MTHD_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_ILLEGAL_MTHD_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_DMA_R_PROTECTION 7 +#define NV4_PGRAPH_NSOURCE_DMA_R_PROTECTION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_DMA_R_PROTECTION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_DMA_W_PROTECTION 8 +#define NV4_PGRAPH_NSOURCE_DMA_W_PROTECTION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_DMA_W_PROTECTION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_FORMAT_EXCEPTION 9 +#define NV4_PGRAPH_NSOURCE_FORMAT_EXCEPTION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_FORMAT_EXCEPTION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_PATCH_EXCEPTION 10 +#define NV4_PGRAPH_NSOURCE_PATCH_EXCEPTION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_PATCH_EXCEPTION_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_STATE_INVALID 11 +#define NV4_PGRAPH_NSOURCE_STATE_INVALID_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_STATE_INVALID_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_DOUBLE_NOTIFY 12 +#define NV4_PGRAPH_NSOURCE_DOUBLE_NOTIFY_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_DOUBLE_NOTIFY_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_NOTIFY_IN_USE 13 +#define NV4_PGRAPH_NSOURCE_NOTIFY_IN_USE_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_NOTIFY_IN_USE_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_METHOD_CNT 14 +#define NV4_PGRAPH_NSOURCE_METHOD_CNT_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_METHOD_CNT_PENDING 0x1 +#define NV4_PGRAPH_NSOURCE_BFR_NOTIFICATION 15 +#define NV4_PGRAPH_NSOURCE_BFR_NOTIFICATION_NOT_PENDING 0x0 +#define NV4_PGRAPH_NSOURCE_BFR_NOTIFICATION_PENDING 0x1 +#define NV4_PGRAPH_INTR_EN 0x400140 +#define NV4_PGRAPH_INTR_EN_NOTIFY 0 +#define NV4_PGRAPH_INTR_EN_NOTIFY_ENABLED 0x1 +#define NV4_PGRAPH_INTR_EN_MISSING_HW 4 +#define NV4_PGRAPH_INTR_EN_MISSING_HW_ENABLED 0x1 +#define NV4_PGRAPH_INTR_EN_TLB_PRESENT_A 8 +#define NV4_PGRAPH_INTR_EN_TLB_PRESENT_A_ENABLED 0x1 +#define NV4_PGRAPH_INTR_EN_TLB_PRESENT_B 9 +#define NV4_PGRAPH_INTR_EN_TLB_PRESENT_B_ENABLED 0x1 +#define NV4_PGRAPH_INTR_EN_CONTEXT_SWITCH 12 +#define NV4_PGRAPH_INTR_EN_CONTEXT_SWITCH_ENABLED 0x1 +#define NV4_PGRAPH_INTR_EN_BUFFER_NOTIFY 16 +#define NV4_PGRAPH_INTR_EN_BUFFER_NOTIFY_ENABLED 0x1 +#define NV4_PGRAPH_CTX_SWITCH1 0x400160 +#define NV4_PGRAPH_CTX_SWITCH1_GRCLASS 0 +#define NV4_PGRAPH_CTX_SWITCH1_CHROMA_KEY 12 +#define NV4_PGRAPH_CTX_SWITCH1_CHROMA_KEY_DISABLE 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_CHROMA_KEY_ENABLE 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_USER_CLIP 13 +#define NV4_PGRAPH_CTX_SWITCH1_USER_CLIP_DISABLE 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_USER_CLIP_ENABLE 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_SWIZZLE 14 +#define NV4_PGRAPH_CTX_SWITCH1_SWIZZLE_DISABLE 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_SWIZZLE_ENABLE 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG 17:15 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_AND 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_ROP_AND 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_AND 0x2 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY 0x3 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_PRE 0x4 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_PRE 0x5 +#define NV4_PGRAPH_CTX_SWITCH1_DITHER_MODE 20 +#define NV4_PGRAPH_CTX_SWITCH1_DITHER_MODE_COMPATIBILITY 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_DITHER_MODE_DITHER 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_DITHER_MODE_TRUNCATE 0x2 +#define NV4_PGRAPH_CTX_SWITCH1_DITHER_MODE_MS 0x3 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_STATUS 24 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_STATUS_INVALID 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_PATCH_STATUS_VALID 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE 25 +#define NV4_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_INVALID 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_VALID 0x1 +#define NV4_PGRAPH_CTX_SWITCH1_VOLATILE_RESET 31 +#define NV4_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_IGNORE 0x0 +#define NV4_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_ENABLED 0x1 +#define NV4_PGRAPH_CTX_SWITCH2 0x400164 +#define NV4_PGRAPH_CTX_SWITCH2_MONO_FORMAT 0 +#define NV4_PGRAPH_CTX_SWITCH2_MONO_FORMAT_INVALID 0x00 +#define NV4_PGRAPH_CTX_SWITCH2_MONO_FORMAT_CGA6_M1 0x01 +#define NV4_PGRAPH_CTX_SWITCH2_MONO_FORMAT_LE_M1 0x02 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT 13:8 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_INVALID 0x00 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y8 0x01 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A8Y8 0x02 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X24Y8 0x03 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A1R5G5B5 0x06 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X1R5G5B5 0x07 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A1R5G5B5 0x08 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X17R5G5B5 0x09 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_R5G6B5 0x0A +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16R5G6B5 0x0B +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16R5G6B5 0x0C +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A8R8G8B8 0x0D +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X8R8G8B8 0x0E +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y16 0x0F +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16Y16 0x10 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16Y16 0x11 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_V8YB8U8YA8 0x12 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_YB8V8YA8U8 0x13 +#define NV4_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y32 0x14 +#define NV4_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE 16 +#define NV4_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE_INVALID 0x00 +#define NV4_PGRAPH_CTX_SWITCH3 0x400168 +#define NV4_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0 0 +#define NV4_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0_INVALID 0x00 +#define NV4_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1 16 +#define NV4_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1_INVALID 0x00 +#define NV4_PGRAPH_CTX_SWITCH4 0x40016C +#define NV4_PGRAPH_CTX_SWITCH4_USER_INSTANCE 0 +#define NV4_PGRAPH_CTX_SWITCH4_USER_INSTANCE_INVALID 0x00 +#define NV4_PGRAPH_CTX_CACHE1(i) (0x400180+(i)*4) +#define NV4_PGRAPH_CTX_CACHE1_SIZE_1 8 +#define NV4_PGRAPH_CTX_CACHE1_GRCLASS 0 +#define NV4_PGRAPH_CTX_CACHE1_CHROMA_KEY 12 +#define NV4_PGRAPH_CTX_CACHE1_USER_CLIP 13 +#define NV4_PGRAPH_CTX_CACHE1_SWIZZLE 14 +#define NV4_PGRAPH_CTX_CACHE1_PATCH_CONFIG 19:15 +#define NV4_PGRAPH_CTX_CACHE1_SPARE1 20 +#define NV4_PGRAPH_CTX_CACHE1_PATCH_STATUS 24 +#define NV4_PGRAPH_CTX_CACHE1_CONTEXT_SURFACE 25 +#define NV4_PGRAPH_CTX_CACHE2(i) (0x4001a0+(i)*4) +#define NV4_PGRAPH_CTX_CACHE2_SIZE_1 8 +#define NV4_PGRAPH_CTX_CACHE2_MONO_FORMAT 0 +#define NV4_PGRAPH_CTX_CACHE2_COLOR_FORMAT 13:8 +#define NV4_PGRAPH_CTX_CACHE2_NOTIFY_INSTANCE 16 +#define NV4_PGRAPH_CTX_CACHE3(i) (0x4001c0+(i)*4) +#define NV4_PGRAPH_CTX_CACHE3_SIZE_1 8 +#define NV4_PGRAPH_CTX_CACHE3_DMA_INSTANCE_0 0 +#define NV4_PGRAPH_CTX_CACHE3_DMA_INSTANCE_1 16 +#define NV4_PGRAPH_CTX_CACHE4(i) (0x4001e0+(i)*4) +#define NV4_PGRAPH_CTX_CACHE4_SIZE_1 8 +#define NV4_PGRAPH_CTX_CACHE4_USER_INSTANCE 0 +#define NV4_PGRAPH_CTX_CONTROL 0x400170 +#define NV4_PGRAPH_CTX_CONTROL_MINIMUM_TIME 0 +#define NV4_PGRAPH_CTX_CONTROL_MINIMUM_TIME_33US 0x0 +#define NV4_PGRAPH_CTX_CONTROL_MINIMUM_TIME_262US 0x1 +#define NV4_PGRAPH_CTX_CONTROL_MINIMUM_TIME_2MS 0x2 +#define NV4_PGRAPH_CTX_CONTROL_MINIMUM_TIME_17MS 0x3 +#define NV4_PGRAPH_CTX_CONTROL_TIME 8 +#define NV4_PGRAPH_CTX_CONTROL_TIME_EXPIRED 0x0 +#define NV4_PGRAPH_CTX_CONTROL_TIME_NOT_EXPIRED 0x1 +#define NV4_PGRAPH_CTX_CONTROL_CHID 16 +#define NV4_PGRAPH_CTX_CONTROL_CHID_INVALID 0x0 +#define NV4_PGRAPH_CTX_CONTROL_CHID_VALID 0x1 +#define NV4_PGRAPH_CTX_CONTROL_CHANGE 20 +#define NV4_PGRAPH_CTX_CONTROL_CHANGE_UNAVAILABLE 0x0 +#define NV4_PGRAPH_CTX_CONTROL_CHANGE_AVAILABLE 0x1 +#define NV4_PGRAPH_CTX_CONTROL_SWITCHING 24 +#define NV4_PGRAPH_CTX_CONTROL_SWITCHING_IDLE 0x0 +#define NV4_PGRAPH_CTX_CONTROL_SWITCHING_BUSY 0x1 +#define NV4_PGRAPH_CTX_CONTROL_DEVICE 28 +#define NV4_PGRAPH_CTX_CONTROL_DEVICE_DISABLED 0x0 +#define NV4_PGRAPH_CTX_CONTROL_DEVICE_ENABLED 0x1 +#define NV4_PGRAPH_CTX_USER 0x400174 +#define NV4_PGRAPH_CTX_USER_SUBCH 13 +#define NV4_PGRAPH_CTX_USER_SUBCH_0 0x0 +#define NV4_PGRAPH_CTX_USER_CHID 24 +#define NV4_PGRAPH_CTX_USER_CHID_0 0x0 +#define NV4_PGRAPH_FIFO 0x400720 +#define NV4_PGRAPH_FIFO_ACCESS 0 +#define NV4_PGRAPH_FIFO_ACCESS_DISABLED 0x0 +#define NV4_PGRAPH_FIFO_ACCESS_ENABLED 0x1 +#define NV4_PGRAPH_FFINTFC_FIFO_0(i) (0x400730+(i)*4) +#define NV4_PGRAPH_FFINTFC_FIFO_0_SIZE_1 4 +#define NV4_PGRAPH_FFINTFC_FIFO_0_TAG 0 +#define NV4_PGRAPH_FFINTFC_FIFO_0_TAG_MTHD 0x0 +#define NV4_PGRAPH_FFINTFC_FIFO_0_TAG_CHSW 0x1 +// Note: shift left by 1 (3:1). Subch number = 0-7 +#define NV4_PGRAPH_FFINTFC_FIFO_0_SUBCH 1 +#define NV4_PGRAPH_FFINTFC_FIFO_0_MTHD 4 +#define NV4_PGRAPH_FFINTFC_FIFO_0_MTHD_CTX_SWITCH 0x0 +#define NV4_PGRAPH_FFINTFC_FIFO_1(i) (0x400740+(i)*4) +#define NV4_PGRAPH_FFINTFC_FIFO_1_SIZE_1 4 +#define NV4_PGRAPH_FFINTFC_FIFO_1_ARGUMENT 0 +#define NV4_PGRAPH_FFINTFC_FIFO_PTR 0x400750 +#define NV4_PGRAPH_FFINTFC_FIFO_PTR_WRITE 0 +#define NV4_PGRAPH_FFINTFC_FIFO_PTR_WRITE_0 0x0 +#define NV4_PGRAPH_FFINTFC_FIFO_PTR_READ 4 +#define NV4_PGRAPH_FFINTFC_FIFO_PTR_READ_0 0x0 +#define NV4_PGRAPH_FFINTFC_ST2 0x400754 +#define NV4_PGRAPH_FFINTFC_ST2_STATUS 0 +#define NV4_PGRAPH_FFINTFC_ST2_STATUS_INVALID 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_STATUS_VALID 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_MTHD 1 +#define NV4_PGRAPH_FFINTFC_ST2_MTHD_CTX_SWITCH 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH 12 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_0 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_1 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_2 0x2 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_3 0x3 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_4 0x4 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_5 0x5 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_6 0x6 +#define NV4_PGRAPH_FFINTFC_ST2_SUBCH_7 0x7 +#define NV4_PGRAPH_FFINTFC_ST2_CHID 15 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_0 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_1 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_2 0x2 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_3 0x3 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_4 0x4 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_5 0x5 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_6 0x6 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_7 0x7 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_8 0x8 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_9 0x9 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_10 0xA +#define NV4_PGRAPH_FFINTFC_ST2_CHID_11 0xB +#define NV4_PGRAPH_FFINTFC_ST2_CHID_12 0xC +#define NV4_PGRAPH_FFINTFC_ST2_CHID_13 0xD +#define NV4_PGRAPH_FFINTFC_ST2_CHID_14 0xE +#define NV4_PGRAPH_FFINTFC_ST2_CHID_15 0xF +#define NV4_PGRAPH_FFINTFC_ST2_CHID_STATUS 19 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_STATUS_INVALID 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_CHID_STATUS_VALID 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_CH_SWITCH_DETECT 20 +#define NV4_PGRAPH_FFINTFC_ST2_CH_SWITCH_DETECT_CLEAR 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_CH_SWITCH_DETECT_SET 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_FIFO_HOLD 21 +#define NV4_PGRAPH_FFINTFC_ST2_FIFO_HOLD_CLEAR 0x0 +#define NV4_PGRAPH_FFINTFC_ST2_FIFO_HOLD_SET 0x1 +#define NV4_PGRAPH_FFINTFC_ST2_D 0x400758 +#define NV4_PGRAPH_FFINTFC_ST2_D_ARGUMENT 0 +#define NV4_PGRAPH_FFINTFC_ST2_D_ARGUMENT_0 0x0 +#define NV4_PGRAPH_STATUS 0x400700 +#define NV4_PGRAPH_STATUS_STATE 0 +#define NV4_PGRAPH_STATUS_STATE_IDLE 0x0 +#define NV4_PGRAPH_STATUS_STATE_BUSY 0x1 +#define NV4_PGRAPH_STATUS_XY_LOGIC 4 +#define NV4_PGRAPH_STATUS_XY_LOGIC_IDLE 0x0 +#define NV4_PGRAPH_STATUS_XY_LOGIC_BUSY 0x1 +#define NV4_PGRAPH_STATUS_FE 5 +#define NV4_PGRAPH_STATUS_FE_IDLE 0x0 +#define NV4_PGRAPH_STATUS_FE_BUSY 0x1 +#define NV4_PGRAPH_STATUS_RASTERIZER 6 +#define NV4_PGRAPH_STATUS_RASTERIZER_IDLE 0x0 +#define NV4_PGRAPH_STATUS_RASTERIZER_BUSY 0x1 +#define NV4_PGRAPH_STATUS_PORT_NOTIFY 8 +#define NV4_PGRAPH_STATUS_PORT_NOTIFY_IDLE 0x0 +#define NV4_PGRAPH_STATUS_PORT_NOTIFY_BUSY 0x1 +#define NV4_PGRAPH_STATUS_PORT_REGISTER 12 +#define NV4_PGRAPH_STATUS_PORT_REGISTER_IDLE 0x0 +#define NV4_PGRAPH_STATUS_PORT_REGISTER_BUSY 0x1 +#define NV4_PGRAPH_STATUS_PORT_DMA 16 +#define NV4_PGRAPH_STATUS_PORT_DMA_IDLE 0x0 +#define NV4_PGRAPH_STATUS_PORT_DMA_BUSY 0x1 +#define NV4_PGRAPH_STATUS_DMA_ENGINE 17 +#define NV4_PGRAPH_STATUS_DMA_ENGINE_IDLE 0x0 +#define NV4_PGRAPH_STATUS_DMA_ENGINE_BUSY 0x1 +#define NV4_PGRAPH_STATUS_DMA_NOTIFY 20 +#define NV4_PGRAPH_STATUS_DMA_NOTIFY_IDLE 0x0 +#define NV4_PGRAPH_STATUS_DMA_NOTIFY_BUSY 0x1 +#define NV4_PGRAPH_STATUS_DMA_BUFFER_NOTIFY 21 +#define NV4_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_IDLE 0x0 +#define NV4_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_BUSY 0x1 +#define NV4_PGRAPH_STATUS_D3D 24 +#define NV4_PGRAPH_STATUS_D3D_IDLE 0x0 +#define NV4_PGRAPH_STATUS_D3D_BUSY 0x1 +#define NV4_PGRAPH_STATUS_CACHE 25 +#define NV4_PGRAPH_STATUS_CACHE_IDLE 0x0 +#define NV4_PGRAPH_STATUS_CACHE_BUSY 0x1 +#define NV4_PGRAPH_STATUS_LIGHTING 26 +#define NV4_PGRAPH_STATUS_LIGHTING_IDLE 0x0 +#define NV4_PGRAPH_STATUS_LIGHTING_BUSY 0x1 +#define NV4_PGRAPH_STATUS_PREROP 27 +#define NV4_PGRAPH_STATUS_PREROP_IDLE 0x0 +#define NV4_PGRAPH_STATUS_PREROP_BUSY 0x1 +#define NV4_PGRAPH_STATUS_ROP 28 +#define NV4_PGRAPH_STATUS_ROP_IDLE 0x0 +#define NV4_PGRAPH_STATUS_ROP_BUSY 0x1 +#define NV4_PGRAPH_STATUS_PORT_USER 29 +#define NV4_PGRAPH_STATUS_PORT_USER_IDLE 0x0 +#define NV4_PGRAPH_STATUS_PORT_USER_BUSY 0x1 +#define NV4_PGRAPH_TRAPPED_ADDR 0x400704 +#define NV4_PGRAPH_TRAPPED_ADDR_MTHD 2 +#define NV4_PGRAPH_TRAPPED_ADDR_SUBCH 13 +#define NV4_PGRAPH_TRAPPED_ADDR_CHID 24 +#define NV4_PGRAPH_TRAPPED_DATA 0x400708 +#define NV4_PGRAPH_TRAPPED_DATA_VALUE 0 +#define NV4_PGRAPH_SURFACE 0x40070C +#define NV4_PGRAPH_SURFACE_TYPE 0 +#define NV4_PGRAPH_SURFACE_TYPE_INVALID 0x0 +#define NV4_PGRAPH_SURFACE_TYPE_NON_SWIZZLE 0x1 +#define NV4_PGRAPH_SURFACE_TYPE_SWIZZLE 0x2 +#define NV4_PGRAPH_NOTIFY 0x400714 +#define NV4_PGRAPH_NOTIFY_BUFFER_REQ 0 +#define NV4_PGRAPH_NOTIFY_BUFFER_REQ_NOT_PENDING 0x0 +#define NV4_PGRAPH_NOTIFY_BUFFER_REQ_PENDING 0x1 +#define NV4_PGRAPH_NOTIFY_BUFFER_STYLE 8 +#define NV4_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_ONLY 0x0 +#define NV4_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_THEN_AWAKEN 0x1 +#define NV4_PGRAPH_NOTIFY_REQ 16 +#define NV4_PGRAPH_NOTIFY_REQ_NOT_PENDING 0x0 +#define NV4_PGRAPH_NOTIFY_REQ_PENDING 0x1 +#define NV4_PGRAPH_NOTIFY_STYLE 20 +#define NV4_PGRAPH_NOTIFY_STYLE_WRITE_ONLY 0x0 +#define NV4_PGRAPH_NOTIFY_STYLE_WRITE_THEN_AWAKEN 0x1 +#define NV4_PGRAPH_BOFFSET(i) (0x400640+(i)*4) +//used for all +#define NV4_PGRAPH_BOFFSET_LINADRS_DEFAULT 0x0 +#define NV4_PGRAPH_BOFFSET_SIZE_1 6 +#define NV4_PGRAPH_BOFFSET_LINADRS 0 +#define NV4_PGRAPH_BOFFSET_LINADRS_0 0x0 +#define NV4_PGRAPH_BOFFSET0 0x400640 +#define NV4_PGRAPH_BOFFSET0_ALIAS_1 NV_PGRAPH_BOFFSET(0) +#define NV4_PGRAPH_BOFFSET0_LINADRS 0 +#define NV4_PGRAPH_BOFFSET1 0x400644 +#define NV4_PGRAPH_BOFFSET1_ALIAS_1 NV_PGRAPH_BOFFSET(1) +#define NV4_PGRAPH_BOFFSET1_LINADRS 0 +#define NV4_PGRAPH_BOFFSET2 0x400648 +#define NV4_PGRAPH_BOFFSET2_ALIAS_1 NV_PGRAPH_BOFFSET(2) +#define NV4_PGRAPH_BOFFSET2_LINADRS 0 +#define NV4_PGRAPH_BOFFSET3 0x40064C +#define NV4_PGRAPH_BOFFSET3_ALIAS_1 NV_PGRAPH_BOFFSET(3) +#define NV4_PGRAPH_BOFFSET3_LINADRS 0 +#define NV4_PGRAPH_BOFFSET4 0x400650 +#define NV4_PGRAPH_BOFFSET4_ALIAS_1 NV_PGRAPH_BOFFSET(4) +#define NV4_PGRAPH_BOFFSET4_LINADRS 0 +#define NV4_PGRAPH_BOFFSET5 0x400654 +#define NV4_PGRAPH_BOFFSET5_ALIAS_1 NV_PGRAPH_BOFFSET(5) +#define NV4_PGRAPH_BOFFSET5_LINADRS 0 +#define NV4_PGRAPH_BBASE(i) (0x400658+(i)*4) +//used for all +#define NV4_PGRAPH_BBASE_LINADRS_DEFAULT 0x0 +#define NV4_PGRAPH_BBASE_SIZE_1 6 +#define NV4_PGRAPH_BBASE_LINADRS 0 +#define NV4_PGRAPH_BBASE0 0x400658 +#define NV4_PGRAPH_BBASE0_ALIAS_1 NV_PGRAPH_BBASE(0) +#define NV4_PGRAPH_BBASE0_LINADRS 0 +#define NV4_PGRAPH_BBASE1 0x40065c +#define NV4_PGRAPH_BBASE1_ALIAS_1 NV_PGRAPH_BBASE(1) +#define NV4_PGRAPH_BBASE1_LINADRS 0 +#define NV4_PGRAPH_BBASE2 0x400660 +#define NV4_PGRAPH_BBASE2_ALIAS_1 NV_PGRAPH_BBASE(2) +#define NV4_PGRAPH_BBASE2_LINADRS 0 +#define NV4_PGRAPH_BBASE3 0x400664 +#define NV4_PGRAPH_BBASE3_ALIAS_1 NV_PGRAPH_BBASE(3) +#define NV4_PGRAPH_BBASE3_LINADRS 0 +#define NV4_PGRAPH_BBASE4 0x400668 +#define NV4_PGRAPH_BBASE4_ALIAS_1 NV_PGRAPH_BBASE(4) +#define NV4_PGRAPH_BBASE4_LINADRS 0 +#define NV4_PGRAPH_BBASE5 0x40066C +#define NV4_PGRAPH_BBASE5_ALIAS_1 NV_PGRAPH_BBASE(5) +#define NV4_PGRAPH_BBASE5_LINADRS 0 +#define NV4_PGRAPH_BPITCH(i) (0x400670+(i)*4) +//used for all +#define NV4_PGRAPH_BPITCH_LINADRS_DEFAULT 0x0 +#define NV4_PGRAPH_BPITCH_SIZE_1 5 +#define NV4_PGRAPH_BPITCH_VALUE 0 // use bit 0 for all +#define NV4_PGRAPH_BPITCH_VALUE_0 0x0 +#define NV4_PGRAPH_BPITCH0 0x400670 +#define NV4_PGRAPH_BPITCH0_ALIAS_1 NV_PGRAPH_BPITCH(0) +#define NV4_PGRAPH_BPITCH1 0x400674 +#define NV4_PGRAPH_BPITCH1_ALIAS_1 NV_PGRAPH_BPITCH(1) +#define NV4_PGRAPH_BPITCH2 0x400678 +#define NV4_PGRAPH_BPITCH2_ALIAS_1 NV_PGRAPH_BPITCH(2) +#define NV4_PGRAPH_BPITCH3 0x40067C +#define NV4_PGRAPH_BPITCH3_ALIAS_1 NV_PGRAPH_BPITCH(3) +#define NV4_PGRAPH_BPITCH4 0x400680 +#define NV4_PGRAPH_BPITCH4_ALIAS_1 NV_PGRAPH_BPITCH(4) +#define NV4_PGRAPH_BLIMIT(i) (0x400684+(i)*4) +//following two used for all +#define NV4_PGRAPH_BLIMIT_SIZE_1 6 +#define NV4_PGRAPH_BLIMIT_VALUE 0 +#define NV4_PGRAPH_BLIMIT_TYPE 31 +#define NV4_PGRAPH_BLIMIT_TYPE_IN_MEMORY 0x0 +#define NV4_PGRAPH_BLIMIT_TYPE_NULL 0x1 +#define NV4_PGRAPH_BLIMIT0 0x400684 +#define NV4_PGRAPH_BLIMIT0_ALIAS_1 NV_PGRAPH_BLIMIT(0) +#define NV4_PGRAPH_BLIMIT1 0x400688 +#define NV4_PGRAPH_BLIMIT1_ALIAS_1 NV_PGRAPH_BLIMIT(1) +#define NV4_PGRAPH_BLIMIT2 0x40068c +#define NV4_PGRAPH_BLIMIT2_ALIAS_1 NV_PGRAPH_BLIMIT(2) +#define NV4_PGRAPH_BLIMIT3 0x400690 +#define NV4_PGRAPH_BLIMIT3_ALIAS_1 NV_PGRAPH_BLIMIT(3) +#define NV4_PGRAPH_BLIMIT4 0x400694 +#define NV4_PGRAPH_BLIMIT4_ALIAS_1 NV_PGRAPH_BLIMIT(4) +#define NV4_PGRAPH_BLIMIT5 0x400698 +#define NV4_PGRAPH_BLIMIT5_ALIAS_1 NV_PGRAPH_BLIMIT(5) +#define NV4_PGRAPH_BSWIZZLE2 0x40069c +#define NV4_PGRAPH_BSWIZZLE2_WIDTH 16 +#define NV4_PGRAPH_BSWIZZLE2_WIDTH_0 0x0 +#define NV4_PGRAPH_BSWIZZLE2_HEIGHT 24 +#define NV4_PGRAPH_BSWIZZLE2_HEIGHT_0 0x0 +#define NV4_PGRAPH_BSWIZZLE5 0x4006a0 +#define NV4_PGRAPH_BSWIZZLE5_WIDTH 16 +#define NV4_PGRAPH_BSWIZZLE5_WIDTH_0 0x0 +#define NV4_PGRAPH_BSWIZZLE5_HEIGHT 24 +#define NV4_PGRAPH_BSWIZZLE5_HEIGHT_0 0x0 +#define NV4_PGRAPH_BPIXEL 0x400724 +#define NV4_PGRAPH_BPIXEL_DEPTH0 0 +#define NV4_PGRAPH_BPIXEL_DEPTH1 4 +#define NV4_PGRAPH_BPIXEL_DEPTH2 8 +#define NV4_PGRAPH_BPIXEL_DEPTH3 12 +#define NV4_PGRAPH_BPIXEL_DEPTH4 16 +#define NV4_PGRAPH_BPIXEL_DEPTH5 20 + +// valid for depth0-depth5 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_INVALID 0x0 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_Y8 0x1 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X1R5G5B5_Z1R5G5B5 0x2 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X1R5G5B5_O1R5G5B5 0x3 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_A1R5G5B5 0x4 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_R5G6B5 0x5 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_Y16 0x6 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X8R8G8B8_Z8R8G8B8 0x7 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X8R8G8B8_O1Z7R8G8B8 0x8 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X1A7R8G8B8_Z1A7R8G8B8 0x9 +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X1A7R8G8B8_O1A7R8G8B8 0xA +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_X8R8G8B8_O8R8G8B8 0xB +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_A8R8G8B8 0xC +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_Y32 0xD +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_V8YB8U8YA8 0xE +#define NV4_PGRAPH_BPIXEL_DEPTH_FORMAT_YB8V8YA8U8 0xF + +#define NV4_PGRAPH_LIMIT_VIOL_PIX 0x400610 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_ADRS 0 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_ADRS_0 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_BLIT 29 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_BLIT_NO_VIOL 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_BLIT_VIOL 0x1 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_LIMIT 30 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_LIMIT_NO_VIOL 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_LIMIT_VIOL 0x1 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_OVRFLW 31 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_NO_VIOL 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_VIOL 0x1 +#define NV4_PGRAPH_LIMIT_VIOL_Z 0x400614 +#define NV4_PGRAPH_LIMIT_VIOL_Z_ADRS 0 +#define NV4_PGRAPH_LIMIT_VIOL_Z_ADRS_0 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_Z_LIMIT 30 +#define NV4_PGRAPH_LIMIT_VIOL_Z_LIMIT_NO_VIOL 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_Z_LIMIT_VIOL 0x1 +#define NV4_PGRAPH_LIMIT_VIOL_Z_OVRFLW 31 +#define NV4_PGRAPH_LIMIT_VIOL_Z_OVRFLW_NO_VIOL 0x0 +#define NV4_PGRAPH_LIMIT_VIOL_Z_OVRFLW_VIOL 0x1 +#define NV4_PGRAPH_STATE 0x400710 +#define NV4_PGRAPH_STATE_BUFFER_0 0 +#define NV4_PGRAPH_STATE_BUFFER_0_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_0_VALID 0x1 +#define NV4_PGRAPH_STATE_BUFFER_1 1 +#define NV4_PGRAPH_STATE_BUFFER_1_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_1_VALID 0x1 +#define NV4_PGRAPH_STATE_BUFFER_2 2 +#define NV4_PGRAPH_STATE_BUFFER_2_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_2_VALID 0x1 +#define NV4_PGRAPH_STATE_BUFFER_3 3 +#define NV4_PGRAPH_STATE_BUFFER_3_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_3_VALID 0x1 +#define NV4_PGRAPH_STATE_BUFFER_4 4 +#define NV4_PGRAPH_STATE_BUFFER_4_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_4_VALID 0x1 +#define NV4_PGRAPH_STATE_BUFFER_5 5 +#define NV4_PGRAPH_STATE_BUFFER_5_INVALID 0x0 +#define NV4_PGRAPH_STATE_BUFFER_5_VALID 0x1 +#define NV4_PGRAPH_STATE_PITCH_0 8 +#define NV4_PGRAPH_STATE_PITCH_0_INVALID 0x0 +#define NV4_PGRAPH_STATE_PITCH_0_VALID 0x1 +#define NV4_PGRAPH_STATE_PITCH_1 9 +#define NV4_PGRAPH_STATE_PITCH_1_INVALID 0x0 +#define NV4_PGRAPH_STATE_PITCH_1_VALID 0x1 +#define NV4_PGRAPH_STATE_PITCH_2 10 +#define NV4_PGRAPH_STATE_PITCH_2_INVALID 0x0 +#define NV4_PGRAPH_STATE_PITCH_2_VALID 0x1 +#define NV4_PGRAPH_STATE_PITCH_3 11 +#define NV4_PGRAPH_STATE_PITCH_3_INVALID 0x0 +#define NV4_PGRAPH_STATE_PITCH_3_VALID 0x1 +#define NV4_PGRAPH_STATE_PITCH_4 12 +#define NV4_PGRAPH_STATE_PITCH_4_INVALID 0x0 +#define NV4_PGRAPH_STATE_PITCH_4_VALID 0x1 +#define NV4_PGRAPH_STATE_CHROMA_COLOR 16 +#define NV4_PGRAPH_STATE_CHROMA_COLOR_INVALID 0x0 +#define NV4_PGRAPH_STATE_CHROMA_COLOR_VALID 0x1 +#define NV4_PGRAPH_STATE_CHROMA_COLORFMT 17 +#define NV4_PGRAPH_STATE_CHROMA_COLORFMT_INVALID 0x0 +#define NV4_PGRAPH_STATE_CHROMA_COLORFMT_VALID 0x1 +#define NV4_PGRAPH_STATE_CPATTERN_COLORFMT 20 +#define NV4_PGRAPH_STATE_CPATTERN_COLORFMT_INVALID 0x0 +#define NV4_PGRAPH_STATE_CPATTERN_COLORFMT_VALID 0x1 +#define NV4_PGRAPH_STATE_CPATTERN_MONOFMT 21 +#define NV4_PGRAPH_STATE_CPATTERN_MONOFMT_INVALID 0x0 +#define NV4_PGRAPH_STATE_CPATTERN_MONOFMT_VALID 0x1 +#define NV4_PGRAPH_STATE_CPATTERN_SELECT 22 +#define NV4_PGRAPH_STATE_CPATTERN_SELECT_INVALID 0x0 +#define NV4_PGRAPH_STATE_CPATTERN_SELECT_VALID 0x1 +#define NV4_PGRAPH_STATE_PATTERN_COLOR0 24 +#define NV4_PGRAPH_STATE_PATTERN_COLOR0_INVALID 0x0 +#define NV4_PGRAPH_STATE_PATTERN_COLOR0_VALID 0x1 +#define NV4_PGRAPH_STATE_PATTERN_COLOR1 25 +#define NV4_PGRAPH_STATE_PATTERN_COLOR1_INVALID 0x0 +#define NV4_PGRAPH_STATE_PATTERN_COLOR1_VALID 0x1 +#define NV4_PGRAPH_STATE_PATTERN_PATT0 26 +#define NV4_PGRAPH_STATE_PATTERN_PATT0_INVALID 0x0 +#define NV4_PGRAPH_STATE_PATTERN_PATT0_VALID 0x1 +#define NV4_PGRAPH_STATE_PATTERN_PATT1 27 +#define NV4_PGRAPH_STATE_PATTERN_PATT1_INVALID 0x0 +#define NV4_PGRAPH_STATE_PATTERN_PATT1_VALID 0x1 +#define NV4_PGRAPH_CACHE_INDEX 0x400728 +#define NV4_PGRAPH_CACHE_INDEX_BANK 2 +#define NV4_PGRAPH_CACHE_INDEX_BANK_10 0x0 +#define NV4_PGRAPH_CACHE_INDEX_BANK_32 0x1 +#define NV4_PGRAPH_CACHE_INDEX_ADRS 3 +#define NV4_PGRAPH_CACHE_INDEX_ADRS_0 0x0 +#define NV4_PGRAPH_CACHE_INDEX_ADRS_1024 0x400 +#define NV4_PGRAPH_CACHE_INDEX_OP 13 +#define NV4_PGRAPH_CACHE_INDEX_OP_WR_CACHE 0x0 +#define NV4_PGRAPH_CACHE_INDEX_OP_RD_CACHE 0x1 +#define NV4_PGRAPH_CACHE_INDEX_OP_RD_INDEX 0x2 +#define NV4_PGRAPH_CACHE_RAM 0x40072c +#define NV4_PGRAPH_CACHE_RAM_VALUE 0 +#define NV4_PGRAPH_DMA_PITCH 0x400760 +#define NV4_PGRAPH_DMA_PITCH_S0 0 +#define NV4_PGRAPH_DMA_PITCH_S1 16 +#define NV4_PGRAPH_DVD_COLORFMT 0x400764 +#define NV4_PGRAPH_DVD_COLORFMT_IMAGE 0 +#define NV4_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_INVALID 0x00 +#define NV4_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_V8YB8U8YA8 0x12 +#define NV4_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_YB8V8YA8U8 0x13 +#define NV4_PGRAPH_DVD_COLORFMT_OVLY 8 +#define NV4_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_INVALID 0x00 +#define NV4_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A8Y8U8V8 0x01 +#define NV4_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A4V6YB6A4U6YA6 0x02 +#define NV4_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_TRANSPARENT 0x03 +#define NV4_PGRAPH_SCALED_FORMAT 0x400768 +#define NV4_PGRAPH_SCALED_FORMAT_ORIGIN 16 +#define NV4_PGRAPH_SCALED_FORMAT_ORIGIN_INVALID 0x0 +#define NV4_PGRAPH_SCALED_FORMAT_ORIGIN_CENTER 0x1 +#define NV4_PGRAPH_SCALED_FORMAT_ORIGIN_CORNER 0x2 +#define NV4_PGRAPH_SCALED_FORMAT_INTERPOLATOR 24 +#define NV4_PGRAPH_SCALED_FORMAT_INTERPOLATOR_ZOH 0x0 +#define NV4_PGRAPH_SCALED_FORMAT_INTERPOLATOR_FOH 0x1 +#define NV4_PGRAPH_PATT_COLOR0 0x400800 +#define NV4_PGRAPH_PATT_COLOR0_VALUE 0 +#define NV4_PGRAPH_PATT_COLOR1 0x400804 +#define NV4_PGRAPH_PATT_COLOR1_VALUE 0 +#define NV4_PGRAPH_PATT_COLORRAM(i) (0x400900+(i)*4) +#define NV4_PGRAPH_PATT_COLORRAM_SIZE_1 64 +#define NV4_PGRAPH_PATT_COLORRAM_VALUE 0 +#define NV4_PGRAPH_PATTERN(i) (0x400808+(i)*4) +#define NV4_PGRAPH_PATTERN_SIZE_1 2 +#define NV4_PGRAPH_PATTERN_BITMAP 0 +#define NV4_PGRAPH_PATTERN_SHAPE 0x400810 +#define NV4_PGRAPH_PATTERN_SHAPE_VALUE 0 +#define NV4_PGRAPH_PATTERN_SHAPE_VALUE_8X_8Y 0x0 +#define NV4_PGRAPH_PATTERN_SHAPE_VALUE_64X_1Y 0x1 +#define NV4_PGRAPH_PATTERN_SHAPE_VALUE_1X_64Y 0x2 +#define NV4_PGRAPH_PATTERN_SHAPE_SELECT 4 +#define NV4_PGRAPH_PATTERN_SHAPE_SELECT_2COLOR 0x0 +#define NV4_PGRAPH_PATTERN_SHAPE_SELECT_FULLCOLOR 0x1 +#define NV4_PGRAPH_MONO_COLOR0 0x400600 +#define NV4_PGRAPH_MONO_COLOR0_VALUE 0 +#define NV4_PGRAPH_ROP3 0x400604 +#define NV4_PGRAPH_ROP3_VALUE 0 +#define NV4_PGRAPH_CHROMA 0x400814 +#define NV4_PGRAPH_CHROMA_VALUE 0 +#define NV4_PGRAPH_BETA_AND 0x400608 +#define NV4_PGRAPH_BETA_AND_VALUE_FRACTION 23 +#define NV4_PGRAPH_BETA_PREMULT 0x40060c +#define NV4_PGRAPH_BETA_PREMULT_VALUE 0 +#define NV4_PGRAPH_CONTROL0 0x400818 +#define NV4_PGRAPH_CONTROL0_ALPHAREF 0 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC 8 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_NEVER 0x1 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_LESS 0x2 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_EQUAL 0x3 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_LESSEQUAL 0x4 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_GREATER 0x5 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_NOTEQUAL 0x6 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_GREATEREQUAL 0x7 +#define NV4_PGRAPH_CONTROL0_ALPHAFUNC_ALWAYS 0x8 +#define NV4_PGRAPH_CONTROL0_ALPHATESTENABLE 12 +#define NV4_PGRAPH_CONTROL0_ALPHATESTENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_ZENABLE 14 +#define NV4_PGRAPH_CONTROL0_ZENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_ZENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_ZFUNC 16 +#define NV4_PGRAPH_CONTROL0_ZFUNC_NEVER 0x1 +#define NV4_PGRAPH_CONTROL0_ZFUNC_LESS 0x2 +#define NV4_PGRAPH_CONTROL0_ZFUNC_EQUAL 0x3 +#define NV4_PGRAPH_CONTROL0_ZFUNC_LESSEQUAL 0x4 +#define NV4_PGRAPH_CONTROL0_ZFUNC_GREATER 0x5 +#define NV4_PGRAPH_CONTROL0_ZFUNC_NOTEQUAL 0x6 +#define NV4_PGRAPH_CONTROL0_ZFUNC_GREATEREQUAL 0x7 +#define NV4_PGRAPH_CONTROL0_ZFUNC_ALWAYS 0x8 +#define NV4_PGRAPH_CONTROL0_CULLMODE 20 +#define NV4_PGRAPH_CONTROL0_CULLMODE_NONE 0x1 +#define NV4_PGRAPH_CONTROL0_CULLMODE_CW 0x2 +#define NV4_PGRAPH_CONTROL0_CULLMODE_CCW 0x3 +#define NV4_PGRAPH_CONTROL0_DITHERENABLE 22 +#define NV4_PGRAPH_CONTROL0_DITHERENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_DITHERENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_Z_PERSPECTIVE_ENABLE 23 +#define NV4_PGRAPH_CONTROL0_Z_PERSPECTIVE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_Z_PERSPECTIVE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_ZWRITEENABLE 24 +#define NV4_PGRAPH_CONTROL0_ZWRITEENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_ZWRITEENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_STENCIL_WRITE_ENABLE 25 +#define NV4_PGRAPH_CONTROL0_STENCIL_WRITE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_STENCIL_WRITE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_ALPHA_WRITE_ENABLE 26 +#define NV4_PGRAPH_CONTROL0_ALPHA_WRITE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_ALPHA_WRITE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_RED_WRITE_ENABLE 27 +#define NV4_PGRAPH_CONTROL0_RED_WRITE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_RED_WRITE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_GREEN_WRITE_ENABLE 28 +#define NV4_PGRAPH_CONTROL0_GREEN_WRITE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_GREEN_WRITE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_BLUE_WRITE_ENABLE 29 +#define NV4_PGRAPH_CONTROL0_BLUE_WRITE_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL0_BLUE_WRITE_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL0_Z_FORMAT 30 +#define NV4_PGRAPH_CONTROL0_Z_FORMAT_FIXED 0x1 +#define NV4_PGRAPH_CONTROL0_Z_FORMAT_FLOAT 0x2 +#define NV4_PGRAPH_CONTROL1 0x40081c +#define NV4_PGRAPH_CONTROL1_STENCIL_TEST_ENABLE 0 +#define NV4_PGRAPH_CONTROL1_STENCIL_TEST_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_CONTROL1_STENCIL_TEST_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC 4 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_NEVER 0x1 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_LESS 0x2 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_EQUAL 0x3 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_LESSEQUAL 0x4 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_GREATER 0x5 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_NOTEQUAL 0x6 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_GREATEREQUAL 0x7 +#define NV4_PGRAPH_CONTROL1_STENCIL_FUNC_ALWAYS 0x8 +#define NV4_PGRAPH_CONTROL1_STENCIL_REF 8 +#define NV4_PGRAPH_CONTROL1_STENCIL_MASK_READ 16 +#define NV4_PGRAPH_CONTROL1_STENCIL_MASK_WRITE 24 +#define NV4_PGRAPH_CONTROL2 0x400820 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL 0 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_KEEP 0x1 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_ZERO 0x2 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_REPLACE 0x3 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_INCRSAT 0x4 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_DECRSAT 0x5 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_INVERT 0x6 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_INCR 0x7 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_FAIL_DECR 0x8 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL 4 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_KEEP 0x1 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_ZERO 0x2 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_REPLACE 0x3 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_INCRSAT 0x4 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_DECRSAT 0x5 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_INVERT 0x6 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_INCR 0x7 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZFAIL_DECR 0x8 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS 8 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_KEEP 0x1 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_ZERO 0x2 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_REPLACE 0x3 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_INCRSAT 0x4 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_DECRSAT 0x5 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_INVERT 0x6 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_INCR 0x7 +#define NV4_PGRAPH_CONTROL2_STENCIL_OP_ZPASS_DECR 0x8 +#define NV4_PGRAPH_BLEND 0x400824 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND 0 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_DECAL 0x1 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_MODULATE 0x2 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_DECALALPHA 0x3 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_MODULATEALPHA 0x4 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_DECALMASK 0x5 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_MODULATEMASK 0x6 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_COPY 0x7 +#define NV4_PGRAPH_BLEND_TEXTUREMAPBLEND_ADD 0x8 +#define NV4_PGRAPH_BLEND_MASK_BIT 4 +#define NV4_PGRAPH_BLEND_MASK_BIT_LSB 0x1 +#define NV4_PGRAPH_BLEND_MASK_BIT_MSB 0x2 +#define NV4_PGRAPH_BLEND_SHADEMODE 6 +#define NV4_PGRAPH_BLEND_SHADEMODE_FLAT 0x1 +#define NV4_PGRAPH_BLEND_SHADEMODE_GOURAUD 0x2 +#define NV4_PGRAPH_BLEND_SHADEMODE_PHONG 0x3 +#define NV4_PGRAPH_BLEND_TEXTUREPERSPECTIVE 8 +#define NV4_PGRAPH_BLEND_TEXTUREPERSPECTIVE_TRUE 0x1 +#define NV4_PGRAPH_BLEND_SPECULARENABLE 12 +#define NV4_PGRAPH_BLEND_SPECULARENABLE_TRUE 0x1 +#define NV4_PGRAPH_BLEND_FOGENABLE 16 +#define NV4_PGRAPH_BLEND_FOGENABLE_TRUE 0x1 +#define NV4_PGRAPH_BLEND_ALPHABLENDENABLE 20 +#define NV4_PGRAPH_BLEND_ALPHABLENDENABLE_TRUE 0x1 +#define NV4_PGRAPH_BLEND_SRCBLEND 24 +#define NV4_PGRAPH_BLEND_SRCBLEND_ZERO 0x1 +#define NV4_PGRAPH_BLEND_SRCBLEND_ONE 0x2 +#define NV4_PGRAPH_BLEND_SRCBLEND_SRCCOLOR 0x3 +#define NV4_PGRAPH_BLEND_SRCBLEND_INVSRCCOLOR 0x4 +#define NV4_PGRAPH_BLEND_SRCBLEND_SRCALPHA 0x5 +#define NV4_PGRAPH_BLEND_SRCBLEND_INVSRCALPHA 0x6 +#define NV4_PGRAPH_BLEND_SRCBLEND_DESTALPHA 0x7 +#define NV4_PGRAPH_BLEND_SRCBLEND_INVDESTALPHA 0x8 +#define NV4_PGRAPH_BLEND_SRCBLEND_DESTCOLOR 0x9 +#define NV4_PGRAPH_BLEND_SRCBLEND_INVDESTCOLOR 0xA +#define NV4_PGRAPH_BLEND_SRCBLEND_SRCALPHASAT 0xB +#define NV4_PGRAPH_BLEND_SRCBLEND_INVSRCALPHASAT 0xC +#define NV4_PGRAPH_BLEND_SRCBLEND_BETA 0xD +#define NV4_PGRAPH_BLEND_DESTBLEND 28 +#define NV4_PGRAPH_BLEND_DESTBLEND_ZERO 0x1 +#define NV4_PGRAPH_BLEND_DESTBLEND_ONE 0x2 +#define NV4_PGRAPH_BLEND_DESTBLEND_SRCCOLOR 0x3 +#define NV4_PGRAPH_BLEND_DESTBLEND_INVSRCCOLOR 0x4 +#define NV4_PGRAPH_BLEND_DESTBLEND_SRCALPHA 0x5 +#define NV4_PGRAPH_BLEND_DESTBLEND_INVSRCALPHA 0x6 +#define NV4_PGRAPH_BLEND_DESTBLEND_DESTALPHA 0x7 +#define NV4_PGRAPH_BLEND_DESTBLEND_INVDESTALPHA 0x8 +#define NV4_PGRAPH_BLEND_DESTBLEND_DESTCOLOR 0x9 +#define NV4_PGRAPH_BLEND_DESTBLEND_INVDESTCOLOR 0xA +#define NV4_PGRAPH_BLEND_DESTBLEND_SRCALPHASAT 0xB +#define NV4_PGRAPH_DPRAM_INDEX 0x400828 +#define NV4_PGRAPH_DPRAM_INDEX_ADRS 0 +#define NV4_PGRAPH_DPRAM_INDEX_ADRS_0 0x0 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT 8 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_ADRS_0 0x0 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_ADRS_1 0x1 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_DATA_0 0x2 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_DATA_1 0x3 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_WE_0 0x4 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_WE_1 0x5 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_0 0x6 +#define NV4_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_1 0x7 +#define NV4_PGRAPH_DPRAM_DATA 0x40082c +#define NV4_PGRAPH_DPRAM_DATA_VALUE 0 +#define NV4_PGRAPH_DPRAM_ADRS_0 0x40082c +#define NV4_PGRAPH_DPRAM_ADRS_0_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_ADRS_0_VALUE 0 +#define NV4_PGRAPH_DPRAM_ADRS_1 0x40082c +#define NV4_PGRAPH_DPRAM_ADRS_1_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_ADRS_1_VALUE 0 +#define NV4_PGRAPH_DPRAM_DATA_0 0x40082c +#define NV4_PGRAPH_DPRAM_DATA_0_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_DATA_0_VALUE 0 +#define NV4_PGRAPH_DPRAM_DATA_1 0x40082c +#define NV4_PGRAPH_DPRAM_DATA_1_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_DATA_1_VALUE 0 +#define NV4_PGRAPH_DPRAM_WE_0 0x40082c +#define NV4_PGRAPH_DPRAM_WE_0_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_WE_0_VALUE 0 +#define NV4_PGRAPH_DPRAM_WE_1 0x40082c +#define NV4_PGRAPH_DPRAM_WE_1_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_WE_1_VALUE 0 +#define NV4_PGRAPH_DPRAM_ALPHA_0 0x40082c +#define NV4_PGRAPH_DPRAM_ALPHA_0_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_ALPHA_0_VALUE 0 +#define NV4_PGRAPH_DPRAM_ALPHA_1 0x40082c +#define NV4_PGRAPH_DPRAM_ALPHA_1_ALIAS_1 NV_PGRAPH_DPRAM_DATA +#define NV4_PGRAPH_DPRAM_ALPHA_1_VALUE 0 +#define NV4_PGRAPH_STORED_FMT 0x400830 +#define NV4_PGRAPH_STORED_FMT_MONO0 0 +#define NV4_PGRAPH_STORED_FMT_PATT0 8 +#define NV4_PGRAPH_STORED_FMT_PATT1 16 +#define NV4_PGRAPH_STORED_FMT_CHROMA 24 +#define NV4_PGRAPH_FORMATS 0x400618 +#define NV4_PGRAPH_FORMATS_ROP 0 +#define NV4_PGRAPH_FORMATS_ROP_Y8 0x0 +#define NV4_PGRAPH_FORMATS_ROP_RGB15 0x1 +#define NV4_PGRAPH_FORMATS_ROP_RGB16 0x2 +#define NV4_PGRAPH_FORMATS_ROP_Y16 0x3 +#define NV4_PGRAPH_FORMATS_ROP_INVALID 0x4 +#define NV4_PGRAPH_FORMATS_ROP_RGB24 0x5 +#define NV4_PGRAPH_FORMATS_ROP_RGB30 0x6 +#define NV4_PGRAPH_FORMATS_ROP_Y32 0x7 +#define NV4_PGRAPH_FORMATS_SRC 4 +#define NV4_PGRAPH_FORMATS_SRC_INVALID 0x0 +#define NV4_PGRAPH_FORMATS_SRC_LE_Y8 0x1 +#define NV4_PGRAPH_FORMATS_SRC_LE_X16A8Y8 0x2 +#define NV4_PGRAPH_FORMATS_SRC_LE_X24Y8 0x3 +#define NV4_PGRAPH_FORMATS_SRC_LE_A1R5G5B5 0x6 +#define NV4_PGRAPH_FORMATS_SRC_LE_X1R5G5B5 0x7 +#define NV4_PGRAPH_FORMATS_SRC_LE_X16A1R5G5B5 0x8 +#define NV4_PGRAPH_FORMATS_SRC_LE_X17R5G5B5 0x9 +#define NV4_PGRAPH_FORMATS_SRC_LE_R5G6B5 0xA +#define NV4_PGRAPH_FORMATS_SRC_LE_A16R5G6B5 0xB +#define NV4_PGRAPH_FORMATS_SRC_LE_X16R5G6B5 0xC +#define NV4_PGRAPH_FORMATS_SRC_LE_A8R8G8B8 0xD +#define NV4_PGRAPH_FORMATS_SRC_LE_X8R8G8B8 0xE +#define NV4_PGRAPH_FORMATS_SRC_LE_Y16 0xF +#define NV4_PGRAPH_FORMATS_SRC_LE_A16Y16 0x10 +#define NV4_PGRAPH_FORMATS_SRC_LE_X16Y16 0x11 +#define NV4_PGRAPH_FORMATS_SRC_LE_V8YB8U8YA8 0x12 +#define NV4_PGRAPH_FORMATS_SRC_LE_YB8V8YA8U8 0x13 +#define NV4_PGRAPH_FORMATS_SRC_LE_Y32 0x14 +#define NV4_PGRAPH_FORMATS_FB 12 +#define NV4_PGRAPH_FORMATS_FB_INVALID 0x0 +#define NV4_PGRAPH_FORMATS_FB_Y8 0x1 +#define NV4_PGRAPH_FORMATS_FB_X1R5G5B5_Z1R5G5B5 0x2 +#define NV4_PGRAPH_FORMATS_FB_X1R5G5B5_O1R5G5B5 0x3 +#define NV4_PGRAPH_FORMATS_FB_A1R5G5B5 0x4 +#define NV4_PGRAPH_FORMATS_FB_R5G6B5 0x5 +#define NV4_PGRAPH_FORMATS_FB_Y16 0x6 +#define NV4_PGRAPH_FORMATS_FB_X8R8G8B8_Z8R8G8B8 0x7 +#define NV4_PGRAPH_FORMATS_FB_X8R8G8B8_O1Z7R8G8B8 0x8 +#define NV4_PGRAPH_FORMATS_FB_X1A7R8G8B8_Z1A7R8G8B8 0x9 +#define NV4_PGRAPH_FORMATS_FB_X1A7R8G8B8_O1A7R8G8B8 0xA +#define NV4_PGRAPH_FORMATS_FB_X8R8G8B8_O8R8G8B8 0xB +#define NV4_PGRAPH_FORMATS_FB_A8R8G8B8 0xC +#define NV4_PGRAPH_FORMATS_FB_Y32 0xD +#define NV4_PGRAPH_FORMATS_FB_V8YB8U8YA8 0xE +#define NV4_PGRAPH_FORMATS_FB_YB8V8YA8U8 0xF +#define NV4_PGRAPH_ABS_X_RAM(i) (0x400400+(i)*4) +#define NV4_PGRAPH_ABS_X_RAM_SIZE_1 32 +#define NV4_PGRAPH_ABS_X_RAM_VALUE 0 +#define NV4_PGRAPH_X_RAM_BPORT(i) (0x400c00+(i)*4) +#define NV4_PGRAPH_X_RAM_BPORT_SIZE_1 32 +#define NV4_PGRAPH_X_RAM_BPORT_VALUE 0 +#define NV4_PGRAPH_ABS_Y_RAM(i) (0x400480+(i)*4) +#define NV4_PGRAPH_ABS_Y_RAM_SIZE_1 32 +#define NV4_PGRAPH_ABS_Y_RAM_VALUE 0 +#define NV4_PGRAPH_Y_RAM_BPORT(i) (0x400c80+(i)*4) +#define NV4_PGRAPH_Y_RAM_BPORT_SIZE_1 32 +#define NV4_PGRAPH_Y_RAM_BPORT_VALUE 0 +#define NV4_PGRAPH_XY_LOGIC_MISC0 0x400514 +#define NV4_PGRAPH_XY_LOGIC_MISC0_COUNTER 0 +#define NV4_PGRAPH_XY_LOGIC_MISC0_COUNTER_0 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC0_DIMENSION 20 +#define NV4_PGRAPH_XY_LOGIC_MISC0_DIMENSION_NONZERO 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC0_DIMENSION_ZERO 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC0_INDEX 28 +#define NV4_PGRAPH_XY_LOGIC_MISC0_INDEX_0 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1 0x400518 +#define NV4_PGRAPH_XY_LOGIC_MISC1_INITIAL 0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_INITIAL_NEEDED 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_INITIAL_DONE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX 4 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NOTNULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NULL 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY 5 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NOTNULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NULL 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX 12 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_UUMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX 16 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_UUMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA 20 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_CLIPMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2 0x40051C +#define NV4_PGRAPH_XY_LOGIC_MISC2_HANDOFF 0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_HANDOFF_DISABLE 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_HANDOFF_ENABLE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX 4 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NOTNULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NULL 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY 5 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NOTNULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NULL 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX 12 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_UCMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX 16 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_UCMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA 20 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_CLIPMAX 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_IMAGEMAX 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC3 0x400520 +#define NV4_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0 0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_NULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_TRUE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY 4 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_NULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_TRUE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX 8 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_NULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_TRUE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG 12 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_NULL 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_TRUE 0x1 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX 16 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX_0 0x0 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX 24 +#define NV4_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX_0 0x0 +#define NV4_PGRAPH_X_MISC 0x400500 +#define NV4_PGRAPH_X_MISC_BIT33_0 0 +#define NV4_PGRAPH_X_MISC_BIT33_0_0 0x0 +#define NV4_PGRAPH_X_MISC_BIT33_1 1 +#define NV4_PGRAPH_X_MISC_BIT33_1_0 0x0 +#define NV4_PGRAPH_X_MISC_BIT33_2 2 +#define NV4_PGRAPH_X_MISC_BIT33_2_0 0x0 +#define NV4_PGRAPH_X_MISC_BIT33_3 3 +#define NV4_PGRAPH_X_MISC_BIT33_3_0 0x0 +#define NV4_PGRAPH_X_MISC_RANGE_0 4 +#define NV4_PGRAPH_X_MISC_RANGE_0_0 0x0 +#define NV4_PGRAPH_X_MISC_RANGE_1 5 +#define NV4_PGRAPH_X_MISC_RANGE_1_0 0x0 +#define NV4_PGRAPH_X_MISC_RANGE_2 6 +#define NV4_PGRAPH_X_MISC_RANGE_2_0 0x0 +#define NV4_PGRAPH_X_MISC_RANGE_3 7 +#define NV4_PGRAPH_X_MISC_RANGE_3_0 0x0 +#define NV4_PGRAPH_X_MISC_ADDER_OUTPUT 28 +#define NV4_PGRAPH_X_MISC_ADDER_OUTPUT_EQ_0 0x0 +#define NV4_PGRAPH_X_MISC_ADDER_OUTPUT_LT_0 0x1 +#define NV4_PGRAPH_X_MISC_ADDER_OUTPUT_GT_0 0x2 +#define NV4_PGRAPH_Y_MISC 0x400504 +#define NV4_PGRAPH_Y_MISC_BIT33_0 0 +#define NV4_PGRAPH_Y_MISC_BIT33_0_0 0x0 +#define NV4_PGRAPH_Y_MISC_BIT33_1 1 +#define NV4_PGRAPH_Y_MISC_BIT33_1_0 0x0 +#define NV4_PGRAPH_Y_MISC_BIT33_2 2 +#define NV4_PGRAPH_Y_MISC_BIT33_2_0 0x0 +#define NV4_PGRAPH_Y_MISC_BIT33_3 3 +#define NV4_PGRAPH_Y_MISC_BIT33_3_0 0x0 +#define NV4_PGRAPH_Y_MISC_RANGE_0 4 +#define NV4_PGRAPH_Y_MISC_RANGE_0_0 0x0 +#define NV4_PGRAPH_Y_MISC_RANGE_1 5 +#define NV4_PGRAPH_Y_MISC_RANGE_1_0 0x0 +#define NV4_PGRAPH_Y_MISC_RANGE_2 6 +#define NV4_PGRAPH_Y_MISC_RANGE_2_0 0x0 +#define NV4_PGRAPH_Y_MISC_RANGE_3 7 +#define NV4_PGRAPH_Y_MISC_RANGE_3_0 0x0 +#define NV4_PGRAPH_Y_MISC_ADDER_OUTPUT 28 +#define NV4_PGRAPH_Y_MISC_ADDER_OUTPUT_EQ_0 0x0 +#define NV4_PGRAPH_Y_MISC_ADDER_OUTPUT_LT_0 0x1 +#define NV4_PGRAPH_Y_MISC_ADDER_OUTPUT_GT_0 0x2 +#define NV4_PGRAPH_ABS_UCLIP_XMIN 0x40053C +#define NV4_PGRAPH_ABS_UCLIP_XMIN_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIP_XMAX 0x400544 +#define NV4_PGRAPH_ABS_UCLIP_XMAX_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIP_YMIN 0x400540 +#define NV4_PGRAPH_ABS_UCLIP_YMIN_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIP_YMAX 0x400548 +#define NV4_PGRAPH_ABS_UCLIP_YMAX_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIPA_XMIN 0x400560 +#define NV4_PGRAPH_ABS_UCLIPA_XMIN_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIPA_XMAX 0x400568 +#define NV4_PGRAPH_ABS_UCLIPA_XMAX_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIPA_YMIN 0x400564 +#define NV4_PGRAPH_ABS_UCLIPA_YMIN_VALUE 0 +#define NV4_PGRAPH_ABS_UCLIPA_YMAX 0x40056C +#define NV4_PGRAPH_ABS_UCLIPA_YMAX_VALUE 0 +#define NV4_PGRAPH_SOURCE_COLOR 0x40050C +#define NV4_PGRAPH_SOURCE_COLOR_VALUE 0 +#define NV4_PGRAPH_SOURCE_COLOR_VALUE_0 0x0 +#define NV4_PGRAPH_VALID1 0x400508 +#define NV4_PGRAPH_VALID1_VLD 0 +#define NV4_PGRAPH_VALID1_VLD_0 0x0 +#define NV4_PGRAPH_VALID1_VLD_NOCLIP (0x1<<19) +#define NV4_PGRAPH_VALID1_VLD_SRCCOLOR (0x1<<16) +#define NV4_PGRAPH_VALID1_VLD_GOTMOVE (0x1<<21) +#define NV4_PGRAPH_VALID1_VLD_GOTX01 (0x3<<0) +#define NV4_PGRAPH_VALID1_VLD_GOTX02 (0x7<<0) +#define NV4_PGRAPH_VALID1_VLD_GOTX03 (0xF<<0) +#define NV4_PGRAPH_VALID1_VLD_GOTXCHAIN01 (0x3<<4) +#define NV4_PGRAPH_VALID1_VLD_GOTXCHAIN02 (0x7<<4) +#define NV4_PGRAPH_VALID1_VLD_GOTXCHAIN03 (0xF<<4) +#define NV4_PGRAPH_VALID1_VLD_GOTY01 (0x3<<8) +#define NV4_PGRAPH_VALID1_VLD_GOTY02 (0x7<<8) +#define NV4_PGRAPH_VALID1_VLD_GOTY03 (0xF<<8) +#define NV4_PGRAPH_VALID1_VLD_GOTYCHAIN01 (0x3<<12) +#define NV4_PGRAPH_VALID1_VLD_GOTYCHAIN02 (0x7<<12) +#define NV4_PGRAPH_VALID1_VLD_GOTYCHAIN03 (0xF<<12) +#define NV4_PGRAPH_VALID1_VLD_X_OFFSET (0x1<<0) +#define NV4_PGRAPH_VALID1_VLD_XCHAIN_OFFSET (0x1<<4) +#define NV4_PGRAPH_VALID1_VLD_Y_OFFSET (0x1<<8) +#define NV4_PGRAPH_VALID1_VLD_YCHAIN_OFFSET (0x1<<12) +#define NV4_PGRAPH_VALID1_VLD_GOTCOLOR0 (0x1<<17) +#define NV4_PGRAPH_VALID1_VLD_GOTCOLOR1 (0x1<<18) +#define NV4_PGRAPH_VALID1_VLD_GOTCLIP (0x1<<20) +#define NV4_PGRAPH_VALID1_VLD_GOTFONT (0x1<<22) +#define NV4_PGRAPH_VALID1_VLD_GOTOFFSET (0x1<<22) +#define NV4_PGRAPH_VALID1_VLD_GOTBPITCH (0x1<<2) +#define NV4_PGRAPH_VALID1_VLD_GOTBOFFSET (0x1<<3) +#define NV4_PGRAPH_VALID1_VLD_GOTDUDX (0x1<<4) +#define NV4_PGRAPH_VALID1_VLD_GOTDVDY (0x1<<5) +#define NV4_PGRAPH_VALID1_VLD_GOTPOINT (0x1<<8) +#define NV4_PGRAPH_VALID1_VLD_GOTSIZE (0x1<<9) +#define NV4_PGRAPH_VALID1_VLD_GOTPITCH (0x1<<10) +#define NV4_PGRAPH_VALID1_VLD_GOTSTART (0x1<<11) +#define NV4_PGRAPH_VALID1_VLD_GOTDUDX2 (0x1<<12) +#define NV4_PGRAPH_VALID1_VLD_GOTDVDY2 (0x1<<13) +#define NV4_PGRAPH_VALID1_VLD_GOTPOINT2 (0x1<<14) +#define NV4_PGRAPH_VALID1_VLD_GOTSIZE2 (0x1<<15) +#define NV4_PGRAPH_VALID1_VLD_GOTPITCH2 (0x1<<16) +#define NV4_PGRAPH_VALID1_VLD_GOTSTART2 (0x1<<17) +#define NV4_PGRAPH_VALID1_VLD_GOTOFFSIN (0x1<<0) +#define NV4_PGRAPH_VALID1_VLD_GOTOFFSOUT (0x1<<1) +#define NV4_PGRAPH_VALID1_VLD_GOTPITCHIN (0x1<<2) +#define NV4_PGRAPH_VALID1_VLD_GOTPITCHOUT (0x1<<3) +#define NV4_PGRAPH_VALID1_VLD_GOTLENGTH (0x1<<4) +#define NV4_PGRAPH_VALID1_VLD_GOTCOUNT (0x1<<5) +#define NV4_PGRAPH_VALID1_VLD_GOTFORMAT (0x1<<6) +#define NV4_PGRAPH_VALID1_VLD_GOTNOTIFY (0x1<<7) +#define NV4_PGRAPH_VALID1_CLIP_MIN 28 +#define NV4_PGRAPH_VALID1_CLIP_MIN_NO_ERROR 0x0 +#define NV4_PGRAPH_VALID1_CLIP_MIN_ONLY 0x1 +#define NV4_PGRAPH_VALID1_CLIPA_MIN 29 +#define NV4_PGRAPH_VALID1_CLIPA_MIN_NO_ERROR 0x0 +#define NV4_PGRAPH_VALID1_CLIPA_MIN_ONLY 0x1 +#define NV4_PGRAPH_VALID1_CLIP_MAX 30 +#define NV4_PGRAPH_VALID1_CLIP_MAX_NO_ERROR 0x0 +#define NV4_PGRAPH_VALID1_CLIP_MAX_ONLY 0x1 +#define NV4_PGRAPH_VALID1_CLIPA_MAX 31 +#define NV4_PGRAPH_VALID1_CLIPA_MAX_NO_ERROR 0x0 +#define NV4_PGRAPH_VALID1_CLIPA_MAX_ONLY 0x1 +#define NV4_PGRAPH_VALID2 0x400578 +#define NV4_PGRAPH_VALID2_VLD2 0 +#define NV4_PGRAPH_VALID2_VLD2_0 0x0 +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COMBINE0A (1<<28) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COMBINE0C (1<<27) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COMBINE1A (1<<26) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COMBINE1C (1<<25) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COMBFACTOR (1<<24) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_FILTER1 (1<<23) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_OFFSET1 (1<<22) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_FORMAT1 (1<<21) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_BLEND (1<<20) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_CONTROL2 (1<<19) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_CONTROL1 (1<<18) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_CONTROL0 (1<<17) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_FILTER0 (1<<16) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_FORMAT0 (1<<15) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_OFFSET0 (1<<14) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_FOGCOLOR (1<<13) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COLORKEY (1<<12) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_V1 (1<<9) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_U1 (1<<8) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_V0 (1<<7) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_U0 (1<<6) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_X (1<<5) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_Y (1<<4) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_ZETA (1<<3) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_M (1<<2) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_COLOR (1<<1) +#define NV4_PGRAPH_VALID2_VLD2_GOT3D_SPECULAR (1<<0) +#define NV4_PGRAPH_VALID2_VLD2_DX3FULLVERTEX (0x7f<<0) +#define NV4_PGRAPH_VALID2_VLD2_DX5FULLVERTEX (0x7f<<0) +#define NV4_PGRAPH_VALID2_VLD2_DX6FULLVERTEX (0x1ff<<0) +#define NV4_PGRAPH_VALID2_VLD2_DX3FULLSTATE (0x3f<<13) +#define NV4_PGRAPH_VALID2_VLD2_DX5FULLSTATE (0x1ff<<12) +#define NV4_PGRAPH_VALID2_VLD2_DX6FULLSTATE (0xFfff<<13) +#define NV4_PGRAPH_ABS_ICLIP_XMAX 0x400534 +#define NV4_PGRAPH_ABS_ICLIP_XMAX_VALUE 0 +#define NV4_PGRAPH_ABS_ICLIP_YMAX 0x400538 +#define NV4_PGRAPH_ABS_ICLIP_YMAX_VALUE 0 +#define NV4_PGRAPH_CLIPX_0 0x400524 +// Valid for all clips! +#define NV4_PGRAPH_CLIP_CONDITION_IS_GT 0x0 +#define NV4_PGRAPH_CLIP_CONDITION_IS_LT 0x1 +#define NV4_PGRAPH_CLIP_CONDITION_IS_EQ 0x2 +#define NV4_PGRAPH_CLIPX_0_CLIP0_MIN 0 +#define NV4_PGRAPH_CLIPX_0_CLIP0_MAX 2 +#define NV4_PGRAPH_CLIPX_0_CLIP1_MIN 4 +#define NV4_PGRAPH_CLIPX_0_CLIP1_MAX 6 +#define NV4_PGRAPH_CLIPX_0_CLIP2_MIN 8 +#define NV4_PGRAPH_CLIPX_0_CLIP2_MAX 10 +#define NV4_PGRAPH_CLIPX_0_CLIP3_MIN 12 +#define NV4_PGRAPH_CLIPX_0_CLIP3_MAX 14 +#define NV4_PGRAPH_CLIPX_0_CLIP4_MIN 16 +#define NV4_PGRAPH_CLIPX_0_CLIP4_MAX 18 +#define NV4_PGRAPH_CLIPX_0_CLIP5_MIN 20 +#define NV4_PGRAPH_CLIPX_0_CLIP5_MAX 22 +#define NV4_PGRAPH_CLIPX_0_CLIP6_MIN 24 +#define NV4_PGRAPH_CLIPX_0_CLIP6_MAX 26 +#define NV4_PGRAPH_CLIPX_0_CLIP7_MIN 28 +#define NV4_PGRAPH_CLIPX_0_CLIP7_MAX 30 +#define NV4_PGRAPH_CLIPX_1 0x400528 +#define NV4_PGRAPH_CLIPX_1_CLIP8_MIN 0 +#define NV4_PGRAPH_CLIPX_1_CLIP8_MAX 2 +#define NV4_PGRAPH_CLIPX_1_CLIP9_MIN 4 +#define NV4_PGRAPH_CLIPX_1_CLIP9_MAX 6 +#define NV4_PGRAPH_CLIPX_1_CLIP10_MIN 8 +#define NV4_PGRAPH_CLIPX_1_CLIP10_MAX 10 +#define NV4_PGRAPH_CLIPX_1_CLIP11_MIN 12 +#define NV4_PGRAPH_CLIPX_1_CLIP11_MAX 14 +#define NV4_PGRAPH_CLIPX_1_CLIP12_MIN 16 +#define NV4_PGRAPH_CLIPX_1_CLIP12_MAX 18 +#define NV4_PGRAPH_CLIPX_1_CLIP13_MIN 20 +#define NV4_PGRAPH_CLIPX_1_CLIP13_MAX 22 +#define NV4_PGRAPH_CLIPX_1_CLIP14_MIN 24 +#define NV4_PGRAPH_CLIPX_1_CLIP14_MAX 26 +#define NV4_PGRAPH_CLIPX_1_CLIP15_MIN 28 +#define NV4_PGRAPH_CLIPX_1_CLIP15_MAX 30 +#define NV4_PGRAPH_CLIPY_0 0x40052c +#define NV4_PGRAPH_CLIPY_0_CLIP0_MIN 0 +#define NV4_PGRAPH_CLIPY_0_CLIP0_MAX 2 +#define NV4_PGRAPH_CLIPY_0_CLIP1_MIN 4 +#define NV4_PGRAPH_CLIPY_0_CLIP1_MAX 6 +#define NV4_PGRAPH_CLIPY_0_CLIP2_MIN 8 +#define NV4_PGRAPH_CLIPY_0_CLIP2_MAX 10 +#define NV4_PGRAPH_CLIPY_0_CLIP3_MIN 12 +#define NV4_PGRAPH_CLIPY_0_CLIP3_MAX 14 +#define NV4_PGRAPH_CLIPY_0_CLIP4_MIN 16 +#define NV4_PGRAPH_CLIPY_0_CLIP4_MAX 18 +#define NV4_PGRAPH_CLIPY_0_CLIP5_MIN 20 +#define NV4_PGRAPH_CLIPY_0_CLIP5_MAX 22 +#define NV4_PGRAPH_CLIPY_0_CLIP6_MIN 24 +#define NV4_PGRAPH_CLIPY_0_CLIP6_MAX 26 +#define NV4_PGRAPH_CLIPY_0_CLIP7_MIN 28 +#define NV4_PGRAPH_CLIPY_0_CLIP7_MAX 30 +#define NV4_PGRAPH_CLIPY_1 0x400530 +#define NV4_PGRAPH_CLIPY_1_CLIP8_MIN 0 +#define NV4_PGRAPH_CLIPY_1_CLIP8_MAX 2 +#define NV4_PGRAPH_CLIPY_1_CLIP9_MIN 4 +#define NV4_PGRAPH_CLIPY_1_CLIP9_MAX 6 +#define NV4_PGRAPH_CLIPY_1_CLIP10_MIN 8 +#define NV4_PGRAPH_CLIPY_1_CLIP10_MAX 10 +#define NV4_PGRAPH_CLIPY_1_CLIP11_MIN 12 +#define NV4_PGRAPH_CLIPY_1_CLIP11_MAX 14 +#define NV4_PGRAPH_CLIPY_1_CLIP12_MIN 16 +#define NV4_PGRAPH_CLIPY_1_CLIP12_MAX 18 +#define NV4_PGRAPH_CLIPY_1_CLIP13_MIN 20 +#define NV4_PGRAPH_CLIPY_1_CLIP13_MAX 22 +#define NV4_PGRAPH_CLIPY_1_CLIP14_MIN 24 +#define NV4_PGRAPH_CLIPY_1_CLIP14_MAX 26 +#define NV4_PGRAPH_CLIPY_1_CLIP15_MIN 28 +#define NV4_PGRAPH_CLIPY_1_CLIP15_MAX 30 +#define NV4_PGRAPH_MISC24_0 0x400510 +#define NV4_PGRAPH_MISC24_0_VALUE 0 +#define NV4_PGRAPH_MISC24_1 0x400570 +#define NV4_PGRAPH_MISC24_1_VALUE 0 +#define NV4_PGRAPH_MISC24_2 0x400574 +#define NV4_PGRAPH_MISC24_2_VALUE 0 +#define NV4_PGRAPH_PASSTHRU_0 0x40057C +#define NV4_PGRAPH_PASSTHRU_0_VALUE 0 +#define NV4_PGRAPH_PASSTHRU_1 0x400580 +#define NV4_PGRAPH_PASSTHRU_1_VALUE 0 +#define NV4_PGRAPH_PASSTHRU_2 0x400584 +#define NV4_PGRAPH_PASSTHRU_2_VALUE 0 +#define NV4_PGRAPH_U_RAM(i) (0x400d00+(i)*4) +#define NV4_PGRAPH_U_RAM_SIZE_1 16 +#define NV4_PGRAPH_U_RAM_VALUE 6 +#define NV4_PGRAPH_V_RAM(i) (0x400d40+(i)*4) +#define NV4_PGRAPH_V_RAM_SIZE_1 16 +#define NV4_PGRAPH_V_RAM_VALUE 6 +#define NV4_PGRAPH_M_RAM(i) (0x400d80+(i)*4) +#define NV4_PGRAPH_M_RAM_SIZE_1 16 +#define NV4_PGRAPH_M_RAM_VALUE 6 +#define NV4_PGRAPH_D3D_XY 0x4005c0 +#define NV4_PGRAPH_D3D_XY_X_VALUE 0 +#define NV4_PGRAPH_D3D_XY_Y_VALUE 16 +#define NV4_PGRAPH_D3D_U0 0x4005c4 +#define NV4_PGRAPH_D3D_U0_VALUE 6 +#define NV4_PGRAPH_D3D_V0 0x4005c8 +#define NV4_PGRAPH_D3D_V0_VALUE 6 +#define NV4_PGRAPH_D3D_U1 0x4005cc +#define NV4_PGRAPH_D3D_U1_VALUE 6 +#define NV4_PGRAPH_D3D_V1 0x4005d0 +#define NV4_PGRAPH_D3D_V1_VALUE 6 +#define NV4_PGRAPH_D3D_ZETA 0x4005d4 +#define NV4_PGRAPH_D3D_ZETA_VALUE 0 +#define NV4_PGRAPH_D3D_RGB 0x4005d8 +#define NV4_PGRAPH_D3D_RGB_VALUE 0 +#define NV4_PGRAPH_D3D_S 0x4005dc +#define NV4_PGRAPH_D3D_S_VALUE 0 +#define NV4_PGRAPH_D3D_M 0x4005e0 +#define NV4_PGRAPH_D3D_M_VALUE 6 +#define NV4_PGRAPH_FORMAT0 0x4005A8 +#define NV4_PGRAPH_FORMAT0_CONTEXT_DMA 1 +#define NV4_PGRAPH_FORMAT0_CONTEXT_DMA_A 0x0 +#define NV4_PGRAPH_FORMAT0_CONTEXT_DMA_B 0x1 +#define NV4_PGRAPH_FORMAT0_COLORKEYENABLE 2 +#define NV4_PGRAPH_FORMAT0_COLORKEYENABLE_FALSE 0x0 +#define NV4_PGRAPH_FORMAT0_COLORKEYENABLE_TRUE 0x1 +#define NV4_PGRAPH_FORMAT0_ORIGIN_ZOH 5 +#define NV4_PGRAPH_FORMAT0_ORIGIN_ZOH_CENTER 0x0 +#define NV4_PGRAPH_FORMAT0_ORIGIN_ZOH_CORNER 0x1 +#define NV4_PGRAPH_FORMAT0_ORIGIN_FOH 7 +#define NV4_PGRAPH_FORMAT0_ORIGIN_FOH_CENTER 0x0 +#define NV4_PGRAPH_FORMAT0_ORIGIN_FOH_CORNER 0x1 +#define NV4_PGRAPH_FORMAT0_COLOR 8 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_Y8 0x0 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_AY8 0x1 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_A1R5G5B5 0x2 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_X1R5G5B5 0x3 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_A4R4G4B4 0x4 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_R5G6B5 0x5 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_A8R8G8B8 0x6 +#define NV4_PGRAPH_FORMAT0_COLOR_LE_X8R8G8B8 0x7 +// 0x1-0Xf used for 1-16 mipmap levels +#define NV4_PGRAPH_FORMAT0_MIPMAP_LEVELS 12 +#define NV4_PGRAPH_FORMAT0_MIPMAP_LEVELS_INVALID 0x0 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U 16 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_1 0x0 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_2 0x1 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_4 0x2 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_8 0x3 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_16 0x4 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_32 0x5 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_64 0x6 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_128 0x7 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_256 0x8 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_512 0x9 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_1024 0xA +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_U_2048 0xB +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V 20 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_1 0x0 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_2 0x1 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_4 0x2 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_8 0x3 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_16 0x4 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_32 0x5 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_64 0x6 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_128 0x7 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_256 0x8 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_512 0x9 +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_1024 0xA +#define NV4_PGRAPH_FORMAT0_BASE_SIZE_V_2048 0xB +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSU 24 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSU_WRAP 0x1 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSU_MIRROR 0x2 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSU_CLAMP 0x3 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSU_BORDER 0x4 +#define NV4_PGRAPH_FORMAT0_WRAPU 27 +#define NV4_PGRAPH_FORMAT0_WRAPU_FALSE 0x0 +#define NV4_PGRAPH_FORMAT0_WRAPU_TRUE 0x1 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSV 28 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSV_WRAP 0x1 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSV_MIRROR 0x2 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSV_CLAMP 0x3 +#define NV4_PGRAPH_FORMAT0_TEXTUREADDRESSV_BORDER 0x4 +#define NV4_PGRAPH_FORMAT0_WRAPV 31 +#define NV4_PGRAPH_FORMAT0_WRAPV_FALSE 0x0 +#define NV4_PGRAPH_FORMAT0_WRAPV_TRUE 0x1 +#define NV4_PGRAPH_FORMAT1 0x4005AC +#define NV4_PGRAPH_FORMAT1_CONTEXT_DMA 1 +#define NV4_PGRAPH_FORMAT1_CONTEXT_DMA_A 0x0 +#define NV4_PGRAPH_FORMAT1_CONTEXT_DMA_B 0x1 +#define NV4_PGRAPH_FORMAT1_COLORKEYENABLE 2 +#define NV4_PGRAPH_FORMAT1_COLORKEYENABLE_FALSE 0x0 +#define NV4_PGRAPH_FORMAT1_COLORKEYENABLE_TRUE 0x1 +#define NV4_PGRAPH_FORMAT1_ORIGIN_ZOH 5 +#define NV4_PGRAPH_FORMAT1_ORIGIN_ZOH_CENTER 0x0 +#define NV4_PGRAPH_FORMAT1_ORIGIN_ZOH_CORNER 0x1 +#define NV4_PGRAPH_FORMAT1_ORIGIN_FOH 7 +#define NV4_PGRAPH_FORMAT1_ORIGIN_FOH_CENTER 0x0 +#define NV4_PGRAPH_FORMAT1_ORIGIN_FOH_CORNER 0x1 +#define NV4_PGRAPH_FORMAT1_COLOR 8 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_Y8 0x0 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_AY8 0x1 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_A1R5G5B5 0x2 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_X1R5G5B5 0x3 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_A4R4G4B4 0x4 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_R5G6B5 0x5 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_A8R8G8B8 0x6 +#define NV4_PGRAPH_FORMAT1_COLOR_LE_X8R8G8B8 0x7 +// 15:12 = number of mipmap levels (1-15. 0 = invalid). Stupid defines removed here +#define NV4_PGRAPH_FORMAT1_MIPMAP_LEVELS 12 +#define NV4_PGRAPH_FORMAT1_MIPMAP_LEVELS_INVALID 0x0 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U 16 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_1 0x0 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_2 0x1 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_4 0x2 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_8 0x3 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_16 0x4 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_32 0x5 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_64 0x6 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_128 0x7 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_256 0x8 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_512 0x9 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_1024 0xA +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_U_2048 0xB +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V 20 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_1 0x0 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_2 0x1 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_4 0x2 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_8 0x3 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_16 0x4 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_32 0x5 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_64 0x6 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_128 0x7 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_256 0x8 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_512 0x9 +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_1024 0xA +#define NV4_PGRAPH_FORMAT1_BASE_SIZE_V_2048 0xB +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSU 24 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSU_WRAP 0x1 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSU_MIRROR 0x2 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSU_CLAMP 0x3 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSU_BORDER 0x4 +#define NV4_PGRAPH_FORMAT1_WRAPU 27 +#define NV4_PGRAPH_FORMAT1_WRAPU_TRUE 0x1 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSV 28 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSV_WRAP 0x1 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSV_MIRROR 0x2 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSV_CLAMP 0x3 +#define NV4_PGRAPH_FORMAT1_TEXTUREADDRESSV_BORDER 0x4 +#define NV4_PGRAPH_FORMAT1_WRAPV 31 +#define NV4_PGRAPH_FORMAT1_WRAPV_TRUE 0x1 +#define NV4_PGRAPH_FILTER0 0x4005B0 +#define NV4_PGRAPH_FILTER0_KERNEL_SIZE_X 1 +#define NV4_PGRAPH_FILTER0_KERNEL_SIZE_Y 9 +#define NV4_PGRAPH_FILTER0_MIPMAP_DITHER_ENABLE 15 +#define NV4_PGRAPH_FILTER0_MIPMAP_DITHER_ENABLE_FALSE 0x0 +#define NV4_PGRAPH_FILTER0_MIPMAP_DITHER_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_FILTER0_MIPMAPLODBIAS 16 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN 24 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_NEAREST 0x1 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_LINEAR 0x2 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_MIPNEAREST 0x3 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_MIPLINEAR 0x4 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_LINEARMIPNEAREST 0x5 +#define NV4_PGRAPH_FILTER0_TEXTUREMIN_LINEARMIPLINEAR 0x6 +#define NV4_PGRAPH_FILTER0_ANISOTROPIC_MIN_ENABLE 27 +#define NV4_PGRAPH_FILTER0_ANISOTROPIC_MIN_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG 28 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_NEAREST 0x1 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_LINEAR 0x2 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_MIPNEAREST 0x3 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_MIPLINEAR 0x4 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_LINEARMIPNEAREST 0x5 +#define NV4_PGRAPH_FILTER0_TEXTUREMAG_LINEARMIPLINEAR 0x6 +#define NV4_PGRAPH_FILTER0_ANISOTROPIC_MAG_ENABLE 31 +#define NV4_PGRAPH_FILTER0_ANISOTROPIC_MAG_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_FILTER1 0x4005B4 +#define NV4_PGRAPH_FILTER1_KERNEL_SIZE_X 1 +#define NV4_PGRAPH_FILTER1_KERNEL_SIZE_Y 9 +#define NV4_PGRAPH_FILTER1_MIPMAP_DITHER_ENABLE 15 +#define NV4_PGRAPH_FILTER1_MIPMAP_DITHER_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_FILTER1_MIPMAPLODBIAS 16 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN 24 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_NEAREST 0x1 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_LINEAR 0x2 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_MIPNEAREST 0x3 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_MIPLINEAR 0x4 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_LINEARMIPNEAREST 0x5 +#define NV4_PGRAPH_FILTER1_TEXTUREMIN_LINEARMIPLINEAR 0x6 +#define NV4_PGRAPH_FILTER1_ANISOTROPIC_MIN_ENABLE 27 +#define NV4_PGRAPH_FILTER1_ANISOTROPIC_MIN_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG 28 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_NEAREST 0x1 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_LINEAR 0x2 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_MIPNEAREST 0x3 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_MIPLINEAR 0x4 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_LINEARMIPNEAREST 0x5 +#define NV4_PGRAPH_FILTER1_TEXTUREMAG_LINEARMIPLINEAR 0x6 +#define NV4_PGRAPH_FILTER1_ANISOTROPIC_MAG_ENABLE 31 +#define NV4_PGRAPH_FILTER1_ANISOTROPIC_MAG_ENABLE_TRUE 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA 0x400590 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_0 0 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_0_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_0_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0 4:2 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_0_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_1 8 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_1_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_1_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1 10 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_1_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_2 16 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_2_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_2_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2 18 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_2_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_3 24 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_3_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0ALPHA_INVERSE_3_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3 26 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0ALPHA_ARGUMENT_3_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION 29 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADD 0x1 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADD2 0x2 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADD4 0x3 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADDSIGNED 0x4 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_MUX 0x5 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADDCOMPLEMENT 0x6 +#define NV4_PGRAPH_COMBINE0ALPHA_OPERATION_ADDSIGNED2 0x7 +#define NV4_PGRAPH_COMBINE0COLOR 0x400594 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_0 0 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_0_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_0_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_0 1 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_0_COLOR 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_0_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0 2 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_0_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_1 8 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_1_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_1_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_1 9 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_1_COLOR 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_1_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1 10 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_1_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_2 16 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_2_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_2_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_2 17 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_2_COLOR 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_2_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2 18 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_2_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_3 24 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_3_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_INVERSE_3_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_3 25 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_3_COLOR 0x0 +#define NV4_PGRAPH_COMBINE0COLOR_ALPHA_3_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3 26 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_ZERO 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_INPUT 0x4 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE0COLOR_ARGUMENT_3_TEXTURELOD 0x7 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION 29 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADD 0x1 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADD2 0x2 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADD4 0x3 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADDSIGNED 0x4 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_MUX 0x5 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADDCOMPLEMENT 0x6 +#define NV4_PGRAPH_COMBINE0COLOR_OPERATION_ADDSIGNED2 0x7 +#define NV4_PGRAPH_COMBINE1ALPHA 0x400598 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_0 0 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_0_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_0_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0 2 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_0_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_1 8 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_1_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_1_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1 10 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_1_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_2 16 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_2_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_2_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2 18 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_2_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_3 24 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_3_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1ALPHA_INVERSE_3_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3 26 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1ALPHA_ARGUMENT_3_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION 29 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADD 0x1 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADD2 0x2 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADD4 0x3 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADDSIGNED 0x4 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_MUX 0x5 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADDCOMPLEMENT 0x6 +#define NV4_PGRAPH_COMBINE1ALPHA_OPERATION_ADDSIGNED2 0x7 +#define NV4_PGRAPH_COMBINE1COLOR 0x40059C +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_0 0 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_0_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_0_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_0 1 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_0_COLOR 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_0_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0 4:2 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_0_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_1 8 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_1_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_1_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_1 9 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_1_COLOR 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_1_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1 10 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_1_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_2 16 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_2_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_2_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_2 17 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_2_COLOR 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_2_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2 18 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_2_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_3 24 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_3_NORMAL 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_INVERSE_3_INVERSE 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_3 25 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_3_COLOR 0x0 +#define NV4_PGRAPH_COMBINE1COLOR_ALPHA_3_ALPHA 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3 26 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_ZERO 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_FACTOR 0x2 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_DIFFUSE 0x3 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_INPUT 0x4 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_TEXTURE0 0x5 +#define NV4_PGRAPH_COMBINE1COLOR_ARGUMENT_3_TEXTURE1 0x6 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION 29 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADD 0x1 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADD2 0x2 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADD4 0x3 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADDSIGNED 0x4 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_MUX 0x5 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADDCOMPLEMENT 0x6 +#define NV4_PGRAPH_COMBINE1COLOR_OPERATION_ADDSIGNED2 0x7 +#define NV4_PGRAPH_DMA_START_0 0x401000 +#define NV4_PGRAPH_DMA_START_0_VALUE 0 +#define NV4_PGRAPH_DMA_START_1 0x401004 +#define NV4_PGRAPH_DMA_START_1_VALUE 0 +#define NV4_PGRAPH_DMA_LENGTH 0x401008 +#define NV4_PGRAPH_DMA_LENGTH_VALUE 0 +#define NV4_PGRAPH_DMA_MISC 0x40100C +#define NV4_PGRAPH_DMA_MISC_COUNT 0 +#define NV4_PGRAPH_DMA_MISC_FMT_SRC 16 +#define NV4_PGRAPH_DMA_MISC_FMT_DST 20 +#define NV4_PGRAPH_DMA_DATA_0 0x401020 +#define NV4_PGRAPH_DMA_DATA_0_VALUE 0 +#define NV4_PGRAPH_DMA_DATA_1 0x401024 +#define NV4_PGRAPH_DMA_DATA_1_VALUE 0 +#define NV4_PGRAPH_DMA_RM 0x401030 +#define NV4_PGRAPH_DMA_RM_ASSIST_A 0 +#define NV4_PGRAPH_DMA_RM_ASSIST_A_NOT_PENDING 0x0 +#define NV4_PGRAPH_DMA_RM_ASSIST_A_PENDING 0x1 +#define NV4_PGRAPH_DMA_RM_ASSIST_A_RESET 0x1 +#define NV4_PGRAPH_DMA_RM_ASSIST_B 1 +#define NV4_PGRAPH_DMA_RM_ASSIST_B_NOT_PENDING 0x0 +#define NV4_PGRAPH_DMA_RM_ASSIST_B_PENDING 0x1 +#define NV4_PGRAPH_DMA_RM_ASSIST_B_RESET 0x1 +#define NV4_PGRAPH_DMA_RM_WRITE_REQ 4 +#define NV4_PGRAPH_DMA_RM_WRITE_REQ_NOT_PENDING 0x0 +#define NV4_PGRAPH_DMA_RM_WRITE_REQ_PENDING 0x1 +#define NV4_PGRAPH_DMA_A_XLATE_INST 0x401040 +#define NV4_PGRAPH_DMA_A_XLATE_INST_VALUE 0 +#define NV4_PGRAPH_DMA_A_CONTROL 0x401044 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_TABLE 12 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_NOT_PRESENT 0x0 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_PRESENT 0x1 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY 13 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x0 +#define NV4_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_LINEAR 0x1 +#define NV4_PGRAPH_DMA_A_CONTROL_TARGET_NODE 16 +#define NV4_PGRAPH_DMA_A_CONTROL_TARGET_NODE_NVM 0x0 +#define NV4_PGRAPH_DMA_A_CONTROL_TARGET_NODE_PCI 0x2 +#define NV4_PGRAPH_DMA_A_CONTROL_TARGET_NODE_AGP 0x3 +#define NV4_PGRAPH_DMA_A_CONTROL_ADJUST 20 +#define NV4_PGRAPH_DMA_A_LIMIT 0x401048 +#define NV4_PGRAPH_DMA_A_LIMIT_OFFSET 0 +#define NV4_PGRAPH_DMA_A_TLB_PTE 0x40104C +#define NV4_PGRAPH_DMA_A_TLB_PTE_ACCESS 1 +#define NV4_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_ONLY 0x0 +#define NV4_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_WRITE 0x1 +#define NV4_PGRAPH_DMA_A_TLB_PTE_FRAME_ADDRESS 12 +#define NV4_PGRAPH_DMA_A_TLB_TAG 0x401050 +#define NV4_PGRAPH_DMA_A_TLB_TAG_ADDRESS 12 +#define NV4_PGRAPH_DMA_A_ADJ_OFFSET 0x401054 +#define NV4_PGRAPH_DMA_A_ADJ_OFFSET_VALUE 0 +#define NV4_PGRAPH_DMA_A_OFFSET 0x401058 +#define NV4_PGRAPH_DMA_A_OFFSET_VALUE 0 +#define NV4_PGRAPH_DMA_A_SIZE 0x40105C +#define NV4_PGRAPH_DMA_A_SIZE_VALUE 0 +#define NV4_PGRAPH_DMA_A_Y_SIZE 0x401060 +#define NV4_PGRAPH_DMA_A_Y_SIZE_VALUE 0 +#define NV4_PGRAPH_DMA_B_XLATE_INST 0x401080 +#define NV4_PGRAPH_DMA_B_XLATE_INST_VALUE 0 +#define NV4_PGRAPH_DMA_B_CONTROL 0x401084 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_TABLE 12 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_NOT_PRESENT 0x0 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_PRESENT 0x1 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY 13 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x0 +#define NV4_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_LINEAR 0x1 +#define NV4_PGRAPH_DMA_B_CONTROL_TARGET_NODE 16 +#define NV4_PGRAPH_DMA_B_CONTROL_TARGET_NODE_NVM 0x0 +#define NV4_PGRAPH_DMA_B_CONTROL_TARGET_NODE_PCI 0x2 +#define NV4_PGRAPH_DMA_B_CONTROL_TARGET_NODE_AGP 0x3 +#define NV4_PGRAPH_DMA_B_CONTROL_ADJUST 20 +#define NV4_PGRAPH_DMA_B_LIMIT 0x401088 +#define NV4_PGRAPH_DMA_B_LIMIT_OFFSET 0 +#define NV4_PGRAPH_DMA_B_TLB_PTE 0x40108C +#define NV4_PGRAPH_DMA_B_TLB_PTE_ACCESS 1 +#define NV4_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_ONLY 0x0 +#define NV4_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_WRITE 0x1 +#define NV4_PGRAPH_DMA_B_TLB_PTE_FRAME_ADDRESS 12 +#define NV4_PGRAPH_DMA_B_TLB_TAG 0x401090 +#define NV4_PGRAPH_DMA_B_TLB_TAG_ADDRESS 12 +#define NV4_PGRAPH_DMA_B_ADJ_OFFSET 0x401094 +#define NV4_PGRAPH_DMA_B_ADJ_OFFSET_VALUE 0 +#define NV4_PGRAPH_DMA_B_OFFSET 0x401098 +#define NV4_PGRAPH_DMA_B_OFFSET_VALUE 0 +#define NV4_PGRAPH_DMA_B_SIZE 0x40109C +#define NV4_PGRAPH_DMA_B_SIZE_VALUE 0 +#define NV4_PGRAPH_DMA_B_Y_SIZE 0x4010A0 +#define NV4_PGRAPH_DMA_B_Y_SIZE_VALUE 0 +#define NV4_PGRAPH_CONTROL_OUT_INTERPOLATOR 0 +#define NV4_PGRAPH_CONTROL_OUT_INTERPOLATOR_ZOH_MS 0x0 +#define NV4_PGRAPH_CONTROL_OUT_INTERPOLATOR_ZOH 0x1 +#define NV4_PGRAPH_CONTROL_OUT_INTERPOLATOR_FOH 0x2 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_U 4 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_U_CYLINDRICAL 0x0 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_U_WRAP 0x1 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_U_MIRROR 0x2 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_U_CLAMP 0x3 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_V 6 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_V_CYLINDRICAL 0x0 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_V_WRAP 0x1 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_V_MIRROR 0x2 +#define NV4_PGRAPH_CONTROL_OUT_WRAP_V_CLAMP 0x3 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_FORMAT 8 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_FORMAT_LE_X8R8G8B8 0x0 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_FORMAT_LE_A8R8G8B8 0x1 +#define NV4_PGRAPH_CONTROL_OUT_SRCCOLOR 10 +#define NV4_PGRAPH_CONTROL_OUT_SRCCOLOR_NORMAL 0x0 +#define NV4_PGRAPH_CONTROL_OUT_SRCCOLOR_COLOR_INVERSE 0x1 +#define NV4_PGRAPH_CONTROL_OUT_SRCCOLOR_ALPHA_INVERSE 0x2 +#define NV4_PGRAPH_CONTROL_OUT_SRCCOLOR_ALPHA_ONE 0x3 +#define NV4_PGRAPH_CONTROL_OUT_CULLING 12 +#define NV4_PGRAPH_CONTROL_OUT_CULLING_ILLEGAL 0x0 +#define NV4_PGRAPH_CONTROL_OUT_CULLING_NONE 0x1 +#define NV4_PGRAPH_CONTROL_OUT_CULLING_COUNTERCLOCKWISE 0x2 +#define NV4_PGRAPH_CONTROL_OUT_CULLING_CLOCKWISE 0x3 +#define NV4_PGRAPH_CONTROL_OUT_ZBUFFER 15 +#define NV4_PGRAPH_CONTROL_OUT_ZBUFFER_SCREEN 0x0 +#define NV4_PGRAPH_CONTROL_OUT_ZBUFFER_LINEAR 0x1 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE 16 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_ILLEGAL 0x0 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_FALSE 0x1 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_LT 0x2 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_EQ 0x3 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_LE 0x4 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_GT 0x5 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_NE 0x6 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_GE 0x7 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_COMPARE_TRUE 0x8 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE 20 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE_NEVER 0x0 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE_ALPHA 0x1 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE_ALPHA_ZETA 0x2 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE_ZETA 0x3 +#define NV4_PGRAPH_CONTROL_OUT_ZETA_WRITE_ALWAYS 0x4 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_WRITE 24 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_WRITE_NEVER 0x0 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_WRITE_ALPHA 0x1 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_WRITE_ALPHA_ZETA 0x2 +#define NV4_PGRAPH_CONTROL_OUT_COLOR_WRITE_ZETA 0x3 +#define NV4_PGRAPH_CONTROL_OUT_ROP 28 +#define NV4_PGRAPH_CONTROL_OUT_ROP_BLEND_AND 0x0 +#define NV4_PGRAPH_CONTROL_OUT_ROP_ADD_WITH_SATURATION 0x1 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_BETA 29 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_BETA_SRCALPHA 0x0 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_BETA_DESTCOLOR 0x1 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT0 30 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT0_DESTCOLOR 0x0 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT0_ZERO 0x1 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT1 31 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT1_SRCCOLOR 0x0 +#define NV4_PGRAPH_CONTROL_OUT_BLEND_INPUT1_ZERO 0x1 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_KEY 0 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE 8 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_ILLEGAL 0x0 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_FALSE 0x1 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_LT 0x2 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_EQ 0x3 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_LE 0x4 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_GT 0x5 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_NE 0x6 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_GE 0x7 +#define NV4_PGRAPH_ALPHACNTRL_ALPHA_COMPARE_TRUE 0x8 + +#define NV4_PVIDEO_START 0x680000 +#define NV4_PVIDEO_END 0x6802FF + +#define NV4_PVIDEO_INTR_0 0x680100 +#define NV4_PVIDEO_INTR_0_NOTIFY 0 +#define NV4_PVIDEO_INTR_0_NOTIFY_NOT_PENDING 0x0 +#define NV4_PVIDEO_INTR_0_NOTIFY_PENDING 0x1 +#define NV4_PVIDEO_INTR_0_NOTIFY_RESET 0x1 +#define NV4_PVIDEO_INTR_EN_0 0x680140 +#define NV4_PVIDEO_INTR_EN_0_NOTIFY 0 +#define NV4_PVIDEO_INTR_EN_0_NOTIFY_ENABLED 0x1 +#define NV4_PVIDEO_STEP_SIZE 0x680200 +#define NV4_PVIDEO_STEP_SIZE_X 0 +#define NV4_PVIDEO_STEP_SIZE_Y 16 +#define NV4_PVIDEO_CONTROL_Y 0x680204 +#define NV4_PVIDEO_CONTROL_Y_BLUR 0 +#define NV4_PVIDEO_CONTROL_Y_BLUR_OFF 0x0 +#define NV4_PVIDEO_CONTROL_Y_BLUR_ON 0x1 +#define NV4_PVIDEO_CONTROL_Y_LINE 4 +#define NV4_PVIDEO_CONTROL_Y_LINE_HALF 0x0 +#define NV4_PVIDEO_CONTROL_Y_LINE_FULL 0x1 +#define NV4_PVIDEO_CONTROL_X 0x680208 +#define NV4_PVIDEO_CONTROL_X_WEIGHT 0 +#define NV4_PVIDEO_CONTROL_X_WEIGHT_LIGHT 0x0 +#define NV4_PVIDEO_CONTROL_X_WEIGHT_HEAVY 0x1 +#define NV4_PVIDEO_CONTROL_X_SHARPENING 4 +#define NV4_PVIDEO_CONTROL_X_SHARPENING_OFF 0x0 +#define NV4_PVIDEO_CONTROL_X_SHARPENING_ON 0x1 +#define NV4_PVIDEO_CONTROL_X_SMOOTHING 8 +#define NV4_PVIDEO_CONTROL_X_SMOOTHING_OFF 0x0 +#define NV4_PVIDEO_CONTROL_X_SMOOTHING_ON 0x1 +#define NV4_PVIDEO_BUFF0_START 0x68020c +#define NV4_PVIDEO_BUFF0_START_ADDRESS 2 +#define NV4_PVIDEO_BUFF1_START 0x680210 +#define NV4_PVIDEO_BUFF1_START_ADDRESS 2 +#define NV4_PVIDEO_BUFF0_PITCH 0x680214 +#define NV4_PVIDEO_BUFF0_PITCH_LENGTH 4 +#define NV4_PVIDEO_BUFF1_PITCH 0x680218 +#define NV4_PVIDEO_BUFF1_PITCH_LENGTH 4 +#define NV4_PVIDEO_BUFF0_OFFSET 0x68021c +#define NV4_PVIDEO_BUFF0_OFFSET_X 0 +#define NV4_PVIDEO_BUFF0_OFFSET_Y 4 +#define NV4_PVIDEO_BUFF0_OFFSET_Y_OFF 0x0 +#define NV4_PVIDEO_BUFF0_OFFSET_Y_QUARTER 0x1 +#define NV4_PVIDEO_BUFF0_OFFSET_Y_HALF 0x2 +#define NV4_PVIDEO_BUFF1_OFFSET 0x680220 +#define NV4_PVIDEO_BUFF1_OFFSET_X 0 +#define NV4_PVIDEO_BUFF1_OFFSET_Y 4 +#define NV4_PVIDEO_BUFF1_OFFSET_Y_OFF 0x0 +#define NV4_PVIDEO_BUFF1_OFFSET_Y_QUARTER 0x1 +#define NV4_PVIDEO_BUFF1_OFFSET_Y_HALF 0x2 +#define NV4_PVIDEO_OE_STATE 0x680224 +#define NV4_PVIDEO_OE_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PVIDEO_OE_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PVIDEO_OE_STATE_BUFF0_ERROR 8 +#define NV4_PVIDEO_OE_STATE_BUFF1_ERROR 12 +#define NV4_PVIDEO_OE_STATE_BUFF0_IN_USE 16 +#define NV4_PVIDEO_OE_STATE_BUFF1_IN_USE 20 +#define NV4_PVIDEO_OE_STATE_CURRENT_BUFFER 24 +#define NV4_PVIDEO_OE_STATE_CURRENT_BUFFER_0 0x0 +#define NV4_PVIDEO_OE_STATE_CURRENT_BUFFER_1 0x1 +#define NV4_PVIDEO_SU_STATE 0x680228 +#define NV4_PVIDEO_SU_STATE_BUFF0_IN_USE 16 +#define NV4_PVIDEO_SU_STATE_BUFF1_IN_USE 20 +#define NV4_PVIDEO_RM_STATE 0x68022c +#define NV4_PVIDEO_RM_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PVIDEO_RM_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PVIDEO_WINDOW_START 0x680230 +#define NV4_PVIDEO_WINDOW_START_X 0 +#define NV4_PVIDEO_WINDOW_START_Y 16 +#define NV4_PVIDEO_WINDOW_SIZE 0x680234 +#define NV4_PVIDEO_WINDOW_SIZE_X 0 +#define NV4_PVIDEO_WINDOW_SIZE_Y 16 +#define NV4_PVIDEO_FIFO_THRES 0x680238 +#define NV4_PVIDEO_FIFO_THRES_SIZE 3 +#define NV4_PVIDEO_FIFO_BURST 0x68023c +#define NV4_PVIDEO_FIFO_BURST_LENGTH 0 +#define NV4_PVIDEO_FIFO_BURST_LENGTH_32 0x1 +#define NV4_PVIDEO_FIFO_BURST_LENGTH_64 0x2 +#define NV4_PVIDEO_FIFO_BURST_LENGTH_128 0x3 +#define NV4_PVIDEO_KEY 0x680240 +#define NV4_PVIDEO_KEY_INDEX 0 +#define NV4_PVIDEO_KEY_565 0 +#define NV4_PVIDEO_KEY_555 0 +#define NV4_PVIDEO_KEY_888 0 +#define NV4_PVIDEO_KEY_PACK 24 +#define NV4_PVIDEO_OVERLAY 0x680244 +#define NV4_PVIDEO_OVERLAY_VIDEO 0 +#define NV4_PVIDEO_OVERLAY_VIDEO_OFF 0x0 +#define NV4_PVIDEO_OVERLAY_VIDEO_ON 0x1 +#define NV4_PVIDEO_OVERLAY_KEY 4 +#define NV4_PVIDEO_OVERLAY_KEY_OFF 0x0 +#define NV4_PVIDEO_OVERLAY_KEY_ON 0x1 +#define NV4_PVIDEO_OVERLAY_FORMAT 8 +#define NV4_PVIDEO_OVERLAY_FORMAT_CCIR 0x0 +#define NV4_PVIDEO_OVERLAY_FORMAT_YUY2 0x1 +#define NV4_PVIDEO_RED_CSC 0x680280 +#define NV4_PVIDEO_RED_CSC_OFFSET 0 +#define NV4_PVIDEO_GREEN_CSC 0x680284 +#define NV4_PVIDEO_GREEN_CSC_OFFSET 0 +#define NV4_PVIDEO_BLUE_CSC 0x680288 +#define NV4_PVIDEO_BLUE_CSC_OFFSET 0 +#define NV4_PVIDEO_CSC_ADJUST 0x68028c +#define NV4_PVIDEO_CSC_ADJUST_B_FLAG 0 +#define NV4_PVIDEO_CSC_ADJUST_B_FLAG_OFF 0x0 +#define NV4_PVIDEO_CSC_ADJUST_B_FLAG_ON 0x1 +#define NV4_PVIDEO_CSC_ADJUST_G_FLAG 4 +#define NV4_PVIDEO_CSC_ADJUST_G_FLAG_OFF 0x0 +#define NV4_PVIDEO_CSC_ADJUST_G_FLAG_ON 0x1 +#define NV4_PVIDEO_CSC_ADJUST_R_FLAG 8 +#define NV4_PVIDEO_CSC_ADJUST_R_FLAG_OFF 0x0 +#define NV4_PVIDEO_CSC_ADJUST_R_FLAG_ON 0x1 +#define NV4_PVIDEO_CSC_ADJUST_L_FLAG 12 +#define NV4_PVIDEO_CSC_ADJUST_L_FLAG_OFF 0x0 +#define NV4_PVIDEO_CSC_ADJUST_L_FLAG_ON 0x1 +#define NV4_PVIDEO_CSC_ADJUST_CHROMA 16 +#define NV4_PVIDEO_CSC_ADJUST_CHROMA_OFF 0x0 +#define NV4_PVIDEO_CSC_ADJUST_CHROMA_ON 0x1 + +#define NV4_PRMCIO_START 0x601000 +#define NV4_PRMCIO_END 0x601FFF + +#define NV4_PRMCIO_INP0 0x6013c2 +#define NV4_PRMCIO_INP0_MONO 0x6013ba +#define NV4_PRMCIO_INP0_COLOR 0x6013da +#define NV4_PRMCIO_INP0_READ_MONO 0x6013ca +#define NV4_PRMCIO_INP0_WRITE_MONO 0x6013ba +#define NV4_PRMCIO_INP0_WRITE_COLOR 0x6013da +// DEFAULT = Palette +#define NV4_PRMCIO_ARX 0x6013c0 +#define NV4_PRMCIO_AR_WRITE 0x6013c0 // After ARX +#define NV4_PRMCIO_AR_READ 0x6013c1 +#define NV4_PRMCIO_AR_PALETTE_WRITE 0x6013c0 +#define NV4_PRMCIO_AR_PALETTE_READ 0x6013c1 +#define NV4_PRMCIO_AR_MODE_INDEX 0x10 +#define NV4_PRMCIO_AR_OSCAN_INDEX 0x11 +#define NV4_PRMCIO_AR_PLANE_INDEX 0x12 +#define NV4_PRMCIO_AR_HPP_INDEX 0x13 +#define NV4_PRMCIO_AR_CSEL_INDEX 0x14 +#define NV4_PRMCIO_CRX_MONO 0x6013b4 +#define NV4_PRMCIO_CRX_COLOR 0x6013d4 +#define NV4_PRMCIO_CR_MONO 0x6013b5 +#define NV4_PRMCIO_CR_COLOR 0x6013d5 +#define NV4_PRMCIO_CRE_MONO 0x6013b5 +#define NV4_PRMCIO_CRE_COLOR 0x6013d5 + +#define NV4_PCRTC_INTR_0 0x600100 +#define NV4_PCRTC_INTR_0_VBLANK 0 +#define NV4_PCRTC_INTR_0_VBLANK_NOT_PENDING 0x0 +#define NV4_PCRTC_INTR_0_VBLANK_PENDING 0x1 +#define NV4_PCRTC_INTR_0_VBLANK_RESET 0x1 +#define NV4_PCRTC_INTR_EN_0 0x600140 +#define NV4_PCRTC_INTR_EN_0_VBLANK 0 +#define NV4_PCRTC_INTR_EN_0_VBLANK_ENABLED 0x1 +#define NV4_PCRTC_START 0x600800 +#define NV4_PCRTC_START_ADDRESS 2 +#define NV4_PCRTC_CONFIG 0x600804 +#define NV4_PCRTC_CONFIG_START_ADDRESS 0 +#define NV4_PCRTC_CONFIG_START_ADDRESS_VGA 0x0 +#define NV4_PCRTC_CONFIG_START_ADDRESS_NON_VGA 0x1 +#define NV4_PCRTC_CONFIG_START_ADDRESS_HSYNC 0x2 +#define NV4_PCRTC_RASTER 0x600808 +#define NV4_PCRTC_RASTER_POSITION 0 +#define NV4_PCRTC_RASTER_SA_LOAD 12 +#define NV4_PCRTC_RASTER_SA_LOAD_DISPLAY 0x0 +#define NV4_PCRTC_RASTER_SA_LOAD_BEFORE 0x1 +#define NV4_PCRTC_RASTER_SA_LOAD_AFTER 0x2 +#define NV4_PCRTC_RASTER_VERT_BLANK 16 +#define NV4_PCRTC_RASTER_VERT_BLANK_ACTIVE 0x1 +#define NV4_PCRTC_RASTER_VERT_BLANK_INACTIVE 0x0 + +#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 +#define NV4_CIO_INP0_MONO 0x3ba +#define NV4_CIO_INP0_COLOR 0x3da +#define NV4_CIO_INP0_READ_MONO 0x3ca +#define NV4_CIO_INP0_WRITE_MONO 0x3ba +#define NV4_CIO_INP0_WRITE_COLOR 0x3da +#define NV4_CIO_ARX 0x3c0 // if index is not 0x10-0x13 write palette +#define NV4_CIO_AR_PALETTE_WRITE 0x3c0 +#define NV4_CIO_AR_PALETTE_READ 0x3c1 +#define NV4_CIO_AR_MODE_WRITE 0x3c0 +#define NV4_CIO_AR_MODE_READ 0x3c1 +#define NV4_CIO_AR_MODE_INDEX 0x10 +#define NV4_CIO_AR_OSCAN_WRITE 0x3c0 +#define NV4_CIO_AR_OSCAN_READ 0x3c1 +#define NV4_CIO_AR_OSCAN_INDEX 0x11 +#define NV4_CIO_AR_PLANE_WRITE 0x3c0 +#define NV4_CIO_AR_PLANE_READ 0x3c1 +#define NV4_CIO_AR_PLANE_INDEX 0x12 +#define NV4_CIO_AR_HPP_WRITE 0x3c0 +#define NV4_CIO_AR_HPP_READ 0x3c1 +#define NV4_CIO_AR_HPP_INDEX 0x13 +#define NV4_CIO_AR_CSEL_WRITE 0x3c0 +#define NV4_CIO_AR_CSEL_READ 0x3c1 +#define NV4_CIO_AR_CSEL_INDEX 0x14 +#define NV4_CIO_CRX_MONO 0x3b4 +#define NV4_CIO_CRX_COLOR 0x3d4 +#define NV4_CIO_CR_MONO 0x3b5 +#define NV4_CIO_CR_COLOR 0x3d5 +#define NV4_CIO_CR_HDT_INDEX 0x0 +#define NV4_CIO_CR_HDE_INDEX 0x1 +#define NV4_CIO_CR_HBS_INDEX 0x2 +#define NV4_CIO_CR_HBE_INDEX 0x3 +#define NV4_CIO_CR_HBE_4_0 0 +#define NV4_CIO_CR_HRS_INDEX 0x4 +#define NV4_CIO_CR_HRE_INDEX 0x5 +#define NV4_CIO_CR_HRE_HBE_5 7 +#define NV4_CIO_CR_HRE_4_0 0 +#define NV4_CIO_CR_VDT_INDEX 0x6 +#define NV4_CIO_CR_OVL_INDEX 0x7 +#define NV4_CIO_CR_OVL_VDE_8 1 +#define NV4_CIO_CR_OVL_VDE_9 6 +#define NV4_CIO_CR_OVL_VDT_8 0 +#define NV4_CIO_CR_OVL_VDT_9 5 +#define NV4_CIO_CR_OVL_VBS_8 3 +#define NV4_CIO_CR_OVL_VRS_8 2 +#define NV4_CIO_CR_OVL_VRS_9 7 +#define NV4_CIO_CR_RSAL_INDEX 0x8 +#define NV4_CIO_CR_RSAL_PANNING 5 +#define NV4_CIO_CR_CELL_HT_INDEX 0x9 +#define NV4_CIO_CR_CELL_HT_SCANDBL 7 +#define NV4_CIO_CR_CELL_HT_VBS_9 5 +#define NV4_CIO_CR_CURS_ST_INDEX 0xA +#define NV4_CIO_CR_CURS_END_INDEX 0xB +#define NV4_CIO_CR_SA_HI_INDEX 0xC +#define NV4_CIO_CR_SA_LO_INDEX 0xD +#define NV4_CIO_CR_TCOFF_HI_INDEX 0xE +#define NV4_CIO_CR_TCOFF_LO_INDEX 0xF +#define NV4_CIO_CR_VRS_INDEX 0x10 +#define NV4_CIO_CR_VRE_INDEX 0x11 +#define NV4_CIO_CR_VRE_3_0 0 +#define NV4_CIO_CR_VDE_INDEX 0x12 +#define NV4_CIO_CR_OFFSET_INDEX 0x13 +#define NV4_CIO_CR_ULINE_INDEX 0x14 +#define NV4_CIO_CR_VBS_INDEX 0x15 +#define NV4_CIO_CR_VBE_INDEX 0x16 +#define NV4_CIO_CR_MODE_INDEX 0x17 +#define NV4_CIO_CR_LCOMP_INDEX 0x18 +#define NV4_CIO_CR_GDATA_INDEX 0x22 +#define NV4_CIO_CR_ARFF_INDEX 0x24 +#define NV4_CIO_CR_ARX_INDEX 0x26 +#define NV4_CIO_CRE_MONO 0x3b5 +#define NV4_CIO_CRE_COLOR 0x3d5 +#define NV4_CIO_CRE_RPC0_INDEX 0x19 +#define NV4_CIO_CRE_RPC0_START 0 +#define NV4_CIO_CRE_RPC0_OFFSET_10_8 5 +#define NV4_CIO_CRE_RPC1_INDEX 0x1A +#define NV4_CIO_CRE_RPC1_LARGE 2 +#define NV4_CIO_CRE_FF_INDEX 0x1B +#define NV4_CIO_CRE_FF_BURST 0 +#define NV4_CIO_CRE_FF_BURST_8 0x0 +#define NV4_CIO_CRE_FF_BURST_32 0x1 +#define NV4_CIO_CRE_FF_BURST_64 0x2 +#define NV4_CIO_CRE_FF_BURST_128 0x3 +#define NV4_CIO_CRE_FF_BURST_256 0x4 +#define NV4_CIO_CRE_ENH_INDEX 0x1C +#define NV4_CIO_CRE_PAGE0_INDEX 0x1D +#define NV4_CIO_CRE_PAGE1_INDEX 0x1E +#define NV4_CIO_SR_LOCK_INDEX 0x1F +#define NV4_CIO_SR_UNLOCK_RW_VALUE 0x57 +#define NV4_CIO_SR_UNLOCK_RO_VALUE 0x75 +#define NV4_CIO_SR_LOCK_VALUE 0x99 +#define NV4_SR_UNLOCK_RW_VALUE 0x57 +#define NV4_SR_UNLOCK_RO_VALUE 0x75 +#define NV4_SR_LOCK_VALUE 0x99 +#define NV4_CIO_CRE_FFLWM_INDEX 0x20 +#define NV4_CIO_CRE_FFLWM_LWM 0 +#define NV4_CIO_CRE_FABID_INDEX 0x25 +#define NV4_CIO_CRE_LSR_INDEX 0x25 +#define NV4_CIO_CRE_LSR_VDE_10 1 +#define NV4_CIO_CRE_LSR_VDT_10 0 +#define NV4_CIO_CRE_LSR_HBE_6 4 +#define NV4_CIO_CRE_LSR_VBS_10 3 +#define NV4_CIO_CRE_LSR_VRS_10 2 +#define NV4_CIO_CRE_CHIP_ID_INDEX 0x27 +#define NV4_CIO_CRE_PIXEL_INDEX 0x28 +#define NV4_CIO_CRE_PIXEL_TV_ADJ 3 +#define NV4_CIO_CRE_PIXEL_FORMAT 0 +#define NV4_CIO_CRE_PIXEL_FORMAT_VGA 0x0 +#define NV4_CIO_CRE_PIXEL_FORMAT_8BPP 0x1 +#define NV4_CIO_CRE_PIXEL_FORMAT_16BPP 0x2 +#define NV4_CIO_CRE_PIXEL_FORMAT_32BPP 0x3 +#define NV4_CIO_CRE_PAGE_OVFL_INDEX 0x29 +#define NV4_CIO_CRE_OSCOL_INDEX 0x2A +#define NV4_CIO_CRE_SCRATCH0_INDEX 0x2B +#define NV4_CIO_CRE_SCRATCH1_INDEX 0x2C +#define NV4_CIO_CRE_HEB_INDEX 0x2D +#define NV4_CIO_CRE_HEB_SA_23 5 +#define NV4_CIO_CRE_HEB_ILC_8 4 +#define NV4_CIO_CRE_HEB_HRS_8 3 +#define NV4_CIO_CRE_HEB_HBS_8 2 +#define NV4_CIO_CRE_HEB_HDE_8 1 +#define NV4_CIO_CRE_HEB_HDT_8 0 +#define NV4_CIO_CRE_HCUR_ADDR2_INDEX 0x2f +#define NV4_CIO_CRE_HCUR_ADDR0_INDEX 0x30 +#define NV4_CIO_CRE_HCUR_ASI 7 +#define NV4_CIO_CRE_HCUR_ASI_FRAMEBUFFER 0x1 +#define NV4_CIO_CRE_HCUR_ASI_INSTMEM 0x0 +#define NV4_CIO_CRE_HCUR_ADDR0_ADR 0 +#define NV4_CIO_CRE_HCUR_ADDR1_INDEX 0x31 +#define NV4_CIO_CRE_HCUR_ADDR1_ADR 2 +#define NV4_CIO_CRE_HCUR_ADDR1_CUR_DBL 1 +#define NV4_CIO_CRE_HCUR_ADDR1_ENABLE 0 +#define NV4_CIO_CRE_VID_END0_INDEX 0x32 +#define NV4_CIO_CRE_VID_END_7_0 0 +#define NV4_CIO_CRE_VID_END1_INDEX 0x33 +#define NV4_CIO_CRE_VID_END_ENABLE 4 +#define NV4_CIO_CRE_VID_END_10_8 0 +#define NV4_CIO_CRE_RL0_INDEX 0x34 +#define NV4_CIO_CRE_RL1_INDEX 0x35 +#define NV4_CIO_CRE_RMA_INDEX 0x38 +#define NV4_CIO_CRE_ILACE_INDEX 0x39 +#define NV4_CIO_CRE_SCRATCH2_INDEX 0x3A +#define NV4_CIO_CRE_SCRATCH3_INDEX 0x3B +#define NV4_CIO_CRE_SCRATCH4_INDEX 0x3C +#define NV4_CIO_CRE_TREG_INDEX 0x3D +#define NV4_CIO_CRE_TREG_HCNT 6 +#define NV4_CIO_CRE_TREG_VCNT 4 +#define NV4_CIO_CRE_TREG_SHADOW 0 +#define NV4_CIO_CRE_TREG_HCNT_INDEX 0x0 +#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 // Write to i2c for EDID/DDC +#define NV4_CIO_CRE_PCI_TO_INDEX 0x40 +#define NV4_CIO_CRE_PCI_TO_DELAY 0 + +#define NV4_VIO_MBEN 0x94 +#define NV4_VIO_ADDEN 0x46e8 +#define NV4_VIO_VSE1 0x102 +#define NV4_VIO_VSE2 0x3c3 +#define NV4_VIO_MISC_READ 0x3cc +#define NV4_VIO_MISC_WRITE 0x3c2 +#define NV4_VIO_SRX 0x3c4 +#define NV4_VIO_SR 0x3c5 +#define NV4_VIO_SR_RESET_INDEX 0x0 +#define NV4_VIO_SR_CLOCK_INDEX 0x1 +#define NV4_VIO_SR_PLANE_MASK_INDEX 0x2 +#define NV4_VIO_SR_CHAR_MAP_INDEX 0x3 +#define NV4_VIO_SR_MEM_MODE_INDEX 0x4 +#define NV4_VIO_GRX 0x3ce +#define NV4_VIO_GX_SR 0x3cf +#define NV4_VIO_GX_SR_INDEX 0x0 +#define NV4_VIO_GX_SREN_INDEX 0x1 +#define NV4_VIO_GX_CCOMP_INDEX 0x2 +#define NV4_VIO_GX_ROP_INDEX 0x3 +#define NV4_VIO_GX_READ_MAP_INDEX 0x4 +#define NV4_VIO_GX_MODE_INDEX 0x5 +#define NV4_VIO_GX_MISC_INDEX 0x6 +#define NV4_VIO_GX_DONT_CARE_INDEX 0x7 +#define NV4_VIO_GX_BIT_MASK_INDEX 0x8 + +#define NV4_PRMVIO_START 0xC0000 +#define NV4_PRMVIO_END 0xC7FFF + +#define NV4_PRMVIO_MBEN 0xC0094 +#define NV4_PRMVIO_ADDEN 0xC46e8 +#define NV4_PRMVIO_VSE1 0xC0102 +#define NV4_PRMVIO_VSE2 0xC03c3 +#define NV4_PRMVIO_MISC_READ 0xC03cc +#define NV4_PRMVIO_MISC_WRITE 0xC03c2 +#define NV4_PRMVIO_SRX 0xC03c4 +#define NV4_PRMVIO_SR_RESET 0xC03c5 +#define NV4_PRMVIO_SR_RESET_INDEX 0x0 +#define NV4_PRMVIO_SR_CLOCK_INDEX 0x1 +#define NV4_PRMVIO_SR_PLANE_MASK_INDEX 0x2 +#define NV4_PRMVIO_SR_CHAR_MAP_INDEX 0x3 +#define NV4_PRMVIO_SR_MEM_MODE_INDEX 0x4 +#define NV4_PRMVIO_GX_SR 0xC03cf +#define NV4_PRMVIO_GX_SR_INDEX 0x0 +#define NV4_PRMVIO_GX_SREN_INDEX 0x1 +#define NV4_PRMVIO_GX_CCOMP_INDEX 0x2 +#define NV4_PRMVIO_GX_ROP_INDEX 0x3 +#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 + +#define NV4_PRMVGA 0xA0000 +#define NV4_PRMVGA_END 0xBFFFF + +#define NV4_PME 0x200FFF:0x200000 +#define NV4_PME_DEBUG_0 0x200080 +#define NV4_PME_DEBUG_0_DET_FIELD_SWITCH 0 +#define NV4_PME_DEBUG_0_DET_FIELD_SWITCH_ENABLED 0x1 +#define NV4_PME_DEBUG_0_CAPTURE_00_FF 4 +#define NV4_PME_DEBUG_0_CAPTURE_00_FF_ENABLED 0x1 +#define NV4_PME_DEBUG_1 0x200084 +#define NV4_PME_DEBUG_1_SEL 0 +#define NV4_PME_DEBUG_1_SEL_VIPCLK 0x0 +#define NV4_PME_DEBUG_1_SEL_MCLK 0x1 +#define NV4_PME_DEBUG_1_SEL_GLOB 0x2 +#define NV4_PME_DEBUG_1_VIPCLK_SEL 4 +#define NV4_PME_DEBUG_1_VIPCLK_SEL_DEFAULT 0x0 +#define NV4_PME_DEBUG_1_MCLK_SEL 8 +#define NV4_PME_DEBUG_1_MCLK_SEL_DEFAULT 0x0 +#define NV4_PME_INTR_0 0x200100 +#define NV4_PME_INTR_0_IMAGE_NOTIFY 0 +#define NV4_PME_INTR_0_IMAGE_NOTIFY_NOT_PENDING 0x0 +#define NV4_PME_INTR_0_IMAGE_NOTIFY_PENDING 0x1 +#define NV4_PME_INTR_0_IMAGE_NOTIFY_RESET 0x1 +#define NV4_PME_INTR_0_VBI_NOTIFY 4 +#define NV4_PME_INTR_0_VBI_NOTIFY_NOT_PENDING 0x0 +#define NV4_PME_INTR_0_VBI_NOTIFY_PENDING 0x1 +#define NV4_PME_INTR_0_VBI_NOTIFY_RESET 0x1 +#define NV4_PME_INTR_0_VID_NOTIFY 8 +#define NV4_PME_INTR_0_VID_NOTIFY_NOT_PENDING 0x0 +#define NV4_PME_INTR_0_VID_NOTIFY_PENDING 0x1 +#define NV4_PME_INTR_0_VID_NOTIFY_RESET 0x1 +#define NV4_PME_INTR_0_AUD_NOTIFY 12 +#define NV4_PME_INTR_0_AUD_NOTIFY_NOT_PENDING 0x0 +#define NV4_PME_INTR_0_AUD_NOTIFY_PENDING 0x1 +#define NV4_PME_INTR_0_AUD_NOTIFY_RESET 0x1 +#define NV4_PME_INTR_0_VMI 16 +#define NV4_PME_INTR_0_VMI_NOT_PENDING 0x0 +#define NV4_PME_INTR_0_VMI_PENDING 0x1 +#define NV4_PME_INTR_0_VMI_RESET 0x1 +#define NV4_PME_INTR_EN_0 0x200140 +#define NV4_PME_INTR_EN_0_IMAGE_NOTIFY 0 +#define NV4_PME_INTR_EN_0_IMAGE_NOTIFY_ENABLED 0x1 +#define NV4_PME_INTR_EN_0_VBI_NOTIFY 4 +#define NV4_PME_INTR_EN_0_VBI_NOTIFY_ENABLED 0x1 +#define NV4_PME_INTR_EN_0_VID_NOTIFY 8 +#define NV4_PME_INTR_EN_0_VID_NOTIFY_ENABLED 0x1 +#define NV4_PME_INTR_EN_0_AUD_NOTIFY 12 +#define NV4_PME_INTR_EN_0_AUD_NOTIFY_ENABLED 0x1 +#define NV4_PME_INTR_EN_0_VMI 16 +#define NV4_PME_INTR_EN_0_VMI_ENABLED 0x1 +#define NV4_PME_CONFIG_0 0x200200 +#define NV4_PME_CONFIG_0_BUS_MODE 0 +#define NV4_PME_CONFIG_0_BUS_MODE_DISABLED 0x0 +#define NV4_PME_CONFIG_0_BUS_MODE_VMI 0x1 +#define NV4_PME_CONFIG_0_BUS_MODE_CCIR656 0x2 +#define NV4_PME_CONFIG_0_IMAGE 4 +#define NV4_PME_CONFIG_0_IMAGE_ENABLED 0x1 +#define NV4_PME_CONFIG_0_VBI_MODE 8 +#define NV4_PME_CONFIG_0_VBI_MODE_DISABLED 0x0 +#define NV4_PME_CONFIG_0_VBI_MODE_1 0x1 +#define NV4_PME_CONFIG_0_VBI_MODE_2 0x2 +#define NV4_PME_CONFIG_0_VID_CD 12 +#define NV4_PME_CONFIG_0_VID_CD_ENABLED 0x1 +#define NV4_PME_CONFIG_0_AUD_CD 16 +#define NV4_PME_CONFIG_0_AUD_CD_ENABLED 0x1 +#define NV4_PME_CONFIG_1 0x200204 +#define NV4_PME_CONFIG_1_BUFFS 0 +#define NV4_PME_CONFIG_1_BUFFS_PNVM 0x0 +#define NV4_PME_CONFIG_1_BUFFS_SYS 0x1 +#define NV4_PME_CONFIG_1_HOST 4 +#define NV4_PME_CONFIG_1_HOST_PCI 0x0 +#define NV4_PME_CONFIG_1_HOST_AGP 0x1 +#define NV4_PME_NULL_DATA 0x200208 +#define NV4_PME_NULL_DATA_COMPARE 0 +#define NV4_PME_NULL_DATA_COMPARE_ENABLED 0x1 +#define NV4_PME_NULL_DATA_LINE_DETECT 4 +#define NV4_PME_NULL_DATA_LINE_DETECT_ENABLED 0x1 +#define NV4_PME_NULL_DATA_BYTE 24 +#define NV4_PME_VID_BUFF0_START_SYS 0x200300 +#define NV4_PME_VID_BUFF0_START_SYS_ADDRESS 4 +#define NV4_PME_VID_BUFF1_START_SYS 0x200304 +#define NV4_PME_VID_BUFF1_START_SYS_ADDRESS 4 +#define NV4_PME_VID_BUFF0_START_PNVM 0x200308 +#define NV4_PME_VID_BUFF0_START_PNVM_ADDRESS 4 +#define NV4_PME_VID_BUFF1_START_PNVM 0x20030c +#define NV4_PME_VID_BUFF1_START_PNVM_ADDRESS 4 +#define NV4_PME_VID_BUFF0_LENGTH 0x200310 +#define NV4_PME_VID_BUFF0_LENGTH_BITS 12 +#define NV4_PME_VID_BUFF1_LENGTH 0x200314 +#define NV4_PME_VID_BUFF1_LENGTH_BITS 12 +#define NV4_PME_VID_ME_STATE 0x200318 +#define NV4_PME_VID_ME_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_VID_ME_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_VID_ME_STATE_BUFF0_INTR_CHAINGAP 8 +#define NV4_PME_VID_ME_STATE_BUFF1_INTR_CHAINGAP 12 +#define NV4_PME_VID_ME_STATE_BUFF0_IN_USE 16 +#define NV4_PME_VID_ME_STATE_BUFF1_IN_USE 20 +#define NV4_PME_VID_ME_STATE_CURRENT_BUFFER 24 +#define NV4_PME_VID_ME_STATE_CURRENT_BUFFER_0 0x0 +#define NV4_PME_VID_ME_STATE_CURRENT_BUFFER_1 0x1 +#define NV4_PME_VID_SU_STATE 0x20031c +#define NV4_PME_VID_SU_STATE_BUFF0_IN_USE 16 +#define NV4_PME_VID_SU_STATE_BUFF1_IN_USE 20 +#define NV4_PME_VID_RM_STATE 0x200320 +#define NV4_PME_VID_RM_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_VID_RM_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_VID_RM_STATE_BUFF0_INTR_CHAINGAP 8 +#define NV4_PME_VID_RM_STATE_BUFF1_INTR_CHAINGAP 12 +#define NV4_PME_VID_CURRENT 0x200324 +#define NV4_PME_VID_CURRENT_POS 2 +#define NV4_PME_AUD_BUFF0_START_SYS 0x200340 +#define NV4_PME_AUD_BUFF0_START_SYS_ADDRESS 4 +#define NV4_PME_AUD_BUFF1_START_SYS 0x200344 +#define NV4_PME_AUD_BUFF1_START_SYS_ADDRESS 4 +#define NV4_PME_AUD_BUFF0_START_PNVM 0x200348 +#define NV4_PME_AUD_BUFF0_START_PNVM_ADDRESS 4 +#define NV4_PME_AUD_BUFF1_START_PNVM 0x20034c +#define NV4_PME_AUD_BUFF1_START_PNVM_ADDRESS 4 +#define NV4_PME_AUD_BUFF0_LENGTH 0x200350 +#define NV4_PME_AUD_BUFF0_LENGTH_BITS 10 +#define NV4_PME_AUD_BUFF1_LENGTH 0x200354 +#define NV4_PME_AUD_BUFF1_LENGTH_BITS 10 +#define NV4_PME_AUD_ME_STATE 0x200358 +#define NV4_PME_AUD_ME_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_AUD_ME_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_AUD_ME_STATE_BUFF0_INTR_CHAINGAP 8 +#define NV4_PME_AUD_ME_STATE_BUFF1_INTR_CHAINGAP 12 +#define NV4_PME_AUD_ME_STATE_BUFF0_IN_USE 16 +#define NV4_PME_AUD_ME_STATE_BUFF1_IN_USE 20 +#define NV4_PME_AUD_ME_STATE_CURRENT_BUFFER 24 +#define NV4_PME_AUD_ME_STATE_CURRENT_BUFFER_0 0x0 +#define NV4_PME_AUD_ME_STATE_CURRENT_BUFFER_1 0x1 +#define NV4_PME_AUD_SU_STATE 0x20035c +#define NV4_PME_AUD_SU_STATE_BUFF0_IN_USE 16 +#define NV4_PME_AUD_SU_STATE_BUFF1_IN_USE 20 +#define NV4_PME_AUD_RM_STATE 0x200360 +#define NV4_PME_AUD_RM_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_AUD_RM_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_AUD_RM_STATE_BUFF0_INTR_CHAINGAP 8 +#define NV4_PME_AUD_RM_STATE_BUFF1_INTR_CHAINGAP 12 +#define NV4_PME_AUD_CURRENT 0x200364 +#define NV4_PME_AUD_CURRENT_POS 2 +#define NV4_PME_VBI_BUFF0_START 0x200380 +#define NV4_PME_VBI_BUFF0_START_ADDRESS 4 +#define NV4_PME_VBI_BUFF1_START 0x200384 +#define NV4_PME_VBI_BUFF1_START_ADDRESS 4 +#define NV4_PME_VBI_BUFF0_PITCH 0x200388 +#define NV4_PME_VBI_BUFF0_PITCH_VALUE 4 +#define NV4_PME_VBI_BUFF1_PITCH 0x20038c +#define NV4_PME_VBI_BUFF1_PITCH_VALUE 4 +#define NV4_PME_VBI_BUFF0_LENGTH 0x200390 +#define NV4_PME_VBI_BUFF0_LENGTH_BITS 4 +#define NV4_PME_VBI_BUFF1_LENGTH 0x200394 +#define NV4_PME_VBI_BUFF1_LENGTH_BITS 4 +#define NV4_PME_VBI_ME_STATE 0x200398 +#define NV4_PME_VBI_ME_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_VBI_ME_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_VBI_ME_STATE_BUFF0_ERROR_CODE 8 +#define NV4_PME_VBI_ME_STATE_BUFF1_ERROR_CODE 12 +#define NV4_PME_VBI_ME_STATE_BUFF0_IN_USE 16 +#define NV4_PME_VBI_ME_STATE_BUFF1_IN_USE 20 +#define NV4_PME_VBI_ME_STATE_CURRENT_BUFFER 24 +#define NV4_PME_VBI_ME_STATE_CURRENT_BUFFER_0 0x0 +#define NV4_PME_VBI_ME_STATE_CURRENT_BUFFER_1 0x1 +#define NV4_PME_VBI_SU_STATE 0x20039c +#define NV4_PME_VBI_SU_STATE_BUFF0_FIELD 8 +#define NV4_PME_VBI_SU_STATE_BUFF1_FIELD 12 +#define NV4_PME_VBI_SU_STATE_BUFF0_IN_USE 16 +#define NV4_PME_VBI_SU_STATE_BUFF1_IN_USE 20 +#define NV4_PME_VBI_RM_STATE 0x2003a0 +#define NV4_PME_VBI_RM_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_VBI_RM_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_VBI 0x2003a4 +#define NV4_PME_VBI_START_LINE 0 +#define NV4_PME_VBI_NUM_LINES 16 +#define NV4_PME_IMAGE_BUFF0_START 0x200400 +#define NV4_PME_IMAGE_BUFF0_START_ADDRESS 4 +#define NV4_PME_IMAGE_BUFF1_START 0x200404 +#define NV4_PME_IMAGE_BUFF1_START_ADDRESS 4 +#define NV4_PME_IMAGE_BUFF0_PITCH 0x200408 +#define NV4_PME_IMAGE_BUFF0_PITCH_VALUE 4 +#define NV4_PME_IMAGE_BUFF1_PITCH 0x20040c +#define NV4_PME_IMAGE_BUFF1_PITCH_VALUE 4 +#define NV4_PME_IMAGE_BUFF0_LENGTH 0x200410 +#define NV4_PME_IMAGE_BUFF0_LENGTH_BITS 4 +#define NV4_PME_IMAGE_BUFF1_LENGTH 0x200414 +#define NV4_PME_IMAGE_BUFF1_LENGTH_BITS 4 +#define NV4_PME_IMAGE_ME_STATE 0x200418 +#define NV4_PME_IMAGE_ME_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_IMAGE_ME_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_IMAGE_ME_STATE_BUFF0_ERROR_CODE 8 +#define NV4_PME_IMAGE_ME_STATE_BUFF1_ERROR_CODE 12 +#define NV4_PME_IMAGE_ME_STATE_BUFF0_IN_USE 16 +#define NV4_PME_IMAGE_ME_STATE_BUFF1_IN_USE 20 +#define NV4_PME_IMAGE_ME_STATE_CURRENT_BUFFER 24 +#define NV4_PME_IMAGE_ME_STATE_CURRENT_BUFFER_0 0x0 +#define NV4_PME_IMAGE_ME_STATE_CURRENT_BUFFER_1 0x1 +#define NV4_PME_IMAGE_SU_STATE 0x20041c +#define NV4_PME_IMAGE_SU_STATE_BUFF0_FIELD 8 +#define NV4_PME_IMAGE_SU_STATE_BUFF1_FIELD 12 +#define NV4_PME_IMAGE_SU_STATE_BUFF0_IN_USE 16 +#define NV4_PME_IMAGE_SU_STATE_BUFF1_IN_USE 20 +#define NV4_PME_IMAGE_RM_STATE 0x200420 +#define NV4_PME_IMAGE_RM_STATE_BUFF0_INTR_NOTIFY 0 +#define NV4_PME_IMAGE_RM_STATE_BUFF1_INTR_NOTIFY 4 +#define NV4_PME_IMAGE_BUFF0_SCALE_INCR 0x200424 +#define NV4_PME_IMAGE_BUFF0_SCALE_INCR_Y 16 +#define NV4_PME_IMAGE_BUFF0_SCALE_INCR_X 0 +#define NV4_PME_IMAGE_BUFF1_SCALE_INCR 0x200428 +#define NV4_PME_IMAGE_BUFF1_SCALE_INCR_Y 16 +#define NV4_PME_IMAGE_BUFF1_SCALE_INCR_X 0 +#define NV4_PME_IMAGE_Y_CROP 0x20042c +#define NV4_PME_IMAGE_Y_CROP_STARTLINE 0 +#define NV4_PME_FIFO_LINE_START 0x200480 +#define NV4_PME_FIFO_LINE_START_ADDRESS 4 +#define NV4_PME_FIFO_CURRENT 0x200484 +#define NV4_PME_FIFO_CURRENT_ADDRESS 2 +#define NV4_PME_VMI_POLL 0x200488 +#define NV4_PME_VMI_POLL_UNCD 0 +#define NV4_PME_VMI_POLL_UNCD_NOT_PENDING 0x0 +#define NV4_PME_VMI_POLL_UNCD_PENDING 0x1 +#define NV4_PME_VMI_POLL_VIDCD 1 +#define NV4_PME_VMI_POLL_VIDCD_NOT_PENDING 0x0 +#define NV4_PME_VMI_POLL_VIDCD_PENDING 0x1 +#define NV4_PME_VMI_POLL_AUDCD 2 +#define NV4_PME_VMI_POLL_AUDCD_NOT_PENDING 0x0 +#define NV4_PME_VMI_POLL_AUDCD_PENDING 0x1 +#define NV4_PME_VMI_POLL_INT 3 +#define NV4_PME_VMI_POLL_INT_NOT_PENDING 0x0 +#define NV4_PME_VMI_POLL_INT_PENDING 0x1 +#define NV4_PME_VMI_POLL_CPURDREC 4 +#define NV4_PME_VMI_POLL_CPURDREC_NOT_PENDING 0x0 +#define NV4_PME_VMI_POLL_CPURDREC_PENDING 0x1 +#define NV4_PME_EXTERNAL(i) (0x200600+(i)*4) +#define NV4_PME_EXTERNAL_SIZE_1 256 +#define NV4_PME_EXTERNAL_DATA 0 + +#define NV4_PFB_START 0x100000 +#define NV4_PFB_END 0x100FFF + +#define NV4_PFB_BOOT_0 0x100000 +#define NV4_PFB_BOOT_0_RAM_AMOUNT 0 +#define NV4_PFB_BOOT_0_RAM_AMOUNT_2MB 0x0 +#define NV4_PFB_BOOT_0_RAM_AMOUNT_4MB 0x1 +#define NV4_PFB_BOOT_0_RAM_AMOUNT_8MB 0x2 +#define NV4_PFB_BOOT_0_RAM_AMOUNT_16MB 0x3 +#define NV4_PFB_BOOT_0_RAM_WIDTH_128 2 +#define NV4_PFB_BOOT_0_RAM_WIDTH_128_OFF 0x0 +#define NV4_PFB_BOOT_0_RAM_WIDTH_128_ON 0x1 +#define NV4_PFB_BOOT_0_RAM_TYPE 3 +#define NV4_PFB_BOOT_0_RAM_TYPE_256K 0x0 +#define NV4_PFB_BOOT_0_RAM_TYPE_512K_2BANK 0x1 +#define NV4_PFB_BOOT_0_RAM_TYPE_512K_4BANK 0x2 +#define NV4_PFB_BOOT_0_RAM_TYPE_1024K_2BANK 0x3 +#define NV4_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x0 +#define NV4_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x1 +#define NV4_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x2 +#define NV4_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x3 +#define NV4_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x4 +#define NV4_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x5 +#define NV4_PFB_BOOT_0_UMA 8 +#define NV4_PFB_BOOT_0_UMA_DISABLE 0x0 +#define NV4_PFB_BOOT_0_UMA_ENABLE 0x1 +#define NV4_PFB_BOOT_0_UMA_SIZE 12 +#define NV4_PFB_BOOT_0_UMA_SIZE_DEFAULT 0x7 +#define NV4_PFB_BOOT_0_UMA_SIZE_2M 0x0 +#define NV4_PFB_BOOT_0_UMA_SIZE_4M 0x1 +#define NV4_PFB_BOOT_0_UMA_SIZE_6M 0x2 +#define NV4_PFB_BOOT_0_UMA_SIZE_8M 0x3 +#define NV4_PFB_BOOT_0_UMA_SIZE_10M 0x4 +#define NV4_PFB_BOOT_0_UMA_SIZE_12M 0x5 +#define NV4_PFB_BOOT_0_UMA_SIZE_14M 0x6 +#define NV4_PFB_BOOT_0_UMA_SIZE_16M 0x7 +#define NV4_PFB_BOOT_0_UMA_SIZE_18M 0x8 +#define NV4_PFB_BOOT_0_UMA_SIZE_20M 0x9 +#define NV4_PFB_BOOT_0_UMA_SIZE_22M 0xA +#define NV4_PFB_BOOT_0_UMA_SIZE_24M 0xB +#define NV4_PFB_BOOT_0_UMA_SIZE_26M 0xC +#define NV4_PFB_BOOT_0_UMA_SIZE_28M 0xD +#define NV4_PFB_BOOT_0_UMA_SIZE_30M 0xE +#define NV4_PFB_BOOT_0_UMA_SIZE_32M 0xF +#define NV4_PFB_DEBUG_0 0x100080 +#define NV4_PFB_DEBUG_0_PAGE_MODE 0 +#define NV4_PFB_DEBUG_0_PAGE_MODE_ENABLED 0x0 +#define NV4_PFB_DEBUG_0_PAGE_MODE_DISABLED 0x1 +#define NV4_PFB_DEBUG_0_REFRESH 4 +#define NV4_PFB_DEBUG_0_REFRESH_ENABLED 0x0 +#define NV4_PFB_DEBUG_0_REFRESH_DISABLED 0x1 +#define NV4_PFB_DEBUG_0_REFRESH_COUNTX64 8 +#define NV4_PFB_DEBUG_0_REFRESH_COUNTX64_DEFAULT 0x10 +#define NV4_PFB_DEBUG_0_REFRESH_SLOW_CLK 14 +#define NV4_PFB_DEBUG_0_REFRESH_SLOW_CLK_ENABLED 0x1 +#define NV4_PFB_DEBUG_0_CASOE 20 +#define NV4_PFB_DEBUG_0_CASOE_ENABLED 0x0 +#define NV4_PFB_DEBUG_0_CASOE_DISABLED 0x1 +#define NV4_PFB_DEBUG_0_CKE_INVERT 28 +#define NV4_PFB_DEBUG_0_CKE_INVERT_OFF 0x0 +#define NV4_PFB_DEBUG_0_CKE_INVERT_ON 0x1 +#define NV4_PFB_DEBUG_0_REFINC 29 +#define NV4_PFB_DEBUG_0_REFINC_DISABLED 0x0 +#define NV4_PFB_DEBUG_0_REFINC_ENABLED 0x1 +#define NV4_PFB_DEBUG_0_SAVE_POWER 30 +#define NV4_PFB_DEBUG_0_SAVE_POWER_ON 0x0 +#define NV4_PFB_DEBUG_0_SAVE_POWER_OFF 0x1 +#define NV4_PFB_GREEN_0 0x1000C0 +#define NV4_PFB_GREEN_0_LEVEL 0 +#define NV4_PFB_GREEN_0_LEVEL_VIDEO_ENABLED 0x0 +#define NV4_PFB_GREEN_0_LEVEL_VIDEO_DISABLED 0x1 +#define NV4_PFB_GREEN_0_LEVEL_TIMING_DISABLED 0x2 +#define NV4_PFB_GREEN_0_LEVEL_MEMORY_DISABLED 0x3 +#define NV4_PFB_CONFIG_0 0x100200 +#define NV4_PFB_CONFIG_0_TYPE 0 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_FIXED_8BPP 0x120 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_FIXED_16BPP 0x220 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_FIXED_32BPP 0x320 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_VAR_8BPP 0x4120 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_VAR_16BPP 0x4220 +#define NV4_PFB_CONFIG_0_TYPE_OLD1024_VAR_32BPP 0x4320 +#define NV4_PFB_CONFIG_0_TYPE_TETRIS 0x2000 +#define NV4_PFB_CONFIG_0_TYPE_NOTILING 0x1114 +#define NV4_PFB_CONFIG_0_TETRIS_MODE 15 +// 18:15 = tetris mode # +#define NV4_PFB_CONFIG_0_TETRIS_MODE_PASS 0x0 +// 18 = shift # +#define NV4_PFB_CONFIG_0_TETRIS_SHIFT 18 +#define NV4_PFB_CONFIG_0_BANK_SWAP 20 +#define NV4_PFB_CONFIG_0_BANK_SWAP_OFF 0x0 +#define NV4_PFB_CONFIG_0_BANK_SWAP_1M 0x1 +#define NV4_PFB_CONFIG_0_BANK_SWAP_2M 0x5 +#define NV4_PFB_CONFIG_0_BANK_SWAP_4M 0x7 +#define NV4_PFB_CONFIG_0_UNUSED 23 +#define NV4_PFB_CONFIG_0_SCRAMBLE_EN 29 +#define NV4_PFB_CONFIG_0_SCRAMBLE_EN_INIT 0x0 +#define NV4_PFB_CONFIG_0_SCRAMBLE_ACTIVE 0x1 +#define NV4_PFB_CONFIG_0_PRAMIN_WR 28 +#define NV4_PFB_CONFIG_0_PRAMIN_WR_INIT 0x0 +#define NV4_PFB_CONFIG_0_PRAMIN_WR_DISABLED 0x1 +#define NV4_PFB_CONFIG_0_PRAMIN_WR_MASK 24 +#define NV4_PFB_CONFIG_0_PRAMIN_WR_MASK_INIT 0x0 +#define NV4_PFB_CONFIG_0_PRAMIN_WR_MASK_CLEAR 0xF +#define NV4_PFB_CONFIG_1 0x100204 +#define NV4_PFB_CONFIG_1_CAS_LATENCY 0 +#define NV4_PFB_CONFIG_1_CAS_LATENCY_3 0x3 +#define NV4_PFB_CONFIG_1_CAS_LATENCY_2 0x2 +#define NV4_PFB_CONFIG_1_CAS_LATENCY_4 0x4 +#define NV4_PFB_CONFIG_1_RAS_RAS 4 +#define NV4_PFB_CONFIG_1_RAS_RAS_DEFAULT 0x9 +#define NV4_PFB_CONFIG_1_RAS_RAS_9CYCLES 0x8 +#define NV4_PFB_CONFIG_1_RAS_RAS_8CYCLES 0x7 +#define NV4_PFB_CONFIG_1_RAS_RAS_7CYCLES 0x6 +#define NV4_PFB_CONFIG_1_RAS_PCHG 8 +#define NV4_PFB_CONFIG_1_RAS_PCHG_DEFAULT 0x2 +#define NV4_PFB_CONFIG_1_RAS_PCHG_2CYCLES 0x1 +#define NV4_PFB_CONFIG_1_RAS_LOW 12 +#define NV4_PFB_CONFIG_1_RAS_LOW_DEFAULT 0x6 +#define NV4_PFB_CONFIG_1_RAS_LOW_7CYCLES 0x7 +#define NV4_PFB_CONFIG_1_RAS_LOW_5CYCLES 0x5 +#define NV4_PFB_CONFIG_1_RAS_LOW_4CYCLES 0x4 +#define NV4_PFB_CONFIG_1_MRS_TO_RAS 16 +#define NV4_PFB_CONFIG_1_MRS_TO_RAS_DEFAULT 0x1 +#define NV4_PFB_CONFIG_1_MRS_TO_RAS_2CYCLES 0x2 +#define NV4_PFB_CONFIG_1_MRS_TO_RAS_0CYCLES 0x0 +#define NV4_PFB_CONFIG_1_WRITE_TO_READ 20 +#define NV4_PFB_CONFIG_1_WRITE_TO_READ_DEFAULT 0x0 +#define NV4_PFB_CONFIG_1_RAS_TO_CAS_M1 24 +#define NV4_PFB_CONFIG_1_RAS_TO_CAS_M1_DEFAULT 0x1 +#define NV4_PFB_CONFIG_1_RAS_TO_CAS_M1_2CYCLES 0x2 +#define NV4_PFB_CONFIG_1_RAS_TO_CAS_M1_0CYCLES 0x0 +#define NV4_PFB_CONFIG_1_READ_TO_WRITE 28 +#define NV4_PFB_CONFIG_1_READ_TO_WRITE_DEFAULT 0x4 +#define NV4_PFB_CONFIG_1_READ_TO_WRITE_5CYCLES 0x5 +#define NV4_PFB_CONFIG_1_READ_TO_WRITE_3CYCLES 0x3 +#define NV4_PFB_CONFIG_1_READ_TO_WRITE_2CYCLES 0x2 +#define NV4_PFB_CONFIG_1_READ_TO_PCHG 31 +#define NV4_PFB_CONFIG_1_READ_TO_PCHG_ON 0x1 +#define NV4_PFB_CONFIG_1_READ_TO_PCHG_OFF 0x0 +#define NV4_PFB_RTL 0x100300 +#define NV4_PFB_RTL_H 0 +#define NV4_PFB_RTL_H_DEFAULT 0x0 +#define NV4_PFB_RTL_MC 1 +#define NV4_PFB_RTL_MC_DEFAULT 0x0 +#define NV4_PFB_RTL_V 2 +#define NV4_PFB_RTL_V_DEFAULT 0x0 +#define NV4_PFB_RTL_G 3 +#define NV4_PFB_RTL_G_DEFAULT 0x0 +#define NV4_PFB_RTL_GB 4 +#define NV4_PFB_RTL_GB_DEFAULT 0x0 +#define NV4_PFB_SCRAMBLE(i) (0x100400+((i)*4)) +#define NV4_PFB_SCRAMBLE_SIZE_1 8 +#define NV4_PFB_SCRAMBLE_w0 0 +#define NV4_PFB_SCRAMBLE_w1 8 +#define NV4_PFB_SCRAMBLE_w2 16 +#define NV4_PFB_SCRAMBLE_w3 24 +#define NV4_PFB_SCRAMBLE_EN 0x100420 +#define NV4_PFB_SCRAMBLE_VALUE_0 0x03020100 +#define NV4_PFB_SCRAMBLE_VALUE_1 0x07060504 +#define NV4_PFB_SCRAMBLE_VALUE_2 0x0b0a0908 +#define NV4_PFB_SCRAMBLE_VALUE_3 0x0f0e0d0c +#define NV4_PFB_SCRAMBLE_VALUE_4 0x13121110 +#define NV4_PFB_SCRAMBLE_VALUE_5 0x17161514 +#define NV4_PFB_SCRAMBLE_VALUE_6 0x1b1a1918 +#define NV4_PFB_SCRAMBLE_VALUE_7 0x1f1e1d1c +#define NV4_PFB_CONFIG_0_RESOLUTION 0 +#define NV4_PFB_CONFIG_0_RESOLUTION_320_PIXELS 0xA +#define NV4_PFB_CONFIG_0_RESOLUTION_400_PIXELS 0xD +#define NV4_PFB_CONFIG_0_RESOLUTION_480_PIXELS 0xF +#define NV4_PFB_CONFIG_0_RESOLUTION_512_PIXELS 0x10 +#define NV4_PFB_CONFIG_0_RESOLUTION_640_PIXELS 0x14 +#define NV4_PFB_CONFIG_0_RESOLUTION_800_PIXELS 0x19 +#define NV4_PFB_CONFIG_0_RESOLUTION_960_PIXELS 0x1e +#define NV4_PFB_CONFIG_0_RESOLUTION_1024_PIXELS 0x20 +#define NV4_PFB_CONFIG_0_RESOLUTION_1152_PIXELS 0x24 +#define NV4_PFB_CONFIG_0_RESOLUTION_1280_PIXELS 0x28 +#define NV4_PFB_CONFIG_0_RESOLUTION_1600_PIXELS 0x32 +#define NV4_PFB_CONFIG_0_RESOLUTION_DEFAULT 0x14 +#define NV4_PFB_CONFIG_0_PIXEL_DEPTH 8 +#define NV4_PFB_CONFIG_0_PIXEL_DEPTH_8_BITS 0x1 +#define NV4_PFB_CONFIG_0_PIXEL_DEPTH_16_BITS 0x2 +#define NV4_PFB_CONFIG_0_PIXEL_DEPTH_32_BITS 0x3 +#define NV4_PFB_CONFIG_0_PIXEL_DEPTH_DEFAULT 0x1 +#define NV4_PFB_CONFIG_0_TILING 12 +#define NV4_PFB_CONFIG_0_TILING_ENABLED 0x0 +#define NV4_PFB_CONFIG_0_TILING_DISABLED 0x1 +#define NV4_PFB_CONFIG_0_TILING_DEBUG 13 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_DISABLED 0x0 +#define NV4_PFB_CONFIG_0_TILE 12 +#define NV4_PFB_CONFIG_0_TILE_OLD1024_FIXED 0x0 +#define NV4_PFB_CONFIG_0_TILE_OLD1024_VARIABLE 0x4 +#define NV4_PFB_CONFIG_0_TILE_TETRIS_ALLOW 0x1 +#define NV4_PFB_CONFIG_0_TILE_TETRIS_REDUNDANT 0x2 +#define NV4_PFB_CONFIG_0_TILE_TETRIS_REDUNDANT2 0x3 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_ON 13 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_ON_ENABLED 0x0 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_ON_DISABLED 0x1 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TILESIZE 14 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TILESIZE_FIXED 0x0 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TILESIZE_VARIABLE 0x1 +// tetris mode # = 17:15 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TETRIS_MODE 15 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TETRIS_MODE_PASS 0x0 +// tetris shift # = 18 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_TETRIS_SHIFT 18 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP 20 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_OFF 0x0 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_ON 0x1 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_MSB 21 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_MSB_1M 0x0 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_MSB_2M 0x2 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_BANK_SWAP_MSB_4M 0x3 +#define NV4_PFB_CONFIG_0_TILING_DEBUG_UNUSED 23 +#define NV4_PFB_CONFIG_1_SGRAM100 3 +#define NV4_PFB_CONFIG_1_SGRAM100_ENABLED 0x0 +#define NV4_PFB_CONFIG_1_SGRAM100_DISABLED 0x1 +#define NV4_PFB_DEBUG_0_CKE_ALWAYSON 29 +#define NV4_PFB_DEBUG_0_CKE_ALWAYSON_OFF 0x0 +#define NV4_PFB_DEBUG_0_CKE_ALWAYSON_ON 0x1 + +// WARNING! WARNING! WARNING! +// STB V4400 has shown PROM at 0x700000 instead of 0x300000 (errata), clashing with first 0x10000 of instance memory +// Nvidia never ran into this issue because they never used that area +// 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) +#define NV4_PRAMIN_CONTEXT_2 ( 2*32+31):( 2*32+ 0) +#define NV4_PRAMIN_CONTEXT_3 ( 3*32+31):( 3*32+ 0) +#define NV4_PRAMIN_RAMHT_START 0x710000 +#define NV4_PRAMIN_RAMHT_END 0x710FFF +#define NV4_PRAMIN_RAMFC_START 0x711000 +#define NV4_PRAMIN_RAMFC_END 0x7111FF +#define NV4_PRAMIN_RAMRO_START 0x711200 +#define NV4_PRAMIN_RAMRO_END 0x7113FF +#define NV4_PRAMIN_CTX_0(i) (0x700000 + (i)*16) +// This is the same format as PGRAPH_CTX_SWITCH +#define NV4_PRAMIN_CTX_0_SIZE_1 0x10000 +#define NV4_PRAMIN_CTX_0_NVCLASS 0 +#define NV4_PRAMIN_CTX_0_CHROMA_KEY 12 +#define NV4_PRAMIN_CTX_0_CHROMA_KEY_ENABLE 0x1 +#define NV4_PRAMIN_CTX_0_USER_CLIP 13 +#define NV4_PRAMIN_CTX_0_USER_CLIP_ENABLE 0x1 +#define NV4_PRAMIN_CTX_0_SWIZZLE 14 +#define NV4_PRAMIN_CTX_0_SWIZZLE_ENABLE 0x1 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG 17:15 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_SRCCOPY_AND 0x0 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_ROP_AND 0x1 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_BLEND_AND 0x2 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_SRCCOPY 0x3 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_SRCCOPY_PRE 0x4 +#define NV4_PRAMIN_CTX_0_PATCH_CONFIG_BLEND_PRE 0x5 +#define NV4_PRAMIN_CTX_0_PATCH_STATUS 24 +#define NV4_PRAMIN_CTX_0_PATCH_STATUS_INVALID 0x0 +#define NV4_PRAMIN_CTX_0_PATCH_STATUS_VALID 0x1 +#define NV4_PRAMIN_CTX_0_CONTEXT_SURFACE 25 +#define NV4_PRAMIN_CTX_0_CONTEXT_SURFACE_INVALID 0x0 +#define NV4_PRAMIN_CTX_0_CONTEXT_SURFACE_VALID 0x1 +#define NV4_PRAMIN_CTX_1(i) (0x700004 + (i)*16) +#define NV4_PRAMIN_CTX_1_SIZE_1 0x10000 +#define NV4_PRAMIN_CTX_1_MONO_FORMAT 0 +#define NV4_PRAMIN_CTX_1_MONO_FORMAT_INVALID 0x00 +#define NV4_PRAMIN_CTX_1_MONO_FORMAT_CGA6_M1 0x01 +#define NV4_PRAMIN_CTX_1_MONO_FORMAT_LE_M1 0x02 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT 8 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_INVALID 0x00 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_Y8 0x01 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X16A8Y8 0x02 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X24Y8 0x03 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_A1R5G5B5 0x06 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X1R5G5B5 0x07 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X16A1R5G5B5 0x08 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X17R5G5B5 0x09 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_R5G6B5 0x0A +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_A16R5G6B5 0x0B +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X16R5G6B5 0x0C +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_A8R8G8B8 0x0D +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X8R8G8B8 0x0E +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_Y16 0x0F +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_A16Y16 0x10 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_X16Y16 0x11 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_V8YB8U8YA8 0x12 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_YB8V8YA8U8 0x13 +#define NV4_PRAMIN_CTX_1_COLOR_FORMAT_LE_Y32 0x14 +#define NV4_PRAMIN_CTX_1_NOTIFY_INSTANCE 16 +#define NV4_PRAMIN_CTX_1_NOTIFY_INSTANCE_INVALID 0x00 +#define NV4_PRAMIN_CTX_2(i) (0x700008 + (i)*16) +#define NV4_PRAMIN_CTX_2_SIZE_1 0x10000 +#define NV4_PRAMIN_CTX_2_DMA_0_INSTANCE 0 +#define NV4_PRAMIN_CTX_2_DMA_0_INSTANCE_INVALID 0x00 +#define NV4_PRAMIN_CTX_2_DMA_1_INSTANCE 16 +#define NV4_PRAMIN_CTX_2_DMA_1_INSTANCE_INVALID 0x00 + +#define NV4_FIFO_DMA_OPCODE ( 0*32+31):( 0*32+29) +#define NV4_FIFO_DMA_OPCODE_METHOD 0x0 +#define NV4_FIFO_DMA_OPCODE_JUMP 0x1 +#define NV4_FIFO_DMA_METHOD_COUNT ( 0*32+28):( 0*32+18) +#define NV4_FIFO_DMA_METHOD_SUBCHANNEL ( 0*32+15):( 0*32+13) +#define NV4_FIFO_DMA_METHOD_ADDRESS ( 0*32+12):( 0*32+ 2) +#define NV4_FIFO_DMA_DATA ( 1*32+31):( 1*32+ 0) +#define NV4_FIFO_DMA_JUMP_OFFSET 2 + +// DFB is in BAR1. Access it as VRAM + +#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 + +#define NV4_PDAC_DATA(i) (0x680000+(i)*4) +#define NV4_PDAC_DATA_SIZE_1 16 +#define NV4_PDAC_DATA_VALUE 0 + +// WARNING! +// This has shown up at 0x700000 on real NV4 +#define NV4_PROM_START 0x300000 +#define NV4_PROM_END 0x30FFFF +#define NV4_PROM_DATA(i) (NV4_PROM_START+(i)) +#define NV4_PROM_SIZE 65536 + +#define NV4_PROM_ERRATA_START 0x700000 +#define NV4_PROM_ERRATA_END 0x70FFFF +#define NV4_PROM_ERRATA_DATA(i) (NV4_PROM_ERRATA_START+(i)) + +#define NV4_PRM 0x5FFF:0x4000 +#define NV4_PRM_INTR_0 0x4100 +#define NV4_PRM_INTR_0_TRACE_MPU401 0 +#define NV4_PRM_INTR_0_TRACE_MPU401_NOT_PENDING 0x0 +#define NV4_PRM_INTR_0_TRACE_MPU401_PENDING 0x1 +#define NV4_PRM_INTR_0_TRACE_MPU401_RESET 0x1 +#define NV4_PRM_INTR_0_TRACE_FM 4 +#define NV4_PRM_INTR_0_TRACE_FM_NOT_PENDING 0x0 +#define NV4_PRM_INTR_0_TRACE_FM_PENDING 0x1 +#define NV4_PRM_INTR_0_TRACE_FM_RESET 0x1 +#define NV4_PRM_INTR_0_TRACE_SB_DIGITAL 8 +#define NV4_PRM_INTR_0_TRACE_SB_DIGITAL_NOT_PENDING 0x0 +#define NV4_PRM_INTR_0_TRACE_SB_DIGITAL_PENDING 0x1 +#define NV4_PRM_INTR_0_TRACE_SB_DIGITAL_RESET 0x1 +#define NV4_PRM_INTR_0_TRACE_SB_MIXER 12 +#define NV4_PRM_INTR_0_TRACE_SB_MIXER_NOT_PENDING 0x0 +#define NV4_PRM_INTR_0_TRACE_SB_MIXER_PENDING 0x1 +#define NV4_PRM_INTR_0_TRACE_SB_MIXER_RESET 0x1 +#define NV4_PRM_INTR_0_TRACE_OVERFLOW 16 +#define NV4_PRM_INTR_0_TRACE_OVERFLOW_NOT_PENDING 0x0 +#define NV4_PRM_INTR_0_TRACE_OVERFLOW_PENDING 0x1 +#define NV4_PRM_INTR_0_TRACE_OVERFLOW_RESET 0x1 +#define NV4_PRM_INTR_EN_0 0x4140 +#define NV4_PRM_INTR_EN_0_TRACE_MPU401 0 +#define NV4_PRM_INTR_EN_0_TRACE_MPU401_ENABLED 0x1 +#define NV4_PRM_INTR_EN_0_TRACE_FM 4 +#define NV4_PRM_INTR_EN_0_TRACE_FM_ENABLED 0x1 +#define NV4_PRM_INTR_EN_0_TRACE_SB_DIGITAL 8 +#define NV4_PRM_INTR_EN_0_TRACE_SB_DIGITAL_ENABLED 0x1 +#define NV4_PRM_INTR_EN_0_TRACE_SB_MIXER 12 +#define NV4_PRM_INTR_EN_0_TRACE_SB_MIXER_ENABLED 0x1 +#define NV4_PRM_INTR_EN_0_TRACE_OVERFLOW 16 +#define NV4_PRM_INTR_EN_0_TRACE_OVERFLOW_ENABLED 0x1 +#define NV4_PRM_RAMRM 0x4200 +#define NV4_PRM_RAMRM_BASE_ADDRESS 12 +#define NV4_PRM_RAMRM_BASE_ADDRESS_2000 0x2000 +#define NV4_PRM_TRACE 0x4300 +#define NV4_PRM_TRACE_IO_CAPTURE 0 +#define NV4_PRM_TRACE_IO_CAPTURE_DISABLED 0x0 +#define NV4_PRM_TRACE_IO_CAPTURE_WRITES 0x1 +#define NV4_PRM_TRACE_IO_CAPTURE_READS 0x2 +#define NV4_PRM_TRACE_IO_CAPTURE_READS_WRITES 0x3 +#define NV4_PRM_TRACE_IO_WRITE 4 +#define NV4_PRM_TRACE_IO_WRITE_NONE 0x0 +#define NV4_PRM_TRACE_IO_WRITE_OCCURED 0x1 +#define NV4_PRM_TRACE_IO_WRITE_RESET 0x1 +#define NV4_PRM_TRACE_IO_READ 5 +#define NV4_PRM_TRACE_IO_READ_NONE 0x0 +#define NV4_PRM_TRACE_IO_READ_OCCURED 0x1 +#define NV4_PRM_TRACE_IO_READ_RESET 0x1 +#define NV4_PRM_TRACE_INDEX 0x4310 +#define NV4_PRM_TRACE_INDEX_ADDRESS 0 +#define NV4_PRM_TRACE_INDEX_ADDRESS_0 0x0 +#define NV4_PRM_IGNORE_0 0x4320 +#define NV4_PRM_IGNORE_0_MPU401 0 +#define NV4_PRM_IGNORE_0_MPU401_DISABLED 0x0 +#define NV4_PRM_IGNORE_0_MPU401_WRITES 0x1 +#define NV4_PRM_IGNORE_0_MPU401_READS 0x2 +#define NV4_PRM_IGNORE_0_MPU401_READS_WRITES 0x3 +#define NV4_PRM_IGNORE_0_FM 4 +#define NV4_PRM_IGNORE_0_FM_DISABLED 0x0 +#define NV4_PRM_IGNORE_0_FM_WRITES 0x1 +#define NV4_PRM_IGNORE_0_FM_READS 0x2 +#define NV4_PRM_IGNORE_0_FM_READS_WRITES 0x3 +#define NV4_PRM_IGNORE_0_SB_DIGITAL 8 +#define NV4_PRM_IGNORE_0_SB_DIGITAL_DISABLED 0x0 +#define NV4_PRM_IGNORE_0_SB_DIGITAL_WRITES 0x1 +#define NV4_PRM_IGNORE_0_SB_DIGITAL_READS 0x2 +#define NV4_PRM_IGNORE_0_SB_DIGITAL_READS_WRITES 0x3 +#define NV4_PRM_IGNORE_0_SB_MIXER 12 +#define NV4_PRM_IGNORE_0_SB_MIXER_DISABLED 0x0 +#define NV4_PRM_IGNORE_0_SB_MIXER_WRITES 0x1 +#define NV4_PRM_IGNORE_0_SB_MIXER_READS 0x2 +#define NV4_PRM_IGNORE_0_SB_MIXER_READS_WRITES 0x3 + +// +// PIO submission +// + +#define NV4_USER_START 0x800000 +#define NV4_USER_END 0xFFFFFF + +#define NV4_USER_OBJECT(i,j) (0x800000+(i)*0x10000+(j)*0x2000) +#define NV4_USER_OBJECT_SIZE_1 16 +#define NV4_USER_OBJECT_SIZE_2 8 +#define NV4_USER_OBJECT_HANDLE 0 +#define NV4_USER_FREE016(i,j) (0x800010+(i)*65536+(j)*8192) +#define NV4_USER_FREE016_SIZE_1 16 +#define NV4_USER_FREE016_SIZE_2 8 +#define NV4_USER_FREE016_COUNT_LO 0 +#define NV4_USER_FREE016_COUNT_LO_0 0x0 +#define NV4_USER_FREE016_COUNT 2 +#define NV4_USER_FREE016_COUNT_HI 10 +#define NV4_USER_FREE016_COUNT_HI_0 0x0 +#define NV4_USER_FREE032(i,j) (0x800010+(i)*65536+(j)*8192) +#define NV4_USER_FREE032_SIZE_1 16 +#define NV4_USER_FREE032_SIZE_2 8 +#define NV4_USER_FREE032_COUNT_LO 0 +#define NV4_USER_FREE032_COUNT_LO_0 0x0 +#define NV4_USER_FREE032_COUNT 2 +#define NV4_USER_FREE032_COUNT_HI 10 +#define NV4_USER_FREE032_COUNT_HI_0 0x0 +#define NV4_USER_ZERO016(i,j,k) (0x0800012+(i)*65536+(j)*8192+(k)*2) +#define NV4_USER_ZERO016_SIZE_1 16 +#define NV4_USER_ZERO016_SIZE_2 8 +#define NV4_USER_ZERO016_SIZE_3 7 +#define NV4_USER_ZERO016_COUNT 0 +#define NV4_USER_ZERO016_COUNT_0 0x0 +#define NV4_USER_ZERO032(i,j,k) (0x0800014+(i)*65536+(j)*8192+(k)*4) +#define NV4_USER_ZERO032_SIZE_1 16 +#define NV4_USER_ZERO032_SIZE_2 8 +#define NV4_USER_ZERO032_SIZE_3 3 +#define NV4_USER_ZERO032_COUNT 0 +#define NV4_USER_ZERO032_COUNT_0 0x0 +#define NV4_USER_DMA_PUT(i,j) (0x800040+(i)*0x10000+(j)*0x2000) +#define NV4_USER_DMA_PUT_OFFSET 2 +#define NV4_USER_DMA_GET(i,j) (0x800044+(i)*0x10000+(j)*0x2000) +#define NV4_USER_DMA_GET_OFFSET 2 + +#define NV4_USER_ADR_CHID 16 +#define NV4_USER_ADR_SUBCHID 13 +#define NV4_USER_ADR_METHOD 0 +#define NV4_USER_DEVICE 16 + +#define NV4_PTIMER_START 0x9000 +#define NV4_PTIMER_END 0x9FFF + +#define NV4_PTIMER_INTR 0x9100 +#define NV4_PTIMER_INTR_ALARM 0 +#define NV4_PTIMER_INTR_ALARM_NOT_PENDING 0x0 +#define NV4_PTIMER_INTR_ALARM_PENDING 0x1 +#define NV4_PTIMER_INTR_ALARM_RESET 0x1 +#define NV4_PTIMER_INTR_EN 0x9140 +#define NV4_PTIMER_INTR_EN_ALARM 0 +#define NV4_PTIMER_INTR_EN_ALARM_ENABLED 0x1 // 0 = disabled +#define NV4_PTIMER_NUMERATOR 0x9200 +#define NV4_PTIMER_NUMERATOR_VALUE 0 +#define NV4_PTIMER_NUMERATOR_VALUE_0 0x0 +#define NV4_PTIMER_DENOMINATOR 0x9210 +#define NV4_PTIMER_DENOMINATOR_VALUE 0 +#define NV4_PTIMER_DENOMINATOR_VALUE_0 0x0 +#define NV4_PTIMER_TIME_0 0x9400 +#define NV4_PTIMER_TIME_0_NSEC 5 +#define NV4_PTIMER_TIME_1 0x9410 +#define NV4_PTIMER_TIME_1_NSEC 0 +#define NV4_PTIMER_ALARM 0x9420 +#define NV4_PTIMER_ALARM_NSEC 5 + +#define NV4_TRACE 0xFFFF: 0x0 +#define NV4_TRACE_DATA ( 0*32+ 7):( 0*32+ 0) +#define NV4_TRACE_ACCESS ( 0*32+14):( 0*32+14) +#define NV4_TRACE_ACCESS_WRITE 0x0 +#define NV4_TRACE_ACCESS_READ 0x1 +#define NV4_TRACE_TYPE ( 0*32+15):( 0*32+15) +#define NV4_TRACE_TYPE_IO 0x0 +#define NV4_TRACE_TYPE_MEMORY 0x1 +#define NV4_TRACE_ADDRESS ( 0*32+31):( 0*32+16) + +#define NV4_RAMHT_SIZE_0 0xFFF +#define NV4_RAMHT_SIZE_1 0x1FFF +#define NV4_RAMHT_SIZE_2 0x3FFF +#define NV4_RAMHT_SIZE_3 0x7FFF +#define NV4_RAMHT_HANDLE ( 0*32+31):( 0*32+ 0) +#define NV4_RAMHT_INSTANCE ( 1*32+15):( 1*32+ 0) +#define NV4_RAMHT_ENGINE ( 1*32+17):( 1*32+16) +#define NV4_RAMHT_ENGINE_SW 0x0 +#define NV4_RAMHT_ENGINE_GRAPHICS 0x1 +#define NV4_RAMHT_ENGINE_DVD 0x2 +#define NV4_RAMHT_CHID ( 1*32+27):( 1*32+24) +#define NV4_RAMHT_STATUS ( 1*32+31):( 1*32+31) +#define NV4_RAMHT_STATUS_INVALID 0x0 +#define NV4_RAMHT_STATUS_VALID 0x1 + +#define NV4_RAMRO_SIZE_0 0x1FF +#define NV4_RAMRO_SIZE_1 0x1FFF +#define NV4_RAMRO_METHOD ( 0*32+12):( 0*32+ 0) +#define NV4_RAMRO_SUBCHANNEL ( 0*32+15):( 0*32+13) +#define NV4_RAMRO_CHID ( 0*32+22):( 0*32+16) +#define NV4_RAMRO_TYPE ( 0*32+23):( 0*32+23) +#define NV4_RAMRO_TYPE_WRITE 0x0 +#define NV4_RAMRO_TYPE_READ 0x1 +#define NV4_RAMRO_BYTE_ENABLES ( 0*32+27):( 0*32+24) +#define NV4_RAMRO_REASON ( 0*32+31):( 0*32+28) +#define NV4_RAMRO_REASON_ILLEGAL_ACCESS 0x0 +#define NV4_RAMRO_REASON_NO_CACHE_AVAILABLE 0x1 +#define NV4_RAMRO_REASON_CACHE_RAN_OUT 0x2 +#define NV4_RAMRO_REASON_FREE_COUNT_OVERRUN 0x3 +#define NV4_RAMRO_REASON_CAUGHT_LYING 0x4 +#define NV4_RAMRO_REASON_RESERVED_ACCESS 0x5 +#define NV4_RAMRO_DATA ( 1*32+31):( 1*32+ 0) + +#define NV4_RAMFC_SIZE_0 0x1FF +#define NV4_RAMFC_DMA_PUT ( 0*32+28):( 0*32+ 2) +#define NV4_RAMFC_DMA_GET ( 1*32+28):( 1*32+ 2) +#define NV4_RAMFC_DMA_INST ( 2*32+15):( 2*32+ 0) +#define NV4_RAMFC_DMA_METHOD ( 3*32+12):( 3*32+ 2) +#define NV4_RAMFC_DMA_SUBCHANNEL ( 3*32+15):( 3*32+13) +#define NV4_RAMFC_DMA_METHOD_COUNT ( 3*32+28):( 3*32+18) +#define NV4_RAMFC_DMA_FETCH_TRIG ( 4*32+ 7):( 4*32+ 3) +#define NV4_RAMFC_DMA_FETCH_SIZE ( 4*32+15):( 4*32+13) +#define NV4_RAMFC_DMA_FETCH_MAX_REQS ( 4*32+19):( 4*32+16) +#define NV4_RAMFC_ENGINE_SUB_0 ( 5*32+ 1):( 5*32+ 0) +#define NV4_RAMFC_ENGINE_SUB_1 ( 5*32+ 5):( 5*32+ 4) +#define NV4_RAMFC_ENGINE_SUB_2 ( 5*32+ 9):( 5*32+ 8) +#define NV4_RAMFC_ENGINE_SUB_3 ( 5*32+13):( 5*32+12) +#define NV4_RAMFC_ENGINE_SUB_4 ( 5*32+17):( 5*32+16) +#define NV4_RAMFC_ENGINE_SUB_5 ( 5*32+21):( 5*32+20) +#define NV4_RAMFC_ENGINE_SUB_6 ( 5*32+25):( 5*32+24) +#define NV4_RAMFC_ENGINE_SUB_7 ( 5*32+29):( 5*32+28) +#define NV4_RAMFC_ENGINE_SW 0x0 +#define NV4_RAMFC_ENGINE_GRAPHICS 0x1 +#define NV4_RAMFC_ENGINE_DVD 0x2 +#define NV4_RAMFC_PULL1_ENGINE ( 6*32+ 1):( 6*32+ 0) +#define NV4_RAMFC_PULL1_ENGINE_SW 0x0 +#define NV4_RAMFC_PULL1_ENGINE_GRAPHICS 0x1 +#define NV4_RAMFC_PULL1_ENGINE_DVD 0x2 + + +#define NV4_RAMDVD_CTX_TABLE (63*32+31):( 0*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT(c,s) (((c)*4+((s)/2))*32+((s)%2)*16+15):(((c)*4+((s)/2))*32+((s)%2)*16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_0 ( 0*32+15):( 0*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_1 ( 0*32+31):( 0*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_2 ( 1*32+15):( 1*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_3 ( 1*32+31):( 1*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_4 ( 2*32+15):( 2*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_5 ( 2*32+31):( 2*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_6 ( 3*32+15):( 3*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_0_7 ( 3*32+31):( 3*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_0 (60*32+15):(60*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_1 (60*32+31):(60*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_2 (61*32+15):(61*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_3 (61*32+31):(61*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_4 (62*32+15):(62*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_5 (62*32+31):(62*32+16) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_6 (63*32+15):(63*32+ 0) +#define NV4_RAMDVD_CTX_TABLE_OBJECT_15_7 (63*32+31):(63*32+16) + +#define NV4_DMA_CLASS ( 0*32+11):( 0*32+ 0) +#define NV4_DMA_PAGE_TABLE ( 0*32+12):( 0*32+12) +#define NV4_DMA_PAGE_TABLE_NOT_PRESENT 0x0 +#define NV4_DMA_PAGE_TABLE_PRESENT 0x1 +#define NV4_DMA_PAGE_ENTRY ( 0*32+13):( 0*32+13) +#define NV4_DMA_PAGE_ENTRY_NOT_LINEAR 0x0 +#define NV4_DMA_PAGE_ENTRY_LINEAR 0x1 +#define NV4_DMA_TARGET_NODE ( 0*32+17):( 0*32+16) +#define NV4_DMA_TARGET_NODE_NVM 0x0 +#define NV4_DMA_TARGET_NODE_PCI 0x2 +#define NV4_DMA_TARGET_NODE_AGP 0x3 +#define NV4_DMA_ADJUST ( 0*32+31):( 0*32+20) +#define NV4_DMA_LIMIT ( 1*32+31):( 1*32+ 0) +#define NV4_DMA_ACCESS ( 2*32+ 1):( 2*32+ 1) +#define NV4_DMA_ACCESS_READ_ONLY 0x0 +#define NV4_DMA_ACCESS_READ_AND_WRITE 0x1 +#define NV4_DMA_FRAME_ADDRESS ( 2*32+31):( 2*32+12) + +#define NV4_SUBCHAN_CTX_SWITCH ( 0*32+31):( 0*32+ 0) +#define NV4_SUBCHAN_DMA_INSTANCE ( 1*32+15):( 1*32+ 0) +#define NV4_SUBCHAN_NOTIFY_INSTANCE ( 1*32+31):( 1*32+16) +#define NV4_SUBCHAN_MEMFMT_INSTANCE ( 2*32+15):( 2*32+ 0) +#define NV4_SUBCHAN_MEMFMT_LINEAR ( 2*32+16):( 2*32+16) +#define NV4_SUBCHAN_MEMFMT_LINEAR_OUT 0x0 +#define NV4_SUBCHAN_MEMFMT_LINEAR_IN 0x1 \ No newline at end of file diff --git a/src/include/86box/utils/video_stdlib.h b/src/include/86box/utils/video_stdlib.h new file mode 100644 index 000000000..0d4b148d6 --- /dev/null +++ b/src/include/86box/utils/video_stdlib.h @@ -0,0 +1,23 @@ +/* + * 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. + * + * Standard library for implementation of video functionality that is duplicated across multiple cards. + * + * + * + * Authors: Connor Hyde + * + * Copyright 2025 Connor Hyde + */ + + +/* ROP */ + +#define VIDEO_ROP_SRC_COPY 0xCC + +int32_t video_rop_gdi_ternary(int32_t rop, int32_t src, int32_t dst, int32_t pattern); \ No newline at end of file diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 81424dbcb..c87ef4f77 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -630,6 +630,13 @@ 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 nv1_device_edge2k; +extern const device_t nv1_device_edge3k; +extern const device_t nv3_device_pci; +extern const device_t nv3_device_agp; +extern const device_t nv3t_device_pci; +extern const device_t nv3t_device_agp; +extern const device_t nv4_device_agp; /* Wyse 700 */ extern const device_t wy700_device; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 1a004d958..87ff7293a 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -171,7 +171,15 @@ add_library(ui STATIC qt_newfloppydialog.ui qt_harddiskdialog.cpp qt_harddiskdialog.hpp - qt_harddiskdialog.ui + qt_harddiskdialog.ui + + qt_gpudebug_vram.cpp + qt_gpudebug_vram.hpp + qt_gpudebug_vram.ui + + qt_gpudebug_visualnv.cpp + qt_gpudebug_visualnv.hpp + qt_gpudebug_visualnv.ui qt_harddrive_common.cpp qt_harddrive_common.hpp diff --git a/src/qt/qt_gpudebug_visualnv.cpp b/src/qt/qt_gpudebug_visualnv.cpp new file mode 100644 index 000000000..3b2ba8472 --- /dev/null +++ b/src/qt/qt_gpudebug_visualnv.cpp @@ -0,0 +1,177 @@ +/* + * 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. + * + * GPU Debugging Tools - Visual NV Debugger implementation + * + * + * + * Authors: starfrost + * + * Copyright 2025 starfrost + */ + +/* C++ includes */ +#include +#include + + +/* Qt includes*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ui_qt_gpudebug_visualnv.h" + +/* 86Box core includes */ +extern "C" +{ + /* NOTE: DO NOT REMOVE */ + #include <86box/86box.h> + #include <86box/device.h> + #include <86box/mem.h> + #include <86box/pci.h> + #include <86box/rom.h> + #include <86box/video.h> + #include <86box/nv/vid_nv.h> + #include <86box/nv/vid_nv3.h> +} + +VisualNVDialog::VisualNVDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::VisualNVDialog) +{ + ui->setupUi(this); + + connect(ui->btnLoadSavestate, &QPushButton::clicked, this, &VisualNVDialog::on_btnLoadSavestate_clicked); + connect(ui->fbStartAddress, &QPlainTextEdit::textChanged, this, &VisualNVDialog::on_fbStartAddress_changed); + connect(ui->bPitch0Value, &QPlainTextEdit::textChanged, this, &VisualNVDialog::on_bPitch0Value_changed); + connect(ui->bPitch1Value, &QPlainTextEdit::textChanged, this, &VisualNVDialog::on_bPitch1Value_changed); +} + +// VisualNV dialog destructor +VisualNVDialog::~VisualNVDialog() +{ + +} + +void VisualNVDialog::on_btnLoadSavestate_clicked() +{ + if (!nv3) + return; + + QString bar0_file_name = QFileDialog::getOpenFileName + ( + this, + tr("Please provide NVPlay 0.3.0.7+ NV3BAR0.BIN file"), + ".", + tr("NVPlay MMIO Dump Files (*.bin)") + ); + + QString bar1_file_name = QFileDialog::getOpenFileName + ( + this, + tr("Please provide NVPlay 0.3.0.7+ NV3BAR1.BIN file"), + ".", + tr("NVPlay VRAM/RAMIN Dump Files (*.bin)") + ); + + // + // Open both dump files + // + + QFile bar0(bar0_file_name); + QFile bar1(bar1_file_name); + + if (!bar0.open(QIODevice::ReadOnly)) + { + warning("Failed to open NV3BAR0.bin!"); + return; + } + + if (!bar1.open(QIODevice::ReadOnly)) + { + warning("Failed to open NV3BAR1.bin!"); + return; + } + + if (bar0.size() != NV3_MMIO_SIZE + || bar1.size() != NV3_MMIO_SIZE) + { + warning("NV3BAR0.bin and NV3BAR1.bin must be 16MB!"); + bar0.close(); + bar1.close(); + return; + } + + // Load VRAM contents only for now. Todo: MMIO+RAMIN + QString oldTitle = this->windowTitle(); + + this->setWindowTitle(tr("RIVA 128 Realtime Debugger: Savestate Loading...")); + + bar1.read((char*)nv3->nvbase.svga.vram, nv3->nvbase.vram_amount); + + this->setWindowTitle(oldTitle); + +} + +void VisualNVDialog::on_fbStartAddress_changed() +{ + if (nv3) + { + nv3->nvbase.debug_dba_enabled = true; + + bool ok = true; + + nv3->nvbase.debug_dba = ui->fbStartAddress->toPlainText().toInt(&ok); + + if (!ok) + nv3->nvbase.debug_dba_enabled = false; + } +} + +void VisualNVDialog::on_bPitch0Value_changed() +{ + if (nv3) + { + bool ok = true; + + uint32_t old_bpitch = nv3->pgraph.bpitch[0]; + + nv3->pgraph.bpitch[0] = ui->bPitch0Value->toPlainText().toInt(&ok); + + if (!ok) + nv3->pgraph.bpitch[0] = old_bpitch; + } + +} + +void VisualNVDialog::on_bPitch1Value_changed() +{ + if (nv3) + { + bool ok = true; + + uint32_t old_bpitch = nv3->pgraph.bpitch[1]; + + nv3->pgraph.bpitch[1] = ui->bPitch0Value->toPlainText().toInt(&ok); + + if (!ok) + nv3->pgraph.bpitch[1] = old_bpitch; + } + +} \ No newline at end of file diff --git a/src/qt/qt_gpudebug_visualnv.hpp b/src/qt/qt_gpudebug_visualnv.hpp new file mode 100644 index 000000000..ee87dc0b3 --- /dev/null +++ b/src/qt/qt_gpudebug_visualnv.hpp @@ -0,0 +1,46 @@ +/* + * 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. + * + * GPU Debugging Tools - VRAM Viewer headers + * + * + * + * Authors: starfrost + * + * Copyright 2025 starfrost + */ + + +#pragma once + +#include + +namespace Ui +{ + class VisualNVDialog; +} + +class VisualNVDialog : public QDialog +{ + Q_OBJECT + + public: + explicit VisualNVDialog(QWidget *parent = nullptr); + ~VisualNVDialog(); + + void on_btnLoadSavestate_clicked(); + void on_fbStartAddress_changed(); + void on_bPitch0Value_changed(); + void on_bPitch1Value_changed(); + + protected: + private: + Ui::VisualNVDialog* ui; + + +}; \ No newline at end of file diff --git a/src/qt/qt_gpudebug_visualnv.ui b/src/qt/qt_gpudebug_visualnv.ui new file mode 100644 index 000000000..ce45c4e44 --- /dev/null +++ b/src/qt/qt_gpudebug_visualnv.ui @@ -0,0 +1,213 @@ + + + VisualNVDialog + + + + 0 + 0 + 620 + 350 + + + + + 0 + 0 + + + + + 620 + 350 + + + + + 620 + 350 + + + + RIVA 128 Realtime Debugger + + + + + + + + 10 + 0 + 201 + 171 + + + + PFIFO State + + + + + + 220 + 0 + 361 + 171 + + + + PGRAPH State + + + + + + 10 + 180 + 571 + 141 + + + + VRAM Control + + + + + 160 + 30 + 104 + 21 + + + + + + + 10 + 30 + 151 + 21 + + + + <html><head/><body><p>VRAM Visual Aperture Start</p></body></html> + + + + + + 390 + 30 + 91 + 16 + + + + <html><head/><body><p>FB Start Address:</p></body></html> + + + + + + 480 + 30 + 81 + 16 + + + + <html><head/><body><p><span style=" font-weight:700;">PLACEHOLDER</span></p></body></html> + + + + + + 160 + 60 + 104 + 21 + + + + + + + 10 + 60 + 151 + 21 + + + + <html><head/><body><p>Pixel Depth</p></body></html> + + + + + + 10 + 110 + 231 + 24 + + + + Load nvplay savestate from real hardware + + + + + + 390 + 60 + 61 + 16 + + + + <html><head/><body><p>BPITCH[0]:</p></body></html> + + + + + + 460 + 60 + 104 + 21 + + + + + + + 460 + 90 + 104 + 21 + + + + + + + 390 + 90 + 61 + 16 + + + + <html><head/><body><p>BPITCH[1]:</p></body></html> + + + + + + + + + + diff --git a/src/qt/qt_gpudebug_vram.cpp b/src/qt/qt_gpudebug_vram.cpp new file mode 100644 index 000000000..000f41263 --- /dev/null +++ b/src/qt/qt_gpudebug_vram.cpp @@ -0,0 +1,54 @@ +/* + * 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. + * + * GPU Debugging Tools - VRAM Viewer implementation + * + * + * + * Authors: starfrost + * + * Copyright 2025 starfrost + */ + +/* C++ includes */ +#include +#include + + +/* Qt includes*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ui_qt_gpudebug_vram.h" + +/* 86Box core includes */ +extern "C" +{ + +} + +GPUDebugVRAMDialog::GPUDebugVRAMDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::GPUDebugVRAMDialog) +{ + ui->setupUi(this); +} + +GPUDebugVRAMDialog::~GPUDebugVRAMDialog() +{ + +} \ No newline at end of file diff --git a/src/qt/qt_gpudebug_vram.hpp b/src/qt/qt_gpudebug_vram.hpp new file mode 100644 index 000000000..18b2e8c96 --- /dev/null +++ b/src/qt/qt_gpudebug_vram.hpp @@ -0,0 +1,40 @@ +/* + * 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. + * + * GPU Debugging Tools - VRAM Viewer headers + * + * + * + * Authors: starfrost + * + * Copyright 2025 starfrost + */ + + +#pragma once + +#include + +namespace Ui +{ + class GPUDebugVRAMDialog; +} + +class GPUDebugVRAMDialog : public QDialog +{ + Q_OBJECT + + public: + explicit GPUDebugVRAMDialog(QWidget *parent = nullptr); + ~GPUDebugVRAMDialog(); + protected: + private: + Ui::GPUDebugVRAMDialog* ui; + + +}; \ No newline at end of file diff --git a/src/qt/qt_gpudebug_vram.ui b/src/qt/qt_gpudebug_vram.ui new file mode 100644 index 000000000..a92a60306 --- /dev/null +++ b/src/qt/qt_gpudebug_vram.ui @@ -0,0 +1,42 @@ + + + GPUDebugVRAMDialog + + + + 0 + 0 + 600 + 400 + + + + + 0 + 0 + + + + + 600 + 400 + + + + + 600 + 400 + + + + VRAM Viewer + + + + + + + + + + diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 954547078..e0900d1ef 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -24,6 +24,8 @@ #include "qt_mainwindow.hpp" #include "ui_qt_mainwindow.h" +#include "ui_qt_gpudebug_vram.h" +#include "ui_qt_gpudebug_visualnv.h" #include "qt_specifydimensions.h" #include "qt_soundgain.hpp" @@ -106,6 +108,8 @@ void qt_set_sequence_auto_mnemonic(bool b); #include "qt_mediamenu.hpp" #include "qt_util.hpp" +#include "qt_gpudebug_vram.hpp" + #if defined __unix__ && !defined __HAIKU__ # ifndef Q_OS_MACOS # include "evdev_keyboard.hpp" @@ -285,29 +289,7 @@ MainWindow::MainWindow(QWidget *parent) this->setWindowTitle(QString("%1 - %2 %3").arg(vmname, EMU_NAME, EMU_VERSION_FULL)); connect(this, &MainWindow::hardResetCompleted, this, [this]() { - ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); - num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); - scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); - caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); - int ext_ax_kbd = machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD) && - (keyboard_type == KEYBOARD_TYPE_AX); - int int_ax_kbd = machine_has_flags(machine, MACHINE_KEYBOARD_JIS) && - !machine_has_bus(machine, MACHINE_BUS_PS2_PORTS); - kana_label->setVisible(ext_ax_kbd || int_ax_kbd); - while (QApplication::overrideCursor()) - QApplication::restoreOverrideCursor(); -#ifdef USE_WACOM - ui->menuTablet_tool->menuAction()->setVisible(mouse_input_mode >= 1); -#else - ui->menuTablet_tool->menuAction()->setVisible(false); -#endif - - bool enable_comp_option = false; - for (int i = 0; i < MONITORS_NUM; i++) { - if (monitors[i].mon_composite) { enable_comp_option = true; break; } - } - - ui->actionCGA_composite_settings->setEnabled(enable_comp_option); + onHardResetCompleted(); }); connect(this, &MainWindow::showMessageForNonQtThread, this, &MainWindow::showMessage_, Qt::QueuedConnection); @@ -908,6 +890,50 @@ MainWindow::MainWindow(QWidget *parent) updateShortcuts(); } +void MainWindow::onHardResetCompleted() +{ + ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); + num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + int ext_ax_kbd = machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD) && + (keyboard_type == KEYBOARD_TYPE_AX); + int int_ax_kbd = machine_has_flags(machine, MACHINE_KEYBOARD_JIS) && + !machine_has_bus(machine, MACHINE_BUS_PS2_PORTS); + kana_label->setVisible(ext_ax_kbd || int_ax_kbd); + while (QApplication::overrideCursor()) + QApplication::restoreOverrideCursor(); +#ifdef USE_WACOM + ui->menuTablet_tool->menuAction()->setVisible(mouse_input_mode >= 1); +#else + ui->menuTablet_tool->menuAction()->setVisible(false); +#endif + + bool enable_comp_option = false; + for (int i = 0; i < MONITORS_NUM; i++) { + if (monitors[i].mon_composite) { enable_comp_option = true; break; } + } + + ui->actionCGA_composite_settings->setEnabled(enable_comp_option); + +#ifdef ENABLE_NV_LOG + /* + THIS CODE SUCKS AND THIS DESIGN IS TERRIBLE - EVERYTHING ABOUT IT IS BAD AND WRONG. + ENTIRE DEVICE SUBSYSTEM IDEALLY WOULD BE DECOUPLED FROM UI BUT MEH + */ + + const device_t* vid_device = video_card_getdevice(gfxcard[0]); + + bool is_nv3 = (vid_device == &nv3_device_agp + || vid_device == &nv3_device_pci + || vid_device == &nv3t_device_agp + || vid_device == &nv3t_device_pci); + + ui->actionDebug_GPUDebug_VisualNv->setVisible(is_nv3); +#endif +} + + void MainWindow::closeEvent(QCloseEvent *event) { @@ -2525,3 +2551,29 @@ void MainWindow::on_actionCGA_composite_settings_triggered() config_save(); } + +void MainWindow::on_actionDebug_GPUDebug_VRAM_triggered() +{ + debugVramDialog = new GPUDebugVRAMDialog(this); + debugVramDialog->setWindowFlag(Qt::CustomizeWindowHint, true); + debugVramDialog->setWindowFlag(Qt::WindowTitleHint, true); + debugVramDialog->setWindowFlag(Qt::WindowSystemMenuHint, false); + // If I have this as a NON-MODAL dialog, input is just eaten without doing anything + // WTF?!?!?!?!? + //debugVramDialog->show(); + debugVramDialog->exec(); + +} + + +void MainWindow::on_actionDebug_GPUDebug_VisualNv_triggered() +{ + visualNvDialog = new VisualNVDialog(this); + visualNvDialog->setWindowFlag(Qt::CustomizeWindowHint, true); + visualNvDialog->setWindowFlag(Qt::WindowTitleHint, true); + visualNvDialog->setWindowFlag(Qt::WindowSystemMenuHint, false); + // If I have this as a NON-MODAL dialog, input is just eaten without doing anything + // WTF?!?!?!?!? + //visualNvDialog->show(); + visualNvDialog->exec(); +} \ No newline at end of file diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index f562c2ea9..6ae838896 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -17,6 +17,11 @@ extern QTimer discordupdate; +// NON-modal dialogs +#include "qt_gpudebug_vram.hpp" +#include "qt_gpudebug_visualnv.hpp" + + class MediaMenu; class RendererStack; @@ -74,6 +79,8 @@ signals: public slots: void showSettings(); void hardReset(); + void onHardResetCompleted(); + void togglePause(); void initRendererMonitorSlot(int monitor_index); void destroyRendererMonitorSlot(int monitor_index); @@ -136,7 +143,9 @@ private slots: void on_actionPreferences_triggered(); void on_actionEnable_Discord_integration_triggered(bool checked); void on_actionRenderer_options_triggered(); - + void on_actionDebug_GPUDebug_VRAM_triggered(); + void on_actionDebug_GPUDebug_VisualNv_triggered(); + void refreshMediaMenu(); void showMessage_(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool* done = nullptr); void getTitle_(wchar_t *title); @@ -175,6 +184,10 @@ private slots: private: Ui::MainWindow *ui; + + // NON-modal dialogs - these use ::show() and therefore have to be maintained as objects + GPUDebugVRAMDialog *debugVramDialog; + VisualNVDialog *visualNvDialog; std::unique_ptr status; std::shared_ptr mm; diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index ca7aca2ca..bebef8c88 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -251,11 +251,19 @@ + + + &Debugging Tools + + + + + @@ -919,7 +927,27 @@ &CGA composite settings... - + + + + + GPU Debug - VRAM Viewer + + + + + RIVA 128 Realtime Debugger + + + + + GPU Debug - VRAM Viewer + + + + + RIVA 128 Realtime Debugger + @@ -1049,6 +1077,54 @@ &8x + + + true + + + &Full screen stretch + + + + + true + + + &4:3 + + + + + true + + + &Square pixels (Keep ratio) + + + + + true + + + &Integer scale + + + + + true + + + 4:&3 Integer scale + + + + + true + + + &1x + + diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index c3efdaaff..b806f3ccb 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -1525,7 +1525,7 @@ emu8k_outw(uint16_t addr, uint16_t val, void *priv) default: break; } - emu8k_log("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice, + emu8k_log("EMU8K WRITE: : Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice, val); } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index f041ebb8c..fe9be9c2d 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -798,7 +798,7 @@ sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *priv) break; default: - sb_log("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + sb_log("sb_ct1335: : Unknown register write: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; } } @@ -899,7 +899,7 @@ sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *priv) break; default: - sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + sb_log("sb_ct1345: : Unknown register write: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; } } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index bcbc7aafd..fab669d28 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -24,4 +24,7 @@ add_library(utils OBJECT ini.c log.c random.c + + # VIDEO + video/video_rop.c ) diff --git a/src/utils/log.c b/src/utils/log.c index f0eb6aa3c..b8c28afab 100644 --- a/src/utils/log.c +++ b/src/utils/log.c @@ -44,6 +44,7 @@ typedef struct log_t { char **cyclic_buff; int32_t cyclic_last_line; int32_t log_cycles; + int32_t last_repeat_order; } log_t; /* File to log output to. */ @@ -219,9 +220,18 @@ log_out_cyclic(void* priv, const char* fmt, va_list ap) } - if (is_cycle) { - if (log->cyclic_last_line % repeat_order == 0) { - log->log_cycles++; + if (is_cycle) + { + if (log->cyclic_last_line % repeat_order == 0) + { + log->log_cycles++; + + // If the order of the log repeat changes + if (log->last_repeat_order != repeat_order + && log->last_repeat_order > 0) + { + log->log_cycles = 1; + } if (log->log_cycles == 1) { /* @@ -265,10 +275,13 @@ log_out_cyclic(void* priv, const char* fmt, va_list ap) } log->cyclic_last_line++; + + log->last_repeat_order = repeat_order; } } #endif + void log_fatal(void *priv, const char *fmt, ...) { diff --git a/src/utils/video/video_rop.c b/src/utils/video/video_rop.c new file mode 100644 index 000000000..146822201 --- /dev/null +++ b/src/utils/video/video_rop.c @@ -0,0 +1,790 @@ +#include +#include <86box/utils/video_stdlib.h> + +/* + Implements a standard GDI ternary rop for e.g. bitblit acceleration. + For further information on this function, refer to the documentation on Win32 GDI: + + https://learn.microsoft.com/en-us/windows/win32/gdi/binary-raster-operations + + This is currently used in the following graphics cards: Tseng Labs ET4000/32p, Cirrus Logic CL-GD54xx, 3dfx Voodoo Banshee/Voodoo 3, Trident TGUI9440, + S3 ViRGE, C&T 69000, ATI Mach64, and NVidia RIVA 128 +*/ +int32_t video_rop_gdi_ternary(int32_t rop, int32_t src, int32_t dst, int32_t pattern) +{ + uint32_t out = 0x00; + + switch (rop) + { + case 0x00: + out = 0; + break; + case 0x01: + out = ~(dst | (pattern | src)); + break; + case 0x02: + out = dst & ~(pattern | src); + break; + case 0x03: + out = ~(pattern | src); + break; + case 0x04: + out = src & ~(dst | pattern); + break; + case 0x05: + out = ~(dst | pattern); + break; + case 0x06: + out = ~(pattern | ~(dst ^ src)); + break; + case 0x07: + out = ~(pattern | (dst & src)); + break; + case 0x08: + out = src & (dst & ~pattern); + break; + case 0x09: + out = ~(pattern | (dst ^ src)); + break; + case 0x0a: + out = dst & ~pattern; + break; + case 0x0b: + out = ~(pattern | (src & ~dst)); + break; + case 0x0c: + out = src & ~pattern; + break; + case 0x0d: + out = ~(pattern | (dst & ~src)); + break; + case 0x0e: + out = ~(pattern | ~(dst | src)); + break; + case 0x0f: + out = ~pattern; + break; + case 0x10: + out = pattern & ~(dst | src); + break; + case 0x11: + out = ~(dst | src); + break; + case 0x12: + out = ~(src | ~(dst ^ pattern)); + break; + case 0x13: + out = ~(src | (dst & pattern)); + break; + case 0x14: + out = ~(dst | ~(pattern ^ src)); + break; + case 0x15: + out = ~(dst | (pattern & src)); + break; + case 0x16: + out = pattern ^ (src ^ (dst & ~(pattern & src))); + break; + case 0x17: + out = ~(src ^ ((src ^ pattern) & (dst ^ src))); + break; + case 0x18: + out = (src ^ pattern) & (pattern ^ dst); + break; + case 0x19: + out = ~(src ^ (dst & ~(pattern & src))); + break; + case 0x1a: + out = pattern ^ (dst | (src & pattern)); + break; + case 0x1b: + out = ~(src ^ (dst & (pattern ^ src))); + break; + case 0x1c: + out = pattern ^ (src | (dst & pattern)); + break; + case 0x1d: + out = ~(dst ^ (src & (pattern ^ dst))); + break; + case 0x1e: + out = pattern ^ (dst | src); + break; + case 0x1f: + out = ~(pattern & (dst | src)); + break; + case 0x20: + out = dst & (pattern & ~src); + break; + case 0x21: + out = ~(src | (dst ^ pattern)); + break; + case 0x22: + out = dst & ~src; + break; + case 0x23: + out = ~(src | (pattern & ~dst)); + break; + case 0x24: + out = (src ^ pattern) & (dst ^ src); + break; + case 0x25: + out = ~(pattern ^ (dst & ~(src & pattern))); + break; + case 0x26: + out = src ^ (dst | (pattern & src)); + break; + case 0x27: + out = src ^ (dst | ~(pattern ^ src)); + break; + case 0x28: + out = dst & (pattern ^ src); + break; + case 0x29: + out = ~(pattern ^ (src ^ (dst | (pattern & src)))); + break; + case 0x2a: + out = dst & ~(pattern & src); + break; + case 0x2b: + out = ~(src ^ ((src ^ pattern) & (pattern ^ dst))); + break; + case 0x2c: + out = src ^ (pattern & (dst | src)); + break; + case 0x2d: + out = pattern ^ (src | ~dst); + break; + case 0x2e: + out = pattern ^ (src | (dst ^ pattern)); + break; + case 0x2f: + out = ~(pattern & (src | ~dst)); + break; + case 0x30: + out = pattern & ~src; + break; + case 0x31: + out = ~(src | (dst & ~pattern)); + break; + case 0x32: + out = src ^ (dst | (pattern | src)); + break; + case 0x33: + out = ~src; + break; + case 0x34: + out = src ^ (pattern | (dst & src)); + break; + case 0x35: + out = src ^ (pattern | ~(dst ^ src)); + break; + case 0x36: + out = src ^ (dst | pattern); + break; + case 0x37: + out = ~(src & (dst | pattern)); + break; + case 0x38: + out = pattern ^ (src & (dst | pattern)); + break; + case 0x39: + out = src ^ (pattern | ~dst); + break; + case 0x3a: + out = src ^ (pattern | (dst ^ src)); + break; + case 0x3b: + out = ~(src & (pattern | ~dst)); + break; + case 0x3c: + out = pattern ^ src; + break; + case 0x3d: + out = src ^ (pattern | ~(dst | src)); + break; + case 0x3e: + out = src ^ (pattern | (dst & ~src)); + break; + case 0x3f: + out = ~(pattern & src); + break; + case 0x40: + out = pattern & (src & ~dst); + break; + case 0x41: + out = ~(dst | (pattern ^ src)); + break; + case 0x42: + out = (src ^ dst) & (pattern ^ dst); + break; + case 0x43: + out = ~(src ^ (pattern & ~(dst & src))); + break; + case 0x44: + out = src & ~dst; + break; + case 0x45: + out = ~(dst | (pattern & ~src)); + break; + case 0x46: + out = dst ^ (src | (pattern & dst)); + break; + case 0x47: + out = ~(pattern ^ (src & (dst ^ pattern))); + break; + case 0x48: + out = src & (dst ^ pattern); + break; + case 0x49: + out = ~(pattern ^ (dst ^ (src | (pattern & dst)))); + break; + case 0x4a: + out = dst ^ (pattern & (src | dst)); + break; + case 0x4b: + out = pattern ^ (dst | ~src); + break; + case 0x4c: + out = src & ~(dst & pattern); + break; + case 0x4d: + out = ~(src ^ ((src ^ pattern) | (dst ^ src))); + break; + case 0x4e: + out = pattern ^ (dst | (src ^ pattern)); + break; + case 0x4f: + out = ~(pattern & (dst | ~src)); + break; + case 0x50: + out = pattern & ~dst; + break; + case 0x51: + out = ~(dst | (src & ~pattern)); + break; + case 0x52: + out = dst ^ (pattern | (src & dst)); + break; + case 0x53: + out = ~(src ^ (pattern & (dst ^ src))); + break; + case 0x54: + out = ~(dst | ~(pattern | src)); + break; + case 0x55: + out = ~dst; + break; + case 0x56: + out = dst ^ (pattern | src); + break; + case 0x57: + out = ~(dst & (pattern | src)); + break; + case 0x58: + out = pattern ^ (dst & (src | pattern)); + break; + case 0x59: + out = dst ^ (pattern | ~src); + break; + case 0x5a: + out = dst ^ pattern; + break; + case 0x5b: + out = dst ^ (pattern | ~(src | dst)); + break; + case 0x5c: + out = dst ^ (pattern | (src ^ dst)); + break; + case 0x5d: + out = ~(dst & (pattern | ~src)); + break; + case 0x5e: + out = dst ^ (pattern | (src & ~dst)); + break; + case 0x5f: + out = ~(dst & pattern); + break; + case 0x60: + out = pattern & (dst ^ src); + break; + case 0x61: + out = ~(dst ^ (src ^ (pattern | (dst & src)))); + break; + case 0x62: + out = dst ^ (src & (pattern | dst)); + break; + case 0x63: + out = src ^ (dst | ~pattern); + break; + case 0x64: + out = src ^ (dst & (pattern | src)); + break; + case 0x65: + out = dst ^ (src | ~pattern); + break; + case 0x66: + out = dst ^ src; + break; + case 0x67: + out = src ^ (dst | ~(pattern | src)); + break; + case 0x68: + out = ~(dst ^ (src ^ (pattern | ~(dst | src)))); + break; + case 0x69: + out = ~(pattern ^ (dst ^ src)); + break; + case 0x6a: + out = dst ^ (pattern & src); + break; + case 0x6b: + out = ~(pattern ^ (src ^ (dst & (pattern | src)))); + break; + case 0x6c: + out = src ^ (dst & pattern); + break; + case 0x6d: + out = ~(pattern ^ (dst ^ (src & (pattern | dst)))); + break; + case 0x6e: + out = src ^ (dst & (pattern | ~src)); + break; + case 0x6f: + out = ~(pattern & ~(dst ^ src)); + break; + case 0x70: + out = pattern & ~(dst & src); + break; + case 0x71: + out = ~(src ^ ((src ^ dst) & (pattern ^ dst))); + break; + case 0x72: + out = src ^ (dst | (pattern ^ src)); + break; + case 0x73: + out = ~(src & (dst | ~pattern)); + break; + case 0x74: + out = dst ^ (src | (pattern ^ dst)); + break; + case 0x75: + out = ~(dst & (src | ~pattern)); + break; + case 0x76: + out = src ^ (dst | (pattern & ~src)); + break; + case 0x77: + out = ~(dst & src); + break; + case 0x78: + out = pattern ^ (dst & src); + break; + case 0x79: + out = ~(dst ^ (src ^ (pattern & (dst | src)))); + break; + case 0x7a: + out = dst ^ (pattern & (src | ~dst)); + break; + case 0x7b: + out = ~(src & ~(dst ^ pattern)); + break; + case 0x7c: + out = src ^ (pattern & (dst | ~src)); + break; + case 0x7d: + out = ~(dst & ~(pattern ^ src)); + break; + case 0x7e: + out = (src ^ pattern) | (dst ^ src); + break; + case 0x7f: + out = ~(dst & (pattern & src)); + break; + case 0x80: + out = dst & (pattern & src); + break; + case 0x81: + out = ~((src ^ pattern) | (dst ^ src)); + break; + case 0x82: + out = dst & ~(pattern ^ src); + break; + case 0x83: + out = ~(src ^ (pattern & (dst | ~src))); + break; + case 0x84: + out = src & ~(dst ^ pattern); + break; + case 0x85: + out = ~(pattern ^ (dst & (src | ~pattern))); + break; + case 0x86: + out = dst ^ (src ^ (pattern & (dst | src))); + break; + case 0x87: + out = ~(pattern ^ (dst & src)); + break; + case 0x88: + out = dst & src; + break; + case 0x89: + out = ~(src ^ (dst | (pattern & ~src))); + break; + case 0x8a: + out = dst & (src | ~pattern); + break; + case 0x8b: + out = ~(dst ^ (src | (pattern ^ dst))); + break; + case 0x8c: + out = src & (dst | ~pattern); + break; + case 0x8d: + out = ~(src ^ (dst | (pattern ^ src))); + break; + case 0x8e: + out = src ^ ((src ^ dst) & (pattern ^ dst)); + break; + case 0x8f: + out = ~(pattern & ~(dst & src)); + break; + case 0x90: + out = pattern & ~(dst ^ src); + break; + case 0x91: + out = ~(src ^ (dst & (pattern | ~src))); + break; + case 0x92: + out = dst ^ (pattern ^ (src & (dst | pattern))); + break; + case 0x93: + out = ~(src ^ (pattern & dst)); + break; + case 0x94: + out = pattern ^ (src ^ (dst & (pattern | src))); + break; + case 0x95: + out = ~(dst ^ (pattern & src)); + break; + case 0x96: + out = dst ^ (pattern ^ src); + break; + case 0x97: + out = pattern ^ (src ^ (dst | ~(pattern | src))); + break; + case 0x98: + out = ~(src ^ (dst | ~(pattern | src))); + break; + case 0x99: + out = ~(dst ^ src); + break; + case 0x9a: + out = dst ^ (pattern & ~src); + break; + case 0x9b: + out = ~(src ^ (dst & (pattern | src))); + break; + case 0x9c: + out = src ^ (pattern & ~dst); + break; + case 0x9d: + out = ~(dst ^ (src & (pattern | dst))); + break; + case 0x9e: + out = dst ^ (src ^ (pattern | (dst & src))); + break; + case 0x9f: + out = ~(pattern & (dst ^ src)); + break; + case 0xa0: + out = dst & pattern; + break; + case 0xa1: + out = ~(pattern ^ (dst | (src & ~pattern))); + break; + case 0xa2: + out = dst & (pattern | ~src); + break; + case 0xa3: + out = ~(dst ^ (pattern | (src ^ dst))); + break; + case 0xa4: + out = ~(pattern ^ (dst | ~(src | pattern))); + break; + case 0xa5: + out = ~(pattern ^ dst); + break; + case 0xa6: + out = dst ^ (src & ~pattern); + break; + case 0xa7: + out = ~(pattern ^ (dst & (src | pattern))); + break; + case 0xa8: + out = dst & (pattern | src); + break; + case 0xa9: + out = ~(dst ^ (pattern | src)); + break; + case 0xaa: + out = dst; + break; + case 0xab: + out = dst | ~(pattern | src); + break; + case 0xac: + out = src ^ (pattern & (dst ^ src)); + break; + case 0xad: + out = ~(dst ^ (pattern | (src & dst))); + break; + case 0xae: + out = dst | (src & ~pattern); + break; + case 0xaf: + out = dst | ~pattern; + break; + case 0xb0: + out = pattern & (dst | ~src); + break; + case 0xb1: + out = ~(pattern ^ (dst | (src ^ pattern))); + break; + case 0xb2: + out = src ^ ((src ^ pattern) | (dst ^ src)); + break; + case 0xb3: + out = ~(src & ~(dst & pattern)); + break; + case 0xb4: + out = pattern ^ (src & ~dst); + break; + case 0xb5: + out = ~(dst ^ (pattern & (src | dst))); + break; + case 0xb6: + out = dst ^ (pattern ^ (src | (dst & pattern))); + break; + case 0xb7: + out = ~(src & (dst ^ pattern)); + break; + case 0xb8: + out = pattern ^ (src & (dst ^ pattern)); + break; + case 0xb9: + out = ~(dst ^ (src | (pattern & dst))); + break; + case 0xba: + out = dst | (pattern & ~src); + break; + case 0xbb: + out = dst | ~src; + break; + case 0xbc: + out = src ^ (pattern & ~(dst & src)); + break; + case 0xbd: + out = ~((src ^ dst) & (pattern ^ dst)); + break; + case 0xbe: + out = dst | (pattern ^ src); + break; + case 0xbf: + out = dst | ~(pattern & src); + break; + case 0xc0: + out = pattern & src; + break; + case 0xc1: + out = ~(src ^ (pattern | (dst & ~src))); + break; + case 0xc2: + out = ~(src ^ (pattern | ~(dst | src))); + break; + case 0xc3: + out = ~(pattern ^ src); + break; + case 0xc4: + out = src & (pattern | ~dst); + break; + case 0xc5: + out = ~(src ^ (pattern | (dst ^ src))); + break; + case 0xc6: + out = src ^ (dst & ~pattern); + break; + case 0xc7: + out = ~(pattern ^ (src & (dst | pattern))); + break; + case 0xc8: + out = src & (dst | pattern); + break; + case 0xc9: + out = ~(src ^ (pattern | dst)); + break; + case 0xca: + out = dst ^ (pattern & (src ^ dst)); + break; + case 0xcb: + out = ~(src ^ (pattern | (dst & src))); + break; + case 0xcc: + out = src; + break; + case 0xcd: + out = src | ~(dst | pattern); + break; + case 0xce: + out = src | (dst & ~pattern); + break; + case 0xcf: + out = src | ~pattern; + break; + case 0xd0: + out = pattern & (src | ~dst); + break; + case 0xd1: + out = ~(pattern ^ (src | (dst ^ pattern))); + break; + case 0xd2: + out = pattern ^ (dst & ~src); + break; + case 0xd3: + out = ~(src ^ (pattern & (dst | src))); + break; + case 0xd4: + out = src ^ ((src ^ pattern) & (pattern ^ dst)); + break; + case 0xd5: + out = ~(dst & ~(pattern & src)); + break; + case 0xd6: + out = pattern ^ (src ^ (dst | (pattern & src))); + break; + case 0xd7: + out = ~(dst & (pattern ^ src)); + break; + case 0xd8: + out = pattern ^ (dst & (src ^ pattern)); + break; + case 0xd9: + out = ~(src ^ (dst | (pattern & src))); + break; + case 0xda: + out = dst ^ (pattern & ~(src & dst)); + break; + case 0xdb: + out = ~((src ^ pattern) & (dst ^ src)); + break; + case 0xdc: + out = src | (pattern & ~dst); + break; + case 0xdd: + out = src | ~dst; + break; + case 0xde: + out = src | (dst ^ pattern); + break; + case 0xdf: + out = src | ~(dst & pattern); + break; + case 0xe0: + out = pattern & (dst | src); + break; + case 0xe1: + out = ~(pattern ^ (dst | src)); + break; + case 0xe2: + out = dst ^ (src & (pattern ^ dst)); + break; + case 0xe3: + out = ~(pattern ^ (src | (dst & pattern))); + break; + case 0xe4: + out = src ^ (dst & (pattern ^ src)); + break; + case 0xe5: + out = ~(pattern ^ (dst | (src & pattern))); + break; + case 0xe6: + out = src ^ (dst & ~(pattern & src)); + break; + case 0xe7: + out = ~((src ^ pattern) & (pattern ^ dst)); + break; + case 0xe8: + out = src ^ ((src ^ pattern) & (dst ^ src)); + break; + case 0xe9: + out = ~(dst ^ (src ^ (pattern & ~(dst & src)))); + break; + case 0xea: + out = dst | (pattern & src); + break; + case 0xeb: + out = dst | ~(pattern ^ src); + break; + case 0xec: + out = src | (dst & pattern); + break; + case 0xed: + out = src | ~(dst ^ pattern); + break; + case 0xee: + out = dst | src; + break; + case 0xef: + out = src | (dst | ~pattern); + break; + case 0xf0: + out = pattern; + break; + case 0xf1: + out = pattern | ~(dst | src); + break; + case 0xf2: + out = pattern | (dst & ~src); + break; + case 0xf3: + out = pattern | ~src; + break; + case 0xf4: + out = pattern | (src & ~dst); + break; + case 0xf5: + out = pattern | ~dst; + break; + case 0xf6: + out = pattern | (dst ^ src); + break; + case 0xf7: + out = pattern | ~(dst & src); + break; + case 0xf8: + out = pattern | (dst & src); + break; + case 0xf9: + out = pattern | ~(dst ^ src); + break; + case 0xfa: + out = dst | pattern; + break; + case 0xfb: + out = dst | (pattern | ~src); + break; + case 0xfc: + out = pattern | src; + break; + case 0xfd: + out = pattern | (src | ~dst); + break; + case 0xfe: + out = dst | (pattern | src); + break; + case 0xff: + out = ~0; + break; + } + + return out; +} \ No newline at end of file diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 98a9cb385..f1d755dba 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -11,7 +11,7 @@ # Authors: David HrdliÄka, # # Copyright 2020-2021 David HrdliÄka. -# Copyright 2025 starfrost +# Copyright 2025 Connor Hyde / starfrost # add_library(vid OBJECT @@ -136,12 +136,77 @@ add_library(vid OBJECT # Matrox vid_mga.c - # NVidia (pending) + # NVidia - Core + nv/nv_base.c nv/nv_rivatimer.c + # NVidia NV1 + nv/nv1/nv1_core.c + nv/nv1/nv1_core_config.c + + # NVidia RIVA 128 - Subsystems + nv/nv3/nv3_core.c + nv/nv3/nv3_core_config.c + nv/nv3/nv3_core_arbiter.c + + nv/nv3/subsystems/nv3_pramdac.c + nv/nv3/subsystems/nv3_pfifo.c + nv/nv3/subsystems/nv3_pgraph.c + 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 + nv/nv3/subsystems/nv3_user.c + + # NVidia RIVA 128 - Object Classes + nv/nv3/classes/nv3_class_names.c + nv/nv3/classes/nv3_class_shared_methods.c + nv/nv3/classes/nv3_class_001_beta_factor.c + nv/nv3/classes/nv3_class_002_rop.c + nv/nv3/classes/nv3_class_003_chroma_key.c + nv/nv3/classes/nv3_class_004_plane_mask.c + nv/nv3/classes/nv3_class_005_clipping_rectangle.c + nv/nv3/classes/nv3_class_006_pattern.c + nv/nv3/classes/nv3_class_007_rectangle.c + nv/nv3/classes/nv3_class_008_point.c + nv/nv3/classes/nv3_class_009_line.c + nv/nv3/classes/nv3_class_00a_lin.c + nv/nv3/classes/nv3_class_00b_triangle.c + nv/nv3/classes/nv3_class_00c_win95_gdi_text.c + nv/nv3/classes/nv3_class_00d_m2mf.c + nv/nv3/classes/nv3_class_00e_scaled_image_from_mem.c + nv/nv3/classes/nv3_class_010_blit.c + nv/nv3/classes/nv3_class_011_image.c + nv/nv3/classes/nv3_class_012_bitmap.c + nv/nv3/classes/nv3_class_014_transfer2memory.c + nv/nv3/classes/nv3_class_015_stretched_image_from_cpu.c + nv/nv3/classes/nv3_class_017_d3d5_tri_zeta_buffer.c + nv/nv3/classes/nv3_class_018_point_zeta_buffer.c + nv/nv3/classes/nv3_class_01c_image_in_memory.c + + # NVidia RIVA 128 - Render + nv/nv3/render/nv3_render_core.c + nv/nv3/render/nv3_render_primitives.c + nv/nv3/render/nv3_render_blit.c + + # NVidia RIVA TNT/TNT2 - Core + nv/nv4/nv4_core.c + nv/nv4/nv4_core_io.c + nv/nv4/nv4_core_config.c + nv/nv4/nv4_debug_register_list.c + nv/nv4/subsystems/nv4_pramdac.c + nv/nv4/subsystems/nv4_ptimer.c + # Generic vid_bochs_vbe.c - ) if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") diff --git a/src/video/nv/nv1/nv1_core.c b/src/video/nv/nv1/nv1_core.c new file mode 100644 index 000000000..3de528b26 --- /dev/null +++ b/src/video/nv/nv1/nv1_core.c @@ -0,0 +1,110 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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_nv1.h> + + +void nv1_init() +{ + +} + +void* nv1_init_edge2k(const device_t *info) +{ + +} + +void* nv1_init_edge3k(const device_t *info) +{ + +} + +void nv1_close(void* priv) +{ + +} + +void nv1_speed_changed(void *priv) +{ + +} + +void nv1_draw_cursor(svga_t* svga, int32_t drawline) +{ + +} + +void nv1_recalc_timings(svga_t* svga) +{ + +} + +void nv1_force_redraw(void* priv) +{ + +} + +// See if the bios rom is available. +int32_t nv1_available(void) +{ + return (rom_present(NV1_VBIOS_E3D_2X00) + || rom_present(NV1_VBIOS_E3D_3X00)); +} + +// NV3 (RIVA 128) +// PCI +// 2MB or 4MB VRAM +const device_t nv1_device_edge2k = +{ + .name = "nVIDIA NV1 [Diamond Edge 3D 2x00] [Not Direct3D Compatible]", + .internal_name = "nv1_edge2k", + .flags = DEVICE_PCI, + .local = 0, + .init = nv1_init_edge2k, + .close = nv1_close, + .speed_changed = nv1_speed_changed, + .force_redraw = nv1_force_redraw, + .available = nv1_available, + .config = nv1_config, +}; + +// NV3 (RIVA 128) +// AGP +// 2MB or 4MB VRAM +const device_t nv1_device_edge3k = +{ + .name = "nVIDIA NV1 [Diamond Edge 3D 3x00] [Not Direct3D Compatible]", + .internal_name = "nv1_edge3k", + .flags = DEVICE_PCI, + .local = 0, + .init = nv1_init_edge3k, + .close = nv1_close, + .speed_changed = nv1_speed_changed, + .force_redraw = nv1_force_redraw, + .available = nv1_available, + .config = nv1_config, +}; diff --git a/src/video/nv/nv1/nv1_core_config.c b/src/video/nv/nv1/nv1_core_config.c new file mode 100644 index 000000000..460067f6f --- /dev/null +++ b/src/video/nv/nv1/nv1_core_config.c @@ -0,0 +1,133 @@ +/* + * 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. + * + * Provides NV4 configuration + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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_nv1.h> + +const device_config_t nv1_config[] = +{ + // Memory configuration + { + .name = "vram_size", + .description = "VRAM Size", + .type = CONFIG_SELECTION, + .default_int = NV1_VRAM_SIZE_4MB, + .selection = + { + // I thought this was never released, but it seems that at least one was released: + // The card was called the "NEC G7AGK" + { + .description = "1 MB", + .value = NV1_VRAM_SIZE_1MB, + }, + { + .description = "2 MB", + .value = NV1_VRAM_SIZE_2MB, + }, + { + .description = "4 MB", + .value = NV1_VRAM_SIZE_4MB, + }, + } + + }, + // Multithreading configuration + { + + .name = "pgraph_threads", +#ifndef RELEASE_BUILD + .description = "PFIFO/PGRAPH - Number of threads to split large object method execution into", +#else + .description = "Render threads", +#endif + .type = CONFIG_SELECTION, + .default_int = 1, // todo: change later + .selection = + { + { + .description = "1 thread (Only use if issues appear with more threads)", + .value = 1, + }, + { + .description = "2 threads", + .value = 2, + }, + { + .description = "4 threads", + .value = 4, + }, + { + .description = "8 threads", + .value = 8, + }, + }, + }, + { + .name = "RAMDAC Type", + .description = "SGS-Thomson RAMDAC type", + .default_int = 0x1764, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "SGS-Thomson STG-1732X", + .value = 0x1732, + }, + { + .description = "SGS-Thomson STG-1764X/NVDAC64", + .value = 0x1764, + }, + } + }, + { + .name = "Chip type", + .description = "Chip type", + .default_int = 0x1, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "SGS-Thomson STG-2000", + .value = 0x2000, + }, + { + .description = "Nvidia NV1", + .value = 0x1, + }, + } + }, +#ifndef RELEASE_BUILD + { + .name = "nv_debug_fulllog", + .description = "Disable Cyclical Lines Detection for nv_log (Use for getting full context at cost of VERY large log files)", + .type = CONFIG_BINARY, + .default_int = 0, + }, +#endif + { + .type = CONFIG_END + } +}; \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_001_beta_factor.c b/src/video/nv/nv3/classes/nv3_class_001_beta_factor.c new file mode 100644 index 000000000..4520a941f --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_001_beta_factor.c @@ -0,0 +1,50 @@ +/* + * 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: Methods for class 0x01 (Beta factor) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_001_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + /* even if we don't do anything with this yet... */ + case NV3_BETA_FACTOR: + if (param & 0x80000000) /* bit0 */ + nv3->pgraph.beta_factor = 0; + else + nv3->pgraph.beta_factor = param & 0x7F800000; + + nv_log("Method Execution: Beta Factor = %02x", nv3->pgraph.beta_factor); + + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_002_rop.c b/src/video/nv/nv3/classes/nv3_class_002_rop.c new file mode 100644 index 000000000..56b135888 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_002_rop.c @@ -0,0 +1,44 @@ +/* + * 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: Methods for class 0x02 (Render operation) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_002_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_ROP_SET_ROP: + nv3->pgraph.rop = param & 0xFF; + nv_log("Method Execution: ROP = %02x\n", nv3->pgraph.rop); + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_003_chroma_key.c b/src/video/nv/nv3/classes/nv3_class_003_chroma_key.c new file mode 100644 index 000000000..f19a06932 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_003_chroma_key.c @@ -0,0 +1,54 @@ +/* + * 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: Methods for class 0x02 (Chroma/color key) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_003_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_CHROMA_UNKNOWN_0200: + nv_log("Method Execution: Chroma Unknown 0x0200 0x%08x", param); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + + break; + case NV3_CHROMA_KEY: + { + nv3_color_expanded_t expanded_color = nv3_render_expand_color(param, grobj); + + nv3->pgraph.chroma_key = nv3_render_to_chroma(expanded_color); + + nv_log("Method Execution: Chroma = 0x%08x", nv3->pgraph.chroma_key); + break; + } + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_004_plane_mask.c b/src/video/nv/nv3/classes/nv3_class_004_plane_mask.c new file mode 100644 index 000000000..d93de9bc1 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_004_plane_mask.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x02 (Plane mask) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_004_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_005_clipping_rectangle.c b/src/video/nv/nv3/classes/nv3_class_005_clipping_rectangle.c new file mode 100644 index 000000000..c7ec3ae98 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_005_clipping_rectangle.c @@ -0,0 +1,49 @@ +/* + * 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: Methods for class 0x05 (Clipping rectangle) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_005_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_CLIP_POSITION: + nv3->pgraph.clip_start.x = (param >> 16) & 0xFFFF; + nv3->pgraph.clip_start.y = (param) & 0xFFFF; + nv_log("Method Execution: Clip Position: %d,%d\n", nv3->pgraph.clip_start.x, nv3->pgraph.clip_start.y); + break; + case NV3_CLIP_SIZE: + nv3->pgraph.clip_size.x = (param >> 16) & 0xFFFF; + nv3->pgraph.clip_size.y = (param) & 0xFFFF; + nv_log("Method Execution: Clip Size: %d,%d\n", nv3->pgraph.clip_start.x, nv3->pgraph.clip_start.y); + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_006_pattern.c b/src/video/nv/nv3/classes/nv3_class_006_pattern.c new file mode 100644 index 000000000..5aa5bf0fc --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_006_pattern.c @@ -0,0 +1,86 @@ +/* + * 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: Methods for class 0x06 (Pattern) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_006_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + /* Valid software method, suppress logging */ + case NV3_PATTERN_FORMAT: + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + case NV3_PATTERN_SHAPE: + /* If the shape is not valid, tell the software that it's invalid */ + + /* + Technically you are meant to do this: + + But in practice, I don't know, because it always submits 0x20 or 0x40, which are valid when param & 0x03, + and appear to be deliberate behaviour in the drivers rather than bugs. What + if (param > NV3_PATTERN_SHAPE_LAST_VALID) + { + warning("NV3 class 0x06 (Pattern) invalid shape %d (This is a bug)", param); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_INVALID_DATA); + return; + } + + */ + nv3->pgraph.pattern_shape = param & 0x03; + + break; + /* Seems to be "SetPatternSelect" on Riva TNT and later, but possibly called by accident on Riva 128. There is no hardware equivalent for this. So let's just suppress + the warnings. */ + case NV3_PATTERN_UNUSED_DRIVER_BUG: + break; + case NV3_PATTERN_COLOR0: + { + nv3_color_expanded_t expanded_colour0 = nv3_render_expand_color(param, grobj); + nv3_render_set_pattern_color(expanded_colour0, false); + break; + } + case NV3_PATTERN_COLOR1: + { + nv3_color_expanded_t expanded_colour1 = nv3_render_expand_color(param, grobj); + nv3_render_set_pattern_color(expanded_colour1, true); + break; + } + case NV3_PATTERN_BITMAP_HIGH: + nv3->pgraph.pattern_bitmap = 0; //reset + nv3->pgraph.pattern_bitmap |= ((uint64_t)param << 32); + break; + case NV3_PATTERN_BITMAP_LOW: + nv3->pgraph.pattern_bitmap |= param; + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_007_rectangle.c b/src/video/nv/nv3/classes/nv3_class_007_rectangle.c new file mode 100644 index 000000000..d1273a84a --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_007_rectangle.c @@ -0,0 +1,69 @@ +/* + * 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: Methods for class 0x07 (Rectangle) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_007_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_RECTANGLE_COLOR: + nv3->pgraph.rectangle.color = param; + break; + default: + /* Check for any rectangle point or size method. */ + if (method_id >= NV3_RECTANGLE_START && method_id <= NV3_RECTANGLE_END) + { + uint32_t index = (method_id - NV3_RECTANGLE_START) >> 3; + + // If the size is submitted, render it. + if (method_id & 0x04) + { + nv3->pgraph.rectangle.size[index].x = param & 0xFFFF; + nv3->pgraph.rectangle.size[index].y = (param >> 16) & 0xFFFF; + + nv_log("Method Execution: Rect%d Size=%d,%d Color=0x%08x\n", index, nv3->pgraph.rectangle.size[index].x, nv3->pgraph.rectangle.size[index].y, nv3->pgraph.rectangle.color); + + nv3_render_rect(nv3->pgraph.rectangle.position[index], nv3->pgraph.rectangle.size[index], nv3->pgraph.rectangle.color, grobj); + } + else // position + { + nv3->pgraph.rectangle.position[index].x = param & 0xFFFF; + nv3->pgraph.rectangle.position[index].y = (param >> 16) & 0xFFFF; + + nv_log("Method Execution: Rect%d Position=%d,%d\n", index, nv3->pgraph.rectangle.position[index].x, nv3->pgraph.rectangle.position[index].y); + } + + return; + } + + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_008_point.c b/src/video/nv/nv3/classes/nv3_class_008_point.c new file mode 100644 index 000000000..41002f745 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_008_point.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x08 (Point) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_008_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_009_line.c b/src/video/nv/nv3/classes/nv3_class_009_line.c new file mode 100644 index 000000000..f149bb8b3 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_009_line.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x09 (Line) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_009_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_00a_lin.c b/src/video/nv/nv3/classes/nv3_class_00a_lin.c new file mode 100644 index 000000000..473aaa214 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_00a_lin.c @@ -0,0 +1,41 @@ +/* + * 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: Methods for class 0x0A (Lin - a line without starting or ending pixels) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_00a_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_00b_triangle.c b/src/video/nv/nv3/classes/nv3_class_00b_triangle.c new file mode 100644 index 000000000..d08b7a72e --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_00b_triangle.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x0B (Basic triangle) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_00b_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c b/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c new file mode 100644 index 000000000..64d76c278 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c @@ -0,0 +1,285 @@ +/* + * 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: Methods for class 0x0C (Windows 95 GDI text acceleration) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + /* Type A: Unclipped Rectangle */ + + /* NOTE: This method is used by the GDI driver as part of the notification engine. */ + case NV3_W95TXT_A_COLOR: + nv3->pgraph.win95_gdi_text.color_a = param; + nv_log("Method Execution: GDI-A Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); + break; + /* Type B: Clipped Rectangle */ + case NV3_W95TXT_B_COLOR: + nv3->pgraph.win95_gdi_text.color_b = param; + nv_log("Method Execution: GDI-B Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_b); + break; + case NV3_W95TXT_B_CLIP_TOPLEFT: + nv3->pgraph.win95_gdi_text.clip_b.left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_b.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-B Clip Left,Top %04x,%04x", nv3->pgraph.win95_gdi_text.clip_b.left, nv3->pgraph.win95_gdi_text.clip_b.top); + break; + case NV3_W95TXT_B_CLIP_BOTTOMRIGHT: + nv3->pgraph.win95_gdi_text.clip_b.bottom = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_b.right = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-B Clip Bottom,Right %04x,%04x", nv3->pgraph.win95_gdi_text.clip_b.right, nv3->pgraph.win95_gdi_text.clip_b.bottom); + break; + /* Type C: Unclipped Bitmap */ + case NV3_W95TXT_C_CLIP_COLOR: + nv3->pgraph.win95_gdi_text.color1_c = param; + nv_log("Method Execution: GDI-C Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color1_c); + break; + case NV3_W95TXT_C_CLIP_SIZE: + nv3->pgraph.win95_gdi_text.size_c.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_c.y = ((param >> 16) & 0xFFFF); + + nv3->pgraph.win95_gdi_text_bit_count = 0; + nv_log("Method Execution: GDI-C Size In %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_c.x, nv3->pgraph.win95_gdi_text.size_c.y); + break; + case NV3_W95TXT_C_CLIP_POSITION: + nv3->pgraph.win95_gdi_text.point_c.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.point_c.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-C Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_c.x, nv3->pgraph.win95_gdi_text.point_c.y); + + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_c.x ; + nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_c.y; + + break; + case NV3_W95TXT_C_CLIP_TOPLEFT: + nv3->pgraph.win95_gdi_text.clip_c.left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_c.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-C Clip Left,Top %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.top); + break; + case NV3_W95TXT_C_CLIP_BOTTOMRIGHT: + nv3->pgraph.win95_gdi_text.clip_c.right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_c.bottom = ((param >> 16) & 0xFFFF); + /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ + nv_log("Method Execution: GDI-C Clip Right,Bottom %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.top); + break; + /* Type B and C not implemented YET, as they are not used by NT GDI driver */ + case NV3_W95TXT_D_CLIP_TOPLEFT: + nv3->pgraph.win95_gdi_text.clip_d.left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_d.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-D Clip Left,Top %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); + break; + case NV3_W95TXT_D_CLIP_BOTTOMRIGHT: + nv3->pgraph.win95_gdi_text.clip_d.right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_d.bottom = ((param >> 16) & 0xFFFF); + /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ + nv_log("Method Execution: GDI-D Clip Right,Bottom %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); + break; + + case NV3_W95TXT_D_CLIP_COLOR: + nv3->pgraph.win95_gdi_text.color1_d = param; + nv_log("Method Execution: GDI-D Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); + break; + case NV3_W95TXT_D_CLIP_SIZE_IN: + nv3->pgraph.win95_gdi_text.size_in_d.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_in_d.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-D Size In %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_in_d.x, nv3->pgraph.win95_gdi_text.size_in_d.y); + break; + case NV3_W95TXT_D_CLIP_SIZE_OUT: + nv3->pgraph.win95_gdi_text.size_out_d.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_out_d.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-D Size Out %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_out_d.x, nv3->pgraph.win95_gdi_text.size_out_d.y); + break; + case NV3_W95TXT_D_CLIP_POSITION: + nv3->pgraph.win95_gdi_text.point_d.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.point_d.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-D Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_d.x, nv3->pgraph.win95_gdi_text.point_d.y); + + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_d.x; + nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_d.y; + nv3->pgraph.win95_gdi_text_bit_count = 0; + + break; + /* Type E: Two-colour 1bpp */ + case NV3_W95TXT_E_CLIP_TOPLEFT: + nv3->pgraph.win95_gdi_text.clip_e.left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_e.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Clip Left,Top 0x%08x\n", nv3->pgraph.win95_gdi_text.clip_e.left, nv3->pgraph.win95_gdi_text.clip_e.top); + break; + case NV3_W95TXT_E_CLIP_BOTTOMRIGHT: + nv3->pgraph.win95_gdi_text.clip_e.right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_e.bottom = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Clip Bottom,Right 0x%08x\n", nv3->pgraph.win95_gdi_text.clip_e.right, nv3->pgraph.win95_gdi_text.clip_e.bottom); + /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ + break; + case NV3_W95TXT_E_CLIP_COLOR_0: + nv3->pgraph.win95_gdi_text.color0_e = param; + nv_log("Method Execution: GDI-E Color0 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); + break; + case NV3_W95TXT_E_CLIP_COLOR_1: + nv3->pgraph.win95_gdi_text.color1_e = param; + nv_log("Method Execution: GDI-E Color1 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); + break; + case NV3_W95TXT_E_CLIP_SIZE_IN: + nv3->pgraph.win95_gdi_text.size_in_e.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_in_e.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Size In %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_in_e.x, nv3->pgraph.win95_gdi_text.size_in_e.y); + break; + case NV3_W95TXT_E_CLIP_SIZE_OUT: + nv3->pgraph.win95_gdi_text.size_out_e.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_out_e.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Size Out %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_out_e.x, nv3->pgraph.win95_gdi_text.size_out_e.y); + break; + case NV3_W95TXT_E_CLIP_POSITION: + nv3->pgraph.win95_gdi_text.point_e.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.point_e.y = ((param >> 16) & 0xFFFF); + + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_e.x; + nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_e.y; + nv3->pgraph.win95_gdi_text_bit_count = 0; + + nv_log("Method Execution: GDI-E Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_e.x, nv3->pgraph.win95_gdi_text.point_e.y); + break; + default: + /* Type A submission: these are the same things as rectangles */ + if (method_id >= NV3_W95TXT_A_RECT_START && method_id <= NV3_W95TXT_A_RECT_END) + { + uint32_t index = (method_id - NV3_W95TXT_A_RECT_START) >> 3; + + // IN THIS ONE SPECIFIC PLACE, ****AND ONLY THIS ONE SPECIFIC PLACE****, X AND Y ARE SWAPPED???? */ + // If the size is submitted, render it. + if (method_id & 0x04) + { + nv3->pgraph.win95_gdi_text.rect_a_size[index].x = (param >> 16) & 0xFFFF; + nv3->pgraph.win95_gdi_text.rect_a_size[index].y = param & 0xFFFF; + + nv_log("Method Execution: Rect GDI-A%d Size=%d,%d", index, nv3->pgraph.win95_gdi_text.rect_a_size[index].x, + nv3->pgraph.win95_gdi_text.rect_a_size[index].y); + + nv3_render_rect(nv3->pgraph.win95_gdi_text.rect_a_position[index], + nv3->pgraph.win95_gdi_text.rect_a_size[index], nv3->pgraph.win95_gdi_text.color_a, grobj); + } + else // position + { + nv3->pgraph.win95_gdi_text.rect_a_position[index].x = (param >> 16) & 0xFFFF; + nv3->pgraph.win95_gdi_text.rect_a_position[index].y = param & 0xFFFF; + + nv_log("Method Execution: Rect GDI-A%d Position=%d,%d\n", index, + nv3->pgraph.win95_gdi_text.rect_a_position[index].x, nv3->pgraph.win95_gdi_text.rect_a_position[index].y); + } + + return; + } + /* Type B: Clipped Rectangle */ + else if (method_id >= NV3_W95TXT_B_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_B_CLIP_CLIPRECT_END) + { + uint32_t index = (method_id - NV3_W95TXT_B_CLIP_CLIPRECT_START) >> 3; + + /* Works slightly differently, we define the bounds of the rectangle instead. */ + if (method_id & 0x04) + { + nv3->pgraph.win95_gdi_text.clipped_rect[index].right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clipped_rect[index].bottom = ((param >> 16) & 0xFFFF); + + nv_log("Method Execution: Rect GDI-B%d Right,Bottom=%d,%d\n", index, nv3->pgraph.win95_gdi_text.clipped_rect[index].right, + nv3->pgraph.win95_gdi_text.clipped_rect[index].bottom); + + nv3_render_rect_clipped(nv3->pgraph.win95_gdi_text.clipped_rect[index], + nv3->pgraph.win95_gdi_text.color_b, grobj); + } + else // left,top + { + nv3->pgraph.win95_gdi_text.clipped_rect[index].left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clipped_rect[index].top = ((param >> 16) & 0xFFFF); + + nv_log("Method Execution: Rect GDI-B%d Left,Top=%d,%d\n", index, + nv3->pgraph.win95_gdi_text.clipped_rect[index].left, nv3->pgraph.win95_gdi_text.clipped_rect[index].top); + } + + return; + } + /* Type C */ + else if (method_id >= NV3_W95TXT_C_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_C_CLIP_CLIPRECT_END) + { + /* lol */ + uint32_t index = (method_id - NV3_W95TXT_C_CLIP_CLIPRECT_START) >> 3; + + nv3->pgraph.win95_gdi_text.bitmap_c[index] = param; + + /* Mammoth logger! */ + nv_log("Method Execution: Rect GDI-C%d Data=%08x Size%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", + index, param, nv3->pgraph.win95_gdi_text.size_c.x, nv3->pgraph.win95_gdi_text.size_c.y, + nv3->pgraph.win95_gdi_text.point_c.x, nv3->pgraph.win95_gdi_text.point_c.y, + nv3->pgraph.win95_gdi_text.color1_c, + nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.right, + nv3->pgraph.win95_gdi_text.clip_c.top, nv3->pgraph.win95_gdi_text.clip_c.bottom); + + nv3_render_gdi_transparent_bitmap(false, nv3->pgraph.win95_gdi_text.color1_c, nv3->pgraph.win95_gdi_text.bitmap_c[index], grobj); + return; + } + else if (method_id >= NV3_W95TXT_D_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_D_CLIP_CLIPRECT_END) + { + /* lol */ + uint32_t index = (method_id - NV3_W95TXT_D_CLIP_CLIPRECT_START) >> 3; + + nv3->pgraph.win95_gdi_text.bitmap_d[index] = param; + + /* Mammoth logger! */ + nv_log("Method Execution: Rect GDI-D%d Data=%08x SizeIn%04x,%04x SizeOut%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", + index, param, nv3->pgraph.win95_gdi_text.size_in_d.x, nv3->pgraph.win95_gdi_text.size_in_d.y, + nv3->pgraph.win95_gdi_text.size_out_d.x, nv3->pgraph.win95_gdi_text.size_out_d.y, + nv3->pgraph.win95_gdi_text.point_d.x, nv3->pgraph.win95_gdi_text.point_d.y, + nv3->pgraph.win95_gdi_text.color1_d, + nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.right, + nv3->pgraph.win95_gdi_text.clip_d.top, nv3->pgraph.win95_gdi_text.clip_d.bottom); + + nv3_render_gdi_transparent_bitmap(true, nv3->pgraph.win95_gdi_text.color1_d, nv3->pgraph.win95_gdi_text.bitmap_d[index], grobj); + return; + } + else if (method_id >= NV3_W95TXT_E_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_E_CLIP_CLIPRECT_END) + { + /* lol */ + uint32_t index = (method_id - NV3_W95TXT_E_CLIP_CLIPRECT_START) >> 3; + + nv3->pgraph.win95_gdi_text.bitmap_e[index] = param; + + /* Mammoth logger! */ + nv_log("Method Execution: Rect GDI-E%d Data=%08x SizeIn%04x,%04x SizeOut%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", + index, param, nv3->pgraph.win95_gdi_text.size_in_e.x, nv3->pgraph.win95_gdi_text.size_in_e.y, + nv3->pgraph.win95_gdi_text.size_out_e.x, nv3->pgraph.win95_gdi_text.size_out_e.y, + nv3->pgraph.win95_gdi_text.point_e.x, nv3->pgraph.win95_gdi_text.point_e.y, + nv3->pgraph.win95_gdi_text.color1_e, + nv3->pgraph.win95_gdi_text.clip_e.left, nv3->pgraph.win95_gdi_text.clip_e.right, nv3->pgraph.win95_gdi_text.clip_e.top, nv3->pgraph.win95_gdi_text.clip_e.bottom); + + nv3_render_gdi_1bpp_bitmap(nv3->pgraph.win95_gdi_text.color0_e, nv3->pgraph.win95_gdi_text.color1_e, nv3->pgraph.win95_gdi_text.bitmap_e[index], grobj); + return; + } + + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c b/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c new file mode 100644 index 000000000..f07aab737 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_00d_m2mf.c @@ -0,0 +1,94 @@ +/* + * 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: Methods for class 0x0D (Reformat image in memory) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_00d_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_M2MF_IN_CTXDMA_OFFSET: + nv3->pgraph.m2mf.offset_in = param; + nv_log("Method Execution: M2MF Offset In = 0x%08x", param); + break; + case NV3_M2MF_OUT_CTXDMA_OFFSET: + nv3->pgraph.m2mf.offset_out = param; + nv_log("Method Execution: M2MF Offset Out = 0x%08x", param); + break; + case NV3_M2MF_IN_PITCH: + nv3->pgraph.m2mf.pitch_in = param; + nv_log("Method Execution: M2MF Pitch In = 0x%08x", param); + break; + case NV3_M2MF_OUT_PITCH: + nv3->pgraph.m2mf.pitch_out = param; + nv_log("Method Execution: M2MF Pitch Out = 0x%08x", param); + break; + case NV3_M2MF_SCANLINE_LENGTH_IN_BYTES: + nv3->pgraph.m2mf.scanline_length = param; + nv_log("Method Execution: M2MF Scanline Length in Bytes = 0x%08x", param); + break; + case NV3_M2MF_NUM_SCANLINES: + nv3->pgraph.m2mf.num_scanlines = param; + nv_log("Method Execution: M2MF Num Scanlines = 0x%08x", param); + break; + case NV3_M2MF_FORMAT: + nv3->pgraph.m2mf.format = param; + nv_log("Method Execution: M2MF Format = 0x%08x", param); + + // Format Done - start m2mf + + nv3_perform_dma_m2mf(grobj); + + break; + case NV3_M2MF_NOTIFY: + /* This is technically its own thing, but I don't know if it's ever a problem with how we've designed it */ + if (nv3->pgraph.notify_pending) + { + nv_log("WARNING: M2MF notification with notify_pending already set. param=0x%08x, method=0x%04x, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n"); + nv_log("IF THIS BUILD WAS COMPILED WITH NV_LOG_ENABLE_ULTRA, YOU SHOULD SEE A CONTEXT BELOW"); + nv3_debug_ramin_print_context_info(param, context); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY); + + // disable + nv3->pgraph.notify_pending = false; + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY); + /* may need to disable fifo in this state */ + return; + } + + nv_log("Method Execution: TODO: ACTUALLY IMPLEMENT M2MF!!!!"); + // set a notify as pending. + nv3->pgraph.notifier = param; + nv3->pgraph.notify_pending = true; + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break;; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_00e_scaled_image_from_mem.c b/src/video/nv/nv3/classes/nv3_class_00e_scaled_image_from_mem.c new file mode 100644 index 000000000..457c8ade1 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_00e_scaled_image_from_mem.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x0E (Get image from vram and scale it) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_00e_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_010_blit.c b/src/video/nv/nv3/classes/nv3_class_010_blit.c new file mode 100644 index 000000000..ed1ac465b --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_010_blit.c @@ -0,0 +1,60 @@ +/* + * 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: Methods for class 0x10 (Blit something) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_010_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_BLIT_POSITION_IN: + nv3->pgraph.blit.point_in.x = (param & 0xFFFF); + nv3->pgraph.blit.point_in.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: S2SB POINT_IN %d,%d\n", nv3->pgraph.blit.point_in.x, nv3->pgraph.blit.point_in.y); + break; + case NV3_BLIT_POSITION_OUT: + nv3->pgraph.blit.point_out.x = (param & 0xFFFF); + nv3->pgraph.blit.point_out.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: S2SB POINT_OUT %d,%d\n", nv3->pgraph.blit.point_out.x, nv3->pgraph.blit.point_out.y); + + break; + case NV3_BLIT_SIZE: + /* This is the last one*/ + nv3->pgraph.blit.size.x = (param & 0xFFFF); + nv3->pgraph.blit.size.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: S2SB Size %d,%d grobj_0=0x%08x\n", nv3->pgraph.blit.size.x, nv3->pgraph.blit.size.y, grobj.grobj_0); + + nv3_render_blit_screen2screen(grobj); + + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_011_image.c b/src/video/nv/nv3/classes/nv3_class_011_image.c new file mode 100644 index 000000000..1eda15df7 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_011_image.c @@ -0,0 +1,67 @@ +/* + * 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: Methods for class 0x11 (Color image) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_011_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + case NV3_IMAGE_START_POSITION: + nv3->pgraph.image.point.x = (param & 0xFFFF); + nv3->pgraph.image.point.y = (param >> 16); + nv_log("Method Execution: Image Point=%d,%d\n", nv3->pgraph.image.point.x, nv3->pgraph.image.point.y); + break; + /* Seems to allow scaling of the bitblt. */ + case NV3_IMAGE_SIZE: + nv3->pgraph.image.size.x = (param & 0xFFFF); + nv3->pgraph.image.size.y = (param >> 16); + nv_log("Method Execution: Image Size (Clip)=%d,%d\n", nv3->pgraph.image.size.x, nv3->pgraph.image.size.y); + break; + case NV3_IMAGE_SIZE_IN: + nv3->pgraph.image.size_in.x = (param & 0xFFFF); + nv3->pgraph.image.size_in.y = (param >> 16); + nv3->pgraph.image_current_position = nv3->pgraph.image.point; + nv_log("Method Execution: Image SizeIn=%d,%d\n", nv3->pgraph.image.size_in.x, nv3->pgraph.image.size_in.y); + break; + default: + if (method_id >= NV3_IMAGE_COLOR_START && method_id <= NV3_IMAGE_COLOR_END) + { + uint32_t pixel_slot = (method_id - NV3_IMAGE_COLOR_START) >> 2; + nv_log("Method Execution: Image Pixel%d Colour%08x Format%x\n", pixel_slot, param, (grobj.grobj_0) & 0x07); + nv3_render_blit_image(param, grobj); + } + else + { + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + + } + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_012_bitmap.c b/src/video/nv/nv3/classes/nv3_class_012_bitmap.c new file mode 100644 index 000000000..2ac47f0de --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_012_bitmap.c @@ -0,0 +1,41 @@ +/* + * 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: Methods for class 0x12 (Monochrome bitmap) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_012_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_014_transfer2memory.c b/src/video/nv/nv3/classes/nv3_class_014_transfer2memory.c new file mode 100644 index 000000000..b49b1fc89 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_014_transfer2memory.c @@ -0,0 +1,41 @@ +/* + * 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: Methods for class 0x14 (Transfer to Memory) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_014_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_015_stretched_image_from_cpu.c b/src/video/nv/nv3/classes/nv3_class_015_stretched_image_from_cpu.c new file mode 100644 index 000000000..3fa88ba39 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_015_stretched_image_from_cpu.c @@ -0,0 +1,40 @@ +/* + * 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: Methods for class 0x15 (stretched image from cpu to memory) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_015_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_017_d3d5_tri_zeta_buffer.c b/src/video/nv/nv3/classes/nv3_class_017_d3d5_tri_zeta_buffer.c new file mode 100644 index 000000000..3bb8f66d7 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_017_d3d5_tri_zeta_buffer.c @@ -0,0 +1,40 @@ +/* +* 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: Methods for class 0x17 (Direct3D 5.0 accelerated triangle with zeta buffer) +* +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 Connor Hyde +*/ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_017_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_018_point_zeta_buffer.c b/src/video/nv/nv3/classes/nv3_class_018_point_zeta_buffer.c new file mode 100644 index 000000000..87111b70c --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_018_point_zeta_buffer.c @@ -0,0 +1,42 @@ +/* + * 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: Methods for class 0x18 (Point with zeta buffer) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +struct nv3_object_class_018 nv3_d3d5_point_zeta_buffer; + +void nv3_class_018_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c b/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c new file mode 100644 index 000000000..12ac3fe6b --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c @@ -0,0 +1,99 @@ +/* + * 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: Methods for class 0x1C (Image in memory) + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_class_01c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + /* We need this for a lot of methods, so may as well store it here. */ + uint32_t src_buffer_id = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; + + + switch (method_id) + { + /* Color format of the image */ + case NV3_IMAGE_IN_MEMORY_COLOR_FORMAT: + { + // convert to how the bpixel registers represent surface + uint32_t real_format = 1; + + /* TODO: THIS CODE MIGHT BE NONSENSE + Convert between different internal representations of the pixel format, because Nvidia says: I WANT TO MAKE YOUR LIFE PAIN. + */ + switch (param) + { + case nv3_image_in_memory_pixel_format_x8g8b8r8: + real_format = 3; //32bit + // no change + break; + case nv3_image_in_memory_pixel_format_x1r5g5b5_p2: + real_format = 2; + break; + case nv3_image_in_memory_pixel_format_le_y16_p2: + real_format = 0; + break; + } + + /* Set the format */ + + nv3->pgraph.bpixel[src_buffer_id] = (real_format | NV3_BPIXEL_FORMAT_IS_VALID); + + nv_log("Method Execution: Image in Memory BUF%d COLOR_FORMAT=0x%04x\n", src_buffer_id, param); + + break; + } + /* DOn't log invalid */ + case NV3_IMAGE_IN_MEMORY_IN_MEMORY_DMA_CTX_TYPE: + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + /* Pitch - length between scanlines */ + case NV3_IMAGE_IN_MEMORY_PITCH: + nv3->pgraph.image_in_memory.pitch = param & 0x1FF0; + nv3->pgraph.bpitch[src_buffer_id] = param & 0x1FF0; // 12:0 + + nv_log("Method Execution: Image in Memory BUF%d PITCH=0x%04x\n", src_buffer_id, nv3->pgraph.bpitch[src_buffer_id]); + break; + /* Byte offset in GPU VRAM of top left pixel (22:0) */ + case NV3_IMAGE_IN_MEMORY_TOP_LEFT_OFFSET: + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) // RIVA 128ZX + nv3->pgraph.boffset[src_buffer_id] = param & 0x7FFFFF; + else + nv3->pgraph.boffset[src_buffer_id] = param & 0x3FFFFF; + + nv_log("Method Execution: Image in Memory BUF%d TOP_LEFT_OFFSET=0x%08x\n", src_buffer_id, nv3->pgraph.boffset[src_buffer_id]); + break; + case NV3_NVCLASS_CRAP_START ... NV3_NVCLASS_CRAP_END: + /* Suppress but don't do anything */ + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + default: + warning("%s: Invalid or unimplemented method 0x%04x\n", nv3_class_names[context.class_id & 0x1F], method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_names.c b/src/video/nv/nv3/classes/nv3_class_names.c new file mode 100644 index 000000000..64e35d9b3 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_names.c @@ -0,0 +1,67 @@ +/* + * 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: Defines core class names for debugging purposes + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +/* These are the object classes AS RECOGNISED BY THE GRAPHICS HARDWARE. */ +/* The drivers implement a COMPLETELY DIFFERENT SET OF CLASSES. */ + +/* THERE CAN ONLY BE 32 CLASSES IN NV3 BECAUSE THE CLASS ID PART OF THE CONTEXT OF A GRAPHICS OBJECT IN PFIFO RAM HASH TABLE IS ONLY 5 BITS LONG! */ + +const char* nv3_class_names[] = +{ + "NV3 INVALID class 0x00", + "NV3 class 0x01: Beta factor", + "NV3 class 0x02: Render operation", + "NV3 class 0x03: Chroma key", + "NV3 class 0x04: Plane mask", + "NV3 class 0x05: Clipping rectangle", + "NV3 class 0x06: Pattern", + "NV3 class 0x07: Rectangle", + "NV3 class 0x08: Point", + "NV3 class 0x09: Line", + "NV3 class 0x0A: Lin (line without starting or ending pixel)", + "NV3 class 0x0B: Triangle", + "NV3 class 0x0C: Windows 95 GDI text acceleration", + "NV3 class 0x0D: Memory to memory format", + "NV3 class 0x0E: Scaled image from memory", + "NV3 INVALID class 0x0F", + "NV3 class 0x10: Blit", + "NV3 class 0x11: Image", + "NV3 class 0x12: Bitmap", + "NV3 INVALID class 0x13", + "NV3 class 0x14: Transfer to Memory", + "NV3 class 0x15: Stretched image from CPU", + "NV3 INVALID class 0x16", + "NV3 class 0x17: Direct3D 5.0 accelerated textured triangle w/zeta buffer", + "NV3 class 0x18: Point with zeta buffer", + "NV3 INVALID class 0x19", + "NV3 INVALID class 0x1A", + "NV3 INVALID class 0x1B", + "NV3 class 0x1C: Image in Memory", + "NV3 INVALID class 0x1D", + "NV3 INVALID class 0x1E", + "NV3 INVALID class 0x1F", +}; \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_shared_methods.c b/src/video/nv/nv3/classes/nv3_class_shared_methods.c new file mode 100644 index 000000000..89473d829 --- /dev/null +++ b/src/video/nv/nv3/classes/nv3_class_shared_methods.c @@ -0,0 +1,67 @@ +/* + * 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: Methods shared across multiple classes + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 Connor Hyde + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_generic_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + switch (method_id) + { + /* mthdCreate in software(?)*/ + case NV3_ROOT_HI_IM_OBJECT_MCOBJECTYFACE: + //nv_log("mthdCreate obj_name=0x%08x\n", param); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + break; + // set up the current notification request/object + // and check for double notifiers. + case NV3_SET_NOTIFY: + if (nv3->pgraph.notify_pending) + { + nv_log("Executed method NV3_SET_NOTIFY with nv3->pgraph.notify_pending already set. param=0x%08x, method=0x%04x, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n"); + nv_log("IF THIS IS A DEBUG BUILD, YOU SHOULD SEE A CONTEXT BELOW"); + nv3_debug_ramin_print_context_info(param, context); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY); + + // disable + nv3->pgraph.notify_pending = false; + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_DOUBLE_NOTIFY); + /* may need to disable fifo in this state */ + return; + } + + // set a notify as pending. + nv3->pgraph.notifier = param; + nv3->pgraph.notify_pending = true; + break; + default: + nv_log("Shared Generic Methods: Invalid or Unimplemented method 0x%04x", method_id); + nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); + return; + } +} diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c new file mode 100644 index 000000000..01af9100d --- /dev/null +++ b/src/video/nv/nv3/nv3_core.c @@ -0,0 +1,1567 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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> + +/* Main device object pointer */ +nv3_t* nv3; + +/* These are a ****PLACEHOLDER**** and are copied from 3dfx VoodooBanshee/Voodoo3*/ +static video_timings_t timing_nv3_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +static video_timings_t timing_nv3_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +// Revision C +static video_timings_t timing_nv3t_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +static video_timings_t timing_nv3t_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; + +// Prototypes for functions only used in this translation unit +void nv3_init_mappings_mmio(void); +void nv3_init_mappings_svga(void); +bool nv3_is_svga_redirect_address(uint32_t addr); + +uint8_t nv3_svga_read(uint16_t addr, void* priv); +void nv3_svga_write(uint16_t addr, uint8_t val, void* priv); + +// Determine if this address needs to be redirected to the SVGA subsystem. + +bool nv3_is_svga_redirect_address(uint32_t addr) +{ + return (addr >= NV3_PRMVIO_START && addr <= NV3_PRMVIO_END) // VGA + || (addr >= NV3_PRMCIO_START && addr <= NV3_PRMCIO_END) // CRTC + || (addr >= NV3_USER_DAC_START && addr <= NV3_USER_DAC_END); // Note: 6813c6-6813c9 are ignored somewhere else +} + +// 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) +{ + 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 >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + return nv3_mmio_arbitrate_read(addr); + } + + if (nv3_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv3_svga_read(real_address, nv3); + + 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 = 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 = 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 (nv3_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv3_svga_read(real_address, nv3) + | (nv3_svga_read(real_address + 1, nv3) << 8); + + nv_log_verbose_only("Redirected MMIO read16 to SVGA: addr=0x%04x returned 0x%04x\n", addr, ret); + + return ret; + } + + 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) +{ + 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 (nv3_is_svga_redirect_address(addr)) + { + // svga writes are not logged anyway rn + uint32_t real_address = addr & 0x3FF; + + ret = nv3_svga_read(real_address, nv3) + | (nv3_svga_read(real_address + 1, nv3) << 8) + | (nv3_svga_read(real_address + 2, nv3) << 16) + | (nv3_svga_read(real_address + 3, nv3) << 24); + + nv_log_verbose_only("Redirected MMIO read32 to SVGA: addr=0x%04x returned 0x%04x\n", addr, ret); + + return ret; + } + ret = nv3_mmio_arbitrate_read(addr); + return ret; + +} + +// Write 8-bit MMIO +void nv3_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 >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + nv3_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 (nv3_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); + + nv3_svga_write(real_address, val & 0xFF, nv3); + + return; + } + + // 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) +{ + addr &= 0xFFFFFF; + + // This is weitek vga stuff + if (nv3_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); + + nv3_svga_write(real_address, val & 0xFF, nv3); + nv3_svga_write(real_address + 1, (val >> 8) & 0xFF, nv3); + + return; + } + + // 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) +{ + addr &= 0xFFFFFF; + + // This is weitek vga stuff + if (nv3_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); + + nv3_svga_write(real_address, val & 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; + } + + nv3_mmio_arbitrate_write(addr, val); +} + +// AGP read function +uint8_t nv3_agp_read(int32_t func, int32_t addr) +{ + uint8_t ret = 0x00; + + switch (addr) + { + case NV3_AGP_CAPABILITIES_CAP_ID: + ret = NV3_AGP_CAPABILITIES_CAP_ID_AGP; // AGP capable device + break; + case NV3_AGP_CAPABILITIES_NEXT_PTR: // Always off + ret = 0x00; + case NV3_AGP_CAPABILITIES_AGP_VERSION: + ret = (0x1 << NV3_AGP_CAPABILITIES_AGP_VERSION_MAJOR) | NV3_AGP_CAPABILITIES_AGP_VERSION_MINOR; + break; + case NV3_AGP_STATUS_RATE: + // NV3T = AGP 2X, NV3 = AGP 1X + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + ret = NV3_AGP_STATUS_RATE_1X_SUPPORTED | NV3_AGP_STATUS_RATE_2X_SUPPORTED; + else + ret = NV3_AGP_STATUS_RATE_1X_SUPPORTED; + break; + case NV3_AGP_STATUS_BYTE1: + ret = 0x00; // SBA not supported + break; + case NV3_AGP_STATUS_MAX_REQUESTS: + ret = NV3_AGP_STATUS_MAX_REQUESTS_AMOUNT; + break; + // This is also used for SBA but SBA is always off so we can use a bool + case NV3_AGP_COMMAND_BYTE1: + ret = nv3->nvbase.agp_enabled; + break; + default: + ret = nv3->nvbase.pci_config.pci_regs[addr]; + break; + } + + return ret; +} + +// 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; + + // sanity check + if (!nv3) + return ret; + + // 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 = (NV_PCI_DEVICE_NV3 & 0xFF); + break; + + case NV3_PCI_CFG_DEVICE_ID + 1: + ret = (NV_PCI_DEVICE_NV3 >> 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 PCI_REG_COMMAND_L: + ret = nv3->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L]; + break; + + case PCI_REG_COMMAND_H: + 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->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] | NV3_PCI_STATUS_L_66MHZ_CAPABLE); + else + ret = nv3->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L]; + + break; + + case PCI_REG_STATUS_H: + 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: + ret = nv3->nvbase.gpu_revision; // 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->nvbase.pci_config.vbios_enabled; + break; + + case NV3_AGP_CAPABILITIES_POINTER: + if (nv3->nvbase.bus_generation >= nv_bus_agp_1x) + ret = NV3_AGP_CAPABILITIES_START; + else + ret = 0x00; + break; + + case NV3_PCI_CFG_INT_LINE: + ret = nv3->nvbase.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->nvbase.pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)]; + break; + + case NV3_AGP_START ... NV3_AGP_END: + if (nv3->nvbase.bus_generation < nv_bus_agp_1x) + break; + + ret = nv3_agp_read(func, addr); + + break; + + + default: // by default just return pci_config.pci_regs + ret = nv3->nvbase.pci_config.pci_regs[addr]; + break; + + } + + nv_log("nv3_pci_read func=0x%04x addr=0x%04x ret=0x%04x\n", func, addr, ret); + return ret; +} + +void nv3_agp_write(int32_t func, int32_t addr, uint8_t val) +{ + nv3->nvbase.pci_config.pci_regs[addr] = val; + + switch (addr) + { + case NV3_AGP_COMMAND_BYTE1: + nv3->nvbase.agp_enabled = val; + break; + default: + break; + } +} + +void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) +{ + // sanity check + if (!nv3) + return; + + // 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 >= 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_pci_write func=0x%04x addr=0x%04x val=0x%04x\n", func, addr, val); + + nv3->nvbase.pci_config.pci_regs[addr] = val; + + switch (addr) + { + // standard pci command stuff + case PCI_REG_COMMAND_L: + 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->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->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] = val | (NV3_PCI_STATUS_L_66MHZ_CAPABLE); + break; + case PCI_REG_STATUS_H: + 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; + 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->nvbase.pci_config.vbios_enabled = (val & 0x01); + + if (nv3->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(&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->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); + + 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->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: + 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->nvbase.pci_config.pci_regs[NV3_PCI_CFG_SUBSYSTEM_ID + (addr & 0x03)] = val; + break; + + case NV3_AGP_START ... NV3_AGP_END: + if (nv3->nvbase.bus_generation < nv_bus_agp_1x) + break; + + nv3_agp_write(func, addr, val); + + break; + + default: + break; + } +} + + +// +// SVGA functions +// +void nv3_recalc_timings(svga_t* svga) +{ + // sanity check + if (!nv3) + return; + + nv3_t* nv3 = (nv3_t*)svga->priv; + uint32_t pixel_mode = svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 0x03; + + svga->memaddr_latch += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0x1F) << 16; + + /* Turn off override if we are in VGA mode */ + svga->override = !(pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_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 NV3_CRTC_REGISTER_PIXELMODE_8BPP: + svga->rowoffset += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0xE0) << 1; // ????? + svga->bpp = 8; + svga->lowres = 0; + svga->map8 = svga->pallook; + break; + case NV3_CRTC_REGISTER_PIXELMODE_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[NV3_CRTC_REGISTER_VRETRACESTART] >> 1) & 0x01) + svga->rowoffset += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0xE0) << 2; + else + svga->rowoffset += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0xE0) << 3; + + /* sometimes it really renders in 15bpp, so you need to do this */ + if ((nv3->pramdac.general_control >> NV3_PRAMDAC_GENERAL_CONTROL_565_MODE) & 0x01) + { + svga->bpp = 16; + svga->lowres = 0; + } + else + { + svga->bpp = 15; + svga->lowres = 0; + + } + + break; + case NV3_CRTC_REGISTER_PIXELMODE_32BPP: + svga->rowoffset += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0xE0) << 3; + + svga->bpp = 32; + svga->lowres = 0; + //svga->render = nv3_render_32bpp; + 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) +{ + // sanity check + if (!nv3) + return; + + nv3_recalc_timings(&nv3->nvbase.svga); +} + +// Force Redraw +// Reset etc. +void nv3_force_redraw(void* priv) +{ + // sanity check + if (!nv3) + return; + + nv3->nvbase.svga.fullchange = changeframecount; +} + +// Read from SVGA core memory +uint8_t nv3_svga_read(uint16_t addr, void* priv) +{ + + nv3_t* nv3 = (nv3_t*)priv; + + uint8_t ret = 0x00; + + // sanity check + if (!nv3) + return ret; + + // 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 NV3_CRTC_REGISTER_INDEX: + ret = nv3->nvbase.svga.crtcreg; + break; + case NV3_CRTC_REGISTER_WTF: + ret = 0x08; // Required to not freeze in certain situations on v3.xx drivers. Even though this register doesn't actually exist lol + break; + case NV3_CRTC_REGISTER_CURRENT: + // Support the extended NVIDIA CRTC register range + switch (nv3->nvbase.svga.crtcreg) + { + case NV3_CRTC_REGISTER_RL0: + ret = nv3->nvbase.svga.displine & 0xFF; + break; + /* Is rl1?*/ + case NV3_CRTC_REGISTER_RL1: + ret = (nv3->nvbase.svga.displine >> 8) & 7; + break; + case NV3_CRTC_REGISTER_I2C: + ret = i2c_gpio_get_sda(nv3->nvbase.i2c) << 3 + | i2c_gpio_get_scl(nv3->nvbase.i2c) << 2; + + break; + 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_write(uint16_t addr, uint8_t val, void* priv) +{ + // sanity check + if (!nv3) + return; + + // 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 = 0x00; + + // todo: + // Pixel formats (8bit vs 555 vs 565) + // VBE 3.0? + + switch (addr) + { + case NV3_CRTC_REGISTER_INDEX: + // real mode access to GPU MMIO space... + nv3->nvbase.svga.crtcreg = val; + break; + // support the extended crtc regs and debug this out + case NV3_CRTC_REGISTER_CURRENT: + + // 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... + old_value = nv3->nvbase.svga.crtc[crtcreg]; + + 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; + /* Handle some large screen stuff */ + case NV3_CRTC_REGISTER_PIXELMODE: + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) + nv3->nvbase.svga.vtotal += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) + nv3->nvbase.svga.vblankstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) + nv3->nvbase.svga.vsyncstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) + nv3->nvbase.svga.hdisp += 0x400; + + /* Make sure dispend and vblankstart are right if we are displaying above 1024 vert */ + if (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) + nv3->nvbase.svga.dispend += 0x400; + + break; + case NV3_CRTC_REGISTER_HEB: + if (val & 0x01) + nv3->nvbase.svga.hdisp += 0x100; + break; + case NV3_CRTC_REGISTER_I2C_GPIO: + { + uint8_t scl = !!(val & 0x20); + uint8_t sda = !!(val & 0x10); + // Set an I2C GPIO register + i2c_gpio_set(nv3->nvbase.i2c, scl, sda); + break; + } + /* [6:0] contains cursorAddr [22:16] */ + case NV3_CRTC_REGISTER_CURSOR_ADDR0: + 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 & 0xF8) << 4); // 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_value != 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 (nv3->nvbase.svga.crtcreg < 0xE + || nv3->nvbase.svga.crtcreg > 0x10) + { + nv3->nvbase.svga.fullchange = changeframecount; + nv3_recalc_timings(&nv3->nvbase.svga); + } + } + + break; + default: + svga_out(addr, val, &nv3->nvbase.svga); + break; + } + +} + +/* DFB, sets up a dumb framebuffer */ +uint8_t nv3_dfb_read8(uint32_t addr, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + return nv3->nvbase.svga.vram[addr]; +} + +uint16_t nv3_dfb_read16(uint32_t addr, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + return (nv3->nvbase.svga.vram[addr + 1] << 8) | nv3->nvbase.svga.vram[addr]; +} + +uint32_t nv3_dfb_read32(uint32_t addr, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + return (nv3->nvbase.svga.vram[addr + 3] << 24) | (nv3->nvbase.svga.vram[addr + 2] << 16) + + (nv3->nvbase.svga.vram[addr + 1] << 8) | nv3->nvbase.svga.vram[addr]; +} + +void nv3_dfb_write8(uint32_t addr, uint8_t val, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + nv3->nvbase.svga.vram[addr] = val; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + nv3_render_current_bpp_dfb_8(addr); +} + +void nv3_dfb_write16(uint32_t addr, uint16_t val, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + nv3->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; + nv3->nvbase.svga.vram[addr] = (val) & 0xFF; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + nv3_render_current_bpp_dfb_16(addr); + +} + +void nv3_dfb_write32(uint32_t addr, uint32_t val, void* priv) +{ + addr &= (nv3->nvbase.svga.vram_mask); + nv3->nvbase.svga.vram[addr + 3] = (val >> 24) & 0xFF; + nv3->nvbase.svga.vram[addr + 2] = (val >> 16) & 0xFF; + nv3->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; + nv3->nvbase.svga.vram[addr] = (val) & 0xFF; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + + nv3_render_current_bpp_dfb_32(addr); + +} + +/* Cursor shit */ +void nv3_draw_cursor(svga_t* svga, int32_t drawline) +{ + // sanity check + if (!nv3) + return; + + // if cursor disabled is set, return + if ((nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_CURSOR_START] >> NV3_CRTC_REGISTER_CURSOR_START_DISABLED) & 0x01) + return; + + // NT GDI drivers: Load cursor using NV_IMAGE_FROM_MEMORY ("NV3LCD") + // 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 = NV3_RAMIN_OFFSET_CURSOR; + + /* let's just assume buffer 0 here...that code needs to be totally rewritten*/ + nv3_coord_16_t start_position = nv3->pramdac.cursor_start; + + /* refuse to draw if thge cursor is offscreen */ + if (start_position.x >= nv3->nvbase.svga.hdisp + || start_position.y >= nv3->nvbase.svga.dispend) + { + return; + } + + nv_log("nv3_draw_cursor start=0x%04x,0x%04x", start_position.x, start_position.y); + + uint32_t final_position = nv3_render_get_vram_address_for_buffer(start_position, 0); + + uint16_t* vram_16 = (uint16_t*)nv3->nvbase.svga.vram; + uint32_t* vram_32 = (uint32_t*)nv3->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 < NV3_PRAMDAC_CURSOR_SIZE_Y; y++) + { + for (int32_t x = 0; x < NV3_PRAMDAC_CURSOR_SIZE_X; x++) + { + uint16_t current_pixel = nv3_ramin_read16(ramin_cursor_position, nv3); + + // 0000 = transparent, so skip drawing + if (current_pixel) + { + bool replace_bit = (current_pixel & 0x8000); + + // use buffer 0 BPIXEL + uint32_t bpixel_format = (nv3->pgraph.bpixel[0]) & 0x03; + + switch (bpixel_format) + { + case bpixel_fmt_8bit: + if (replace_bit) + nv3->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 ^ nv3->nvbase.svga.vram[final_position]; + nv3->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] = nv3->nvbase.svga.conv_16to32(&nv3->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 = nv3->nvbase.svga.conv_16to32(&nv3->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 (nv3->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 = nv3->pramdac.cursor_start.x; + + // reset at the end of each line so we "jump" to the start x + final_position = nv3_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 nv3_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 = NV3_PROM_END - NV3_PROM_START; + uint32_t real_rom_size = max_rom_size; + + // set it + if (nv3->nvbase.vbios.sz < max_rom_size) + real_rom_size = nv3->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 = nv3->nvbase.vbios.rom[rom_address]; + nv_log("PROM VBIOS Read 0x%05x <- 0x%05x", val, rom_address); + return val; + } +} + +void nv3_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); +} + +// Initialise the MMIO mappings +void nv3_init_mappings_mmio(void) +{ + nv_log("Initialising MMIO mapping\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(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, + nv3_dfb_read16, + nv3_dfb_read32, + nv3_dfb_write8, + nv3_dfb_write16, + nv3_dfb_write32, + nv3->nvbase.svga.vram, 0, &nv3->nvbase.svga); + + // the SVGA/LFB mapping is also mirrored + mem_mapping_add(&nv3->nvbase.framebuffer_mapping_mirror, 0, 0, + nv3_dfb_read8, + nv3_dfb_read16, + nv3_dfb_read32, + nv3_dfb_write8, + nv3_dfb_write16, + nv3_dfb_write32, + nv3->nvbase.svga.vram, 0, &nv3->nvbase.svga); + + io_sethandler(0x03c0, 0x0020, + nv3_svga_read, NULL, NULL, + nv3_svga_write, NULL, NULL, + nv3); +} + +void nv3_init_mappings(void) +{ + nv3_init_mappings_mmio(); + nv3_init_mappings_svga(); +} + +// Updates the mappings after initialisation. +void nv3_update_mappings(void) +{ + // sanity check + if (!nv3) + return; + + // setting this to 0 doesn't seem to disable it, based on the datasheet + + nv_log("\nMemory Mapping Config Change:\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->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->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(&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); + + // Setup BAR0 (MMIO) + + nv_log("BAR0 (MMIO Base) = 0x%08x\n", nv3->nvbase.bar0_mmio_base); + + + if (nv3->nvbase.bar0_mmio_base) + mem_mapping_set_addr(&nv3->nvbase.mmio_mapping, nv3->nvbase.bar0_mmio_base, NV3_MMIO_SIZE); + + // if this breaks anything, remove it + nv_log("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 + + /* TODO: 2MB */ + + // 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 + + // 8MB VRAM memory map: + // LFB_BASE->LFB_BASE+VRAM_SIZE=LFB + // What is in 800000-c00000? + // LFB_BASE+0xC00000 = RAMIN + + if (nv3->nvbase.bar1_lfb_base) + { + if (nv3->nvbase.vram_amount == NV3_VRAM_SIZE_4MB) + { + mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping, nv3->nvbase.bar1_lfb_base, NV3_VRAM_SIZE_4MB); + mem_mapping_set_addr(&nv3->nvbase.ramin_mapping_mirror, nv3->nvbase.bar1_lfb_base + NV3_LFB_RAMIN_MIRROR_START, NV3_LFB_MAPPING_SIZE); + mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping_mirror, nv3->nvbase.bar1_lfb_base + NV3_LFB_MIRROR_START, NV3_VRAM_SIZE_4MB); + mem_mapping_set_addr(&nv3->nvbase.ramin_mapping, nv3->nvbase.bar1_lfb_base + NV3_LFB_RAMIN_START, NV3_LFB_MAPPING_SIZE); + } + else if (nv3->nvbase.vram_amount == NV3_VRAM_SIZE_8MB) + { + // we don't need this one in the case of 8mb, because regular mapping is 8mb + mem_mapping_disable(&nv3->nvbase.ramin_mapping_mirror); + mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping, nv3->nvbase.bar1_lfb_base, NV3_VRAM_SIZE_8MB); + mem_mapping_set_addr(&nv3->nvbase.framebuffer_mapping_mirror, nv3->nvbase.bar1_lfb_base + NV3_LFB_MIRROR_START, NV3_LFB_MAPPING_SIZE); + mem_mapping_set_addr(&nv3->nvbase.ramin_mapping, nv3->nvbase.bar1_lfb_base + NV3_LFB_RAMIN_START, NV3_LFB_MAPPING_SIZE); + } + else + { + fatal("NV3 2MB not implemented yet"); + } + } + + // Did we change the banked SVGA mode? + switch (nv3->nvbase.svga.gdcreg[0x06] & 0x0c) + { + case NV3_CRTC_BANKED_128K_A0000: + nv_log("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("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("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("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) +{ + // set the vram amount and gpu revision + + /* We don't bother looking these up if they are nonzero. On Riva 128 ZX, they are already set by the init function (always 8 MB VRAM + Revision C0) */ + if (!nv3->nvbase.vram_amount) + nv3->nvbase.vram_amount = device_get_config_int("vram_size"); + + if (!nv3->nvbase.gpu_revision) + nv3->nvbase.gpu_revision = device_get_config_int("chip_revision"); + + /* Set log device name based on card model */ + const char* log_device_name = (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) ? "NV3T" : "NV3"; + + if (device_get_config_int("nv_debug_fulllog")) + nv3->nvbase.log = log_open(log_device_name); + else + nv3->nvbase.log = log_open_cyclic(log_device_name); + +#ifdef ENABLE_NV_LOG + // Allows nv_log to be used for multiple nvidia devices + nv_log_set_device(nv3->nvbase.log); +#endif + nv_log("Initialising core\n"); + + // this will only be logged if ENABLE_NV_LOG_ULTRA is defined + nv_log_verbose_only("ULTRA LOGGING enabled"); + + // Figure out which vbios the user selected + // This depends on the bus we are using and if the gpu is rev a/b or rev c + const char* vbios_id = device_get_config_bios("vbios"); + const char* vbios_file = ""; + + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + { + if (nv3->nvbase.bus_generation == nv_bus_pci) + vbios_file = device_get_bios_file(&nv3t_device_pci, vbios_id, 0); + else + vbios_file = device_get_bios_file(&nv3t_device_agp, vbios_id, 0); + } + else + { + if (nv3->nvbase.bus_generation == nv_bus_pci) + vbios_file = device_get_bios_file(&nv3_device_pci, vbios_id, 0); + else + vbios_file = device_get_bios_file(&nv3_device_agp, vbios_id, 0); + } + + + int32_t err = rom_init(&nv3->nvbase.vbios, vbios_file, 0xC0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (err) + { + nv_log("NV3 FATAL: failed to load VBIOS err=%d\n", err); + fatal("Nvidia NV3 init failed: Somehow selected a nonexistent VBIOS? err=%d\n", err); + return NULL; + } + else + nv_log("Successfully loaded VBIOS %s located at %s\n", vbios_id, vbios_file); + + // set up the bus and start setting up SVGA core + if (nv3->nvbase.bus_generation == nv_bus_pci) + { + nv_log("Using PCI bus\n"); + + pci_add_card(PCI_ADD_NORMAL, nv3_pci_read, nv3_pci_write, NULL, &nv3->nvbase.pci_slot); + + /* Initialise the right revision of the card */ + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + { + svga_init(&nv3t_device_pci, &nv3->nvbase.svga, nv3, nv3->nvbase.vram_amount, + nv3_recalc_timings, nv3_svga_read, nv3_svga_write, nv3_draw_cursor, NULL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv3t_pci); + } + else + { + svga_init(&nv3_device_pci, &nv3->nvbase.svga, nv3, nv3->nvbase.vram_amount, + nv3_recalc_timings, nv3_svga_read, nv3_svga_write, nv3_draw_cursor, NULL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv3_pci); + } + + } + else if (nv3->nvbase.bus_generation == nv_bus_agp_1x + || nv3->nvbase.bus_generation == nv_bus_agp_2x) + { + nv_log("Using AGP 1X/2X bus\n"); + + pci_add_card(PCI_ADD_AGP, nv3_pci_read, nv3_pci_write, NULL, &nv3->nvbase.pci_slot); + + /* Initialise the right revision of the card */ + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + { + svga_init(&nv3t_device_agp, &nv3->nvbase.svga, nv3, nv3->nvbase.vram_amount, + nv3_recalc_timings, nv3_svga_read, nv3_svga_write, nv3_draw_cursor, NULL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv3t_agp); + } + else + { + svga_init(&nv3_device_agp, &nv3->nvbase.svga, nv3, nv3->nvbase.vram_amount, + nv3_recalc_timings, nv3_svga_read, nv3_svga_write, nv3_draw_cursor, NULL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv3_agp); + } + } + + // set vram + nv_log("VRAM=%d bytes\n", nv3->nvbase.svga.vram_max); + + // init memory mappings + nv3_init_mappings(); + + // make us actually exist + 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 + + nv_log("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 engine + + nv_log("Initialising I2C..."); + nv3->nvbase.i2c = i2c_gpio_init("nv3_i2c"); + nv3->nvbase.ddc = ddc_init(i2c_gpio_get_bus(nv3->nvbase.i2c)); + + return nv3; +} + +// RIVA 128 PCI initialisation function: This function simply allocates the device struct, 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); + return nv3; +} + +// RIVA 128 AGP initialisation function: This function simply allocates the device struct, 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); + return nv3; +} + +// RIVA 128 ZX PCI initialisation function: This function simply allocates the device struct, and sets the bus to PCI before initialising. +// It also sets the GPU revision to C0 because NV3T config doesn't let you configure the rev (there were multiple steppings, but it's basically irrelevant), +// and sets RAM to 8 MB (the only supported config on ZX cards) +void* nv3t_init_pci(const device_t* info) +{ + nv3 = (nv3_t*)calloc(1, sizeof(nv3_t)); + nv3->nvbase.bus_generation = nv_bus_pci; + nv3->nvbase.gpu_revision = NV3_PCI_CFG_REVISION_C00; + nv3->nvbase.vram_amount = NV3_VRAM_SIZE_8MB; + nv3_init(info); + return nv3; +} + +// RIVA 128 ZX AGP initialisation function: This function simply allocates the device struct, and sets the bus to AGP before initialising. +// It also sets the GPU revision to C0 because NV3T config doesn't let you configure the rev (there were multiple steppings, but it's basically irrelevant) +// and sets RAM to 8 MB (the only supported config on ZX cards) +void* nv3t_init_agp(const device_t* info) +{ + nv3 = (nv3_t*)calloc(1, sizeof(nv3_t)); + nv3->nvbase.bus_generation = nv_bus_agp_2x; // Riva 128 ZX is AGP2X + nv3->nvbase.gpu_revision = NV3_PCI_CFG_REVISION_C00; + nv3->nvbase.vram_amount = NV3_VRAM_SIZE_8MB; + nv3_init(info); + return nv3; +} + +void nv3_close(void* priv) +{ + // Shut down logging + log_close(nv3->nvbase.log); +#ifdef ENABLE_NV_LOG + nv_log_set_device(NULL); +#endif + + // Shut down I2C and the DDC + ddc_close(nv3->nvbase.ddc); + i2c_gpio_close(nv3->nvbase.i2c); + + // Destroy the Rivatimers. (It doesn't matter if they are running.) + rivatimer_destroy(nv3->nvbase.pixel_clock_timer); + rivatimer_destroy(nv3->nvbase.memory_clock_timer); + + // Shut down SVGA + svga_close(&nv3->nvbase.svga); + free(nv3); + nv3 = NULL; +} + +// See if the bios rom is available. +int32_t nv3_available(void) +{ + return rom_present(NV3_VBIOS_ASUS_V3000_V151) + || rom_present(NV3_VBIOS_DIAMOND_V330_V162) + || rom_present(NV3_VBIOS_ERAZOR_V14700) + || rom_present(NV3_VBIOS_ERAZOR_V15403) + || rom_present(NV3_VBIOS_ERAZOR_V15500) + || rom_present(NV3_VBIOS_STB_V128_V182) + || rom_present(NV3_VBIOS_STB_V128_V182) + || rom_present(NV3T_VBIOS_ASUS_V170) + || rom_present(NV3T_VBIOS_DIAMOND_V330_V182B) + || rom_present(NV3T_VBIOS_REFERENCE_CEK_V171) + || rom_present(NV3T_VBIOS_REFERENCE_CEK_V172); +} + +// NV3 (RIVA 128) +// PCI +// 2MB or 4MB VRAM +const device_t nv3_device_pci = +{ + .name = "nVIDIA RIVA 128 (NV3) PCI", + .internal_name = "nv3_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = nv3_init_pci, + .close = nv3_close, + .speed_changed = nv3_speed_changed, + .force_redraw = nv3_force_redraw, + .available = nv3_available, + .config = nv3_config, +}; + +// 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, + .available = nv3_available, + .config = nv3_config, +}; + +// NV3T (RIVA 128 ZX) +// PCI +// 8MB VRAM +const device_t nv3t_device_pci = +{ + .name = "nVIDIA RIVA 128 ZX (NV3T) PCI", + .internal_name = "nv3t_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = nv3t_init_pci, + .close = nv3_close, + .speed_changed = nv3_speed_changed, + .force_redraw = nv3_force_redraw, + .available = nv3_available, + .config = nv3t_config, +}; + +// NV3T (RIVA 128) +// AGP +// 2MB or 4MB VRAM +const device_t nv3t_device_agp = +{ + .name = "nVIDIA RIVA 128 ZX (NV3T) AGP", + .internal_name = "nv3t_agp", + .flags = DEVICE_AGP, + .local = 0, + .init = nv3t_init_agp, + .close = nv3_close, + .speed_changed = nv3_speed_changed, + .force_redraw = nv3_force_redraw, + .available = nv3_available, + .config = nv3t_config, +}; \ No newline at end of file diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c new file mode 100644 index 000000000..3399ca9fe --- /dev/null +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -0,0 +1,213 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +// STANDARD NV3 includes +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +// 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) +{ + // sanity check + if (!nv3) + return 0x00; + + uint32_t ret = 0x00; + + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always to dword align, but it crashes if you don't do this. + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + 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_PFIFO_START && address <= NV3_PFIFO_END) + ret = nv3_pfifo_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) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut + ret = nv3_pramdac_read(address); + else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) + ret = nv3_dfb_read32(address & nv3->nvbase.svga.vram_mask, &nv3->nvbase.svga); + else if (address >= NV3_USER_START && address <= NV3_USER_END) + ret = nv3_user_read(address); + else + { + //nvplay stuff + //#ifdef ENABLE_NV_LOG_ULTRA + //warning("MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning unmapped pattern]\n", address); + //#else + nv_log("MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning unmapped pattern]\n", address); + //#endif + + // The real hardware returns a garbage pattern + return 0x00; + } + + return ret; +} + +void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) +{ + // sanity check + if (!nv3) + return; + + // 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. + address &= 0xFFFFFF; + + + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always dword aligned in Nvidia's drivers, but it crashes if you don't do this. + // Exclude the 4bpp/8bpp CLUT for this purpose + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + 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) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut + nv3_pramdac_write(address, value); + else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) + nv3_dfb_write32(address, value, &nv3->nvbase.svga); + else if (address >= NV3_USER_START && address <= NV3_USER_END) + nv3_user_write(address, value); + //RAMIN is its own thing + else + { + //nvplay stuff + //#ifdef ENABLE_NV_LOG_ULTRA + //warning("MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); + //#else + nv_log("MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); + //#endif + + return; + } +} + + +// // +// ******* 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_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) {}; diff --git a/src/video/nv/nv3/nv3_core_config.c b/src/video/nv/nv3/nv3_core_config.c new file mode 100644 index 000000000..b039ff82b --- /dev/null +++ b/src/video/nv/nv3/nv3_core_config.c @@ -0,0 +1,240 @@ +/* + * 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. + * + * Provides NV3 configuration + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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> + +const device_config_t nv3_config[] = +{ + // VBIOS type configuration + { + .name = "vbios", + .description = "Model", + .type = CONFIG_BIOS, + .default_string = "NV3_VBIOS_ERAZOR_V15403", + .default_int = 0, + .bios = + { + + { + .name = "ELSA VICTORY Erazor - Version 1.47.00", .files_no = 1, + .internal_name = "NV3_VBIOS_ERAZOR_V14700", + .files = {NV3_VBIOS_ERAZOR_V14700, ""} + }, + { + .name = "ELSA VICTORY Erazor - Version 1.54.03", .files_no = 1, + .internal_name = "NV3_VBIOS_ERAZOR_V15403", + .files = {NV3_VBIOS_ERAZOR_V15403, ""} + }, + { + .name = "ELSA VICTORY Erazor - Version 1.55.00", .files_no = 1, + .internal_name = "NV3_VBIOS_ERAZOR_V15500", + .files = {NV3_VBIOS_ERAZOR_V15500, ""} + }, + { + .name = "Diamond Viper V330 - Version 1.62-CO", .files_no = 1, + .internal_name = "NV3_VBIOS_DIAMOND_V330_V162", + .files = {NV3_VBIOS_DIAMOND_V330_V162, ""}, + }, + { + .name = "ASUS AGP/3DP-V3000 - Version 1.51B", .files_no = 1, + .internal_name = "NV3_VBIOS_ASUS_V3000_V151", + .files = {NV3_VBIOS_ASUS_V3000_V151, ""}, + }, + { + .name = "STB Velocity 128 - Version 1.60 [BUGGY]", .files_no = 1, + .internal_name = "NV3_VBIOS_STB_V128_V160", + .files = {NV3_VBIOS_STB_V128_V160, ""}, + }, + { + .name = "STB Velocity 128 - Version 1.82", .files_no = 1, + .internal_name = "NV3_VBIOS_STB_V128_V182", + .files = {NV3_VBIOS_STB_V128_V182, ""}, + }, + } + }, + // Memory configuration + { + .name = "vram_size", + .description = "VRAM Size", + .type = CONFIG_SELECTION, + .default_int = NV3_VRAM_SIZE_4MB, + .selection = + { + // I thought this was never released, but it seems that at least one was released: + // The card was called the "NEC G7AGK" + { + .description = "2 MB", + .value = NV3_VRAM_SIZE_2MB, + }, + + { + .description = "4 MB", + .value = NV3_VRAM_SIZE_4MB, + }, + } + + }, + { + .name = "chip_revision", + .description = "Chip Revision", + .type = CONFIG_SELECTION, + .default_int = NV3_PCI_CFG_REVISION_B00, + .selection = + { + { + .description = "RIVA 128 Prototype (Revision A; January 1997)", + .value = NV3_PCI_CFG_REVISION_A00, + }, + { + .description = "RIVA 128 (Revision B)", + .value = NV3_PCI_CFG_REVISION_B00, + }, + } + }, + // Multithreading configuration + { + + .name = "pgraph_threads", +#ifndef RELEASE_BUILD + .description = "PFIFO/PGRAPH - Number of threads to split large object method execution into", +#else + .description = "Render threads", +#endif + .type = CONFIG_SELECTION, + .default_int = 1, // todo: change later + .selection = + { + { + .description = "1 thread (Only use if issues appear with more threads)", + .value = 1, + }, + { + .description = "2 threads", + .value = 2, + }, + { + .description = "4 threads", + .value = 4, + }, + { + .description = "8 threads", + .value = 8, + }, + }, + }, +#ifndef RELEASE_BUILD + { + .name = "nv_debug_fulllog", + .description = "Disable Cyclical Lines Detection for nv_log (Use for getting full context at cost of VERY large log files)", + .type = CONFIG_BINARY, + .default_int = 0, + }, +#endif + { + .type = CONFIG_END + } +}; + +const device_config_t nv3t_config[] = +{ + // VBIOS type configuration + { + .name = "vbios", + .description = "Model", + .type = CONFIG_BIOS, + .default_string = "NV3T_VBIOS_DIAMOND_V330_V182B", + .default_int = 0, + .bios = + { + { + + .name = "Diamond Multimedia Viper V330 8M BIOS - Version 1.82B", .files_no = 1, + .internal_name = "NV3T_VBIOS_DIAMOND_V330_V182B", + .files = {NV3T_VBIOS_DIAMOND_V330_V182B, ""}, + }, + { + .name = "ASUS AGP-V3000 ZXTV BIOS - V1.70D.03", .files_no = 1, + .internal_name = "NV3T_VBIOS_ASUS_V170", + .files = {NV3T_VBIOS_ASUS_V170, ""}, + }, + { + .name = "NVidia Reference BIOS - V1.71B-N", .files_no = 1, + + .internal_name = "NV3T_VBIOS_REFERENCE_CEK_V171", + .files = {NV3T_VBIOS_REFERENCE_CEK_V171, ""}, + }, + + { + .name = "NVidia Reference BIOS - V1.72B", .files_no = 1, + .internal_name = "NV3T_VBIOS_REFERENCE_CEK_V172", + .files = {NV3T_VBIOS_REFERENCE_CEK_V172, ""}, + }, + } + }, + // Multithreading configuration + { + + .name = "pgraph_threads", +#ifndef RELEASE_BUILD + .description = "PFIFO/PGRAPH - Number of threads to split large object method execution into", +#else + .description = "Render threads", +#endif + .type = CONFIG_SELECTION, + .default_int = 1, // todo: change later + .selection = + { + { + .description = "1 thread (Only use if issues appear with more threads)", + .value = 1, + }, + { + .description = "2 threads", + .value = 2, + }, + { + .description = "4 threads", + .value = 4, + }, + { + .description = "8 threads", + .value = 8, + }, + }, + }, +#ifndef RELEASE_BUILD + { + .name = "nv_debug_fulllog", + .description = "Disable Cyclical Lines Detection for nv_log (Use for getting full context at cost of VERY large log files)", + .type = CONFIG_BINARY, + .default_int = 0, + }, +#endif + { + .type = CONFIG_END + } +}; \ No newline at end of file diff --git a/src/video/nv/nv3/render/nv3_render_blit.c b/src/video/nv/nv3/render/nv3_render_blit.c new file mode 100644 index 000000000..92b657cd0 --- /dev/null +++ b/src/video/nv/nv3/render/nv3_render_blit.c @@ -0,0 +1,229 @@ +/* +* 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 Core rendering code (Software version) +* +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 Connor Hyde +*/ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/plat.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +/* Check the line bounds */ +void nv3_class_011_check_line_bounds(void) +{ + uint32_t relative_x = nv3->pgraph.image_current_position.x - nv3->pgraph.image.point.x; + + /* In the case of class 0x11 there is no requirement to check for relative_y because we have exceeded the size of the image */ + if (relative_x >= nv3->pgraph.image.size_in.x) + { + nv3->pgraph.image_current_position.y++; + nv3->pgraph.image_current_position.x = nv3->pgraph.image.point.x; + } +} + +/* Renders an image from cpu */ +void nv3_render_blit_image(uint32_t color, nv3_grobj_t grobj) +{ + /* todo: a lot of stuff */ + + uint32_t pixel0 = 0, pixel1 = 0, pixel2 = 0, pixel3 = 0; + + /* Some extra data is sent as padding, we need to clip it off using size_out */ + + uint16_t clip_x = nv3->pgraph.image.point.x + nv3->pgraph.image.size.x; + /* we need to unpack them - IF THIS IS USED SOMEWHERE ELSE, DO SOMETHING ELSE WITH IT */ + /* the reverse order is due to the endianness */ + switch (nv3->nvbase.svga.bpp) + { + // 4 pixels packed into one color in 8bpp + case 8: + + //pixel3 + pixel3 = color & 0xFF; + if (nv3->pgraph.image_current_position.x < clip_x) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel3, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + pixel2 = (color >> 8) & 0xFF; + if (nv3->pgraph.image_current_position.x < clip_x) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel2, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + pixel1 = (color >> 16) & 0xFF; + if (nv3->pgraph.image_current_position.x < clip_x) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel1, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + pixel0 = (color >> 24) & 0xFF; + if (nv3->pgraph.image_current_position.x < clip_x) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel0, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + break; + // 2 pixels packed into one color in 15/16bpp + case 15: + case 16: + pixel1 = (color) & 0xFFFF; + if (nv3->pgraph.image_current_position.x < (clip_x)) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel1, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + pixel0 = (color >> 16) & 0xFFFF; + if (nv3->pgraph.image_current_position.x < (clip_x)) nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel0, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + break; + // just one pixel in 32bpp + case 32: + if (nv3->pgraph.image_current_position.x < clip_x) nv3_render_write_pixel(nv3->pgraph.image_current_position, color, grobj); + nv3->pgraph.image_current_position.x++; + nv3_class_011_check_line_bounds(); + + break; + } +} + + +#define NV3_MAX_HORIZONTAL_SIZE 1920 +#define NV3_MAX_VERTICAL_SIZE 1200 + +/* 1920 for margin. Holds a buffer of the old screen we want to hold so we don't overwrite things we already overwtote +We only need to clear it once per blit, because the blits are always the same size, and then only for the size of our new blit + +Extremely not crazy about this...Surely a better way to do it without buffering the ENTIRE SCREEN. I only update the parts that are needed, but still... + +This is LUDICROUSLY INEFFICIENT (2*O(n^2)) and COMPLETELY TERRIBLE code, but it's currently 2:48am so I can't think of a better approach... +*/ +uint32_t nv3_s2sb_line_buffer[NV3_MAX_HORIZONTAL_SIZE*NV3_MAX_VERTICAL_SIZE] = {0}; + +void nv3_render_blit_screen2screen_for_buffer(nv3_grobj_t grobj, uint32_t dst_buffer) +{ + if (nv3->pgraph.blit.size.x < NV3_MAX_HORIZONTAL_SIZE + && nv3->pgraph.blit.size.y < NV3_MAX_VERTICAL_SIZE) + memset(&nv3_s2sb_line_buffer, 0x00, (sizeof(uint32_t) * nv3->pgraph.blit.size.y) * (sizeof(uint32_t) * nv3->pgraph.blit.size.x)); + + /* First calculate our source and destination buffer */ + uint32_t src_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; + + nv3_coord_16_t in_position = nv3->pgraph.blit.point_in; + nv3_coord_16_t out_position = nv3->pgraph.blit.point_out; + + /* Coordinates for copying an entire line at a time */ + uint32_t buf_position = 0, vram_position = 0, size_x = nv3->pgraph.blit.size.x; + + /* + Read the old pixel into the line buffer + Assumption: All data is sent in an unpacked format. In the case of an NVIDIA GPU this means that all data is sent 32 bits at a time regardless of if + the actual source data is 32 bits in size or not. For pixel data, the upper bits are left as 0 in 8bpp/16bpp mode. For 86box purposes, the data is written + 8/16 bits at a time. + + TODO: CHECK FOR PACKED FORMAT!!!!! + */ + + if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + size_x <<= 1; + else if (nv3->nvbase.svga.bpp == 32) + size_x <<= 2; + + for (int32_t y = 0; y < nv3->pgraph.blit.size.y; y++) + { + buf_position = (nv3->pgraph.blit.size.x * y); + /* shouldn't matter in non-wtf mode */ + vram_position = nv3_render_get_vram_address_for_buffer(in_position, src_buffer); + + memcpy(&nv3_s2sb_line_buffer[buf_position], &nv3->nvbase.svga.vram[vram_position], size_x); + in_position.y++; + /* 32bit buffer */ + } + + /* simply write it all back to vram */ + for (int32_t y = 0; y < nv3->pgraph.blit.size.y; y++) + { + buf_position = (nv3->pgraph.blit.size.x * y); + vram_position = nv3_render_get_vram_address_for_buffer(out_position, dst_buffer); + + memcpy(&nv3->nvbase.svga.vram[vram_position], &nv3_s2sb_line_buffer[buf_position], size_x); + out_position.y++; + } + + /* + //32bit only as a test + uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; + + if (nv3->pgraph.boffset[src_buffer] != nv3->pgraph.boffset[dst_buffer]) + { + // stretch out the position to the new one + + nv3_coord_16_t current_pos_in; + nv3_coord_16_t current_pos_out; + + current_pos_in.x = nv3->pgraph.blit.point_in.x; + current_pos_in.y = nv3->pgraph.blit.point_in.y; + current_pos_out.x = nv3->pgraph.blit.point_out.x; + current_pos_out.y = nv3->pgraph.blit.point_out.y; + + for (uint32_t y = 0; y < nv3->pgraph.blit.size.y; y++) + { + current_pos_in.y = nv3->pgraph.blit.point_in.y + y; + current_pos_out.y = nv3->pgraph.blit.point_out.y + y; + + for (uint32_t x = 0; x < nv3->pgraph.blit.size.x; x++) + { + current_pos_in.x = nv3->pgraph.blit.point_in.x + x; + current_pos_out.x = nv3->pgraph.blit.point_out.x + x; + + uint32_t index = nv3_render_get_vram_address_for_buffer(current_pos_in, dst_buffer) >> 2; + uint32_t index_dst = nv3_render_get_vram_address_for_buffer(current_pos_out, src_buffer) >> 2; + + vram_32[index_dst] = vram_32[index]; + + //nv3_render_write_pixel(current_pos, vram_32[index], grobj); + } + + current_pos_in.x = nv3->pgraph.blit.point_in.x; + current_pos_out.x = nv3->pgraph.blit.point_out.x; + + } + } + */ +} + +void nv3_render_blit_screen2screen(nv3_grobj_t grobj) +{ + uint32_t dst_buffer = (nv3_pgraph_destination_buffer)grobj.grobj_0; // 5 = just use the source buffer + + if (dst_buffer & pgraph_dest_buffer0) + nv3_render_blit_screen2screen_for_buffer(grobj, 0); + if (dst_buffer & pgraph_dest_buffer1) + nv3_render_blit_screen2screen_for_buffer(grobj, 1); + if (dst_buffer & pgraph_dest_buffer2) + nv3_render_blit_screen2screen_for_buffer(grobj, 2); + if (dst_buffer & pgraph_dest_buffer3) + nv3_render_blit_screen2screen_for_buffer(grobj, 3); + + +} \ No newline at end of file diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c new file mode 100644 index 000000000..c40fa84a9 --- /dev/null +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -0,0 +1,869 @@ +/* +* 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 Core rendering code (Software version) +* +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 Connor Hyde +*/ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/plat.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> +#include <86box/utils/video_stdlib.h> + +/* Functions only used in this translation unit */ +void nv3_render_8bpp(uint32_t vram_start, nv3_coord_16_t screen_size); +void nv3_render_15bpp(uint32_t vram_start, nv3_coord_16_t screen_size); +void nv3_render_16bpp(uint32_t vram_start, nv3_coord_16_t screen_size); +void nv3_render_32bpp(uint32_t vram_start, nv3_coord_16_t screen_size); + +/* Expand a colour. + NOTE: THE GPU INTERNALLY OPERATES ON RGB10!!!!!!!!!!! +*/ +nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj) +{ + // grobj0 = seems to share the format of PGRAPH_CONTEXT_SWITCH register. + + uint8_t format = (grobj.grobj_0 & 0x07); + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; + + nv3_color_expanded_t color_final; + // set the pixel format + color_final.pixel_format = format; + + nv_log_verbose_only("Expanding Colour 0x%08x using pgraph_pixel_format 0x%x alpha enabled=%d\n", color, format, alpha_enabled); + + + // default to fully opaque in case alpha is disabled + color_final.a = 0xFF; + + switch (format) + { + // ALL OF THESE TYPES ARE 32 BITS IN SIZE + + // 555 + case nv3_pgraph_pixel_format_r5g5b5: + // "stretch out" the colour + + color_final.a = (color >> 15) & 0x01; // will be ignored if alpha_enabled isn't used + color_final.r = ((color >> 10) & 0x1F) << 5; + color_final.g = ((color >> 5) & 0x1F) << 5; + color_final.b = (color & 0x1F) << 5; + + break; + // 888 (standard colour + 8-bit alpha) + case nv3_pgraph_pixel_format_r8g8b8: + if (alpha_enabled) + color_final.a = ((color >> 24) & 0xFF) * 4; + + color_final.r = ((color >> 16) & 0xFF) * 4; + color_final.g = ((color >> 8) & 0xFF) * 4; + color_final.b = (color & 0xFF) * 4; + + break; + case nv3_pgraph_pixel_format_r10g10b10: + color_final.a = (color >> 31) & 0x01; + color_final.r = (color >> 30) & 0x3FF; + color_final.g = (color >> 20) & 0x1FF; + color_final.b = (color >> 10); + + break; + case nv3_pgraph_pixel_format_y8: + /* Indexed mode */ + color_final.a = (color >> 8) & 0xFF; + + // yuv + color_final.r = color_final.g = color_final.b = (color & 0xFF) * 4; // convert to rgb10 + break; + case nv3_pgraph_pixel_format_y16: + color_final.a = (color >> 16) & 0xFFFF; + + // yuv + color_final.r = color_final.g = color_final.b = (color & 0xFFFF) * 4; // convert to rgb10 + break; + case nv3_pgraph_pixel_format_y420: + warning("nv3_render_expand_color: YUV420 not implemented\n"); + break; + default: + warning("nv3_render_expand_color unknown format %d", format); + break; + + } + + // i8 is a union under i16 + color_final.i16 = (color & 0xFFFF); + + return color_final; +} + +/* Used for chroma test */ +uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t color) +{ + uint8_t format = (grobj.grobj_0 & 0x07); + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; + + nv_log_verbose_only("Downconverting Colour 0x%08x using pgraph_pixel_format 0x%x alpha enabled=%d\n", color, format, alpha_enabled); + + uint32_t packed_color = 0x00; + + switch (format) + { + case nv3_pgraph_pixel_format_r5g5b5: + packed_color = (color.r >> 5) << 10 | + (color.g >> 5) << 5 | + (color.b >> 5); + + break; + case nv3_pgraph_pixel_format_r8g8b8: + packed_color = (color.a) << 24 | // is this a thing? + (color.r >> 2) << 16 | + (color.g >> 2) << 8 | + color.b; + break; + case nv3_pgraph_pixel_format_r10g10b10: + /* sometimes alpha isn't used but we should incorporate it anyway */ + if (color.a > 0x00) packed_color |= (1 << 31); + + packed_color |= (color.r << 30); + packed_color |= (color.g << 20); + packed_color |= (color.b << 10); + break; + case nv3_pgraph_pixel_format_y8: /* i think this is just indexed mode. since r=g=b we can just take the indexed from the r */ + packed_color = nv3_render_get_palette_index((color.r >> 2) & 0xFF); + break; + case nv3_pgraph_pixel_format_y16: + warning("nv3_render_downconvert_color: Y16 not implemented"); + break; + case nv3_pgraph_pixel_format_y420: + warning("nv3_render_downconvert_color: YUV420 not implemented\n"); + break; + default: + warning("nv3_render_downconvert_color unknown format %d", format); + break; + + } + + return packed_color; +} + +/* Runs the chroma key/color key test */ +bool nv3_render_chroma_test(uint32_t color, nv3_grobj_t grobj) +{ + bool chroma_enabled = ((grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_CHROMA_KEY) & 0x01); + + if (!chroma_enabled) + return true; + + bool alpha = ((nv3->pgraph.chroma_key >> 31) & 0x01); + + if (!alpha) + return true; + + /* this is dumb but i'm lazy, if it kills perf, fix it later - we need to do some format shuffling */ + nv3_grobj_t grobj_fake = {0}; + grobj_fake.grobj_0 = 0x02; /* we don't care about any other bits */ + + nv3_color_expanded_t chroma_expanded = nv3_render_expand_color(nv3->pgraph.chroma_key, grobj_fake); + + uint32_t chroma_downconverted = nv3_render_downconvert_color(grobj, chroma_expanded); + + return !(chroma_downconverted == color); +} + +/* Convert expanded colour format to chroma key format */ +uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded) +{ + // convert the alpha to 1 bit. then return packed rgb10 + return !!expanded.a | (expanded.r << 30) | (expanded.g << 20) | (expanded.b << 10); +} + +/* Get a colour for a palette index. (The colours are 24 bit RGB888 with a 0xFF alpha added for some purposes.) */ +uint32_t nv3_render_get_palette_index(uint8_t index) +{ + uint32_t red_index = index * 3; + uint32_t green_index = red_index + 1; + uint32_t blue_index = red_index + 2; + + uint8_t red_colour = nv3->pramdac.palette[red_index]; + uint8_t green_colour = nv3->pramdac.palette[green_index]; + uint8_t blue_colour = nv3->pramdac.palette[blue_index]; + + /* Alpha is always 0xFF */ + return (0xFF << 24) | ((red_colour) << 16) | ((green_colour) << 8) | blue_colour; +} + +/* Convert a rgb10 colour to a pattern colour */ +void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1) +{ + /* select the right pattern colour, _rgb is already in RGB10 format, so we don't need to do any conversion */ + + if (!use_color1) + { + nv3->pgraph.pattern_color_0_alpha = (pattern_colour.a) & 0xFF; + nv3->pgraph.pattern_color_0_rgb.r = pattern_colour.r; + nv3->pgraph.pattern_color_0_rgb.g = pattern_colour.g; + nv3->pgraph.pattern_color_0_rgb.b = pattern_colour.b; + + } + else + { + nv3->pgraph.pattern_color_1_alpha = (pattern_colour.a) & 0xFF; + nv3->pgraph.pattern_color_1_rgb.r = pattern_colour.r; + nv3->pgraph.pattern_color_1_rgb.g = pattern_colour.g; + nv3->pgraph.pattern_color_1_rgb.b = pattern_colour.b; + } + +} + +/* Combine the current buffer with the pitch to get the address in the framebuffer to draw from for a given position. */ +uint32_t nv3_render_get_vram_address(nv3_coord_16_t position, nv3_grobj_t grobj) +{ + uint32_t vram_x = position.x; + uint32_t vram_y = position.y; + uint32_t current_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; + + uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; + + // we have to multiply the x position by the number of bytes per pixel + switch (framebuffer_bpp) + { + case 8: + break; + case 15: + case 16: + vram_x = position.x << 1; + break; + case 32: + vram_x = position.x << 2; + break; + } + + uint32_t pixel_addr_vram = vram_x + (nv3->pgraph.bpitch[current_buffer] * vram_y) + nv3->pgraph.boffset[current_buffer]; + + pixel_addr_vram &= nv3->nvbase.svga.vram_mask; + + return pixel_addr_vram; +} + + +/* Combine the current buffer with the pitch to get the address in the video ram for a specific position relative to a specific framebuffer */ +uint32_t nv3_render_get_vram_address_for_buffer(nv3_coord_16_t position, uint32_t buffer) +{ + uint32_t vram_x = position.x; + uint32_t vram_y = position.y; + + uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; + + // we have to multiply the x position by the number of bytes per pixel + switch (framebuffer_bpp) + { + case 8: + break; + case 15: + case 16: + vram_x = position.x << 1; + break; + case 32: + vram_x = position.x << 2; + break; + } + + uint32_t pixel_addr_vram = vram_x + (nv3->pgraph.bpitch[buffer] * vram_y) + nv3->pgraph.boffset[buffer]; + + pixel_addr_vram &= nv3->nvbase.svga.vram_mask; + + return pixel_addr_vram; +} + +/* Convert a dumb framebuffer address to a position. No buffer setup or anything, but just start at 0,0 for address 0. */ +nv3_coord_16_t nv3_render_get_dfb_position(uint32_t vram_address) +{ + nv3_coord_16_t pos = {0}; + + uint32_t pitch = nv3->nvbase.svga.hdisp; + + if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + pitch <<= 1; + else if (nv3->nvbase.svga.bpp == 32) + pitch <<= 2; + + pos.y = (vram_address / pitch); + pos.x = (vram_address % pitch); + + /* Fixup our x position */ + if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + pos.x >>= 1; + else if (nv3->nvbase.svga.bpp == 32) + pos.x >>= 2; + + + /* there is some strange behaviour where it writes long past the end of the fb */ + if (pos.y >= nv3->nvbase.svga.monitor->target_buffer->h) pos.y = nv3->nvbase.svga.monitor->target_buffer->h - 1; + + return pos; +} + +/* Read an 8bpp pixel from the framebuffer. */ +uint8_t nv3_render_read_pixel_8(nv3_coord_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + return nv3->nvbase.svga.vram[vram_address]; +} + +/* Read an 16bpp pixel from the framebuffer. */ +uint16_t nv3_render_read_pixel_16(nv3_coord_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + uint16_t* vram_16 = (uint16_t*)(nv3->nvbase.svga.vram); + vram_address >>= 1; //convert to 16bit pointer + + return vram_16[vram_address]; +} + +/* Read an 16bpp pixel from the framebuffer. */ +uint32_t nv3_render_read_pixel_32(nv3_coord_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + uint32_t* vram_32 = (uint32_t*)(nv3->nvbase.svga.vram); + vram_address >>= 2; //convert to 32bit pointer + + return vram_32[vram_address]; +} + +void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, nv3_grobj_t grobj, uint32_t buffer) +{ + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; + + int32_t clip_end_x = nv3->pgraph.clip_start.x + nv3->pgraph.clip_size.x; + int32_t clip_end_y = nv3->pgraph.clip_start.y + nv3->pgraph.clip_size.y; + + /* First, check our current buffer. */ + /* Then do the clip. */ + if (position.x < nv3->pgraph.clip_start.x + || position.y < nv3->pgraph.clip_start.y + || position.x > clip_end_x + || position.y > clip_end_y) + { + // DO NOT DRAW THE PIXEL + return; + } + + /* TODO: Plane Mask...*/ + if (!nv3_render_chroma_test(color, grobj)) + return; + + uint32_t pixel_addr_vram = nv3_render_get_vram_address_for_buffer(position, buffer); + + uint32_t rop_src = 0, rop_dst = 0, rop_pattern = 0; + uint8_t bit = 0x00; + + /* Get our pattern data, may move to another function */ + switch (nv3->pgraph.pattern.shape) + { + + /* This logic is from NV1 envytoos docs, but seems to be same on NV3*/ + case NV3_PATTERN_SHAPE_8X8: + bit = (position.x & 7) | (position.y & 7) << 3; + break; + case NV3_PATTERN_SHAPE_1X64: + bit = (position.x & 0x3f); + break; + case NV3_PATTERN_SHAPE_64X1: + bit = (position.y & 0x3f); + break; + } + + // pull out the actual bit and see which colour we need to use + + bool use_color1 = (nv3->pgraph.pattern_bitmap >> bit) & 0x01; + + if (!use_color1) + { + if (!nv3->pgraph.pattern_color_0_alpha) + return; + + /* This is stupid */ + rop_pattern = nv3_render_downconvert_color(grobj, nv3->pgraph.pattern_color_0_rgb); + } + else + { + if (!nv3->pgraph.pattern_color_1_alpha) + return; + + rop_pattern = nv3_render_downconvert_color(grobj, nv3->pgraph.pattern_color_1_rgb); + } + + + /* Go to vram and do the final ROP for a basic bitblit. + It seems we can skip the downconversion step *for now*, since (framebuffer bits per pixel) == (object bits per pixel) + I'm not sure how games will react. But it depends on how the D3D drivers operate, we may need ro convert texture formats to the current bpp internally. + + We use the pixel format of the destination buffer to achieve this (thanks frostbite2000) + */ + + // translate the patch config to GDI rop + uint32_t final_rop = nv3_render_translate_nvrop(grobj, nv3->pgraph.rop); + + uint32_t destination_format = (nv3->pgraph.bpixel[buffer]) & 0x03; + + switch (destination_format) + { + case bpixel_fmt_8bit: + rop_src = color & 0xFF; + rop_dst = nv3->nvbase.svga.vram[pixel_addr_vram]; + nv3->nvbase.svga.vram[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern) & 0xFF; + + nv3->nvbase.svga.changedvram[pixel_addr_vram >> 12] = changeframecount; + + break; + case bpixel_fmt_16bit: + { + uint16_t* vram_16 = (uint16_t*)(nv3->nvbase.svga.vram); + pixel_addr_vram >>= 1; + + // mask to 16bit + + rop_src = color & 0xFFFF; + + /* if alpha is turned on and we aren't in 565 mode, reject transparent pixels */ + bool is_16bpp = (nv3->pramdac.general_control >> NV3_PRAMDAC_GENERAL_CONTROL_565_MODE) & 0x01; + + // a1r5g5b5 + if (!is_16bpp) + { + if (alpha_enabled && + !(color & 0x8000)) + return; + } + + // convert to 15bpp or 16bpp based on if we are in 16bpp mode + + rop_dst = vram_16[pixel_addr_vram]; + + vram_16[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern) & 0xFFFF; + + nv3->nvbase.svga.changedvram[pixel_addr_vram >> 11] = changeframecount; + + break; + } + case bpixel_fmt_32bit: + { + uint32_t* vram_32 = (uint32_t*)(nv3->nvbase.svga.vram); + pixel_addr_vram >>= 2; + + rop_src = color; + rop_dst = vram_32[pixel_addr_vram]; + vram_32[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern); + + nv3->nvbase.svga.changedvram[pixel_addr_vram >> 10] = changeframecount; + + break; + } + } +} + +/* Plots a pixel. */ +void nv3_render_write_pixel(nv3_coord_16_t position, uint32_t color, nv3_grobj_t grobj) +{ + // PFB_0 is always set to hardcoded "NO_TILING" value of 0x1114. + // It seems, you are meant to use the CRTC + + nv3_pgraph_destination_buffer dst_buffer = (nv3_pgraph_destination_buffer)grobj.grobj_0; + + if (dst_buffer & (pgraph_dest_buffer0)) + nv3_render_write_pixel_to_buffer(position, color, grobj, 0); + if (dst_buffer & (pgraph_dest_buffer1)) + nv3_render_write_pixel_to_buffer(position, color, grobj, 1); + if (dst_buffer & (pgraph_dest_buffer2)) + nv3_render_write_pixel_to_buffer(position, color, grobj, 2); + if (dst_buffer & (pgraph_dest_buffer3)) + nv3_render_write_pixel_to_buffer(position, color, grobj, 3); +} + +/* Ensure the correct monitor size */ +void nv3_render_ensure_screen_size(void) +{ + /* First check if hdisp == xsize and dispend == ysize. */ + bool changed = false; + + if (nv3->nvbase.svga.hdisp != nv3->nvbase.svga.monitor->mon_xsize) + { + changed = true; + nv3->nvbase.svga.monitor->mon_xsize = nv3->nvbase.svga.hdisp; + } + + if (nv3->nvbase.svga.dispend != nv3->nvbase.svga.monitor->mon_ysize) + { + changed = true; + nv3->nvbase.svga.monitor->mon_ysize = nv3->nvbase.svga.dispend; + } + + /* + if either changed: + -> set resolution + -> set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes + */ + if (changed) + { + nv3->nvbase.refresh_time = 1 / (nv3->nvbase.pixel_clock_frequency / (double)ysize / (double)xsize); // rivatimers count in microseconds + set_screen_size(xsize, ysize); + } + +} + + +/* Blit to the monitor from DFB, 8bpp */ +void nv3_render_current_bpp_dfb_8(uint32_t address) +{ + /* Broken as fuck early vbios does this. Wtf? */ + if (!nv3->nvbase.svga.hdisp) + return; + + nv3_coord_16_t size = {0}; + size.x = size.y = 1; + + nv3_coord_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + *p = nv3_render_get_palette_index(data & 0xFF); +} + +/* Blit to the monitor from DFB, 15/16bpp */ +void nv3_render_current_bpp_dfb_16(uint32_t address) +{ + /* Broken as fuck early vbios does this. Wtf? */ + if (!nv3->nvbase.svga.hdisp) + return; + + nv3_coord_16_t size = {0}; + size.x = size.y = 1; + + nv3_coord_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + if ((nv3->pramdac.general_control >> NV3_PRAMDAC_GENERAL_CONTROL_565_MODE) & 0x01) + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 16); + else + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + /*does 8bpp packed into 16 occur/ i would be surprised*/ +} + +/* Blit to the monitor from DFB, 32bpp */ +void nv3_render_current_bpp_dfb_32(uint32_t address) +{ + /* Broken as fuck early vbios does this. Wtf? */ + if (!nv3->nvbase.svga.hdisp) + return; + + nv3_coord_16_t size = {0}; + size.x = size.y = 1; + + nv3_coord_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + + if (nv3->nvbase.svga.bpp == 32) + { + *p = data; + } + /* Packed format */ + else if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + { + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, nv3->nvbase.svga.bpp); + *p++; + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, (data >> 16) & 0xFFFF, nv3->nvbase.svga.bpp); + } +} + + +/* Blit to the monitor from GPU, current bpp */ +void nv3_render_current_bpp() +{ + /* Figure out the Display Buffer Address from the CRTC */ + + uint32_t dba = ((nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_RPC0] & 0x1F) << 16) + + (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_STARTADDR_HIGH] << 8) + + nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_STARTADDR_LOW]; + + if (nv3->nvbase.debug_dba_enabled + && nv3->nvbase.debug_dba > 0) + dba = nv3->nvbase.debug_dba; + + nv3_coord_16_t screen_size = {0}; + screen_size.x = nv3->nvbase.svga.hdisp; + screen_size.y = nv3->nvbase.svga.dispend; + + /* Ensure that we are + in the correct mode. Modified SVGA core code */ + nv3_render_ensure_screen_size(); + + /* Don't try and draw stuff that is past the buffer, but, leave it in Video RAM, so it can be used for s2sb's etc */ + + switch (nv3->nvbase.svga.bpp) + { + case 4: + /* Uh we should never be here because we're in the SVGA mode(?) */ + fatal("NV3 - 4bpp not implemented (not even sure if it's SVGA only)"); + break; + case 8: + nv3_render_8bpp(dba, screen_size); + break; + case 15: + nv3_render_15bpp(dba, screen_size); + break; + case 16: + nv3_render_16bpp(dba, screen_size); + break; + case 32: + nv3_render_32bpp(dba, screen_size); + break; + } + +} + +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, indexed 8 bits per pixel format +*/ + +void nv3_render_8bpp(uint32_t vram_start, nv3_coord_16_t screen_size) +{ + if (!nv3) + return; + + uint32_t vram_current_position = vram_start; + uint32_t* p; + uint32_t data = 0; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[0][0]; + + for (uint32_t y = 0; y < screen_size.y; y++) + { + for (uint32_t x = 0; x < screen_size.x; x++) + { + if (vram_current_position >= nv3->nvbase.vram_amount) + return; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[y][x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_current_position]; + + /* should just "tip over" to the next line */ + *p = nv3_render_get_palette_index(data & 0xFF); + + vram_current_position++; + } + } +} + +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 15 bits per pixel format +*/ + +void nv3_render_15bpp(uint32_t vram_start, nv3_coord_16_t screen_size) +{ + if (!nv3) + return; + + uint32_t vram_current_position = vram_start; + uint32_t* p; + uint32_t data = 0; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[0][0]; + + for (uint32_t y = 0; y < screen_size.y; y++) + { + for (uint32_t x = 0; x < screen_size.x; x++) + { + if (vram_current_position >= nv3->nvbase.vram_amount) + return; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[y][x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_current_position]; + + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + vram_current_position += 2; + } + + } +} + +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 16 bits per pixel format +*/ + +void nv3_render_16bpp(uint32_t vram_start, nv3_coord_16_t screen_size) +{ + if (!nv3) + return; + + uint32_t vram_current_position = vram_start; + uint32_t* p; + uint32_t data = 0; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[0][0]; + + for (uint32_t y = 0; y < screen_size.y; y++) + { + for (uint32_t x = 0; x < screen_size.x; x++) + { + if (vram_current_position >= nv3->nvbase.vram_amount) + return; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[y][x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_current_position]; + + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + vram_current_position += 2; + + } + + } +} + +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 32 bits per pixel format +*/ + +void nv3_render_32bpp(uint32_t vram_start, nv3_coord_16_t screen_size) +{ + if (!nv3) + return; + + uint32_t vram_current_position = vram_start; + uint32_t* p; + uint32_t data = 0; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[0][0]; + + for (uint32_t y = 0; y < screen_size.y; y++) + { + for (uint32_t x = 0; x < screen_size.x; x++) + { + if (vram_current_position >= nv3->nvbase.vram_amount) + return; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[y][x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_current_position]; + + /* should just "tip over" to the next line */ + *p = data; + + vram_current_position += 4; + } + } +} + +// Translate an "NV-ROP" into a GDI Ternary ROP +uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop) +{ + // Credit to envytools for this function: + // https://github.com/envytools/envytools/blob/f102b82381f3f11cee113d16374c87091db039d9/nvhw/pgraph.c + // How does one even go about reverse engineering this (I'm sure the behaviour is simpler when you don't have to translate this but...) Marcelina is a legend. + + uint32_t patch_config_rop = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG) & 0x1F; + + /* || patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0*/ + + // TODO: Blending + if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS) // 0x00 is used for "nothing here" it seems. + return VIDEO_ROP_SRC_COPY; + + uint8_t res = 0; + + int32_t swizzle[3]; + + if (patch_config_rop < 8) { + swizzle[0] = patch_config_rop >> 0 & 1; + swizzle[1] = patch_config_rop >> 1 & 1; + swizzle[2] = patch_config_rop >> 2 & 1; + } else if (patch_config_rop < 0x10) { + swizzle[0] = (patch_config_rop >> 0 & 1) + 1; + swizzle[1] = (patch_config_rop >> 1 & 1) + 1; + swizzle[2] = (patch_config_rop >> 2 & 1) + 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST) { + swizzle[0] = 0, swizzle[1] = 1, swizzle[2] = 2; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_DST_SRC) { + swizzle[0] = 1, swizzle[1] = 0, swizzle[2] = 2; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_DST) { + swizzle[0] = 0, swizzle[1] = 2, swizzle[2] = 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_PAT) { + swizzle[0] = 2, swizzle[1] = 0, swizzle[2] = 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_PAT_SRC) { + swizzle[0] = 1, swizzle[1] = 2, swizzle[2] = 0; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_PAT) { + swizzle[0] = 2, swizzle[1] = 1, swizzle[2] = 0; + } else { + warning("NV3 ROP: Invalid patch configuration %02x!", rop); + } + if (patch_config_rop == 0) { + if (rop & 0x01) + res |= 0x11; + if (rop & 0x16) + res |= 0x44; + if (rop & 0x68) + res |= 0x22; + if (rop & 0x80) + res |= 0x88; + } else if (patch_config_rop == 0xf) { + if (rop & 0x01) + res |= 0x03; + if (rop & 0x16) + res |= 0x0c; + if (rop & 0x68) + res |= 0x30; + if (rop & 0x80) + res |= 0xc0; + } else { + int32_t i; + for (i = 0; i < 8; i++) { + int32_t s0 = i >> swizzle[0] & 1; + int32_t s1 = i >> swizzle[1] & 1; + int32_t s2 = i >> swizzle[2] & 1; + int32_t s = s2 << 2 | s1 << 1 | s0; + if (rop >> s & 1) + res |= 1 << i; + } + } + + return res; +} \ No newline at end of file diff --git a/src/video/nv/nv3/render/nv3_render_primitives.c b/src/video/nv/nv3/render/nv3_render_primitives.c new file mode 100644 index 000000000..e2d088c3f --- /dev/null +++ b/src/video/nv/nv3/render/nv3_render_primitives.c @@ -0,0 +1,355 @@ +/* +* 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 code to render basic objects. +* +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 Connor Hyde +*/ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> +#include <86box/utils/video_stdlib.h> + +void nv3_render_rect(nv3_coord_16_t position, nv3_coord_16_t size, uint32_t color, nv3_grobj_t grobj) +{ + nv3_coord_16_t current_pos = {0}; + + for (int32_t y = position.y; y < (position.y + size.y); y++) + { + current_pos.y = y; + + for (int32_t x = position.x; x < (position.x + size.x); x++) + { + current_pos.x = x; + + nv3_render_write_pixel(current_pos, color, grobj); + } + } +} + +/* Render GDI-B clipped rectangle */ +void nv3_render_rect_clipped(nv3_clip_16_t clip, uint32_t color, nv3_grobj_t grobj) +{ + nv3_coord_16_t current_pos = {0}; + + for (int32_t y = clip.top; y < clip.bottom; y++) + { + current_pos.y = y; + + for (int32_t x = clip.left; x < clip.right; x++) + { + current_pos.x = x; + + /* compare against the global clip too */ + if (current_pos.x >= nv3->pgraph.win95_gdi_text.clip_b.left + && current_pos.x <= nv3->pgraph.win95_gdi_text.clip_b.right + && current_pos.y >= nv3->pgraph.win95_gdi_text.clip_b.top + && current_pos.y <= nv3->pgraph.win95_gdi_text.clip_b.bottom) + { + nv3_render_write_pixel(current_pos, color, grobj); + } + } + } +} + +void nv3_render_gdi_transparent_bitmap_blit(bool bit, bool clip, uint32_t color, nv3_grobj_t grobj) +{ + /* If the bit is set, and cliping is enabled (Type D) tru and lcip */ + if (bit && clip) + { + /* Turn the bit off if we need to clip (Type D ) */ + if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_d.left + || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_d.right + || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_d.top + || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_d.bottom) + { + bit = false; + } + + /* + Also clip if we are outside of the SIZE_OUT range + We only need to do this in one direction just to get rid of the crud sent by NV + */ + uint32_t clip_x = nv3->pgraph.win95_gdi_text.point_d.x + (nv3->pgraph.win95_gdi_text.size_out_d.x); + uint32_t clip_y = nv3->pgraph.win95_gdi_text.point_d.y + (nv3->pgraph.win95_gdi_text.size_out_d.y); + + if (nv3->pgraph.win95_gdi_text_current_position.x >= clip_x + || nv3->pgraph.win95_gdi_text_current_position.y >= clip_y) + bit = false; + } + + /* We don't need to and it, because it seems the Riva only uses non-packed bpp formats for this class */ + if (bit) + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, color, grobj); + + /* + Check if we've reached the bottom + Because we check the bits in reverse, we go forward (bits 7,6,5 were set for a 1x3 bitmap) + */ + + uint32_t end_x = (clip) ? nv3->pgraph.win95_gdi_text.point_d.x + nv3->pgraph.win95_gdi_text.size_in_d.x : nv3->pgraph.win95_gdi_text.point_c.x + nv3->pgraph.win95_gdi_text.size_c.x; + + nv3->pgraph.win95_gdi_text_current_position.x++; + + if (nv3->pgraph.win95_gdi_text_current_position.x >= end_x) + { + nv3->pgraph.win95_gdi_text_current_position.y++; + + if (!clip) + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_c.x; + else + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_d.x; + } + +} + +/* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ +void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitmap_data, nv3_grobj_t grobj) +{ + /* + First, we need to figure out how many bits we have left. + If we have less than 32, don't process all of the bits. + + Bits are processed in the following order: [7-0] [15-8] [23-16] [31-24] + TODO: Store this somewhere, so it doesn't need to be recalculated. + + We store a global bit count for this purpose. + */ + + uint32_t bitmap_size = (clip) ? nv3->pgraph.win95_gdi_text.size_in_d.x * nv3->pgraph.win95_gdi_text.size_in_d.y : nv3->pgraph.win95_gdi_text.size_c.x * nv3->pgraph.win95_gdi_text.size_c.y; + uint32_t bits_remaining_in_bitmap = bitmap_size - nv3->pgraph.win95_gdi_text_bit_count; + + /* we have to interpret every bit in reverse bit order but in the right byte order */ + + bool current_bit = false; + + /* Start by rendering bits 7 through 0 */ + for (int32_t bit = 7; bit >= 0; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 15 through 8 */ + for (int32_t bit = 15; bit >= 8; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 23 through 16 */ + for (int32_t bit = 23; bit >= 16; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 31 through 24 */ + for (int32_t bit = 31; bit >= 24; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + +} + +void nv3_render_gdi_1bpp_bitmap_blit(bool bit, uint32_t color0, uint32_t color1, nv3_grobj_t grobj) +{ + /* We can't force the bit off because this is a 1bpp bitmap */ + bool skip = false; + + /* For Type E, always clip */ + /* Turn the bit off if we need to clip (Type D ) */ + if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_e.left + || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_e.right + || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_e.top + || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_e.bottom) + { + skip = true; + } + + /* + Also clip if we are outside of the SIZE_OUT range + We only need to do this in one direction just to get rid of the crud sent by NV + */ + uint32_t clip_x = nv3->pgraph.win95_gdi_text.point_e.x + (nv3->pgraph.win95_gdi_text.size_out_e.x); + uint32_t clip_y = nv3->pgraph.win95_gdi_text.point_e.y + (nv3->pgraph.win95_gdi_text.size_out_e.y); + + if (nv3->pgraph.win95_gdi_text_current_position.x >= clip_x + || nv3->pgraph.win95_gdi_text_current_position.y >= clip_y) + skip = true; + + /* We don't need to and it, because it seems the Riva only uses non-packed bpp formats for this class */ + if (!skip) + { + if (bit) + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, nv3->pgraph.win95_gdi_text.color1_e, grobj); + else + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, nv3->pgraph.win95_gdi_text.color0_e, grobj); + } + + + /* + Check if we've reached the bottom, if so, advance to the next horizontal lin + Because we check the bits in reverse, we go forward (bits 7,6,5 were set for a 1x3 bitmap) + */ + + uint32_t end_x = nv3->pgraph.win95_gdi_text.point_e.x + nv3->pgraph.win95_gdi_text.size_in_e.x; + + nv3->pgraph.win95_gdi_text_current_position.x++; + + if (nv3->pgraph.win95_gdi_text_current_position.x >= end_x) + { + nv3->pgraph.win95_gdi_text_current_position.y++; + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_e.x; + } +} + + +/* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ +void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj) +{ + /* + First, we need to figure out how many bits we have left. + If we have less than 32, don't process all of the bits. + + Bits are processed in the following order: [7-0] [15-8] [23-16] [31-24] + TODO: Store this somewhere, so it doesn't need to be recalculated. + + We store a global bit count for this purpose. + */ + + uint32_t bitmap_size = nv3->pgraph.win95_gdi_text.size_in_e.x * nv3->pgraph.win95_gdi_text.size_in_e.y; + uint32_t bits_remaining_in_bitmap = bitmap_size - nv3->pgraph.win95_gdi_text_bit_count; + + /* we have to interpret every bit in reverse bit order but in the right byte order */ + + bool current_bit = false; + + /* Start by rendering bits 7 through 0 */ + for (int32_t bit = 7; bit >= 0; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 15 through 8 */ + for (int32_t bit = 15; bit >= 8; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 23 through 16 */ + for (int32_t bit = 23; bit >= 16; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 31 through 24 */ + for (int32_t bit = 31; bit >= 24; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pbus.c b/src/video/nv/nv3/subsystems/nv3_pbus.c new file mode 100644 index 000000000..a2e340e85 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pbus.c @@ -0,0 +1,255 @@ +/* + * 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, I need a better email dataess ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +// 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_DEBUG_0, "PBUS - Debug Register", NULL, NULL}, + { 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(void) +{ + nv_log("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])); + + uint32_t ret = 0x00; + + // todo: friendly logging + + nv_log_verbose_only("PBUS Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + switch (reg->address) + { + case NV3_PBUS_DEBUG_0: + ret = nv3->pbus.debug_0; + break; + case NV3_PBUS_INTR: + ret = nv3->pbus.interrupt_status; + break; + case NV3_PBUS_INTR_EN: + ret = nv3->pbus.interrupt_enable; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PBUS Write 0x%08x -> 0x%08x\n", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + // on-read function + if (reg->on_write) + reg->on_write(value); + else + { + switch (reg->address) + { + case NV3_PBUS_DEBUG_0: + nv3->pbus.debug_0 = value; + break; + // 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; + } + + } + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} + +uint8_t nv3_pbus_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 = 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 + { + /* Do we need to read RAMIN here? */ + ret = nv3->nvbase.svga.vram[real_final_address - NV3_MMIO_SIZE] & (nv3->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 nv3_pbus_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 + 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_verbose_only("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? + { + uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; + vram_32[(nv3->pbus.rma.addr - NV3_MMIO_SIZE) >> 2] = nv3->pbus.rma.data; + } + + + break; + } + } + + if (addr & 0x10) + nv3->pbus.rma.addr += 0x04; // Alignment +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c new file mode 100644 index 000000000..3359e9079 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c @@ -0,0 +1,274 @@ +/* + * 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 & Notifier Engine + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.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> + +/* Nvidia DMA Engine */ + +void nv3_perform_dma_m2mf(nv3_grobj_t grobj) +{ + // notify object base=grobj_1 >> 12 + uint32_t notify_obj_base = grobj.grobj_1 >> 12; + + uint32_t notify_obj_info = nv3_ramin_read32(notify_obj_base, nv3); + uint32_t notify_obj_limit = nv3_ramin_read32(notify_obj_base + 0x04, nv3); + uint32_t notify_obj_page = nv3_ramin_read32(notify_obj_base + 0x08, nv3); + + /* extract some important information*/ + uint32_t info_adjust = notify_obj_info & 0xFFF; + bool info_pt_present = (notify_obj_info >> NV3_NOTIFICATION_PT_PRESENT) & 0x01; + uint8_t info_dma_target = (notify_obj_info >> NV3_NOTIFICATION_TARGET) & 0x03; + + /* paging information */ + bool page_is_present = notify_obj_page & 0x01; + bool page_is_readwrite = (notify_obj_page >> NV3_NOTIFICATION_PAGE_ACCESS); + uint32_t frame_base = notify_obj_page & 0xFFFFF000; + + // This code is temporary and will probably be moved somewhere else + // Print torns of debug info + #ifdef DEBUG + nv_log_verbose_only("******* WARNING: IF THIS OPERATION FUCKS UP, RANDOM MEMORY WILL BE CORRUPTED, YOUR ENTIRE SYSTEM MAY BE HOSED *******\n"); + + nv_log_verbose_only("M2MF DMA Information:\n"); + nv_log_verbose_only("Adjust Value: 0x%08x\n", info_adjust); + (info_pt_present) ? nv_log_verbose_only("Pagetable Present: True\n") : nv_log_verbose_only("Pagetable Present: False\n"); + + switch (info_dma_target) + { + case NV3_DMA_TARGET_NODE_VRAM: + nv_log_verbose_only("Notification Target: VRAM\n"); + break; + case NV3_DMA_TARGET_NODE_CART: + nv_log_verbose_only("VERY BAD WARNING: Notification detected with Notification Target: Cartridge. THIS SHOULD NEVER HAPPEN!!!!!\n"); + break; + case NV3_DMA_TARGET_NODE_PCI: + (nv3->nvbase.bus_generation == nv_bus_pci) ? nv_log_verbose_only("Notification Target: PCI Bus\n") : nv_log_verbose_only("Notification Target: PCI Bus (On AGP card?)\n"); + break; + case NV3_DMA_TARGET_NODE_AGP: + (nv3->nvbase.bus_generation == nv_bus_agp_1x + || nv3->nvbase.bus_generation == nv_bus_agp_2x) ? nv_log_verbose_only("Notification Target: AGP Bus\n") : nv_log_verbose_only("Notification Target: AGP Bus (On PCI card?)\n"); + break; + } + + nv_log_verbose_only("Limit: 0x%08x\n", notify_obj_limit); + (page_is_present) ? nv_log_verbose_only("Page is present\n") : nv_log_verbose_only("Page is not present\n"); + (page_is_readwrite) ? nv_log_verbose_only("Page is read-write\n") : nv_log_verbose_only("Page is read-only\n"); + nv_log_verbose_only("Pageframe Address: 0x%08x\n", frame_base); + #endif + + // set up the dma transfer. we need to translate to a physical address. + + uint32_t final_address = 0; + + /* M2MF DMA only uses HW type */ + + final_address = frame_base + info_adjust; + + /* send the notification off */ + nv_log("About to send M2MF DMA to 0x%08x (Check target)\n", final_address); + + uint32_t offset_in = (nv3->pgraph.m2mf.offset_in); + uint32_t offset_out = (nv3->pgraph.m2mf.offset_out); + + uint32_t pitch_in = nv3->pgraph.m2mf.pitch_in; + uint32_t pitch_out = nv3->pgraph.m2mf.pitch_out; + + // pitch out surely can't be 0 + if (pitch_out == 0) + pitch_out = pitch_in; + + uint32_t bytes_per_scanline = nv3->pgraph.m2mf.scanline_length; + + uint8_t increment_in = (nv3->pgraph.m2mf.format) & 0x07; + uint8_t increment_out = (nv3->pgraph.m2mf.format >> NV3_M2MF_FORMAT_INPUT) & 0x07; + + for (uint32_t scanline = 0; scanline < nv3->pgraph.m2mf.num_scanlines; scanline++) + { + for (uint32_t pixel = offset_in; pixel < (offset_in + bytes_per_scanline); pixel += increment_in) + { + nv3->nvbase.svga.vram[offset_out] = nv3->nvbase.svga.vram[offset_in]; + offset_out += increment_out; + } + + offset_in += pitch_in; + offset_out += pitch_out; + } + + /* + switch (info_dma_target) + { + // for M2MF only NVM target node is used. + + case NV3_DMA_TARGET_NODE_VRAM: + + + uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; + + break; + case NV3_DMA_TARGET_NODE_PCI: + case NV3_DMA_TARGET_NODE_AGP: + // Idk how to implement increments of more than 1 but only 1 increments seem to be used with these. + uint32_t size_in = nv3->pgraph.m2mf.num_scanlines * nv3->pgraph.m2mf.pitch_in; + uint32_t size_out = nv3->pgraph.m2mf.num_scanlines * nv3->pgraph.m2mf.pitch_out; + + uint8_t* page_in = calloc(1, size_in); + + for (uint32_t scanline = 0; scanline < nv3->pgraph.m2mf.num_scanlines; scanline++) + { + + } + + dma_bm_read(offset_in, page_in, size_in, size_in); + dma_bm_write(offset_out, page_in, size_out, size_out); + + break; + } +*/ + // we're done + nv3->pgraph.notify_pending = false; +} + + +/* Sees if any notification is required after an object method is executed. If so, executes it... */ +void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) +{ + if (!nv3->pgraph.notify_pending) + return; + + uint32_t current_notification_object = nv3->pgraph.notifier; + uint32_t notification_type = ((current_notification_object >> NV3_PGRAPH_NOTIFY_REQUEST_TYPE) & 0x07); + + // check for a software method (0 = hardware, 1 = software) + if (notification_type != 0) + { + nv_log("Software Notification, firing interrupt"); + nv3_pgraph_interrupt_valid(NV3_PGRAPH_INTR_0_SOFTWARE_NOTIFY); + //return; + } + + // set up the NvNotification structure + nv3_notification_t notify = {0}; + notify.nanoseconds = nv3->ptimer.time; + notify.status = NV3_NOTIFICATION_STATUS_DONE_OK; // it should be fine to just signal that it's ok + + // these are only nonzero when there is an error + notify.info32 = notify.info16 = 0; + + // notify object base=grobj_1 >> 12 + uint32_t notify_obj_base = grobj.grobj_1 >> 12; + + uint32_t notify_obj_info = nv3_ramin_read32(notify_obj_base, nv3); + uint32_t notify_obj_limit = nv3_ramin_read32(notify_obj_base + 0x04, nv3); + uint32_t notify_obj_page = nv3_ramin_read32(notify_obj_base + 0x08, nv3); + + /* extract some important information*/ + uint32_t info_adjust = notify_obj_info & 0xFFF; + bool info_pt_present = (notify_obj_info >> NV3_NOTIFICATION_PT_PRESENT) & 0x01; + uint8_t info_notification_target = (notify_obj_info >> NV3_NOTIFICATION_TARGET) & 0x03; + + /* paging information */ + bool page_is_present = notify_obj_page & 0x01; + bool page_is_readwrite = (notify_obj_page >> NV3_NOTIFICATION_PAGE_ACCESS); + uint32_t frame_base = notify_obj_page & 0xFFFFF000; + + // This code is temporary and will probably be moved somewhere else + // Print torns of debug info + #ifdef DEBUG + nv_log_verbose_only("******* WARNING: IF THIS OPERATION FUCKS UP, RANDOM MEMORY WILL BE CORRUPTED, YOUR ENTIRE SYSTEM MAY BE HOSED *******\n"); + + nv_log_verbose_only("Notification Information:\n"); + nv_log_verbose_only("Adjust Value: 0x%08x\n", info_adjust); + (info_pt_present) ? nv_log_verbose_only("Pagetable Present: True\n") : nv_log_verbose_only("Pagetable Present: False\n"); + + switch (info_notification_target) + { + case NV3_DMA_TARGET_NODE_VRAM: + nv_log_verbose_only("Notification Target: VRAM\n"); + break; + case NV3_DMA_TARGET_NODE_CART: + nv_log_verbose_only("VERY BAD WARNING: Notification detected with Notification Target: Cartridge. THIS SHOULD NEVER HAPPEN!!!!!\n"); + break; + case NV3_DMA_TARGET_NODE_PCI: + (nv3->nvbase.bus_generation == nv_bus_pci) ? nv_log_verbose_only("Notification Target: PCI Bus\n") : nv_log_verbose_only("Notification Target: PCI Bus (On AGP card?)\n"); + break; + case NV3_DMA_TARGET_NODE_AGP: + (nv3->nvbase.bus_generation == nv_bus_agp_1x + || nv3->nvbase.bus_generation == nv_bus_agp_2x) ? nv_log_verbose_only("Notification Target: AGP Bus\n") : nv_log_verbose_only("Notification Target: AGP Bus (On PCI card?)\n"); + break; + } + + nv_log_verbose_only("Limit: 0x%08x\n", notify_obj_limit); + (page_is_present) ? nv_log_verbose_only("Page is present\n") : nv_log_verbose_only("Page is not present\n"); + (page_is_readwrite) ? nv_log_verbose_only("Page is read-write\n") : nv_log_verbose_only("Page is read-only\n"); + nv_log_verbose_only("Pageframe Address: 0x%08x\n", frame_base); + #endif + + // set up the dma transfer. we need to translate to a physical address. + + uint32_t final_address = 0; + + /* Simple case: hardware notification, we can just take the pte since it's based on the type */ + if (notification_type == 0) + { + final_address = frame_base + info_adjust; + } + else + { + // for software we have to calculate the pte index + uint32_t pte_num = ((notification_type << 4) + info_adjust) >> 12; + + /* ramin entries are sorted - 1 object for each pte entry...*/ + final_address = nv3_ramin_read32(notify_obj_base + (0x10 * pte_num) + 8, nv3); + final_address += (info_adjust & 0xFFF); + } + + /* send the notification off */ + nv_log("About to send hardware notification to 0x%08x (Check target)\n", final_address); + + switch (info_notification_target) + { + case NV3_DMA_TARGET_NODE_VRAM: + + uint32_t* vram_32 = (uint32_t*)nv3->nvbase.svga.vram; + + // increment by 1 because each index increments by 4 + vram_32[final_address] = (notify.nanoseconds & 0xFFFFFFFF); + vram_32[final_address + 1] = (notify.nanoseconds >> 32); + vram_32[final_address + 2] = notify.info32; + vram_32[final_address + 3] = (notify.info16 | notify.status); + break; + case NV3_DMA_TARGET_NODE_PCI: + case NV3_DMA_TARGET_NODE_AGP: + dma_bm_write(final_address, (uint8_t*)¬ify, sizeof(nv3_notification_t), 4); + break; + } + + // we're done + nv3->pgraph.notify_pending = false; +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pextdev.c b/src/video/nv/nv3/subsystems/nv3_pextdev.c new file mode 100644 index 000000000..c89d540c3 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pextdev.c @@ -0,0 +1,161 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_pextdev_init(void) +{ + nv_log("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("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("Straps = 0x%04x\n", nv3->pextdev.straps); + nv_log("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])); + + uint32_t ret = 0x00; + + // special consideration for straps + if (address == NV3_PSTRAPS) + { + nv_log_verbose_only("Straps Read (current value=0x%08x)\n", nv3->pextdev.straps); + } + else + { + nv_log_verbose_only("PEXTDEV Read from 0x%08x", address); + } + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + switch (reg->address) + { + case NV3_PSTRAPS: + ret = nv3->pextdev.straps; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PEXTDEV Write 0x%08x -> 0x%08x\n", value, address); + + // special consideration for straps + if (address == NV3_PSTRAPS) + { + /* For some reason, all RIVA 128 ZX VBIOSes try to write to the straps. So only indicate this as a problem and return on Rev A/B */ + if (nv3->nvbase.gpu_revision != NV3_PCI_CFG_REVISION_C00) + { + warning("Huh? Tried to write to the straps (value=%d). Something is wrong...\n", nv3->pextdev.straps); + return; + } + } + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + // on-read function + if (reg->on_write) + reg->on_write(value); + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pfb.c b/src/video/nv/nv3/subsystems/nv3_pfb.c new file mode 100644 index 000000000..7360a2c9a --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pfb.c @@ -0,0 +1,204 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +// Functions only used in this translation unit +uint32_t nv3_pfb_config0_read(void); +void nv3_pfb_config0_write(uint32_t val); + +nv_register_t pfb_registers[] = { + { NV3_PFB_BOOT, "PFB Boot Config", NULL, NULL}, + { NV3_PFB_DELAY, "PFB Delay", NULL, NULL}, + { NV3_PFB_DEBUG_0, "PFB Debug", NULL, NULL }, + { NV3_PFB_GREEN_0, "PFB Green / Power Saving", NULL, NULL,}, + { NV3_PFB_CONFIG_0, "PFB Framebuffer Config 0", nv3_pfb_config0_read, nv3_pfb_config0_write }, + { NV3_PFB_CONFIG_1, "PFB Framebuffer Config 1", NULL, NULL }, + { NV3_PFB_RTL, "PFB RTL (Part of memory timings)", NULL, NULL }, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +void nv3_pfb_init(void) +{ + nv_log("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) + ); + + if (nv3->nvbase.vram_amount == NV3_VRAM_SIZE_4MB) + nv3->pfb.boot |= (NV3_PFB_BOOT_RAM_AMOUNT_4MB << NV3_PFB_BOOT_RAM_AMOUNT); + else + nv3->pfb.boot |= (NV3_PFB_BOOT_RAM_AMOUNT_8MB << 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])); + + uint32_t ret = 0x00; + + // todo: friendly logging + + nv_log_verbose_only("PFB Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + switch (reg->address) + { + case NV3_PFB_BOOT: + ret = nv3->pfb.boot; + break; + case NV3_PFB_DEBUG_0: + ret = nv3->pfb.debug_0; + break; + // Config 0 has a read/write function + case NV3_PFB_CONFIG_1: + ret = nv3->pfb.config_1; + break; + case NV3_PFB_GREEN_0: + ret = nv3->pfb.green; + break; + case NV3_PFB_DELAY: + ret = nv3->pfb.delay; + break; + case NV3_PFB_RTL: + ret = nv3->pfb.rtl; + break; + + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PFB Write 0x%08x -> 0x%08x", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + // on-read function + if (reg->on_write) + reg->on_write(value); + else + { + switch (reg->address) + { + // Boot is read only + case NV3_PFB_DEBUG_0: + nv3->pfb.debug_0 = value; + break; + // Config 0 has a read/write function + case NV3_PFB_CONFIG_1: // Config Register 1 + nv3->pfb.config_1 = value; + break; + case NV3_PFB_GREEN_0: + nv3->pfb.green = value; + break; + case NV3_PFB_DELAY: + nv3->pfb.delay = value; + break; + case NV3_PFB_RTL: + nv3->pfb.rtl = value; + break; + } + } + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} + +uint32_t nv3_pfb_config0_read(void) +{ + return nv3->pfb.config_0; +} + +void nv3_pfb_config0_write(uint32_t val) +{ + nv3->pfb.config_0 = val; + + // i think the actual size and pixel depth are set in PRAMDAC + // so we don't update things here for now + + uint32_t new_pfb_htotal = (nv3->pfb.config_0 & 0x3F) << 5; + // i don't think 16:9 is supported + uint32_t new_pfb_vtotal = new_pfb_htotal * (3.0/4.0); + uint32_t new_bit_depth = (nv3->pfb.config_0 >> 8) & 0x03; + + + // This doesn't actually seem very useful + + nv_log_verbose_only("Framebuffer Config Change\n"); + nv_log_verbose_only("Horizontal Size=%d pixels\n", new_pfb_htotal); + nv_log_verbose_only("Vertical Size @ 4:3=%d pixels\n", new_pfb_vtotal); + + if (new_bit_depth == NV3_PFB_CONFIG_0_DEPTH_8BPP) + nv_log_verbose_only("Bit Depth=8bpp\n"); + else if (new_bit_depth == NV3_PFB_CONFIG_0_DEPTH_16BPP) + nv_log_verbose_only("Bit Depth=16bpp\n"); + else if (new_bit_depth == NV3_PFB_CONFIG_0_DEPTH_32BPP) + nv_log_verbose_only("Bit Depth=32bpp\n"); + +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c new file mode 100644 index 000000000..9ddcda0d3 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -0,0 +1,985 @@ +/* + * 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) + * PIO object submission + * Gray code conversion routines + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.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> + +// +// ****** 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,}, + { NV3_PFIFO_DELAY_0, "PFIFO - DMA Delay/Retry Register", NULL, NULL}, + { NV3_PFIFO_DEBUG_0, "PFIFO - Debug 0", NULL, NULL, }, + { NV3_PFIFO_CONFIG_0, "PFIFO - Config 0", NULL, NULL, }, + { NV3_PFIFO_CONFIG_RAMFC, "PFIFO - RAMIN RAMFC Config", NULL, NULL }, + { NV3_PFIFO_CONFIG_RAMHT, "PFIFO - RAMIN RAMHT Config", NULL, NULL }, + { NV3_PFIFO_CONFIG_RAMRO, "PFIFO - RAMIN RAMRO Config", NULL, NULL }, + { NV3_PFIFO_CACHE_REASSIGNMENT, "PFIFO - Allow Cache Channel Reassignment", NULL, NULL }, + { NV3_PFIFO_CACHE0_PULL0, "PFIFO - Cache0 Puller Control", NULL, NULL}, + { NV3_PFIFO_CACHE1_PULL0, "PFIFO - Cache1 Puller Control"}, + { NV3_PFIFO_CACHE0_PULLER_CTX_STATE, "PFIFO - Cache0 Puller State1 (Is context clean?)", NULL, NULL}, + { NV3_PFIFO_CACHE1_PULL0, "PFIFO - Cache1 Puller State0", NULL, NULL}, + { NV3_PFIFO_CACHE1_PULLER_CTX_STATE, "PFIFO - Cache1 Puller State1 (Is context clean?)", NULL, NULL}, + { NV3_PFIFO_CACHE0_PUSH_ENABLED, "PFIFO - Cache0 Access", NULL, NULL, }, + { NV3_PFIFO_CACHE1_PUSH_ENABLED, "PFIFO - Cache1 Access", NULL, NULL, }, + { NV3_PFIFO_CACHE0_PUSH_CHANNEL_ID, "PFIFO - Cache0 Push Channel ID", NULL, NULL, }, + { NV3_PFIFO_CACHE1_PUSH_CHANNEL_ID, "PFIFO - Cache1 Push Channel ID", NULL, NULL, }, + { NV3_PFIFO_CACHE0_ERROR_PENDING, "PFIFO - Cache0 DMA Error Pending?", NULL, NULL, }, + { NV3_PFIFO_CACHE0_STATUS, "PFIFO - Cache0 Status", NULL, NULL}, + { NV3_PFIFO_CACHE1_STATUS, "PFIFO - Cache1 Status", NULL, NULL}, + { NV3_PFIFO_CACHE0_GET, "PFIFO - Cache0 Get", NULL, NULL }, + { NV3_PFIFO_CACHE0_CTX, "PFIFO - Cache0 Context", NULL, NULL }, + { NV3_PFIFO_CACHE1_GET, "PFIFO - Cache1 Get", NULL, NULL }, + { NV3_PFIFO_CACHE0_PUT, "PFIFO - Cache0 Put", NULL, NULL }, + { NV3_PFIFO_CACHE1_PUT, "PFIFO - Cache1 Put", NULL, NULL }, + //Cache1 exclusive stuff + { NV3_PFIFO_CACHE1_DMA_CONFIG_0, "PFIFO - Cache1 DMA Access (bit 0: is running, bit 4: is busy)"}, + { NV3_PFIFO_CACHE1_DMA_CONFIG_1, "PFIFO - Cache1 DMA Length"}, + { NV3_PFIFO_CACHE1_DMA_CONFIG_2, "PFIFO - Cache1 DMA Address"}, + { NV3_PFIFO_CACHE1_DMA_CONFIG_3, "PFIFO - Cache1 DMA Target Node"}, + { NV3_PFIFO_CACHE1_DMA_STATUS, "PFIFO - Cache1 DMA Status"}, + { NV3_PFIFO_CACHE1_DMA_TLB_PT_BASE, "PFIFO - Cache1 DMA TLB - Pagetable Base"}, + { NV3_PFIFO_CACHE1_DMA_TLB_PTE, "PFIFO - Cache1 DMA TLB - Pagetable Entry (31:12 - Frame Address; bit 0 - Is Present)"}, + { NV3_PFIFO_CACHE1_DMA_TLB_TAG, "PFIFO - Cache1 DMA TLB - Tag"}, + //Runout + { NV3_PFIFO_RUNOUT_GET, "PFIFO Runout Get Address [8:3 if 512b, otherwise 12:3]"}, + { NV3_PFIFO_RUNOUT_PUT, "PFIFO Runout Put Address [8:3 if 512b, otherwise 12:3]"}, + { NV3_PFIFO_RUNOUT_STATUS, "PFIFO Runout Status"}, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +// PFIFO init code +void nv3_pfifo_init(void) +{ + nv_log("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("Repressing PFIFO read. The subsystem is disabled according to pmc_enable, returning 0\n"); + return 0x00; + } + + uint32_t ret = 0x00; + + nv_register_t* reg = nv_get_register(address, pfifo_registers, sizeof(pfifo_registers)/sizeof(pfifo_registers[0])); + + // todo: friendly logging + + nv_log_verbose_only("PFIFO Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + + // on-read function + if (reg->on_read) + ret = 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: + ret = nv3->pfifo.interrupt_status; + break; + case NV3_PFIFO_INTR_EN: + ret = nv3->pfifo.interrupt_enable; + break; + case NV3_PFIFO_DELAY_0: + ret = nv3->pfifo.dma_delay_retry; + break; + // Debug + case NV3_PFIFO_DEBUG_0: + ret = nv3->pfifo.debug_0; + break; + case NV3_PFIFO_CONFIG_0: + ret = nv3->pfifo.config_0; + break; + // Some of these may need to become functions. + case NV3_PFIFO_CONFIG_RAMFC: + ret = nv3->pfifo.ramfc_config; + break; + case NV3_PFIFO_CONFIG_RAMHT: + ret = nv3->pfifo.ramht_config; + break; + case NV3_PFIFO_CONFIG_RAMRO: + ret = nv3->pfifo.ramro_config; + break; + /* These automatically trigger pulls when 1 is written */ + case NV3_PFIFO_CACHE0_PULL0: + ret = nv3->pfifo.cache0_settings.pull0; + break; + case NV3_PFIFO_CACHE1_PULL0: + ret = nv3->pfifo.cache1_settings.pull0; + break; + case NV3_PFIFO_CACHE0_PULLER_CTX_STATE: + ret = (nv3->pfifo.cache0_settings.context_is_dirty) ? (1 << NV3_PFIFO_CACHE0_PULLER_CTX_STATE_DIRTY) : 0; + break; + case NV3_PFIFO_CACHE1_PULLER_CTX_STATE: + ret = (nv3->pfifo.cache0_settings.context_is_dirty) ? (1 << NV3_PFIFO_CACHE0_PULLER_CTX_STATE_DIRTY) : 0; + break; + /* Does this automatically push? */ + case NV3_PFIFO_CACHE0_PUSH_ENABLED: + ret = nv3->pfifo.cache0_settings.push0; + break; + case NV3_PFIFO_CACHE1_PUSH_ENABLED: + ret = nv3->pfifo.cache1_settings.push0; + break; + case NV3_PFIFO_CACHE0_PUSH_CHANNEL_ID: + ret = nv3->pfifo.cache0_settings.channel; + break; + case NV3_PFIFO_CACHE1_PUSH_CHANNEL_ID: + ret = nv3->pfifo.cache1_settings.channel; + break; + case NV3_PFIFO_CACHE0_STATUS: + // CACHE0 has only one entry so it can only ever be empty or full + + if (nv3->pfifo.cache0_settings.put_address == nv3->pfifo.cache0_settings.get_address) + ret |= 1 << NV3_PFIFO_CACHE0_STATUS_EMPTY; + else + ret |= 1 << NV3_PFIFO_CACHE0_STATUS_FULL; + + break; + case NV3_PFIFO_CACHE1_STATUS: + // CACHE1 doesn't... + + if (nv3->pfifo.cache1_settings.put_address == nv3->pfifo.cache1_settings.get_address) + ret |= 1 << NV3_PFIFO_CACHE1_STATUS_EMPTY; + + // Check if Cache1 (0x7C bytes in size depending on gpu?) is full + // Based on how the drivers do it + if (!nv3_pfifo_cache1_num_free_spaces()) + ret |= 1 << NV3_PFIFO_CACHE1_STATUS_FULL; + + if (nv3->pfifo.runout_put != nv3->pfifo.runout_get) + ret |= 1 << NV3_PFIFO_CACHE1_STATUS_RANOUT; + + break; + case NV3_PFIFO_CACHE0_PUT: + ret = nv3->pfifo.cache0_settings.put_address; + break; + case NV3_PFIFO_CACHE0_GET: + ret = nv3->pfifo.cache0_settings.get_address; + break; + case NV3_PFIFO_CACHE1_PUT: + ret = nv3->pfifo.cache1_settings.put_address; + break; + case NV3_PFIFO_CACHE1_GET: + ret = nv3->pfifo.cache1_settings.get_address; + break; + // Reassignment + case NV3_PFIFO_CACHE_REASSIGNMENT: + ret = nv3->pfifo.cache_reassignment & 0x01; //1bit meaningful + break; + // Cache1 exclusive stuff + // Control + case NV3_PFIFO_CACHE1_DMA_CONFIG_0: + ret = nv3->pfifo.cache1_settings.dma_state; + break; + case NV3_PFIFO_CACHE1_DMA_CONFIG_1: + ret = nv3->pfifo.cache1_settings.dma_length & (NV3_VRAM_SIZE_8MB) - 4; //MAX vram size + break; + case NV3_PFIFO_CACHE1_DMA_CONFIG_2: + ret = nv3->pfifo.cache1_settings.dma_address; + break; + case NV3_PFIFO_CACHE1_DMA_CONFIG_3: + if (nv3->nvbase.bus_generation == nv_bus_pci) + return NV3_PFIFO_CACHE1_DMA_CONFIG_3_TARGET_NODE_PCI; + else + return NV3_PFIFO_CACHE1_DMA_CONFIG_3_TARGET_NODE_AGP; + break; + case NV3_PFIFO_CACHE1_DMA_STATUS: + ret = nv3->pfifo.cache1_settings.dma_status; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_PT_BASE: + ret = nv3->pfifo.cache1_settings.dma_tlb_pt_base; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_PTE: + ret = nv3->pfifo.cache1_settings.dma_tlb_pte; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_TAG: + ret = nv3->pfifo.cache1_settings.dma_tlb_tag; + break; + // Runout + case NV3_PFIFO_RUNOUT_GET: + ret = nv3->pfifo.runout_get; + break; + case NV3_PFIFO_RUNOUT_PUT: + ret = nv3->pfifo.runout_put; + break; + case NV3_PFIFO_RUNOUT_STATUS: + if (nv3->pfifo.runout_put == nv3->pfifo.runout_get) + ret |= 1 << NV3_PFIFO_RUNOUT_STATUS_EMPTY; /* good news */ + else + ret |= 1 << NV3_PFIFO_RUNOUT_STATUS_RANOUT; /* bad news */ + + /* TODO: the following code sucks (move to a functio?) */ + + uint32_t new_size_ramro = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + if (new_size_ramro == 0) + new_size_ramro = 0x200; + else if (new_size_ramro == 1) + new_size_ramro = 0x2000; + + // WTF? + if (nv3->pfifo.runout_put + 0x08 & (new_size_ramro - 0x08) == nv3->pfifo.runout_get) + ret |= 1 << NV3_PFIFO_RUNOUT_STATUS_FULL; /* VERY BAD news */ + + break; + + /* Cache1 is handled below - cache0 only has one entry */ + case NV3_PFIFO_CACHE0_CTX: + ret = nv3->pfifo.cache0_settings.context[0]; + break; + + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + /* Handle some special memory areas */ + else if (address >= NV3_PFIFO_CACHE1_CTX_START && address <= NV3_PFIFO_CACHE1_CTX_END) + { + uint32_t ctx_entry_id = ((address - NV3_PFIFO_CACHE1_CTX_START) / 16) % 8; + ret = nv3->pfifo.cache1_settings.context[ctx_entry_id]; + + nv_log_verbose_only("PFIFO Cache1 CTX Read Entry=%d Value=0x%04x\n", ctx_entry_id, ret); + } + /* Direct cache read stuff */ + else if (address >= NV3_PFIFO_CACHE0_METHOD_START && address <= NV3_PFIFO_CACHE0_METHOD_END) + { + nv_log_verbose_only("PFIFO Cache0 Read\n"); + + // See if we want the object name or the channel/subchannel information. + if (address & 4) + { + nv_log_verbose_only("Data=0x%08x\n", nv3->pfifo.cache0_entry.data); + + return nv3->pfifo.cache0_entry.data; + } + else + { + uint32_t final = nv3->pfifo.cache0_entry.method | (nv3->pfifo.cache0_entry.subchannel << NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL); + + nv_log_verbose_only("Param (subchannel=15:13, method=12:2)=0x%08x\n", final); + + + return final; + } + } + else if (address >= NV3_PFIFO_CACHE1_METHOD_START && address <= NV3_PFIFO_CACHE1_METHOD_END) + { + // Not sure if REV C changes this. It should... + uint32_t slot = 0; + + // shift right by 3, convert from address, to slot. + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + slot = (address >> 3) & 0x3F; + else + slot = (address >> 3) & 0x1F; + + nv_log_verbose_only("PFIFO Cache1 Read slot=%d", slot); + + // See if we want the object name or the channel/subchannel information. + if (address & 4) + { + nv_log_verbose_only("Data=0x%08x\n", nv3->pfifo.cache1_entries[slot].data); + return nv3->pfifo.cache1_entries[slot].data; + } + else + { + uint32_t final = nv3->pfifo.cache1_entries[slot].method | (nv3->pfifo.cache1_entries[slot].subchannel << NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL); + nv_log_verbose_only("Param (subchannel=15:13, method=12:2)=0x%08x\n", final); + return final; + } + + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +void nv3_pfifo_trigger_dma_if_required(void) +{ + // Not a thing for cache0 + + bool cache1_dma = false; + + /* Check that DMA is enabled */ + if ((nv3->pfifo.cache1_settings.dma_state & NV3_PFIFO_CACHE1_DMA_STATUS_STATE_RUNNING) + && nv3->pfifo.cache1_settings.dma_enabled) + { + uint32_t bytes_to_send = nv3->pfifo.cache1_settings.dma_length; + uint32_t where_to_send = nv3->pfifo.cache1_settings.dma_address; + uint32_t target_node = nv3->pfifo.cache1_settings.dma_target_node; //2=pci, 3=agp. + + /* Pagetable information */ + uint32_t tlb_pt_base = nv3->pfifo.cache1_settings.dma_tlb_pt_base; + uint32_t tlb_pt_entry = nv3->pfifo.cache1_settings.dma_tlb_pte; // notify_obj_page + uint32_t tlb_pt_tag = nv3->pfifo.cache1_settings.dma_tlb_tag; // 0xFFFFFFFF usually? + + /* + going to treat the format the same as notifiers + */ + if (!(tlb_pt_entry & NV3_PFIFO_CACHE1_DMA_TLB_PTE_IS_PRESENT)) + { + warning("NV3: Tried to DMA to a non-existent page! Big Problem!"); + return; + } + + uint32_t final_page_base = tlb_pt_entry & 0xFFFFF000; /* pull out 31:12 */ + + /* + page size is 0x1000 + */ + uint32_t final_address = final_page_base + (tlb_pt_entry << 10) + where_to_send; //x86 page size is 0x1000 (maybe rsh where_to_send by 2) + + nv_log_verbose_only("DMA Engine: DMA to %08x length=%08x", final_address, bytes_to_send); + + //-dma_bm_write() + } + + //we're done + nv3->pfifo.cache1_settings.dma_state &= ~NV3_PFIFO_CACHE1_DMA_STATUS_STATE_RUNNING; +} + +void nv3_pfifo_write(uint32_t address, uint32_t val) +{ + // before doing anything, check the subsystem enablement + + if (!(nv3->pmc.enable >> NV3_PMC_ENABLE_PFIFO) + & NV3_PMC_ENABLE_PFIFO_ENABLED) + { + nv_log("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_verbose_only("PFIFO Write 0x%08x -> 0x%08x", val, address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_write) + reg->on_write(val); + 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 &= ~val; + nv3_pmc_clear_interrupts(); + + // update the internal cache error state + if (!nv3->pfifo.interrupt_status & NV3_PFIFO_INTR_CACHE_ERROR) + nv3->pfifo.debug_0 &= ~NV3_PFIFO_INTR_CACHE_ERROR; + break; + case NV3_PFIFO_INTR_EN: + nv3->pfifo.interrupt_enable = val & 0x00011111; + nv3_pmc_handle_interrupts(true); + break; + case NV3_PFIFO_DELAY_0: + nv3->pfifo.dma_delay_retry = val; + break; + case NV3_PFIFO_CONFIG_0: + nv3->pfifo.config_0 = val; + break; + + case NV3_PFIFO_CONFIG_RAMHT: + nv3->pfifo.ramht_config = val; +// This code sucks a bit fix it later +#ifdef ENABLE_NV_LOG + uint32_t new_size_ramht = ((val >> 16) & 0x03); + + if (new_size_ramht == 0) + new_size_ramht = 0x1000; + else if (new_size_ramht == 1) + new_size_ramht = 0x2000; + else if (new_size_ramht == 2) + new_size_ramht = 0x4000; + else if (new_size_ramht == 3) + new_size_ramht = 0x8000; + + nv_log("RAMHT Reconfiguration\n" + "Base Address in RAMIN: %d\n" + "Size: 0x%08x bytes\n", ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12, new_size_ramht); +#endif + break; + case NV3_PFIFO_CONFIG_RAMFC: + nv3->pfifo.ramfc_config = val; + + nv_log("RAMFC Reconfiguration\n" + "Base Address in RAMIN: %d\n", ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9); + break; + case NV3_PFIFO_CONFIG_RAMRO: + nv3->pfifo.ramro_config = val; + + uint32_t new_size_ramro = ((val >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + if (new_size_ramro == 0) + new_size_ramro = 0x200; + else if (new_size_ramro == 1) + new_size_ramro = 0x2000; + + nv_log("RAMRO Reconfiguration\n" + "Base Address in RAMIN: %d\n" + "Size: 0x%08x bytes\n", ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9, new_size_ramro); + break; + case NV3_PFIFO_DEBUG_0: + nv3->pfifo.debug_0 = val; + break; + // Reassignment + case NV3_PFIFO_CACHE_REASSIGNMENT: + nv3->pfifo.cache_reassignment = val & 0x01; //1bit meaningful + break; + // Control - these can trigger pulls + case NV3_PFIFO_CACHE0_PULL0: + nv3->pfifo.cache0_settings.pull0 = val; // 8bits meaningful + + if (nv3->pfifo.cache0_settings.pull0 & (1 >> NV3_PFIFO_CACHE0_PULL0_ENABLED)) + nv3_pfifo_cache0_pull(); + + break; + case NV3_PFIFO_CACHE1_PULL0: + nv3->pfifo.cache1_settings.pull0 = val; // 8bits meaningful + + if (nv3->pfifo.cache1_settings.pull0 & (1 >> NV3_PFIFO_CACHE1_PULL0_ENABLED)) + nv3_pfifo_cache1_pull(); + + break; + case NV3_PFIFO_CACHE0_PULLER_CTX_STATE: + nv3->pfifo.cache0_settings.context_is_dirty = (val >> NV3_PFIFO_CACHE0_PULLER_CTX_STATE_DIRTY) & 0x01; + break; + case NV3_PFIFO_CACHE1_PULLER_CTX_STATE: + nv3->pfifo.cache1_settings.context_is_dirty = (val >> NV3_PFIFO_CACHE0_PULLER_CTX_STATE_DIRTY) & 0x01; + break; + case NV3_PFIFO_CACHE0_PUSH_ENABLED: + nv3->pfifo.cache0_settings.push0 = val; + break; + case NV3_PFIFO_CACHE1_PUSH_ENABLED: + nv3->pfifo.cache1_settings.push0 = val; + break; + case NV3_PFIFO_CACHE0_PUSH_CHANNEL_ID: + nv3->pfifo.cache0_settings.channel = val; + break; + case NV3_PFIFO_CACHE1_PUSH_CHANNEL_ID: + nv3->pfifo.cache1_settings.channel = val; + break; + // CACHE0_STATUS and CACHE1_STATUS are not writable + // DMA configuration + case NV3_PFIFO_CACHE1_DMA_CONFIG_0: + nv3->pfifo.cache1_settings.dma_state = val; + break; + case NV3_PFIFO_CACHE1_DMA_CONFIG_1: + nv3->pfifo.cache1_settings.dma_length = val; + break; + case NV3_PFIFO_CACHE1_DMA_CONFIG_2: + nv3->pfifo.cache1_settings.dma_address = val; + break; + case NV3_PFIFO_CACHE1_DMA_STATUS: + nv3->pfifo.cache1_settings.dma_status = val; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_PT_BASE: + nv3->pfifo.cache1_settings.dma_tlb_pt_base = val; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_PTE: + nv3->pfifo.cache1_settings.dma_tlb_pte = val; + break; + case NV3_PFIFO_CACHE1_DMA_TLB_TAG: + nv3->pfifo.cache1_settings.dma_tlb_tag = val; + break; + /* Put and Get addresses */ + case NV3_PFIFO_CACHE0_PUT: + nv3->pfifo.cache0_settings.put_address = val; + break; + case NV3_PFIFO_CACHE0_GET: + nv3->pfifo.cache0_settings.get_address = val; + break; + case NV3_PFIFO_CACHE1_PUT: + nv3->pfifo.cache1_settings.put_address = val; + break; + case NV3_PFIFO_CACHE1_GET: + nv3->pfifo.cache1_settings.get_address = val; + break; + case NV3_PFIFO_RUNOUT_GET: + { + uint32_t size_get = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + if (size_get == 0) //512b + nv3->pfifo.runout_get = val & (NV3_RAMIN_RAMRO_SIZE_0 - 0x07); + else + nv3->pfifo.runout_get = val & (NV3_RAMIN_RAMRO_SIZE_1 - 0x07); + break; + } + case NV3_PFIFO_RUNOUT_PUT: + { + uint32_t size_put = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + if (size_put == 0) //512b + nv3->pfifo.runout_put = val & (NV3_RAMIN_RAMRO_SIZE_0 - 0x07); + else + nv3->pfifo.runout_put = val & (NV3_RAMIN_RAMRO_SIZE_1 - 0x07); + + break; + } + /* Cache1 Context is handled below */ + case NV3_PFIFO_CACHE0_CTX: + nv3->pfifo.cache0_settings.context[0] = val; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else if (address >= NV3_PFIFO_CACHE0_METHOD_START && address <= NV3_PFIFO_CACHE0_METHOD_END) + { + nv_log_verbose_only("PFIFO Cache0 Write\n"); + + // 3104 always written after 3100 + if (address & 4) + { + nv_log_verbose_only("Name = 0x%08x\n", val); + nv3->pfifo.cache0_entry.data = val; + nv3_pfifo_cache0_pull(); // immediately pull out + } + else + { + nv3->pfifo.cache0_entry.method = (val & 0x1FFC); + nv3->pfifo.cache0_entry.subchannel = (val >> NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL) & 0x07; + nv_log_verbose_only("Subchannel = 0x%08x, method = 0x%04x\n", nv3->pfifo.cache0_entry.subchannel, nv3->pfifo.cache0_entry.method); + } + + } + else if (address >= NV3_PFIFO_CACHE1_METHOD_START && address <= NV3_PFIFO_CACHE1_METHOD_END) + { + // Not sure if REV C changes this. It should... + uint32_t slot = 0; + + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_C00) + slot = (address >> 3) & 0x3F; + else + slot = (address >> 3) & 0x1F; + + uint32_t real_entry = nv3_pfifo_cache1_normal2gray(slot); + + nv_log_verbose_only("Cache1 Write Slot %d (Gray code)", real_entry); + + // See if we want the object name or the channel/subchannel information. + if (address & 4) + { + nv_log_verbose_only("Name = 0x%08x\n", val); + nv3->pfifo.cache1_entries[real_entry].data = val; + } + else + { + nv3->pfifo.cache1_entries[real_entry].method = (val & 0x1FFC); + nv3->pfifo.cache1_entries[real_entry].subchannel = (val >> NV3_PFIFO_CACHE1_METHOD_SUBCHANNEL) & 0x07; + nv_log_verbose_only("Subchannel = 0x%08x, method = 0x%04x\n", nv3->pfifo.cache1_entries[real_entry].subchannel, nv3->pfifo.cache1_entries[real_entry].method); + } + } + /* Handle some special memory areas */ + else if (address >= NV3_PFIFO_CACHE1_CTX_START && address <= NV3_PFIFO_CACHE1_CTX_END) + { + uint32_t ctx_entry_id = ((address - NV3_PFIFO_CACHE1_CTX_START) / 16) % 8; + nv3->pfifo.cache1_settings.context[ctx_entry_id] = val; + + nv_log_verbose_only("PFIFO Cache1 CTX Write Entry=%d value=0x%04x\n", ctx_entry_id, val); + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } + + /* Trigger DMA for notifications if we need to */ + nv3_pfifo_trigger_dma_if_required(); +} + + +/* +https://en.wikipedia.org/wiki/Gray_code +WHY?????? IT'S NOT A TELEGRAPH IT'S A GPU????? + +Convert from a normal number to a total insanity number which is only used in PFIFO CACHE1 for ungodly and totally unknowable reasons +(Possibly it just makes it easier to implement in logic) + +I decided to use a lookup table to save everyone's time, also the numbers generated from the function +that existed here before didn't make any sense +*/ + +#define NV3_GRAY_TABLE_NUM_ENTRIES 64 + +uint8_t nv3_pfifo_cache1_gray_code_table[NV3_GRAY_TABLE_NUM_ENTRIES] = { + 0b000000, 0b000001, 0b000011, 0b000010, 0b000110, 0b000111, 0b000101, 0b000100, //0x07 + 0b001100, 0b001101, 0b001111, 0b001110, 0b001010, 0b001011, 0b001001, 0b001000, //0x0F + 0b011000, 0b011001, 0b011011, 0b011010, 0b011110, 0b011111, 0b011101, 0b011100, //0x17 + 0b010100, 0b010101, 0b010111, 0b010110, 0b010010, 0b010011, 0b010001, 0b010000, //0x1F + 0b110000, 0b110001, 0b110011, 0b110010, 0b110110, 0b110111, 0b110101, 0b110100, //0x27 + 0b111100, 0b111101, 0b111111, 0b111110, 0b111010, 0b111011, 0b111001, 0b111000, //0x2F + 0b101000, 0b101001, 0b101011, 0b101010, 0b101110, 0b101111, 0b101101, 0b101100, //0x37 + 0b100100, 0b100101, 0b100111, 0b100110, 0b100010, 0b100011, 0b100001, 0b100000 //0x3F +}; + +/* The function is called up to hundreds of thousands of times per second, it's too slow to do anything else */ +uint8_t nv3_pfifo_cache1_binary_code_table[NV3_GRAY_TABLE_NUM_ENTRIES] = +{ + 0x00, 0x01, 0x03, 0x02, 0x07, 0x06, 0x04, 0x05, // 0x07 (0) + 0x0F, 0x0E, 0x0C, 0x0D, 0x08, 0x09, 0x0B, 0x0A, // 0x0F (1000) + 0x1F, 0x1E, 0x1C, 0x1D, 0x18, 0x19, 0x1B, 0x1A, // 0x17 (10000) + 0x10, 0x11, 0x13, 0x12, 0x17, 0x16, 0x14, 0x15, // 0x1F (11000) + 0x3F, 0x3E, 0x3C, 0x3D, 0x38, 0x39, 0x3B, 0x3A, // 0x27 (100000) + 0x30, 0x31, 0x33, 0x32, 0x37, 0x36, 0x34, 0x35, // 0x2F (101000) + 0x20, 0x21, 0x23, 0x22, 0x27, 0x26, 0x24, 0x25, // 0x37 (110000) + 0x2F, 0x2E, 0x2C, 0x2D, 0x28, 0x29, 0x2B, 0x2A, // 0X3f (111000) +}; + +uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val) +{ + return nv3_pfifo_cache1_gray_code_table[val]; +} + +/* +Back to sanity +*/ +uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val) +{ + return nv3_pfifo_cache1_binary_code_table[val]; +} + +/* +You can't push into cache0 on the real hardware, but it's not practically done because Cache0 is meant to be reserved for software objects, +NV_USER writes always go to CACHE1 +*/ + +// Pulls graphics objects OUT of cache0 +void nv3_pfifo_cache0_pull(void) +{ + // Do nothing if PFIFO CACHE0 is disabled + if (!nv3->pfifo.cache0_settings.pull0 & (1 >> NV3_PFIFO_CACHE0_PULL0_ENABLED)) + return; + + // Do nothing if there is nothing in cache0 to pull + if (nv3->pfifo.cache0_settings.put_address == nv3->pfifo.cache0_settings.get_address) + return; + + // There is only one entry for cache0 + uint8_t current_channel = nv3->pfifo.cache0_settings.channel; + uint8_t current_subchannel = nv3->pfifo.cache0_entry.subchannel; + uint32_t current_param = nv3->pfifo.cache0_entry.data; + uint16_t current_method = nv3->pfifo.cache0_entry.method; + + // i.e. there is no method in cache0, so we have to find the object. + if (!current_method) + { + // flip the get address over + nv3->pfifo.cache0_settings.get_address ^= 0x04; + + if (!nv3_ramin_find_object(current_param, 0, current_channel, current_subchannel)) + return; // interrupt was fired, and we went to ramro + } + + uint32_t current_context = nv3->pfifo.cache0_settings.context[0]; // only 1 entry for CACHE0 so basically ignore the other context entries? + uint8_t class_id = ((nv3_ramin_context_t*)¤t_context)->class_id; + + // Tell the CPU if we found a software method and turn off cache pulling + if (!(current_context & 0x800000)) + { + nv_log_verbose_only("The object in CACHE0 is a software object\n"); + + nv3->pfifo.cache0_settings.pull0 |= NV3_PFIFO_CACHE0_PULL0_SOFTWARE_METHOD; + nv3->pfifo.cache0_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_ENABLED; + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + return; + } + + // Is this needed? + nv3->pfifo.cache0_settings.get_address ^= 0x04; + + #ifndef RELEASE_BUILD + + nv_log_verbose_only("***** DEBUG: CACHE0 PULLED ****** Contextual information below\n"); + + + nv3_ramin_context_t context_structure = *(nv3_ramin_context_t*)¤t_context; + + nv3_debug_ramin_print_context_info(current_param, context_structure); + + nv3_pgraph_submit(current_param, current_method, current_channel, current_subchannel, class_id & 0x1F, context_structure); + #endif + +} + +void nv3_pfifo_context_switch(uint32_t new_channel) +{ + /* Send our contexts to RAMFC. Load the new ones from RAMFC. */ + if (new_channel >= NV3_DMA_CHANNELS) + fatal("nv3_pfifo_context_switch: Tried to switch to invalid dma channel"); + + //uint16_t ramfc_base = nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS & 0xF; +} + +// NV_USER writes go here! +// Pushes graphics objects into cache1 +void nv3_pfifo_cache1_push(uint32_t addr, uint32_t param) +{ + bool oh_shit = false; // RAMRO needed + nv3_ramin_ramro_reason oh_shit_reason = 0x00; // It's all good for now + + // bit 23 of a ramin dword means it's a write... + uint32_t new_address = 0; + + uint32_t method_offset = (addr & 0x1FFC); // size of dma object is 0x2000 and some universal methods are implemented at this point, like free + + // Up to 128 per envytools? + uint32_t channel = (addr >> NV3_OBJECT_SUBMIT_CHANNEL) & 0x7F; + uint32_t subchannel = (addr >> NV3_OBJECT_SUBMIT_SUBCHANNEL) & (NV3_DMA_CHANNELS - 1); + + // first make sure there is even any cache available + if (!nv3->pfifo.cache1_settings.push0) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_no_cache_available; + new_address |= (nv3_runout_reason_no_cache_available << NV3_PFIFO_RUNOUT_RAMIN_ERR); + + } + + // Check if runout is full + if (nv3->pfifo.runout_get != nv3->pfifo.runout_put) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_cache_ran_out; // ? really ? I guess this means we already ran out.. + new_address |= (nv3_runout_reason_cache_ran_out << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + + if (!nv3_pfifo_cache1_num_free_spaces()) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_free_count_overrun; + new_address |= (nv3_runout_reason_free_count_overrun << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + + // 0x0 is used for creating the object. + if (method_offset > 0 && method_offset < 0x100) + { + // Reserved nvidia methods + oh_shit = true; + oh_shit_reason = nv3_runout_reason_reserved_access; + new_address |= (nv3_runout_reason_reserved_access << NV3_PFIFO_RUNOUT_RAMIN_ERR); + + } + + // Now check for context switching + + if (channel != nv3->pfifo.cache1_settings.channel) + { + // Cache reassignment required + if (!nv3->pfifo.cache_reassignment + || (nv3->pfifo.cache1_settings.get_address != nv3->pfifo.cache1_settings.put_address)) + { + oh_shit = true; + oh_shit_reason = nv3_runout_reason_no_cache_available; + new_address |= (nv3_runout_reason_no_cache_available << NV3_PFIFO_RUNOUT_RAMIN_ERR); + } + + nv3_pfifo_context_switch(channel); + } + + // Did we fuck up? + if (oh_shit) + { + nv_log("OH CRAP: Runout Error=%d Channel=%d Subchannel=%d Method=0x%04x", + oh_shit_reason, channel, subchannel, method_offset); + + nv3_ramro_write(nv3->pfifo.runout_put, new_address); + nv3_ramro_write(nv3->pfifo.runout_put + 4, param); + + nv3->pfifo.runout_put += 0x08; + + uint32_t ramro_size = (nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01; + + /* Make sure it's valid */ + switch (ramro_size) + { + case 0: + nv3->pfifo.runout_put &= (NV3_RAMIN_RAMRO_SIZE_0 - 0x07); + break; + case 1: + nv3->pfifo.runout_put &= (NV3_RAMIN_RAMRO_SIZE_1 - 0x07); + break; + } + + //Fire the interrupt. Also the very bad interrupt... + if (nv3->pfifo.runout_get == nv3->pfifo.runout_put) + nv3_pfifo_interrupt(NV3_PFIFO_INTR_RUNOUT_OVERFLOW, true); + else + nv3_pfifo_interrupt(NV3_PFIFO_INTR_RUNOUT, true); + + return; + } + + // We didn't. Let's put it in CACHE1 + uint32_t current_put_index = nv3->pfifo.cache1_settings.put_address >> 2; + nv3->pfifo.cache1_entries[current_put_index].subchannel = subchannel; + nv3->pfifo.cache1_entries[current_put_index].method = method_offset; + nv3->pfifo.cache1_entries[current_put_index].data = param; + + // now we have to recalculate the cache1 put address + uint32_t next_put_address = nv3_pfifo_cache1_gray2normal(current_put_index); + next_put_address++; + + if (nv3->nvbase.gpu_revision >= NV3_PCI_CFG_REVISION_C00) // RIVA 128ZX# + next_put_address &= (NV3_PFIFO_CACHE1_SIZE_REV_C - 1); + else + next_put_address &= (NV3_PFIFO_CACHE1_SIZE_REV_AB - 1); + + nv3->pfifo.cache1_settings.put_address = nv3_pfifo_cache1_normal2gray(next_put_address) << 2; + + nv_log_verbose_only("Submitted object [PIO]: Channel %d.%d, Parameter 0x%08x, Method ID 0x%04x (Put Address is now %d)\n", + channel, subchannel, param, method_offset, nv3->pfifo.cache1_settings.put_address); + + // Now we're done. Phew! +} + +// Pulls graphics objects OUT of cache1 +void nv3_pfifo_cache1_pull(void) +{ + // Do nothing if PFIFO CACHE1 is disabled + if (!nv3->pfifo.cache1_settings.pull0 & (1 >> NV3_PFIFO_CACHE1_PULL0_ENABLED)) + return; + + // Do nothing if there is nothing in cache1 to pull + if (nv3->pfifo.cache1_settings.put_address == nv3->pfifo.cache1_settings.get_address) + return; + + uint32_t get_index = nv3->pfifo.cache1_settings.get_address >> 2; // 32 bit aligned probably + + uint8_t current_channel = nv3->pfifo.cache1_settings.channel; + uint8_t current_subchannel = nv3->pfifo.cache1_entries[get_index].subchannel; + uint32_t current_param = nv3->pfifo.cache1_entries[get_index].data; + uint16_t current_method = nv3->pfifo.cache1_entries[get_index].method; + + // NV_ROOT + if (!current_method) + { + if (!nv3_ramin_find_object(current_param, 1, current_channel, current_subchannel)) + return; // interrupt was fired, and we went to ramro + } + + // should this be obtained from the grobj? Test on real nv3 h/w after drawrect.nvp works + uint32_t current_context = nv3->pfifo.cache1_settings.context[current_subchannel]; // get the current subchannel + + uint8_t class_id = ((nv3_ramin_context_t*)¤t_context)->class_id; + + + + // start by incrementing + uint32_t next_get_address = nv3_pfifo_cache1_gray2normal(get_index) + 1; + + if (nv3->nvbase.gpu_revision >= NV3_PCI_CFG_REVISION_C00) // RIVA 128ZX + next_get_address &= (NV3_PFIFO_CACHE1_SIZE_REV_C - 1); + else + next_get_address &= (NV3_PFIFO_CACHE1_SIZE_REV_AB - 1); + + // Tell the CPU if we found a software method + //bit23 unset=software + //bit23 set=hardware + if (!(current_context & 0x800000)) + { + nv_log_verbose_only("The object in CACHE1 is a software object\n"); + + nv3->pfifo.cache1_settings.pull0 |= NV3_PFIFO_CACHE0_PULL0_SOFTWARE_METHOD; + nv3->pfifo.cache1_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_ENABLED; + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + return; + } + + // Is this needed? + nv3->pfifo.cache1_settings.get_address = nv3_pfifo_cache1_normal2gray(next_get_address) << 2; + + #ifndef RELEASE_BUILD + + nv_log_verbose_only("***** DEBUG: CACHE1 PULLED ****** Contextual information below\n"); + + nv3_ramin_context_t context_structure = *(nv3_ramin_context_t*)¤t_context; + + nv3_debug_ramin_print_context_info(current_param, context_structure); + #endif + + nv3_pgraph_submit(current_param, current_method, current_channel, current_subchannel, class_id & 0x1F, context_structure); + + + //Todo: finish it +} + +// THIS IS PER SUBCHANNEL! +uint32_t nv3_pfifo_cache1_num_free_spaces(void) +{ + // get the index + + uint32_t get_index = nv3->pfifo.cache1_settings.get_address >> 2; + uint32_t put_index = nv3->pfifo.cache1_settings.put_address >> 2; + + uint32_t real_get_address = nv3_pfifo_cache1_gray2normal(get_index) << 2; + uint32_t real_put_address = nv3_pfifo_cache1_gray2normal(put_index) << 2; + + // There is no hope of being able to understand it. Nobody can understand + return (real_get_address - real_put_address - 4) & 0x7C; // there are 64 entries what +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pgraph.c b/src/video/nv/nv3/subsystems/nv3_pgraph.c new file mode 100644 index 000000000..3ad9fa2a1 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pgraph.c @@ -0,0 +1,632 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> +#include <86box/nv/classes/vid_nv3_classes.h> + +// Initialise the PGRAPH subsystem. +void nv3_pgraph_init(void) +{ + nv_log("Initialising PGRAPH..."); + // Set up the vblank interrupt + nv3->nvbase.svga.vblank_start = nv3_pgraph_vblank_start; + nv_log("Done!\n"); +} + +// +// ****** PGRAPH register list START ****** +// + +nv_register_t pgraph_registers[] = { + { NV3_PGRAPH_DEBUG_0, "PGRAPH Debug 0", NULL, NULL }, + { NV3_PGRAPH_DEBUG_1, "PGRAPH Debug 1", NULL, NULL }, + { NV3_PGRAPH_DEBUG_2, "PGRAPH Debug 2", NULL, NULL }, + { NV3_PGRAPH_DEBUG_3, "PGRAPH Debug 3", NULL, NULL }, + { 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 }, + { NV3_PGRAPH_CTX_SWITCH, "PGRAPH DMA Context Switch", NULL, NULL }, + { NV3_PGRAPH_CONTEXT_CONTROL, "PGRAPH DMA Context Control", NULL, NULL }, + { NV3_PGRAPH_CONTEXT_USER, "PGRAPH DMA Context User", NULL, NULL }, + //{ NV3_PGRAPH_CONTEXT_CACHE(0), "PGRAPH DMA Context Cache", NULL, NULL }, + { NV3_PGRAPH_ABS_UCLIP_XMIN, "PGRAPH Absolute Clip Minimum X [17:0]", NULL, NULL }, + { NV3_PGRAPH_ABS_UCLIP_XMAX, "PGRAPH Absolute Clip Maximum X [17:0]", NULL, NULL }, + { NV3_PGRAPH_ABS_UCLIP_YMIN, "PGRAPH Absolute Clip Minimum Y [17:0]", NULL, NULL }, + { NV3_PGRAPH_ABS_UCLIP_YMAX, "PGRAPH Absolute Clip Maximum Y [17:0]", NULL, NULL }, + { NV3_PGRAPH_SRC_CANVAS_MIN, "PGRAPH Source Canvas Minimum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_SRC_CANVAS_MAX, "PGRAPH Source Canvas Maximum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_DST_CANVAS_MIN, "PGRAPH Destination Canvas Minimum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_DST_CANVAS_MAX, "PGRAPH Destination Canvas Maximum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_PATTERN_COLOR_0_RGB, "PGRAPH Pattern Color 0_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_0_ALPHA, "PGRAPH Pattern Color 0_1 (Bits 7:0 = Alpha)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_1_RGB, "PGRAPH Pattern Color 1_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_1_ALPHA, "PGRAPH Pattern Color 1_1 (Bits 7:0 = Alpha)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_BITMAP_HIGH, "PGRAPH Pattern Bitmap (High 32bits)", NULL, NULL}, + { NV3_PGRAPH_PATTERN_BITMAP_LOW, "PGRAPH Pattern Bitmap (Low 32bits)", NULL, NULL}, + { NV3_PGRAPH_PATTERN_SHAPE, "PGRAPH Pattern Shape (1:0 - 0=8x8, 1=64x1, 2=1x64)", NULL, NULL}, + { NV3_PGRAPH_ROP3, "PGRAPH GDI Ternary Render Operation ROP3 (2^3 bits = 256 possible operations)", NULL, NULL}, + { NV3_PGRAPH_PLANE_MASK, "PGRAPH Current Plane Mask (7:0)", NULL, NULL}, + { NV3_PGRAPH_CHROMA_KEY, "PGRAPH Chroma Key (17:0) (Bit 30 = Alpha, 29:20 = Red, 19:10 = Green, 9:0 = Blue)", NULL, NULL}, + { NV3_PGRAPH_BETA, "PGRAPH Beta factor", NULL, NULL }, + { NV3_PGRAPH_DMA, "PGRAPH DMA", NULL, NULL }, + { NV3_PGRAPH_CLIP_MISC, "PGRAPH Clipping Miscellaneous Settings", NULL, NULL }, + { NV3_PGRAPH_NOTIFY, "PGRAPH Notifier (Wip...)", NULL, NULL }, + { NV3_PGRAPH_CLIP0_MIN, "PGRAPH Clip0 Min (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_CLIP0_MAX, "PGRAPH Clip0 Max (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_CLIP1_MIN, "PGRAPH Clip1 Min (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_CLIP1_MAX, "PGRAPH Clip1 Max (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, + { NV3_PGRAPH_FIFO_ACCESS, "PGRAPH - Can we access PFIFO?", NULL, NULL, }, + { NV3_PGRAPH_STATUS, "PGRAPH Status", NULL, NULL }, + { NV3_PGRAPH_TRAPPED_ADDRESS, "PGRAPH Trapped Address", NULL, NULL }, + { NV3_PGRAPH_TRAPPED_DATA, "PGRAPH Trapped Data", NULL, NULL }, + { NV3_PGRAPH_INSTANCE, "PGRAPH Object Instance", NULL, NULL}, + { NV3_PGRAPH_TRAPPED_INSTANCE, "PGRAPH Trapped Object Instance", NULL, NULL }, + { NV3_PGRAPH_DMA_INTR_0, "PGRAPH DMA Interrupt Status (unimplemented)", NULL, NULL }, + { NV3_PGRAPH_DMA_INTR_EN_0, "PGRAPH DMA Interrupt Enable (unimplemented)", 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("Repressing PGRAPH read. The subsystem is disabled according to pmc_enable, returning 0\n"); + return 0x00; + } + + uint32_t ret = 0x00; + + nv_register_t* reg = nv_get_register(address, pgraph_registers, sizeof(pgraph_registers)/sizeof(pgraph_registers[0])); + + // todo: friendly logging + + nv_log_verbose_only("PGRAPH Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + switch (reg->address) + { + case NV3_PGRAPH_DEBUG_0: + ret = nv3->pgraph.debug_0; + break; + case NV3_PGRAPH_DEBUG_1: + ret = nv3->pgraph.debug_1; + break; + case NV3_PGRAPH_DEBUG_2: + ret = nv3->pgraph.debug_2; + break; + case NV3_PGRAPH_DEBUG_3: + ret = nv3->pgraph.debug_3; + break; + //interrupt status and enable regs + case NV3_PGRAPH_INTR_0: + ret = nv3->pgraph.interrupt_status_0; + nv3_pmc_clear_interrupts(); + break; + case NV3_PGRAPH_INTR_1: + ret = nv3->pgraph.interrupt_status_1; + nv3_pmc_clear_interrupts(); + break; + case NV3_PGRAPH_INTR_EN_0: + ret = nv3->pgraph.interrupt_enable_0; + nv3_pmc_handle_interrupts(true); + break; + case NV3_PGRAPH_INTR_EN_1: + ret = nv3->pgraph.interrupt_enable_1; + nv3_pmc_handle_interrupts(true); + break; + // A lot of this is currently a temporary implementation so that we can just debug what the current state looks like + // during the driver initialisation process + + // In the future, these will most likely have their own functions... + + // Context Swithcing (THIS IS CONTROLLED BY PFIFO!) + case NV3_PGRAPH_CTX_SWITCH: + ret = nv3->pgraph.context_switch; + break; + case NV3_PGRAPH_CONTEXT_CONTROL: + ret = *(uint32_t*)&nv3->pgraph.context_control; + break; + case NV3_PGRAPH_CONTEXT_USER: + ret = *(uint32_t*)&nv3->pgraph.context_user; + break; + // Clip + case NV3_PGRAPH_ABS_UCLIP_XMIN: + ret = nv3->pgraph.abs_uclip_xmin; + break; + case NV3_PGRAPH_ABS_UCLIP_XMAX: + ret = nv3->pgraph.abs_uclip_xmax; + break; + case NV3_PGRAPH_ABS_UCLIP_YMIN: + ret = nv3->pgraph.abs_uclip_ymin; + break; + case NV3_PGRAPH_ABS_UCLIP_YMAX: + ret = nv3->pgraph.abs_uclip_ymax; + break; + // Canvas + case NV3_PGRAPH_SRC_CANVAS_MIN: + ret = *(uint32_t*)&nv3->pgraph.src_canvas_min; + break; + case NV3_PGRAPH_SRC_CANVAS_MAX: + ret = *(uint32_t*)&nv3->pgraph.src_canvas_max; + break; + // Pattern + case NV3_PGRAPH_PATTERN_COLOR_0_RGB: + ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_rgb; + break; + case NV3_PGRAPH_PATTERN_COLOR_0_ALPHA: + ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_alpha; + break; + case NV3_PGRAPH_PATTERN_COLOR_1_RGB: + ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_rgb; + break; + case NV3_PGRAPH_PATTERN_COLOR_1_ALPHA: + ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_alpha; + break; + case NV3_PGRAPH_PATTERN_BITMAP_HIGH: + ret = (nv3->pgraph.pattern_bitmap >> 32) & 0xFFFFFFFF; + break; + case NV3_PGRAPH_PATTERN_BITMAP_LOW: + ret = (nv3->pgraph.pattern_bitmap & 0xFFFFFFFF); + break; + // Beta factor + case NV3_PGRAPH_BETA: + ret = nv3->pgraph.beta_factor; + break; + // Todo: Massive table of ROP IDs or at least known ones? + case NV3_PGRAPH_ROP3: + ret = nv3->pgraph.rop; + break; + case NV3_PGRAPH_CHROMA_KEY: + ret = *(uint32_t*)&nv3->pgraph.chroma_key; + break; + case NV3_PGRAPH_PLANE_MASK: + ret = nv3->pgraph.plane_mask; + break; + // DMA + case NV3_PGRAPH_DMA: + ret = *(uint32_t*)&nv3->pgraph.dma_settings; + break; + case NV3_PGRAPH_NOTIFY: + ret = *(uint32_t*)&nv3->pgraph.notifier; + break; + // More clip + case NV3_PGRAPH_CLIP0_MIN: + ret = *(uint32_t*)&nv3->pgraph.clip0_min; + break; + case NV3_PGRAPH_CLIP0_MAX: + ret = *(uint32_t*)&nv3->pgraph.clip0_max; + break; + case NV3_PGRAPH_CLIP1_MIN: + ret = *(uint32_t*)&nv3->pgraph.clip1_min; + break; + case NV3_PGRAPH_CLIP1_MAX: + ret = *(uint32_t*)&nv3->pgraph.clip1_max; + break; + case NV3_PGRAPH_CLIP_MISC: + ret = *(uint32_t*)&nv3->pgraph.clip_misc_settings; + break; + + // Overall Status + case NV3_PGRAPH_STATUS: + ret = *(uint32_t*)&nv3->pgraph.status; + break; + // Trapped Address + case NV3_PGRAPH_TRAPPED_ADDRESS: + ret = nv3->pgraph.trapped_address; + break; + case NV3_PGRAPH_TRAPPED_DATA: + ret = nv3->pgraph.trapped_data; + break; + case NV3_PGRAPH_INSTANCE: + ret = nv3->pgraph.instance; + break; + case NV3_PGRAPH_TRAPPED_INSTANCE: + ret = nv3->pgraph.trapped_instance; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + /* Special exception for memory areas */ + if (address >= NV3_PGRAPH_CONTEXT_CACHE(0) + && address <= NV3_PGRAPH_CONTEXT_CACHE(NV3_PGRAPH_CONTEXT_CACHE_SIZE)) + { + // Addresses should be aligned to 4 bytes. + uint32_t entry = (address - NV3_PGRAPH_CONTEXT_CACHE(0)); + + nv_log_verbose_only("PGRAPH Context Cache Read (Entry=%04x Value=%04x)\n", entry, nv3->pgraph.context_cache[entry]); + } + else /* Completely unknown */ + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + } + + return ret; +} + +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("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_verbose_only("PGRAPH Write 0x%08x -> 0x%08x\n", value, address); + + // if the register actually exists + if (reg) + { + + // on-read function + if (reg->on_write) + reg->on_write(value); + else + { + switch (reg->address) + { + case NV3_PGRAPH_DEBUG_0: + nv3->pgraph.debug_0 = value; + break; + case NV3_PGRAPH_DEBUG_1: + nv3->pgraph.debug_1 = value; + break; + case NV3_PGRAPH_DEBUG_2: + nv3->pgraph.debug_2 = value; + break; + case NV3_PGRAPH_DEBUG_3: + nv3->pgraph.debug_3 = value; + break; + //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; + nv3_pmc_handle_interrupts(true); + break; + case NV3_PGRAPH_INTR_EN_1: + nv3->pgraph.interrupt_enable_1 = value & 0x00011111; + nv3_pmc_handle_interrupts(true); + break; + case NV3_PGRAPH_DMA_INTR_0: + nv3->pgraph.interrupt_status_dma &= ~value; + nv3_pmc_clear_interrupts(); + break; + case NV3_PGRAPH_DMA_INTR_EN_0: + nv3->pgraph.interrupt_enable_dma = value & 0x000111111; + nv_log("Handling PGRAPH_DMA interrupts not implemented"); + nv3_pmc_handle_interrupts(true); + break; + // A lot of this is currently a temporary implementation so that we can just debug what the current state looks like + // during the driver initialisation process + + // In the future, these will most likely have their own functions... + + // Context Swithcing (THIS IS CONTROLLED BY PFIFO!) + case NV3_PGRAPH_CTX_SWITCH: + nv3->pgraph.context_switch = value; + break; + case NV3_PGRAPH_CONTEXT_CONTROL: + *(uint32_t*)&nv3->pgraph.context_control = value; + break; + case NV3_PGRAPH_CONTEXT_USER: + *(uint32_t*)&nv3->pgraph.context_user = value; + break; + // Clip + case NV3_PGRAPH_ABS_UCLIP_XMIN: + nv3->pgraph.abs_uclip_xmin = value; + break; + case NV3_PGRAPH_ABS_UCLIP_XMAX: + nv3->pgraph.abs_uclip_xmax = value; + break; + case NV3_PGRAPH_ABS_UCLIP_YMIN: + nv3->pgraph.abs_uclip_ymin = value; + break; + case NV3_PGRAPH_ABS_UCLIP_YMAX: + nv3->pgraph.abs_uclip_ymax = value; + break; + // Canvas + case NV3_PGRAPH_SRC_CANVAS_MIN: + *(uint32_t*)&nv3->pgraph.src_canvas_min = value; + break; + case NV3_PGRAPH_SRC_CANVAS_MAX: + *(uint32_t*)&nv3->pgraph.src_canvas_max = value; + break; + // Pattern + case NV3_PGRAPH_PATTERN_COLOR_0_RGB: + *(uint32_t*)&nv3->pgraph.pattern_color_0_rgb = value; + break; + case NV3_PGRAPH_PATTERN_COLOR_0_ALPHA: + *(uint32_t*)&nv3->pgraph.pattern_color_0_alpha = value; + break; + case NV3_PGRAPH_PATTERN_COLOR_1_RGB: + *(uint32_t*)&nv3->pgraph.pattern_color_1_rgb = value; + break; + case NV3_PGRAPH_PATTERN_COLOR_1_ALPHA: + *(uint32_t*)&nv3->pgraph.pattern_color_1_alpha = value; + break; + case NV3_PGRAPH_PATTERN_BITMAP_HIGH: + nv3->pgraph.pattern_bitmap |= ((uint64_t)value << 32); + break; + case NV3_PGRAPH_PATTERN_BITMAP_LOW: + nv3->pgraph.pattern_bitmap |= value; + break; + // Beta factor + case NV3_PGRAPH_BETA: + nv3->pgraph.beta_factor = value; + break; + // Todo: Massive table of ROP IDs or at least known ones? + case NV3_PGRAPH_ROP3: + nv3->pgraph.rop = value & 0xFF; + break; + case NV3_PGRAPH_CHROMA_KEY: + nv3->pgraph.chroma_key = value; + break; + case NV3_PGRAPH_PLANE_MASK: + nv3->pgraph.plane_mask = value; + break; + // DMA + case NV3_PGRAPH_DMA: + *(uint32_t*)&nv3->pgraph.dma_settings = value; + break; + case NV3_PGRAPH_NOTIFY: + *(uint32_t*)&nv3->pgraph.notifier = value; + break; + // More clip + case NV3_PGRAPH_CLIP0_MIN: + *(uint32_t*)&nv3->pgraph.clip0_min = value; + break; + case NV3_PGRAPH_CLIP0_MAX: + *(uint32_t*)&nv3->pgraph.clip0_max = value; + break; + case NV3_PGRAPH_CLIP1_MIN: + *(uint32_t*)&nv3->pgraph.clip1_min = value; + break; + case NV3_PGRAPH_CLIP1_MAX: + *(uint32_t*)&nv3->pgraph.clip1_max = value; + break; + case NV3_PGRAPH_CLIP_MISC: + *(uint32_t*)&nv3->pgraph.clip_misc_settings = value; + break; + // Overall Status + case NV3_PGRAPH_STATUS: + *(uint32_t*)&nv3->pgraph.status = value; + break; + // Trapped Address + case NV3_PGRAPH_TRAPPED_ADDRESS: + nv3->pgraph.trapped_address = value; + break; + case NV3_PGRAPH_TRAPPED_DATA: + nv3->pgraph.trapped_data = value; + break; + case NV3_PGRAPH_INSTANCE: + nv3->pgraph.instance = value; + break; + case NV3_PGRAPH_TRAPPED_INSTANCE: + nv3->pgraph.trapped_instance = value; + break; + + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + } + else + { + /* Special exception for memory areas */ + if (address >= NV3_PGRAPH_CONTEXT_CACHE(0) + && address <= NV3_PGRAPH_CONTEXT_CACHE(NV3_PGRAPH_CONTEXT_CACHE_SIZE)) + { + // Addresses should be aligned to 4 bytes. + uint32_t entry = (address - NV3_PGRAPH_CONTEXT_CACHE(0)) >> 2; + + nv_log_verbose_only("PGRAPH Context Cache Write (Entry=%04x Value=0x%08x)\n", entry, value); + nv3->pgraph.context_cache[entry] = value; + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } + } +} + +// Fire a VALID Pgraph interrupt: num is the bit# of the interrupt in the GPU subsystem INTR_EN register. +void nv3_pgraph_interrupt_valid(uint32_t num) +{ + nv3->pgraph.interrupt_status_0 |= (1 << num); + nv3_pmc_handle_interrupts(true); +} + +// Fire an INVALID pgraph interrupt +void nv3_pgraph_interrupt_invalid(uint32_t num) +{ + nv3->pgraph.interrupt_status_1 |= (1 << num); + + // Some code in pcbox hat enables the "reserved" bit HERE if it's set in intr 0. What??? + nv3_pmc_handle_interrupts(true); +} + +// VBlank. Fired every single frame. +void nv3_pgraph_vblank_start(svga_t* svga) +{ + nv3_pgraph_interrupt_valid(NV3_PGRAPH_INTR_0_VBLANK); +} + +/* Sends off method execution to the right class */ +void nv3_pgraph_arbitrate_method(uint32_t param, uint16_t method, uint8_t channel, uint8_t subchannel, uint8_t class_id, nv3_ramin_context_t context) +{ + /* Obtain the grobj information from the context in ramin */ + nv3_grobj_t grobj = {0}; + + // we need to shift left by 4 to get the real address, something to do with the 16 byte unit of reversal + uint32_t real_ramin_base = context.ramin_offset << 4; + + // readin our grobj + grobj.grobj_0 = nv3_ramin_read32(real_ramin_base, nv3); + grobj.grobj_1 = nv3_ramin_read32(real_ramin_base + 4, nv3); + grobj.grobj_2 = nv3_ramin_read32(real_ramin_base + 8, nv3); + grobj.grobj_3 = nv3_ramin_read32(real_ramin_base + 12, nv3); + + nv_log_verbose_only("**** About to execute method **** method=0x%04x param=0x%08x, channel=%d.%d, class=%s, grobj=0x%08x 0x%08x 0x%08x 0x%08x\n", + method, param, channel, subchannel, nv3_class_names[class_id], grobj.grobj_0, grobj.grobj_1, grobj.grobj_2, grobj.grobj_3); + + /* Methods below 0x104 are shared across all classids, so call generic_method for that*/ + if (method <= NV3_SET_NOTIFY) + { + nv3_generic_method(param, method, context, grobj); + } + else + { + // By this point, we already ANDed the class ID to 0x1F. + // Send the grobj, the context, the method and the name off to actually be acted upon. + switch (class_id) + { + case nv3_pgraph_class01_beta_factor: + nv3_class_001_method(param, method, context, grobj); + break; + case nv3_pgraph_class02_rop: + nv3_class_002_method(param, method, context, grobj); + break; + case nv3_pgraph_class03_chroma_key: + nv3_class_003_method(param, method, context, grobj); + break; + case nv3_pgraph_class04_plane_mask: + nv3_class_004_method(param, method, context, grobj); + break; + case nv3_pgraph_class05_clipping_rectangle: + nv3_class_005_method(param, method, context, grobj); + break; + case nv3_pgraph_class06_pattern: + nv3_class_006_method(param, method, context, grobj); + break; + case nv3_pgraph_class07_rectangle: + nv3_class_007_method(param, method, context, grobj); + break; + case nv3_pgraph_class08_point: + nv3_class_008_method(param, method, context, grobj); + break; + case nv3_pgraph_class09_line: + nv3_class_009_method(param, method, context, grobj); + break; + case nv3_pgraph_class0a_lin: + nv3_class_00a_method(param, method, context, grobj); + break; + case nv3_pgraph_class0b_triangle: + nv3_class_00b_method(param, method, context, grobj); + break; + case nv3_pgraph_class0c_w95txt: + nv3_class_00c_method(param, method, context, grobj); + break; + case nv3_pgraph_class0d_m2mf: + nv3_class_00d_method(param, method, context, grobj); + break; + case nv3_pgraph_class0e_scaled_image_from_memory: + nv3_class_00e_method(param, method, context, grobj); + break; + case nv3_pgraph_class10_blit: + nv3_class_010_method(param, method, context, grobj); + break; + case nv3_pgraph_class11_image: + nv3_class_011_method(param, method, context, grobj); + break; + case nv3_pgraph_class12_bitmap: + nv3_class_012_method(param, method, context, grobj); + break; + case nv3_pgraph_class14_transfer2memory: + nv3_class_014_method(param, method, context, grobj); + break; + case nv3_pgraph_class15_stretched_image_from_cpu: + nv3_class_015_method(param, method, context, grobj); + break; + case nv3_pgraph_class17_d3d5tri_zeta_buffer: + nv3_class_017_method(param, method, context, grobj); + break; + case nv3_pgraph_class18_point_zeta_buffer: + nv3_class_018_method(param, method, context, grobj); + break; + case nv3_pgraph_class1c_image_in_memory: + nv3_class_01c_method(param, method, context, grobj); + break; + default: + fatal("NV3 (nv3_pgraph_arbitrate_method): Attempted to execute method on invalid, or unimplemented, class ID %s", nv3_class_names[class_id]); + return; + } + } + + nv3_notify_if_needed(param, method, context, grobj); +} + +/* Arbitrates graphics object submission to the right object types */ +void nv3_pgraph_submit(uint32_t param, uint16_t method, uint8_t channel, uint8_t subchannel, uint8_t class_id, nv3_ramin_context_t context) +{ + // class id can be derived from the context but we debug log it before we get here + // Do we need to read grobj here? + + switch (method) + { + default: + // Object Method arbitration + nv3_pgraph_arbitrate_method(param, method, channel, subchannel, class_id, context); + break; + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pmc.c b/src/video/nv/nv3/subsystems/nv3_pmc.c new file mode 100644 index 000000000..b6528fe0a --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pmc.c @@ -0,0 +1,274 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_pmc_init(void) +{ + nv_log("Initialising PMC....\n"); + + if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_A00) + nv3->pmc.boot = NV3_BOOT_REG_REV_A00; + else if (nv3->nvbase.gpu_revision == NV3_PCI_CFG_REVISION_B00) + nv3->pmc.boot = NV3_BOOT_REG_REV_B00; + else + nv3->pmc.boot = NV3_BOOT_REG_REV_C00; + + nv3->pmc.interrupt_enable = NV3_PMC_INTERRUPT_ENABLE_HARDWARE | NV3_PMC_INTERRUPT_ENABLE_SOFTWARE; + + nv_log("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 +}; + +void nv3_pmc_clear_interrupts(void) +{ + nv_log_verbose_only("Clearing IRQs\n"); + pci_clear_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 = 0x00; + + // 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... + if (nv3->pgraph.interrupt_status_0 & (1 << 8) + && nv3->pgraph.interrupt_enable_0 & (1 << 8)) + new_intr_value |= (NV3_PMC_INTERRUPT_PFB_PENDING << NV3_PMC_INTERRUPT_PFB); + + if (nv3->pgraph.interrupt_status_0 & ~(1 << 8) + && nv3->pgraph.interrupt_enable_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(); + return nv3->pmc.interrupt_status; + } + + + // if we actually need to send the interrupt (i.e. this is a write) send it now + if (send_now) + { + // no interrupts to send + if (!(nv3->pmc.interrupt_status) + || !(nv3->pmc.interrupt_status - 0x80000000)) + { + nv3_pmc_clear_interrupts(); + return nv3->pmc.interrupt_status; + } + + if ((nv3->pmc.interrupt_status & 0x7FFFFFFF)) + { + if (nv3->pmc.interrupt_enable & NV3_PMC_INTERRUPT_ENABLE_HARDWARE) + { + nv_log_verbose_only("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_verbose_only("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_verbose_only("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_verbose_only("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])); + + uint32_t ret = 0x00; + + // todo: friendly logging + nv_log_verbose_only("PMC Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + switch (reg->address) + { + case NV3_PMC_BOOT: + ret = nv3->pmc.boot; + break; + case NV3_PMC_INTERRUPT_STATUS: + nv_log_verbose_only("\n"); // clear_interrupts logs + nv3_pmc_clear_interrupts(); + + ret = nv3_pmc_handle_interrupts(false); + break; + case NV3_PMC_INTERRUPT_ENABLE: + //TODO: ACTUALLY CHANGE THE INTERRUPT STATE + ret = nv3->pmc.interrupt_enable; + break; + case NV3_PMC_ENABLE: + ret = nv3->pmc.enable; + break; + + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PMC Write 0x%08x -> 0x%08x", value, address); + + // if the register actually exists... + if (reg) + { + + // ... 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 can only be done by software interrupts... + if (!(nv3->pmc.interrupt_status & 0x7FFFFFFF)) + { + warning("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 & 0x03; + nv3_pmc_handle_interrupts(value != 0); + break; + case NV3_PMC_ENABLE: + nv3->pmc.enable = value; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pme.c b/src/video/nv/nv3/subsystems/nv3_pme.c new file mode 100644 index 000000000..1f0da2aac --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pme.c @@ -0,0 +1,136 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +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(void) +{ + nv_log("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])); + + uint32_t ret = 0x00; + + // todo: friendly logging + + nv_log_verbose_only("PME Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + // Interrupt state: + // Bit 0 - Image Notifier + // Bit 4 - Vertical Blank Interval Notifier + // Bit 8 - Video Notifier + // Bit 12 - Audio Notifier + // Bit 16 - VMI Notifer + switch (reg->address) + { + case NV3_PME_INTR: + ret = nv3->pme.interrupt_status; + break; + case NV3_PME_INTR_EN: + ret = nv3->pme.interrupt_enable; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PME Write 0x%08x -> 0x%08x\n", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\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; + } + } + + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } + +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pramdac.c b/src/video/nv/nv3/subsystems/nv3_pramdac.c new file mode 100644 index 000000000..9ce5a189a --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pramdac.c @@ -0,0 +1,458 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +// nv3_pramdac.c: NV3 RAMDAC +// Todo: Allow overridability using 68050C register... + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +void nv3_pramdac_init(void) +{ + nv_log("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("Initialising PRAMDAC: Done\n"); +} + +// Polls the pixel clock. +void nv3_pramdac_pixel_clock_poll(double real_time) +{ + /* Ignore in VGA mode */ + if (!nv3->nvbase.svga.override) + return; + + /* Figure out our refresh time. */ + if (!nv3->nvbase.refresh_time) + nv3->nvbase.refresh_time = (1/60.0); // rivatimers count in microseconds but present the info as seconds + + nv3->nvbase.refresh_clock += real_time; + + if (nv3->nvbase.refresh_clock > nv3->nvbase.refresh_time) + { + /* Update the screen because something changed */ + nv3_render_current_bpp(); + video_blit_memtoscreen(0, 0, xsize, ysize); + nv3->nvbase.refresh_clock = 0; + } + + // TODO: ???? +} + +// Polls the memory clock. +// This updates the 2D/3D engine PGRAPH, PTIMER and more +void nv3_pramdac_memory_clock_poll(double real_time) +{ + nv3_ptimer_tick(real_time); + + nv3_pfifo_cache0_pull(); + nv3_pfifo_cache1_pull(); + // TODO: UPDATE PGRAPH! +} + +// Gets the vram clock register. +uint32_t nv3_pramdac_get_vram_clock_register(void) +{ + // the clock format is packed into 19 bits + // M divisor [7-0] + // N divisor [16-8] + // P divisor [18-16] + return (nv3->pramdac.memory_clock_m) + + (nv3->pramdac.memory_clock_n << 8) + + (nv3->pramdac.memory_clock_p << 16); // 0-3 +} + +uint32_t nv3_pramdac_get_pixel_clock_register(void) +{ + return (nv3->pramdac.pixel_clock_m) + + (nv3->pramdac.pixel_clock_n << 8) + + (nv3->pramdac.pixel_clock_p << 16); // 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(void) +{ + // 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; + + if (nv3->pramdac.memory_clock_n == 0) + nv3->pramdac.memory_clock_n = 1; + + // Convert to microseconds + frequency = (frequency * nv3->pramdac.memory_clock_n) / (nv3->pramdac.memory_clock_m << nv3->pramdac.memory_clock_p); + + double time = 1000000.0 / (double)frequency; // needs to be a double for 86box + + nv_log("Memory clock = %.2f MHz\n", frequency / 1000000.0f); + + nv3->nvbase.memory_clock_frequency = frequency; + + // Create and start if it it's not running. + if (!nv3->nvbase.memory_clock_timer) + { + nv3->nvbase.memory_clock_timer = rivatimer_create(time, nv3_pramdac_memory_clock_poll); + rivatimer_start(nv3->nvbase.memory_clock_timer); + } + + rivatimer_set_period(nv3->nvbase.memory_clock_timer, time); +} + +void nv3_pramdac_set_pixel_clock(void) +{ + // frequency divider algorithm from old varcem/86box/pcbox riva driver, + // verified by reversing NT drivers v1.50e CalcMNP [symbols] function + + // 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; + + if (nv3->pramdac.memory_clock_n == 0) + nv3->pramdac.memory_clock_n = 1; + + frequency = (frequency * nv3->pramdac.pixel_clock_n) / (nv3->pramdac.pixel_clock_m << nv3->pramdac.pixel_clock_p); + + nv3->nvbase.svga.clock = cpuclock / frequency; + + double time = 1000000.0 / (double)frequency; // needs to be a double for 86box + + nv_log("Pixel clock = %.2f MHz\n", frequency / 1000000.0f); + + nv3->nvbase.pixel_clock_frequency = frequency; + + // Create and start if it it's not running. + if (!nv3->nvbase.pixel_clock_timer) + { + nv3->nvbase.pixel_clock_timer = rivatimer_create(time, nv3_pramdac_pixel_clock_poll); + rivatimer_start(nv3->nvbase.pixel_clock_timer); + } + + rivatimer_set_period(nv3->nvbase.pixel_clock_timer, time); +} + +// +// ****** PRAMDAC register list START ****** +// + +// NULL means handle in read functions +nv_register_t pramdac_registers[] = +{ + { NV3_PRAMDAC_CURSOR_START, "PRAMDAC - Cursor Start Position"}, + { 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_START, "PRAMDAC - VBBlank Start", NULL, NULL}, + { NV3_PRAMDAC_VBBLANK_END, "PRAMDAC - VBBlank End", NULL, NULL}, + { NV3_PRAMDAC_HBLANK_END, "PRAMDAC - Horizontal Blanking Interval End", NULL, NULL}, + { NV3_PRAMDAC_HBLANK_START, "PRAMDAC - Horizontal Blanking Interval Start", 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}, + { NV3_USER_DAC_PIXEL_MASK, "PRAMDAC - User DAC Pixel Mask", NULL, NULL}, + { NV3_USER_DAC_READ_MODE_ADDRESS, "PRAMDAC - User DAC Read Mode Address", NULL, NULL}, + { NV3_USER_DAC_WRITE_MODE_ADDRESS, "PRAMDAC - User DAC Write Mode Address", NULL, NULL}, + { NV3_USER_DAC_PALETTE_DATA, "PRAMDAC - User DAC Palette Data", 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])); + + uint32_t ret = 0x00; + + // todo: friendly logging + + nv_log_verbose_only("PRAMDAC Read from 0x%08x\n", address); + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + //s hould be pretty easy to understand + switch (reg->address) + { + case NV3_PRAMDAC_COEFF_SELECT: + ret = nv3->pramdac.coeff_select; + break; + case NV3_PRAMDAC_GENERAL_CONTROL: + ret = nv3->pramdac.general_control; + break; + case NV3_PRAMDAC_VSERR_WIDTH: + ret = nv3->pramdac.vserr_width; + break; + case NV3_PRAMDAC_VBBLANK_END: + ret = nv3->pramdac.vbblank_end; + break; + case NV3_PRAMDAC_VBLANK_END: + ret = nv3->pramdac.vblank_end; + break; + case NV3_PRAMDAC_VBLANK_START: + ret = nv3->pramdac.vblank_start; + break; + case NV3_PRAMDAC_VEQU_START: + ret = nv3->pramdac.vequ_start; + break; + case NV3_PRAMDAC_VTOTAL: + ret = nv3->pramdac.vtotal; + break; + case NV3_PRAMDAC_HSYNC_WIDTH: + ret = nv3->pramdac.hsync_width; + break; + case NV3_PRAMDAC_HBURST_START: + ret = nv3->pramdac.hburst_start; + break; + case NV3_PRAMDAC_HBURST_END: + ret = nv3->pramdac.hburst_end; + break; + case NV3_PRAMDAC_HBLANK_START: + ret = nv3->pramdac.hblank_start; + break; + case NV3_PRAMDAC_HBLANK_END: + ret = nv3->pramdac.hblank_end; + break; + case NV3_PRAMDAC_HTOTAL: + ret = nv3->pramdac.htotal; + break; + case NV3_PRAMDAC_HEQU_WIDTH: + ret = nv3->pramdac.hequ_width; + break; + case NV3_PRAMDAC_HSERR_WIDTH: + ret = nv3->pramdac.hserr_width; + break; + case NV3_USER_DAC_PIXEL_MASK: + ret = nv3->pramdac.user_pixel_mask; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + ret = nv3->pramdac.user_read_mode_address; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + ret = nv3->pramdac.user_write_mode_address; + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + ret = nv3->pramdac.palette[nv3->pramdac.user_read_mode_address]; + nv3->pramdac.user_read_mode_address++; + break; + case NV3_PRAMDAC_CURSOR_START: + ret = (nv3->pramdac.cursor_start.y << 16) | nv3->pramdac.cursor_start.x; + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PRAMDAC Write 0x%08x -> 0x%08x\n", value, address); + + // if the register actually exists + if (reg) + { + // 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; + nv3_recalc_timings(&nv3->nvbase.svga); + 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; + case NV3_USER_DAC_PIXEL_MASK: + nv3->pramdac.user_pixel_mask = value; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + nv3->pramdac.user_read_mode_address = value; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + /* + This seems to get reset to 0 after 256 writes, but, the palette is 768 bytes in size. + Clearly there's some mechanism here, but I'm not sure what it is. So let's just reset if we reach 768. + */ + if (nv3->pramdac.user_write_mode_address >= NV3_USER_DAC_PALETTE_SIZE) + nv3->pramdac.user_write_mode_address = value; + + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + nv3->pramdac.palette[nv3->pramdac.user_write_mode_address] = value; + + nv3->pramdac.user_write_mode_address++; + + break; + /* cursor start location */ + case NV3_PRAMDAC_CURSOR_START: + // only 12 bits are used here instead of 16 for some stupid reason + nv3->pramdac.cursor_start.y = (value >> 16) & 0xFFF; + nv3->pramdac.cursor_start.x = (value) & 0xFFF; + nv3_draw_cursor(&nv3->nvbase.svga, 0);//drawline doesn't matter here + break; + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} + diff --git a/src/video/nv/nv3/subsystems/nv3_pramin.c b/src/video/nv/nv3/subsystems/nv3_pramin.c new file mode 100644 index 000000000..77e2d1a6a --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pramin.c @@ -0,0 +1,515 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> +#include <86box/nv/classes/vid_nv3_classes.h> + +// Functions only used in this translation unit +#ifndef RELEASE_BUILD +void nv3_debug_ramin_print_context_info(uint32_t name, nv3_ramin_context_t context); +#endif + +// 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) +{ + if (!nv3) return 0x00; + + addr &= (nv3->nvbase.svga.vram_max - 1); + uint32_t raw_addr = addr; // saved after and + + addr ^= (nv3->nvbase.svga.vram_max - 0x10); + + uint32_t val = 0x00; + + if (!nv3_ramin_arbitrate_read(addr, &val)) // Oh well + { + val = (uint8_t)nv3->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 nv3_ramin_read16(uint32_t addr, void* priv) +{ + if (!nv3) return 0x00; + + addr &= (nv3->nvbase.svga.vram_max - 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 ^= (nv3->nvbase.svga.vram_max - 0x10); + addr >>= 1; // what + + uint32_t val = 0x00; + + if (!nv3_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 nv3_ramin_read32(uint32_t addr, void* priv) +{ + if (!nv3) + return 0x00; + + addr &= (nv3->nvbase.svga.vram_max - 1); + + // why does this not work in one line + uint32_t* vram_32bit = (uint32_t*)nv3->nvbase.svga.vram; + uint32_t raw_addr = addr; // saved after and logged + + addr ^= (nv3->nvbase.svga.vram_max - 0x10); + addr >>= 2; // what + + uint32_t val = 0x00; + + if (!nv3_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 nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv) +{ + if (!nv3) return; + + addr &= (nv3->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/nv3t only and 2mb...i haven't found a 22mb card) + addr ^= (nv3->nvbase.svga.vram_max - 0x10); + + uint32_t val32 = (uint32_t)val; + + if (!nv3_ramin_arbitrate_write(addr, val32)) + { + nv3->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 nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv) +{ + if (!nv3) return; + + addr &= (nv3->nvbase.svga.vram_max - 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 ^= (nv3->nvbase.svga.vram_max - 0x10); + addr >>= 1; // what + + uint32_t val32 = (uint32_t)val; + + if (!nv3_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 nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv) +{ + if (!nv3) return; + + addr &= (nv3->nvbase.svga.vram_max - 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 ^= (nv3->nvbase.svga.vram_max - 0x10); + addr >>= 2; // what + + if (!nv3_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); + } + +} + +void nv3_pfifo_interrupt(uint32_t id, bool fire_now) +{ + nv3->pfifo.interrupt_status |= (1 << id); + nv3_pmc_handle_interrupts(fire_now); +} + +/* +RAMIN access arbitration functions +Arbitrates reads and writes to RAMFC (unused dma context storage), RAMRO (invalid object submission location), RAMHT (hashtable for graphics objectstorage) unused audio memory (RAMAU?) +and generic RAMIN + +Takes a pointer to a result integer. This is because we need to check its result in our normal write function. +Returns true if a valid "non-generic" address was found (e.g. RAMFC/RAMRO/RAMHT). False if the specified address is a generic RAMIN address +*/ +bool nv3_ramin_arbitrate_read(uint32_t address, uint32_t* value) +{ + if (!nv3) return 0x00; + + uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03); + uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + // Get the addresses of RAMHT, RAMFC, RAMRO + // They must be within first 64KB of PRAMIN! + uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned + uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + + // Calculate the RAMHT and RAMRO end points. + // (RAMFC is always 0x1000 bytes on NV3.) + uint32_t ramht_end = ramht_start; + uint32_t ramfc_end = ramfc_start + 0x1000; + uint32_t ramro_end = ramro_start; + + switch (ramht_size) + { + case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_1; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_2; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_3; + break; + } + + switch (ramro_size) + { + case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B: + ramro_end = ramro_start + NV3_RAMIN_RAMRO_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K: + ramro_end = ramro_start + NV3_RAMIN_RAMRO_SIZE_1; + break; + } + + if (address >= ramht_start + && address <= ramht_end) + { + *value = nv3_ramht_read(address); + return true; + } + else if (address >= ramfc_start + && address <= ramfc_end) + { + *value = nv3_ramfc_read(address); + return true; + } + else if (address >= ramro_start + && address <= ramro_end) + { + *value = nv3_ramro_read(address); + return true; + } + + /* temp */ + return false; +} + +bool nv3_ramin_arbitrate_write(uint32_t address, uint32_t value) +{ + if (!nv3) return 0x00; + + uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03); + uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01); + + // Get the addresses of RAMHT, RAMFC, RAMRO + // They must be within first 64KB of PRAMIN! + uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned + uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned + + // Calculate the RAMHT and RAMRO end points. + // (RAMFC is always 0x1000 bytes on NV3.) + uint32_t ramht_end = ramht_start; + uint32_t ramfc_end = ramfc_start + 0x1000; + uint32_t ramro_end = ramro_start; + + switch (ramht_size) + { + case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_1; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_2; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K: + ramht_end = ramht_start + NV3_RAMIN_RAMHT_SIZE_3; + break; + } + + switch (ramro_size) + { + case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B: + ramro_end = ramro_start + NV3_RAMIN_RAMRO_SIZE_0; + break; + case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K: + ramro_end = ramro_start + NV3_RAMIN_RAMRO_SIZE_1; + break; + } + + // send the addresses to the right part + if (address >= ramht_start + && address <= ramht_end) + { + nv3_ramht_write(address, value); + return true; + } + else if (address >= ramfc_start + && address <= ramfc_end) + { + nv3_ramfc_write(address, value); + return true; + } + else if (address >= ramro_start + && address <= ramro_end) + { + nv3_ramro_write(address, value); + return true; + } + + return false; +} + +// THIS IS THE MOST IMPORTANT FUNCTION! +bool nv3_ramin_find_object(uint32_t name, uint32_t cache_num, uint8_t channel, uint8_t subchannel) +{ + // TODO: WRITE IT!!! + // Set the number of entries to search based on the ramht size (2*(size+1)) + // Not a switch statement in case newer gpus have larger ramins + + uint32_t bucket_entries = 2; + uint8_t ramht_size = (nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03; + + switch (ramht_size) + { + case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K: + // stays as is + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K: + bucket_entries = 4; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K: + bucket_entries = 8; + break; + case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K: + bucket_entries = 16; + break; + + } + + // Calculate the address in the hashtable + uint32_t ramht_base = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS; + + // This is certainly wrong. But the objects seem to be written to 4600? So I just multiply it by 80 to multiply the final address by 10. + // Why does this work? + uint32_t ramht_cur_address = ramht_base + (nv3_ramht_hash(name, channel) * bucket_entries * 8); + + nv_log_verbose_only("Beginning search for graphics object at RAMHT base=0x%04x, name=0x%08x, Cache%d, channel=%d.%d)\n", + ramht_cur_address, name, cache_num, channel, subchannel); + + bool found_object = false; + + // set up some variables + uint32_t found_obj_name = 0x00; + nv3_ramin_context_t obj_context_struct = {0}; + + for (uint32_t bucket_entry = 0; bucket_entry < bucket_entries; bucket_entry++) + { + found_obj_name = nv3_ramin_read32(ramht_cur_address, NULL); + ramht_cur_address += 0x04; + uint32_t obj_context = nv3_ramin_read32(ramht_cur_address, NULL); + ramht_cur_address += 0x04; + obj_context_struct = *(nv3_ramin_context_t*)&obj_context; + + // see if the object is in the right channel + if (found_obj_name == name + && obj_context_struct.channel == channel) + { + found_object = true; + break; + } + } + + if (!found_object) + { + if (!cache_num) + { + nv3->pfifo.debug_0 |= NV3_PFIFO_CACHE0_ERROR_PENDING; + nv3->pfifo.cache0_settings.pull0 |= NV3_PFIFO_CACHE0_PULL0_HASH_FAILURE; + //It turns itself off on failure, the drivers turn it back on + nv3->pfifo.cache0_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_ENABLED; + } + else + { + nv3->pfifo.debug_0 |= NV3_PFIFO_CACHE1_ERROR_PENDING; + nv3->pfifo.cache1_settings.pull0 |= NV3_PFIFO_CACHE1_PULL0_HASH_FAILURE; + //It turns itself off on failure, the drivers turn it back on + nv3->pfifo.cache1_settings.pull0 &= ~NV3_PFIFO_CACHE1_PULL0_ENABLED; + } + + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + + return false; + } + + // So we did find an object. + // Now try to read some of this... + + // Class ID is 5 bits in all other parts of the gpu but 7 bits here. A move in a direction that didn't pan out? + // Represented as 0x40-0x5f? Some other meaning + + // Perform more validation + + if (obj_context_struct.class_id < NV3_PFIFO_FIRST_VALID_GRAPHICS_OBJECT_ID + || obj_context_struct.class_id > NV3_PFIFO_LAST_VALID_GRAPHICS_OBJECT_ID) + { + fatal("NV3: Invalid graphics object class ID name=0x%04x type=%04x, interpreted by pgraph as: %04x (Contact starfrost)", + name, obj_context_struct.class_id, obj_context_struct.class_id & 0x1F); + } + else if (obj_context_struct.channel > (NV3_DMA_CHANNELS - 1)) + fatal("NV3: Super fucked up graphics object. Contact starfrost with the error string: DMA Channel ID=%d, it should be 0-7", obj_context_struct.channel); + + // Illegal accesses sent to RAMRO, so ignore here + // TODO: SEND THESE TO RAMRO!!!!! + + #ifndef RELEASE_BUILD + nv3_debug_ramin_print_context_info(name, obj_context_struct); + #endif + + // By definition we can't have a cache error by here so take it off + if (!cache_num) + nv3->pfifo.cache0_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_HASH_FAILURE; + else + nv3->pfifo.cache1_settings.pull0 &= ~NV3_PFIFO_CACHE1_PULL0_HASH_FAILURE; + + // Caches store all the subchannels for our current dma channel and basically get stale every context switch + // Also we have to check that a osftware object didn't end up in here... + + bool is_software = false; + if (!cache_num) + is_software = (nv3->pfifo.cache0_settings.context[subchannel] & 0x800000); + else + is_software = (nv3->pfifo.cache1_settings.context[subchannel] & 0x800000); + + // This isn't an error but it's sent as an interrupt so the drivers can sync + if (is_software) + { + // handle it as an error + if (!cache_num) + { + nv3->pfifo.cache0_settings.pull0 |= NV3_PFIFO_CACHE0_PULL0_SOFTWARE_METHOD; + nv3->pfifo.cache0_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_ENABLED; + } + else + { + nv3->pfifo.cache1_settings.pull0 |= NV3_PFIFO_CACHE1_PULL0_SOFTWARE_METHOD; + nv3->pfifo.cache1_settings.pull0 &= ~NV3_PFIFO_CACHE1_PULL0_ENABLED; + } + + // It's an error but it isn't lol + nv3_pfifo_interrupt(NV3_PFIFO_INTR_CACHE_ERROR, true); + + } + else + { + // obviously turn off the "is software" if it's not + if (!cache_num) + nv3->pfifo.cache0_settings.pull0 &= ~NV3_PFIFO_CACHE0_PULL0_SOFTWARE_METHOD; + else + nv3->pfifo.cache1_settings.pull0 &= ~NV3_PFIFO_CACHE1_PULL0_SOFTWARE_METHOD; + } + + // Ok we found it. Lol + return true; + +} + + +// Prints out some informaiton about the object +void nv3_debug_ramin_print_context_info(uint32_t name, nv3_ramin_context_t context) +{ + #ifndef RELEASE_BUILD + nv_log_verbose_only("Found object:\n"); + nv_log_verbose_only("Param: 0x%04x\n", name); + + nv_log_verbose_only("Context:\n"); + nv_log_verbose_only("DMA Channel %d (0-7 valid)\n", context.channel); + nv_log_verbose_only("Class ID: 0x%04x (%s)\n", context.class_id & 0x1F, nv3_class_names[context.class_id & 0x1F]); + nv_log_verbose_only("Render Engine %d (0=Software, also DMA? 1=Accelerated Renderer)\n", context.is_rendering); + nv_log_verbose_only("PRAMIN Offset 0x%08x\n", context.ramin_offset << 4); + #endif +} diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c new file mode 100644 index 000000000..59fa41e8d --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c @@ -0,0 +1,40 @@ +/* + * 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 for unused DMA channels + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +uint32_t nv3_ramfc_read(uint32_t address) +{ + nv_log_verbose_only("RAMFC (Unused DMA channel context) Read (0x%04x) (UNIMPLEMENTED returning 0x00)\n", address); + return 0x00; //temp +} + +void nv3_ramfc_write(uint32_t address, uint32_t value) +{ + nv_log_verbose_only("RAMFC (Unused DMA channel context) Write (0x%04x -> 0x%04x)\n", value, address); +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c new file mode 100644 index 000000000..9f90b3434 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c @@ -0,0 +1,56 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +/* This implements the hash that all the objects are stored within. +It is used to get the offset within RAMHT of a graphics object. + */ + +uint32_t nv3_ramht_hash(uint32_t name, uint32_t channel) +{ + // the official nvidia hash algorithm, tweaked for readability + uint32_t hash = ((name ^ (name >> 8) ^ (name >> 16) ^ (name >> 24)) & 0xFF) ^ (channel & NV3_DMA_CHANNELS_TOTAL); + + + // is this the right endianness? + nv_log_verbose_only("Generated RAMHT hash 0x%04x (RAMHT slot=0x%04x (from name 0x%08x for DMA channel 0x%04x)\n)\n", hash, (hash/8), name, channel); + return hash; +} + + +uint32_t nv3_ramht_read(uint32_t address) +{ + nv_log_verbose_only("RAMHT (Graphics object storage hashtable) Read (0x%04x), I DON'T BELIEVE THIS SHOULD EVER HAPPEN - RETURNING 0x00\n", address); + return 0x00; +} + +void nv3_ramht_write(uint32_t address, uint32_t value) +{ + nv_log_verbose_only("RAMHT (Graphics object storage hashtable) Write (0x%04x -> 0x%04x), I DON'T BELIEVE THIS SHOULD EVER HAPPEN - UNIMPLEMENTED\n", value, address); +} diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c new file mode 100644 index 000000000..142d746d2 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c @@ -0,0 +1,40 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +uint32_t nv3_ramro_read(uint32_t address) +{ + nv_log("BIG Problem: RAM Runout (invalid dma object submission) Read (0x%04x)\n", address); + return 0x00; +} + +void nv3_ramro_write(uint32_t address, uint32_t value) +{ + nv_log("BIG Problem: RAM Runout WRITE, OH CRAP!!!! (0x%04x -> 0x%04x)", value, address); +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_ptimer.c b/src/video/nv/nv3/subsystems/nv3_ptimer.c new file mode 100644 index 000000000..ab14be4f9 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_ptimer.c @@ -0,0 +1,227 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + + +nv_register_t ptimer_registers[] = { + { NV3_PTIMER_INTR, "PTIMER - Interrupt Status", NULL, NULL}, + { NV3_PTIMER_INTR_EN, "PTIMER - Interrupt Enable", NULL, NULL,}, + { NV3_PTIMER_NUMERATOR, "PTIMER - Numerator", NULL, NULL, }, + { NV3_PTIMER_DENOMINATOR, "PTIMER - Denominator", NULL, NULL, }, + { NV3_PTIMER_TIME_0_NSEC, "PTIMER - Time0", NULL, NULL, }, + { NV3_PTIMER_TIME_1_NSEC, "PTIMER - Time1", NULL, NULL, }, + { NV3_PTIMER_ALARM_NSEC, "PTIMER - Alarm", NULL, NULL, }, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +// ptimer init code +void nv3_ptimer_init(void) +{ + nv_log("Initialising PTIMER..."); + + nv_log("Done!\n"); +} + +// Handles the PTIMER alarm interrupt +void nv3_ptimer_interrupt(uint32_t num) +{ + nv3->ptimer.interrupt_status |= (1 << num); + + nv3_pmc_handle_interrupts(true); +} + +// Ticks the timer. +void nv3_ptimer_tick(double real_time) +{ + // prevent a divide by zero + if (nv3->ptimer.clock_numerator == 0 + || nv3->ptimer.clock_denominator == 0) + return; + + // get the current time + + // See Envytools. We need to use the frequency as a source. + // We need to figure out how many cycles actually occurred because this counts up every cycle... + // However it seems that their formula is wrong. I can't be bothered to figure out what's going on and, based on documentation from NVIDIA, + // timer_0 is meant to roll over every 4 seconds. Multiplying by 10 basically does the job. + + // Convert to microseconds + double freq_base = (real_time / 1000000.0f) / ((double)1.0 / nv3->nvbase.memory_clock_frequency) * 10.0f; + double current_time = freq_base * ((double)nv3->ptimer.clock_numerator) / (double)nv3->ptimer.clock_denominator; // *10.0? + + // truncate it + nv3->ptimer.time += (uint64_t)current_time; + + // Check if the alarm has actually triggered.. + // Only log on ptimer alarm. Otherwise, it's too much spam. + if (nv3->ptimer.time >= nv3->ptimer.alarm) + { + nv_log_verbose_only("PTIMER alarm interrupt fired (if interrupts enabled) because we reached TIME value 0x%08x\n", nv3->ptimer.alarm); + nv3_ptimer_interrupt(NV3_PTIMER_INTR_ALARM); + } +} + +uint32_t nv3_ptimer_read(uint32_t address) +{ + // always enabled + + nv_register_t* reg = nv_get_register(address, ptimer_registers, sizeof(ptimer_registers)/sizeof(ptimer_registers[0])); + + // Only log these when tehy actually tick + if (address != NV3_PTIMER_TIME_0_NSEC + && address != NV3_PTIMER_TIME_1_NSEC) + { + nv_log_verbose_only("PTIMER Read from 0x%08x", address); + } + + uint32_t ret = 0x00; + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + // Interrupt state: + // Bit 0: Alarm + + switch (reg->address) + { + case NV3_PTIMER_INTR: + ret = nv3->ptimer.interrupt_status; + break; + case NV3_PTIMER_INTR_EN: + ret = nv3->ptimer.interrupt_enable; + break; + case NV3_PTIMER_NUMERATOR: + ret = nv3->ptimer.clock_numerator; // 15:0 + break; + case NV3_PTIMER_DENOMINATOR: + ret = nv3->ptimer.clock_denominator ; //15:0 + break; + // 64-bit value + // High part + case NV3_PTIMER_TIME_0_NSEC: + ret = nv3->ptimer.time & 0xFFFFFFFF; //28:0 + break; + // Low part + case NV3_PTIMER_TIME_1_NSEC: + ret = nv3->ptimer.time >> 32; // 31:5 + break; + case NV3_PTIMER_ALARM_NSEC: + ret = nv3->ptimer.alarm; // 31:5 + break; + } + + } + //TIME0 and TIME1 produce too much log spam that slows everything down + if (reg->address != NV3_PTIMER_TIME_0_NSEC + && reg->address != NV3_PTIMER_TIME_1_NSEC) + { + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PTIMER Write 0x%08x -> 0x%08x", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\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; + + // Interrupt enablement state + case NV3_PTIMER_INTR_EN: + nv3->ptimer.interrupt_enable = value & 0x1; + break; + // nUMERATOR + case NV3_PTIMER_NUMERATOR: + nv3->ptimer.clock_numerator = value & 0xFFFF; // 15:0 + break; + case NV3_PTIMER_DENOMINATOR: + // prevent Div0 + if (!value) + value = 1; + + nv3->ptimer.clock_denominator = value & 0xFFFF; //15:0 + break; + // 64-bit value + // High part + case NV3_PTIMER_TIME_0_NSEC: + nv3->ptimer.time |= (value) & 0xFFFFFFE0; //28:0 + break; + // Low part + case NV3_PTIMER_TIME_1_NSEC: + nv3->ptimer.time |= ((uint64_t)(value & 0xFFFFFFE0) << 32); // 31:5 + break; + case NV3_PTIMER_ALARM_NSEC: + nv3->ptimer.alarm = value & 0xFFFFFFE0; // 31:5 + break; + } + } + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pvideo.c b/src/video/nv/nv3/subsystems/nv3_pvideo.c new file mode 100644 index 000000000..60019b9c6 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_pvideo.c @@ -0,0 +1,159 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + + +nv_register_t pvideo_registers[] = { + { NV3_PVIDEO_INTR, "PVIDEO - Interrupt Status", NULL, NULL}, + { NV3_PVIDEO_INTR_EN, "PVIDEO - Interrupt Enable", NULL, NULL,}, + { NV3_PVIDEO_FIFO_THRESHOLD, "PVIDEO - FIFO Fill Threshold", NULL, NULL}, + { NV3_PVIDEO_FIFO_BURST_LENGTH, "PVIDEO - FIFO Burst Length (1=32, 2=64, 3=128)", NULL, NULL}, + { NV3_PVIDEO_OVERLAY, "PVIDEO - Overlay Info (Bit0 = Video On, Bit4 = Key On, Bit8 = Format, 0=CCIR, 1=YUV2)", NULL, NULL }, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +// ptimer init code +void nv3_pvideo_init(void) +{ + 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])); + uint32_t ret = 0x00; + + // todo: friendly logging + + nv_log_verbose_only("PVIDEO Read from 0x%08x", address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + // Interrupt state: + // Bit 0 - Notifier + + switch (reg->address) + { + case NV3_PVIDEO_INTR: + ret = nv3->pvideo.interrupt_status; + break; + case NV3_PVIDEO_INTR_EN: + ret = nv3->pvideo.interrupt_enable; + break; + case NV3_PVIDEO_FIFO_THRESHOLD: + ret = nv3->pvideo.fifo_threshold; + break; + case NV3_PVIDEO_FIFO_BURST_LENGTH: + ret = nv3->pvideo.fifo_burst_size & 0x03; + break; + case NV3_PVIDEO_OVERLAY: + ret = nv3->pvideo.overlay_settings & 0xFF; + break; + + } + } + + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +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_verbose_only("PVIDEO Write 0x%08x -> 0x%08x\n", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\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; + case NV3_PVIDEO_FIFO_THRESHOLD: + // only bits 6:3 matter + nv3->pvideo.fifo_threshold = ((value >> 3) & 0x0F) << 3; + break; + case NV3_PVIDEO_FIFO_BURST_LENGTH: + nv3->pvideo.fifo_burst_size = value & 0x03; + break; + case NV3_PVIDEO_OVERLAY: + nv3->pvideo.overlay_settings = value & 0xFF; + break; + } + } + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_user.c b/src/video/nv/nv3/subsystems/nv3_user.c new file mode 100644 index 000000000..f10e28793 --- /dev/null +++ b/src/video/nv/nv3/subsystems/nv3_user.c @@ -0,0 +1,70 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * NV3 User Submission Area (NV_USER, conceptually considered "Cache1 Pusher") + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + + +// PIO Method Submission +// 128 channels conceptually supported - a hangover from nv1 where multiple windows all directly programming the gpu were supported? total lunacy. +uint32_t nv3_user_read(uint32_t address) +{ + // Get the address within the subchannel + //todo: print out the subchannel + uint8_t method_offset = (address & 0x1FFC); + + uint8_t channel = (address - NV3_USER_START) / 0x10000; + uint8_t subchannel = ((address - NV3_USER_START)) / 0x2000 % NV3_DMA_SUBCHANNELS_PER_CHANNEL; + + nv_log_verbose_only("User Submission Area PIO Channel %d.%d method_offset=0x%04x\n", channel, subchannel, method_offset); + + // 0x10 is free CACHE1 object + // TODO: THERE ARE OTHER STUFF! + switch (method_offset) + { + case NV3_SUBCHANNEL_PIO_IS_PFIFO_FREE: + return nv3_pfifo_cache1_num_free_spaces(); + case NV3_SUBCHANNEL_PIO_ALWAYS_ZERO_START ... NV3_SUBCHANNEL_PIO_ALWAYS_ZERO_END: + return 0x00; + + } + + nv_log("NV_USER READ: Channel FIELD NOT IMPLEMENTED!!!! offset=0x%04x\n", method_offset); + + return 0x00; +}; + +// Although NV3 doesn't have DMA mode unlike NV4 and later, it's conceptually similar to a "pusher" that pushes graphics commands that you write into CACHE1 that are then pulled out. +// So we send the writes here. This might do other stuff, so we keep this function +void nv3_user_write(uint32_t address, uint32_t value) +{ + nv3_pfifo_cache1_push(address, value); + + // This isn't ideal, but otherwise, the dynarec causes the GPU to write so many objects into CACHE1, it starts overwriting the old objects + // This basically makes the fifo not a fifo, but oh well + nv3_pfifo_cache1_pull(); +} \ No newline at end of file diff --git a/src/video/nv/nv4/nv4_core.c b/src/video/nv/nv4/nv4_core.c new file mode 100644 index 000000000..5712cf7d1 --- /dev/null +++ b/src/video/nv/nv4/nv4_core.c @@ -0,0 +1,388 @@ +/* + * 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 bringup and device emulation. + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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_nv4.h> + +nv4_t* nv4; + +// Stolen from Voodoo 3 +static video_timings_t timing_nv4_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; + +// 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; + } +} + + +bool 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"; + + /* Just hardcode full logging */ + + if (device_get_config_int("nv_debug_fulllog")) + nv4->nvbase.log = log_open(log_device_name); + else + nv4->nvbase.log = log_open_cyclic(log_device_name); + + nv_log_set_device(nv4->nvbase.log); + + nv4->nvbase.bus_generation = nv_bus_agp_2x; + + // Figure out which vbios the user selected + // This depends on the bus we are using and if the gpu is rev a/b or rev c + + const char* vbios_file = NV4_VBIOS_STB_REVA; + + int32_t err = rom_init(&nv4->nvbase.vbios, vbios_file, 0xC0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (err) + { + nv_log("NV4 FATAL: failed to load VBIOS err=%d\n", err); + fatal("Nvidia NV4 init failed: Somehow selected a nonexistent VBIOS? err=%d\n", err); + return false; + } + else + nv_log("Successfully loaded VBIOS located at %s\n", vbios_file); + + pci_add_card(PCI_ADD_AGP, nv4_pci_read, nv4_pci_write, NULL, &nv4->nvbase.pci_slot); + + svga_init(&nv4_device_agp, &nv4->nvbase.svga, nv4, nv4->nvbase.vram_amount, + nv4_recalc_timings, nv4_svga_read, nv4_svga_write, nv4_draw_cursor, NULL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv4_agp); + + // Setup clock information. These values don't matter, I pulled them out of an STB BIOS, we don't need to macro them + nv4->pramdac.nvclk = 0x17809; + nv4->pramdac.mclk = 0x1a30a; + nv4->pramdac.vclk = 0x1400c; + + //timer_add(nv4->pramdac.nvclk, ) + + + + nv4_init_mappings(); + //nv4_update_mappings(); + + return true; +} + +void* nv4_init_stb4400(const device_t *info) +{ + bool successful = nv4_init(); + + if (successful) + return nv4; + else + return NULL; +} + +void nv4_nvclk_tick() +{ + +} + +void nv4_mclk_tick() +{ + +} + +void nv4_vclk_tick() +{ + +} + +void nv4_close(void* priv) +{ + free(nv4); +} + +void nv4_speed_changed(void *priv) +{ + +} + +void nv4_draw_cursor(svga_t* svga, int32_t drawline) +{ + +} + + +// +// 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(); + } +} + + +// See if the bios rom is available. +int32_t nv4_available(void) +{ + return (rom_present(NV4_VBIOS_STB_REVA)); +} + +// NV4 (RIVA 128) +// AGP +// 8MB or 16MB VRAM +const device_t nv4_device_agp = +{ + .name = "nVIDIA RIVA TNT (STB Velocity 4400)", + .internal_name = "nv4_stb4400", + .flags = DEVICE_AGP, + .local = 0, + .init = nv4_init_stb4400, + .close = nv4_close, + .speed_changed = nv4_speed_changed, + .force_redraw = nv4_force_redraw, + .available = nv4_available, + .config = nv4_config, +}; diff --git a/src/video/nv/nv4/nv4_core_config.c b/src/video/nv/nv4/nv4_core_config.c new file mode 100644 index 000000000..2dd88eed6 --- /dev/null +++ b/src/video/nv/nv4/nv4_core_config.c @@ -0,0 +1,92 @@ +/* + * 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. + * + * Provides NV4 configuration + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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_nv4.h> + +const device_config_t nv4_config[] = +{ + // Memory configuration + { + .name = "vram_size", + .description = "VRAM Size", + .type = CONFIG_SELECTION, + .default_int = NV4_VRAM_SIZE_16MB, + .selection = + { + // I thought this was never released, but it seems that at least one was released: + // The card was called the "NEC G7AGK" + { + .description = "8 MB", + .value = NV4_VRAM_SIZE_8MB, + }, + + { + .description = "16 MB", + .value = NV4_VRAM_SIZE_16MB, + }, + } + + }, + // Multithreading configuration + { + + .name = "pgraph_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .default_int = 1, // todo: change later + .selection = + { + { + .description = "1 thread (Only use if issues appear with more threads)", + .value = 1, + }, + { + .description = "2 threads", + .value = 2, + }, + { + .description = "4 threads", + .value = 4, + }, + { + .description = "8 threads", + .value = 8, + }, + }, + }, +#ifndef RELEASE_BUILD + { + .name = "nv_debug_fulllog", + .description = "Disable Cyclical Lines Detection for nv_log (Use for getting full context at cost of VERY large log files)", + .type = CONFIG_BINARY, + .default_int = 0, + }, +#endif + { + .type = CONFIG_END + } +}; \ No newline at end of file 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..4c5aa5a40 --- /dev/null +++ b/src/video/nv/nv4/nv4_core_io.c @@ -0,0 +1,1283 @@ +/* + * 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) +{ + uint32_t ret = 0x00; + + if (addr >= NV4_PTIMER_START && addr <= NV4_PTIMER_END) + ret = nv4_ptimer_read(addr); + else if (addr >= NV4_PRAMDAC_START && addr <= NV4_PRAMDAC_END) + ret = nv4_pramdac_read(addr); + + #ifdef NV_LOG + nv_register_t reg = nv_get_register(addr, &nv4_registers, sizeof(nv4_registers)/sizeof(nv4_registers[0])); + + if (reg) + { + if (reg->on_read) + ret = reg->on_read(); + + nv_log_verbose_only("Register read from 0x%08x value=%08x", addr, ret); + + } + #endif + +} + +void nv4_mmio_arbitrate_write(uint32_t addr, uint32_t val) +{ + if (addr >= NV4_PTIMER_START && addr <= NV4_PTIMER_END) + nv4_ptimer_write(addr, val); + else if (addr >= NV4_PRAMDAC_START && addr <= NV4_PRAMDAC_END) + nv4_pramdac_write(addr, val); + + #ifdef NV_LOG + nv_register_t reg = nv_get_register(addr, &nv4_registers, sizeof(nv4_registers)/sizeof(nv4_registers[0])); + + if (reg) + { + if (reg->on_write) + reg->on_write(val); + + nv_log_verbose_only("Register write from 0x%08x value=%08x", addr, val); + + } + #endif +} + +// 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%08x 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) >> 16; // 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_BAR_RESERVED_START ... NV4_PBUS_PCI_BAR_RESERVED_END: + case NV4_PBUS_PCI_BAR0_UNUSED1: + case NV4_PBUS_PCI_BAR0_UNUSED2: + case NV4_PBUS_PCI_BAR1_UNUSED1: + case NV4_PBUS_PCI_BAR1_UNUSED2: + + ret = 0x00; // hard lock + 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 & 0xFF, 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 & 0xFF, val); + + nv4->nvbase.pci_config.pci_regs[addr] = val; + + switch (addr) + { + // standard pci command stuff + case NV4_PBUS_PCI_COMMAND: + nv4->nvbase.pci_config.pci_regs[PCI_REG_COMMAND_L] = val; + // actually update the mappings + nv4_update_mappings(); + break; + case NV4_PBUS_PCI_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 NV4_PBUS_PCI_STATUS: + nv4->nvbase.pci_config.pci_regs[PCI_REG_STATUS_L] = val | (NV4_PBUS_PCI_STATUS_66MHZ_CAPABLE << NV4_PBUS_PCI_STATUS_66MHZ); + break; + case NV4_PBUS_PCI_STATUS_2: + 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 + 3] << 24 | + nv4->nvbase.pci_config.pci_regs[NV4_PBUS_PCI_ROM + 2] << 16; + + // only bits 31;22 matter + //new_addr &= 0xFFC00000; + + // 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%x -> 0x%x\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; + } +} + + +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) + 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); +} diff --git a/src/video/nv/nv4/nv4_debug_register_list.c b/src/video/nv/nv4/nv4_debug_register_list.c new file mode 100644 index 000000000..32516be0c --- /dev/null +++ b/src/video/nv/nv4/nv4_debug_register_list.c @@ -0,0 +1,46 @@ +/* + * 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 debug register list + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/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> + +#ifdef NV_LOG + +nv_register_t nv4_registers[] = { + { NV4_PTIMER_INTR, "NV4 PTIMER - Interrupt Status", NULL, NULL}, + { NV4_PTIMER_INTR_EN, "NV4 PTIMER - Interrupt Enable", NULL, NULL,}, + { NV4_PTIMER_NUMERATOR, "NV4 PTIMER - Numerator", NULL, NULL, }, + { NV4_PTIMER_DENOMINATOR, "NV4 PTIMER - Denominator", NULL, NULL, }, + { NV4_PTIMER_TIME_0_NSEC, "NV4 PTIMER - Time0", NULL, NULL, }, + { NV4_PTIMER_TIME_1_NSEC, "NV4 PTIMER - Time1", NULL, NULL, }, + { NV4_PTIMER_ALARM_NSEC, "NV4 PTIMER - Alarm", NULL, NULL, }, + { NV4_PRAMDAC_VPLL_COEFF, "NV4 PRAMDAC - Pixel Clock Coefficient", NULL, NULL, }, + { NV4_PRAMDAC_NVPLL_COEFF, "NV4 PRAMDAC - GPU Core Clock Coefficient", NULL, NULL, }, + { NV4_PRAMDAC_MPLL_COEFF, "NV4 PRAMDAC - VRAM Clock Coefficient", NULL, NULL, }, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +#endif \ No newline at end of file diff --git a/src/video/nv/nv4/subsystems/nv4_pramdac.c b/src/video/nv/nv4/subsystems/nv4_pramdac.c new file mode 100644 index 000000000..0b8292796 --- /dev/null +++ b/src/video/nv/nv4/subsystems/nv4_pramdac.c @@ -0,0 +1,84 @@ +/* +* 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/Riva TNT - RAMDAC +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 starfrost +*/ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv4.h> + + +uint64_t nv4_pramdac_get_hz(uint32_t coeff, bool apply_divider) +{ + uint32_t m = coeff & 0xFF; + uint32_t n = (coeff >> 8) & 0xFF; + uint32_t p = (coeff >> 16) & 0x07; + + // Check clock base + uint32_t hz_base = (nv4->straps & (1 << NV4_STRAP_CRYSTAL)) ? 14318180 : 13500000; + uint32_t final_hz = (hz_base * n) / (m << p); + + // Check VCLK divider + + if (apply_divider) + { + if (nv4->pramdac.clk_coeff_select & (1 << NV4_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO)) + final_hz >>= 1; + } + + return final_hz; +} + +void nv4_pramdac_set_vclk() +{ + uint64_t final_hz = nv4_pramdac_get_hz(nv4->pramdac.nvclk, false); + + //TODO: Everything + if (nv4->nvbase.nv4_vclk_timer) + timer_set_delay_u64(nv4->nvbase.nv4_vclk_timer, final_hz / TIMER_USEC); + +} + +uint32_t nv4_pramdac_read(uint32_t address) +{ + uint32_t ret = 0x00; + + switch (address) + { + case NV4_PRAMDAC_VPLL_COEFF: // Pixel clock + ret = nv4->pramdac.vclk; + break; + case NV4_PRAMDAC_NVPLL_COEFF: // System clock + ret = nv4->pramdac.nvclk; + break; + case NV4_PRAMDAC_MPLL_COEFF: // Memory clock + ret = nv4->pramdac.mclk; + break; + + } +} + +void nv4_pramdac_write(uint32_t address, uint32_t data) +{ + +} diff --git a/src/video/nv/nv4/subsystems/nv4_ptimer.c b/src/video/nv/nv4/subsystems/nv4_ptimer.c new file mode 100644 index 000000000..29df0168b --- /dev/null +++ b/src/video/nv/nv4/subsystems/nv4_ptimer.c @@ -0,0 +1,227 @@ +/* + * 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. + * + * Nvidia RIVA TNT (NV4 architecture) - Timer emulation + * + * + * + * Authors: Connor Hyde, + * + * Copyright 2024-2025 starfrost + */ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> // DEPENDENT!!! +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv4.h> + +nv_register_t ptimer_registers[] = { + { NV4_PTIMER_INTR, "NV4 PTIMER - Interrupt Status", NULL, NULL}, + { NV4_PTIMER_INTR_EN, "NV4 PTIMER - Interrupt Enable", NULL, NULL,}, + { NV4_PTIMER_NUMERATOR, "NV4 PTIMER - Numerator", NULL, NULL, }, + { NV4_PTIMER_DENOMINATOR, "NV4 PTIMER - Denominator", NULL, NULL, }, + { NV4_PTIMER_TIME_0_NSEC, "NV4 PTIMER - Time0", NULL, NULL, }, + { NV4_PTIMER_TIME_1_NSEC, "NV4 PTIMER - Time1", NULL, NULL, }, + { NV4_PTIMER_ALARM_NSEC, "NV4 PTIMER - Alarm", NULL, NULL, }, + { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value +}; + +// ptimer init code +void nv4_ptimer_init(void) +{ + nv_log("Initialising PTIMER..."); + + nv_log("Done!\n"); +} + +// Handles the PTIMER alarm interrupt +void nv4_ptimer_interrupt(uint32_t num) +{ + nv4->ptimer.interrupt_status |= (1 << num); + + //todo + //nv4_pmc_handle_interrupts(true); +} + +// Ticks the timer. +void nv4_ptimer_tick(double real_time) +{ + // prevent a divide by zero + if (nv4->ptimer.clock_numerator == 0 + || nv4->ptimer.clock_denominator == 0) + return; + + // get the current time + + // See Envytools. We need to use the frequency as a source. + // We need to figure out how many cycles actually occurred because this counts up every cycle... + // However it seems that their formula is wrong. I can't be bothered to figure out what's going on and, based on documentation from NVIDIA, + // timer_0 is meant to roll over every 4 seconds. Multiplying by 10 basically does the job. + + // Convert to microseconds + double freq_base = (real_time / 1000000.0f) / ((double)1.0 / nv4->nvbase.memory_clock_frequency) * 10.0f; + double current_time = freq_base * ((double)nv4->ptimer.clock_numerator) / (double)nv4->ptimer.clock_denominator; // *10.0? + + // truncate it + nv4->ptimer.time += (uint64_t)current_time; + + // Check if the alarm has actually triggered.. + // Only log on ptimer alarm. Otherwise, it's too much spam. + if (nv4->ptimer.time >= nv4->ptimer.alarm) + { + nv_log_verbose_only("PTIMER alarm interrupt fired (if interrupts enabled) because we reached TIME value 0x%08x\n", nv4->ptimer.alarm); + nv4_ptimer_interrupt(NV4_PTIMER_INTR_ALARM); + } +} + +uint32_t nv4_ptimer_read(uint32_t address) +{ + // always enabled + + nv_register_t* reg = nv_get_register(address, ptimer_registers, sizeof(ptimer_registers)/sizeof(ptimer_registers[0])); + + // Only log these when tehy actually tick + if (address != NV4_PTIMER_TIME_0_NSEC + && address != NV4_PTIMER_TIME_1_NSEC) + { + nv_log_verbose_only("PTIMER Read from 0x%08x", address); + } + + uint32_t ret = 0x00; + + // if the register actually exists + if (reg) + { + // on-read function + if (reg->on_read) + ret = reg->on_read(); + else + { + // Interrupt state: + // Bit 0: Alarm + + switch (reg->address) + { + case NV4_PTIMER_INTR: + ret = nv4->ptimer.interrupt_status; + break; + case NV4_PTIMER_INTR_EN: + ret = nv4->ptimer.interrupt_enable; + break; + case NV4_PTIMER_NUMERATOR: + ret = nv4->ptimer.clock_numerator; // 15:0 + break; + case NV4_PTIMER_DENOMINATOR: + ret = nv4->ptimer.clock_denominator ; //15:0 + break; + // 64-bit value + // High part + case NV4_PTIMER_TIME_0: + ret = nv4->ptimer.time & 0xFFFFFFFF; //28:0 + break; + // Low part + case NV4_PTIMER_TIME_1: + ret = nv4->ptimer.time >> 32; // 31:5 + break; + case NV4_PTIMER_ALARM: + ret = nv4->ptimer.alarm; // 31:5 + break; + } + + } + //TIME0 and TIME1 produce too much log spam that slows everything down + if (reg->address != NV4_PTIMER_TIME_0_NSEC + && reg->address != NV4_PTIMER_TIME_1_NSEC) + { + if (reg->friendly_name) + nv_log_verbose_only(": 0x%08x <- %s\n", ret, reg->friendly_name); + else + nv_log_verbose_only("\n"); + } + } + else + { + nv_log(": Unknown register read (address=0x%08x), returning 0x00\n", address); + } + + return ret; +} + +void nv4_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_verbose_only("PTIMER Write 0x%08x -> 0x%08x", value, address); + + // if the register actually exists + if (reg) + { + if (reg->friendly_name) + nv_log_verbose_only(": %s\n", reg->friendly_name); + else + nv_log_verbose_only("\n"); + + // on-read function + if (reg->on_write) + reg->on_write(value); + else + { + switch (reg->address) + { + // Interrupt state: + // Bit 0 - Alarm + + case NV4_PTIMER_INTR: + nv4->ptimer.interrupt_status &= ~value; + //TODO nv4_pmc_clear_interrupts(); + break; + + // Interrupt enablement state + case NV4_PTIMER_INTR_EN: + nv4->ptimer.interrupt_enable = value & 0x1; + break; + // nUMERATOR + case NV4_PTIMER_NUMERATOR: + nv4->ptimer.clock_numerator = value & 0xFFFF; // 15:0 + break; + case NV4_PTIMER_DENOMINATOR: + // prevent Div0 + if (!value) + value = 1; + + nv4->ptimer.clock_denominator = value & 0xFFFF; //15:0 + break; + // 64-bit value + // High part + case NV4_PTIMER_TIME_0: + nv4->ptimer.time |= (value) & 0xFFFFFFE0; //28:0 + break; + // Low part + case NV4_PTIMER_TIME_1: + nv4->ptimer.time |= ((uint64_t)(value & 0xFFFFFFE0) << 32); // 31:5 + break; + case NV4_PTIMER_ALARM: + nv4->ptimer.alarm = value & 0xFFFFFFE0; // 31:5 + break; + } + } + } + else /* Completely unknown */ + { + nv_log(": Unknown register write (address=0x%08x)\n", address); + } +} \ No newline at end of file diff --git a/src/video/nv/nv_base.c b/src/video/nv/nv_base.c new file mode 100644 index 000000000..c7a83d5ad --- /dev/null +++ b/src/video/nv/nv_base.c @@ -0,0 +1,107 @@ +/* + * 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, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +// Common NV1/3/4... init +#define HAVE_STDARG_H // wtf is this crap +#include +#include +#include +#include +#include <86box/86box.h> +#ifndef RELEASE_BUILD +#include <86box/device.h> +#endif +#include <86box/log.h> + + +// Common logging +#ifdef ENABLE_NV_LOG +int nv_do_log = ENABLE_NV_LOG; + +// A bit of kludge so that in the future we can abstract this function acorss multiple generations of Nvidia GPUs +void* nv_log_device; +bool nv_log_full = false; + +void nv_log_set_device(void* device) +{ + // in case the cyclical logger doesn't show you the full context of what went on, you can enable this debug feature + #ifndef RELEASE_BUILD + if (device + && device_get_config_int("nv_debug_fulllog")) + { + nv_log_full = true; + } + #endif + + nv_log_device = device; +} + +void nv_log_internal(const char* fmt, va_list arg) +{ + if (!nv_log_device) + return; + + // If our debug config option is configured, full log. Otherwise log with cyclical detection. + if (nv_log_full) + log_out(nv_log_device, fmt, arg); + else + log_out_cyclic(nv_log_device, fmt, arg); + +} + +void nv_log(const char *fmt, ...) +{ + va_list arg; + + if (!nv_do_log) + return; + + va_start(arg, fmt); + nv_log_internal(fmt, arg); + va_end(arg); +} + +void nv_log_verbose_only(const char *fmt, ...) +{ + #ifdef ENABLE_NV_LOG_ULTRA + va_list arg; + + if (!nv_do_log) + return; + + va_start(arg, fmt); + nv_log_internal(fmt, arg); + va_end(arg); + #endif +} + +#else +void nv_log(const char *fmt, ...) +{ + +} + +void nv_log_verbose_only(const char *fmt, ...) +{ + +} + +void nv_log_set_device(void* device) +{ + +} +#endif \ No newline at end of file diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 4e76e150d..3ea8a0358 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -262,6 +262,13 @@ video_cards[] = { { .device = &compaq_voodoo_3_3500_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3500_se_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3500_si_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv1_device_edge2k, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv1_device_edge3k, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv3_device_agp, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv3_device_pci, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv3t_device_agp, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv3t_device_pci, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nv4_device_agp, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = NULL, .flags = VIDEO_FLAG_TYPE_NONE } // clang-format on }; diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index fe02b7811..7ee3d9ae7 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -675,7 +675,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) default: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) { - voodoo_log("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); + voodoo_log(": Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); } else { voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); }