From 46259aeb02f6196882130af3ca2cf58b5af6d274 Mon Sep 17 00:00:00 2001 From: blueshogun96 Date: Sat, 20 Jan 2018 15:44:07 -0800 Subject: [PATCH 01/37] Azurik 3D rendering fix (D3DDevice_LoadVertexShaderProgram) --- src/CxbxKrnl/EmuD3D8.cpp | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 1875319a5..62bf15a80 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -2742,6 +2742,8 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShader) LOG_FUNC_END; HRESULT hRet; + + g_CurrentVertexShader = Handle; if(VshHandleIsVertexShader(Handle)) { @@ -8967,7 +8969,36 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_LoadVertexShaderProgram) LOG_FUNC_ARG(Address) LOG_FUNC_END; - LOG_UNIMPLEMENTED(); + // NOTE: Azurik needs this to work, but this implementation makes + // Sonic Heroes (E3 Demo) run slower and look a bit worse. An investigation + // may be necessary... +#if 1 + DWORD Handle = g_CurrentVertexShader; + + // TODO: Cache vertex shaders? Azurik overwrites the same vertex shader + // slot over and over again with many different vertex shaders per frame... + if( VshHandleIsVertexShader(Handle) ) + { + X_D3DVertexShader *pD3DVertexShader = (X_D3DVertexShader *)(Handle & 0x7FFFFFFF); + VERTEX_SHADER *pVertexShader = (VERTEX_SHADER *)pD3DVertexShader->Handle; + + // Save the contents of the existing vertex shader program + DWORD* pDeclaration = (DWORD*) malloc( pVertexShader->DeclarationSize ); + memmove( pDeclaration, pVertexShader->pDeclaration, pVertexShader->DeclarationSize ); + + // Delete the vertex shader + EMUPATCH(D3DDevice_DeleteVertexShader)(Handle); + + // Re-create the vertex shader with the new code + HRESULT hr = EMUPATCH(D3DDevice_CreateVertexShader)( pDeclaration, pFunction, &Handle, 0 ); + free(pDeclaration); + if( FAILED( hr ) ) + CxbxKrnlCleanup( "Error re-creating vertex shader!" ); + + EMUPATCH(D3DDevice_LoadVertexShader)(Handle, Address); + EMUPATCH(D3DDevice_SelectVertexShader)(Handle, Address); + } +#endif } // ****************************************************************** From 4ee53eaa0d3016daae4e4f066efd673ada60fb83 Mon Sep 17 00:00:00 2001 From: blueshogun96 Date: Sat, 20 Jan 2018 15:53:23 -0800 Subject: [PATCH 02/37] Remove double slashes from file paths --- src/CxbxKrnl/EmuFile.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/CxbxKrnl/EmuFile.cpp b/src/CxbxKrnl/EmuFile.cpp index 2c95382c7..60f6b5b9e 100644 --- a/src/CxbxKrnl/EmuFile.cpp +++ b/src/CxbxKrnl/EmuFile.cpp @@ -331,6 +331,16 @@ void copy_string_to_PSTRING_to(std::string const & src, const xboxkrnl::PSTRING memcpy(dest->Buffer, src.c_str(), dest->Length); } +void replace_all(std::string& str, const std::string& from, const std::string& to) { + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} + NTSTATUS CxbxConvertFilePath( std::string RelativeXboxPath, OUT std::wstring &RelativeHostPath, @@ -423,6 +433,19 @@ NTSTATUS CxbxConvertFilePath( HostPath.append(1, '\\'); } + // Lastly, remove any '\\' sequences in the string (this should fix the problem with Azurik game saves) + replace_all( RelativePath, "\\\\", "\\" ); + + if (g_bPrintfOn) { + DbgPrintf("FILE: %s Corrected path...\n", aFileAPIName.c_str()); + printf(" Org:\"%s\"\n", OriginalPath.c_str()); + if (_strnicmp(HostPath.c_str(), CxbxBasePath.c_str(), CxbxBasePath.length()) == 0) { + printf(" New:\"$CxbxPath\\%s%s\"\n", (HostPath.substr(CxbxBasePath.length(), std::string::npos)).c_str(), RelativePath.c_str()); + } + else + printf(" New:\"$XbePath\\%s\"\n", RelativePath.c_str()); + } + if (g_bPrintfOn) { DbgPrintf("FILE: %s Corrected path...\n", aFileAPIName.c_str()); printf(" Org:\"%s\"\n", OriginalPath.c_str()); From 1a650f280e5259190c7a3108f6f28463380967bf Mon Sep 17 00:00:00 2001 From: blueshogun96 Date: Sat, 20 Jan 2018 16:10:07 -0800 Subject: [PATCH 03/37] Increase stack reserve and commit size (stops Azurik from crashing during FMVs in release mode) --- build/win32/Cxbx.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index c5b271a41..7b40d273d 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -171,6 +171,8 @@ 0x10000 true true + 65536 + 65536 true From cd6813131d19139747e225464ccfa219fdd83952 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Sun, 21 Jan 2018 14:41:43 +0000 Subject: [PATCH 04/37] Disable new color conversion As much as I hate to do this, it is currently causing crashes in titles that use P8 format textures. It will be restored once this (and other related issues) are resolved. --- src/CxbxKrnl/EmuD3D8/Convert.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/CxbxKrnl/EmuD3D8/Convert.h diff --git a/src/CxbxKrnl/EmuD3D8/Convert.h b/src/CxbxKrnl/EmuD3D8/Convert.h old mode 100644 new mode 100755 index b16a86521..b148609fc --- a/src/CxbxKrnl/EmuD3D8/Convert.h +++ b/src/CxbxKrnl/EmuD3D8/Convert.h @@ -36,7 +36,12 @@ #include "CxbxKrnl.h" -//#define OLD_COLOR_CONVERSION + +// It's a real shame but the new conversion code needs to be disable for now +// it causes crashes and other issues in titles using palletted textures +// It seems draw time conversion is really required before this can function +// correctly. +#define OLD_COLOR_CONVERSION // simple render state encoding lookup table #define X_D3DRSSE_UNK 0x7fffffff From c16f94f27371a81a1bf5b23d91e72e8ca43e928b Mon Sep 17 00:00:00 2001 From: ergo720 Date: Sun, 21 Jan 2018 20:08:12 +0100 Subject: [PATCH 05/37] HalInitiateShutDown implementation --- src/CxbxKrnl/CxbxKrnl.cpp | 9 +++++++++ src/CxbxKrnl/CxbxKrnl.h | 3 +++ src/CxbxKrnl/EmuKrnlHal.cpp | 4 ++-- src/CxbxKrnl/SMCDevice.cpp | 13 ++++++++++--- src/CxbxKrnl/SMCDevice.h | 9 ++++++++- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 29eb29666..c94c01044 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -1264,6 +1264,15 @@ void CxbxKrnlResume() g_bEmuSuspended = false; } +void CxbxKrnlShutDown() +{ + if (CxbxKrnl_hEmuParent != NULL) + SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0); + + EmuShared::Cleanup(); + TerminateProcess(g_CurrentProcessHandle, 0); +} + __declspec(noreturn) void CxbxKrnlTerminateThread() { TerminateThread(GetCurrentThread(), 0); diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index 7fd8bf3b5..1cf9fcf81 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -183,6 +183,9 @@ void CxbxKrnlSuspend(); /*! resume emulation */ void CxbxKrnlResume(); +/*! terminate gracefully the emulation */ +void CxbxKrnlShutDown(); + /*! terminate the calling thread */ __declspec(noreturn) void CxbxKrnlTerminateThread(); diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index 928172b02..3a60daac8 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -698,8 +698,8 @@ XBSYSAPI EXPORTNUM(360) xboxkrnl::NTSTATUS NTAPI xboxkrnl::HalInitiateShutdown ) { LOG_FUNC(); - - LOG_UNIMPLEMENTED(); + + xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, SMC_COMMAND_RESET, 0, SMC_RESET_ASSERT_SHUTDOWN); RETURN(S_OK); } diff --git a/src/CxbxKrnl/SMCDevice.cpp b/src/CxbxKrnl/SMCDevice.cpp index 2520f24c7..c4371329c 100644 --- a/src/CxbxKrnl/SMCDevice.cpp +++ b/src/CxbxKrnl/SMCDevice.cpp @@ -41,6 +41,7 @@ namespace xboxkrnl #include // For xbox.h:AV_PACK_HDTV }; +#include "CxbxKrnl.h" #include "EmuShared.h" #include "SMCDevice.h" // For SMCDevice #include "LED.h" @@ -164,7 +165,13 @@ void SMCDevice::WriteByte(uint8_t command, uint8_t value) if (value == 0) // Note : MAME Xbox/Chihiro driver doesn't check for zero m_PICVersionStringIndex = 0; return; - //0x02 reset and power off control + case SMC_COMMAND_RESET: //0x02 reset and power off control + // See http://xboxdevwiki.net/PIC#Reset_and_Power_Off + switch (value) { + case SMC_RESET_ASSERT_RESET: return; //TODO + case SMC_RESET_ASSERT_POWERCYCLE: return; //TODO + case SMC_RESET_ASSERT_SHUTDOWN: CxbxKrnlShutDown(); return; // Power off, terminating the emulation + } //0x05 power fan mode(0 = automatic; 1 = custom speed from reg 0x06) //0x06 power fan speed(0..~50) case SMC_COMMAND_LED_MODE: // 0x07 LED mode(0 = automatic; 1 = custom sequence from reg 0x08) @@ -175,9 +182,9 @@ void SMCDevice::WriteByte(uint8_t command, uint8_t value) // Notes from https://github.com/ergo720/Cxbx-Reloaded/blob/LED/src/CxbxKrnl/EmuKrnlHal.cpp#L572 // // HalWriteSMBusValue(0x20, 0x08, false, x) and then HalWriteSMBusValue(0x20, 0x07, false, y > 1) - // will cause the led to be solid green, with the next pair of + // will cause the led to be solid green, while the next pair of // HalWriteSMBusValue with arbitrary y will cause the led to assume the color of the sequence x - // and afterwards this will repeat with whatever y; ntstatus are always 0 + // and afterwards this will repeat with whatever y; ntstatus is always 0 // // TODO : Implement the above, SMB_GLOBAL_STATUS should probably get the GS_PRERR_STS flag. But how? return; diff --git a/src/CxbxKrnl/SMCDevice.h b/src/CxbxKrnl/SMCDevice.h index d7147f160..dd0cfabbb 100644 --- a/src/CxbxKrnl/SMCDevice.h +++ b/src/CxbxKrnl/SMCDevice.h @@ -74,7 +74,7 @@ // //Command Description //0x01 PIC version string counter reset -//0x02 reset and power off control +#define SMC_COMMAND_RESET 0x02 //0x02 reset and power off control //0x05 power fan mode(0 = automatic; 1 = custom speed from reg 0x06) //0x06 power fan speed(0..~50) #define SMC_COMMAND_LED_MODE 0x07 // LED mode(0 = automatic; 1 = custom sequence from reg 0x08) @@ -87,6 +87,13 @@ //0x20 response to PIC challenge(written first) //0x21 response to PIC challenge(written second) +// +// Register values for SMC_COMMAND_RESET +// +#define SMC_RESET_ASSERT_RESET 0x01 +#define SMC_RESET_ASSERT_POWERCYCLE 0x40 +#define SMC_RESET_ASSERT_SHUTDOWN 0x80 + typedef enum { // TODO : Move to it's own file Revision1_0, Revision1_1, From afa4e4034d0c3b88b11867d55a640c2e99885969 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sun, 21 Jan 2018 22:20:38 +0100 Subject: [PATCH 06/37] The NV2A is now registered as a hardware device, just like all other devices. Like the NVNet device, it's implementation is currently just a forward to the existing code. Still, this removes a dependency from EmuX86 on the NV2A device - from now on it's reached via the generic device framework. --- build/win32/Cxbx.vcxproj | 2 + build/win32/Cxbx.vcxproj.filters | 6 ++ src/CxbxKrnl/CxbxKrnl.cpp | 3 - src/CxbxKrnl/EmuX86.cpp | 17 +--- src/CxbxKrnl/Xbox.cpp | 4 + src/CxbxKrnl/devices/video/nv2a.cpp | 122 ++++++++++++++++++++++++++++ src/CxbxKrnl/devices/video/nv2a.h | 54 ++++++++++++ 7 files changed, 190 insertions(+), 18 deletions(-) create mode 100644 src/CxbxKrnl/devices/video/nv2a.cpp create mode 100644 src/CxbxKrnl/devices/video/nv2a.h diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index c5b271a41..5074bfe6d 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -190,6 +190,7 @@ + @@ -359,6 +360,7 @@ + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 53da67549..546c0b4c5 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -226,6 +226,9 @@ Hardware + + Hardware + @@ -441,6 +444,9 @@ Hardware + + Hardware + diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 29eb29666..70d63a912 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -1017,9 +1017,6 @@ __declspec(noreturn) void CxbxKrnlInit // Now the hardware devices exist, couple the EEPROM buffer to it's device g_EEPROM->SetEEPROM((uint8_t*)EEPROM); - // Always initialise NV2A: We may need it for disabled HLE patches too! - EmuNV2A_Init(); - if (bLLE_GPU) { DbgPrintf("INIT: Initializing OpenGL.\n"); diff --git a/src/CxbxKrnl/EmuX86.cpp b/src/CxbxKrnl/EmuX86.cpp index 379eba313..15bc5c9ff 100644 --- a/src/CxbxKrnl/EmuX86.cpp +++ b/src/CxbxKrnl/EmuX86.cpp @@ -47,10 +47,8 @@ #include "mnemonics.h" #include "CxbxKrnl.h" -#include "Emu.h" +#include "Emu.h" // For EmuWarning #include "EmuX86.h" -#include "EmuNV2A.h" -#include "EmuNVNet.h" #include "HLEIntercept.h" // for bLLE_GPU #include @@ -177,11 +175,7 @@ uint32_t EmuX86_Read(xbaddr addr, int size) uint32_t value; - if (addr >= NV2A_ADDR && addr < NV2A_ADDR + NV2A_SIZE) { - // Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU) - value = EmuNV2A_Read(addr - NV2A_ADDR, size); - // Note : EmuNV2A_Read does it's own logging - } else if (addr >= XBOX_FLASH_ROM_BASE) { // 0xFFF00000 - 0xFFFFFFF + if (addr >= XBOX_FLASH_ROM_BASE) { // 0xFFF00000 - 0xFFFFFFF value = EmuFlash_Read32(addr - XBOX_FLASH_ROM_BASE); // TODO : Make flash access size-aware } else { // Pass the Read to the PCI Bus, this will handle devices with BARs set to MMIO addresses @@ -211,13 +205,6 @@ void EmuX86_Write(xbaddr addr, uint32_t value, int size) return; } - if (addr >= NV2A_ADDR && addr < NV2A_ADDR + NV2A_SIZE) { - // Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU) - EmuNV2A_Write(addr - NV2A_ADDR, value, size); - // Note : EmuNV2A_Write does it's own logging - return; - } - if (addr >= XBOX_FLASH_ROM_BASE) { // 0xFFF00000 - 0xFFFFFFF EmuWarning("EmuX86_Write(0x%08X, 0x%08X) [FLASH_ROM]", addr, value); return; diff --git a/src/CxbxKrnl/Xbox.cpp b/src/CxbxKrnl/Xbox.cpp index 2e6c4c10e..e354bbb4b 100644 --- a/src/CxbxKrnl/Xbox.cpp +++ b/src/CxbxKrnl/Xbox.cpp @@ -40,12 +40,14 @@ #include "SMCDevice.h" // For SMCDevice #include "EEPROMDevice.h" // For EEPROMDevice #include "EmuNVNet.h" // For NVNetDevice +#include "devices\video\nv2a.h" // For NV2ADevice PCIBus* g_PCIBus; SMBus* g_SMBus; SMCDevice* g_SMC; EEPROMDevice* g_EEPROM; NVNetDevice* g_NVNet; +NV2ADevice* g_NV2A; #define SMBUS_TV_ENCODER_ID_CONEXANT 0x8A // = Write; Read = 08B #define SMBUS_TV_ENCODER_ID_FOCUS 0xD4 // = Write; Read = 0D5 @@ -57,12 +59,14 @@ void InitXboxHardware() g_SMC = new SMCDevice(Revision1_1); // TODO : Make configurable g_EEPROM = new EEPROMDevice(); g_NVNet = new NVNetDevice(); + g_NV2A = new NV2ADevice(); g_SMBus->ConnectDevice(SMBUS_SMC_SLAVE_ADDRESS, g_SMC); g_SMBus->ConnectDevice(SMBUS_EEPROM_ADDRESS, g_EEPROM); g_PCIBus->ConnectDevice(PCI_DEVID(0, PCI_DEVFN(1, 1)), g_SMBus); g_PCIBus->ConnectDevice(PCI_DEVID(0, PCI_DEVFN(4, 0)), g_NVNet); + g_PCIBus->ConnectDevice(PCI_DEVID(1, PCI_DEVFN(0, 0)), g_NV2A); // TODO : Handle other SMBUS Addresses, like PIC_ADDRESS, XCALIBUR_ADDRESS // Resources : http://pablot.com/misc/fancontroller.cpp diff --git a/src/CxbxKrnl/devices/video/nv2a.cpp b/src/CxbxKrnl/devices/video/nv2a.cpp new file mode 100644 index 000000000..3ea6c6972 --- /dev/null +++ b/src/CxbxKrnl/devices/video/nv2a.cpp @@ -0,0 +1,122 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * src->devices->video->nv2a.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2017-2018 Luke Usher +// * (c) 2018 Patrick van Logchem +// * +// * All rights reserved +// * +// ****************************************************************** +#define _XBOXKRNL_DEFEXTRN_ + +#define LOG_PREFIX "NV2A" + +#include "../../CxbxKrnl/CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc +#include "../../CxbxKrnl/EmuNV2A.h" // For now, use EmuNV2A + +#include "nv2a.h" + +/* NV2ADevice */ + +// PCI Device functions + +void NV2ADevice::Init() +{ + PCIBarRegister r; + + // Register Memory bar : + r.Raw.type = PCI_BAR_TYPE_MEMORY; + r.Memory.address = NV2A_ADDR >> 4; + RegisterBAR(0, NV2A_SIZE, r.value); + + // Register physical memory on bar 1 + r.Memory.address = 0; + RegisterBAR(1, XBOX_MEMORY_SIZE, r.value); // TODO : Read g_PhysicalMemory->Size + + m_DeviceId = 0x02A5; + m_VendorId = PCI_VENDOR_ID_NVIDIA; + + // For now, forward to EmuNv2A + EmuNV2A_Init(); +} + +void NV2ADevice::Reset() +{ +} + +uint32_t NV2ADevice::IORead(int barIndex, uint32_t port, unsigned size) +{ + return 0; +} + +void NV2ADevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) +{ +} + +uint32_t NV2ADevice::MMIORead(int barIndex, uint32_t addr, unsigned size) +{ + switch (barIndex) { + case 0: + uint32_t value; + // For now, forward to EmuNV2A + { + // Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU) + value = EmuNV2A_Read(addr, size); + // Note : EmuNV2A_Read does it's own logging + } + // TODO : call block handler + return value; + case 1: + return 0; // TODO : access physical memory + } + + // TODO : Log unexpected bar access + return 0; +} + +void NV2ADevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) +{ + switch (barIndex) { + case 0: + // For now, forward to EmuNV2A + { + // Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU) + EmuNV2A_Write(addr, value, size); + // Note : EmuNV2A_Write does it's own logging + } + // TODO : call block handler + return; + case 1: + // TODO : access physical memory + return; + } + + // TODO : Log unexpected bar access +} diff --git a/src/CxbxKrnl/devices/video/nv2a.h b/src/CxbxKrnl/devices/video/nv2a.h new file mode 100644 index 000000000..be6c90324 --- /dev/null +++ b/src/CxbxKrnl/devices/video/nv2a.h @@ -0,0 +1,54 @@ +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * src->devices->video->nv2a.h +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2017-2018 Luke Usher +// * (c) 2018 Patrick van Logchem +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +#include "../../CxbxKrnl/PCIDevice.h" // For PCIDevice + +#define NV2A_ADDR 0xFD000000 +#define NV2A_SIZE 0x01000000 + +class NV2ADevice : public PCIDevice { +public: + // PCI Device functions + void Init(); + void Reset(); + + uint32_t IORead(int barIndex, uint32_t port, unsigned size); + void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size); + uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size); + void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size); +}; + +extern NV2ADevice* g_NV2A; From 1e5d7ffede7ae94c934ac1c4577ef8e662d806c6 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sun, 21 Jan 2018 23:50:30 +0100 Subject: [PATCH 07/37] Simplified LED encoding and drawing code - Ergo720's LED_MultiColor.xbe actually flashes the LED correctly now! --- src/Cxbx/WndMain.cpp | 141 ++++++++++++++----------------------- src/Cxbx/WndMain.h | 10 +-- src/CxbxKrnl/SMCDevice.cpp | 25 ++----- 3 files changed, 62 insertions(+), 114 deletions(-) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index d9d944bf8..db200becb 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -375,14 +375,14 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP m_yBmp = GetSystemMetrics(SM_CYMENUCHECK); m_LedDC = CreateCompatibleDC(hDC); m_LedBmp = CreateCompatibleBitmap(hDC, m_xBmp, m_yBmp); - m_BrushBlack = CreateSolidBrush(RGB(0, 0, 0)); - m_BrushRed = CreateSolidBrush(RGB(255, 0, 0)); - m_BrushGreen = CreateSolidBrush(RGB(0, 255, 0)); - m_BrushOrange = CreateSolidBrush(RGB(255, 165, 0)); - m_PenBlack = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); - m_PenRed = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); - m_PenGreen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0)); - m_PenOrange = CreatePen(PS_SOLID, 1, RGB(255, 165, 0)); + m_Brushes[XBOX_LED_COLOUR_OFF] = CreateSolidBrush(RGB(0, 0, 0)); + m_Brushes[XBOX_LED_COLOUR_GREEN] = CreateSolidBrush(RGB(0, 255, 0)); + m_Brushes[XBOX_LED_COLOUR_RED] = CreateSolidBrush(RGB(255, 0, 0)); + m_Brushes[XBOX_LED_COLOUR_ORANGE] = CreateSolidBrush(RGB(255, 165, 0)); + m_Pens[XBOX_LED_COLOUR_OFF] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); + m_Pens[XBOX_LED_COLOUR_GREEN] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0)); + m_Pens[XBOX_LED_COLOUR_RED] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); + m_Pens[XBOX_LED_COLOUR_ORANGE] = CreatePen(PS_SOLID, 1, RGB(255, 165, 0)); DrawLedBitmap(hwnd, true); } @@ -1305,21 +1305,21 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP DeleteObject(m_LedBmp); - DeleteObject(m_BrushBlack); + DeleteObject(m_Brushes[XBOX_LED_COLOUR_OFF]); - DeleteObject(m_BrushRed); + DeleteObject(m_Brushes[XBOX_LED_COLOUR_GREEN]); - DeleteObject(m_BrushGreen); + DeleteObject(m_Brushes[XBOX_LED_COLOUR_RED]); - DeleteObject(m_BrushOrange); + DeleteObject(m_Brushes[XBOX_LED_COLOUR_ORANGE]); - DeleteObject(m_PenBlack); + DeleteObject(m_Pens[XBOX_LED_COLOUR_OFF]); - DeleteObject(m_PenRed); + DeleteObject(m_Pens[XBOX_LED_COLOUR_GREEN]); - DeleteObject(m_PenGreen); + DeleteObject(m_Pens[XBOX_LED_COLOUR_RED]); - DeleteObject(m_PenOrange); + DeleteObject(m_Pens[XBOX_LED_COLOUR_ORANGE]); ReleaseDC(hwnd, hDC); @@ -2105,88 +2105,53 @@ void WndMain::CrashMonitor() void WndMain::DrawLedBitmap(HWND hwnd, bool bdefault) { HMENU hMenu = GetMenu(hwnd); - if (bdefault) // draw default black bitmap - { - SelectObject(m_LedDC, m_BrushBlack); - SelectObject(m_LedDC, m_PenBlack); - m_OriLed = (HBITMAP)SelectObject(m_LedDC, m_LedBmp); - Rectangle(m_LedDC, 0, 0, m_xBmp, m_yBmp); - m_LedBmp = (HBITMAP)SelectObject(m_LedDC, m_OriLed); - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_BITMAP | MIIM_FTYPE; - mii.fType = MFT_RIGHTJUSTIFY; - mii.hbmpItem = m_LedBmp; - SetMenuItemInfo(hMenu, ID_LED, FALSE, &mii); - DrawMenuBar(hwnd); + int ActiveLEDColor; + + // When so requested, or when not emulating, draw a black bitmap + if (bdefault || !m_bIsStarted) { + ActiveLEDColor = XBOX_LED_COLOUR_OFF; } - else // draw colored bitmap - { + else { // draw colored bitmap + static int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; static int LedSequenceOffset = 0; + bool bLedHasChanged; - int LedSequence[4]; g_EmuShared->GetLedStatus(&bLedHasChanged); - g_EmuShared->GetLedSequence(LedSequence); - if (bLedHasChanged) - { - LedSequenceOffset = 0; + if (bLedHasChanged) { + // To prevent restarting the sequence when identical sequences are set, check if the new sequence is actually different + int NewLedSequence[4]; + g_EmuShared->GetLedSequence(NewLedSequence); + if (LedSequence[0] != NewLedSequence[0] || LedSequence[1] != NewLedSequence[1] || LedSequence[2] != NewLedSequence[2] || LedSequence[3] != NewLedSequence[3]) { + // Only when the new sequence is different, restart it's cycle + g_EmuShared->GetLedSequence(LedSequence); + LedSequenceOffset = 0; + } + // Indicate we've handled the change bLedHasChanged = false; g_EmuShared->SetLedStatus(&bLedHasChanged); } - m_OriLed = (HBITMAP)SelectObject(m_LedDC, m_LedBmp); - Rectangle(m_LedDC, 0, 0, m_xBmp, m_yBmp); - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_BITMAP | MIIM_FTYPE; - mii.fType = MFT_RIGHTJUSTIFY; - mii.hbmpItem = m_LedBmp; - - switch (LedSequence[LedSequenceOffset]) - { - case XBOX_LED_COLOUR_RED: - { - SelectObject(m_LedDC, m_BrushRed); - SelectObject(m_LedDC, m_PenRed); - } - break; - - case XBOX_LED_COLOUR_GREEN: - { - SelectObject(m_LedDC, m_BrushGreen); - SelectObject(m_LedDC, m_PenGreen); - } - break; - - case XBOX_LED_COLOUR_ORANGE: - { - SelectObject(m_LedDC, m_BrushOrange); - SelectObject(m_LedDC, m_PenOrange); - } - break; - - case XBOX_LED_COLOUR_OFF: - { - SelectObject(m_LedDC, m_BrushBlack); - SelectObject(m_LedDC, m_PenBlack); - } - break; - } - - m_LedBmp = (HBITMAP)SelectObject(m_LedDC, m_OriLed); - if (LedSequenceOffset == 3) - { - LedSequenceOffset = 0; - } - else - { - ++LedSequenceOffset; - } - SetMenuItemInfo(hMenu, ID_LED, FALSE, &mii); - - DrawMenuBar(hwnd); + // Select active color and cycle through all 4 phases in the sequence + ActiveLEDColor = LedSequence[LedSequenceOffset & 3]; + ++LedSequenceOffset; } + SelectObject(m_LedDC, m_Brushes[ActiveLEDColor]); + SelectObject(m_LedDC, m_Pens[ActiveLEDColor]); + + m_OriLed = (HBITMAP)SelectObject(m_LedDC, m_LedBmp); + Rectangle(m_LedDC, 0, 0, m_xBmp, m_yBmp); + m_LedBmp = (HBITMAP)SelectObject(m_LedDC, m_OriLed); + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_BITMAP; + mii.fType = MFT_RIGHTJUSTIFY; + mii.hbmpItem = m_LedBmp; + SetMenuItemInfo(hMenu, ID_LED, FALSE, &mii); + + DrawMenuBar(hwnd); + return; } diff --git a/src/Cxbx/WndMain.h b/src/Cxbx/WndMain.h index 5a5a70183..04ce46bef 100644 --- a/src/Cxbx/WndMain.h +++ b/src/Cxbx/WndMain.h @@ -151,14 +151,8 @@ class WndMain : public Wnd HBITMAP m_LogoBmp; HBITMAP m_GameLogoBMP; HBITMAP m_LedBmp; - HBRUSH m_BrushBlack; - HBRUSH m_BrushRed; - HBRUSH m_BrushGreen; - HBRUSH m_BrushOrange; - HPEN m_PenBlack; - HPEN m_PenRed; - HPEN m_PenGreen; - HPEN m_PenOrange; + HBRUSH m_Brushes[4]; + HPEN m_Pens[4]; int m_xBmp, m_yBmp; // ****************************************************************** diff --git a/src/CxbxKrnl/SMCDevice.cpp b/src/CxbxKrnl/SMCDevice.cpp index c4371329c..98934fa79 100644 --- a/src/CxbxKrnl/SMCDevice.cpp +++ b/src/CxbxKrnl/SMCDevice.cpp @@ -52,26 +52,15 @@ void SetLEDSequence(LED::Sequence aLEDSequence) DbgPrintf("SMC : SetLEDSequence : %u\n", (byte)aLEDSequence); bool bLedHasChanged = true; + int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; - if (aLEDSequence == LED::GREEN) // Automatic solid green color - { - int LedSequence[4] = { XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN }; + LedSequence[0] = ((aLEDSequence >> 6) & 2) | ((aLEDSequence >> 3) & 1); + LedSequence[1] = ((aLEDSequence >> 5) & 2) | ((aLEDSequence >> 2) & 1); + LedSequence[2] = ((aLEDSequence >> 4) & 2) | ((aLEDSequence >> 1) & 1); + LedSequence[3] = ((aLEDSequence >> 3) & 2) | ((aLEDSequence >> 0) & 1); - g_EmuShared->SetLedStatus(&bLedHasChanged); - g_EmuShared->SetLedSequence(LedSequence); - } - else // Draw the color represented by the sequence obtained - { - int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; - - LedSequence[0] = ((aLEDSequence >> 3) & 1) | ((aLEDSequence >> 6) & 2); - LedSequence[1] = ((aLEDSequence >> 2) & 1) | ((aLEDSequence >> 5) & 2); - LedSequence[2] = ((aLEDSequence >> 1) & 1) | ((aLEDSequence >> 4) & 2); - LedSequence[3] = (aLEDSequence & 1) | ((aLEDSequence >> 3) & 2); - - g_EmuShared->SetLedStatus(&bLedHasChanged); - g_EmuShared->SetLedSequence(LedSequence); - } + g_EmuShared->SetLedStatus(&bLedHasChanged); + g_EmuShared->SetLedSequence(LedSequence); } /* SMCDevice */ From 33d3dc418e92b1f7bca03262e78e799e5b9016d9 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Mon, 22 Jan 2018 00:16:01 +0100 Subject: [PATCH 08/37] All hardware devices are moved outside CxbxKrnl, towards devices (some into devices\video) --- build/win32/Cxbx.vcxproj | 45 +- build/win32/Cxbx.vcxproj.filters | 119 +- src/CxbxKrnl/CxbxKrnl.cpp | 6 +- src/CxbxKrnl/EmuKrnlHal.cpp | 6 +- src/CxbxKrnl/EmuX86.cpp | 2 +- src/{CxbxKrnl => devices}/EEPROMDevice.cpp | 0 src/{CxbxKrnl => devices}/EEPROMDevice.h | 0 src/{CxbxKrnl => devices}/EmuNVNet.cpp | 7 +- src/{CxbxKrnl => devices}/EmuNVNet.h | 0 src/{CxbxKrnl => devices}/LED.h | 0 src/{CxbxKrnl => devices}/PCIBus.cpp | 0 src/{CxbxKrnl => devices}/PCIBus.h | 0 src/{CxbxKrnl => devices}/PCIDevice.cpp | 0 src/{CxbxKrnl => devices}/PCIDevice.h | 0 src/{CxbxKrnl => devices}/SMBus.cpp | 0 src/{CxbxKrnl => devices}/SMBus.h | 0 src/{CxbxKrnl => devices}/SMCDevice.cpp | 5 +- src/{CxbxKrnl => devices}/SMCDevice.h | 0 src/{CxbxKrnl => devices}/SMDevice.cpp | 0 src/{CxbxKrnl => devices}/SMDevice.h | 0 src/{CxbxKrnl => devices}/Xbox.cpp | 0 src/{CxbxKrnl => devices}/Xbox.h | 0 src/{CxbxKrnl => devices/video}/EmuNV2A.cpp | 7523 ++++++++++--------- src/{CxbxKrnl => devices/video}/EmuNV2A.h | 0 src/{CxbxKrnl => }/devices/video/nv2a.cpp | 4 +- src/{CxbxKrnl => }/devices/video/nv2a.h | 2 +- src/{CxbxKrnl => devices/video}/nv2a_int.h | 0 src/{CxbxKrnl => devices/video}/vga.h | 0 28 files changed, 3863 insertions(+), 3856 deletions(-) rename src/{CxbxKrnl => devices}/EEPROMDevice.cpp (100%) rename src/{CxbxKrnl => devices}/EEPROMDevice.h (100%) rename src/{CxbxKrnl => devices}/EmuNVNet.cpp (99%) rename src/{CxbxKrnl => devices}/EmuNVNet.h (100%) rename src/{CxbxKrnl => devices}/LED.h (100%) rename src/{CxbxKrnl => devices}/PCIBus.cpp (100%) rename src/{CxbxKrnl => devices}/PCIBus.h (100%) rename src/{CxbxKrnl => devices}/PCIDevice.cpp (100%) rename src/{CxbxKrnl => devices}/PCIDevice.h (100%) rename src/{CxbxKrnl => devices}/SMBus.cpp (100%) rename src/{CxbxKrnl => devices}/SMBus.h (100%) rename src/{CxbxKrnl => devices}/SMCDevice.cpp (99%) rename src/{CxbxKrnl => devices}/SMCDevice.h (100%) rename src/{CxbxKrnl => devices}/SMDevice.cpp (100%) rename src/{CxbxKrnl => devices}/SMDevice.h (100%) rename src/{CxbxKrnl => devices}/Xbox.cpp (100%) rename src/{CxbxKrnl => devices}/Xbox.h (100%) rename src/{CxbxKrnl => devices/video}/EmuNV2A.cpp (96%) rename src/{CxbxKrnl => devices/video}/EmuNV2A.h (100%) rename src/{CxbxKrnl => }/devices/video/nv2a.cpp (96%) rename src/{CxbxKrnl => }/devices/video/nv2a.h (97%) rename src/{CxbxKrnl => devices/video}/nv2a_int.h (100%) rename src/{CxbxKrnl => devices/video}/vga.h (100%) diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index 5074bfe6d..344ad3e05 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -190,8 +190,6 @@ - - @@ -218,8 +216,6 @@ - - @@ -231,20 +227,12 @@ - - - - - - - - @@ -260,6 +248,19 @@ + + + + + + + + + + + + + @@ -360,8 +361,6 @@ - - @@ -481,8 +480,6 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - - @@ -525,18 +522,12 @@ - - - %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) - - - @@ -600,6 +591,16 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + + + + + + + + + + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 546c0b4c5..9a9f24fdc 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -196,37 +196,37 @@ Emulator - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - Hardware - + Hardware - + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + Hardware @@ -354,9 +354,6 @@ Emulator - - Emulator - Emulator @@ -405,46 +402,52 @@ HLEDatabase\D3D8 - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - Emulator Emulator - - Hardware - Hardware - + Hardware - + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + Hardware diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 1162d9cd4..160e4e51c 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -51,7 +51,6 @@ namespace xboxkrnl #include "EmuEEPROM.h" // For CxbxRestoreEEPROM, EEPROM, XboxFactoryGameRegion #include "EmuKrnl.h" #include "EmuShared.h" -#include "EmuNV2A.h" // For InitOpenGLContext #include "HLEIntercept.h" #include "ReservedMemory.h" // For virtual_memory_placeholder #include "VMManager.h" @@ -63,8 +62,9 @@ namespace xboxkrnl #include // For time() #include // For std::ostringstream -#include "Xbox.h" // For InitXboxHardware() -#include "EEPROMDevice.h" // For g_EEPROM +#include "devices\EEPROMDevice.h" // For g_EEPROM +#include "devices\video\EmuNV2A.h" // For InitOpenGLContext +#include "devices\Xbox.h" // For InitXboxHardware() /* prevent name collisions */ namespace NtDll diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index 3a60daac8..ac4b91247 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -51,11 +51,11 @@ namespace xboxkrnl #include "Emu.h" // For EmuWarning() #include "EmuKrnl.h" #include "EmuX86.h" // HalReadWritePciSpace needs this -#include "SMBus.h" // For g_SMBus -#include "EmuEEPROM.h" // For EEPROM -#include "SMCDevice.h" // For SMC_COMMAND_SCRATCH #include "EmuShared.h" #include "EmuFile.h" // For FindNtSymbolicLinkObjectByDriveLetter +#include "Common\EmuEEPROM.h" // For EEPROM +#include "devices\SMBus.h" // For g_SMBus +#include "devices\SMCDevice.h" // For SMC_COMMAND_SCRATCH #include // for std::replace #include diff --git a/src/CxbxKrnl/EmuX86.cpp b/src/CxbxKrnl/EmuX86.cpp index 15bc5c9ff..b29d2bb4e 100644 --- a/src/CxbxKrnl/EmuX86.cpp +++ b/src/CxbxKrnl/EmuX86.cpp @@ -52,7 +52,7 @@ #include "HLEIntercept.h" // for bLLE_GPU #include -#include "PCIBus.h" +#include "devices\PCIBus.h" // // Read & write handlers handlers for I/O diff --git a/src/CxbxKrnl/EEPROMDevice.cpp b/src/devices/EEPROMDevice.cpp similarity index 100% rename from src/CxbxKrnl/EEPROMDevice.cpp rename to src/devices/EEPROMDevice.cpp diff --git a/src/CxbxKrnl/EEPROMDevice.h b/src/devices/EEPROMDevice.h similarity index 100% rename from src/CxbxKrnl/EEPROMDevice.h rename to src/devices/EEPROMDevice.h diff --git a/src/CxbxKrnl/EmuNVNet.cpp b/src/devices/EmuNVNet.cpp similarity index 99% rename from src/CxbxKrnl/EmuNVNet.cpp rename to src/devices/EmuNVNet.cpp index 042b8df4d..61d5de6bc 100644 --- a/src/CxbxKrnl/EmuNVNet.cpp +++ b/src/devices/EmuNVNet.cpp @@ -48,9 +48,10 @@ namespace xboxkrnl #include // For PKINTERRUPT, etc. }; -#include "CxbxKrnl.h" -#include "Emu.h" -#include "EmuKrnl.h" +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\Emu.h" +#include "CxbxKrnl\EmuKrnl.h" + #include "EmuNVNet.h" // NVNET Register Definitions diff --git a/src/CxbxKrnl/EmuNVNet.h b/src/devices/EmuNVNet.h similarity index 100% rename from src/CxbxKrnl/EmuNVNet.h rename to src/devices/EmuNVNet.h diff --git a/src/CxbxKrnl/LED.h b/src/devices/LED.h similarity index 100% rename from src/CxbxKrnl/LED.h rename to src/devices/LED.h diff --git a/src/CxbxKrnl/PCIBus.cpp b/src/devices/PCIBus.cpp similarity index 100% rename from src/CxbxKrnl/PCIBus.cpp rename to src/devices/PCIBus.cpp diff --git a/src/CxbxKrnl/PCIBus.h b/src/devices/PCIBus.h similarity index 100% rename from src/CxbxKrnl/PCIBus.h rename to src/devices/PCIBus.h diff --git a/src/CxbxKrnl/PCIDevice.cpp b/src/devices/PCIDevice.cpp similarity index 100% rename from src/CxbxKrnl/PCIDevice.cpp rename to src/devices/PCIDevice.cpp diff --git a/src/CxbxKrnl/PCIDevice.h b/src/devices/PCIDevice.h similarity index 100% rename from src/CxbxKrnl/PCIDevice.h rename to src/devices/PCIDevice.h diff --git a/src/CxbxKrnl/SMBus.cpp b/src/devices/SMBus.cpp similarity index 100% rename from src/CxbxKrnl/SMBus.cpp rename to src/devices/SMBus.cpp diff --git a/src/CxbxKrnl/SMBus.h b/src/devices/SMBus.h similarity index 100% rename from src/CxbxKrnl/SMBus.h rename to src/devices/SMBus.h diff --git a/src/CxbxKrnl/SMCDevice.cpp b/src/devices/SMCDevice.cpp similarity index 99% rename from src/CxbxKrnl/SMCDevice.cpp rename to src/devices/SMCDevice.cpp index c4371329c..0e9f0250e 100644 --- a/src/CxbxKrnl/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -41,8 +41,9 @@ namespace xboxkrnl #include // For xbox.h:AV_PACK_HDTV }; -#include "CxbxKrnl.h" -#include "EmuShared.h" +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\EmuShared.h" + #include "SMCDevice.h" // For SMCDevice #include "LED.h" diff --git a/src/CxbxKrnl/SMCDevice.h b/src/devices/SMCDevice.h similarity index 100% rename from src/CxbxKrnl/SMCDevice.h rename to src/devices/SMCDevice.h diff --git a/src/CxbxKrnl/SMDevice.cpp b/src/devices/SMDevice.cpp similarity index 100% rename from src/CxbxKrnl/SMDevice.cpp rename to src/devices/SMDevice.cpp diff --git a/src/CxbxKrnl/SMDevice.h b/src/devices/SMDevice.h similarity index 100% rename from src/CxbxKrnl/SMDevice.h rename to src/devices/SMDevice.h diff --git a/src/CxbxKrnl/Xbox.cpp b/src/devices/Xbox.cpp similarity index 100% rename from src/CxbxKrnl/Xbox.cpp rename to src/devices/Xbox.cpp diff --git a/src/CxbxKrnl/Xbox.h b/src/devices/Xbox.h similarity index 100% rename from src/CxbxKrnl/Xbox.h rename to src/devices/Xbox.h diff --git a/src/CxbxKrnl/EmuNV2A.cpp b/src/devices/video/EmuNV2A.cpp similarity index 96% rename from src/CxbxKrnl/EmuNV2A.cpp rename to src/devices/video/EmuNV2A.cpp index c7ecaa455..da222a46a 100644 --- a/src/CxbxKrnl/EmuNV2A.cpp +++ b/src/devices/video/EmuNV2A.cpp @@ -1,3761 +1,3762 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * .,-::::: .,:: .::::::::. .,:: .: -// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; -// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' -// * $$$ Y$$$P $$""""Y$$ Y$$$P -// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, -// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, -// * -// * Cxbx->Win32->CxbxKrnl->EmuNV2A.cpp -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * (c) 2016 Luke Usher -// * -// * EmuNV2A.cpp is heavily based on code from XQEMU -// * Copyright(c) 2012 espes -// * Copyright(c) 2015 Jannik Vogel -// * https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a.c -// * -// * All rights reserved -// * -// ****************************************************************** -#define _XBOXKRNL_DEFEXTRN_ - -#define LOG_PREFIX "NV2A" - -#include // For __beginthreadex(), etc. -#include "vga.h" - -// prevent name collisions -namespace xboxkrnl -{ - #include // For PKINTERRUPT, etc. -}; - - -#ifdef _MSC_VER // Check if MS Visual C compiler -# pragma comment(lib, "opengl32.lib") // Compiler-specific directive to avoid manually configuration -//# pragma comment(lib, "glu32.lib") // Link libraries -# pragma comment(lib, "glew32.lib") -#endif - -#include // For uint32_t -#include // For std::string -#include -#include -#include -#include - -#include "CxbxKrnl.h" -#include "Emu.h" -#include "EmuFS.h" -#include "EmuKrnl.h" -#include "EmuNV2A.h" -#include "HLEIntercept.h" -#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox - -#include -#include -#include -#include -//#include - - -// Public Domain ffs Implementation -// See: http://snipplr.com/view/22147/stringsh-implementation/ -int ffs(int v) -{ - unsigned int x = v; - int c = 1; - - /* - * adapted from from - * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch - * - * a modified binary search algorithm to count 0 bits from - * the right (lsb). This algorithm should work regardless - * of the size of ints on the platform. - * - */ - - /* a couple special cases */ - if (x == 0) return 0; - if (x & 1) return 1; /* probably pretty common */ - - c = 1; - while ((x & 0xffff) == 0) { - x >>= 16; - c += 16; - } - if ((x & 0xff) == 0) { - x >>= 8; - c += 8; - } - if ((x & 0x0f) == 0) { - x >>= 4; - c += 4; - } - if ((x & 0x03) == 0) { - x >>= 2; - c += 2; - } - - c -= (x & 1); - c += 1; /* ffs() requires indexing bits from 1 */ - /* ie., the lsb is bit 1, not bit 0 */ - return c; -} - -inline int GET_MASK(int v, int mask) { - return (((v) & (mask)) >> (ffs(mask) - 1)); -}; - -inline int SET_MASK(int v, int mask, int val) { - const unsigned int __val = (val); - const unsigned int __mask = (mask); - - (v) &= ~(__mask); - return (v) |= ((__val) << (ffs(__mask)-1)) & (__mask); -} - -#define CASE_4(v, step) \ - case (v): \ - case (v)+(step) : \ - case (v)+(step) * 2: \ - case (v)+(step) * 3 - - -enum FifoMode { - FIFO_PIO = 0, - FIFO_DMA = 1, -}; - -enum FIFOEngine { - ENGINE_SOFTWARE = 0, - ENGINE_GRAPHICS = 1, - ENGINE_DVD = 2, -}; - -typedef struct RAMHTEntry { - uint32_t handle; - xbaddr instance; - enum FIFOEngine engine; - unsigned int channel_id : 5; - bool valid; -} RAMHTEntry; - -typedef struct DMAObject { - unsigned int dma_class; - unsigned int dma_target; - xbaddr address; - xbaddr limit; -} DMAObject; - -typedef struct VertexAttribute { - bool dma_select; - xbaddr offset; - - /* inline arrays are packed in order? - * Need to pass the offset to converted attributes */ - unsigned int inline_array_offset; - - float inline_value[4]; - - unsigned int format; - unsigned int size; /* size of the data type */ - unsigned int count; /* number of components */ - uint32_t stride; - - bool needs_conversion; - uint8_t *converted_buffer; - unsigned int converted_elements; - unsigned int converted_size; - unsigned int converted_count; - - float *inline_buffer; - - GLint gl_count; - GLenum gl_type; - GLboolean gl_normalize; - - GLuint gl_converted_buffer; - GLuint gl_inline_buffer; -} VertexAttribute; - -typedef struct Surface { - bool draw_dirty; - bool buffer_dirty; - bool write_enabled_cache; - unsigned int pitch; - - xbaddr offset; -} Surface; - -typedef struct SurfaceShape { - unsigned int z_format; - unsigned int color_format; - unsigned int zeta_format; - unsigned int log_width, log_height; - unsigned int clip_x, clip_y; - unsigned int clip_width, clip_height; - unsigned int anti_aliasing; -} SurfaceShape; - -typedef struct TextureShape { - bool cubemap; - unsigned int dimensionality; - unsigned int color_format; - unsigned int levels; - unsigned int width, height, depth; - - unsigned int min_mipmap_level, max_mipmap_level; - unsigned int pitch; -} TextureShape; - -typedef struct TextureKey { - TextureShape state; - uint64_t data_hash; - uint8_t* texture_data; - uint8_t* palette_data; -} TextureKey; - -typedef struct TextureBinding { - GLenum gl_target; - GLuint gl_texture; - unsigned int refcnt; -} TextureBinding; - -typedef struct KelvinState { - xbaddr dma_notifies; - xbaddr dma_state; - xbaddr dma_semaphore; - unsigned int semaphore_offset; -} KelvinState; - -typedef struct ContextSurfaces2DState { - xbaddr dma_image_source; - xbaddr dma_image_dest; - unsigned int color_format; - unsigned int source_pitch, dest_pitch; - xbaddr source_offset, dest_offset; - -} ContextSurfaces2DState; - -typedef struct ImageBlitState { - xbaddr context_surfaces; - unsigned int operation; - unsigned int in_x, in_y; - unsigned int out_x, out_y; - unsigned int width, height; - -} ImageBlitState; - -typedef struct GraphicsObject { - uint8_t graphics_class; - union { - ContextSurfaces2DState context_surfaces_2d; - - ImageBlitState image_blit; - - KelvinState kelvin; - } data; -} GraphicsObject; - -typedef struct GraphicsSubchannel { - xbaddr object_instance; - GraphicsObject object; - uint32_t object_cache[5]; -} GraphicsSubchannel; - -typedef struct GraphicsContext { - bool channel_3d; - unsigned int subchannel; -} GraphicsContext; - -typedef struct CacheEntry { - unsigned int method : 14; - unsigned int subchannel : 3; - bool nonincreasing; - uint32_t parameter; -} CacheEntry; - -typedef struct Cache1State { - unsigned int channel_id; - FifoMode mode; - - /* Pusher state */ - bool push_enabled; - bool dma_push_enabled; - bool dma_push_suspended; - xbaddr dma_instance; - - bool method_nonincreasing; - unsigned int method : 14; - unsigned int subchannel : 3; - unsigned int method_count : 24; - uint32_t dcount; - - bool subroutine_active; - xbaddr subroutine_return; - xbaddr get_jmp_shadow; - uint32_t rsvd_shadow; - uint32_t data_shadow; - uint32_t error; - - bool pull_enabled; - enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS]; - enum FIFOEngine last_engine; - - /* The actual command queue */ - std::mutex mutex; - std::condition_variable cache_cond; - std::queue cache; - std::queue working_cache; -} Cache1State; - -typedef struct ChannelControl { - xbaddr dma_put; - xbaddr dma_get; - uint32_t ref; -} ChannelControl; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t regs[NV_PMC_SIZE]; // TODO : union -} pmc; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - std::thread puller_thread; - Cache1State cache1; - uint32_t regs[NV_PFIFO_SIZE]; // TODO : union -} pfifo; - -struct { - uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union -} pvideo; - - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t numerator; - uint32_t denominator; - uint32_t alarm_time; - uint32_t regs[NV_PTIMER_SIZE]; // TODO : union -} ptimer; - -struct { - uint32_t regs[NV_PFB_SIZE]; // TODO : union -} pfb; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t start; - uint32_t regs[NV_PCRTC_SIZE]; // TODO : union -} pcrtc; - -struct { - uint32_t core_clock_coeff; - uint64_t core_clock_freq; - uint32_t memory_clock_coeff; - uint32_t video_clock_coeff; - uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union -} pramdac; - -struct { - uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union -} pramin; - -struct { - ChannelControl channel_control[NV2A_NUM_CHANNELS]; -} user; - -// PRMCIO (Actually the VGA controller) -struct { - uint8_t cr_index; - uint8_t cr[256]; /* CRT registers */ -} prmcio; - -struct { - std::mutex mutex; - - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - std::condition_variable interrupt_cond; - - xbaddr context_table; - xbaddr context_address; - - - unsigned int trapped_method; - unsigned int trapped_subchannel; - unsigned int trapped_channel_id; - uint32_t trapped_data[2]; - uint32_t notify_source; - - bool fifo_access; - std::condition_variable fifo_access_cond; - std::condition_variable flip_3d; - - unsigned int channel_id; - bool channel_valid; - GraphicsContext context[NV2A_NUM_CHANNELS]; - - xbaddr dma_color, dma_zeta; - Surface surface_color, surface_zeta; - unsigned int surface_type; - SurfaceShape surface_shape; - SurfaceShape last_surface_shape; - - xbaddr dma_a, dma_b; - //GLruCache *texture_cache; - bool texture_dirty[NV2A_MAX_TEXTURES]; - TextureBinding *texture_binding[NV2A_MAX_TEXTURES]; - - //GHashTable *shader_cache; - //ShaderBinding *shader_binding; - - bool texture_matrix_enable[NV2A_MAX_TEXTURES]; - - /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ - float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */ - - // wglContext *gl_context; - GLuint gl_framebuffer; - GLuint gl_color_buffer, gl_zeta_buffer; - GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS]; - - xbaddr dma_report; - xbaddr report_offset; - bool zpass_pixel_count_enable; - unsigned int zpass_pixel_count_result; - unsigned int gl_zpass_pixel_count_query_count; - GLuint* gl_zpass_pixel_count_queries; - - xbaddr dma_vertex_a, dma_vertex_b; - - unsigned int primitive_mode; - - bool enable_vertex_program_write; - - //uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE]; - - uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS]; - - /* lighting constant arrays */ - uint32_t ltctxa[NV2A_LTCTXA_COUNT][4]; - bool ltctxa_dirty[NV2A_LTCTXA_COUNT]; - uint32_t ltctxb[NV2A_LTCTXB_COUNT][4]; - bool ltctxb_dirty[NV2A_LTCTXB_COUNT]; - uint32_t ltc1[NV2A_LTC1_COUNT][4]; - bool ltc1_dirty[NV2A_LTC1_COUNT]; - - // should figure out where these are in lighting context - float light_infinite_half_vector[NV2A_MAX_LIGHTS][3]; - float light_infinite_direction[NV2A_MAX_LIGHTS][3]; - float light_local_position[NV2A_MAX_LIGHTS][3]; - float light_local_attenuation[NV2A_MAX_LIGHTS][3]; - - //VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES]; - - unsigned int inline_array_length; - uint32_t inline_array[NV2A_MAX_BATCH_LENGTH]; - GLuint gl_inline_array_buffer; - - unsigned int inline_elements_length; - uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH]; - - unsigned int inline_buffer_length; - - unsigned int draw_arrays_length; - unsigned int draw_arrays_max_count; - - /* FIXME: Unknown size, possibly endless, 1000 will do for now */ - GLint gl_draw_arrays_start[1000]; - GLsizei gl_draw_arrays_count[1000]; - - GLuint gl_element_buffer; - GLuint gl_memory_buffer; - GLuint gl_vertex_array; - - uint32_t regs[NV_PGRAPH_SIZE]; // TODO : union -} pgraph; - -static void update_irq() -{ - /* PFIFO */ - if (pfifo.pending_interrupts & pfifo.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO; - } - - /* PCRTC */ - if (pcrtc.pending_interrupts & pcrtc.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC; - } - - /* PGRAPH */ - if (pgraph.pending_interrupts & pgraph.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH; - } - - /* TODO : PBUS * / - if (pbus.pending_interrupts & pbus.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS; - } - else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS; - } */ - - /* TODO : SOFTWARE * / - if (user.pending_interrupts & user.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE; - } - else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE; - } */ - - if (pmc.pending_interrupts && pmc.enabled_interrupts) { - HalSystemInterrupts[3].Assert(true); - } else { - HalSystemInterrupts[3].Assert(false); - } - - SwitchToThread(); -} - - -#define DEBUG_START(DEV) \ -const char *DebugNV_##DEV##(xbaddr addr) \ -{ \ - switch (addr) { -#define DEBUG_CASE(a) \ - case a: return #a; -#define DEBUG_CASE_EX(a, c) \ - case a: return #a##c; -#define DEBUG_END(DEV) \ - default: \ - return "Unknown " #DEV " Address"; \ - } \ -} - -DEBUG_START(PMC) - DEBUG_CASE(NV_PMC_BOOT_0); - DEBUG_CASE(NV_PMC_INTR_0); - DEBUG_CASE(NV_PMC_INTR_EN_0); - DEBUG_CASE(NV_PMC_ENABLE); -DEBUG_END(PMC) - -DEBUG_START(PBUS) - DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID"); - DEBUG_CASE(NV_PBUS_PCI_NV_1); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, ":LATENCY_TIMER"); - DEBUG_CASE(NV_PBUS_PCI_NV_4); - DEBUG_CASE(NV_PBUS_PCI_NV_5); - DEBUG_CASE(NV_PBUS_PCI_NV_6); - DEBUG_CASE(NV_PBUS_PCI_NV_7); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, ":SUBSYSTEM"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, ":ROM_BASE"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, ":CAP_PTR"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, ":RESERVED"); - DEBUG_CASE(NV_PBUS_PCI_NV_15); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, ":SUBSYSTEM"); - DEBUG_CASE(NV_PBUS_PCI_NV_17); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, ":AGP_STATUS"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, ":AGP_COMMAND"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, ":ROM_SHADOW"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, ":VGA"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, ":SCRATCH"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, ":DT_TIMEOUT"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, ":PME"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, ":POWER_STATE"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, ":RESERVED"); -DEBUG_END(PBUS) - -DEBUG_START(PFIFO) - DEBUG_CASE(NV_PFIFO_INTR_0); - DEBUG_CASE(NV_PFIFO_INTR_EN_0); - DEBUG_CASE(NV_PFIFO_RAMHT); - DEBUG_CASE(NV_PFIFO_RAMFC); - DEBUG_CASE(NV_PFIFO_RAMRO); - DEBUG_CASE(NV_PFIFO_RUNOUT_STATUS); - DEBUG_CASE(NV_PFIFO_MODE); - DEBUG_CASE(NV_PFIFO_DMA); - DEBUG_CASE(NV_PFIFO_CACHE1_PUSH0); - DEBUG_CASE(NV_PFIFO_CACHE1_PUSH1); - DEBUG_CASE(NV_PFIFO_CACHE1_STATUS); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUSH); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_FETCH); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_STATE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_INSTANCE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUT); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_SUBROUTINE); - DEBUG_CASE(NV_PFIFO_CACHE1_PULL0); - DEBUG_CASE(NV_PFIFO_CACHE1_ENGINE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DCOUNT); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_RSVD_SHADOW); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DATA_SHADOW); -DEBUG_END(PFIFO) - -DEBUG_START(PRMA) -DEBUG_END(PRMA) - -DEBUG_START(PVIDEO) - DEBUG_CASE(NV_PVIDEO_INTR); - DEBUG_CASE(NV_PVIDEO_INTR_EN); - DEBUG_CASE(NV_PVIDEO_BUFFER); - DEBUG_CASE(NV_PVIDEO_STOP); - DEBUG_CASE(NV_PVIDEO_BASE); - DEBUG_CASE(NV_PVIDEO_LIMIT); - DEBUG_CASE(NV_PVIDEO_LUMINANCE); - DEBUG_CASE(NV_PVIDEO_CHROMINANCE); - DEBUG_CASE(NV_PVIDEO_OFFSET); - DEBUG_CASE(NV_PVIDEO_SIZE_IN); - DEBUG_CASE(NV_PVIDEO_POINT_IN); - DEBUG_CASE(NV_PVIDEO_DS_DX); - DEBUG_CASE(NV_PVIDEO_DT_DY); - DEBUG_CASE(NV_PVIDEO_POINT_OUT); - DEBUG_CASE(NV_PVIDEO_SIZE_OUT); - DEBUG_CASE(NV_PVIDEO_FORMAT); -DEBUG_END(PVIDEO) - -DEBUG_START(PTIMER) - DEBUG_CASE(NV_PTIMER_INTR_0); - DEBUG_CASE(NV_PTIMER_INTR_EN_0); - DEBUG_CASE(NV_PTIMER_NUMERATOR); - DEBUG_CASE(NV_PTIMER_DENOMINATOR); - DEBUG_CASE(NV_PTIMER_TIME_0); - DEBUG_CASE(NV_PTIMER_TIME_1); - DEBUG_CASE(NV_PTIMER_ALARM_0); - -DEBUG_END(PTIMER) - -DEBUG_START(PCOUNTER) -DEBUG_END(PCOUNTER) - -DEBUG_START(PVPE) -DEBUG_END(PVPE) - -DEBUG_START(PTV) -DEBUG_END(PTV) - -DEBUG_START(PRMFB) -DEBUG_END(PRMFB) - -DEBUG_START(PRMVIO) -DEBUG_END(PRMVIO) - -DEBUG_START(PFB) - DEBUG_CASE(NV_PFB_CFG0) - DEBUG_CASE(NV_PFB_CSTATUS) - DEBUG_CASE(NV_PFB_REFCTRL) - DEBUG_CASE(NV_PFB_NVM) // NV_PFB_NVM_MODE_DISABLE - DEBUG_CASE(NV_PFB_PIN) - DEBUG_CASE(NV_PFB_PAD) - DEBUG_CASE(NV_PFB_TIMING0) - DEBUG_CASE(NV_PFB_TIMING1) - DEBUG_CASE(NV_PFB_TIMING2) - DEBUG_CASE(NV_PFB_TILE) - DEBUG_CASE(NV_PFB_TLIMIT) - DEBUG_CASE(NV_PFB_TSIZE) - DEBUG_CASE(NV_PFB_TSTATUS) - DEBUG_CASE(NV_PFB_MRS) - DEBUG_CASE(NV_PFB_EMRS) - DEBUG_CASE(NV_PFB_MRS_EXT) - DEBUG_CASE(NV_PFB_EMRS_EXT) - DEBUG_CASE(NV_PFB_REF) - DEBUG_CASE(NV_PFB_PRE) - DEBUG_CASE(NV_PFB_ZCOMP) - DEBUG_CASE(NV_PFB_ARB_PREDIVIDER) - DEBUG_CASE(NV_PFB_ARB_TIMEOUT) - DEBUG_CASE(NV_PFB_ARB_XFER_REM) - DEBUG_CASE(NV_PFB_ARB_DIFF_BANK) - DEBUG_CASE(NV_PFB_CLOSE_PAGE0) - DEBUG_CASE(NV_PFB_CLOSE_PAGE1) - DEBUG_CASE(NV_PFB_CLOSE_PAGE2) - DEBUG_CASE(NV_PFB_BPARB) - DEBUG_CASE(NV_PFB_CMDQ0) - DEBUG_CASE(NV_PFB_CMDQ1) - DEBUG_CASE(NV_PFB_ILL_INSTR) - DEBUG_CASE(NV_PFB_RT) - DEBUG_CASE(NV_PFB_AUTOCLOSE) - DEBUG_CASE(NV_PFB_WBC) - DEBUG_CASE(NV_PFB_CMDQ_PRT) - DEBUG_CASE(NV_PFB_CPU_RRQ) - DEBUG_CASE(NV_PFB_BYPASS); -DEBUG_END(PFB) - -DEBUG_START(PSTRAPS) -DEBUG_END(PSTRAPS) - -DEBUG_START(PGRAPH) - DEBUG_CASE(NV_PGRAPH_INTR); - DEBUG_CASE(NV_PGRAPH_NSOURCE); - DEBUG_CASE(NV_PGRAPH_INTR_EN); - DEBUG_CASE(NV_PGRAPH_CTX_CONTROL); - DEBUG_CASE(NV_PGRAPH_CTX_USER); - DEBUG_CASE(NV_PGRAPH_CTX_SWITCH1); - DEBUG_CASE(NV_PGRAPH_TRAPPED_ADDR); - DEBUG_CASE(NV_PGRAPH_TRAPPED_DATA_LOW); - DEBUG_CASE(NV_PGRAPH_SURFACE); - DEBUG_CASE(NV_PGRAPH_INCREMENT); - DEBUG_CASE(NV_PGRAPH_FIFO); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TABLE); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_POINTER); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TRIGGER); - DEBUG_CASE(NV_PGRAPH_CSV0_D); - DEBUG_CASE(NV_PGRAPH_CSV0_C); - DEBUG_CASE(NV_PGRAPH_CSV1_B); - DEBUG_CASE(NV_PGRAPH_CSV1_A); - DEBUG_CASE(NV_PGRAPH_CHEOPS_OFFSET); - DEBUG_CASE(NV_PGRAPH_BLEND); - DEBUG_CASE(NV_PGRAPH_BLENDCOLOR); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR0); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR1); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR2); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR3); - DEBUG_CASE(NV_PGRAPH_BUMPOFFSET1); - DEBUG_CASE(NV_PGRAPH_BUMPSCALE1); - DEBUG_CASE(NV_PGRAPH_CLEARRECTX); - DEBUG_CASE(NV_PGRAPH_CLEARRECTY); - DEBUG_CASE(NV_PGRAPH_COLORCLEARVALUE); - DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR0); - DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR1); - DEBUG_CASE(NV_PGRAPH_COMBINEALPHAI0); - DEBUG_CASE(NV_PGRAPH_COMBINEALPHAO0); - DEBUG_CASE(NV_PGRAPH_COMBINECOLORI0); - DEBUG_CASE(NV_PGRAPH_COMBINECOLORO0); - DEBUG_CASE(NV_PGRAPH_COMBINECTL); - DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG0); - DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG1); - DEBUG_CASE(NV_PGRAPH_CONTROL_0); - DEBUG_CASE(NV_PGRAPH_CONTROL_2); - DEBUG_CASE(NV_PGRAPH_CONTROL_3); - DEBUG_CASE(NV_PGRAPH_FOGCOLOR); - DEBUG_CASE(NV_PGRAPH_FOGPARAM0); - DEBUG_CASE(NV_PGRAPH_FOGPARAM1); - DEBUG_CASE(NV_PGRAPH_SETUPRASTER); - DEBUG_CASE(NV_PGRAPH_SHADERCLIPMODE); - DEBUG_CASE(NV_PGRAPH_SHADERCTL); - DEBUG_CASE(NV_PGRAPH_SHADERPROG); - DEBUG_CASE(NV_PGRAPH_SHADOWZSLOPETHRESHOLD); - DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR0); - DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR1); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0_ADDRV); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS1); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS2); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS3); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_1); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_2); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_3); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_1); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_2); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_3); - DEBUG_CASE(NV_PGRAPH_TEXCTL2_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL2_1); - DEBUG_CASE(NV_PGRAPH_TEXFILTER0); - DEBUG_CASE(NV_PGRAPH_TEXFILTER1); - DEBUG_CASE(NV_PGRAPH_TEXFILTER2); - DEBUG_CASE(NV_PGRAPH_TEXFILTER3); - DEBUG_CASE(NV_PGRAPH_TEXFMT0); - DEBUG_CASE(NV_PGRAPH_TEXFMT1); - DEBUG_CASE(NV_PGRAPH_TEXFMT2); - DEBUG_CASE(NV_PGRAPH_TEXFMT3); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT0); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT1); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT2); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT3); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET0); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET1); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET2); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET3); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE0); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE1); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE2); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE3); - DEBUG_CASE(NV_PGRAPH_ZSTENCILCLEARVALUE); - DEBUG_CASE(NV_PGRAPH_ZCLIPMIN); - DEBUG_CASE(NV_PGRAPH_ZOFFSETBIAS); - DEBUG_CASE(NV_PGRAPH_ZOFFSETFACTOR); - DEBUG_CASE(NV_PGRAPH_EYEVEC0); - DEBUG_CASE(NV_PGRAPH_EYEVEC1); - DEBUG_CASE(NV_PGRAPH_EYEVEC2); - DEBUG_CASE(NV_PGRAPH_ZCLIPMAX); -DEBUG_END(PGRAPH) - -DEBUG_START(PCRTC) - DEBUG_CASE(NV_PCRTC_INTR_0); - DEBUG_CASE(NV_PCRTC_INTR_EN_0); - DEBUG_CASE(NV_PCRTC_START); - DEBUG_CASE(NV_PCRTC_CONFIG); - -DEBUG_END(PCRTC) - -DEBUG_START(PRMCIO) - DEBUG_CASE(VGA_CRT_DC); - DEBUG_CASE(VGA_CRT_DM); - DEBUG_CASE(VGA_ATT_R); - DEBUG_CASE(VGA_ATT_W); - DEBUG_CASE(VGA_GFX_D); - DEBUG_CASE(VGA_SEQ_D); - DEBUG_CASE(VGA_MIS_R); - DEBUG_CASE(VGA_MIS_W); - DEBUG_CASE(VGA_FTC_R); - DEBUG_CASE(VGA_IS1_RC); - DEBUG_CASE(VGA_IS1_RM); - DEBUG_CASE(VGA_PEL_D); - DEBUG_CASE(VGA_PEL_MSK); - DEBUG_CASE(VGA_CRT_IC); - DEBUG_CASE(VGA_CRT_IM); - DEBUG_CASE(VGA_GFX_I); - DEBUG_CASE(VGA_SEQ_I); - DEBUG_CASE(VGA_PEL_IW); - DEBUG_CASE(VGA_PEL_IR); -DEBUG_END(PRMCIO) - -DEBUG_START(PRAMDAC) - DEBUG_CASE(NV_PRAMDAC_NVPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_MPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_VPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_PLL_TEST_COUNTER); - -DEBUG_END(PRAMDAC) - -DEBUG_START(PRMDIO) -DEBUG_END(PRMDIO) - -DEBUG_START(PRAMIN) -DEBUG_END(PRAMIN) - -DEBUG_START(USER) - - DEBUG_CASE(NV_USER_DMA_PUT); - DEBUG_CASE(NV_USER_DMA_GET); - DEBUG_CASE(NV_USER_REF); - - DEBUG_END(USER) - - - - -#define DEBUG_READ32(DEV) DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr)) -#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } - -#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr)) -#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; } - -#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr) -#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr) -#define DEVICE_READ32_REG(dev) result = dev.regs[addr] -#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result - -#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(xbaddr addr, uint32_t value) -#define DEVICE_WRITE32_REG(dev) dev.regs[addr] = value -#define DEVICE_WRITE32_END(DEV) DEBUG_WRITE32(DEV) - -static inline uint32_t ldl_le_p(const void *p) -{ - return *(uint32_t*)p; -} - -static DMAObject nv_dma_load(xbaddr dma_obj_address) -{ - assert(dma_obj_address < NV_PRAMIN_SIZE); - - uint32_t *dma_obj = (uint32_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + dma_obj_address); - uint32_t flags = ldl_le_p(dma_obj); - uint32_t limit = ldl_le_p(dma_obj + 1); - uint32_t frame = ldl_le_p(dma_obj + 2); - - DMAObject object; - object.dma_class = GET_MASK(flags, NV_DMA_CLASS); - object.dma_target = GET_MASK(flags, NV_DMA_TARGET); - object.address = (frame & NV_DMA_ADDRESS) | GET_MASK(flags, NV_DMA_ADJUST); - object.limit = limit; - - return object; -} - -static void *nv_dma_map(xbaddr dma_obj_address, xbaddr *len) -{ - assert(dma_obj_address < NV_PRAMIN_SIZE); - - DMAObject dma = nv_dma_load(dma_obj_address); - - /* TODO: Handle targets and classes properly */ - printf("dma_map %x, %x, %x %x" "\n", - dma.dma_class, dma.dma_target, dma.address, dma.limit); - - dma.address &= 0x07FFFFFF; - - // assert(dma.address + dma.limit < memory_region_size(d->vram)); - *len = dma.limit; - return (void*)(MM_SYSTEM_PHYSICAL_MAP + dma.address); -} - -/* pusher should be fine to run from a mimo handler -* whenever's it's convenient */ -static void pfifo_run_pusher() { - uint8_t channel_id; - ChannelControl *control; - Cache1State *state; - CacheEntry *command; - uint8_t *dma; - xbaddr dma_len; - uint32_t word; - - /* TODO: How is cache1 selected? */ - state = &pfifo.cache1; - channel_id = state->channel_id; - control = &user.channel_control[channel_id]; - - if (!state->push_enabled) return; - - /* only handling DMA for now... */ - - /* Channel running DMA */ - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - assert(channel_modes & (1 << channel_id)); - assert(state->mode == FIFO_DMA); - - if (!state->dma_push_enabled) return; - if (state->dma_push_suspended) return; - - /* We're running so there should be no pending errors... */ - assert(state->error == NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE); - - dma = (uint8_t*)nv_dma_map(state->dma_instance, &dma_len); - - printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n", - dma_len, control->dma_get, control->dma_put); - - /* based on the convenient pseudocode in envytools */ - while (control->dma_get != control->dma_put) { - if (control->dma_get >= dma_len) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION; - break; - } - - word = ldl_le_p((uint32_t*)(dma + control->dma_get)); - control->dma_get += 4; - - if (state->method_count) { - /* data word of methods command */ - state->data_shadow = word; - - CacheEntry* command = (CacheEntry*)calloc(1, sizeof(CacheEntry)); - command->method = state->method; - command->subchannel = state->subchannel; - command->nonincreasing = state->method_nonincreasing; - command->parameter = word; - - std::lock_guard lk(state->mutex); - state->cache.push(command); - state->cache_cond.notify_all(); - - if (!state->method_nonincreasing) { - state->method += 4; - } - - state->method_count--; - state->dcount++; - } else { - /* no command active - this is the first word of a new one */ - state->rsvd_shadow = word; - /* match all forms */ - if ((word & 0xe0000003) == 0x20000000) { - /* old jump */ - state->get_jmp_shadow = control->dma_get; - control->dma_get = word & 0x1fffffff; - printf("pb OLD_JMP 0x%08X\n", control->dma_get); - } - else if ((word & 3) == 1) { - /* jump */ - state->get_jmp_shadow = control->dma_get; - control->dma_get = word & 0xfffffffc; - printf("pb JMP 0x%08X\n", control->dma_get); - } - else if ((word & 3) == 2) { - /* call */ - if (state->subroutine_active) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL; - break; - } - state->subroutine_return = control->dma_get; - state->subroutine_active = true; - control->dma_get = word & 0xfffffffc; - printf("pb CALL 0x%08X\n", control->dma_get); - } - else if (word == 0x00020000) { - /* return */ - if (!state->subroutine_active) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN; - break; - } - control->dma_get = state->subroutine_return; - state->subroutine_active = false; - printf("pb RET 0x%08X\n", control->dma_get); - } - else if ((word & 0xe0030003) == 0) { - /* increasing methods */ - state->method = word & 0x1fff; - state->subchannel = (word >> 13) & 7; - state->method_count = (word >> 18) & 0x7ff; - state->method_nonincreasing = false; - state->dcount = 0; - } - else if ((word & 0xe0030003) == 0x40000000) { - /* non-increasing methods */ - state->method = word & 0x1fff; - state->subchannel = (word >> 13) & 7; - state->method_count = (word >> 18) & 0x7ff; - state->method_nonincreasing = true; - state->dcount = 0; - } - else { - printf("pb reserved cmd 0x%08X - 0x%08X\n", - control->dma_get, word); - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD; - break; - } - } - } - - printf("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n", - dma_len, control->dma_get, control->dma_put); - - if (state->error) { - printf("pb error: %d\n", state->error); - assert(false); - - state->dma_push_suspended = true; - - pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER; - update_irq(); - } -} - -static uint32_t ramht_hash(uint32_t handle) -{ - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); - - /* XXX: Think this is different to what nouveau calculates... */ - unsigned int bits = ffs(ramht_size) - 2; - - uint32_t hash = 0; - while (handle) { - hash ^= (handle & ((1 << bits) - 1)); - handle >>= bits; - } - hash ^= pfifo.cache1.channel_id << (bits - 4); - - return hash; -} - - -static RAMHTEntry ramht_lookup(uint32_t handle) -{ - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); - - uint32_t hash = ramht_hash(handle); - assert(hash * 8 < ramht_size); - - uint32_t ramht_address = - GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], - NV_PFIFO_RAMHT_BASE_ADDRESS) << 12; - - uint8_t *entry_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + ramht_address + hash * 8); - - uint32_t entry_handle = ldl_le_p((uint32_t*)entry_ptr); - uint32_t entry_context = ldl_le_p((uint32_t*)(entry_ptr + 4)); - - RAMHTEntry entry; - entry.handle = entry_handle; - entry.instance = (entry_context & NV_RAMHT_INSTANCE) << 4; - entry.engine = (FIFOEngine)((entry_context & NV_RAMHT_ENGINE) >> 16); - entry.channel_id = (entry_context & NV_RAMHT_CHID) >> 24; - entry.valid = entry_context & NV_RAMHT_STATUS; - - return entry; -} - -static void pgraph_context_switch(unsigned int channel_id) -{ - bool valid = false; - - // Scope the lock so that it gets unlocked at end of this block - { - std::lock_guard lk(pgraph.mutex); - - valid = pgraph.channel_valid && pgraph.channel_id == channel_id; - if (!valid) { - pgraph.trapped_channel_id = channel_id; - } - } - - if (!valid) { - printf("puller needs to switch to ch %d\n", channel_id); - - //qemu_mutex_lock_iothread(); - pgraph.pending_interrupts |= NV_PGRAPH_INTR_CONTEXT_SWITCH; - update_irq(); - - std::unique_lock lk(pgraph.mutex); - //qemu_mutex_unlock_iothread(); - - while (pgraph.pending_interrupts & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - pgraph.interrupt_cond.wait(lk); - } - } -} - -static void pgraph_wait_fifo_access() { - std::unique_lock lk(pgraph.mutex); - - while (!pgraph.fifo_access) { - pgraph.fifo_access_cond.wait(lk); - } -} - -static void pgraph_method_log(unsigned int subchannel, unsigned int graphics_class, unsigned int method, uint32_t parameter) { - static unsigned int last = 0; - static unsigned int count = 0; - - if (last == 0x1800 && method != last) { - printf("pgraph method (%d) 0x%08X * %d", subchannel, last, count); - } - if (method != 0x1800) { - const char* method_name = NULL; - unsigned int nmethod = 0; - switch (graphics_class) { - case NV_KELVIN_PRIMITIVE: - nmethod = method | (0x5c << 16); - break; - case NV_CONTEXT_SURFACES_2D: - nmethod = method | (0x6d << 16); - break; - default: - break; - } - /* - if (nmethod != 0 && nmethod < ARRAY_SIZE(nv2a_method_names)) { - method_name = nv2a_method_names[nmethod]; - } - if (method_name) { - printf("pgraph method (%d): %s (0x%x)\n", - subchannel, method_name, parameter); - } - else { - */ - printf("pgraph method (%d): 0x%x -> 0x%04x (0x%x)\n", - subchannel, graphics_class, method, parameter); - //} - - } - if (method == last) { count++; } - else { count = 0; } - last = method; -} - -static void load_graphics_object(xbaddr instance_address, GraphicsObject *obj) -{ - uint8_t *obj_ptr; - uint32_t switch1, switch2, switch3; - - assert(instance_address < NV_PRAMIN_SIZE); - obj_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + instance_address); - - switch1 = ldl_le_p((uint32_t*)obj_ptr); - switch2 = ldl_le_p((uint32_t*)(obj_ptr + 4)); - switch3 = ldl_le_p((uint32_t*)(obj_ptr + 8)); - - obj->graphics_class = switch1 & NV_PGRAPH_CTX_SWITCH1_GRCLASS; - - /* init graphics object */ - switch (obj->graphics_class) { - case NV_KELVIN_PRIMITIVE: - // kelvin->vertex_attributes[NV2A_VERTEX_ATTR_DIFFUSE].inline_value = 0xFFFFFFF; - break; - default: - break; - } -} - -static GraphicsObject* lookup_graphics_object(xbaddr instance_address) -{ - int i; - for (i = 0; i lk(pgraph.mutex); - - int i; - GraphicsSubchannel *subchannel_data; - GraphicsObject *object; - - unsigned int slot; - - assert(pgraph.channel_valid); - subchannel_data = &pgraph.subchannel_data[subchannel]; - object = &subchannel_data->object; - - ContextSurfaces2DState *context_surfaces_2d = &object->data.context_surfaces_2d; - ImageBlitState *image_blit = &object->data.image_blit; - KelvinState *kelvin = &object->data.kelvin; - - pgraph_method_log(subchannel, object->graphics_class, method, parameter); - - if (method == NV_SET_OBJECT) { - subchannel_data->object_instance = parameter; - - //qemu_mutex_lock_iothread(); - load_graphics_object(parameter, object); - //qemu_mutex_unlock_iothread(); - return; - } - - switch (object->graphics_class) { - case NV_CONTEXT_SURFACES_2D: { - switch (method) { - case NV062_SET_CONTEXT_DMA_IMAGE_SOURCE: - context_surfaces_2d->dma_image_source = parameter; - break; - case NV062_SET_CONTEXT_DMA_IMAGE_DESTIN: - context_surfaces_2d->dma_image_dest = parameter; - break; - case NV062_SET_COLOR_FORMAT: - context_surfaces_2d->color_format = parameter; - break; - case NV062_SET_PITCH: - context_surfaces_2d->source_pitch = parameter & 0xFFFF; - context_surfaces_2d->dest_pitch = parameter >> 16; - break; - case NV062_SET_OFFSET_SOURCE: - context_surfaces_2d->source_offset = parameter & 0x07FFFFFF; - break; - case NV062_SET_OFFSET_DESTIN: - context_surfaces_2d->dest_offset = parameter & 0x07FFFFFF; - break; - default: - EmuWarning("EmuNV2A: Unknown NV_CONTEXT_SURFACES_2D Method: 0x%08X\n", method); - } - - break; - } - - case NV_IMAGE_BLIT: { - switch (method) { - case NV09F_SET_CONTEXT_SURFACES: - image_blit->context_surfaces = parameter; - break; - case NV09F_SET_OPERATION: - image_blit->operation = parameter; - break; - case NV09F_CONTROL_POINT_IN: - image_blit->in_x = parameter & 0xFFFF; - image_blit->in_y = parameter >> 16; - break; - case NV09F_CONTROL_POINT_OUT: - image_blit->out_x = parameter & 0xFFFF; - image_blit->out_y = parameter >> 16; - break; - case NV09F_SIZE: - image_blit->width = parameter & 0xFFFF; - image_blit->height = parameter >> 16; - - /* I guess this kicks it off? */ - if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) { - - printf("NV09F_SET_OPERATION_SRCCOPY"); - - GraphicsObject *context_surfaces_obj = lookup_graphics_object(image_blit->context_surfaces); - assert(context_surfaces_obj); - assert(context_surfaces_obj->graphics_class == NV_CONTEXT_SURFACES_2D); - - ContextSurfaces2DState *context_surfaces = &context_surfaces_obj->data.context_surfaces_2d; - - unsigned int bytes_per_pixel; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_Y8: - bytes_per_pixel = 1; - break; - case NV062_SET_COLOR_FORMAT_LE_R5G6B5: - bytes_per_pixel = 2; - break; - case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: - bytes_per_pixel = 4; - break; - default: - printf("Unknown blit surface format: 0x%x\n", context_surfaces->color_format); - assert(false); - break; - } - - xbaddr source_dma_len, dest_dma_len; - uint8_t *source, *dest; - - source = (uint8_t*)nv_dma_map(context_surfaces->dma_image_source, &source_dma_len); - assert(context_surfaces->source_offset < source_dma_len); - source += context_surfaces->source_offset; - - dest = (uint8_t*)nv_dma_map(context_surfaces->dma_image_dest, &dest_dma_len); - assert(context_surfaces->dest_offset < dest_dma_len); - dest += context_surfaces->dest_offset; - - printf(" - 0x%tx -> 0x%tx\n", source - MM_SYSTEM_PHYSICAL_MAP,dest - MM_SYSTEM_PHYSICAL_MAP); - - int y; - for (y = 0; yheight; y++) { - uint8_t *source_row = source - + (image_blit->in_y + y) * context_surfaces->source_pitch - + image_blit->in_x * bytes_per_pixel; - - uint8_t *dest_row = dest - + (image_blit->out_y + y) * context_surfaces->dest_pitch - + image_blit->out_x * bytes_per_pixel; - - memmove(dest_row, source_row, - image_blit->width * bytes_per_pixel); - } - } - else { - assert(false); - } - - break; - default: - EmuWarning("EmuNV2A: Unknown NV_IMAGE_BLIT Method: 0x%08X\n", method); - } - break; - } - - case NV_KELVIN_PRIMITIVE: { - switch (method) { - case NV097_SET_CONTEXT_DMA_NOTIFIES: - kelvin->dma_notifies = parameter; - break; - case NV097_SET_CONTEXT_DMA_A: - pgraph.dma_a = parameter; - break; - case NV097_SET_CONTEXT_DMA_B: - pgraph.dma_b = parameter; - break; - case NV097_SET_CONTEXT_DMA_STATE: - kelvin->dma_state = parameter; - break; - case NV097_SET_CONTEXT_DMA_COLOR: - printf("TODO: pgraph_update_surface\n"); - /* try to get any straggling draws in before the surface's changed :/ */ - //pgraph_update_surface(d, false, true, true); - - pgraph.dma_color = parameter; - break; - case NV097_SET_CONTEXT_DMA_ZETA: - pgraph.dma_zeta = parameter; - break; - case NV097_SET_CONTEXT_DMA_VERTEX_A: - pgraph.dma_vertex_a = parameter; - break; - case NV097_SET_CONTEXT_DMA_VERTEX_B: - pgraph.dma_vertex_b = parameter; - break; - case NV097_SET_CONTEXT_DMA_SEMAPHORE: - kelvin->dma_semaphore = parameter; - break; - case NV097_SET_CONTEXT_DMA_REPORT: - pgraph.dma_report = parameter; - break; - case NV097_SET_SURFACE_CLIP_HORIZONTAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.clip_x = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_X); - pgraph.surface_shape.clip_width = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_WIDTH); - break; - case NV097_SET_SURFACE_CLIP_VERTICAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.clip_y = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_Y); - pgraph.surface_shape.clip_height = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_HEIGHT); - break; - case NV097_SET_SURFACE_FORMAT: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.color_format = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_COLOR); - pgraph.surface_shape.zeta_format = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ZETA); - pgraph.surface_type = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_TYPE); - pgraph.surface_shape.anti_aliasing = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ANTI_ALIASING); - pgraph.surface_shape.log_width = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_WIDTH); - pgraph.surface_shape.log_height = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_HEIGHT); - break; - case NV097_SET_SURFACE_PITCH: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_color.pitch = - GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR); - pgraph.surface_zeta.pitch = - GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA); - break; - case NV097_SET_SURFACE_COLOR_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_color.offset = parameter; - break; - case NV097_SET_SURFACE_ZETA_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_zeta.offset = parameter; - break; - case NV097_SET_COMBINER_SPECULAR_FOG_CW0: - pgraph.regs[NV_PGRAPH_COMBINESPECFOG0] = parameter; - break; - case NV097_SET_COMBINER_SPECULAR_FOG_CW1: - pgraph.regs[NV_PGRAPH_COMBINESPECFOG1] = parameter; - break; - CASE_4(NV097_SET_TEXTURE_ADDRESS, 64): - slot = (method - NV097_SET_TEXTURE_ADDRESS) / 64; - pgraph.regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; - break; - case NV097_SET_CONTROL0: { - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - bool stencil_write_enable = - parameter & NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE, - stencil_write_enable); - - uint32_t z_format = GET_MASK(parameter, NV097_SET_CONTROL0_Z_FORMAT); - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_Z_FORMAT, z_format); - - bool z_perspective = - parameter & NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE, - z_perspective); - break; - } - - case NV097_SET_FOG_MODE: { - /* FIXME: There is also NV_PGRAPH_CSV0_D_FOG_MODE */ - unsigned int mode; - switch (parameter) { - case NV097_SET_FOG_MODE_V_LINEAR: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR; break; - case NV097_SET_FOG_MODE_V_EXP: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP; break; - case NV097_SET_FOG_MODE_V_EXP2: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2; break; - case NV097_SET_FOG_MODE_V_EXP_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP_ABS; break; - case NV097_SET_FOG_MODE_V_EXP2_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2_ABS; break; - case NV097_SET_FOG_MODE_V_LINEAR_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR_ABS; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOG_MODE, - mode); - break; - } - case NV097_SET_FOG_GEN_MODE: { - unsigned int mode; - switch (parameter) { - case NV097_SET_FOG_GEN_MODE_V_SPEC_ALPHA: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_SPEC_ALPHA; break; - case NV097_SET_FOG_GEN_MODE_V_RADIAL: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_RADIAL; break; - case NV097_SET_FOG_GEN_MODE_V_PLANAR: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_PLANAR; break; - case NV097_SET_FOG_GEN_MODE_V_ABS_PLANAR: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_ABS_PLANAR; break; - case NV097_SET_FOG_GEN_MODE_V_FOG_X: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_FOG_X; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGGENMODE, mode); - break; - } - case NV097_SET_FOG_ENABLE: - /* - FIXME: There is also: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGENABLE, - parameter); - */ - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOGENABLE, - parameter); - break; - case NV097_SET_FOG_COLOR: { - /* PGRAPH channels are ARGB, parameter channels are ABGR */ - uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED); - uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN); - uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE); - uint8_t alpha = GET_MASK(parameter, NV097_SET_FOG_COLOR_ALPHA); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_RED, red); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_GREEN, green); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_BLUE, blue); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha); - break; - } - case NV097_SET_ALPHA_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, parameter); - break; - case NV097_SET_BLEND_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EN, parameter); - break; - case NV097_SET_CULL_FACE_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_CULLENABLE, - parameter); - break; - case NV097_SET_DEPTH_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZENABLE, - parameter); - break; - case NV097_SET_DITHER_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_DITHERENABLE, parameter); - break; - case NV097_SET_LIGHTING_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], NV_PGRAPH_CSV0_C_LIGHTING, - parameter); - break; - case NV097_SET_SKIN_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_SKIN, - parameter); - break; - case NV097_SET_STENCIL_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_POINT_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_LINE_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_FILL_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE, parameter); - break; - case NV097_SET_ALPHA_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHAFUNC, parameter & 0xF); - break; - case NV097_SET_ALPHA_REF: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHAREF, parameter); - break; - case NV097_SET_BLEND_FUNC_SFACTOR: { - unsigned int factor; - switch (parameter) { - case NV097_SET_BLEND_FUNC_SFACTOR_V_ZERO: - factor = NV_PGRAPH_BLEND_SFACTOR_ZERO; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA_SATURATE: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA_SATURATE; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; - default: - fprintf(stderr, "Unknown blend source factor: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_SFACTOR, factor); - - break; - } - - case NV097_SET_BLEND_FUNC_DFACTOR: { - unsigned int factor; - switch (parameter) { - case NV097_SET_BLEND_FUNC_DFACTOR_V_ZERO: - factor = NV_PGRAPH_BLEND_DFACTOR_ZERO; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA_SATURATE: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA_SATURATE; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; - default: - fprintf(stderr, "Unknown blend destination factor: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_DFACTOR, factor); - - break; - } - - case NV097_SET_BLEND_COLOR: - pgraph.regs[NV_PGRAPH_BLENDCOLOR] = parameter; - break; - - case NV097_SET_BLEND_EQUATION: { - unsigned int equation; - switch (parameter) { - case NV097_SET_BLEND_EQUATION_V_FUNC_SUBTRACT: - equation = 0; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT: - equation = 1; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_ADD: - equation = 2; break; - case NV097_SET_BLEND_EQUATION_V_MIN: - equation = 3; break; - case NV097_SET_BLEND_EQUATION_V_MAX: - equation = 4; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT_SIGNED: - equation = 5; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_ADD_SIGNED: - equation = 6; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EQN, equation); - - break; - } - - case NV097_SET_DEPTH_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZFUNC, - parameter & 0xF); - break; - - case NV097_SET_COLOR_MASK: { - pgraph.surface_color.write_enabled_cache |= pgraph_color_write_enabled(); - - bool alpha = parameter & NV097_SET_COLOR_MASK_ALPHA_WRITE_ENABLE; - bool red = parameter & NV097_SET_COLOR_MASK_RED_WRITE_ENABLE; - bool green = parameter & NV097_SET_COLOR_MASK_GREEN_WRITE_ENABLE; - bool blue = parameter & NV097_SET_COLOR_MASK_BLUE_WRITE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE, alpha); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE, red); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE, green); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE, blue); - break; - } - case NV097_SET_DEPTH_MASK: - pgraph.surface_zeta.write_enabled_cache |= pgraph_zeta_write_enabled(); - - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ZWRITEENABLE, parameter); - break; - case NV097_SET_STENCIL_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_MASK_WRITE, parameter); - break; - case NV097_SET_STENCIL_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_FUNC, parameter & 0xF); - break; - case NV097_SET_STENCIL_FUNC_REF: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_REF, parameter); - break; - case NV097_SET_STENCIL_FUNC_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_MASK_READ, parameter); - break; - case NV097_SET_STENCIL_OP_FAIL: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_FAIL, - kelvin_map_stencil_op(parameter)); - break; - case NV097_SET_STENCIL_OP_ZFAIL: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_ZFAIL, - kelvin_map_stencil_op(parameter)); - break; - case NV097_SET_STENCIL_OP_ZPASS: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_ZPASS, - kelvin_map_stencil_op(parameter)); - break; - - case NV097_SET_POLYGON_OFFSET_SCALE_FACTOR: - pgraph.regs[NV_PGRAPH_ZOFFSETFACTOR] = parameter; - break; - case NV097_SET_POLYGON_OFFSET_BIAS: - pgraph.regs[NV_PGRAPH_ZOFFSETBIAS] = parameter; - break; - case NV097_SET_FRONT_POLYGON_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_FRONTFACEMODE, - kelvin_map_polygon_mode(parameter)); - break; - case NV097_SET_BACK_POLYGON_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_BACKFACEMODE, - kelvin_map_polygon_mode(parameter)); - break; - case NV097_SET_CLIP_MIN: - pgraph.regs[NV_PGRAPH_ZCLIPMIN] = parameter; - break; - case NV097_SET_CLIP_MAX: - pgraph.regs[NV_PGRAPH_ZCLIPMAX] = parameter; - break; - case NV097_SET_CULL_FACE: { - unsigned int face; - switch (parameter) { - case NV097_SET_CULL_FACE_V_FRONT: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT; break; - case NV097_SET_CULL_FACE_V_BACK: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_BACK; break; - case NV097_SET_CULL_FACE_V_FRONT_AND_BACK: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT_AND_BACK; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_CULLCTRL, - face); - break; - } - case NV097_SET_FRONT_FACE: { - bool ccw; - switch (parameter) { - case NV097_SET_FRONT_FACE_V_CW: - ccw = false; break; - case NV097_SET_FRONT_FACE_V_CCW: - ccw = true; break; - default: - fprintf(stderr, "Unknown front face: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_FRONTFACE, - ccw ? 1 : 0); - break; - } - case NV097_SET_NORMALIZATION_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], - NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, - parameter); - break; - - case NV097_SET_LIGHT_ENABLE_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], - NV_PGRAPH_CSV0_D_LIGHTS, - parameter); - break; - - CASE_4(NV097_SET_TEXGEN_S, 16) : { - slot = (method - NV097_SET_TEXGEN_S) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_S - : NV_PGRAPH_CSV1_A_T0_S; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 0)); - break; - } - CASE_4(NV097_SET_TEXGEN_T, 16) : { - slot = (method - NV097_SET_TEXGEN_T) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_T - : NV_PGRAPH_CSV1_A_T0_T; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 1)); - break; - } - CASE_4(NV097_SET_TEXGEN_R, 16) : { - slot = (method - NV097_SET_TEXGEN_R) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_R - : NV_PGRAPH_CSV1_A_T0_R; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 2)); - break; - } - CASE_4(NV097_SET_TEXGEN_Q, 16) : { - slot = (method - NV097_SET_TEXGEN_Q) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_Q - : NV_PGRAPH_CSV1_A_T0_Q; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 3)); - break; - } - CASE_4(NV097_SET_TEXTURE_MATRIX_ENABLE, 4) : - slot = (method - NV097_SET_TEXTURE_MATRIX_ENABLE) / 4; - pgraph.texture_matrix_enable[slot] = parameter; - break; - - case NV097_SET_TEXGEN_VIEW_MODEL: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); - break; - default: - if (method >= NV097_SET_COMBINER_ALPHA_ICW && method <= NV097_SET_COMBINER_ALPHA_ICW + 28) { - slot = (method - NV097_SET_COMBINER_ALPHA_ICW) / 4; - pgraph.regs[NV_PGRAPH_COMBINEALPHAI0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_PROJECTION_MATRIX && method <= NV097_SET_PROJECTION_MATRIX + 0x3c) { - slot = (method - NV097_SET_PROJECTION_MATRIX) / 4; - // pg->projection_matrix[slot] = *(float*)¶meter; - unsigned int row = NV_IGRAPH_XF_XFCTX_PMAT0 + slot / 4; - pgraph.vsh_constants[row][slot % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_MODEL_VIEW_MATRIX && method <= NV097_SET_MODEL_VIEW_MATRIX + 0xfc) { - slot = (method - NV097_SET_MODEL_VIEW_MATRIX) / 4; - unsigned int matnum = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_MMAT0 + matnum * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_INVERSE_MODEL_VIEW_MATRIX && method <= NV097_SET_INVERSE_MODEL_VIEW_MATRIX + 0xfc) { - slot = (method - NV097_SET_INVERSE_MODEL_VIEW_MATRIX) / 4; - unsigned int matnum = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_IMMAT0 + matnum * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_COMPOSITE_MATRIX && method <= NV097_SET_COMPOSITE_MATRIX + 0x3c) { - slot = (method - NV097_SET_COMPOSITE_MATRIX) / 4; - unsigned int row = NV_IGRAPH_XF_XFCTX_CMAT0 + slot / 4; - pgraph.vsh_constants[row][slot % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_TEXTURE_MATRIX && method <= NV097_SET_TEXTURE_MATRIX + 0xfc) { - slot = (method - NV097_SET_TEXTURE_MATRIX) / 4; - unsigned int tex = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_T0MAT + tex * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_FOG_PARAMS && method <= NV097_SET_FOG_PARAMS + 8) { - slot = (method - NV097_SET_FOG_PARAMS) / 4; - if (slot < 2) { - pgraph.regs[NV_PGRAPH_FOGPARAM0 + slot * 4] = parameter; - } - else { - /* FIXME: No idea where slot = 2 is */ - } - - pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FOG_K][slot] = parameter; - pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FOG_K] = true; - break; - } - - /* Handles NV097_SET_TEXGEN_PLANE_S,T,R,Q */ - if (method >= NV097_SET_TEXGEN_PLANE_S && method <= NV097_SET_TEXGEN_PLANE_S + 0xfc) { - slot = (method - NV097_SET_TEXGEN_PLANE_S) / 4; - unsigned int tex = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_TG0MAT + tex * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_FOG_PLANE && method <= NV097_SET_FOG_PLANE + 12) { - slot = (method - NV097_SET_FOG_PLANE) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_FOG][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true; - break; - } - - if (method >= NV097_SET_SCENE_AMBIENT_COLOR && method <= NV097_SET_SCENE_AMBIENT_COLOR + 8) { - slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4; - // ?? - pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FR_AMB][slot] = parameter; - pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FR_AMB] = true; - break; - } - - if (method >= NV097_SET_VIEWPORT_OFFSET && method <= NV097_SET_VIEWPORT_OFFSET + 12) { - slot = (method - NV097_SET_VIEWPORT_OFFSET) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPOFF] = true; - break; - } - - if (method >= NV097_SET_EYE_POSITION && method <= NV097_SET_EYE_POSITION + 12) { - slot = (method - NV097_SET_EYE_POSITION) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_EYEP][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_EYEP] = true; - break; - } - - if (method >= NV097_SET_COMBINER_FACTOR0 && method <= NV097_SET_COMBINER_FACTOR0 + 28) { - slot = (method - NV097_SET_COMBINER_FACTOR0) / 4; - pgraph.regs[NV_PGRAPH_COMBINEFACTOR0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_FACTOR1 && method <= NV097_SET_COMBINER_FACTOR1 + 28) { - slot = (method - NV097_SET_COMBINER_FACTOR1) / 4; - pgraph.regs[NV_PGRAPH_COMBINEFACTOR1 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_ALPHA_OCW && method <= NV097_SET_COMBINER_ALPHA_OCW + 28) { - slot = (method - NV097_SET_COMBINER_ALPHA_OCW) / 4; - pgraph.regs[NV_PGRAPH_COMBINEALPHAO0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_COLOR_ICW && method <= NV097_SET_COMBINER_COLOR_ICW + 28) { - slot = (method - NV097_SET_COMBINER_COLOR_ICW) / 4; - pgraph.regs[NV_PGRAPH_COMBINECOLORI0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_VIEWPORT_SCALE && method <= NV097_SET_VIEWPORT_SCALE + 12) { - slot = (method - NV097_SET_VIEWPORT_SCALE) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPSCL][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPSCL] = true; - break; - } - - EmuWarning("EmuNV2A: Unknown NV_KELVIN_PRIMITIVE Method: 0x%08X\n", method); - } - break; - } - - default: - EmuWarning("EmuNV2A: Unknown Graphics Class/Method 0x%08X/0x%08X\n", object->graphics_class, method); - break; - } -} - -static void* pfifo_puller_thread() -{ - Cache1State *state = &pfifo.cache1; - - while (true) { - // Scope the lock so that it automatically unlocks at tne end of this block - { - std::unique_lock lk(state->mutex); - - while (state->cache.empty() || !state->pull_enabled) { - state->cache_cond.wait(lk); - } - - // Copy cache to working_cache - while (!state->cache.empty()) { - state->working_cache.push(state->cache.front()); - state->cache.pop(); - } - } - - while (!state->working_cache.empty()) { - CacheEntry* command = state->working_cache.front(); - state->working_cache.pop(); - - if (command->method == 0) { - // qemu_mutex_lock_iothread(); - RAMHTEntry entry = ramht_lookup(command->parameter); - assert(entry.valid); - - assert(entry.channel_id == state->channel_id); - // qemu_mutex_unlock_iothread(); - - switch (entry.engine) { - case ENGINE_GRAPHICS: - pgraph_context_switch(entry.channel_id); - pgraph_wait_fifo_access(); - pgraph_method(command->subchannel, 0, entry.instance); - break; - default: - assert(false); - break; - } - - /* the engine is bound to the subchannel */ - std::lock_guard lk(pfifo.cache1.mutex); - state->bound_engines[command->subchannel] = entry.engine; - state->last_engine = entry.engine; - } else if (command->method >= 0x100) { - /* method passed to engine */ - - uint32_t parameter = command->parameter; - - /* methods that take objects. - * TODO: Check this range is correct for the nv2a */ - if (command->method >= 0x180 && command->method < 0x200) { - //qemu_mutex_lock_iothread(); - RAMHTEntry entry = ramht_lookup(parameter); - assert(entry.valid); - assert(entry.channel_id == state->channel_id); - parameter = entry.instance; - //qemu_mutex_unlock_iothread(); - } - - // qemu_mutex_lock(&state->cache_lock); - enum FIFOEngine engine = state->bound_engines[command->subchannel]; - // qemu_mutex_unlock(&state->cache_lock); - - switch (engine) { - case ENGINE_GRAPHICS: - pgraph_wait_fifo_access(); - pgraph_method(command->subchannel, command->method, parameter); - break; - default: - assert(false); - break; - } - - // qemu_mutex_lock(&state->cache_lock); - state->last_engine = state->bound_engines[command->subchannel]; - // qemu_mutex_unlock(&state->cache_lock); - } - - free(command); - } - } - - return NULL; -} - -DEVICE_READ32(PMC) -{ - DEVICE_READ32_SWITCH() { - case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 - result = 0x02A000A2; - break; - case NV_PMC_INTR_0: - result = pmc.pending_interrupts; - break; - case NV_PMC_INTR_EN_0: - result = pmc.enabled_interrupts; - break; - default: - result = 0; - //DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC); - break; - } - - DEVICE_READ32_END(PMC); -} - -DEVICE_WRITE32(PMC) -{ - switch(addr) { - case NV_PMC_INTR_0: - pmc.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PMC_INTR_EN_0: - pmc.enabled_interrupts = value; - update_irq(); - break; - - default: - //DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC); - break; - } - - DEVICE_WRITE32_END(PMC); -} - - -DEVICE_READ32(PBUS) -{ - DEVICE_READ32_SWITCH() { - case NV_PBUS_PCI_NV_0: - result = 0x10de; // PCI_VENDOR_ID_NVIDIA (?where to return PCI_DEVICE_ID_NVIDIA_NV2A = 0x01b7) - - break; - case NV_PBUS_PCI_NV_1: - result = 1; // NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED - break; - case NV_PBUS_PCI_NV_2: - result = (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1) - break; - - default: - DEBUG_READ32_UNHANDLED(PBUS); // TODO : DEVICE_READ32_REG(pbus); - break; - } - - DEVICE_READ32_END(PBUS); -} - -DEVICE_WRITE32(PBUS) -{ - switch(addr) { - case NV_PBUS_PCI_NV_1: - // TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED) - break; - default: - DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus); - break; - } - - DEVICE_WRITE32_END(PBUS); -} - - -DEVICE_READ32(PFIFO) -{ - DEVICE_READ32_SWITCH() { - case NV_PFIFO_RAMHT: - result = 0x03000100; // = NV_PFIFO_RAMHT_SIZE_4K | NV_PFIFO_RAMHT_BASE_ADDRESS(NumberOfPaddingBytes >> 12) | NV_PFIFO_RAMHT_SEARCH_128 - break; - case NV_PFIFO_RAMFC: - result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ? - break; - case NV_PFIFO_INTR_0: - result = pfifo.pending_interrupts; - break; - case NV_PFIFO_INTR_EN_0: - result = pfifo.enabled_interrupts; - break; - case NV_PFIFO_RUNOUT_STATUS: - result = NV_PFIFO_RUNOUT_STATUS_LOW_MARK; /* low mark empty */ - break; - case NV_PFIFO_CACHE1_PUSH0: - result = pfifo.cache1.push_enabled; - break; - case NV_PFIFO_CACHE1_PUSH1: - SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, pfifo.cache1.channel_id); - SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, pfifo.cache1.mode); - break; - case NV_PFIFO_CACHE1_STATUS: { - std::lock_guard lk(pfifo.cache1.mutex); - - if (pfifo.cache1.cache.empty()) { - result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */ - } - - } break; - case NV_PFIFO_CACHE1_DMA_PUSH: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS, - pfifo.cache1.dma_push_enabled); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, - pfifo.cache1.dma_push_suspended); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_BUFFER, 1); /* buffer emoty */ - break; - case NV_PFIFO_CACHE1_DMA_STATE: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE, - pfifo.cache1.method_nonincreasing); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD, - pfifo.cache1.method >> 2); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, - pfifo.cache1.subchannel); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, - pfifo.cache1.method_count); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR, - pfifo.cache1.error); - break; - case NV_PFIFO_CACHE1_DMA_INSTANCE: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS, - pfifo.cache1.dma_instance >> 4); - break; - case NV_PFIFO_CACHE1_DMA_PUT: - result = user.channel_control[pfifo.cache1.channel_id].dma_put; - break; - case NV_PFIFO_CACHE1_DMA_GET: - result = user.channel_control[pfifo.cache1.channel_id].dma_get; - break; - case NV_PFIFO_CACHE1_DMA_SUBROUTINE: - result = pfifo.cache1.subroutine_return - | pfifo.cache1.subroutine_active; - break; - case NV_PFIFO_CACHE1_PULL0: { - std::lock_guard lk(pfifo.cache1.mutex); - result = pfifo.cache1.pull_enabled; - } break; - case NV_PFIFO_CACHE1_ENGINE: { - std::lock_guard lk(pfifo.cache1.mutex); - for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { - result |= pfifo.cache1.bound_engines[i] << (i * 2); - } - - } break; - case NV_PFIFO_CACHE1_DMA_DCOUNT: - result = pfifo.cache1.dcount; - break; - case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: - result = pfifo.cache1.get_jmp_shadow; - break; - case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: - result = pfifo.cache1.rsvd_shadow; - break; - case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: - result = pfifo.cache1.data_shadow; - break; - default: - DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO); - break; - } - - DEVICE_READ32_END(PFIFO); -} - -DEVICE_WRITE32(PFIFO) -{ - switch(addr) { - case NV_PFIFO_INTR_0: - pfifo.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PFIFO_INTR_EN_0: - pfifo.enabled_interrupts = value; - update_irq(); - break; - case NV_PFIFO_CACHE1_PUSH0: - pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS; - break; - case NV_PFIFO_CACHE1_PUSH1: - pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID); - pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE); - assert(pfifo.cache1.channel_id < NV2A_NUM_CHANNELS); - break; - case NV_PFIFO_CACHE1_DMA_PUSH: - pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS); - if (pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) { - pfifo.cache1.dma_push_suspended = false; - pfifo_run_pusher(); - } - pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS); - break; - case NV_PFIFO_CACHE1_DMA_STATE: - pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE); - pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2; - pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL); - pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT); - pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR); - break; - case NV_PFIFO_CACHE1_DMA_INSTANCE: - pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS) << 4; - break; - case NV_PFIFO_CACHE1_DMA_PUT: - user.channel_control[pfifo.cache1.channel_id].dma_put = value; - break; - case NV_PFIFO_CACHE1_DMA_GET: - user.channel_control[pfifo.cache1.channel_id].dma_get = value; - break; - case NV_PFIFO_CACHE1_DMA_SUBROUTINE: - pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET); - pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE); - break; - case NV_PFIFO_CACHE1_PULL0: { - std::lock_guard lk(pfifo.cache1.mutex); - - if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS) - && !pfifo.cache1.pull_enabled) { - pfifo.cache1.pull_enabled = true; - - /* the puller thread should wake up */ - pfifo.cache1.cache_cond.notify_all(); - } else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS) - && pfifo.cache1.pull_enabled) { - pfifo.cache1.pull_enabled = false; - } - } break; - case NV_PFIFO_CACHE1_ENGINE: { - std::lock_guard lk(pfifo.cache1.mutex); - - for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { - pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3); - } - - } break; - case NV_PFIFO_CACHE1_DMA_DCOUNT: - pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE); - break; - case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: - pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET); - break; - case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: - pfifo.cache1.rsvd_shadow = value; - break; - case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: - pfifo.cache1.data_shadow = value; - break; - default: - DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO); - break; - } - - DEVICE_WRITE32_END(PFIFO); -} - -DEVICE_READ32(PRMA) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMA); // TODO : DEVICE_READ32_REG(prma); - break; - } - - DEVICE_READ32_END(PRMA); -} - -DEVICE_WRITE32(PRMA) -{ - switch(addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMA); // TODO : DEVICE_WRITE32_REG(prma); - break; - } - - DEVICE_WRITE32_END(PRMA); -} - - -DEVICE_READ32(PVIDEO) -{ - DEVICE_READ32_SWITCH() { - - case NV_PVIDEO_STOP: - result = 0; - break; - default: - DEVICE_READ32_REG(pvideo); - break; - } - - DEVICE_READ32_END(PVIDEO); -} - -DEVICE_WRITE32(PVIDEO) -{ - switch (addr) { - case NV_PVIDEO_BUFFER: - pvideo.regs[addr] = value; - // TODO: vga.enable_overlay = true; - // pvideo_vga_invalidate(d); - break; - case NV_PVIDEO_STOP: - pvideo.regs[NV_PVIDEO_BUFFER] = 0; - // TODO: vga.enable_overlay = false; - //pvideo_vga_invalidate(d); - break; - default: - DEVICE_WRITE32_REG(pvideo); - break; - } - - DEVICE_WRITE32_END(PVIDEO); -} - -DEVICE_READ32(PCOUNTER) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PCOUNTER); // TODO : DEVICE_READ32_REG(pcounter); - break; - } - - DEVICE_READ32_END(PCOUNTER); -} - -DEVICE_WRITE32(PCOUNTER) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PCOUNTER); // TODO : DEVICE_WRITE32_REG(pcounter); - break; - } - - DEVICE_WRITE32_END(PCOUNTER); -} - -static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) -{ - union { - uint64_t ll; - struct { - uint32_t low, high; - } l; - } u, res; - uint64_t rl, rh; - - u.ll = a; - rl = (uint64_t)u.l.low * (uint64_t)b; - rh = (uint64_t)u.l.high * (uint64_t)b; - rh += (rl >> 32); - res.l.high = rh / c; - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; - return res.ll; -} - -/* PIMTER - time measurement and time-based alarms */ -static uint32_t ptimer_get_clock() -{ - // Get time in nanoseconds - long int time = static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); - - return muldiv64(time, pramdac.core_clock_freq * ptimer.numerator, CLOCKS_PER_SEC * ptimer.denominator); -} - -DEVICE_READ32(PTIMER) -{ - DEVICE_READ32_SWITCH() { - case NV_PTIMER_INTR_0: - result = ptimer.pending_interrupts; - break; - case NV_PTIMER_INTR_EN_0: - result = ptimer.enabled_interrupts; - break; - case NV_PTIMER_NUMERATOR: - result = ptimer.numerator; - break; - case NV_PTIMER_DENOMINATOR: - result = ptimer.denominator; - break; - case NV_PTIMER_TIME_0: - result = (ptimer_get_clock() & 0x7ffffff) << 5; - break; - case NV_PTIMER_TIME_1: - result = (ptimer_get_clock() >> 27) & 0x1fffffff; - break; - default: - result = 0; - //DEVICE_READ32_REG(ptimer); // Was : DEBUG_READ32_UNHANDLED(PTIMER); - break; - } - - DEVICE_READ32_END(PTIMER); -} - - -DEVICE_WRITE32(PTIMER) -{ - switch (addr) { - - case NV_PTIMER_INTR_0: - ptimer.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PTIMER_INTR_EN_0: - ptimer.enabled_interrupts = value; - update_irq(); - break; - case NV_PTIMER_DENOMINATOR: - ptimer.denominator = value; - break; - case NV_PTIMER_NUMERATOR: - ptimer.numerator = value; - break; - case NV_PTIMER_ALARM_0: - ptimer.alarm_time = value; - break; - default: - //DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER); - break; - } - - DEVICE_WRITE32_END(PTIMER); -} - - -DEVICE_READ32(PVPE) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PVPE); // TODO : DEVICE_READ32_REG(pvpe); - break; - } - - DEVICE_READ32_END(PVPE); -} - - -DEVICE_WRITE32(PVPE) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PVPE); // TODO : DEVICE_WRITE32_REG(pvpe); - break; - } - - DEVICE_WRITE32_END(PVPE); -} - - -DEVICE_READ32(PTV) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PTV); // TODO : DEVICE_READ32_REG(ptv); - break; - } - - DEVICE_READ32_END(PTV); -} - -DEVICE_WRITE32(PTV) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PTV); // TODO : DEVICE_WRITE32_REG(ptv); - break; - } - - DEVICE_WRITE32_END(PTV); -} - - -DEVICE_READ32(PRMFB) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMFB); // TODO : DEVICE_READ32_REG(prmfb); - break; - } - - DEVICE_READ32_END(PRMFB); -} - -DEVICE_WRITE32(PRMFB) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMFB); // TODO : DEVICE_WRITE32_REG(prmfb); - break; - } - - DEVICE_WRITE32_END(PRMFB); -} - - -DEVICE_READ32(PRMVIO) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio); - break; - } - - DEVICE_READ32_END(PRMVIO); -} - -DEVICE_WRITE32(PRMVIO) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio); - break; - } - - DEVICE_WRITE32_END(PRMVIO); -} - - -DEVICE_READ32(PFB) -{ - DEVICE_READ32_SWITCH() { - case NV_PFB_CFG0: - result = 3; // = NV_PFB_CFG0_PART_4 - break; - case NV_PFB_CSTATUS: - { - if (g_bIsChihiro || g_bIsDebug) { result = CONTIGUOUS_MEMORY_CHIHIRO_SIZE; break; } - result = CONTIGUOUS_MEMORY_XBOX_SIZE; - } - break; - case NV_PFB_WBC: - result = 0; // = !NV_PFB_WBC_FLUSH - break; - default: - DEVICE_READ32_REG(pfb); - break; - } - - DEVICE_READ32_END(PFB); -} - -DEVICE_WRITE32(PFB) -{ - switch (addr) { - default: - DEVICE_WRITE32_REG(pfb); - break; - } - - DEVICE_WRITE32_END(PFB); -} - - -DEVICE_READ32(PSTRAPS) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PSTRAPS); - break; - } - - DEVICE_READ32_END(PSTRAPS); -} - -DEVICE_WRITE32(PSTRAPS) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PSTRAPS); - break; - } - - DEVICE_WRITE32_END(PSTRAPS); -} - - -DEVICE_READ32(PGRAPH) -{ - std::lock_guard lk(pgraph.mutex); - - DEVICE_READ32_SWITCH() { - case NV_PGRAPH_INTR: - result = pgraph.pending_interrupts; - break; - case NV_PGRAPH_INTR_EN: - result = pgraph.enabled_interrupts; - break; - case NV_PGRAPH_NSOURCE: - result = pgraph.notify_source; - break; - case NV_PGRAPH_CTX_USER: - SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D, pgraph.context[pgraph.channel_id].channel_3d); - SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D_VALID, 1); - SET_MASK(result, NV_PGRAPH_CTX_USER_SUBCH, pgraph.context[pgraph.channel_id].subchannel << 13); - SET_MASK(result, NV_PGRAPH_CTX_USER_CHID, pgraph.channel_id); - break; - case NV_PGRAPH_TRAPPED_ADDR: - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_CHID, pgraph.trapped_channel_id); - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_SUBCH, pgraph.trapped_subchannel); - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_MTHD, pgraph.trapped_method); - break; - case NV_PGRAPH_TRAPPED_DATA_LOW: - result = pgraph.trapped_data[0]; - break; - case NV_PGRAPH_FIFO: - SET_MASK(result, NV_PGRAPH_FIFO_ACCESS, pgraph.fifo_access); - break; - case NV_PGRAPH_CHANNEL_CTX_TABLE: - result = pgraph.context_table >> 4; - break; - case NV_PGRAPH_CHANNEL_CTX_POINTER: - result = pgraph.context_address >> 4; - break; - default: - DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH); - } - - DEVICE_READ32_END(PGRAPH); -} - -static void pgraph_set_context_user(uint32_t value) -{ - pgraph.channel_id = (value & NV_PGRAPH_CTX_USER_CHID) >> 24; - pgraph.context[pgraph.channel_id].channel_3d = GET_MASK(value, NV_PGRAPH_CTX_USER_CHANNEL_3D); - pgraph.context[pgraph.channel_id].subchannel = GET_MASK(value, NV_PGRAPH_CTX_USER_SUBCH); -} - -DEVICE_WRITE32(PGRAPH) -{ - std::lock_guard lk(pgraph.mutex); - - switch (addr) { - case NV_PGRAPH_INTR: - pgraph.pending_interrupts &= ~value; - pgraph.interrupt_cond.notify_all(); - break; - case NV_PGRAPH_INTR_EN: - pgraph.enabled_interrupts = value; - break; - case NV_PGRAPH_CTX_CONTROL: - pgraph.channel_valid = (value & NV_PGRAPH_CTX_CONTROL_CHID); - break; - case NV_PGRAPH_CTX_USER: - pgraph_set_context_user(value); - break; - case NV_PGRAPH_INCREMENT: - if (value & NV_PGRAPH_INCREMENT_READ_3D) { - SET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_READ_3D, - (GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_READ_3D) + 1) - % GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_MODULO_3D)); - - pgraph.flip_3d.notify_all(); - } - break; - case NV_PGRAPH_FIFO: - pgraph.fifo_access = GET_MASK(value, NV_PGRAPH_FIFO_ACCESS); - pgraph.fifo_access_cond.notify_all(); - break; - case NV_PGRAPH_CHANNEL_CTX_TABLE: - pgraph.context_table = (value & NV_PGRAPH_CHANNEL_CTX_TABLE_INST) << 4; - break; - case NV_PGRAPH_CHANNEL_CTX_POINTER: - pgraph.context_address = - (value & NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4; - break; - case NV_PGRAPH_CHANNEL_CTX_TRIGGER: - if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) { - printf("PGRAPH: read channel %d context from %0x08X\n", - pgraph.channel_id, pgraph.context_address); - - uint8_t *context_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + pgraph.context_address); - uint32_t context_user = ldl_le_p((uint32_t*)context_ptr); - - printf(" - CTX_USER = 0x%x\n", context_user); - - - pgraph_set_context_user(context_user); - } - if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT) { - /* do stuff ... */ - } - - break; - default: - DEVICE_WRITE32_REG(pgraph); // Was : DEBUG_WRITE32_UNHANDLED(PGRAPH); - break; - } - - DEVICE_WRITE32_END(PGRAPH); -} - - -DEVICE_READ32(PCRTC) -{ - DEVICE_READ32_SWITCH() { - - case NV_PCRTC_INTR_0: - result = pcrtc.pending_interrupts; - break; - case NV_PCRTC_INTR_EN_0: - result = pcrtc.enabled_interrupts; - break; - case NV_PCRTC_START: - result = pcrtc.start; - break; - default: - result = 0; - //DEVICE_READ32_REG(pcrtc); // Was : DEBUG_READ32_UNHANDLED(PCRTC); - break; - } - - DEVICE_READ32_END(PCRTC); -} - -DEVICE_WRITE32(PCRTC) -{ - switch (addr) { - - case NV_PCRTC_INTR_0: - pcrtc.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PCRTC_INTR_EN_0: - pcrtc.enabled_interrupts = value; - update_irq(); - break; - case NV_PCRTC_START: - pcrtc.start = value &= 0x07FFFFFF; - break; - - default: - DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC); - break; - } - - DEVICE_WRITE32_END(PCRTC); -} - - -DEVICE_READ32(PRMCIO) -{ - DEVICE_READ32_SWITCH() { - case VGA_CRT_IM: - case VGA_CRT_IC: - result = prmcio.cr_index; - break; - case VGA_CRT_DM: - case VGA_CRT_DC: - result = prmcio.cr[prmcio.cr_index]; - - printf("vga: read CR%x = 0x%02x\n", prmcio.cr_index, result); - break; - default: - DEBUG_READ32_UNHANDLED(PRMCIO); - printf("vga: UNHANDLED ADDR %s\n", addr); - break; - } - - DEVICE_READ32_END(PRMCIO); -} - -DEVICE_WRITE32(PRMCIO) -{ - switch (addr) { - case VGA_CRT_IM: - case VGA_CRT_IC: - prmcio.cr_index = value; - break; - case VGA_CRT_DM: - case VGA_CRT_DC: - printf("vga: write CR%x = 0x%02x\n", prmcio.cr_index, value); - - /* handle CR0-7 protection */ - if ((prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && - prmcio.cr_index <= VGA_CRTC_OVERFLOW) { - /* can always write bit 4 of CR7 */ - if (prmcio.cr_index == VGA_CRTC_OVERFLOW) { - prmcio.cr[VGA_CRTC_OVERFLOW] = (prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) | - (value & 0x10); - EmuWarning("TODO: vbe_update_vgaregs"); - //vbe_update_vgaregs(); - } - return; - } - - prmcio.cr[prmcio.cr_index] = value; - EmuWarning("TODO: vbe_update_vgaregs"); - //vbe_update_vgaregs(); - - switch (prmcio.cr_index) { - case VGA_CRTC_H_TOTAL: - case VGA_CRTC_H_SYNC_START: - case VGA_CRTC_H_SYNC_END: - case VGA_CRTC_V_TOTAL: - case VGA_CRTC_OVERFLOW: - case VGA_CRTC_V_SYNC_END: - case VGA_CRTC_MODE: - // TODO: s->update_retrace_info(s); - EmuWarning("TODO: update_retrace_info"); - break; - } - break; - default: - DEBUG_WRITE32_UNHANDLED(PRMCIO); // TODO : DEVICE_WRITE32_REG(prmcio); - break; - } - - DEVICE_WRITE32_END(PRMCIO); -} - - -DEVICE_READ32(PRAMDAC) -{ - DEVICE_READ32_SWITCH() { - - case NV_PRAMDAC_NVPLL_COEFF: - result = pramdac.core_clock_coeff; - break; - case NV_PRAMDAC_MPLL_COEFF: - result = pramdac.memory_clock_coeff; - break; - case NV_PRAMDAC_VPLL_COEFF: - result = pramdac.video_clock_coeff; - break; - case NV_PRAMDAC_PLL_TEST_COUNTER: - /* emulated PLLs locked instantly? */ - result = NV_PRAMDAC_PLL_TEST_COUNTER_VPLL2_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK; - break; - - default: - //DEVICE_READ32_REG(pramdac); // Was : DEBUG_READ32_UNHANDLED(PRAMDAC); - break; - } - - DEVICE_READ32_END(PRAMDAC); -} - -DEVICE_WRITE32(PRAMDAC) -{ - switch (addr) { - - uint32_t m, n, p; - case NV_PRAMDAC_NVPLL_COEFF: - pramdac.core_clock_coeff = value; - - m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV; - n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV) >> 8; - p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV) >> 16; - - if (m == 0) { - pramdac.core_clock_freq = 0; - } - else { - pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n) - / (1 << p) / m; - } - - break; - case NV_PRAMDAC_MPLL_COEFF: - pramdac.memory_clock_coeff = value; - break; - case NV_PRAMDAC_VPLL_COEFF: - pramdac.video_clock_coeff = value; - break; - - default: - //DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC); - break; - } - - DEVICE_WRITE32_END(PRAMDAC); -} - - -DEVICE_READ32(PRMDIO) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMDIO); - break; - } - - DEVICE_READ32_END(PRMDIO); -} - -DEVICE_WRITE32(PRMDIO) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMDIO); - break; - } - - DEVICE_WRITE32_END(PRMDIO); -} - - -DEVICE_READ32(PRAMIN) -{ - DEVICE_READ32_SWITCH() { - default: - DEVICE_READ32_REG(pramin); - break; - } - - DEVICE_READ32_END(PRAMIN); -} - -DEVICE_WRITE32(PRAMIN) -{ - switch (addr) { - default: - DEVICE_WRITE32_REG(pramin); - break; - } - - DEVICE_WRITE32_END(PRAMIN); -} - - -DEVICE_READ32(USER) -{ - unsigned int channel_id = addr >> 16; - assert(channel_id < NV2A_NUM_CHANNELS); - - ChannelControl *control = &user.channel_control[channel_id]; - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - - /* PIO Mode */ - if (!channel_modes & (1 << channel_id)) { - assert(false); - } - - /* DMA Mode */ - addr &= 0xFFFF; - DEVICE_READ32_SWITCH() { - case NV_USER_DMA_PUT: - result = control->dma_put; - break; - case NV_USER_DMA_GET: - result = control->dma_get; - break; - case NV_USER_REF: - result = control->ref; - break; - default: - DEBUG_READ32_UNHANDLED(USER); - break; - } - - DEVICE_READ32_END(USER); -} - -DEVICE_WRITE32(USER) -{ - unsigned int channel_id = addr >> 16; - assert(channel_id < NV2A_NUM_CHANNELS); - - ChannelControl *control = &user.channel_control[channel_id]; - - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - - if (channel_modes & (1 << channel_id)) { - /* DMA Mode */ - switch (addr & 0xFFFF) { - case NV_USER_DMA_PUT: - control->dma_put = value; - - if (pfifo.cache1.push_enabled) { - pfifo_run_pusher(); - } - break; - case NV_USER_DMA_GET: - control->dma_get = value; - break; - case NV_USER_REF: - control->ref = value; - break; - default: - DEBUG_WRITE32_UNHANDLED(USER); - break; - } - } - else { - /* PIO Mode */ - assert(false); - } - - DEVICE_WRITE32_END(USER); -} - - -typedef struct NV2ABlockInfo { - uint32_t offset; - uint32_t size; - uint32_t(*read)(xbaddr addr); - void(*write)(xbaddr addr, uint32_t value); -} NV2ABlockInfo; - -static const NV2ABlockInfo regions[] = {{ - /* card master control */ - NV_PMC_ADDR, // = 0x000000 - NV_PMC_SIZE, // = 0x001000 - EmuNV2A_PMC_Read32, - EmuNV2A_PMC_Write32, - }, { - /* bus control */ - NV_PBUS_ADDR, // = 0x001000 - NV_PBUS_SIZE, // = 0x001000 - EmuNV2A_PBUS_Read32, - EmuNV2A_PBUS_Write32, - }, { - /* MMIO and DMA FIFO submission to PGRAPH and VPE */ - NV_PFIFO_ADDR, // = 0x002000 - NV_PFIFO_SIZE, // = 0x002000 - EmuNV2A_PFIFO_Read32, - EmuNV2A_PFIFO_Write32, - }, { - /* access to BAR0/BAR1 from real mode */ - NV_PRMA_ADDR, // = 0x007000 - NV_PRMA_SIZE, // = 0x001000 - EmuNV2A_PRMA_Read32, - EmuNV2A_PRMA_Write32, - }, { - /* video overlay */ - NV_PVIDEO_ADDR, // = 0x008000 - NV_PVIDEO_SIZE, // = 0x001000 - EmuNV2A_PVIDEO_Read32, - EmuNV2A_PVIDEO_Write32, - }, { - /* time measurement and time-based alarms */ - NV_PTIMER_ADDR, // = 0x009000 - NV_PTIMER_SIZE, // = 0x001000 - EmuNV2A_PTIMER_Read32, - EmuNV2A_PTIMER_Write32, - }, { - /* performance monitoring counters */ - NV_PCOUNTER_ADDR, // = 0x00a000 - NV_PCOUNTER_SIZE, // = 0x001000 - EmuNV2A_PCOUNTER_Read32, - EmuNV2A_PCOUNTER_Write32, - }, { - /* MPEG2 decoding engine */ - NV_PVPE_ADDR, // = 0x00b000 - NV_PVPE_SIZE, // = 0x001000 - EmuNV2A_PVPE_Read32, - EmuNV2A_PVPE_Write32, - }, { - /* TV encoder */ - NV_PTV_ADDR, // = 0x00d000 - NV_PTV_SIZE, // = 0x001000 - EmuNV2A_PTV_Read32, - EmuNV2A_PTV_Write32, - }, { - /* aliases VGA memory window */ - NV_PRMFB_ADDR, // = 0x0a0000 - NV_PRMFB_SIZE, // = 0x020000 - EmuNV2A_PRMFB_Read32, - EmuNV2A_PRMFB_Write32, - }, { - /* aliases VGA sequencer and graphics controller registers */ - NV_PRMVIO_ADDR, // = 0x0c0000 - NV_PRMVIO_SIZE, // = 0x001000 - EmuNV2A_PRMVIO_Read32, - EmuNV2A_PRMVIO_Write32, - },{ - /* memory interface */ - NV_PFB_ADDR, // = 0x100000 - NV_PFB_SIZE, // = 0x001000 - EmuNV2A_PFB_Read32, - EmuNV2A_PFB_Write32, - }, { - /* straps readout / override */ - NV_PSTRAPS_ADDR, // = 0x101000 - NV_PSTRAPS_SIZE, // = 0x001000 - EmuNV2A_PSTRAPS_Read32, - EmuNV2A_PSTRAPS_Write32, - }, { - /* accelerated 2d/3d drawing engine */ - NV_PGRAPH_ADDR, // = 0x400000 - NV_PGRAPH_SIZE, // = 0x002000 - EmuNV2A_PGRAPH_Read32, - EmuNV2A_PGRAPH_Write32, - }, { - /* more CRTC controls */ - NV_PCRTC_ADDR, // = 0x600000 - NV_PCRTC_SIZE, // = 0x001000 - EmuNV2A_PCRTC_Read32, - EmuNV2A_PCRTC_Write32, - }, { - /* aliases VGA CRTC and attribute controller registers */ - NV_PRMCIO_ADDR, // = 0x601000 - NV_PRMCIO_SIZE, // = 0x001000 - EmuNV2A_PRMCIO_Read32, - EmuNV2A_PRMCIO_Write32, - }, { - /* RAMDAC, cursor, and PLL control */ - NV_PRAMDAC_ADDR, // = 0x680000 - NV_PRAMDAC_SIZE, // = 0x001000 - EmuNV2A_PRAMDAC_Read32, - EmuNV2A_PRAMDAC_Write32, - }, { - /* aliases VGA palette registers */ - NV_PRMDIO_ADDR, // = 0x681000 - NV_PRMDIO_SIZE, // = 0x001000 - EmuNV2A_PRMDIO_Read32, - EmuNV2A_PRMDIO_Write32, - }, { - /* RAMIN access */ - NV_PRAMIN_ADDR, // = 0x700000 - NV_PRAMIN_SIZE, // = 0x100000 - EmuNV2A_PRAMIN_Read32, - EmuNV2A_PRAMIN_Write32, - },{ - /* PFIFO MMIO and DMA submission area */ - NV_USER_ADDR, // = 0x800000, - NV_USER_SIZE, // = 0x800000, - EmuNV2A_USER_Read32, - EmuNV2A_USER_Write32, - }, { - 0xFFFFFFFF, - 0, - nullptr, - nullptr, - }, -}; - -const NV2ABlockInfo* EmuNV2A_Block(xbaddr addr) -{ - // Find the block in the block table - const NV2ABlockInfo* block = ®ions[0]; - int i = 0; - - while (block->read != nullptr) { - if (addr >= block->offset && addr < block->offset + block->size) { - return block; - } - - block = ®ions[++i]; - } - - return nullptr; -} - -uint32_t EmuNV2A_Read(xbaddr addr, int size) -{ - const NV2ABlockInfo* block = EmuNV2A_Block(addr); - - if (block != nullptr) { - switch (size) { - case sizeof(uint8_t): - return block->read(addr - block->offset) & 0xFF; - case sizeof(uint16_t) : - return block->read(addr - block->offset) & 0xFFFF; - case sizeof(uint32_t) : - return block->read(addr - block->offset); - default: - EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); - return 0; - } - } - - EmuWarning("EmuNV2A_Read%d: Unhandled Read Address %08X", size, addr); - return 0; -} - -void EmuNV2A_Write(xbaddr addr, uint32_t value, int size) -{ - const NV2ABlockInfo* block = EmuNV2A_Block(addr); - - if (block != nullptr) { - int shift = 0; - xbaddr aligned_addr = 0; - uint32_t aligned_value = 0; - uint32_t mask = 0; - switch (size) { - case sizeof(uint8_t) : - shift = (addr & 3) * 8; - aligned_addr = addr & ~3; - aligned_value = block->read(aligned_addr - block->offset); - mask = 0xFF << shift; - - // TODO : Must the second byte be written to the next DWORD? - block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); - return; - case sizeof(uint16_t) : - assert((addr & 1) == 0); - - shift = (addr & 2) * 16; - aligned_addr = addr & ~3; - aligned_value = block->read(addr - block->offset); - mask = 0xFFFF << shift; - - // TODO : Must the second byte be written to the next DWORD? - block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); - return; - case sizeof(uint32_t) : - block->write(addr - block->offset, value); - return; - default: - EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); - return; - } - } - - EmuWarning("EmuNV2A_Write%d: Unhandled Write Address %08X (value %08X)", size, addr, value); - return; -} - -// -// OPENGL -// - -// -#define X_D3DTS_STAGECOUNT 4 - -HDC g_EmuWindowsDC = 0; -GLuint VertexProgramIDs[4] = { 0, 0, 0, 0 }; -uint ActiveVertexProgramID = 0; -GLuint TextureIDs[X_D3DTS_STAGECOUNT]= { 0, 0, 0, 0 }; - -// Vertex shader header, mapping Xbox1 registers to the ARB syntax (original version by KingOfC). -// Note about the use of 'conventional' attributes in here: Since we prefer to use only one shader -// for both immediate and deferred mode rendering, we alias all attributes to conventional inputs -// as much as possible. Only when there's no conventional attribute available, we use generic attributes. -// So in the following header, we use conventional attributes first, and generic attributes for the -// rest of the vertex attribute slots. This makes it possible to support immediate and deferred mode -// rendering with the same shader, and the use of the OpenGL fixed-function pipeline without a shader. -std::string DxbxVertexShaderHeader = - "!!ARBvp1.0\n" - "TEMP R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12;\n" - "ADDRESS A0;\n" -#ifdef DXBX_OPENGL_CONVENTIONAL - "ATTRIB v0 = vertex.position;\n" // Was: vertex.attrib[0] (See "conventional" note above) - "ATTRIB v1 = vertex.%s;\n" // Note : We replace this with "weight" or "attrib[1]" depending GL_ARB_vertex_blend - "ATTRIB v2 = vertex.normal;\n" // Was: vertex.attrib[2] - "ATTRIB v3 = vertex.color.primary;\n" // Was: vertex.attrib[3] - "ATTRIB v4 = vertex.color.secondary;\n" // Was: vertex.attrib[4] - "ATTRIB v5 = vertex.fogcoord;\n" // Was: vertex.attrib[5] - "ATTRIB v6 = vertex.attrib[6];\n" - "ATTRIB v7 = vertex.attrib[7];\n" - "ATTRIB v8 = vertex.texcoord[0];\n" // Was: vertex.attrib[8] - "ATTRIB v9 = vertex.texcoord[1];\n" // Was: vertex.attrib[9] - "ATTRIB v10 = vertex.texcoord[2];\n" // Was: vertex.attrib[10] - "ATTRIB v11 = vertex.texcoord[3];\n" // Was: vertex.attrib[11] -#else - "ATTRIB v0 = vertex.attrib[0];\n" - "ATTRIB v1 = vertex.attrib[1];\n" - "ATTRIB v2 = vertex.attrib[2];\n" - "ATTRIB v3 = vertex.attrib[3];\n" - "ATTRIB v4 = vertex.attrib[4];\n" - "ATTRIB v5 = vertex.attrib[5];\n" - "ATTRIB v6 = vertex.attrib[6];\n" - "ATTRIB v7 = vertex.attrib[7];\n" - "ATTRIB v8 = vertex.attrib[8];\n" - "ATTRIB v9 = vertex.attrib[9];\n" - "ATTRIB v10 = vertex.attrib[10];\n" - "ATTRIB v11 = vertex.attrib[11];\n" -#endif - "ATTRIB v12 = vertex.attrib[12];\n" - "ATTRIB v13 = vertex.attrib[13];\n" - "ATTRIB v14 = vertex.attrib[14];\n" - "ATTRIB v15 = vertex.attrib[15];\n" - "OUTPUT oPos = result.position;\n" - "OUTPUT oD0 = result.color.front.primary;\n" - "OUTPUT oD1 = result.color.front.secondary;\n" - "OUTPUT oB0 = result.color.back.primary;\n" - "OUTPUT oB1 = result.color.back.secondary;\n" - "OUTPUT oPts = result.pointsize;\n" - "OUTPUT oFog = result.fogcoord;\n" - "OUTPUT oT0 = result.texcoord[0];\n" - "OUTPUT oT1 = result.texcoord[1];\n" - "OUTPUT oT2 = result.texcoord[2];\n" - "OUTPUT oT3 = result.texcoord[3];\n" - "PARAM c[] = { program.env[0..191] };\n" // All constants in 1 array declaration (requires NV_gpu_program4?) - "PARAM mvp[4] = { state.matrix.mvp };\n"; - -void SetupPixelFormat(HDC DC) -{ - const PIXELFORMATDESCRIPTOR pfd = { - /* .nSize = */ sizeof(PIXELFORMATDESCRIPTOR), // size - /* .nVersion = */ 1, // version - /* .dwFlags = */ PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, // support double-buffering - /* .iPixelType = */ PFD_TYPE_RGBA, // color type - /* .cColorBits = */ 32, // preferred color depth - /* .cRedBits = */ 0, - /* .cRedShift = */ 0, // color bits (ignored) - /* .cGreenBits = */ 0, - /* .cGreenShift = */ 0, - /* .cBlueBits = */ 0, - /* .cBlueShift = */ 0, - /* .cAlphaBits = */ 0, - /* .cAlphaShift = */ 0, // no alpha buffer - /* .cAccumBits = */ 0, - /* .cAccumRedBits = */ 0, // no accumulation buffer, - /* .cAccumGreenBits = */ 0, // accum bits (ignored) - /* .cAccumBlueBits = */ 0, - /* .cAccumAlphaBits = */ 0, - /* .cDepthBits = */ 16, // depth buffer - /* .cStencilBits = */ 0, // no stencil buffer - /* .cAuxBuffers = */ 0, // no auxiliary buffers - /* .iLayerType= */ PFD_MAIN_PLANE, // main layer - /* .bReserved = */ 0, - /* .dwLayerMask = */ 0, - /* .dwVisibleMask = */ 0, - /* .dwDamageMask = */ 0 // no layer, visible, damage masks - }; - - int PixelFormat = ChoosePixelFormat(DC, &pfd); - if (PixelFormat == 0) - return; - - if (SetPixelFormat(DC, PixelFormat, &pfd) != TRUE) - return; -} - -// From https://github.com/inolen/redream/blob/master/src/video/gl_backend.c -static int rb_compile_shader(const char *source, GLenum shader_type, GLuint *shader) -{ - size_t sourceLength = strlen(source); - - *shader = glCreateShader(shader_type); - glShaderSource(*shader, 1, (const GLchar **)&source, - (const GLint *)&sourceLength); - glCompileShader(*shader); - - GLint compiled; - glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); - - if (!compiled) { -// rb_print_shader_log(*shader); - glDeleteShader(*shader); - return 0; - } - - return 1; -} - -void DxbxCompileShader(std::string Shader) -{ - int GLErrorPos; - -// if (MayLog(lfUnit)) -// DbgPrintf(" NV2A: New vertex program :\n" + Shader); - -/* -glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, Shader.size(), Shader.c_str()); - - // errors are catched - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &GLErrorPos); - */ - GLuint shader; - - GLErrorPos = rb_compile_shader(Shader.c_str(), GL_VERTEX_SHADER, &shader); // TODO : GL_VERTEX_SHADER_ARB ?? - /* - if (GLErrorPos > 0) - { - Shader.insert(GLErrorPos, "{ERROR}"); - EmuWarning("Program error at position %d:", GLErrorPos); - EmuWarning((char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)); - EmuWarning(Shader.c_str()); - } - */ -} -void InitOpenGLContext() -{ - HGLRC RC; - std::string szCode; - - g_EmuWindowsDC = GetDC(g_hEmuWindow); // Actually, you can use any windowed control here - SetupPixelFormat(g_EmuWindowsDC); - - RC = wglCreateContext(g_EmuWindowsDC); // makes OpenGL window out of DC - wglMakeCurrent(g_EmuWindowsDC, RC); // makes OpenGL window active - //ReadImplementationProperties(); // Determine a set of booleans indicating which OpenGL extensions are available - //ReadExtensions(); // Assign all OpenGL extension API's (DON'T call them if the extension is not available!) - - // Initialize the viewport : - //Viewport.X = 0; - //Viewport.Y = 0; - //Viewport.Width = g_EmuCDPD.pPresentationParameters.BackBufferWidth; - //Viewport.Height = g_EmuCDPD.pPresentationParameters.BackBufferHeight; - //Viewport.MinZ = -1.0; - //Viewport.MaxZ = 1.0; - - //DxbxUpdateTransformProjection(); - //DxbxUpdateViewport(); - - - //glutInit(); - { // rb_init_context(); - /* link in gl functions at runtime */ - glewExperimental = GL_TRUE; - GLenum err = glewInit(); - if (err != GLEW_OK) { - EmuWarning("GLEW initialization failed: %s", glewGetErrorString(err)); - return; - } - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Switch to left-handed coordinate space (as per http://www.opengl.org/resources/faq/technical/transformations.htm) : - // glScalef(1.0, 1.0, -1.0); - - // Set some defaults : - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); // Nearer Z coordinates cover further Z - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glAlphaFunc(GL_GEQUAL, 0.5); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // GL_LINE for wireframe - -/* - // TODO : The following code only works on cards that support the - // vertex program extensions (NVidia cards mainly); So for ATI we - // have to come up with another solution !!! - glGenProgramsARB(4, &VertexProgramIDs[0]); -*/ - -#ifdef DXBX_OPENGL_CONVENTIONAL - if (GL_ARB_vertex_blend) - DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "weight"); - else - DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "attrib[1]"); -#endif - - // Precompiled shader for the fixed function pipeline : - szCode = DxbxVertexShaderHeader + - "# This part adjusts the vertex position by the super-sampling scale & offset :\n" - "MOV R0, v0;\n" - "RCP R0.w, R0.w;\n" - "MUL R0, R0, c[0];\n" // c[-96] in D3D speak - applies SuperSampleScale - // Note : Use R12 instead of oPos because this is not yet the final assignment : - "ADD R12, R0, c[1];\n" // c[-95] in D3D speak - applies SuperSampleOffset - - "# This part just reads all other components and passes them to the output :\n" - "MOV oD0, v3;\n" - "MOV oD1, v4;\n" - "MOV oFog, v4.w;\n" // specular fog - // "MOV oFog, v0.z;\n" // z fog - // "RCP oFog, v0.w;\n" // w fog - "MOV oPts, v1.x;\n" - "MOV oB0, v7;\n" - "MOV oB1, v8;\n" - "MOV oT0, v9;\n" - "MOV oT1, v10;\n" - "MOV oT2, v11;\n" - "MOV oT3, v12;\n" - - "# This part applies the screen-space transform (not present when '#pragma screenspace' was used) :\n" - "MUL R12.xyz, R12, c[58];\n" // c[-38] in D3D speak - see EmuNV2A_ViewportScale, - "RCP R1.x, R12.w;\n" // Originally RCC, but that"s not supported in ARBvp1.0 (use "MIN R1, R1, 0" and "MAX R1, R1, 1"?) - "MAD R12.xyz, R12, R1.x, c[59];\n" // c[-37] in D3D speak - see EmuNV2A_ViewportOffset - - "# Dxbx addition : Transform the vertex to clip coordinates :\n" - "DP4 R0.x, mvp[0], R12;\n" - "DP4 R0.y, mvp[1], R12;\n" - "DP4 R0.z, mvp[2], R12;\n" - "DP4 R0.w, mvp[3], R12;\n" - "MOV R12, R0;\n" - - "# Apply Z coord mapping\n" - "ADD R12.z, R12.z, R12.z;\n" - "ADD R12.z, R12.z, -R12.w;\n" - - "# Here""s the final assignment to oPos :\n" - "MOV oPos, R12;\n" - "END\n"; // TODO : Check if newline is required? - -// glBindProgramARB(GL_VERTEX_PROGRAM_ARB, VertexProgramIDs[0]); - DxbxCompileShader(szCode); -} - -// HACK: Until we implement VGA/proper interrupt generation -// we simulate VBLANK by calling the interrupt at 60Hz -std::thread vblank_thread; -extern std::chrono::time_point> GetNextVBlankTime(); -static void nv2a_vblank_thread() -{ - auto nextVBlankTime = GetNextVBlankTime(); - - while (true) { - // Handle VBlank - if (std::chrono::steady_clock::now() > nextVBlankTime) { - pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK; - update_irq(); - nextVBlankTime = GetNextVBlankTime(); - } - } -} - -void EmuNV2A_Init() -{ - // Allocate PRAMIN Region - VirtualAlloc((void*)(NV2A_ADDR + NV_PRAMIN_ADDR), NV_PRAMIN_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - - pcrtc.start = 0; - - pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */ - pramdac.core_clock_freq = 189000000; - pramdac.memory_clock_coeff = 0; - pramdac.video_clock_coeff = 0x0003C20D; /* 25182Khz...? */ - - pfifo.puller_thread = std::thread(pfifo_puller_thread); - - // Only spawn VBlank thread when LLE is enabled - if (bLLE_GPU) { - vblank_thread = std::thread(nv2a_vblank_thread);; - } -} +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Win32->CxbxKrnl->EmuNV2A.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * (c) 2016 Luke Usher +// * +// * EmuNV2A.cpp is heavily based on code from XQEMU +// * Copyright(c) 2012 espes +// * Copyright(c) 2015 Jannik Vogel +// * https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a.c +// * +// * All rights reserved +// * +// ****************************************************************** +#define _XBOXKRNL_DEFEXTRN_ + +#define LOG_PREFIX "NV2A" + +#include // For __beginthreadex(), etc. +#include "vga.h" + +// prevent name collisions +namespace xboxkrnl +{ + #include // For PKINTERRUPT, etc. +}; + + +#ifdef _MSC_VER // Check if MS Visual C compiler +# pragma comment(lib, "opengl32.lib") // Compiler-specific directive to avoid manually configuration +//# pragma comment(lib, "glu32.lib") // Link libraries +# pragma comment(lib, "glew32.lib") +#endif + +#include // For uint32_t +#include // For std::string +#include +#include +#include +#include + +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\Emu.h" +#include "CxbxKrnl\EmuFS.h" +#include "CxbxKrnl\EmuKrnl.h" +#include "CxbxKrnl\HLEIntercept.h" + +#include "EmuNV2A.h" +#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox + +#include +#include +#include +#include +//#include + + +// Public Domain ffs Implementation +// See: http://snipplr.com/view/22147/stringsh-implementation/ +int ffs(int v) +{ + unsigned int x = v; + int c = 1; + + /* + * adapted from from + * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch + * + * a modified binary search algorithm to count 0 bits from + * the right (lsb). This algorithm should work regardless + * of the size of ints on the platform. + * + */ + + /* a couple special cases */ + if (x == 0) return 0; + if (x & 1) return 1; /* probably pretty common */ + + c = 1; + while ((x & 0xffff) == 0) { + x >>= 16; + c += 16; + } + if ((x & 0xff) == 0) { + x >>= 8; + c += 8; + } + if ((x & 0x0f) == 0) { + x >>= 4; + c += 4; + } + if ((x & 0x03) == 0) { + x >>= 2; + c += 2; + } + + c -= (x & 1); + c += 1; /* ffs() requires indexing bits from 1 */ + /* ie., the lsb is bit 1, not bit 0 */ + return c; +} + +inline int GET_MASK(int v, int mask) { + return (((v) & (mask)) >> (ffs(mask) - 1)); +}; + +inline int SET_MASK(int v, int mask, int val) { + const unsigned int __val = (val); + const unsigned int __mask = (mask); + + (v) &= ~(__mask); + return (v) |= ((__val) << (ffs(__mask)-1)) & (__mask); +} + +#define CASE_4(v, step) \ + case (v): \ + case (v)+(step) : \ + case (v)+(step) * 2: \ + case (v)+(step) * 3 + + +enum FifoMode { + FIFO_PIO = 0, + FIFO_DMA = 1, +}; + +enum FIFOEngine { + ENGINE_SOFTWARE = 0, + ENGINE_GRAPHICS = 1, + ENGINE_DVD = 2, +}; + +typedef struct RAMHTEntry { + uint32_t handle; + xbaddr instance; + enum FIFOEngine engine; + unsigned int channel_id : 5; + bool valid; +} RAMHTEntry; + +typedef struct DMAObject { + unsigned int dma_class; + unsigned int dma_target; + xbaddr address; + xbaddr limit; +} DMAObject; + +typedef struct VertexAttribute { + bool dma_select; + xbaddr offset; + + /* inline arrays are packed in order? + * Need to pass the offset to converted attributes */ + unsigned int inline_array_offset; + + float inline_value[4]; + + unsigned int format; + unsigned int size; /* size of the data type */ + unsigned int count; /* number of components */ + uint32_t stride; + + bool needs_conversion; + uint8_t *converted_buffer; + unsigned int converted_elements; + unsigned int converted_size; + unsigned int converted_count; + + float *inline_buffer; + + GLint gl_count; + GLenum gl_type; + GLboolean gl_normalize; + + GLuint gl_converted_buffer; + GLuint gl_inline_buffer; +} VertexAttribute; + +typedef struct Surface { + bool draw_dirty; + bool buffer_dirty; + bool write_enabled_cache; + unsigned int pitch; + + xbaddr offset; +} Surface; + +typedef struct SurfaceShape { + unsigned int z_format; + unsigned int color_format; + unsigned int zeta_format; + unsigned int log_width, log_height; + unsigned int clip_x, clip_y; + unsigned int clip_width, clip_height; + unsigned int anti_aliasing; +} SurfaceShape; + +typedef struct TextureShape { + bool cubemap; + unsigned int dimensionality; + unsigned int color_format; + unsigned int levels; + unsigned int width, height, depth; + + unsigned int min_mipmap_level, max_mipmap_level; + unsigned int pitch; +} TextureShape; + +typedef struct TextureKey { + TextureShape state; + uint64_t data_hash; + uint8_t* texture_data; + uint8_t* palette_data; +} TextureKey; + +typedef struct TextureBinding { + GLenum gl_target; + GLuint gl_texture; + unsigned int refcnt; +} TextureBinding; + +typedef struct KelvinState { + xbaddr dma_notifies; + xbaddr dma_state; + xbaddr dma_semaphore; + unsigned int semaphore_offset; +} KelvinState; + +typedef struct ContextSurfaces2DState { + xbaddr dma_image_source; + xbaddr dma_image_dest; + unsigned int color_format; + unsigned int source_pitch, dest_pitch; + xbaddr source_offset, dest_offset; + +} ContextSurfaces2DState; + +typedef struct ImageBlitState { + xbaddr context_surfaces; + unsigned int operation; + unsigned int in_x, in_y; + unsigned int out_x, out_y; + unsigned int width, height; + +} ImageBlitState; + +typedef struct GraphicsObject { + uint8_t graphics_class; + union { + ContextSurfaces2DState context_surfaces_2d; + + ImageBlitState image_blit; + + KelvinState kelvin; + } data; +} GraphicsObject; + +typedef struct GraphicsSubchannel { + xbaddr object_instance; + GraphicsObject object; + uint32_t object_cache[5]; +} GraphicsSubchannel; + +typedef struct GraphicsContext { + bool channel_3d; + unsigned int subchannel; +} GraphicsContext; + +typedef struct CacheEntry { + unsigned int method : 14; + unsigned int subchannel : 3; + bool nonincreasing; + uint32_t parameter; +} CacheEntry; + +typedef struct Cache1State { + unsigned int channel_id; + FifoMode mode; + + /* Pusher state */ + bool push_enabled; + bool dma_push_enabled; + bool dma_push_suspended; + xbaddr dma_instance; + + bool method_nonincreasing; + unsigned int method : 14; + unsigned int subchannel : 3; + unsigned int method_count : 24; + uint32_t dcount; + + bool subroutine_active; + xbaddr subroutine_return; + xbaddr get_jmp_shadow; + uint32_t rsvd_shadow; + uint32_t data_shadow; + uint32_t error; + + bool pull_enabled; + enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS]; + enum FIFOEngine last_engine; + + /* The actual command queue */ + std::mutex mutex; + std::condition_variable cache_cond; + std::queue cache; + std::queue working_cache; +} Cache1State; + +typedef struct ChannelControl { + xbaddr dma_put; + xbaddr dma_get; + uint32_t ref; +} ChannelControl; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t regs[NV_PMC_SIZE]; // TODO : union +} pmc; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + std::thread puller_thread; + Cache1State cache1; + uint32_t regs[NV_PFIFO_SIZE]; // TODO : union +} pfifo; + +struct { + uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union +} pvideo; + + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t numerator; + uint32_t denominator; + uint32_t alarm_time; + uint32_t regs[NV_PTIMER_SIZE]; // TODO : union +} ptimer; + +struct { + uint32_t regs[NV_PFB_SIZE]; // TODO : union +} pfb; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t start; + uint32_t regs[NV_PCRTC_SIZE]; // TODO : union +} pcrtc; + +struct { + uint32_t core_clock_coeff; + uint64_t core_clock_freq; + uint32_t memory_clock_coeff; + uint32_t video_clock_coeff; + uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union +} pramdac; + +struct { + uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union +} pramin; + +struct { + ChannelControl channel_control[NV2A_NUM_CHANNELS]; +} user; + +// PRMCIO (Actually the VGA controller) +struct { + uint8_t cr_index; + uint8_t cr[256]; /* CRT registers */ +} prmcio; + +struct { + std::mutex mutex; + + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + std::condition_variable interrupt_cond; + + xbaddr context_table; + xbaddr context_address; + + + unsigned int trapped_method; + unsigned int trapped_subchannel; + unsigned int trapped_channel_id; + uint32_t trapped_data[2]; + uint32_t notify_source; + + bool fifo_access; + std::condition_variable fifo_access_cond; + std::condition_variable flip_3d; + + unsigned int channel_id; + bool channel_valid; + GraphicsContext context[NV2A_NUM_CHANNELS]; + + xbaddr dma_color, dma_zeta; + Surface surface_color, surface_zeta; + unsigned int surface_type; + SurfaceShape surface_shape; + SurfaceShape last_surface_shape; + + xbaddr dma_a, dma_b; + //GLruCache *texture_cache; + bool texture_dirty[NV2A_MAX_TEXTURES]; + TextureBinding *texture_binding[NV2A_MAX_TEXTURES]; + + //GHashTable *shader_cache; + //ShaderBinding *shader_binding; + + bool texture_matrix_enable[NV2A_MAX_TEXTURES]; + + /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ + float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */ + + // wglContext *gl_context; + GLuint gl_framebuffer; + GLuint gl_color_buffer, gl_zeta_buffer; + GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS]; + + xbaddr dma_report; + xbaddr report_offset; + bool zpass_pixel_count_enable; + unsigned int zpass_pixel_count_result; + unsigned int gl_zpass_pixel_count_query_count; + GLuint* gl_zpass_pixel_count_queries; + + xbaddr dma_vertex_a, dma_vertex_b; + + unsigned int primitive_mode; + + bool enable_vertex_program_write; + + //uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE]; + + uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; + bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS]; + + /* lighting constant arrays */ + uint32_t ltctxa[NV2A_LTCTXA_COUNT][4]; + bool ltctxa_dirty[NV2A_LTCTXA_COUNT]; + uint32_t ltctxb[NV2A_LTCTXB_COUNT][4]; + bool ltctxb_dirty[NV2A_LTCTXB_COUNT]; + uint32_t ltc1[NV2A_LTC1_COUNT][4]; + bool ltc1_dirty[NV2A_LTC1_COUNT]; + + // should figure out where these are in lighting context + float light_infinite_half_vector[NV2A_MAX_LIGHTS][3]; + float light_infinite_direction[NV2A_MAX_LIGHTS][3]; + float light_local_position[NV2A_MAX_LIGHTS][3]; + float light_local_attenuation[NV2A_MAX_LIGHTS][3]; + + //VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES]; + + unsigned int inline_array_length; + uint32_t inline_array[NV2A_MAX_BATCH_LENGTH]; + GLuint gl_inline_array_buffer; + + unsigned int inline_elements_length; + uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH]; + + unsigned int inline_buffer_length; + + unsigned int draw_arrays_length; + unsigned int draw_arrays_max_count; + + /* FIXME: Unknown size, possibly endless, 1000 will do for now */ + GLint gl_draw_arrays_start[1000]; + GLsizei gl_draw_arrays_count[1000]; + + GLuint gl_element_buffer; + GLuint gl_memory_buffer; + GLuint gl_vertex_array; + + uint32_t regs[NV_PGRAPH_SIZE]; // TODO : union +} pgraph; + +static void update_irq() +{ + /* PFIFO */ + if (pfifo.pending_interrupts & pfifo.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO; + } + + /* PCRTC */ + if (pcrtc.pending_interrupts & pcrtc.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC; + } + + /* PGRAPH */ + if (pgraph.pending_interrupts & pgraph.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH; + } + + /* TODO : PBUS * / + if (pbus.pending_interrupts & pbus.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS; + } + else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS; + } */ + + /* TODO : SOFTWARE * / + if (user.pending_interrupts & user.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE; + } + else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE; + } */ + + if (pmc.pending_interrupts && pmc.enabled_interrupts) { + HalSystemInterrupts[3].Assert(true); + } else { + HalSystemInterrupts[3].Assert(false); + } + + SwitchToThread(); +} + + +#define DEBUG_START(DEV) \ +const char *DebugNV_##DEV##(xbaddr addr) \ +{ \ + switch (addr) { +#define DEBUG_CASE(a) \ + case a: return #a; +#define DEBUG_CASE_EX(a, c) \ + case a: return #a##c; +#define DEBUG_END(DEV) \ + default: \ + return "Unknown " #DEV " Address"; \ + } \ +} + +DEBUG_START(PMC) + DEBUG_CASE(NV_PMC_BOOT_0); + DEBUG_CASE(NV_PMC_INTR_0); + DEBUG_CASE(NV_PMC_INTR_EN_0); + DEBUG_CASE(NV_PMC_ENABLE); +DEBUG_END(PMC) + +DEBUG_START(PBUS) + DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID"); + DEBUG_CASE(NV_PBUS_PCI_NV_1); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, ":LATENCY_TIMER"); + DEBUG_CASE(NV_PBUS_PCI_NV_4); + DEBUG_CASE(NV_PBUS_PCI_NV_5); + DEBUG_CASE(NV_PBUS_PCI_NV_6); + DEBUG_CASE(NV_PBUS_PCI_NV_7); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, ":SUBSYSTEM"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, ":ROM_BASE"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, ":CAP_PTR"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, ":RESERVED"); + DEBUG_CASE(NV_PBUS_PCI_NV_15); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, ":SUBSYSTEM"); + DEBUG_CASE(NV_PBUS_PCI_NV_17); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, ":AGP_STATUS"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, ":AGP_COMMAND"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, ":ROM_SHADOW"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, ":VGA"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, ":SCRATCH"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, ":DT_TIMEOUT"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, ":PME"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, ":POWER_STATE"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, ":RESERVED"); +DEBUG_END(PBUS) + +DEBUG_START(PFIFO) + DEBUG_CASE(NV_PFIFO_INTR_0); + DEBUG_CASE(NV_PFIFO_INTR_EN_0); + DEBUG_CASE(NV_PFIFO_RAMHT); + DEBUG_CASE(NV_PFIFO_RAMFC); + DEBUG_CASE(NV_PFIFO_RAMRO); + DEBUG_CASE(NV_PFIFO_RUNOUT_STATUS); + DEBUG_CASE(NV_PFIFO_MODE); + DEBUG_CASE(NV_PFIFO_DMA); + DEBUG_CASE(NV_PFIFO_CACHE1_PUSH0); + DEBUG_CASE(NV_PFIFO_CACHE1_PUSH1); + DEBUG_CASE(NV_PFIFO_CACHE1_STATUS); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUSH); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_FETCH); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_STATE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_INSTANCE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUT); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_SUBROUTINE); + DEBUG_CASE(NV_PFIFO_CACHE1_PULL0); + DEBUG_CASE(NV_PFIFO_CACHE1_ENGINE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DCOUNT); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_RSVD_SHADOW); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DATA_SHADOW); +DEBUG_END(PFIFO) + +DEBUG_START(PRMA) +DEBUG_END(PRMA) + +DEBUG_START(PVIDEO) + DEBUG_CASE(NV_PVIDEO_INTR); + DEBUG_CASE(NV_PVIDEO_INTR_EN); + DEBUG_CASE(NV_PVIDEO_BUFFER); + DEBUG_CASE(NV_PVIDEO_STOP); + DEBUG_CASE(NV_PVIDEO_BASE); + DEBUG_CASE(NV_PVIDEO_LIMIT); + DEBUG_CASE(NV_PVIDEO_LUMINANCE); + DEBUG_CASE(NV_PVIDEO_CHROMINANCE); + DEBUG_CASE(NV_PVIDEO_OFFSET); + DEBUG_CASE(NV_PVIDEO_SIZE_IN); + DEBUG_CASE(NV_PVIDEO_POINT_IN); + DEBUG_CASE(NV_PVIDEO_DS_DX); + DEBUG_CASE(NV_PVIDEO_DT_DY); + DEBUG_CASE(NV_PVIDEO_POINT_OUT); + DEBUG_CASE(NV_PVIDEO_SIZE_OUT); + DEBUG_CASE(NV_PVIDEO_FORMAT); +DEBUG_END(PVIDEO) + +DEBUG_START(PTIMER) + DEBUG_CASE(NV_PTIMER_INTR_0); + DEBUG_CASE(NV_PTIMER_INTR_EN_0); + DEBUG_CASE(NV_PTIMER_NUMERATOR); + DEBUG_CASE(NV_PTIMER_DENOMINATOR); + DEBUG_CASE(NV_PTIMER_TIME_0); + DEBUG_CASE(NV_PTIMER_TIME_1); + DEBUG_CASE(NV_PTIMER_ALARM_0); + +DEBUG_END(PTIMER) + +DEBUG_START(PCOUNTER) +DEBUG_END(PCOUNTER) + +DEBUG_START(PVPE) +DEBUG_END(PVPE) + +DEBUG_START(PTV) +DEBUG_END(PTV) + +DEBUG_START(PRMFB) +DEBUG_END(PRMFB) + +DEBUG_START(PRMVIO) +DEBUG_END(PRMVIO) + +DEBUG_START(PFB) + DEBUG_CASE(NV_PFB_CFG0) + DEBUG_CASE(NV_PFB_CSTATUS) + DEBUG_CASE(NV_PFB_REFCTRL) + DEBUG_CASE(NV_PFB_NVM) // NV_PFB_NVM_MODE_DISABLE + DEBUG_CASE(NV_PFB_PIN) + DEBUG_CASE(NV_PFB_PAD) + DEBUG_CASE(NV_PFB_TIMING0) + DEBUG_CASE(NV_PFB_TIMING1) + DEBUG_CASE(NV_PFB_TIMING2) + DEBUG_CASE(NV_PFB_TILE) + DEBUG_CASE(NV_PFB_TLIMIT) + DEBUG_CASE(NV_PFB_TSIZE) + DEBUG_CASE(NV_PFB_TSTATUS) + DEBUG_CASE(NV_PFB_MRS) + DEBUG_CASE(NV_PFB_EMRS) + DEBUG_CASE(NV_PFB_MRS_EXT) + DEBUG_CASE(NV_PFB_EMRS_EXT) + DEBUG_CASE(NV_PFB_REF) + DEBUG_CASE(NV_PFB_PRE) + DEBUG_CASE(NV_PFB_ZCOMP) + DEBUG_CASE(NV_PFB_ARB_PREDIVIDER) + DEBUG_CASE(NV_PFB_ARB_TIMEOUT) + DEBUG_CASE(NV_PFB_ARB_XFER_REM) + DEBUG_CASE(NV_PFB_ARB_DIFF_BANK) + DEBUG_CASE(NV_PFB_CLOSE_PAGE0) + DEBUG_CASE(NV_PFB_CLOSE_PAGE1) + DEBUG_CASE(NV_PFB_CLOSE_PAGE2) + DEBUG_CASE(NV_PFB_BPARB) + DEBUG_CASE(NV_PFB_CMDQ0) + DEBUG_CASE(NV_PFB_CMDQ1) + DEBUG_CASE(NV_PFB_ILL_INSTR) + DEBUG_CASE(NV_PFB_RT) + DEBUG_CASE(NV_PFB_AUTOCLOSE) + DEBUG_CASE(NV_PFB_WBC) + DEBUG_CASE(NV_PFB_CMDQ_PRT) + DEBUG_CASE(NV_PFB_CPU_RRQ) + DEBUG_CASE(NV_PFB_BYPASS); +DEBUG_END(PFB) + +DEBUG_START(PSTRAPS) +DEBUG_END(PSTRAPS) + +DEBUG_START(PGRAPH) + DEBUG_CASE(NV_PGRAPH_INTR); + DEBUG_CASE(NV_PGRAPH_NSOURCE); + DEBUG_CASE(NV_PGRAPH_INTR_EN); + DEBUG_CASE(NV_PGRAPH_CTX_CONTROL); + DEBUG_CASE(NV_PGRAPH_CTX_USER); + DEBUG_CASE(NV_PGRAPH_CTX_SWITCH1); + DEBUG_CASE(NV_PGRAPH_TRAPPED_ADDR); + DEBUG_CASE(NV_PGRAPH_TRAPPED_DATA_LOW); + DEBUG_CASE(NV_PGRAPH_SURFACE); + DEBUG_CASE(NV_PGRAPH_INCREMENT); + DEBUG_CASE(NV_PGRAPH_FIFO); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TABLE); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_POINTER); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TRIGGER); + DEBUG_CASE(NV_PGRAPH_CSV0_D); + DEBUG_CASE(NV_PGRAPH_CSV0_C); + DEBUG_CASE(NV_PGRAPH_CSV1_B); + DEBUG_CASE(NV_PGRAPH_CSV1_A); + DEBUG_CASE(NV_PGRAPH_CHEOPS_OFFSET); + DEBUG_CASE(NV_PGRAPH_BLEND); + DEBUG_CASE(NV_PGRAPH_BLENDCOLOR); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR0); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR1); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR2); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR3); + DEBUG_CASE(NV_PGRAPH_BUMPOFFSET1); + DEBUG_CASE(NV_PGRAPH_BUMPSCALE1); + DEBUG_CASE(NV_PGRAPH_CLEARRECTX); + DEBUG_CASE(NV_PGRAPH_CLEARRECTY); + DEBUG_CASE(NV_PGRAPH_COLORCLEARVALUE); + DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR0); + DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR1); + DEBUG_CASE(NV_PGRAPH_COMBINEALPHAI0); + DEBUG_CASE(NV_PGRAPH_COMBINEALPHAO0); + DEBUG_CASE(NV_PGRAPH_COMBINECOLORI0); + DEBUG_CASE(NV_PGRAPH_COMBINECOLORO0); + DEBUG_CASE(NV_PGRAPH_COMBINECTL); + DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG0); + DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG1); + DEBUG_CASE(NV_PGRAPH_CONTROL_0); + DEBUG_CASE(NV_PGRAPH_CONTROL_2); + DEBUG_CASE(NV_PGRAPH_CONTROL_3); + DEBUG_CASE(NV_PGRAPH_FOGCOLOR); + DEBUG_CASE(NV_PGRAPH_FOGPARAM0); + DEBUG_CASE(NV_PGRAPH_FOGPARAM1); + DEBUG_CASE(NV_PGRAPH_SETUPRASTER); + DEBUG_CASE(NV_PGRAPH_SHADERCLIPMODE); + DEBUG_CASE(NV_PGRAPH_SHADERCTL); + DEBUG_CASE(NV_PGRAPH_SHADERPROG); + DEBUG_CASE(NV_PGRAPH_SHADOWZSLOPETHRESHOLD); + DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR0); + DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR1); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS0); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS0_ADDRV); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS1); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS2); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS3); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_1); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_2); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_3); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_1); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_2); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_3); + DEBUG_CASE(NV_PGRAPH_TEXCTL2_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL2_1); + DEBUG_CASE(NV_PGRAPH_TEXFILTER0); + DEBUG_CASE(NV_PGRAPH_TEXFILTER1); + DEBUG_CASE(NV_PGRAPH_TEXFILTER2); + DEBUG_CASE(NV_PGRAPH_TEXFILTER3); + DEBUG_CASE(NV_PGRAPH_TEXFMT0); + DEBUG_CASE(NV_PGRAPH_TEXFMT1); + DEBUG_CASE(NV_PGRAPH_TEXFMT2); + DEBUG_CASE(NV_PGRAPH_TEXFMT3); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT0); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT1); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT2); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT3); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET0); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET1); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET2); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET3); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE0); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE1); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE2); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE3); + DEBUG_CASE(NV_PGRAPH_ZSTENCILCLEARVALUE); + DEBUG_CASE(NV_PGRAPH_ZCLIPMIN); + DEBUG_CASE(NV_PGRAPH_ZOFFSETBIAS); + DEBUG_CASE(NV_PGRAPH_ZOFFSETFACTOR); + DEBUG_CASE(NV_PGRAPH_EYEVEC0); + DEBUG_CASE(NV_PGRAPH_EYEVEC1); + DEBUG_CASE(NV_PGRAPH_EYEVEC2); + DEBUG_CASE(NV_PGRAPH_ZCLIPMAX); +DEBUG_END(PGRAPH) + +DEBUG_START(PCRTC) + DEBUG_CASE(NV_PCRTC_INTR_0); + DEBUG_CASE(NV_PCRTC_INTR_EN_0); + DEBUG_CASE(NV_PCRTC_START); + DEBUG_CASE(NV_PCRTC_CONFIG); + +DEBUG_END(PCRTC) + +DEBUG_START(PRMCIO) + DEBUG_CASE(VGA_CRT_DC); + DEBUG_CASE(VGA_CRT_DM); + DEBUG_CASE(VGA_ATT_R); + DEBUG_CASE(VGA_ATT_W); + DEBUG_CASE(VGA_GFX_D); + DEBUG_CASE(VGA_SEQ_D); + DEBUG_CASE(VGA_MIS_R); + DEBUG_CASE(VGA_MIS_W); + DEBUG_CASE(VGA_FTC_R); + DEBUG_CASE(VGA_IS1_RC); + DEBUG_CASE(VGA_IS1_RM); + DEBUG_CASE(VGA_PEL_D); + DEBUG_CASE(VGA_PEL_MSK); + DEBUG_CASE(VGA_CRT_IC); + DEBUG_CASE(VGA_CRT_IM); + DEBUG_CASE(VGA_GFX_I); + DEBUG_CASE(VGA_SEQ_I); + DEBUG_CASE(VGA_PEL_IW); + DEBUG_CASE(VGA_PEL_IR); +DEBUG_END(PRMCIO) + +DEBUG_START(PRAMDAC) + DEBUG_CASE(NV_PRAMDAC_NVPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_MPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_VPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_PLL_TEST_COUNTER); + +DEBUG_END(PRAMDAC) + +DEBUG_START(PRMDIO) +DEBUG_END(PRMDIO) + +DEBUG_START(PRAMIN) +DEBUG_END(PRAMIN) + +DEBUG_START(USER) + + DEBUG_CASE(NV_USER_DMA_PUT); + DEBUG_CASE(NV_USER_DMA_GET); + DEBUG_CASE(NV_USER_REF); + + DEBUG_END(USER) + + + + +#define DEBUG_READ32(DEV) DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr)) +#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } + +#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr)) +#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; } + +#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr) +#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr) +#define DEVICE_READ32_REG(dev) result = dev.regs[addr] +#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result + +#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(xbaddr addr, uint32_t value) +#define DEVICE_WRITE32_REG(dev) dev.regs[addr] = value +#define DEVICE_WRITE32_END(DEV) DEBUG_WRITE32(DEV) + +static inline uint32_t ldl_le_p(const void *p) +{ + return *(uint32_t*)p; +} + +static DMAObject nv_dma_load(xbaddr dma_obj_address) +{ + assert(dma_obj_address < NV_PRAMIN_SIZE); + + uint32_t *dma_obj = (uint32_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + dma_obj_address); + uint32_t flags = ldl_le_p(dma_obj); + uint32_t limit = ldl_le_p(dma_obj + 1); + uint32_t frame = ldl_le_p(dma_obj + 2); + + DMAObject object; + object.dma_class = GET_MASK(flags, NV_DMA_CLASS); + object.dma_target = GET_MASK(flags, NV_DMA_TARGET); + object.address = (frame & NV_DMA_ADDRESS) | GET_MASK(flags, NV_DMA_ADJUST); + object.limit = limit; + + return object; +} + +static void *nv_dma_map(xbaddr dma_obj_address, xbaddr *len) +{ + assert(dma_obj_address < NV_PRAMIN_SIZE); + + DMAObject dma = nv_dma_load(dma_obj_address); + + /* TODO: Handle targets and classes properly */ + printf("dma_map %x, %x, %x %x" "\n", + dma.dma_class, dma.dma_target, dma.address, dma.limit); + + dma.address &= 0x07FFFFFF; + + // assert(dma.address + dma.limit < memory_region_size(d->vram)); + *len = dma.limit; + return (void*)(MM_SYSTEM_PHYSICAL_MAP + dma.address); +} + +/* pusher should be fine to run from a mimo handler +* whenever's it's convenient */ +static void pfifo_run_pusher() { + uint8_t channel_id; + ChannelControl *control; + Cache1State *state; + CacheEntry *command; + uint8_t *dma; + xbaddr dma_len; + uint32_t word; + + /* TODO: How is cache1 selected? */ + state = &pfifo.cache1; + channel_id = state->channel_id; + control = &user.channel_control[channel_id]; + + if (!state->push_enabled) return; + + /* only handling DMA for now... */ + + /* Channel running DMA */ + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + assert(channel_modes & (1 << channel_id)); + assert(state->mode == FIFO_DMA); + + if (!state->dma_push_enabled) return; + if (state->dma_push_suspended) return; + + /* We're running so there should be no pending errors... */ + assert(state->error == NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE); + + dma = (uint8_t*)nv_dma_map(state->dma_instance, &dma_len); + + printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n", + dma_len, control->dma_get, control->dma_put); + + /* based on the convenient pseudocode in envytools */ + while (control->dma_get != control->dma_put) { + if (control->dma_get >= dma_len) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION; + break; + } + + word = ldl_le_p((uint32_t*)(dma + control->dma_get)); + control->dma_get += 4; + + if (state->method_count) { + /* data word of methods command */ + state->data_shadow = word; + + CacheEntry* command = (CacheEntry*)calloc(1, sizeof(CacheEntry)); + command->method = state->method; + command->subchannel = state->subchannel; + command->nonincreasing = state->method_nonincreasing; + command->parameter = word; + + std::lock_guard lk(state->mutex); + state->cache.push(command); + state->cache_cond.notify_all(); + + if (!state->method_nonincreasing) { + state->method += 4; + } + + state->method_count--; + state->dcount++; + } else { + /* no command active - this is the first word of a new one */ + state->rsvd_shadow = word; + /* match all forms */ + if ((word & 0xe0000003) == 0x20000000) { + /* old jump */ + state->get_jmp_shadow = control->dma_get; + control->dma_get = word & 0x1fffffff; + printf("pb OLD_JMP 0x%08X\n", control->dma_get); + } + else if ((word & 3) == 1) { + /* jump */ + state->get_jmp_shadow = control->dma_get; + control->dma_get = word & 0xfffffffc; + printf("pb JMP 0x%08X\n", control->dma_get); + } + else if ((word & 3) == 2) { + /* call */ + if (state->subroutine_active) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL; + break; + } + state->subroutine_return = control->dma_get; + state->subroutine_active = true; + control->dma_get = word & 0xfffffffc; + printf("pb CALL 0x%08X\n", control->dma_get); + } + else if (word == 0x00020000) { + /* return */ + if (!state->subroutine_active) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN; + break; + } + control->dma_get = state->subroutine_return; + state->subroutine_active = false; + printf("pb RET 0x%08X\n", control->dma_get); + } + else if ((word & 0xe0030003) == 0) { + /* increasing methods */ + state->method = word & 0x1fff; + state->subchannel = (word >> 13) & 7; + state->method_count = (word >> 18) & 0x7ff; + state->method_nonincreasing = false; + state->dcount = 0; + } + else if ((word & 0xe0030003) == 0x40000000) { + /* non-increasing methods */ + state->method = word & 0x1fff; + state->subchannel = (word >> 13) & 7; + state->method_count = (word >> 18) & 0x7ff; + state->method_nonincreasing = true; + state->dcount = 0; + } + else { + printf("pb reserved cmd 0x%08X - 0x%08X\n", + control->dma_get, word); + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD; + break; + } + } + } + + printf("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n", + dma_len, control->dma_get, control->dma_put); + + if (state->error) { + printf("pb error: %d\n", state->error); + assert(false); + + state->dma_push_suspended = true; + + pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER; + update_irq(); + } +} + +static uint32_t ramht_hash(uint32_t handle) +{ + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + + /* XXX: Think this is different to what nouveau calculates... */ + unsigned int bits = ffs(ramht_size) - 2; + + uint32_t hash = 0; + while (handle) { + hash ^= (handle & ((1 << bits) - 1)); + handle >>= bits; + } + hash ^= pfifo.cache1.channel_id << (bits - 4); + + return hash; +} + + +static RAMHTEntry ramht_lookup(uint32_t handle) +{ + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + + uint32_t hash = ramht_hash(handle); + assert(hash * 8 < ramht_size); + + uint32_t ramht_address = + GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], + NV_PFIFO_RAMHT_BASE_ADDRESS) << 12; + + uint8_t *entry_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + ramht_address + hash * 8); + + uint32_t entry_handle = ldl_le_p((uint32_t*)entry_ptr); + uint32_t entry_context = ldl_le_p((uint32_t*)(entry_ptr + 4)); + + RAMHTEntry entry; + entry.handle = entry_handle; + entry.instance = (entry_context & NV_RAMHT_INSTANCE) << 4; + entry.engine = (FIFOEngine)((entry_context & NV_RAMHT_ENGINE) >> 16); + entry.channel_id = (entry_context & NV_RAMHT_CHID) >> 24; + entry.valid = entry_context & NV_RAMHT_STATUS; + + return entry; +} + +static void pgraph_context_switch(unsigned int channel_id) +{ + bool valid = false; + + // Scope the lock so that it gets unlocked at end of this block + { + std::lock_guard lk(pgraph.mutex); + + valid = pgraph.channel_valid && pgraph.channel_id == channel_id; + if (!valid) { + pgraph.trapped_channel_id = channel_id; + } + } + + if (!valid) { + printf("puller needs to switch to ch %d\n", channel_id); + + //qemu_mutex_lock_iothread(); + pgraph.pending_interrupts |= NV_PGRAPH_INTR_CONTEXT_SWITCH; + update_irq(); + + std::unique_lock lk(pgraph.mutex); + //qemu_mutex_unlock_iothread(); + + while (pgraph.pending_interrupts & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + pgraph.interrupt_cond.wait(lk); + } + } +} + +static void pgraph_wait_fifo_access() { + std::unique_lock lk(pgraph.mutex); + + while (!pgraph.fifo_access) { + pgraph.fifo_access_cond.wait(lk); + } +} + +static void pgraph_method_log(unsigned int subchannel, unsigned int graphics_class, unsigned int method, uint32_t parameter) { + static unsigned int last = 0; + static unsigned int count = 0; + + if (last == 0x1800 && method != last) { + printf("pgraph method (%d) 0x%08X * %d", subchannel, last, count); + } + if (method != 0x1800) { + const char* method_name = NULL; + unsigned int nmethod = 0; + switch (graphics_class) { + case NV_KELVIN_PRIMITIVE: + nmethod = method | (0x5c << 16); + break; + case NV_CONTEXT_SURFACES_2D: + nmethod = method | (0x6d << 16); + break; + default: + break; + } + /* + if (nmethod != 0 && nmethod < ARRAY_SIZE(nv2a_method_names)) { + method_name = nv2a_method_names[nmethod]; + } + if (method_name) { + printf("pgraph method (%d): %s (0x%x)\n", + subchannel, method_name, parameter); + } + else { + */ + printf("pgraph method (%d): 0x%x -> 0x%04x (0x%x)\n", + subchannel, graphics_class, method, parameter); + //} + + } + if (method == last) { count++; } + else { count = 0; } + last = method; +} + +static void load_graphics_object(xbaddr instance_address, GraphicsObject *obj) +{ + uint8_t *obj_ptr; + uint32_t switch1, switch2, switch3; + + assert(instance_address < NV_PRAMIN_SIZE); + obj_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + instance_address); + + switch1 = ldl_le_p((uint32_t*)obj_ptr); + switch2 = ldl_le_p((uint32_t*)(obj_ptr + 4)); + switch3 = ldl_le_p((uint32_t*)(obj_ptr + 8)); + + obj->graphics_class = switch1 & NV_PGRAPH_CTX_SWITCH1_GRCLASS; + + /* init graphics object */ + switch (obj->graphics_class) { + case NV_KELVIN_PRIMITIVE: + // kelvin->vertex_attributes[NV2A_VERTEX_ATTR_DIFFUSE].inline_value = 0xFFFFFFF; + break; + default: + break; + } +} + +static GraphicsObject* lookup_graphics_object(xbaddr instance_address) +{ + int i; + for (i = 0; i lk(pgraph.mutex); + + int i; + GraphicsSubchannel *subchannel_data; + GraphicsObject *object; + + unsigned int slot; + + assert(pgraph.channel_valid); + subchannel_data = &pgraph.subchannel_data[subchannel]; + object = &subchannel_data->object; + + ContextSurfaces2DState *context_surfaces_2d = &object->data.context_surfaces_2d; + ImageBlitState *image_blit = &object->data.image_blit; + KelvinState *kelvin = &object->data.kelvin; + + pgraph_method_log(subchannel, object->graphics_class, method, parameter); + + if (method == NV_SET_OBJECT) { + subchannel_data->object_instance = parameter; + + //qemu_mutex_lock_iothread(); + load_graphics_object(parameter, object); + //qemu_mutex_unlock_iothread(); + return; + } + + switch (object->graphics_class) { + case NV_CONTEXT_SURFACES_2D: { + switch (method) { + case NV062_SET_CONTEXT_DMA_IMAGE_SOURCE: + context_surfaces_2d->dma_image_source = parameter; + break; + case NV062_SET_CONTEXT_DMA_IMAGE_DESTIN: + context_surfaces_2d->dma_image_dest = parameter; + break; + case NV062_SET_COLOR_FORMAT: + context_surfaces_2d->color_format = parameter; + break; + case NV062_SET_PITCH: + context_surfaces_2d->source_pitch = parameter & 0xFFFF; + context_surfaces_2d->dest_pitch = parameter >> 16; + break; + case NV062_SET_OFFSET_SOURCE: + context_surfaces_2d->source_offset = parameter & 0x07FFFFFF; + break; + case NV062_SET_OFFSET_DESTIN: + context_surfaces_2d->dest_offset = parameter & 0x07FFFFFF; + break; + default: + EmuWarning("EmuNV2A: Unknown NV_CONTEXT_SURFACES_2D Method: 0x%08X\n", method); + } + + break; + } + + case NV_IMAGE_BLIT: { + switch (method) { + case NV09F_SET_CONTEXT_SURFACES: + image_blit->context_surfaces = parameter; + break; + case NV09F_SET_OPERATION: + image_blit->operation = parameter; + break; + case NV09F_CONTROL_POINT_IN: + image_blit->in_x = parameter & 0xFFFF; + image_blit->in_y = parameter >> 16; + break; + case NV09F_CONTROL_POINT_OUT: + image_blit->out_x = parameter & 0xFFFF; + image_blit->out_y = parameter >> 16; + break; + case NV09F_SIZE: + image_blit->width = parameter & 0xFFFF; + image_blit->height = parameter >> 16; + + /* I guess this kicks it off? */ + if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) { + + printf("NV09F_SET_OPERATION_SRCCOPY"); + + GraphicsObject *context_surfaces_obj = lookup_graphics_object(image_blit->context_surfaces); + assert(context_surfaces_obj); + assert(context_surfaces_obj->graphics_class == NV_CONTEXT_SURFACES_2D); + + ContextSurfaces2DState *context_surfaces = &context_surfaces_obj->data.context_surfaces_2d; + + unsigned int bytes_per_pixel; + switch (context_surfaces->color_format) { + case NV062_SET_COLOR_FORMAT_LE_Y8: + bytes_per_pixel = 1; + break; + case NV062_SET_COLOR_FORMAT_LE_R5G6B5: + bytes_per_pixel = 2; + break; + case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: + bytes_per_pixel = 4; + break; + default: + printf("Unknown blit surface format: 0x%x\n", context_surfaces->color_format); + assert(false); + break; + } + + xbaddr source_dma_len, dest_dma_len; + uint8_t *source, *dest; + + source = (uint8_t*)nv_dma_map(context_surfaces->dma_image_source, &source_dma_len); + assert(context_surfaces->source_offset < source_dma_len); + source += context_surfaces->source_offset; + + dest = (uint8_t*)nv_dma_map(context_surfaces->dma_image_dest, &dest_dma_len); + assert(context_surfaces->dest_offset < dest_dma_len); + dest += context_surfaces->dest_offset; + + printf(" - 0x%tx -> 0x%tx\n", source - MM_SYSTEM_PHYSICAL_MAP,dest - MM_SYSTEM_PHYSICAL_MAP); + + int y; + for (y = 0; yheight; y++) { + uint8_t *source_row = source + + (image_blit->in_y + y) * context_surfaces->source_pitch + + image_blit->in_x * bytes_per_pixel; + + uint8_t *dest_row = dest + + (image_blit->out_y + y) * context_surfaces->dest_pitch + + image_blit->out_x * bytes_per_pixel; + + memmove(dest_row, source_row, + image_blit->width * bytes_per_pixel); + } + } + else { + assert(false); + } + + break; + default: + EmuWarning("EmuNV2A: Unknown NV_IMAGE_BLIT Method: 0x%08X\n", method); + } + break; + } + + case NV_KELVIN_PRIMITIVE: { + switch (method) { + case NV097_SET_CONTEXT_DMA_NOTIFIES: + kelvin->dma_notifies = parameter; + break; + case NV097_SET_CONTEXT_DMA_A: + pgraph.dma_a = parameter; + break; + case NV097_SET_CONTEXT_DMA_B: + pgraph.dma_b = parameter; + break; + case NV097_SET_CONTEXT_DMA_STATE: + kelvin->dma_state = parameter; + break; + case NV097_SET_CONTEXT_DMA_COLOR: + printf("TODO: pgraph_update_surface\n"); + /* try to get any straggling draws in before the surface's changed :/ */ + //pgraph_update_surface(d, false, true, true); + + pgraph.dma_color = parameter; + break; + case NV097_SET_CONTEXT_DMA_ZETA: + pgraph.dma_zeta = parameter; + break; + case NV097_SET_CONTEXT_DMA_VERTEX_A: + pgraph.dma_vertex_a = parameter; + break; + case NV097_SET_CONTEXT_DMA_VERTEX_B: + pgraph.dma_vertex_b = parameter; + break; + case NV097_SET_CONTEXT_DMA_SEMAPHORE: + kelvin->dma_semaphore = parameter; + break; + case NV097_SET_CONTEXT_DMA_REPORT: + pgraph.dma_report = parameter; + break; + case NV097_SET_SURFACE_CLIP_HORIZONTAL: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.clip_x = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_X); + pgraph.surface_shape.clip_width = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_WIDTH); + break; + case NV097_SET_SURFACE_CLIP_VERTICAL: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.clip_y = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_Y); + pgraph.surface_shape.clip_height = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_HEIGHT); + break; + case NV097_SET_SURFACE_FORMAT: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.color_format = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_COLOR); + pgraph.surface_shape.zeta_format = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ZETA); + pgraph.surface_type = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_TYPE); + pgraph.surface_shape.anti_aliasing = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ANTI_ALIASING); + pgraph.surface_shape.log_width = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_WIDTH); + pgraph.surface_shape.log_height = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_HEIGHT); + break; + case NV097_SET_SURFACE_PITCH: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_color.pitch = + GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR); + pgraph.surface_zeta.pitch = + GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA); + break; + case NV097_SET_SURFACE_COLOR_OFFSET: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_color.offset = parameter; + break; + case NV097_SET_SURFACE_ZETA_OFFSET: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_zeta.offset = parameter; + break; + case NV097_SET_COMBINER_SPECULAR_FOG_CW0: + pgraph.regs[NV_PGRAPH_COMBINESPECFOG0] = parameter; + break; + case NV097_SET_COMBINER_SPECULAR_FOG_CW1: + pgraph.regs[NV_PGRAPH_COMBINESPECFOG1] = parameter; + break; + CASE_4(NV097_SET_TEXTURE_ADDRESS, 64): + slot = (method - NV097_SET_TEXTURE_ADDRESS) / 64; + pgraph.regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; + break; + case NV097_SET_CONTROL0: { + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + bool stencil_write_enable = + parameter & NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE, + stencil_write_enable); + + uint32_t z_format = GET_MASK(parameter, NV097_SET_CONTROL0_Z_FORMAT); + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_Z_FORMAT, z_format); + + bool z_perspective = + parameter & NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE, + z_perspective); + break; + } + + case NV097_SET_FOG_MODE: { + /* FIXME: There is also NV_PGRAPH_CSV0_D_FOG_MODE */ + unsigned int mode; + switch (parameter) { + case NV097_SET_FOG_MODE_V_LINEAR: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR; break; + case NV097_SET_FOG_MODE_V_EXP: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP; break; + case NV097_SET_FOG_MODE_V_EXP2: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2; break; + case NV097_SET_FOG_MODE_V_EXP_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP_ABS; break; + case NV097_SET_FOG_MODE_V_EXP2_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2_ABS; break; + case NV097_SET_FOG_MODE_V_LINEAR_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR_ABS; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOG_MODE, + mode); + break; + } + case NV097_SET_FOG_GEN_MODE: { + unsigned int mode; + switch (parameter) { + case NV097_SET_FOG_GEN_MODE_V_SPEC_ALPHA: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_SPEC_ALPHA; break; + case NV097_SET_FOG_GEN_MODE_V_RADIAL: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_RADIAL; break; + case NV097_SET_FOG_GEN_MODE_V_PLANAR: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_PLANAR; break; + case NV097_SET_FOG_GEN_MODE_V_ABS_PLANAR: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_ABS_PLANAR; break; + case NV097_SET_FOG_GEN_MODE_V_FOG_X: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_FOG_X; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGGENMODE, mode); + break; + } + case NV097_SET_FOG_ENABLE: + /* + FIXME: There is also: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGENABLE, + parameter); + */ + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOGENABLE, + parameter); + break; + case NV097_SET_FOG_COLOR: { + /* PGRAPH channels are ARGB, parameter channels are ABGR */ + uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED); + uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN); + uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE); + uint8_t alpha = GET_MASK(parameter, NV097_SET_FOG_COLOR_ALPHA); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_RED, red); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_GREEN, green); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_BLUE, blue); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha); + break; + } + case NV097_SET_ALPHA_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, parameter); + break; + case NV097_SET_BLEND_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EN, parameter); + break; + case NV097_SET_CULL_FACE_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_CULLENABLE, + parameter); + break; + case NV097_SET_DEPTH_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZENABLE, + parameter); + break; + case NV097_SET_DITHER_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_DITHERENABLE, parameter); + break; + case NV097_SET_LIGHTING_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], NV_PGRAPH_CSV0_C_LIGHTING, + parameter); + break; + case NV097_SET_SKIN_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_SKIN, + parameter); + break; + case NV097_SET_STENCIL_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_POINT_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_LINE_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_FILL_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE, parameter); + break; + case NV097_SET_ALPHA_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAFUNC, parameter & 0xF); + break; + case NV097_SET_ALPHA_REF: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAREF, parameter); + break; + case NV097_SET_BLEND_FUNC_SFACTOR: { + unsigned int factor; + switch (parameter) { + case NV097_SET_BLEND_FUNC_SFACTOR_V_ZERO: + factor = NV_PGRAPH_BLEND_SFACTOR_ZERO; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA_SATURATE: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA_SATURATE; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; + default: + fprintf(stderr, "Unknown blend source factor: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_SFACTOR, factor); + + break; + } + + case NV097_SET_BLEND_FUNC_DFACTOR: { + unsigned int factor; + switch (parameter) { + case NV097_SET_BLEND_FUNC_DFACTOR_V_ZERO: + factor = NV_PGRAPH_BLEND_DFACTOR_ZERO; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA_SATURATE: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA_SATURATE; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; + default: + fprintf(stderr, "Unknown blend destination factor: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_DFACTOR, factor); + + break; + } + + case NV097_SET_BLEND_COLOR: + pgraph.regs[NV_PGRAPH_BLENDCOLOR] = parameter; + break; + + case NV097_SET_BLEND_EQUATION: { + unsigned int equation; + switch (parameter) { + case NV097_SET_BLEND_EQUATION_V_FUNC_SUBTRACT: + equation = 0; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT: + equation = 1; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_ADD: + equation = 2; break; + case NV097_SET_BLEND_EQUATION_V_MIN: + equation = 3; break; + case NV097_SET_BLEND_EQUATION_V_MAX: + equation = 4; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT_SIGNED: + equation = 5; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_ADD_SIGNED: + equation = 6; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EQN, equation); + + break; + } + + case NV097_SET_DEPTH_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZFUNC, + parameter & 0xF); + break; + + case NV097_SET_COLOR_MASK: { + pgraph.surface_color.write_enabled_cache |= pgraph_color_write_enabled(); + + bool alpha = parameter & NV097_SET_COLOR_MASK_ALPHA_WRITE_ENABLE; + bool red = parameter & NV097_SET_COLOR_MASK_RED_WRITE_ENABLE; + bool green = parameter & NV097_SET_COLOR_MASK_GREEN_WRITE_ENABLE; + bool blue = parameter & NV097_SET_COLOR_MASK_BLUE_WRITE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE, alpha); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE, red); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE, green); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE, blue); + break; + } + case NV097_SET_DEPTH_MASK: + pgraph.surface_zeta.write_enabled_cache |= pgraph_zeta_write_enabled(); + + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ZWRITEENABLE, parameter); + break; + case NV097_SET_STENCIL_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_MASK_WRITE, parameter); + break; + case NV097_SET_STENCIL_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_FUNC, parameter & 0xF); + break; + case NV097_SET_STENCIL_FUNC_REF: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_REF, parameter); + break; + case NV097_SET_STENCIL_FUNC_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_MASK_READ, parameter); + break; + case NV097_SET_STENCIL_OP_FAIL: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_FAIL, + kelvin_map_stencil_op(parameter)); + break; + case NV097_SET_STENCIL_OP_ZFAIL: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_ZFAIL, + kelvin_map_stencil_op(parameter)); + break; + case NV097_SET_STENCIL_OP_ZPASS: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_ZPASS, + kelvin_map_stencil_op(parameter)); + break; + + case NV097_SET_POLYGON_OFFSET_SCALE_FACTOR: + pgraph.regs[NV_PGRAPH_ZOFFSETFACTOR] = parameter; + break; + case NV097_SET_POLYGON_OFFSET_BIAS: + pgraph.regs[NV_PGRAPH_ZOFFSETBIAS] = parameter; + break; + case NV097_SET_FRONT_POLYGON_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_FRONTFACEMODE, + kelvin_map_polygon_mode(parameter)); + break; + case NV097_SET_BACK_POLYGON_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_BACKFACEMODE, + kelvin_map_polygon_mode(parameter)); + break; + case NV097_SET_CLIP_MIN: + pgraph.regs[NV_PGRAPH_ZCLIPMIN] = parameter; + break; + case NV097_SET_CLIP_MAX: + pgraph.regs[NV_PGRAPH_ZCLIPMAX] = parameter; + break; + case NV097_SET_CULL_FACE: { + unsigned int face; + switch (parameter) { + case NV097_SET_CULL_FACE_V_FRONT: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT; break; + case NV097_SET_CULL_FACE_V_BACK: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_BACK; break; + case NV097_SET_CULL_FACE_V_FRONT_AND_BACK: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT_AND_BACK; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_CULLCTRL, + face); + break; + } + case NV097_SET_FRONT_FACE: { + bool ccw; + switch (parameter) { + case NV097_SET_FRONT_FACE_V_CW: + ccw = false; break; + case NV097_SET_FRONT_FACE_V_CCW: + ccw = true; break; + default: + fprintf(stderr, "Unknown front face: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_FRONTFACE, + ccw ? 1 : 0); + break; + } + case NV097_SET_NORMALIZATION_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], + NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, + parameter); + break; + + case NV097_SET_LIGHT_ENABLE_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], + NV_PGRAPH_CSV0_D_LIGHTS, + parameter); + break; + + CASE_4(NV097_SET_TEXGEN_S, 16) : { + slot = (method - NV097_SET_TEXGEN_S) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_S + : NV_PGRAPH_CSV1_A_T0_S; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 0)); + break; + } + CASE_4(NV097_SET_TEXGEN_T, 16) : { + slot = (method - NV097_SET_TEXGEN_T) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_T + : NV_PGRAPH_CSV1_A_T0_T; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 1)); + break; + } + CASE_4(NV097_SET_TEXGEN_R, 16) : { + slot = (method - NV097_SET_TEXGEN_R) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_R + : NV_PGRAPH_CSV1_A_T0_R; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 2)); + break; + } + CASE_4(NV097_SET_TEXGEN_Q, 16) : { + slot = (method - NV097_SET_TEXGEN_Q) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_Q + : NV_PGRAPH_CSV1_A_T0_Q; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 3)); + break; + } + CASE_4(NV097_SET_TEXTURE_MATRIX_ENABLE, 4) : + slot = (method - NV097_SET_TEXTURE_MATRIX_ENABLE) / 4; + pgraph.texture_matrix_enable[slot] = parameter; + break; + + case NV097_SET_TEXGEN_VIEW_MODEL: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); + break; + default: + if (method >= NV097_SET_COMBINER_ALPHA_ICW && method <= NV097_SET_COMBINER_ALPHA_ICW + 28) { + slot = (method - NV097_SET_COMBINER_ALPHA_ICW) / 4; + pgraph.regs[NV_PGRAPH_COMBINEALPHAI0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_PROJECTION_MATRIX && method <= NV097_SET_PROJECTION_MATRIX + 0x3c) { + slot = (method - NV097_SET_PROJECTION_MATRIX) / 4; + // pg->projection_matrix[slot] = *(float*)¶meter; + unsigned int row = NV_IGRAPH_XF_XFCTX_PMAT0 + slot / 4; + pgraph.vsh_constants[row][slot % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_MODEL_VIEW_MATRIX && method <= NV097_SET_MODEL_VIEW_MATRIX + 0xfc) { + slot = (method - NV097_SET_MODEL_VIEW_MATRIX) / 4; + unsigned int matnum = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_MMAT0 + matnum * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_INVERSE_MODEL_VIEW_MATRIX && method <= NV097_SET_INVERSE_MODEL_VIEW_MATRIX + 0xfc) { + slot = (method - NV097_SET_INVERSE_MODEL_VIEW_MATRIX) / 4; + unsigned int matnum = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_IMMAT0 + matnum * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_COMPOSITE_MATRIX && method <= NV097_SET_COMPOSITE_MATRIX + 0x3c) { + slot = (method - NV097_SET_COMPOSITE_MATRIX) / 4; + unsigned int row = NV_IGRAPH_XF_XFCTX_CMAT0 + slot / 4; + pgraph.vsh_constants[row][slot % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_TEXTURE_MATRIX && method <= NV097_SET_TEXTURE_MATRIX + 0xfc) { + slot = (method - NV097_SET_TEXTURE_MATRIX) / 4; + unsigned int tex = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_T0MAT + tex * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_FOG_PARAMS && method <= NV097_SET_FOG_PARAMS + 8) { + slot = (method - NV097_SET_FOG_PARAMS) / 4; + if (slot < 2) { + pgraph.regs[NV_PGRAPH_FOGPARAM0 + slot * 4] = parameter; + } + else { + /* FIXME: No idea where slot = 2 is */ + } + + pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FOG_K][slot] = parameter; + pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FOG_K] = true; + break; + } + + /* Handles NV097_SET_TEXGEN_PLANE_S,T,R,Q */ + if (method >= NV097_SET_TEXGEN_PLANE_S && method <= NV097_SET_TEXGEN_PLANE_S + 0xfc) { + slot = (method - NV097_SET_TEXGEN_PLANE_S) / 4; + unsigned int tex = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_TG0MAT + tex * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_FOG_PLANE && method <= NV097_SET_FOG_PLANE + 12) { + slot = (method - NV097_SET_FOG_PLANE) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_FOG][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true; + break; + } + + if (method >= NV097_SET_SCENE_AMBIENT_COLOR && method <= NV097_SET_SCENE_AMBIENT_COLOR + 8) { + slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4; + // ?? + pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FR_AMB][slot] = parameter; + pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FR_AMB] = true; + break; + } + + if (method >= NV097_SET_VIEWPORT_OFFSET && method <= NV097_SET_VIEWPORT_OFFSET + 12) { + slot = (method - NV097_SET_VIEWPORT_OFFSET) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPOFF] = true; + break; + } + + if (method >= NV097_SET_EYE_POSITION && method <= NV097_SET_EYE_POSITION + 12) { + slot = (method - NV097_SET_EYE_POSITION) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_EYEP][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_EYEP] = true; + break; + } + + if (method >= NV097_SET_COMBINER_FACTOR0 && method <= NV097_SET_COMBINER_FACTOR0 + 28) { + slot = (method - NV097_SET_COMBINER_FACTOR0) / 4; + pgraph.regs[NV_PGRAPH_COMBINEFACTOR0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_FACTOR1 && method <= NV097_SET_COMBINER_FACTOR1 + 28) { + slot = (method - NV097_SET_COMBINER_FACTOR1) / 4; + pgraph.regs[NV_PGRAPH_COMBINEFACTOR1 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_ALPHA_OCW && method <= NV097_SET_COMBINER_ALPHA_OCW + 28) { + slot = (method - NV097_SET_COMBINER_ALPHA_OCW) / 4; + pgraph.regs[NV_PGRAPH_COMBINEALPHAO0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_COLOR_ICW && method <= NV097_SET_COMBINER_COLOR_ICW + 28) { + slot = (method - NV097_SET_COMBINER_COLOR_ICW) / 4; + pgraph.regs[NV_PGRAPH_COMBINECOLORI0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_VIEWPORT_SCALE && method <= NV097_SET_VIEWPORT_SCALE + 12) { + slot = (method - NV097_SET_VIEWPORT_SCALE) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPSCL][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPSCL] = true; + break; + } + + EmuWarning("EmuNV2A: Unknown NV_KELVIN_PRIMITIVE Method: 0x%08X\n", method); + } + break; + } + + default: + EmuWarning("EmuNV2A: Unknown Graphics Class/Method 0x%08X/0x%08X\n", object->graphics_class, method); + break; + } +} + +static void* pfifo_puller_thread() +{ + Cache1State *state = &pfifo.cache1; + + while (true) { + // Scope the lock so that it automatically unlocks at tne end of this block + { + std::unique_lock lk(state->mutex); + + while (state->cache.empty() || !state->pull_enabled) { + state->cache_cond.wait(lk); + } + + // Copy cache to working_cache + while (!state->cache.empty()) { + state->working_cache.push(state->cache.front()); + state->cache.pop(); + } + } + + while (!state->working_cache.empty()) { + CacheEntry* command = state->working_cache.front(); + state->working_cache.pop(); + + if (command->method == 0) { + // qemu_mutex_lock_iothread(); + RAMHTEntry entry = ramht_lookup(command->parameter); + assert(entry.valid); + + assert(entry.channel_id == state->channel_id); + // qemu_mutex_unlock_iothread(); + + switch (entry.engine) { + case ENGINE_GRAPHICS: + pgraph_context_switch(entry.channel_id); + pgraph_wait_fifo_access(); + pgraph_method(command->subchannel, 0, entry.instance); + break; + default: + assert(false); + break; + } + + /* the engine is bound to the subchannel */ + std::lock_guard lk(pfifo.cache1.mutex); + state->bound_engines[command->subchannel] = entry.engine; + state->last_engine = entry.engine; + } else if (command->method >= 0x100) { + /* method passed to engine */ + + uint32_t parameter = command->parameter; + + /* methods that take objects. + * TODO: Check this range is correct for the nv2a */ + if (command->method >= 0x180 && command->method < 0x200) { + //qemu_mutex_lock_iothread(); + RAMHTEntry entry = ramht_lookup(parameter); + assert(entry.valid); + assert(entry.channel_id == state->channel_id); + parameter = entry.instance; + //qemu_mutex_unlock_iothread(); + } + + // qemu_mutex_lock(&state->cache_lock); + enum FIFOEngine engine = state->bound_engines[command->subchannel]; + // qemu_mutex_unlock(&state->cache_lock); + + switch (engine) { + case ENGINE_GRAPHICS: + pgraph_wait_fifo_access(); + pgraph_method(command->subchannel, command->method, parameter); + break; + default: + assert(false); + break; + } + + // qemu_mutex_lock(&state->cache_lock); + state->last_engine = state->bound_engines[command->subchannel]; + // qemu_mutex_unlock(&state->cache_lock); + } + + free(command); + } + } + + return NULL; +} + +DEVICE_READ32(PMC) +{ + DEVICE_READ32_SWITCH() { + case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 + result = 0x02A000A2; + break; + case NV_PMC_INTR_0: + result = pmc.pending_interrupts; + break; + case NV_PMC_INTR_EN_0: + result = pmc.enabled_interrupts; + break; + default: + result = 0; + //DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC); + break; + } + + DEVICE_READ32_END(PMC); +} + +DEVICE_WRITE32(PMC) +{ + switch(addr) { + case NV_PMC_INTR_0: + pmc.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PMC_INTR_EN_0: + pmc.enabled_interrupts = value; + update_irq(); + break; + + default: + //DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC); + break; + } + + DEVICE_WRITE32_END(PMC); +} + + +DEVICE_READ32(PBUS) +{ + DEVICE_READ32_SWITCH() { + case NV_PBUS_PCI_NV_0: + result = 0x10de; // PCI_VENDOR_ID_NVIDIA (?where to return PCI_DEVICE_ID_NVIDIA_NV2A = 0x01b7) + + break; + case NV_PBUS_PCI_NV_1: + result = 1; // NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED + break; + case NV_PBUS_PCI_NV_2: + result = (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1) + break; + + default: + DEBUG_READ32_UNHANDLED(PBUS); // TODO : DEVICE_READ32_REG(pbus); + break; + } + + DEVICE_READ32_END(PBUS); +} + +DEVICE_WRITE32(PBUS) +{ + switch(addr) { + case NV_PBUS_PCI_NV_1: + // TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED) + break; + default: + DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus); + break; + } + + DEVICE_WRITE32_END(PBUS); +} + + +DEVICE_READ32(PFIFO) +{ + DEVICE_READ32_SWITCH() { + case NV_PFIFO_RAMHT: + result = 0x03000100; // = NV_PFIFO_RAMHT_SIZE_4K | NV_PFIFO_RAMHT_BASE_ADDRESS(NumberOfPaddingBytes >> 12) | NV_PFIFO_RAMHT_SEARCH_128 + break; + case NV_PFIFO_RAMFC: + result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ? + break; + case NV_PFIFO_INTR_0: + result = pfifo.pending_interrupts; + break; + case NV_PFIFO_INTR_EN_0: + result = pfifo.enabled_interrupts; + break; + case NV_PFIFO_RUNOUT_STATUS: + result = NV_PFIFO_RUNOUT_STATUS_LOW_MARK; /* low mark empty */ + break; + case NV_PFIFO_CACHE1_PUSH0: + result = pfifo.cache1.push_enabled; + break; + case NV_PFIFO_CACHE1_PUSH1: + SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, pfifo.cache1.channel_id); + SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, pfifo.cache1.mode); + break; + case NV_PFIFO_CACHE1_STATUS: { + std::lock_guard lk(pfifo.cache1.mutex); + + if (pfifo.cache1.cache.empty()) { + result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */ + } + + } break; + case NV_PFIFO_CACHE1_DMA_PUSH: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS, + pfifo.cache1.dma_push_enabled); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, + pfifo.cache1.dma_push_suspended); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_BUFFER, 1); /* buffer emoty */ + break; + case NV_PFIFO_CACHE1_DMA_STATE: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE, + pfifo.cache1.method_nonincreasing); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD, + pfifo.cache1.method >> 2); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, + pfifo.cache1.subchannel); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, + pfifo.cache1.method_count); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR, + pfifo.cache1.error); + break; + case NV_PFIFO_CACHE1_DMA_INSTANCE: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS, + pfifo.cache1.dma_instance >> 4); + break; + case NV_PFIFO_CACHE1_DMA_PUT: + result = user.channel_control[pfifo.cache1.channel_id].dma_put; + break; + case NV_PFIFO_CACHE1_DMA_GET: + result = user.channel_control[pfifo.cache1.channel_id].dma_get; + break; + case NV_PFIFO_CACHE1_DMA_SUBROUTINE: + result = pfifo.cache1.subroutine_return + | pfifo.cache1.subroutine_active; + break; + case NV_PFIFO_CACHE1_PULL0: { + std::lock_guard lk(pfifo.cache1.mutex); + result = pfifo.cache1.pull_enabled; + } break; + case NV_PFIFO_CACHE1_ENGINE: { + std::lock_guard lk(pfifo.cache1.mutex); + for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { + result |= pfifo.cache1.bound_engines[i] << (i * 2); + } + + } break; + case NV_PFIFO_CACHE1_DMA_DCOUNT: + result = pfifo.cache1.dcount; + break; + case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: + result = pfifo.cache1.get_jmp_shadow; + break; + case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: + result = pfifo.cache1.rsvd_shadow; + break; + case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: + result = pfifo.cache1.data_shadow; + break; + default: + DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO); + break; + } + + DEVICE_READ32_END(PFIFO); +} + +DEVICE_WRITE32(PFIFO) +{ + switch(addr) { + case NV_PFIFO_INTR_0: + pfifo.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PFIFO_INTR_EN_0: + pfifo.enabled_interrupts = value; + update_irq(); + break; + case NV_PFIFO_CACHE1_PUSH0: + pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS; + break; + case NV_PFIFO_CACHE1_PUSH1: + pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID); + pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE); + assert(pfifo.cache1.channel_id < NV2A_NUM_CHANNELS); + break; + case NV_PFIFO_CACHE1_DMA_PUSH: + pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS); + if (pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) { + pfifo.cache1.dma_push_suspended = false; + pfifo_run_pusher(); + } + pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS); + break; + case NV_PFIFO_CACHE1_DMA_STATE: + pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE); + pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2; + pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL); + pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT); + pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR); + break; + case NV_PFIFO_CACHE1_DMA_INSTANCE: + pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS) << 4; + break; + case NV_PFIFO_CACHE1_DMA_PUT: + user.channel_control[pfifo.cache1.channel_id].dma_put = value; + break; + case NV_PFIFO_CACHE1_DMA_GET: + user.channel_control[pfifo.cache1.channel_id].dma_get = value; + break; + case NV_PFIFO_CACHE1_DMA_SUBROUTINE: + pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET); + pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE); + break; + case NV_PFIFO_CACHE1_PULL0: { + std::lock_guard lk(pfifo.cache1.mutex); + + if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS) + && !pfifo.cache1.pull_enabled) { + pfifo.cache1.pull_enabled = true; + + /* the puller thread should wake up */ + pfifo.cache1.cache_cond.notify_all(); + } else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS) + && pfifo.cache1.pull_enabled) { + pfifo.cache1.pull_enabled = false; + } + } break; + case NV_PFIFO_CACHE1_ENGINE: { + std::lock_guard lk(pfifo.cache1.mutex); + + for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { + pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3); + } + + } break; + case NV_PFIFO_CACHE1_DMA_DCOUNT: + pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE); + break; + case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: + pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET); + break; + case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: + pfifo.cache1.rsvd_shadow = value; + break; + case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: + pfifo.cache1.data_shadow = value; + break; + default: + DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO); + break; + } + + DEVICE_WRITE32_END(PFIFO); +} + +DEVICE_READ32(PRMA) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMA); // TODO : DEVICE_READ32_REG(prma); + break; + } + + DEVICE_READ32_END(PRMA); +} + +DEVICE_WRITE32(PRMA) +{ + switch(addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMA); // TODO : DEVICE_WRITE32_REG(prma); + break; + } + + DEVICE_WRITE32_END(PRMA); +} + + +DEVICE_READ32(PVIDEO) +{ + DEVICE_READ32_SWITCH() { + + case NV_PVIDEO_STOP: + result = 0; + break; + default: + DEVICE_READ32_REG(pvideo); + break; + } + + DEVICE_READ32_END(PVIDEO); +} + +DEVICE_WRITE32(PVIDEO) +{ + switch (addr) { + case NV_PVIDEO_BUFFER: + pvideo.regs[addr] = value; + // TODO: vga.enable_overlay = true; + // pvideo_vga_invalidate(d); + break; + case NV_PVIDEO_STOP: + pvideo.regs[NV_PVIDEO_BUFFER] = 0; + // TODO: vga.enable_overlay = false; + //pvideo_vga_invalidate(d); + break; + default: + DEVICE_WRITE32_REG(pvideo); + break; + } + + DEVICE_WRITE32_END(PVIDEO); +} + +DEVICE_READ32(PCOUNTER) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PCOUNTER); // TODO : DEVICE_READ32_REG(pcounter); + break; + } + + DEVICE_READ32_END(PCOUNTER); +} + +DEVICE_WRITE32(PCOUNTER) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PCOUNTER); // TODO : DEVICE_WRITE32_REG(pcounter); + break; + } + + DEVICE_WRITE32_END(PCOUNTER); +} + +static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { + uint32_t low, high; + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + +/* PIMTER - time measurement and time-based alarms */ +static uint32_t ptimer_get_clock() +{ + // Get time in nanoseconds + long int time = static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); + + return muldiv64(time, pramdac.core_clock_freq * ptimer.numerator, CLOCKS_PER_SEC * ptimer.denominator); +} + +DEVICE_READ32(PTIMER) +{ + DEVICE_READ32_SWITCH() { + case NV_PTIMER_INTR_0: + result = ptimer.pending_interrupts; + break; + case NV_PTIMER_INTR_EN_0: + result = ptimer.enabled_interrupts; + break; + case NV_PTIMER_NUMERATOR: + result = ptimer.numerator; + break; + case NV_PTIMER_DENOMINATOR: + result = ptimer.denominator; + break; + case NV_PTIMER_TIME_0: + result = (ptimer_get_clock() & 0x7ffffff) << 5; + break; + case NV_PTIMER_TIME_1: + result = (ptimer_get_clock() >> 27) & 0x1fffffff; + break; + default: + result = 0; + //DEVICE_READ32_REG(ptimer); // Was : DEBUG_READ32_UNHANDLED(PTIMER); + break; + } + + DEVICE_READ32_END(PTIMER); +} + + +DEVICE_WRITE32(PTIMER) +{ + switch (addr) { + + case NV_PTIMER_INTR_0: + ptimer.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PTIMER_INTR_EN_0: + ptimer.enabled_interrupts = value; + update_irq(); + break; + case NV_PTIMER_DENOMINATOR: + ptimer.denominator = value; + break; + case NV_PTIMER_NUMERATOR: + ptimer.numerator = value; + break; + case NV_PTIMER_ALARM_0: + ptimer.alarm_time = value; + break; + default: + //DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER); + break; + } + + DEVICE_WRITE32_END(PTIMER); +} + + +DEVICE_READ32(PVPE) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PVPE); // TODO : DEVICE_READ32_REG(pvpe); + break; + } + + DEVICE_READ32_END(PVPE); +} + + +DEVICE_WRITE32(PVPE) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PVPE); // TODO : DEVICE_WRITE32_REG(pvpe); + break; + } + + DEVICE_WRITE32_END(PVPE); +} + + +DEVICE_READ32(PTV) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PTV); // TODO : DEVICE_READ32_REG(ptv); + break; + } + + DEVICE_READ32_END(PTV); +} + +DEVICE_WRITE32(PTV) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PTV); // TODO : DEVICE_WRITE32_REG(ptv); + break; + } + + DEVICE_WRITE32_END(PTV); +} + + +DEVICE_READ32(PRMFB) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMFB); // TODO : DEVICE_READ32_REG(prmfb); + break; + } + + DEVICE_READ32_END(PRMFB); +} + +DEVICE_WRITE32(PRMFB) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMFB); // TODO : DEVICE_WRITE32_REG(prmfb); + break; + } + + DEVICE_WRITE32_END(PRMFB); +} + + +DEVICE_READ32(PRMVIO) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio); + break; + } + + DEVICE_READ32_END(PRMVIO); +} + +DEVICE_WRITE32(PRMVIO) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio); + break; + } + + DEVICE_WRITE32_END(PRMVIO); +} + + +DEVICE_READ32(PFB) +{ + DEVICE_READ32_SWITCH() { + case NV_PFB_CFG0: + result = 3; // = NV_PFB_CFG0_PART_4 + break; + case NV_PFB_CSTATUS: + { + if (g_bIsChihiro || g_bIsDebug) { result = CONTIGUOUS_MEMORY_CHIHIRO_SIZE; break; } + result = CONTIGUOUS_MEMORY_XBOX_SIZE; + } + break; + case NV_PFB_WBC: + result = 0; // = !NV_PFB_WBC_FLUSH + break; + default: + DEVICE_READ32_REG(pfb); + break; + } + + DEVICE_READ32_END(PFB); +} + +DEVICE_WRITE32(PFB) +{ + switch (addr) { + default: + DEVICE_WRITE32_REG(pfb); + break; + } + + DEVICE_WRITE32_END(PFB); +} + + +DEVICE_READ32(PSTRAPS) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PSTRAPS); + break; + } + + DEVICE_READ32_END(PSTRAPS); +} + +DEVICE_WRITE32(PSTRAPS) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PSTRAPS); + break; + } + + DEVICE_WRITE32_END(PSTRAPS); +} + + +DEVICE_READ32(PGRAPH) +{ + std::lock_guard lk(pgraph.mutex); + + DEVICE_READ32_SWITCH() { + case NV_PGRAPH_INTR: + result = pgraph.pending_interrupts; + break; + case NV_PGRAPH_INTR_EN: + result = pgraph.enabled_interrupts; + break; + case NV_PGRAPH_NSOURCE: + result = pgraph.notify_source; + break; + case NV_PGRAPH_CTX_USER: + SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D, pgraph.context[pgraph.channel_id].channel_3d); + SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D_VALID, 1); + SET_MASK(result, NV_PGRAPH_CTX_USER_SUBCH, pgraph.context[pgraph.channel_id].subchannel << 13); + SET_MASK(result, NV_PGRAPH_CTX_USER_CHID, pgraph.channel_id); + break; + case NV_PGRAPH_TRAPPED_ADDR: + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_CHID, pgraph.trapped_channel_id); + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_SUBCH, pgraph.trapped_subchannel); + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_MTHD, pgraph.trapped_method); + break; + case NV_PGRAPH_TRAPPED_DATA_LOW: + result = pgraph.trapped_data[0]; + break; + case NV_PGRAPH_FIFO: + SET_MASK(result, NV_PGRAPH_FIFO_ACCESS, pgraph.fifo_access); + break; + case NV_PGRAPH_CHANNEL_CTX_TABLE: + result = pgraph.context_table >> 4; + break; + case NV_PGRAPH_CHANNEL_CTX_POINTER: + result = pgraph.context_address >> 4; + break; + default: + DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH); + } + + DEVICE_READ32_END(PGRAPH); +} + +static void pgraph_set_context_user(uint32_t value) +{ + pgraph.channel_id = (value & NV_PGRAPH_CTX_USER_CHID) >> 24; + pgraph.context[pgraph.channel_id].channel_3d = GET_MASK(value, NV_PGRAPH_CTX_USER_CHANNEL_3D); + pgraph.context[pgraph.channel_id].subchannel = GET_MASK(value, NV_PGRAPH_CTX_USER_SUBCH); +} + +DEVICE_WRITE32(PGRAPH) +{ + std::lock_guard lk(pgraph.mutex); + + switch (addr) { + case NV_PGRAPH_INTR: + pgraph.pending_interrupts &= ~value; + pgraph.interrupt_cond.notify_all(); + break; + case NV_PGRAPH_INTR_EN: + pgraph.enabled_interrupts = value; + break; + case NV_PGRAPH_CTX_CONTROL: + pgraph.channel_valid = (value & NV_PGRAPH_CTX_CONTROL_CHID); + break; + case NV_PGRAPH_CTX_USER: + pgraph_set_context_user(value); + break; + case NV_PGRAPH_INCREMENT: + if (value & NV_PGRAPH_INCREMENT_READ_3D) { + SET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_READ_3D, + (GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_READ_3D) + 1) + % GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_MODULO_3D)); + + pgraph.flip_3d.notify_all(); + } + break; + case NV_PGRAPH_FIFO: + pgraph.fifo_access = GET_MASK(value, NV_PGRAPH_FIFO_ACCESS); + pgraph.fifo_access_cond.notify_all(); + break; + case NV_PGRAPH_CHANNEL_CTX_TABLE: + pgraph.context_table = (value & NV_PGRAPH_CHANNEL_CTX_TABLE_INST) << 4; + break; + case NV_PGRAPH_CHANNEL_CTX_POINTER: + pgraph.context_address = + (value & NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4; + break; + case NV_PGRAPH_CHANNEL_CTX_TRIGGER: + if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) { + printf("PGRAPH: read channel %d context from %0x08X\n", + pgraph.channel_id, pgraph.context_address); + + uint8_t *context_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + pgraph.context_address); + uint32_t context_user = ldl_le_p((uint32_t*)context_ptr); + + printf(" - CTX_USER = 0x%x\n", context_user); + + + pgraph_set_context_user(context_user); + } + if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT) { + /* do stuff ... */ + } + + break; + default: + DEVICE_WRITE32_REG(pgraph); // Was : DEBUG_WRITE32_UNHANDLED(PGRAPH); + break; + } + + DEVICE_WRITE32_END(PGRAPH); +} + + +DEVICE_READ32(PCRTC) +{ + DEVICE_READ32_SWITCH() { + + case NV_PCRTC_INTR_0: + result = pcrtc.pending_interrupts; + break; + case NV_PCRTC_INTR_EN_0: + result = pcrtc.enabled_interrupts; + break; + case NV_PCRTC_START: + result = pcrtc.start; + break; + default: + result = 0; + //DEVICE_READ32_REG(pcrtc); // Was : DEBUG_READ32_UNHANDLED(PCRTC); + break; + } + + DEVICE_READ32_END(PCRTC); +} + +DEVICE_WRITE32(PCRTC) +{ + switch (addr) { + + case NV_PCRTC_INTR_0: + pcrtc.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PCRTC_INTR_EN_0: + pcrtc.enabled_interrupts = value; + update_irq(); + break; + case NV_PCRTC_START: + pcrtc.start = value &= 0x07FFFFFF; + break; + + default: + DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC); + break; + } + + DEVICE_WRITE32_END(PCRTC); +} + + +DEVICE_READ32(PRMCIO) +{ + DEVICE_READ32_SWITCH() { + case VGA_CRT_IM: + case VGA_CRT_IC: + result = prmcio.cr_index; + break; + case VGA_CRT_DM: + case VGA_CRT_DC: + result = prmcio.cr[prmcio.cr_index]; + + printf("vga: read CR%x = 0x%02x\n", prmcio.cr_index, result); + break; + default: + DEBUG_READ32_UNHANDLED(PRMCIO); + printf("vga: UNHANDLED ADDR %s\n", addr); + break; + } + + DEVICE_READ32_END(PRMCIO); +} + +DEVICE_WRITE32(PRMCIO) +{ + switch (addr) { + case VGA_CRT_IM: + case VGA_CRT_IC: + prmcio.cr_index = value; + break; + case VGA_CRT_DM: + case VGA_CRT_DC: + printf("vga: write CR%x = 0x%02x\n", prmcio.cr_index, value); + + /* handle CR0-7 protection */ + if ((prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && + prmcio.cr_index <= VGA_CRTC_OVERFLOW) { + /* can always write bit 4 of CR7 */ + if (prmcio.cr_index == VGA_CRTC_OVERFLOW) { + prmcio.cr[VGA_CRTC_OVERFLOW] = (prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) | + (value & 0x10); + EmuWarning("TODO: vbe_update_vgaregs"); + //vbe_update_vgaregs(); + } + return; + } + + prmcio.cr[prmcio.cr_index] = value; + EmuWarning("TODO: vbe_update_vgaregs"); + //vbe_update_vgaregs(); + + switch (prmcio.cr_index) { + case VGA_CRTC_H_TOTAL: + case VGA_CRTC_H_SYNC_START: + case VGA_CRTC_H_SYNC_END: + case VGA_CRTC_V_TOTAL: + case VGA_CRTC_OVERFLOW: + case VGA_CRTC_V_SYNC_END: + case VGA_CRTC_MODE: + // TODO: s->update_retrace_info(s); + EmuWarning("TODO: update_retrace_info"); + break; + } + break; + default: + DEBUG_WRITE32_UNHANDLED(PRMCIO); // TODO : DEVICE_WRITE32_REG(prmcio); + break; + } + + DEVICE_WRITE32_END(PRMCIO); +} + + +DEVICE_READ32(PRAMDAC) +{ + DEVICE_READ32_SWITCH() { + + case NV_PRAMDAC_NVPLL_COEFF: + result = pramdac.core_clock_coeff; + break; + case NV_PRAMDAC_MPLL_COEFF: + result = pramdac.memory_clock_coeff; + break; + case NV_PRAMDAC_VPLL_COEFF: + result = pramdac.video_clock_coeff; + break; + case NV_PRAMDAC_PLL_TEST_COUNTER: + /* emulated PLLs locked instantly? */ + result = NV_PRAMDAC_PLL_TEST_COUNTER_VPLL2_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK; + break; + + default: + //DEVICE_READ32_REG(pramdac); // Was : DEBUG_READ32_UNHANDLED(PRAMDAC); + break; + } + + DEVICE_READ32_END(PRAMDAC); +} + +DEVICE_WRITE32(PRAMDAC) +{ + switch (addr) { + + uint32_t m, n, p; + case NV_PRAMDAC_NVPLL_COEFF: + pramdac.core_clock_coeff = value; + + m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV; + n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV) >> 8; + p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV) >> 16; + + if (m == 0) { + pramdac.core_clock_freq = 0; + } + else { + pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n) + / (1 << p) / m; + } + + break; + case NV_PRAMDAC_MPLL_COEFF: + pramdac.memory_clock_coeff = value; + break; + case NV_PRAMDAC_VPLL_COEFF: + pramdac.video_clock_coeff = value; + break; + + default: + //DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC); + break; + } + + DEVICE_WRITE32_END(PRAMDAC); +} + + +DEVICE_READ32(PRMDIO) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMDIO); + break; + } + + DEVICE_READ32_END(PRMDIO); +} + +DEVICE_WRITE32(PRMDIO) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMDIO); + break; + } + + DEVICE_WRITE32_END(PRMDIO); +} + + +DEVICE_READ32(PRAMIN) +{ + DEVICE_READ32_SWITCH() { + default: + DEVICE_READ32_REG(pramin); + break; + } + + DEVICE_READ32_END(PRAMIN); +} + +DEVICE_WRITE32(PRAMIN) +{ + switch (addr) { + default: + DEVICE_WRITE32_REG(pramin); + break; + } + + DEVICE_WRITE32_END(PRAMIN); +} + + +DEVICE_READ32(USER) +{ + unsigned int channel_id = addr >> 16; + assert(channel_id < NV2A_NUM_CHANNELS); + + ChannelControl *control = &user.channel_control[channel_id]; + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + + /* PIO Mode */ + if (!channel_modes & (1 << channel_id)) { + assert(false); + } + + /* DMA Mode */ + addr &= 0xFFFF; + DEVICE_READ32_SWITCH() { + case NV_USER_DMA_PUT: + result = control->dma_put; + break; + case NV_USER_DMA_GET: + result = control->dma_get; + break; + case NV_USER_REF: + result = control->ref; + break; + default: + DEBUG_READ32_UNHANDLED(USER); + break; + } + + DEVICE_READ32_END(USER); +} + +DEVICE_WRITE32(USER) +{ + unsigned int channel_id = addr >> 16; + assert(channel_id < NV2A_NUM_CHANNELS); + + ChannelControl *control = &user.channel_control[channel_id]; + + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + + if (channel_modes & (1 << channel_id)) { + /* DMA Mode */ + switch (addr & 0xFFFF) { + case NV_USER_DMA_PUT: + control->dma_put = value; + + if (pfifo.cache1.push_enabled) { + pfifo_run_pusher(); + } + break; + case NV_USER_DMA_GET: + control->dma_get = value; + break; + case NV_USER_REF: + control->ref = value; + break; + default: + DEBUG_WRITE32_UNHANDLED(USER); + break; + } + } + else { + /* PIO Mode */ + assert(false); + } + + DEVICE_WRITE32_END(USER); +} + + +typedef struct NV2ABlockInfo { + uint32_t offset; + uint32_t size; + uint32_t(*read)(xbaddr addr); + void(*write)(xbaddr addr, uint32_t value); +} NV2ABlockInfo; + +static const NV2ABlockInfo regions[] = {{ + /* card master control */ + NV_PMC_ADDR, // = 0x000000 + NV_PMC_SIZE, // = 0x001000 + EmuNV2A_PMC_Read32, + EmuNV2A_PMC_Write32, + }, { + /* bus control */ + NV_PBUS_ADDR, // = 0x001000 + NV_PBUS_SIZE, // = 0x001000 + EmuNV2A_PBUS_Read32, + EmuNV2A_PBUS_Write32, + }, { + /* MMIO and DMA FIFO submission to PGRAPH and VPE */ + NV_PFIFO_ADDR, // = 0x002000 + NV_PFIFO_SIZE, // = 0x002000 + EmuNV2A_PFIFO_Read32, + EmuNV2A_PFIFO_Write32, + }, { + /* access to BAR0/BAR1 from real mode */ + NV_PRMA_ADDR, // = 0x007000 + NV_PRMA_SIZE, // = 0x001000 + EmuNV2A_PRMA_Read32, + EmuNV2A_PRMA_Write32, + }, { + /* video overlay */ + NV_PVIDEO_ADDR, // = 0x008000 + NV_PVIDEO_SIZE, // = 0x001000 + EmuNV2A_PVIDEO_Read32, + EmuNV2A_PVIDEO_Write32, + }, { + /* time measurement and time-based alarms */ + NV_PTIMER_ADDR, // = 0x009000 + NV_PTIMER_SIZE, // = 0x001000 + EmuNV2A_PTIMER_Read32, + EmuNV2A_PTIMER_Write32, + }, { + /* performance monitoring counters */ + NV_PCOUNTER_ADDR, // = 0x00a000 + NV_PCOUNTER_SIZE, // = 0x001000 + EmuNV2A_PCOUNTER_Read32, + EmuNV2A_PCOUNTER_Write32, + }, { + /* MPEG2 decoding engine */ + NV_PVPE_ADDR, // = 0x00b000 + NV_PVPE_SIZE, // = 0x001000 + EmuNV2A_PVPE_Read32, + EmuNV2A_PVPE_Write32, + }, { + /* TV encoder */ + NV_PTV_ADDR, // = 0x00d000 + NV_PTV_SIZE, // = 0x001000 + EmuNV2A_PTV_Read32, + EmuNV2A_PTV_Write32, + }, { + /* aliases VGA memory window */ + NV_PRMFB_ADDR, // = 0x0a0000 + NV_PRMFB_SIZE, // = 0x020000 + EmuNV2A_PRMFB_Read32, + EmuNV2A_PRMFB_Write32, + }, { + /* aliases VGA sequencer and graphics controller registers */ + NV_PRMVIO_ADDR, // = 0x0c0000 + NV_PRMVIO_SIZE, // = 0x001000 + EmuNV2A_PRMVIO_Read32, + EmuNV2A_PRMVIO_Write32, + },{ + /* memory interface */ + NV_PFB_ADDR, // = 0x100000 + NV_PFB_SIZE, // = 0x001000 + EmuNV2A_PFB_Read32, + EmuNV2A_PFB_Write32, + }, { + /* straps readout / override */ + NV_PSTRAPS_ADDR, // = 0x101000 + NV_PSTRAPS_SIZE, // = 0x001000 + EmuNV2A_PSTRAPS_Read32, + EmuNV2A_PSTRAPS_Write32, + }, { + /* accelerated 2d/3d drawing engine */ + NV_PGRAPH_ADDR, // = 0x400000 + NV_PGRAPH_SIZE, // = 0x002000 + EmuNV2A_PGRAPH_Read32, + EmuNV2A_PGRAPH_Write32, + }, { + /* more CRTC controls */ + NV_PCRTC_ADDR, // = 0x600000 + NV_PCRTC_SIZE, // = 0x001000 + EmuNV2A_PCRTC_Read32, + EmuNV2A_PCRTC_Write32, + }, { + /* aliases VGA CRTC and attribute controller registers */ + NV_PRMCIO_ADDR, // = 0x601000 + NV_PRMCIO_SIZE, // = 0x001000 + EmuNV2A_PRMCIO_Read32, + EmuNV2A_PRMCIO_Write32, + }, { + /* RAMDAC, cursor, and PLL control */ + NV_PRAMDAC_ADDR, // = 0x680000 + NV_PRAMDAC_SIZE, // = 0x001000 + EmuNV2A_PRAMDAC_Read32, + EmuNV2A_PRAMDAC_Write32, + }, { + /* aliases VGA palette registers */ + NV_PRMDIO_ADDR, // = 0x681000 + NV_PRMDIO_SIZE, // = 0x001000 + EmuNV2A_PRMDIO_Read32, + EmuNV2A_PRMDIO_Write32, + }, { + /* RAMIN access */ + NV_PRAMIN_ADDR, // = 0x700000 + NV_PRAMIN_SIZE, // = 0x100000 + EmuNV2A_PRAMIN_Read32, + EmuNV2A_PRAMIN_Write32, + },{ + /* PFIFO MMIO and DMA submission area */ + NV_USER_ADDR, // = 0x800000, + NV_USER_SIZE, // = 0x800000, + EmuNV2A_USER_Read32, + EmuNV2A_USER_Write32, + }, { + 0xFFFFFFFF, + 0, + nullptr, + nullptr, + }, +}; + +const NV2ABlockInfo* EmuNV2A_Block(xbaddr addr) +{ + // Find the block in the block table + const NV2ABlockInfo* block = ®ions[0]; + int i = 0; + + while (block->read != nullptr) { + if (addr >= block->offset && addr < block->offset + block->size) { + return block; + } + + block = ®ions[++i]; + } + + return nullptr; +} + +uint32_t EmuNV2A_Read(xbaddr addr, int size) +{ + const NV2ABlockInfo* block = EmuNV2A_Block(addr); + + if (block != nullptr) { + switch (size) { + case sizeof(uint8_t): + return block->read(addr - block->offset) & 0xFF; + case sizeof(uint16_t) : + return block->read(addr - block->offset) & 0xFFFF; + case sizeof(uint32_t) : + return block->read(addr - block->offset); + default: + EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); + return 0; + } + } + + EmuWarning("EmuNV2A_Read%d: Unhandled Read Address %08X", size, addr); + return 0; +} + +void EmuNV2A_Write(xbaddr addr, uint32_t value, int size) +{ + const NV2ABlockInfo* block = EmuNV2A_Block(addr); + + if (block != nullptr) { + int shift = 0; + xbaddr aligned_addr = 0; + uint32_t aligned_value = 0; + uint32_t mask = 0; + switch (size) { + case sizeof(uint8_t) : + shift = (addr & 3) * 8; + aligned_addr = addr & ~3; + aligned_value = block->read(aligned_addr - block->offset); + mask = 0xFF << shift; + + // TODO : Must the second byte be written to the next DWORD? + block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); + return; + case sizeof(uint16_t) : + assert((addr & 1) == 0); + + shift = (addr & 2) * 16; + aligned_addr = addr & ~3; + aligned_value = block->read(addr - block->offset); + mask = 0xFFFF << shift; + + // TODO : Must the second byte be written to the next DWORD? + block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); + return; + case sizeof(uint32_t) : + block->write(addr - block->offset, value); + return; + default: + EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); + return; + } + } + + EmuWarning("EmuNV2A_Write%d: Unhandled Write Address %08X (value %08X)", size, addr, value); + return; +} + +// +// OPENGL +// + +// +#define X_D3DTS_STAGECOUNT 4 + +HDC g_EmuWindowsDC = 0; +GLuint VertexProgramIDs[4] = { 0, 0, 0, 0 }; +uint ActiveVertexProgramID = 0; +GLuint TextureIDs[X_D3DTS_STAGECOUNT]= { 0, 0, 0, 0 }; + +// Vertex shader header, mapping Xbox1 registers to the ARB syntax (original version by KingOfC). +// Note about the use of 'conventional' attributes in here: Since we prefer to use only one shader +// for both immediate and deferred mode rendering, we alias all attributes to conventional inputs +// as much as possible. Only when there's no conventional attribute available, we use generic attributes. +// So in the following header, we use conventional attributes first, and generic attributes for the +// rest of the vertex attribute slots. This makes it possible to support immediate and deferred mode +// rendering with the same shader, and the use of the OpenGL fixed-function pipeline without a shader. +std::string DxbxVertexShaderHeader = + "!!ARBvp1.0\n" + "TEMP R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12;\n" + "ADDRESS A0;\n" +#ifdef DXBX_OPENGL_CONVENTIONAL + "ATTRIB v0 = vertex.position;\n" // Was: vertex.attrib[0] (See "conventional" note above) + "ATTRIB v1 = vertex.%s;\n" // Note : We replace this with "weight" or "attrib[1]" depending GL_ARB_vertex_blend + "ATTRIB v2 = vertex.normal;\n" // Was: vertex.attrib[2] + "ATTRIB v3 = vertex.color.primary;\n" // Was: vertex.attrib[3] + "ATTRIB v4 = vertex.color.secondary;\n" // Was: vertex.attrib[4] + "ATTRIB v5 = vertex.fogcoord;\n" // Was: vertex.attrib[5] + "ATTRIB v6 = vertex.attrib[6];\n" + "ATTRIB v7 = vertex.attrib[7];\n" + "ATTRIB v8 = vertex.texcoord[0];\n" // Was: vertex.attrib[8] + "ATTRIB v9 = vertex.texcoord[1];\n" // Was: vertex.attrib[9] + "ATTRIB v10 = vertex.texcoord[2];\n" // Was: vertex.attrib[10] + "ATTRIB v11 = vertex.texcoord[3];\n" // Was: vertex.attrib[11] +#else + "ATTRIB v0 = vertex.attrib[0];\n" + "ATTRIB v1 = vertex.attrib[1];\n" + "ATTRIB v2 = vertex.attrib[2];\n" + "ATTRIB v3 = vertex.attrib[3];\n" + "ATTRIB v4 = vertex.attrib[4];\n" + "ATTRIB v5 = vertex.attrib[5];\n" + "ATTRIB v6 = vertex.attrib[6];\n" + "ATTRIB v7 = vertex.attrib[7];\n" + "ATTRIB v8 = vertex.attrib[8];\n" + "ATTRIB v9 = vertex.attrib[9];\n" + "ATTRIB v10 = vertex.attrib[10];\n" + "ATTRIB v11 = vertex.attrib[11];\n" +#endif + "ATTRIB v12 = vertex.attrib[12];\n" + "ATTRIB v13 = vertex.attrib[13];\n" + "ATTRIB v14 = vertex.attrib[14];\n" + "ATTRIB v15 = vertex.attrib[15];\n" + "OUTPUT oPos = result.position;\n" + "OUTPUT oD0 = result.color.front.primary;\n" + "OUTPUT oD1 = result.color.front.secondary;\n" + "OUTPUT oB0 = result.color.back.primary;\n" + "OUTPUT oB1 = result.color.back.secondary;\n" + "OUTPUT oPts = result.pointsize;\n" + "OUTPUT oFog = result.fogcoord;\n" + "OUTPUT oT0 = result.texcoord[0];\n" + "OUTPUT oT1 = result.texcoord[1];\n" + "OUTPUT oT2 = result.texcoord[2];\n" + "OUTPUT oT3 = result.texcoord[3];\n" + "PARAM c[] = { program.env[0..191] };\n" // All constants in 1 array declaration (requires NV_gpu_program4?) + "PARAM mvp[4] = { state.matrix.mvp };\n"; + +void SetupPixelFormat(HDC DC) +{ + const PIXELFORMATDESCRIPTOR pfd = { + /* .nSize = */ sizeof(PIXELFORMATDESCRIPTOR), // size + /* .nVersion = */ 1, // version + /* .dwFlags = */ PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, // support double-buffering + /* .iPixelType = */ PFD_TYPE_RGBA, // color type + /* .cColorBits = */ 32, // preferred color depth + /* .cRedBits = */ 0, + /* .cRedShift = */ 0, // color bits (ignored) + /* .cGreenBits = */ 0, + /* .cGreenShift = */ 0, + /* .cBlueBits = */ 0, + /* .cBlueShift = */ 0, + /* .cAlphaBits = */ 0, + /* .cAlphaShift = */ 0, // no alpha buffer + /* .cAccumBits = */ 0, + /* .cAccumRedBits = */ 0, // no accumulation buffer, + /* .cAccumGreenBits = */ 0, // accum bits (ignored) + /* .cAccumBlueBits = */ 0, + /* .cAccumAlphaBits = */ 0, + /* .cDepthBits = */ 16, // depth buffer + /* .cStencilBits = */ 0, // no stencil buffer + /* .cAuxBuffers = */ 0, // no auxiliary buffers + /* .iLayerType= */ PFD_MAIN_PLANE, // main layer + /* .bReserved = */ 0, + /* .dwLayerMask = */ 0, + /* .dwVisibleMask = */ 0, + /* .dwDamageMask = */ 0 // no layer, visible, damage masks + }; + + int PixelFormat = ChoosePixelFormat(DC, &pfd); + if (PixelFormat == 0) + return; + + if (SetPixelFormat(DC, PixelFormat, &pfd) != TRUE) + return; +} + +// From https://github.com/inolen/redream/blob/master/src/video/gl_backend.c +static int rb_compile_shader(const char *source, GLenum shader_type, GLuint *shader) +{ + size_t sourceLength = strlen(source); + + *shader = glCreateShader(shader_type); + glShaderSource(*shader, 1, (const GLchar **)&source, + (const GLint *)&sourceLength); + glCompileShader(*shader); + + GLint compiled; + glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { +// rb_print_shader_log(*shader); + glDeleteShader(*shader); + return 0; + } + + return 1; +} + +void DxbxCompileShader(std::string Shader) +{ + int GLErrorPos; + +// if (MayLog(lfUnit)) +// DbgPrintf(" NV2A: New vertex program :\n" + Shader); + +/* +glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, Shader.size(), Shader.c_str()); + + // errors are catched + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &GLErrorPos); + */ + GLuint shader; + + GLErrorPos = rb_compile_shader(Shader.c_str(), GL_VERTEX_SHADER, &shader); // TODO : GL_VERTEX_SHADER_ARB ?? + /* + if (GLErrorPos > 0) + { + Shader.insert(GLErrorPos, "{ERROR}"); + EmuWarning("Program error at position %d:", GLErrorPos); + EmuWarning((char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)); + EmuWarning(Shader.c_str()); + } + */ +} +void InitOpenGLContext() +{ + HGLRC RC; + std::string szCode; + + g_EmuWindowsDC = GetDC(g_hEmuWindow); // Actually, you can use any windowed control here + SetupPixelFormat(g_EmuWindowsDC); + + RC = wglCreateContext(g_EmuWindowsDC); // makes OpenGL window out of DC + wglMakeCurrent(g_EmuWindowsDC, RC); // makes OpenGL window active + //ReadImplementationProperties(); // Determine a set of booleans indicating which OpenGL extensions are available + //ReadExtensions(); // Assign all OpenGL extension API's (DON'T call them if the extension is not available!) + + // Initialize the viewport : + //Viewport.X = 0; + //Viewport.Y = 0; + //Viewport.Width = g_EmuCDPD.pPresentationParameters.BackBufferWidth; + //Viewport.Height = g_EmuCDPD.pPresentationParameters.BackBufferHeight; + //Viewport.MinZ = -1.0; + //Viewport.MaxZ = 1.0; + + //DxbxUpdateTransformProjection(); + //DxbxUpdateViewport(); + + + //glutInit(); + { // rb_init_context(); + /* link in gl functions at runtime */ + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (err != GLEW_OK) { + EmuWarning("GLEW initialization failed: %s", glewGetErrorString(err)); + return; + } + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + // Switch to left-handed coordinate space (as per http://www.opengl.org/resources/faq/technical/transformations.htm) : + // glScalef(1.0, 1.0, -1.0); + + // Set some defaults : + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); // Nearer Z coordinates cover further Z + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glAlphaFunc(GL_GEQUAL, 0.5); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // GL_LINE for wireframe + +/* + // TODO : The following code only works on cards that support the + // vertex program extensions (NVidia cards mainly); So for ATI we + // have to come up with another solution !!! + glGenProgramsARB(4, &VertexProgramIDs[0]); +*/ + +#ifdef DXBX_OPENGL_CONVENTIONAL + if (GL_ARB_vertex_blend) + DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "weight"); + else + DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "attrib[1]"); +#endif + + // Precompiled shader for the fixed function pipeline : + szCode = DxbxVertexShaderHeader + + "# This part adjusts the vertex position by the super-sampling scale & offset :\n" + "MOV R0, v0;\n" + "RCP R0.w, R0.w;\n" + "MUL R0, R0, c[0];\n" // c[-96] in D3D speak - applies SuperSampleScale + // Note : Use R12 instead of oPos because this is not yet the final assignment : + "ADD R12, R0, c[1];\n" // c[-95] in D3D speak - applies SuperSampleOffset + + "# This part just reads all other components and passes them to the output :\n" + "MOV oD0, v3;\n" + "MOV oD1, v4;\n" + "MOV oFog, v4.w;\n" // specular fog + // "MOV oFog, v0.z;\n" // z fog + // "RCP oFog, v0.w;\n" // w fog + "MOV oPts, v1.x;\n" + "MOV oB0, v7;\n" + "MOV oB1, v8;\n" + "MOV oT0, v9;\n" + "MOV oT1, v10;\n" + "MOV oT2, v11;\n" + "MOV oT3, v12;\n" + + "# This part applies the screen-space transform (not present when '#pragma screenspace' was used) :\n" + "MUL R12.xyz, R12, c[58];\n" // c[-38] in D3D speak - see EmuNV2A_ViewportScale, + "RCP R1.x, R12.w;\n" // Originally RCC, but that"s not supported in ARBvp1.0 (use "MIN R1, R1, 0" and "MAX R1, R1, 1"?) + "MAD R12.xyz, R12, R1.x, c[59];\n" // c[-37] in D3D speak - see EmuNV2A_ViewportOffset + + "# Dxbx addition : Transform the vertex to clip coordinates :\n" + "DP4 R0.x, mvp[0], R12;\n" + "DP4 R0.y, mvp[1], R12;\n" + "DP4 R0.z, mvp[2], R12;\n" + "DP4 R0.w, mvp[3], R12;\n" + "MOV R12, R0;\n" + + "# Apply Z coord mapping\n" + "ADD R12.z, R12.z, R12.z;\n" + "ADD R12.z, R12.z, -R12.w;\n" + + "# Here""s the final assignment to oPos :\n" + "MOV oPos, R12;\n" + "END\n"; // TODO : Check if newline is required? + +// glBindProgramARB(GL_VERTEX_PROGRAM_ARB, VertexProgramIDs[0]); + DxbxCompileShader(szCode); +} + +// HACK: Until we implement VGA/proper interrupt generation +// we simulate VBLANK by calling the interrupt at 60Hz +std::thread vblank_thread; +extern std::chrono::time_point> GetNextVBlankTime(); +static void nv2a_vblank_thread() +{ + auto nextVBlankTime = GetNextVBlankTime(); + + while (true) { + // Handle VBlank + if (std::chrono::steady_clock::now() > nextVBlankTime) { + pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK; + update_irq(); + nextVBlankTime = GetNextVBlankTime(); + } + } +} + +void EmuNV2A_Init() +{ + // Allocate PRAMIN Region + VirtualAlloc((void*)(NV2A_ADDR + NV_PRAMIN_ADDR), NV_PRAMIN_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + pcrtc.start = 0; + + pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */ + pramdac.core_clock_freq = 189000000; + pramdac.memory_clock_coeff = 0; + pramdac.video_clock_coeff = 0x0003C20D; /* 25182Khz...? */ + + pfifo.puller_thread = std::thread(pfifo_puller_thread); + + // Only spawn VBlank thread when LLE is enabled + if (bLLE_GPU) { + vblank_thread = std::thread(nv2a_vblank_thread);; + } +} diff --git a/src/CxbxKrnl/EmuNV2A.h b/src/devices/video/EmuNV2A.h similarity index 100% rename from src/CxbxKrnl/EmuNV2A.h rename to src/devices/video/EmuNV2A.h diff --git a/src/CxbxKrnl/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp similarity index 96% rename from src/CxbxKrnl/devices/video/nv2a.cpp rename to src/devices/video/nv2a.cpp index 3ea6c6972..25309a8e4 100644 --- a/src/CxbxKrnl/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -38,8 +38,8 @@ #define LOG_PREFIX "NV2A" -#include "../../CxbxKrnl/CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc -#include "../../CxbxKrnl/EmuNV2A.h" // For now, use EmuNV2A +#include "CxbxKrnl\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc +#include "EmuNV2A.h" // For now, use EmuNV2A #include "nv2a.h" diff --git a/src/CxbxKrnl/devices/video/nv2a.h b/src/devices/video/nv2a.h similarity index 97% rename from src/CxbxKrnl/devices/video/nv2a.h rename to src/devices/video/nv2a.h index be6c90324..1c35c7d8c 100644 --- a/src/CxbxKrnl/devices/video/nv2a.h +++ b/src/devices/video/nv2a.h @@ -34,7 +34,7 @@ // ****************************************************************** #pragma once -#include "../../CxbxKrnl/PCIDevice.h" // For PCIDevice +#include "devices\PCIDevice.h" // For PCIDevice #define NV2A_ADDR 0xFD000000 #define NV2A_SIZE 0x01000000 diff --git a/src/CxbxKrnl/nv2a_int.h b/src/devices/video/nv2a_int.h similarity index 100% rename from src/CxbxKrnl/nv2a_int.h rename to src/devices/video/nv2a_int.h diff --git a/src/CxbxKrnl/vga.h b/src/devices/video/vga.h similarity index 100% rename from src/CxbxKrnl/vga.h rename to src/devices/video/vga.h From 7697dc9333b04763cbc555b5b18519233148c394 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Mon, 22 Jan 2018 00:16:01 +0100 Subject: [PATCH 09/37] All hardware devices are moved outside CxbxKrnl, towards devices (some into devices\video) --- build/win32/Cxbx.vcxproj | 45 +- build/win32/Cxbx.vcxproj.filters | 119 +- src/CxbxKrnl/CxbxKrnl.cpp | 6 +- src/CxbxKrnl/EmuKrnlHal.cpp | 6 +- src/CxbxKrnl/EmuX86.cpp | 2 +- src/{CxbxKrnl => devices}/EEPROMDevice.cpp | 0 src/{CxbxKrnl => devices}/EEPROMDevice.h | 0 src/{CxbxKrnl => devices}/EmuNVNet.cpp | 7 +- src/{CxbxKrnl => devices}/EmuNVNet.h | 0 src/{CxbxKrnl => devices}/LED.h | 0 src/{CxbxKrnl => devices}/PCIBus.cpp | 0 src/{CxbxKrnl => devices}/PCIBus.h | 0 src/{CxbxKrnl => devices}/PCIDevice.cpp | 0 src/{CxbxKrnl => devices}/PCIDevice.h | 0 src/{CxbxKrnl => devices}/SMBus.cpp | 0 src/{CxbxKrnl => devices}/SMBus.h | 0 src/{CxbxKrnl => devices}/SMCDevice.cpp | 5 +- src/{CxbxKrnl => devices}/SMCDevice.h | 0 src/{CxbxKrnl => devices}/SMDevice.cpp | 0 src/{CxbxKrnl => devices}/SMDevice.h | 0 src/{CxbxKrnl => devices}/Xbox.cpp | 0 src/{CxbxKrnl => devices}/Xbox.h | 0 src/{CxbxKrnl => devices/video}/EmuNV2A.cpp | 7523 ++++++++++--------- src/{CxbxKrnl => devices/video}/EmuNV2A.h | 0 src/{CxbxKrnl => }/devices/video/nv2a.cpp | 4 +- src/{CxbxKrnl => }/devices/video/nv2a.h | 2 +- src/{CxbxKrnl => devices/video}/nv2a_int.h | 0 src/{CxbxKrnl => devices/video}/vga.h | 0 28 files changed, 3863 insertions(+), 3856 deletions(-) rename src/{CxbxKrnl => devices}/EEPROMDevice.cpp (100%) rename src/{CxbxKrnl => devices}/EEPROMDevice.h (100%) rename src/{CxbxKrnl => devices}/EmuNVNet.cpp (99%) rename src/{CxbxKrnl => devices}/EmuNVNet.h (100%) rename src/{CxbxKrnl => devices}/LED.h (100%) rename src/{CxbxKrnl => devices}/PCIBus.cpp (100%) rename src/{CxbxKrnl => devices}/PCIBus.h (100%) rename src/{CxbxKrnl => devices}/PCIDevice.cpp (100%) rename src/{CxbxKrnl => devices}/PCIDevice.h (100%) rename src/{CxbxKrnl => devices}/SMBus.cpp (100%) rename src/{CxbxKrnl => devices}/SMBus.h (100%) rename src/{CxbxKrnl => devices}/SMCDevice.cpp (99%) rename src/{CxbxKrnl => devices}/SMCDevice.h (100%) rename src/{CxbxKrnl => devices}/SMDevice.cpp (100%) rename src/{CxbxKrnl => devices}/SMDevice.h (100%) rename src/{CxbxKrnl => devices}/Xbox.cpp (100%) rename src/{CxbxKrnl => devices}/Xbox.h (100%) rename src/{CxbxKrnl => devices/video}/EmuNV2A.cpp (96%) rename src/{CxbxKrnl => devices/video}/EmuNV2A.h (100%) rename src/{CxbxKrnl => }/devices/video/nv2a.cpp (96%) rename src/{CxbxKrnl => }/devices/video/nv2a.h (97%) rename src/{CxbxKrnl => devices/video}/nv2a_int.h (100%) rename src/{CxbxKrnl => devices/video}/vga.h (100%) diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index 5074bfe6d..344ad3e05 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -190,8 +190,6 @@ - - @@ -218,8 +216,6 @@ - - @@ -231,20 +227,12 @@ - - - - - - - - @@ -260,6 +248,19 @@ + + + + + + + + + + + + + @@ -360,8 +361,6 @@ - - @@ -481,8 +480,6 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - - @@ -525,18 +522,12 @@ - - - %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) - - - @@ -600,6 +591,16 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + + + + + + + + + + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 546c0b4c5..9a9f24fdc 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -196,37 +196,37 @@ Emulator - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - Hardware - + Hardware - + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + Hardware @@ -354,9 +354,6 @@ Emulator - - Emulator - Emulator @@ -405,46 +402,52 @@ HLEDatabase\D3D8 - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - - - Hardware - Emulator Emulator - - Hardware - Hardware - + Hardware - + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + + Hardware + + Hardware diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 1162d9cd4..160e4e51c 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -51,7 +51,6 @@ namespace xboxkrnl #include "EmuEEPROM.h" // For CxbxRestoreEEPROM, EEPROM, XboxFactoryGameRegion #include "EmuKrnl.h" #include "EmuShared.h" -#include "EmuNV2A.h" // For InitOpenGLContext #include "HLEIntercept.h" #include "ReservedMemory.h" // For virtual_memory_placeholder #include "VMManager.h" @@ -63,8 +62,9 @@ namespace xboxkrnl #include // For time() #include // For std::ostringstream -#include "Xbox.h" // For InitXboxHardware() -#include "EEPROMDevice.h" // For g_EEPROM +#include "devices\EEPROMDevice.h" // For g_EEPROM +#include "devices\video\EmuNV2A.h" // For InitOpenGLContext +#include "devices\Xbox.h" // For InitXboxHardware() /* prevent name collisions */ namespace NtDll diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index 3a60daac8..ac4b91247 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -51,11 +51,11 @@ namespace xboxkrnl #include "Emu.h" // For EmuWarning() #include "EmuKrnl.h" #include "EmuX86.h" // HalReadWritePciSpace needs this -#include "SMBus.h" // For g_SMBus -#include "EmuEEPROM.h" // For EEPROM -#include "SMCDevice.h" // For SMC_COMMAND_SCRATCH #include "EmuShared.h" #include "EmuFile.h" // For FindNtSymbolicLinkObjectByDriveLetter +#include "Common\EmuEEPROM.h" // For EEPROM +#include "devices\SMBus.h" // For g_SMBus +#include "devices\SMCDevice.h" // For SMC_COMMAND_SCRATCH #include // for std::replace #include diff --git a/src/CxbxKrnl/EmuX86.cpp b/src/CxbxKrnl/EmuX86.cpp index 15bc5c9ff..b29d2bb4e 100644 --- a/src/CxbxKrnl/EmuX86.cpp +++ b/src/CxbxKrnl/EmuX86.cpp @@ -52,7 +52,7 @@ #include "HLEIntercept.h" // for bLLE_GPU #include -#include "PCIBus.h" +#include "devices\PCIBus.h" // // Read & write handlers handlers for I/O diff --git a/src/CxbxKrnl/EEPROMDevice.cpp b/src/devices/EEPROMDevice.cpp similarity index 100% rename from src/CxbxKrnl/EEPROMDevice.cpp rename to src/devices/EEPROMDevice.cpp diff --git a/src/CxbxKrnl/EEPROMDevice.h b/src/devices/EEPROMDevice.h similarity index 100% rename from src/CxbxKrnl/EEPROMDevice.h rename to src/devices/EEPROMDevice.h diff --git a/src/CxbxKrnl/EmuNVNet.cpp b/src/devices/EmuNVNet.cpp similarity index 99% rename from src/CxbxKrnl/EmuNVNet.cpp rename to src/devices/EmuNVNet.cpp index 042b8df4d..61d5de6bc 100644 --- a/src/CxbxKrnl/EmuNVNet.cpp +++ b/src/devices/EmuNVNet.cpp @@ -48,9 +48,10 @@ namespace xboxkrnl #include // For PKINTERRUPT, etc. }; -#include "CxbxKrnl.h" -#include "Emu.h" -#include "EmuKrnl.h" +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\Emu.h" +#include "CxbxKrnl\EmuKrnl.h" + #include "EmuNVNet.h" // NVNET Register Definitions diff --git a/src/CxbxKrnl/EmuNVNet.h b/src/devices/EmuNVNet.h similarity index 100% rename from src/CxbxKrnl/EmuNVNet.h rename to src/devices/EmuNVNet.h diff --git a/src/CxbxKrnl/LED.h b/src/devices/LED.h similarity index 100% rename from src/CxbxKrnl/LED.h rename to src/devices/LED.h diff --git a/src/CxbxKrnl/PCIBus.cpp b/src/devices/PCIBus.cpp similarity index 100% rename from src/CxbxKrnl/PCIBus.cpp rename to src/devices/PCIBus.cpp diff --git a/src/CxbxKrnl/PCIBus.h b/src/devices/PCIBus.h similarity index 100% rename from src/CxbxKrnl/PCIBus.h rename to src/devices/PCIBus.h diff --git a/src/CxbxKrnl/PCIDevice.cpp b/src/devices/PCIDevice.cpp similarity index 100% rename from src/CxbxKrnl/PCIDevice.cpp rename to src/devices/PCIDevice.cpp diff --git a/src/CxbxKrnl/PCIDevice.h b/src/devices/PCIDevice.h similarity index 100% rename from src/CxbxKrnl/PCIDevice.h rename to src/devices/PCIDevice.h diff --git a/src/CxbxKrnl/SMBus.cpp b/src/devices/SMBus.cpp similarity index 100% rename from src/CxbxKrnl/SMBus.cpp rename to src/devices/SMBus.cpp diff --git a/src/CxbxKrnl/SMBus.h b/src/devices/SMBus.h similarity index 100% rename from src/CxbxKrnl/SMBus.h rename to src/devices/SMBus.h diff --git a/src/CxbxKrnl/SMCDevice.cpp b/src/devices/SMCDevice.cpp similarity index 99% rename from src/CxbxKrnl/SMCDevice.cpp rename to src/devices/SMCDevice.cpp index 98934fa79..a95239505 100644 --- a/src/CxbxKrnl/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -41,8 +41,9 @@ namespace xboxkrnl #include // For xbox.h:AV_PACK_HDTV }; -#include "CxbxKrnl.h" -#include "EmuShared.h" +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\EmuShared.h" + #include "SMCDevice.h" // For SMCDevice #include "LED.h" diff --git a/src/CxbxKrnl/SMCDevice.h b/src/devices/SMCDevice.h similarity index 100% rename from src/CxbxKrnl/SMCDevice.h rename to src/devices/SMCDevice.h diff --git a/src/CxbxKrnl/SMDevice.cpp b/src/devices/SMDevice.cpp similarity index 100% rename from src/CxbxKrnl/SMDevice.cpp rename to src/devices/SMDevice.cpp diff --git a/src/CxbxKrnl/SMDevice.h b/src/devices/SMDevice.h similarity index 100% rename from src/CxbxKrnl/SMDevice.h rename to src/devices/SMDevice.h diff --git a/src/CxbxKrnl/Xbox.cpp b/src/devices/Xbox.cpp similarity index 100% rename from src/CxbxKrnl/Xbox.cpp rename to src/devices/Xbox.cpp diff --git a/src/CxbxKrnl/Xbox.h b/src/devices/Xbox.h similarity index 100% rename from src/CxbxKrnl/Xbox.h rename to src/devices/Xbox.h diff --git a/src/CxbxKrnl/EmuNV2A.cpp b/src/devices/video/EmuNV2A.cpp similarity index 96% rename from src/CxbxKrnl/EmuNV2A.cpp rename to src/devices/video/EmuNV2A.cpp index c7ecaa455..da222a46a 100644 --- a/src/CxbxKrnl/EmuNV2A.cpp +++ b/src/devices/video/EmuNV2A.cpp @@ -1,3761 +1,3762 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * .,-::::: .,:: .::::::::. .,:: .: -// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; -// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' -// * $$$ Y$$$P $$""""Y$$ Y$$$P -// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, -// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, -// * -// * Cxbx->Win32->CxbxKrnl->EmuNV2A.cpp -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * (c) 2016 Luke Usher -// * -// * EmuNV2A.cpp is heavily based on code from XQEMU -// * Copyright(c) 2012 espes -// * Copyright(c) 2015 Jannik Vogel -// * https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a.c -// * -// * All rights reserved -// * -// ****************************************************************** -#define _XBOXKRNL_DEFEXTRN_ - -#define LOG_PREFIX "NV2A" - -#include // For __beginthreadex(), etc. -#include "vga.h" - -// prevent name collisions -namespace xboxkrnl -{ - #include // For PKINTERRUPT, etc. -}; - - -#ifdef _MSC_VER // Check if MS Visual C compiler -# pragma comment(lib, "opengl32.lib") // Compiler-specific directive to avoid manually configuration -//# pragma comment(lib, "glu32.lib") // Link libraries -# pragma comment(lib, "glew32.lib") -#endif - -#include // For uint32_t -#include // For std::string -#include -#include -#include -#include - -#include "CxbxKrnl.h" -#include "Emu.h" -#include "EmuFS.h" -#include "EmuKrnl.h" -#include "EmuNV2A.h" -#include "HLEIntercept.h" -#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox - -#include -#include -#include -#include -//#include - - -// Public Domain ffs Implementation -// See: http://snipplr.com/view/22147/stringsh-implementation/ -int ffs(int v) -{ - unsigned int x = v; - int c = 1; - - /* - * adapted from from - * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch - * - * a modified binary search algorithm to count 0 bits from - * the right (lsb). This algorithm should work regardless - * of the size of ints on the platform. - * - */ - - /* a couple special cases */ - if (x == 0) return 0; - if (x & 1) return 1; /* probably pretty common */ - - c = 1; - while ((x & 0xffff) == 0) { - x >>= 16; - c += 16; - } - if ((x & 0xff) == 0) { - x >>= 8; - c += 8; - } - if ((x & 0x0f) == 0) { - x >>= 4; - c += 4; - } - if ((x & 0x03) == 0) { - x >>= 2; - c += 2; - } - - c -= (x & 1); - c += 1; /* ffs() requires indexing bits from 1 */ - /* ie., the lsb is bit 1, not bit 0 */ - return c; -} - -inline int GET_MASK(int v, int mask) { - return (((v) & (mask)) >> (ffs(mask) - 1)); -}; - -inline int SET_MASK(int v, int mask, int val) { - const unsigned int __val = (val); - const unsigned int __mask = (mask); - - (v) &= ~(__mask); - return (v) |= ((__val) << (ffs(__mask)-1)) & (__mask); -} - -#define CASE_4(v, step) \ - case (v): \ - case (v)+(step) : \ - case (v)+(step) * 2: \ - case (v)+(step) * 3 - - -enum FifoMode { - FIFO_PIO = 0, - FIFO_DMA = 1, -}; - -enum FIFOEngine { - ENGINE_SOFTWARE = 0, - ENGINE_GRAPHICS = 1, - ENGINE_DVD = 2, -}; - -typedef struct RAMHTEntry { - uint32_t handle; - xbaddr instance; - enum FIFOEngine engine; - unsigned int channel_id : 5; - bool valid; -} RAMHTEntry; - -typedef struct DMAObject { - unsigned int dma_class; - unsigned int dma_target; - xbaddr address; - xbaddr limit; -} DMAObject; - -typedef struct VertexAttribute { - bool dma_select; - xbaddr offset; - - /* inline arrays are packed in order? - * Need to pass the offset to converted attributes */ - unsigned int inline_array_offset; - - float inline_value[4]; - - unsigned int format; - unsigned int size; /* size of the data type */ - unsigned int count; /* number of components */ - uint32_t stride; - - bool needs_conversion; - uint8_t *converted_buffer; - unsigned int converted_elements; - unsigned int converted_size; - unsigned int converted_count; - - float *inline_buffer; - - GLint gl_count; - GLenum gl_type; - GLboolean gl_normalize; - - GLuint gl_converted_buffer; - GLuint gl_inline_buffer; -} VertexAttribute; - -typedef struct Surface { - bool draw_dirty; - bool buffer_dirty; - bool write_enabled_cache; - unsigned int pitch; - - xbaddr offset; -} Surface; - -typedef struct SurfaceShape { - unsigned int z_format; - unsigned int color_format; - unsigned int zeta_format; - unsigned int log_width, log_height; - unsigned int clip_x, clip_y; - unsigned int clip_width, clip_height; - unsigned int anti_aliasing; -} SurfaceShape; - -typedef struct TextureShape { - bool cubemap; - unsigned int dimensionality; - unsigned int color_format; - unsigned int levels; - unsigned int width, height, depth; - - unsigned int min_mipmap_level, max_mipmap_level; - unsigned int pitch; -} TextureShape; - -typedef struct TextureKey { - TextureShape state; - uint64_t data_hash; - uint8_t* texture_data; - uint8_t* palette_data; -} TextureKey; - -typedef struct TextureBinding { - GLenum gl_target; - GLuint gl_texture; - unsigned int refcnt; -} TextureBinding; - -typedef struct KelvinState { - xbaddr dma_notifies; - xbaddr dma_state; - xbaddr dma_semaphore; - unsigned int semaphore_offset; -} KelvinState; - -typedef struct ContextSurfaces2DState { - xbaddr dma_image_source; - xbaddr dma_image_dest; - unsigned int color_format; - unsigned int source_pitch, dest_pitch; - xbaddr source_offset, dest_offset; - -} ContextSurfaces2DState; - -typedef struct ImageBlitState { - xbaddr context_surfaces; - unsigned int operation; - unsigned int in_x, in_y; - unsigned int out_x, out_y; - unsigned int width, height; - -} ImageBlitState; - -typedef struct GraphicsObject { - uint8_t graphics_class; - union { - ContextSurfaces2DState context_surfaces_2d; - - ImageBlitState image_blit; - - KelvinState kelvin; - } data; -} GraphicsObject; - -typedef struct GraphicsSubchannel { - xbaddr object_instance; - GraphicsObject object; - uint32_t object_cache[5]; -} GraphicsSubchannel; - -typedef struct GraphicsContext { - bool channel_3d; - unsigned int subchannel; -} GraphicsContext; - -typedef struct CacheEntry { - unsigned int method : 14; - unsigned int subchannel : 3; - bool nonincreasing; - uint32_t parameter; -} CacheEntry; - -typedef struct Cache1State { - unsigned int channel_id; - FifoMode mode; - - /* Pusher state */ - bool push_enabled; - bool dma_push_enabled; - bool dma_push_suspended; - xbaddr dma_instance; - - bool method_nonincreasing; - unsigned int method : 14; - unsigned int subchannel : 3; - unsigned int method_count : 24; - uint32_t dcount; - - bool subroutine_active; - xbaddr subroutine_return; - xbaddr get_jmp_shadow; - uint32_t rsvd_shadow; - uint32_t data_shadow; - uint32_t error; - - bool pull_enabled; - enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS]; - enum FIFOEngine last_engine; - - /* The actual command queue */ - std::mutex mutex; - std::condition_variable cache_cond; - std::queue cache; - std::queue working_cache; -} Cache1State; - -typedef struct ChannelControl { - xbaddr dma_put; - xbaddr dma_get; - uint32_t ref; -} ChannelControl; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t regs[NV_PMC_SIZE]; // TODO : union -} pmc; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - std::thread puller_thread; - Cache1State cache1; - uint32_t regs[NV_PFIFO_SIZE]; // TODO : union -} pfifo; - -struct { - uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union -} pvideo; - - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t numerator; - uint32_t denominator; - uint32_t alarm_time; - uint32_t regs[NV_PTIMER_SIZE]; // TODO : union -} ptimer; - -struct { - uint32_t regs[NV_PFB_SIZE]; // TODO : union -} pfb; - -struct { - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - uint32_t start; - uint32_t regs[NV_PCRTC_SIZE]; // TODO : union -} pcrtc; - -struct { - uint32_t core_clock_coeff; - uint64_t core_clock_freq; - uint32_t memory_clock_coeff; - uint32_t video_clock_coeff; - uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union -} pramdac; - -struct { - uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union -} pramin; - -struct { - ChannelControl channel_control[NV2A_NUM_CHANNELS]; -} user; - -// PRMCIO (Actually the VGA controller) -struct { - uint8_t cr_index; - uint8_t cr[256]; /* CRT registers */ -} prmcio; - -struct { - std::mutex mutex; - - uint32_t pending_interrupts; - uint32_t enabled_interrupts; - std::condition_variable interrupt_cond; - - xbaddr context_table; - xbaddr context_address; - - - unsigned int trapped_method; - unsigned int trapped_subchannel; - unsigned int trapped_channel_id; - uint32_t trapped_data[2]; - uint32_t notify_source; - - bool fifo_access; - std::condition_variable fifo_access_cond; - std::condition_variable flip_3d; - - unsigned int channel_id; - bool channel_valid; - GraphicsContext context[NV2A_NUM_CHANNELS]; - - xbaddr dma_color, dma_zeta; - Surface surface_color, surface_zeta; - unsigned int surface_type; - SurfaceShape surface_shape; - SurfaceShape last_surface_shape; - - xbaddr dma_a, dma_b; - //GLruCache *texture_cache; - bool texture_dirty[NV2A_MAX_TEXTURES]; - TextureBinding *texture_binding[NV2A_MAX_TEXTURES]; - - //GHashTable *shader_cache; - //ShaderBinding *shader_binding; - - bool texture_matrix_enable[NV2A_MAX_TEXTURES]; - - /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ - float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */ - - // wglContext *gl_context; - GLuint gl_framebuffer; - GLuint gl_color_buffer, gl_zeta_buffer; - GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS]; - - xbaddr dma_report; - xbaddr report_offset; - bool zpass_pixel_count_enable; - unsigned int zpass_pixel_count_result; - unsigned int gl_zpass_pixel_count_query_count; - GLuint* gl_zpass_pixel_count_queries; - - xbaddr dma_vertex_a, dma_vertex_b; - - unsigned int primitive_mode; - - bool enable_vertex_program_write; - - //uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE]; - - uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS]; - - /* lighting constant arrays */ - uint32_t ltctxa[NV2A_LTCTXA_COUNT][4]; - bool ltctxa_dirty[NV2A_LTCTXA_COUNT]; - uint32_t ltctxb[NV2A_LTCTXB_COUNT][4]; - bool ltctxb_dirty[NV2A_LTCTXB_COUNT]; - uint32_t ltc1[NV2A_LTC1_COUNT][4]; - bool ltc1_dirty[NV2A_LTC1_COUNT]; - - // should figure out where these are in lighting context - float light_infinite_half_vector[NV2A_MAX_LIGHTS][3]; - float light_infinite_direction[NV2A_MAX_LIGHTS][3]; - float light_local_position[NV2A_MAX_LIGHTS][3]; - float light_local_attenuation[NV2A_MAX_LIGHTS][3]; - - //VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES]; - - unsigned int inline_array_length; - uint32_t inline_array[NV2A_MAX_BATCH_LENGTH]; - GLuint gl_inline_array_buffer; - - unsigned int inline_elements_length; - uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH]; - - unsigned int inline_buffer_length; - - unsigned int draw_arrays_length; - unsigned int draw_arrays_max_count; - - /* FIXME: Unknown size, possibly endless, 1000 will do for now */ - GLint gl_draw_arrays_start[1000]; - GLsizei gl_draw_arrays_count[1000]; - - GLuint gl_element_buffer; - GLuint gl_memory_buffer; - GLuint gl_vertex_array; - - uint32_t regs[NV_PGRAPH_SIZE]; // TODO : union -} pgraph; - -static void update_irq() -{ - /* PFIFO */ - if (pfifo.pending_interrupts & pfifo.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO; - } - - /* PCRTC */ - if (pcrtc.pending_interrupts & pcrtc.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC; - } - - /* PGRAPH */ - if (pgraph.pending_interrupts & pgraph.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH; - } else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH; - } - - /* TODO : PBUS * / - if (pbus.pending_interrupts & pbus.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS; - } - else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS; - } */ - - /* TODO : SOFTWARE * / - if (user.pending_interrupts & user.enabled_interrupts) { - pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE; - } - else { - pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE; - } */ - - if (pmc.pending_interrupts && pmc.enabled_interrupts) { - HalSystemInterrupts[3].Assert(true); - } else { - HalSystemInterrupts[3].Assert(false); - } - - SwitchToThread(); -} - - -#define DEBUG_START(DEV) \ -const char *DebugNV_##DEV##(xbaddr addr) \ -{ \ - switch (addr) { -#define DEBUG_CASE(a) \ - case a: return #a; -#define DEBUG_CASE_EX(a, c) \ - case a: return #a##c; -#define DEBUG_END(DEV) \ - default: \ - return "Unknown " #DEV " Address"; \ - } \ -} - -DEBUG_START(PMC) - DEBUG_CASE(NV_PMC_BOOT_0); - DEBUG_CASE(NV_PMC_INTR_0); - DEBUG_CASE(NV_PMC_INTR_EN_0); - DEBUG_CASE(NV_PMC_ENABLE); -DEBUG_END(PMC) - -DEBUG_START(PBUS) - DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID"); - DEBUG_CASE(NV_PBUS_PCI_NV_1); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, ":LATENCY_TIMER"); - DEBUG_CASE(NV_PBUS_PCI_NV_4); - DEBUG_CASE(NV_PBUS_PCI_NV_5); - DEBUG_CASE(NV_PBUS_PCI_NV_6); - DEBUG_CASE(NV_PBUS_PCI_NV_7); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, ":SUBSYSTEM"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, ":ROM_BASE"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, ":CAP_PTR"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, ":RESERVED"); - DEBUG_CASE(NV_PBUS_PCI_NV_15); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, ":SUBSYSTEM"); - DEBUG_CASE(NV_PBUS_PCI_NV_17); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, ":AGP_STATUS"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, ":AGP_COMMAND"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, ":ROM_SHADOW"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, ":VGA"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, ":SCRATCH"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, ":DT_TIMEOUT"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, ":PME"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, ":POWER_STATE"); - DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, ":RESERVED"); -DEBUG_END(PBUS) - -DEBUG_START(PFIFO) - DEBUG_CASE(NV_PFIFO_INTR_0); - DEBUG_CASE(NV_PFIFO_INTR_EN_0); - DEBUG_CASE(NV_PFIFO_RAMHT); - DEBUG_CASE(NV_PFIFO_RAMFC); - DEBUG_CASE(NV_PFIFO_RAMRO); - DEBUG_CASE(NV_PFIFO_RUNOUT_STATUS); - DEBUG_CASE(NV_PFIFO_MODE); - DEBUG_CASE(NV_PFIFO_DMA); - DEBUG_CASE(NV_PFIFO_CACHE1_PUSH0); - DEBUG_CASE(NV_PFIFO_CACHE1_PUSH1); - DEBUG_CASE(NV_PFIFO_CACHE1_STATUS); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUSH); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_FETCH); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_STATE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_INSTANCE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUT); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_SUBROUTINE); - DEBUG_CASE(NV_PFIFO_CACHE1_PULL0); - DEBUG_CASE(NV_PFIFO_CACHE1_ENGINE); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DCOUNT); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_RSVD_SHADOW); - DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DATA_SHADOW); -DEBUG_END(PFIFO) - -DEBUG_START(PRMA) -DEBUG_END(PRMA) - -DEBUG_START(PVIDEO) - DEBUG_CASE(NV_PVIDEO_INTR); - DEBUG_CASE(NV_PVIDEO_INTR_EN); - DEBUG_CASE(NV_PVIDEO_BUFFER); - DEBUG_CASE(NV_PVIDEO_STOP); - DEBUG_CASE(NV_PVIDEO_BASE); - DEBUG_CASE(NV_PVIDEO_LIMIT); - DEBUG_CASE(NV_PVIDEO_LUMINANCE); - DEBUG_CASE(NV_PVIDEO_CHROMINANCE); - DEBUG_CASE(NV_PVIDEO_OFFSET); - DEBUG_CASE(NV_PVIDEO_SIZE_IN); - DEBUG_CASE(NV_PVIDEO_POINT_IN); - DEBUG_CASE(NV_PVIDEO_DS_DX); - DEBUG_CASE(NV_PVIDEO_DT_DY); - DEBUG_CASE(NV_PVIDEO_POINT_OUT); - DEBUG_CASE(NV_PVIDEO_SIZE_OUT); - DEBUG_CASE(NV_PVIDEO_FORMAT); -DEBUG_END(PVIDEO) - -DEBUG_START(PTIMER) - DEBUG_CASE(NV_PTIMER_INTR_0); - DEBUG_CASE(NV_PTIMER_INTR_EN_0); - DEBUG_CASE(NV_PTIMER_NUMERATOR); - DEBUG_CASE(NV_PTIMER_DENOMINATOR); - DEBUG_CASE(NV_PTIMER_TIME_0); - DEBUG_CASE(NV_PTIMER_TIME_1); - DEBUG_CASE(NV_PTIMER_ALARM_0); - -DEBUG_END(PTIMER) - -DEBUG_START(PCOUNTER) -DEBUG_END(PCOUNTER) - -DEBUG_START(PVPE) -DEBUG_END(PVPE) - -DEBUG_START(PTV) -DEBUG_END(PTV) - -DEBUG_START(PRMFB) -DEBUG_END(PRMFB) - -DEBUG_START(PRMVIO) -DEBUG_END(PRMVIO) - -DEBUG_START(PFB) - DEBUG_CASE(NV_PFB_CFG0) - DEBUG_CASE(NV_PFB_CSTATUS) - DEBUG_CASE(NV_PFB_REFCTRL) - DEBUG_CASE(NV_PFB_NVM) // NV_PFB_NVM_MODE_DISABLE - DEBUG_CASE(NV_PFB_PIN) - DEBUG_CASE(NV_PFB_PAD) - DEBUG_CASE(NV_PFB_TIMING0) - DEBUG_CASE(NV_PFB_TIMING1) - DEBUG_CASE(NV_PFB_TIMING2) - DEBUG_CASE(NV_PFB_TILE) - DEBUG_CASE(NV_PFB_TLIMIT) - DEBUG_CASE(NV_PFB_TSIZE) - DEBUG_CASE(NV_PFB_TSTATUS) - DEBUG_CASE(NV_PFB_MRS) - DEBUG_CASE(NV_PFB_EMRS) - DEBUG_CASE(NV_PFB_MRS_EXT) - DEBUG_CASE(NV_PFB_EMRS_EXT) - DEBUG_CASE(NV_PFB_REF) - DEBUG_CASE(NV_PFB_PRE) - DEBUG_CASE(NV_PFB_ZCOMP) - DEBUG_CASE(NV_PFB_ARB_PREDIVIDER) - DEBUG_CASE(NV_PFB_ARB_TIMEOUT) - DEBUG_CASE(NV_PFB_ARB_XFER_REM) - DEBUG_CASE(NV_PFB_ARB_DIFF_BANK) - DEBUG_CASE(NV_PFB_CLOSE_PAGE0) - DEBUG_CASE(NV_PFB_CLOSE_PAGE1) - DEBUG_CASE(NV_PFB_CLOSE_PAGE2) - DEBUG_CASE(NV_PFB_BPARB) - DEBUG_CASE(NV_PFB_CMDQ0) - DEBUG_CASE(NV_PFB_CMDQ1) - DEBUG_CASE(NV_PFB_ILL_INSTR) - DEBUG_CASE(NV_PFB_RT) - DEBUG_CASE(NV_PFB_AUTOCLOSE) - DEBUG_CASE(NV_PFB_WBC) - DEBUG_CASE(NV_PFB_CMDQ_PRT) - DEBUG_CASE(NV_PFB_CPU_RRQ) - DEBUG_CASE(NV_PFB_BYPASS); -DEBUG_END(PFB) - -DEBUG_START(PSTRAPS) -DEBUG_END(PSTRAPS) - -DEBUG_START(PGRAPH) - DEBUG_CASE(NV_PGRAPH_INTR); - DEBUG_CASE(NV_PGRAPH_NSOURCE); - DEBUG_CASE(NV_PGRAPH_INTR_EN); - DEBUG_CASE(NV_PGRAPH_CTX_CONTROL); - DEBUG_CASE(NV_PGRAPH_CTX_USER); - DEBUG_CASE(NV_PGRAPH_CTX_SWITCH1); - DEBUG_CASE(NV_PGRAPH_TRAPPED_ADDR); - DEBUG_CASE(NV_PGRAPH_TRAPPED_DATA_LOW); - DEBUG_CASE(NV_PGRAPH_SURFACE); - DEBUG_CASE(NV_PGRAPH_INCREMENT); - DEBUG_CASE(NV_PGRAPH_FIFO); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TABLE); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_POINTER); - DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TRIGGER); - DEBUG_CASE(NV_PGRAPH_CSV0_D); - DEBUG_CASE(NV_PGRAPH_CSV0_C); - DEBUG_CASE(NV_PGRAPH_CSV1_B); - DEBUG_CASE(NV_PGRAPH_CSV1_A); - DEBUG_CASE(NV_PGRAPH_CHEOPS_OFFSET); - DEBUG_CASE(NV_PGRAPH_BLEND); - DEBUG_CASE(NV_PGRAPH_BLENDCOLOR); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR0); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR1); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR2); - DEBUG_CASE(NV_PGRAPH_BORDERCOLOR3); - DEBUG_CASE(NV_PGRAPH_BUMPOFFSET1); - DEBUG_CASE(NV_PGRAPH_BUMPSCALE1); - DEBUG_CASE(NV_PGRAPH_CLEARRECTX); - DEBUG_CASE(NV_PGRAPH_CLEARRECTY); - DEBUG_CASE(NV_PGRAPH_COLORCLEARVALUE); - DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR0); - DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR1); - DEBUG_CASE(NV_PGRAPH_COMBINEALPHAI0); - DEBUG_CASE(NV_PGRAPH_COMBINEALPHAO0); - DEBUG_CASE(NV_PGRAPH_COMBINECOLORI0); - DEBUG_CASE(NV_PGRAPH_COMBINECOLORO0); - DEBUG_CASE(NV_PGRAPH_COMBINECTL); - DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG0); - DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG1); - DEBUG_CASE(NV_PGRAPH_CONTROL_0); - DEBUG_CASE(NV_PGRAPH_CONTROL_2); - DEBUG_CASE(NV_PGRAPH_CONTROL_3); - DEBUG_CASE(NV_PGRAPH_FOGCOLOR); - DEBUG_CASE(NV_PGRAPH_FOGPARAM0); - DEBUG_CASE(NV_PGRAPH_FOGPARAM1); - DEBUG_CASE(NV_PGRAPH_SETUPRASTER); - DEBUG_CASE(NV_PGRAPH_SHADERCLIPMODE); - DEBUG_CASE(NV_PGRAPH_SHADERCTL); - DEBUG_CASE(NV_PGRAPH_SHADERPROG); - DEBUG_CASE(NV_PGRAPH_SHADOWZSLOPETHRESHOLD); - DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR0); - DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR1); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0_ADDRV); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS1); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS2); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS3); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_1); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_2); - DEBUG_CASE(NV_PGRAPH_TEXCTL0_3); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_1); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_2); - DEBUG_CASE(NV_PGRAPH_TEXCTL1_3); - DEBUG_CASE(NV_PGRAPH_TEXCTL2_0); - DEBUG_CASE(NV_PGRAPH_TEXCTL2_1); - DEBUG_CASE(NV_PGRAPH_TEXFILTER0); - DEBUG_CASE(NV_PGRAPH_TEXFILTER1); - DEBUG_CASE(NV_PGRAPH_TEXFILTER2); - DEBUG_CASE(NV_PGRAPH_TEXFILTER3); - DEBUG_CASE(NV_PGRAPH_TEXFMT0); - DEBUG_CASE(NV_PGRAPH_TEXFMT1); - DEBUG_CASE(NV_PGRAPH_TEXFMT2); - DEBUG_CASE(NV_PGRAPH_TEXFMT3); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT0); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT1); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT2); - DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT3); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET0); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET1); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET2); - DEBUG_CASE(NV_PGRAPH_TEXOFFSET3); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE0); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE1); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE2); - DEBUG_CASE(NV_PGRAPH_TEXPALETTE3); - DEBUG_CASE(NV_PGRAPH_ZSTENCILCLEARVALUE); - DEBUG_CASE(NV_PGRAPH_ZCLIPMIN); - DEBUG_CASE(NV_PGRAPH_ZOFFSETBIAS); - DEBUG_CASE(NV_PGRAPH_ZOFFSETFACTOR); - DEBUG_CASE(NV_PGRAPH_EYEVEC0); - DEBUG_CASE(NV_PGRAPH_EYEVEC1); - DEBUG_CASE(NV_PGRAPH_EYEVEC2); - DEBUG_CASE(NV_PGRAPH_ZCLIPMAX); -DEBUG_END(PGRAPH) - -DEBUG_START(PCRTC) - DEBUG_CASE(NV_PCRTC_INTR_0); - DEBUG_CASE(NV_PCRTC_INTR_EN_0); - DEBUG_CASE(NV_PCRTC_START); - DEBUG_CASE(NV_PCRTC_CONFIG); - -DEBUG_END(PCRTC) - -DEBUG_START(PRMCIO) - DEBUG_CASE(VGA_CRT_DC); - DEBUG_CASE(VGA_CRT_DM); - DEBUG_CASE(VGA_ATT_R); - DEBUG_CASE(VGA_ATT_W); - DEBUG_CASE(VGA_GFX_D); - DEBUG_CASE(VGA_SEQ_D); - DEBUG_CASE(VGA_MIS_R); - DEBUG_CASE(VGA_MIS_W); - DEBUG_CASE(VGA_FTC_R); - DEBUG_CASE(VGA_IS1_RC); - DEBUG_CASE(VGA_IS1_RM); - DEBUG_CASE(VGA_PEL_D); - DEBUG_CASE(VGA_PEL_MSK); - DEBUG_CASE(VGA_CRT_IC); - DEBUG_CASE(VGA_CRT_IM); - DEBUG_CASE(VGA_GFX_I); - DEBUG_CASE(VGA_SEQ_I); - DEBUG_CASE(VGA_PEL_IW); - DEBUG_CASE(VGA_PEL_IR); -DEBUG_END(PRMCIO) - -DEBUG_START(PRAMDAC) - DEBUG_CASE(NV_PRAMDAC_NVPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_MPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_VPLL_COEFF); - DEBUG_CASE(NV_PRAMDAC_PLL_TEST_COUNTER); - -DEBUG_END(PRAMDAC) - -DEBUG_START(PRMDIO) -DEBUG_END(PRMDIO) - -DEBUG_START(PRAMIN) -DEBUG_END(PRAMIN) - -DEBUG_START(USER) - - DEBUG_CASE(NV_USER_DMA_PUT); - DEBUG_CASE(NV_USER_DMA_GET); - DEBUG_CASE(NV_USER_REF); - - DEBUG_END(USER) - - - - -#define DEBUG_READ32(DEV) DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr)) -#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } - -#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr)) -#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; } - -#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr) -#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr) -#define DEVICE_READ32_REG(dev) result = dev.regs[addr] -#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result - -#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(xbaddr addr, uint32_t value) -#define DEVICE_WRITE32_REG(dev) dev.regs[addr] = value -#define DEVICE_WRITE32_END(DEV) DEBUG_WRITE32(DEV) - -static inline uint32_t ldl_le_p(const void *p) -{ - return *(uint32_t*)p; -} - -static DMAObject nv_dma_load(xbaddr dma_obj_address) -{ - assert(dma_obj_address < NV_PRAMIN_SIZE); - - uint32_t *dma_obj = (uint32_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + dma_obj_address); - uint32_t flags = ldl_le_p(dma_obj); - uint32_t limit = ldl_le_p(dma_obj + 1); - uint32_t frame = ldl_le_p(dma_obj + 2); - - DMAObject object; - object.dma_class = GET_MASK(flags, NV_DMA_CLASS); - object.dma_target = GET_MASK(flags, NV_DMA_TARGET); - object.address = (frame & NV_DMA_ADDRESS) | GET_MASK(flags, NV_DMA_ADJUST); - object.limit = limit; - - return object; -} - -static void *nv_dma_map(xbaddr dma_obj_address, xbaddr *len) -{ - assert(dma_obj_address < NV_PRAMIN_SIZE); - - DMAObject dma = nv_dma_load(dma_obj_address); - - /* TODO: Handle targets and classes properly */ - printf("dma_map %x, %x, %x %x" "\n", - dma.dma_class, dma.dma_target, dma.address, dma.limit); - - dma.address &= 0x07FFFFFF; - - // assert(dma.address + dma.limit < memory_region_size(d->vram)); - *len = dma.limit; - return (void*)(MM_SYSTEM_PHYSICAL_MAP + dma.address); -} - -/* pusher should be fine to run from a mimo handler -* whenever's it's convenient */ -static void pfifo_run_pusher() { - uint8_t channel_id; - ChannelControl *control; - Cache1State *state; - CacheEntry *command; - uint8_t *dma; - xbaddr dma_len; - uint32_t word; - - /* TODO: How is cache1 selected? */ - state = &pfifo.cache1; - channel_id = state->channel_id; - control = &user.channel_control[channel_id]; - - if (!state->push_enabled) return; - - /* only handling DMA for now... */ - - /* Channel running DMA */ - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - assert(channel_modes & (1 << channel_id)); - assert(state->mode == FIFO_DMA); - - if (!state->dma_push_enabled) return; - if (state->dma_push_suspended) return; - - /* We're running so there should be no pending errors... */ - assert(state->error == NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE); - - dma = (uint8_t*)nv_dma_map(state->dma_instance, &dma_len); - - printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n", - dma_len, control->dma_get, control->dma_put); - - /* based on the convenient pseudocode in envytools */ - while (control->dma_get != control->dma_put) { - if (control->dma_get >= dma_len) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION; - break; - } - - word = ldl_le_p((uint32_t*)(dma + control->dma_get)); - control->dma_get += 4; - - if (state->method_count) { - /* data word of methods command */ - state->data_shadow = word; - - CacheEntry* command = (CacheEntry*)calloc(1, sizeof(CacheEntry)); - command->method = state->method; - command->subchannel = state->subchannel; - command->nonincreasing = state->method_nonincreasing; - command->parameter = word; - - std::lock_guard lk(state->mutex); - state->cache.push(command); - state->cache_cond.notify_all(); - - if (!state->method_nonincreasing) { - state->method += 4; - } - - state->method_count--; - state->dcount++; - } else { - /* no command active - this is the first word of a new one */ - state->rsvd_shadow = word; - /* match all forms */ - if ((word & 0xe0000003) == 0x20000000) { - /* old jump */ - state->get_jmp_shadow = control->dma_get; - control->dma_get = word & 0x1fffffff; - printf("pb OLD_JMP 0x%08X\n", control->dma_get); - } - else if ((word & 3) == 1) { - /* jump */ - state->get_jmp_shadow = control->dma_get; - control->dma_get = word & 0xfffffffc; - printf("pb JMP 0x%08X\n", control->dma_get); - } - else if ((word & 3) == 2) { - /* call */ - if (state->subroutine_active) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL; - break; - } - state->subroutine_return = control->dma_get; - state->subroutine_active = true; - control->dma_get = word & 0xfffffffc; - printf("pb CALL 0x%08X\n", control->dma_get); - } - else if (word == 0x00020000) { - /* return */ - if (!state->subroutine_active) { - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN; - break; - } - control->dma_get = state->subroutine_return; - state->subroutine_active = false; - printf("pb RET 0x%08X\n", control->dma_get); - } - else if ((word & 0xe0030003) == 0) { - /* increasing methods */ - state->method = word & 0x1fff; - state->subchannel = (word >> 13) & 7; - state->method_count = (word >> 18) & 0x7ff; - state->method_nonincreasing = false; - state->dcount = 0; - } - else if ((word & 0xe0030003) == 0x40000000) { - /* non-increasing methods */ - state->method = word & 0x1fff; - state->subchannel = (word >> 13) & 7; - state->method_count = (word >> 18) & 0x7ff; - state->method_nonincreasing = true; - state->dcount = 0; - } - else { - printf("pb reserved cmd 0x%08X - 0x%08X\n", - control->dma_get, word); - state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD; - break; - } - } - } - - printf("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n", - dma_len, control->dma_get, control->dma_put); - - if (state->error) { - printf("pb error: %d\n", state->error); - assert(false); - - state->dma_push_suspended = true; - - pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER; - update_irq(); - } -} - -static uint32_t ramht_hash(uint32_t handle) -{ - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); - - /* XXX: Think this is different to what nouveau calculates... */ - unsigned int bits = ffs(ramht_size) - 2; - - uint32_t hash = 0; - while (handle) { - hash ^= (handle & ((1 << bits) - 1)); - handle >>= bits; - } - hash ^= pfifo.cache1.channel_id << (bits - 4); - - return hash; -} - - -static RAMHTEntry ramht_lookup(uint32_t handle) -{ - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); - - uint32_t hash = ramht_hash(handle); - assert(hash * 8 < ramht_size); - - uint32_t ramht_address = - GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], - NV_PFIFO_RAMHT_BASE_ADDRESS) << 12; - - uint8_t *entry_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + ramht_address + hash * 8); - - uint32_t entry_handle = ldl_le_p((uint32_t*)entry_ptr); - uint32_t entry_context = ldl_le_p((uint32_t*)(entry_ptr + 4)); - - RAMHTEntry entry; - entry.handle = entry_handle; - entry.instance = (entry_context & NV_RAMHT_INSTANCE) << 4; - entry.engine = (FIFOEngine)((entry_context & NV_RAMHT_ENGINE) >> 16); - entry.channel_id = (entry_context & NV_RAMHT_CHID) >> 24; - entry.valid = entry_context & NV_RAMHT_STATUS; - - return entry; -} - -static void pgraph_context_switch(unsigned int channel_id) -{ - bool valid = false; - - // Scope the lock so that it gets unlocked at end of this block - { - std::lock_guard lk(pgraph.mutex); - - valid = pgraph.channel_valid && pgraph.channel_id == channel_id; - if (!valid) { - pgraph.trapped_channel_id = channel_id; - } - } - - if (!valid) { - printf("puller needs to switch to ch %d\n", channel_id); - - //qemu_mutex_lock_iothread(); - pgraph.pending_interrupts |= NV_PGRAPH_INTR_CONTEXT_SWITCH; - update_irq(); - - std::unique_lock lk(pgraph.mutex); - //qemu_mutex_unlock_iothread(); - - while (pgraph.pending_interrupts & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - pgraph.interrupt_cond.wait(lk); - } - } -} - -static void pgraph_wait_fifo_access() { - std::unique_lock lk(pgraph.mutex); - - while (!pgraph.fifo_access) { - pgraph.fifo_access_cond.wait(lk); - } -} - -static void pgraph_method_log(unsigned int subchannel, unsigned int graphics_class, unsigned int method, uint32_t parameter) { - static unsigned int last = 0; - static unsigned int count = 0; - - if (last == 0x1800 && method != last) { - printf("pgraph method (%d) 0x%08X * %d", subchannel, last, count); - } - if (method != 0x1800) { - const char* method_name = NULL; - unsigned int nmethod = 0; - switch (graphics_class) { - case NV_KELVIN_PRIMITIVE: - nmethod = method | (0x5c << 16); - break; - case NV_CONTEXT_SURFACES_2D: - nmethod = method | (0x6d << 16); - break; - default: - break; - } - /* - if (nmethod != 0 && nmethod < ARRAY_SIZE(nv2a_method_names)) { - method_name = nv2a_method_names[nmethod]; - } - if (method_name) { - printf("pgraph method (%d): %s (0x%x)\n", - subchannel, method_name, parameter); - } - else { - */ - printf("pgraph method (%d): 0x%x -> 0x%04x (0x%x)\n", - subchannel, graphics_class, method, parameter); - //} - - } - if (method == last) { count++; } - else { count = 0; } - last = method; -} - -static void load_graphics_object(xbaddr instance_address, GraphicsObject *obj) -{ - uint8_t *obj_ptr; - uint32_t switch1, switch2, switch3; - - assert(instance_address < NV_PRAMIN_SIZE); - obj_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + instance_address); - - switch1 = ldl_le_p((uint32_t*)obj_ptr); - switch2 = ldl_le_p((uint32_t*)(obj_ptr + 4)); - switch3 = ldl_le_p((uint32_t*)(obj_ptr + 8)); - - obj->graphics_class = switch1 & NV_PGRAPH_CTX_SWITCH1_GRCLASS; - - /* init graphics object */ - switch (obj->graphics_class) { - case NV_KELVIN_PRIMITIVE: - // kelvin->vertex_attributes[NV2A_VERTEX_ATTR_DIFFUSE].inline_value = 0xFFFFFFF; - break; - default: - break; - } -} - -static GraphicsObject* lookup_graphics_object(xbaddr instance_address) -{ - int i; - for (i = 0; i lk(pgraph.mutex); - - int i; - GraphicsSubchannel *subchannel_data; - GraphicsObject *object; - - unsigned int slot; - - assert(pgraph.channel_valid); - subchannel_data = &pgraph.subchannel_data[subchannel]; - object = &subchannel_data->object; - - ContextSurfaces2DState *context_surfaces_2d = &object->data.context_surfaces_2d; - ImageBlitState *image_blit = &object->data.image_blit; - KelvinState *kelvin = &object->data.kelvin; - - pgraph_method_log(subchannel, object->graphics_class, method, parameter); - - if (method == NV_SET_OBJECT) { - subchannel_data->object_instance = parameter; - - //qemu_mutex_lock_iothread(); - load_graphics_object(parameter, object); - //qemu_mutex_unlock_iothread(); - return; - } - - switch (object->graphics_class) { - case NV_CONTEXT_SURFACES_2D: { - switch (method) { - case NV062_SET_CONTEXT_DMA_IMAGE_SOURCE: - context_surfaces_2d->dma_image_source = parameter; - break; - case NV062_SET_CONTEXT_DMA_IMAGE_DESTIN: - context_surfaces_2d->dma_image_dest = parameter; - break; - case NV062_SET_COLOR_FORMAT: - context_surfaces_2d->color_format = parameter; - break; - case NV062_SET_PITCH: - context_surfaces_2d->source_pitch = parameter & 0xFFFF; - context_surfaces_2d->dest_pitch = parameter >> 16; - break; - case NV062_SET_OFFSET_SOURCE: - context_surfaces_2d->source_offset = parameter & 0x07FFFFFF; - break; - case NV062_SET_OFFSET_DESTIN: - context_surfaces_2d->dest_offset = parameter & 0x07FFFFFF; - break; - default: - EmuWarning("EmuNV2A: Unknown NV_CONTEXT_SURFACES_2D Method: 0x%08X\n", method); - } - - break; - } - - case NV_IMAGE_BLIT: { - switch (method) { - case NV09F_SET_CONTEXT_SURFACES: - image_blit->context_surfaces = parameter; - break; - case NV09F_SET_OPERATION: - image_blit->operation = parameter; - break; - case NV09F_CONTROL_POINT_IN: - image_blit->in_x = parameter & 0xFFFF; - image_blit->in_y = parameter >> 16; - break; - case NV09F_CONTROL_POINT_OUT: - image_blit->out_x = parameter & 0xFFFF; - image_blit->out_y = parameter >> 16; - break; - case NV09F_SIZE: - image_blit->width = parameter & 0xFFFF; - image_blit->height = parameter >> 16; - - /* I guess this kicks it off? */ - if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) { - - printf("NV09F_SET_OPERATION_SRCCOPY"); - - GraphicsObject *context_surfaces_obj = lookup_graphics_object(image_blit->context_surfaces); - assert(context_surfaces_obj); - assert(context_surfaces_obj->graphics_class == NV_CONTEXT_SURFACES_2D); - - ContextSurfaces2DState *context_surfaces = &context_surfaces_obj->data.context_surfaces_2d; - - unsigned int bytes_per_pixel; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_Y8: - bytes_per_pixel = 1; - break; - case NV062_SET_COLOR_FORMAT_LE_R5G6B5: - bytes_per_pixel = 2; - break; - case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: - bytes_per_pixel = 4; - break; - default: - printf("Unknown blit surface format: 0x%x\n", context_surfaces->color_format); - assert(false); - break; - } - - xbaddr source_dma_len, dest_dma_len; - uint8_t *source, *dest; - - source = (uint8_t*)nv_dma_map(context_surfaces->dma_image_source, &source_dma_len); - assert(context_surfaces->source_offset < source_dma_len); - source += context_surfaces->source_offset; - - dest = (uint8_t*)nv_dma_map(context_surfaces->dma_image_dest, &dest_dma_len); - assert(context_surfaces->dest_offset < dest_dma_len); - dest += context_surfaces->dest_offset; - - printf(" - 0x%tx -> 0x%tx\n", source - MM_SYSTEM_PHYSICAL_MAP,dest - MM_SYSTEM_PHYSICAL_MAP); - - int y; - for (y = 0; yheight; y++) { - uint8_t *source_row = source - + (image_blit->in_y + y) * context_surfaces->source_pitch - + image_blit->in_x * bytes_per_pixel; - - uint8_t *dest_row = dest - + (image_blit->out_y + y) * context_surfaces->dest_pitch - + image_blit->out_x * bytes_per_pixel; - - memmove(dest_row, source_row, - image_blit->width * bytes_per_pixel); - } - } - else { - assert(false); - } - - break; - default: - EmuWarning("EmuNV2A: Unknown NV_IMAGE_BLIT Method: 0x%08X\n", method); - } - break; - } - - case NV_KELVIN_PRIMITIVE: { - switch (method) { - case NV097_SET_CONTEXT_DMA_NOTIFIES: - kelvin->dma_notifies = parameter; - break; - case NV097_SET_CONTEXT_DMA_A: - pgraph.dma_a = parameter; - break; - case NV097_SET_CONTEXT_DMA_B: - pgraph.dma_b = parameter; - break; - case NV097_SET_CONTEXT_DMA_STATE: - kelvin->dma_state = parameter; - break; - case NV097_SET_CONTEXT_DMA_COLOR: - printf("TODO: pgraph_update_surface\n"); - /* try to get any straggling draws in before the surface's changed :/ */ - //pgraph_update_surface(d, false, true, true); - - pgraph.dma_color = parameter; - break; - case NV097_SET_CONTEXT_DMA_ZETA: - pgraph.dma_zeta = parameter; - break; - case NV097_SET_CONTEXT_DMA_VERTEX_A: - pgraph.dma_vertex_a = parameter; - break; - case NV097_SET_CONTEXT_DMA_VERTEX_B: - pgraph.dma_vertex_b = parameter; - break; - case NV097_SET_CONTEXT_DMA_SEMAPHORE: - kelvin->dma_semaphore = parameter; - break; - case NV097_SET_CONTEXT_DMA_REPORT: - pgraph.dma_report = parameter; - break; - case NV097_SET_SURFACE_CLIP_HORIZONTAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.clip_x = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_X); - pgraph.surface_shape.clip_width = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_WIDTH); - break; - case NV097_SET_SURFACE_CLIP_VERTICAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.clip_y = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_Y); - pgraph.surface_shape.clip_height = - GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_HEIGHT); - break; - case NV097_SET_SURFACE_FORMAT: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_shape.color_format = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_COLOR); - pgraph.surface_shape.zeta_format = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ZETA); - pgraph.surface_type = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_TYPE); - pgraph.surface_shape.anti_aliasing = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ANTI_ALIASING); - pgraph.surface_shape.log_width = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_WIDTH); - pgraph.surface_shape.log_height = - GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_HEIGHT); - break; - case NV097_SET_SURFACE_PITCH: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_color.pitch = - GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR); - pgraph.surface_zeta.pitch = - GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA); - break; - case NV097_SET_SURFACE_COLOR_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_color.offset = parameter; - break; - case NV097_SET_SURFACE_ZETA_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - pgraph.surface_zeta.offset = parameter; - break; - case NV097_SET_COMBINER_SPECULAR_FOG_CW0: - pgraph.regs[NV_PGRAPH_COMBINESPECFOG0] = parameter; - break; - case NV097_SET_COMBINER_SPECULAR_FOG_CW1: - pgraph.regs[NV_PGRAPH_COMBINESPECFOG1] = parameter; - break; - CASE_4(NV097_SET_TEXTURE_ADDRESS, 64): - slot = (method - NV097_SET_TEXTURE_ADDRESS) / 64; - pgraph.regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; - break; - case NV097_SET_CONTROL0: { - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); - - bool stencil_write_enable = - parameter & NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE, - stencil_write_enable); - - uint32_t z_format = GET_MASK(parameter, NV097_SET_CONTROL0_Z_FORMAT); - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_Z_FORMAT, z_format); - - bool z_perspective = - parameter & NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE, - z_perspective); - break; - } - - case NV097_SET_FOG_MODE: { - /* FIXME: There is also NV_PGRAPH_CSV0_D_FOG_MODE */ - unsigned int mode; - switch (parameter) { - case NV097_SET_FOG_MODE_V_LINEAR: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR; break; - case NV097_SET_FOG_MODE_V_EXP: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP; break; - case NV097_SET_FOG_MODE_V_EXP2: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2; break; - case NV097_SET_FOG_MODE_V_EXP_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP_ABS; break; - case NV097_SET_FOG_MODE_V_EXP2_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2_ABS; break; - case NV097_SET_FOG_MODE_V_LINEAR_ABS: - mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR_ABS; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOG_MODE, - mode); - break; - } - case NV097_SET_FOG_GEN_MODE: { - unsigned int mode; - switch (parameter) { - case NV097_SET_FOG_GEN_MODE_V_SPEC_ALPHA: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_SPEC_ALPHA; break; - case NV097_SET_FOG_GEN_MODE_V_RADIAL: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_RADIAL; break; - case NV097_SET_FOG_GEN_MODE_V_PLANAR: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_PLANAR; break; - case NV097_SET_FOG_GEN_MODE_V_ABS_PLANAR: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_ABS_PLANAR; break; - case NV097_SET_FOG_GEN_MODE_V_FOG_X: - mode = NV_PGRAPH_CSV0_D_FOGGENMODE_FOG_X; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGGENMODE, mode); - break; - } - case NV097_SET_FOG_ENABLE: - /* - FIXME: There is also: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGENABLE, - parameter); - */ - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOGENABLE, - parameter); - break; - case NV097_SET_FOG_COLOR: { - /* PGRAPH channels are ARGB, parameter channels are ABGR */ - uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED); - uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN); - uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE); - uint8_t alpha = GET_MASK(parameter, NV097_SET_FOG_COLOR_ALPHA); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_RED, red); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_GREEN, green); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_BLUE, blue); - SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha); - break; - } - case NV097_SET_ALPHA_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, parameter); - break; - case NV097_SET_BLEND_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EN, parameter); - break; - case NV097_SET_CULL_FACE_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_CULLENABLE, - parameter); - break; - case NV097_SET_DEPTH_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZENABLE, - parameter); - break; - case NV097_SET_DITHER_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_DITHERENABLE, parameter); - break; - case NV097_SET_LIGHTING_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], NV_PGRAPH_CSV0_C_LIGHTING, - parameter); - break; - case NV097_SET_SKIN_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_SKIN, - parameter); - break; - case NV097_SET_STENCIL_TEST_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_POINT_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_LINE_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE, parameter); - break; - case NV097_SET_POLY_OFFSET_FILL_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE, parameter); - break; - case NV097_SET_ALPHA_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHAFUNC, parameter & 0xF); - break; - case NV097_SET_ALPHA_REF: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHAREF, parameter); - break; - case NV097_SET_BLEND_FUNC_SFACTOR: { - unsigned int factor; - switch (parameter) { - case NV097_SET_BLEND_FUNC_SFACTOR_V_ZERO: - factor = NV_PGRAPH_BLEND_SFACTOR_ZERO; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA_SATURATE: - factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA_SATURATE; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_ALPHA; break; - case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; - default: - fprintf(stderr, "Unknown blend source factor: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_SFACTOR, factor); - - break; - } - - case NV097_SET_BLEND_FUNC_DFACTOR: { - unsigned int factor; - switch (parameter) { - case NV097_SET_BLEND_FUNC_DFACTOR_V_ZERO: - factor = NV_PGRAPH_BLEND_DFACTOR_ZERO; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA_SATURATE: - factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA_SATURATE; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_COLOR: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_COLOR; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_ALPHA; break; - case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: - factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; - default: - fprintf(stderr, "Unknown blend destination factor: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_DFACTOR, factor); - - break; - } - - case NV097_SET_BLEND_COLOR: - pgraph.regs[NV_PGRAPH_BLENDCOLOR] = parameter; - break; - - case NV097_SET_BLEND_EQUATION: { - unsigned int equation; - switch (parameter) { - case NV097_SET_BLEND_EQUATION_V_FUNC_SUBTRACT: - equation = 0; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT: - equation = 1; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_ADD: - equation = 2; break; - case NV097_SET_BLEND_EQUATION_V_MIN: - equation = 3; break; - case NV097_SET_BLEND_EQUATION_V_MAX: - equation = 4; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT_SIGNED: - equation = 5; break; - case NV097_SET_BLEND_EQUATION_V_FUNC_ADD_SIGNED: - equation = 6; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EQN, equation); - - break; - } - - case NV097_SET_DEPTH_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZFUNC, - parameter & 0xF); - break; - - case NV097_SET_COLOR_MASK: { - pgraph.surface_color.write_enabled_cache |= pgraph_color_write_enabled(); - - bool alpha = parameter & NV097_SET_COLOR_MASK_ALPHA_WRITE_ENABLE; - bool red = parameter & NV097_SET_COLOR_MASK_RED_WRITE_ENABLE; - bool green = parameter & NV097_SET_COLOR_MASK_GREEN_WRITE_ENABLE; - bool blue = parameter & NV097_SET_COLOR_MASK_BLUE_WRITE_ENABLE; - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE, alpha); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE, red); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE, green); - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE, blue); - break; - } - case NV097_SET_DEPTH_MASK: - pgraph.surface_zeta.write_enabled_cache |= pgraph_zeta_write_enabled(); - - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], - NV_PGRAPH_CONTROL_0_ZWRITEENABLE, parameter); - break; - case NV097_SET_STENCIL_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_MASK_WRITE, parameter); - break; - case NV097_SET_STENCIL_FUNC: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_FUNC, parameter & 0xF); - break; - case NV097_SET_STENCIL_FUNC_REF: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_REF, parameter); - break; - case NV097_SET_STENCIL_FUNC_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], - NV_PGRAPH_CONTROL_1_STENCIL_MASK_READ, parameter); - break; - case NV097_SET_STENCIL_OP_FAIL: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_FAIL, - kelvin_map_stencil_op(parameter)); - break; - case NV097_SET_STENCIL_OP_ZFAIL: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_ZFAIL, - kelvin_map_stencil_op(parameter)); - break; - case NV097_SET_STENCIL_OP_ZPASS: - SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], - NV_PGRAPH_CONTROL_2_STENCIL_OP_ZPASS, - kelvin_map_stencil_op(parameter)); - break; - - case NV097_SET_POLYGON_OFFSET_SCALE_FACTOR: - pgraph.regs[NV_PGRAPH_ZOFFSETFACTOR] = parameter; - break; - case NV097_SET_POLYGON_OFFSET_BIAS: - pgraph.regs[NV_PGRAPH_ZOFFSETBIAS] = parameter; - break; - case NV097_SET_FRONT_POLYGON_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_FRONTFACEMODE, - kelvin_map_polygon_mode(parameter)); - break; - case NV097_SET_BACK_POLYGON_MODE: - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_BACKFACEMODE, - kelvin_map_polygon_mode(parameter)); - break; - case NV097_SET_CLIP_MIN: - pgraph.regs[NV_PGRAPH_ZCLIPMIN] = parameter; - break; - case NV097_SET_CLIP_MAX: - pgraph.regs[NV_PGRAPH_ZCLIPMAX] = parameter; - break; - case NV097_SET_CULL_FACE: { - unsigned int face; - switch (parameter) { - case NV097_SET_CULL_FACE_V_FRONT: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT; break; - case NV097_SET_CULL_FACE_V_BACK: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_BACK; break; - case NV097_SET_CULL_FACE_V_FRONT_AND_BACK: - face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT_AND_BACK; break; - default: - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_CULLCTRL, - face); - break; - } - case NV097_SET_FRONT_FACE: { - bool ccw; - switch (parameter) { - case NV097_SET_FRONT_FACE_V_CW: - ccw = false; break; - case NV097_SET_FRONT_FACE_V_CCW: - ccw = true; break; - default: - fprintf(stderr, "Unknown front face: 0x%x\n", parameter); - assert(false); - break; - } - SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], - NV_PGRAPH_SETUPRASTER_FRONTFACE, - ccw ? 1 : 0); - break; - } - case NV097_SET_NORMALIZATION_ENABLE: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], - NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, - parameter); - break; - - case NV097_SET_LIGHT_ENABLE_MASK: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], - NV_PGRAPH_CSV0_D_LIGHTS, - parameter); - break; - - CASE_4(NV097_SET_TEXGEN_S, 16) : { - slot = (method - NV097_SET_TEXGEN_S) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_S - : NV_PGRAPH_CSV1_A_T0_S; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 0)); - break; - } - CASE_4(NV097_SET_TEXGEN_T, 16) : { - slot = (method - NV097_SET_TEXGEN_T) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_T - : NV_PGRAPH_CSV1_A_T0_T; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 1)); - break; - } - CASE_4(NV097_SET_TEXGEN_R, 16) : { - slot = (method - NV097_SET_TEXGEN_R) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_R - : NV_PGRAPH_CSV1_A_T0_R; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 2)); - break; - } - CASE_4(NV097_SET_TEXGEN_Q, 16) : { - slot = (method - NV097_SET_TEXGEN_Q) / 16; - unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A - : NV_PGRAPH_CSV1_B; - unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_Q - : NV_PGRAPH_CSV1_A_T0_Q; - SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 3)); - break; - } - CASE_4(NV097_SET_TEXTURE_MATRIX_ENABLE, 4) : - slot = (method - NV097_SET_TEXTURE_MATRIX_ENABLE) / 4; - pgraph.texture_matrix_enable[slot] = parameter; - break; - - case NV097_SET_TEXGEN_VIEW_MODEL: - SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); - break; - default: - if (method >= NV097_SET_COMBINER_ALPHA_ICW && method <= NV097_SET_COMBINER_ALPHA_ICW + 28) { - slot = (method - NV097_SET_COMBINER_ALPHA_ICW) / 4; - pgraph.regs[NV_PGRAPH_COMBINEALPHAI0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_PROJECTION_MATRIX && method <= NV097_SET_PROJECTION_MATRIX + 0x3c) { - slot = (method - NV097_SET_PROJECTION_MATRIX) / 4; - // pg->projection_matrix[slot] = *(float*)¶meter; - unsigned int row = NV_IGRAPH_XF_XFCTX_PMAT0 + slot / 4; - pgraph.vsh_constants[row][slot % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_MODEL_VIEW_MATRIX && method <= NV097_SET_MODEL_VIEW_MATRIX + 0xfc) { - slot = (method - NV097_SET_MODEL_VIEW_MATRIX) / 4; - unsigned int matnum = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_MMAT0 + matnum * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_INVERSE_MODEL_VIEW_MATRIX && method <= NV097_SET_INVERSE_MODEL_VIEW_MATRIX + 0xfc) { - slot = (method - NV097_SET_INVERSE_MODEL_VIEW_MATRIX) / 4; - unsigned int matnum = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_IMMAT0 + matnum * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_COMPOSITE_MATRIX && method <= NV097_SET_COMPOSITE_MATRIX + 0x3c) { - slot = (method - NV097_SET_COMPOSITE_MATRIX) / 4; - unsigned int row = NV_IGRAPH_XF_XFCTX_CMAT0 + slot / 4; - pgraph.vsh_constants[row][slot % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_TEXTURE_MATRIX && method <= NV097_SET_TEXTURE_MATRIX + 0xfc) { - slot = (method - NV097_SET_TEXTURE_MATRIX) / 4; - unsigned int tex = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_T0MAT + tex * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_FOG_PARAMS && method <= NV097_SET_FOG_PARAMS + 8) { - slot = (method - NV097_SET_FOG_PARAMS) / 4; - if (slot < 2) { - pgraph.regs[NV_PGRAPH_FOGPARAM0 + slot * 4] = parameter; - } - else { - /* FIXME: No idea where slot = 2 is */ - } - - pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FOG_K][slot] = parameter; - pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FOG_K] = true; - break; - } - - /* Handles NV097_SET_TEXGEN_PLANE_S,T,R,Q */ - if (method >= NV097_SET_TEXGEN_PLANE_S && method <= NV097_SET_TEXGEN_PLANE_S + 0xfc) { - slot = (method - NV097_SET_TEXGEN_PLANE_S) / 4; - unsigned int tex = slot / 16; - unsigned int entry = slot % 16; - unsigned int row = NV_IGRAPH_XF_XFCTX_TG0MAT + tex * 8 + entry / 4; - pgraph.vsh_constants[row][entry % 4] = parameter; - pgraph.vsh_constants_dirty[row] = true; - break; - } - - if (method >= NV097_SET_FOG_PLANE && method <= NV097_SET_FOG_PLANE + 12) { - slot = (method - NV097_SET_FOG_PLANE) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_FOG][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true; - break; - } - - if (method >= NV097_SET_SCENE_AMBIENT_COLOR && method <= NV097_SET_SCENE_AMBIENT_COLOR + 8) { - slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4; - // ?? - pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FR_AMB][slot] = parameter; - pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FR_AMB] = true; - break; - } - - if (method >= NV097_SET_VIEWPORT_OFFSET && method <= NV097_SET_VIEWPORT_OFFSET + 12) { - slot = (method - NV097_SET_VIEWPORT_OFFSET) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPOFF] = true; - break; - } - - if (method >= NV097_SET_EYE_POSITION && method <= NV097_SET_EYE_POSITION + 12) { - slot = (method - NV097_SET_EYE_POSITION) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_EYEP][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_EYEP] = true; - break; - } - - if (method >= NV097_SET_COMBINER_FACTOR0 && method <= NV097_SET_COMBINER_FACTOR0 + 28) { - slot = (method - NV097_SET_COMBINER_FACTOR0) / 4; - pgraph.regs[NV_PGRAPH_COMBINEFACTOR0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_FACTOR1 && method <= NV097_SET_COMBINER_FACTOR1 + 28) { - slot = (method - NV097_SET_COMBINER_FACTOR1) / 4; - pgraph.regs[NV_PGRAPH_COMBINEFACTOR1 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_ALPHA_OCW && method <= NV097_SET_COMBINER_ALPHA_OCW + 28) { - slot = (method - NV097_SET_COMBINER_ALPHA_OCW) / 4; - pgraph.regs[NV_PGRAPH_COMBINEALPHAO0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_COMBINER_COLOR_ICW && method <= NV097_SET_COMBINER_COLOR_ICW + 28) { - slot = (method - NV097_SET_COMBINER_COLOR_ICW) / 4; - pgraph.regs[NV_PGRAPH_COMBINECOLORI0 + slot * 4] = parameter; - break; - } - - if (method >= NV097_SET_VIEWPORT_SCALE && method <= NV097_SET_VIEWPORT_SCALE + 12) { - slot = (method - NV097_SET_VIEWPORT_SCALE) / 4; - pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPSCL][slot] = parameter; - pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPSCL] = true; - break; - } - - EmuWarning("EmuNV2A: Unknown NV_KELVIN_PRIMITIVE Method: 0x%08X\n", method); - } - break; - } - - default: - EmuWarning("EmuNV2A: Unknown Graphics Class/Method 0x%08X/0x%08X\n", object->graphics_class, method); - break; - } -} - -static void* pfifo_puller_thread() -{ - Cache1State *state = &pfifo.cache1; - - while (true) { - // Scope the lock so that it automatically unlocks at tne end of this block - { - std::unique_lock lk(state->mutex); - - while (state->cache.empty() || !state->pull_enabled) { - state->cache_cond.wait(lk); - } - - // Copy cache to working_cache - while (!state->cache.empty()) { - state->working_cache.push(state->cache.front()); - state->cache.pop(); - } - } - - while (!state->working_cache.empty()) { - CacheEntry* command = state->working_cache.front(); - state->working_cache.pop(); - - if (command->method == 0) { - // qemu_mutex_lock_iothread(); - RAMHTEntry entry = ramht_lookup(command->parameter); - assert(entry.valid); - - assert(entry.channel_id == state->channel_id); - // qemu_mutex_unlock_iothread(); - - switch (entry.engine) { - case ENGINE_GRAPHICS: - pgraph_context_switch(entry.channel_id); - pgraph_wait_fifo_access(); - pgraph_method(command->subchannel, 0, entry.instance); - break; - default: - assert(false); - break; - } - - /* the engine is bound to the subchannel */ - std::lock_guard lk(pfifo.cache1.mutex); - state->bound_engines[command->subchannel] = entry.engine; - state->last_engine = entry.engine; - } else if (command->method >= 0x100) { - /* method passed to engine */ - - uint32_t parameter = command->parameter; - - /* methods that take objects. - * TODO: Check this range is correct for the nv2a */ - if (command->method >= 0x180 && command->method < 0x200) { - //qemu_mutex_lock_iothread(); - RAMHTEntry entry = ramht_lookup(parameter); - assert(entry.valid); - assert(entry.channel_id == state->channel_id); - parameter = entry.instance; - //qemu_mutex_unlock_iothread(); - } - - // qemu_mutex_lock(&state->cache_lock); - enum FIFOEngine engine = state->bound_engines[command->subchannel]; - // qemu_mutex_unlock(&state->cache_lock); - - switch (engine) { - case ENGINE_GRAPHICS: - pgraph_wait_fifo_access(); - pgraph_method(command->subchannel, command->method, parameter); - break; - default: - assert(false); - break; - } - - // qemu_mutex_lock(&state->cache_lock); - state->last_engine = state->bound_engines[command->subchannel]; - // qemu_mutex_unlock(&state->cache_lock); - } - - free(command); - } - } - - return NULL; -} - -DEVICE_READ32(PMC) -{ - DEVICE_READ32_SWITCH() { - case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 - result = 0x02A000A2; - break; - case NV_PMC_INTR_0: - result = pmc.pending_interrupts; - break; - case NV_PMC_INTR_EN_0: - result = pmc.enabled_interrupts; - break; - default: - result = 0; - //DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC); - break; - } - - DEVICE_READ32_END(PMC); -} - -DEVICE_WRITE32(PMC) -{ - switch(addr) { - case NV_PMC_INTR_0: - pmc.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PMC_INTR_EN_0: - pmc.enabled_interrupts = value; - update_irq(); - break; - - default: - //DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC); - break; - } - - DEVICE_WRITE32_END(PMC); -} - - -DEVICE_READ32(PBUS) -{ - DEVICE_READ32_SWITCH() { - case NV_PBUS_PCI_NV_0: - result = 0x10de; // PCI_VENDOR_ID_NVIDIA (?where to return PCI_DEVICE_ID_NVIDIA_NV2A = 0x01b7) - - break; - case NV_PBUS_PCI_NV_1: - result = 1; // NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED - break; - case NV_PBUS_PCI_NV_2: - result = (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1) - break; - - default: - DEBUG_READ32_UNHANDLED(PBUS); // TODO : DEVICE_READ32_REG(pbus); - break; - } - - DEVICE_READ32_END(PBUS); -} - -DEVICE_WRITE32(PBUS) -{ - switch(addr) { - case NV_PBUS_PCI_NV_1: - // TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED) - break; - default: - DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus); - break; - } - - DEVICE_WRITE32_END(PBUS); -} - - -DEVICE_READ32(PFIFO) -{ - DEVICE_READ32_SWITCH() { - case NV_PFIFO_RAMHT: - result = 0x03000100; // = NV_PFIFO_RAMHT_SIZE_4K | NV_PFIFO_RAMHT_BASE_ADDRESS(NumberOfPaddingBytes >> 12) | NV_PFIFO_RAMHT_SEARCH_128 - break; - case NV_PFIFO_RAMFC: - result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ? - break; - case NV_PFIFO_INTR_0: - result = pfifo.pending_interrupts; - break; - case NV_PFIFO_INTR_EN_0: - result = pfifo.enabled_interrupts; - break; - case NV_PFIFO_RUNOUT_STATUS: - result = NV_PFIFO_RUNOUT_STATUS_LOW_MARK; /* low mark empty */ - break; - case NV_PFIFO_CACHE1_PUSH0: - result = pfifo.cache1.push_enabled; - break; - case NV_PFIFO_CACHE1_PUSH1: - SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, pfifo.cache1.channel_id); - SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, pfifo.cache1.mode); - break; - case NV_PFIFO_CACHE1_STATUS: { - std::lock_guard lk(pfifo.cache1.mutex); - - if (pfifo.cache1.cache.empty()) { - result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */ - } - - } break; - case NV_PFIFO_CACHE1_DMA_PUSH: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS, - pfifo.cache1.dma_push_enabled); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, - pfifo.cache1.dma_push_suspended); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_BUFFER, 1); /* buffer emoty */ - break; - case NV_PFIFO_CACHE1_DMA_STATE: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE, - pfifo.cache1.method_nonincreasing); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD, - pfifo.cache1.method >> 2); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, - pfifo.cache1.subchannel); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, - pfifo.cache1.method_count); - SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR, - pfifo.cache1.error); - break; - case NV_PFIFO_CACHE1_DMA_INSTANCE: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS, - pfifo.cache1.dma_instance >> 4); - break; - case NV_PFIFO_CACHE1_DMA_PUT: - result = user.channel_control[pfifo.cache1.channel_id].dma_put; - break; - case NV_PFIFO_CACHE1_DMA_GET: - result = user.channel_control[pfifo.cache1.channel_id].dma_get; - break; - case NV_PFIFO_CACHE1_DMA_SUBROUTINE: - result = pfifo.cache1.subroutine_return - | pfifo.cache1.subroutine_active; - break; - case NV_PFIFO_CACHE1_PULL0: { - std::lock_guard lk(pfifo.cache1.mutex); - result = pfifo.cache1.pull_enabled; - } break; - case NV_PFIFO_CACHE1_ENGINE: { - std::lock_guard lk(pfifo.cache1.mutex); - for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { - result |= pfifo.cache1.bound_engines[i] << (i * 2); - } - - } break; - case NV_PFIFO_CACHE1_DMA_DCOUNT: - result = pfifo.cache1.dcount; - break; - case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: - result = pfifo.cache1.get_jmp_shadow; - break; - case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: - result = pfifo.cache1.rsvd_shadow; - break; - case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: - result = pfifo.cache1.data_shadow; - break; - default: - DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO); - break; - } - - DEVICE_READ32_END(PFIFO); -} - -DEVICE_WRITE32(PFIFO) -{ - switch(addr) { - case NV_PFIFO_INTR_0: - pfifo.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PFIFO_INTR_EN_0: - pfifo.enabled_interrupts = value; - update_irq(); - break; - case NV_PFIFO_CACHE1_PUSH0: - pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS; - break; - case NV_PFIFO_CACHE1_PUSH1: - pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID); - pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE); - assert(pfifo.cache1.channel_id < NV2A_NUM_CHANNELS); - break; - case NV_PFIFO_CACHE1_DMA_PUSH: - pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS); - if (pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) { - pfifo.cache1.dma_push_suspended = false; - pfifo_run_pusher(); - } - pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS); - break; - case NV_PFIFO_CACHE1_DMA_STATE: - pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE); - pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2; - pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL); - pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT); - pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR); - break; - case NV_PFIFO_CACHE1_DMA_INSTANCE: - pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS) << 4; - break; - case NV_PFIFO_CACHE1_DMA_PUT: - user.channel_control[pfifo.cache1.channel_id].dma_put = value; - break; - case NV_PFIFO_CACHE1_DMA_GET: - user.channel_control[pfifo.cache1.channel_id].dma_get = value; - break; - case NV_PFIFO_CACHE1_DMA_SUBROUTINE: - pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET); - pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE); - break; - case NV_PFIFO_CACHE1_PULL0: { - std::lock_guard lk(pfifo.cache1.mutex); - - if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS) - && !pfifo.cache1.pull_enabled) { - pfifo.cache1.pull_enabled = true; - - /* the puller thread should wake up */ - pfifo.cache1.cache_cond.notify_all(); - } else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS) - && pfifo.cache1.pull_enabled) { - pfifo.cache1.pull_enabled = false; - } - } break; - case NV_PFIFO_CACHE1_ENGINE: { - std::lock_guard lk(pfifo.cache1.mutex); - - for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { - pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3); - } - - } break; - case NV_PFIFO_CACHE1_DMA_DCOUNT: - pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE); - break; - case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: - pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET); - break; - case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: - pfifo.cache1.rsvd_shadow = value; - break; - case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: - pfifo.cache1.data_shadow = value; - break; - default: - DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO); - break; - } - - DEVICE_WRITE32_END(PFIFO); -} - -DEVICE_READ32(PRMA) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMA); // TODO : DEVICE_READ32_REG(prma); - break; - } - - DEVICE_READ32_END(PRMA); -} - -DEVICE_WRITE32(PRMA) -{ - switch(addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMA); // TODO : DEVICE_WRITE32_REG(prma); - break; - } - - DEVICE_WRITE32_END(PRMA); -} - - -DEVICE_READ32(PVIDEO) -{ - DEVICE_READ32_SWITCH() { - - case NV_PVIDEO_STOP: - result = 0; - break; - default: - DEVICE_READ32_REG(pvideo); - break; - } - - DEVICE_READ32_END(PVIDEO); -} - -DEVICE_WRITE32(PVIDEO) -{ - switch (addr) { - case NV_PVIDEO_BUFFER: - pvideo.regs[addr] = value; - // TODO: vga.enable_overlay = true; - // pvideo_vga_invalidate(d); - break; - case NV_PVIDEO_STOP: - pvideo.regs[NV_PVIDEO_BUFFER] = 0; - // TODO: vga.enable_overlay = false; - //pvideo_vga_invalidate(d); - break; - default: - DEVICE_WRITE32_REG(pvideo); - break; - } - - DEVICE_WRITE32_END(PVIDEO); -} - -DEVICE_READ32(PCOUNTER) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PCOUNTER); // TODO : DEVICE_READ32_REG(pcounter); - break; - } - - DEVICE_READ32_END(PCOUNTER); -} - -DEVICE_WRITE32(PCOUNTER) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PCOUNTER); // TODO : DEVICE_WRITE32_REG(pcounter); - break; - } - - DEVICE_WRITE32_END(PCOUNTER); -} - -static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) -{ - union { - uint64_t ll; - struct { - uint32_t low, high; - } l; - } u, res; - uint64_t rl, rh; - - u.ll = a; - rl = (uint64_t)u.l.low * (uint64_t)b; - rh = (uint64_t)u.l.high * (uint64_t)b; - rh += (rl >> 32); - res.l.high = rh / c; - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; - return res.ll; -} - -/* PIMTER - time measurement and time-based alarms */ -static uint32_t ptimer_get_clock() -{ - // Get time in nanoseconds - long int time = static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); - - return muldiv64(time, pramdac.core_clock_freq * ptimer.numerator, CLOCKS_PER_SEC * ptimer.denominator); -} - -DEVICE_READ32(PTIMER) -{ - DEVICE_READ32_SWITCH() { - case NV_PTIMER_INTR_0: - result = ptimer.pending_interrupts; - break; - case NV_PTIMER_INTR_EN_0: - result = ptimer.enabled_interrupts; - break; - case NV_PTIMER_NUMERATOR: - result = ptimer.numerator; - break; - case NV_PTIMER_DENOMINATOR: - result = ptimer.denominator; - break; - case NV_PTIMER_TIME_0: - result = (ptimer_get_clock() & 0x7ffffff) << 5; - break; - case NV_PTIMER_TIME_1: - result = (ptimer_get_clock() >> 27) & 0x1fffffff; - break; - default: - result = 0; - //DEVICE_READ32_REG(ptimer); // Was : DEBUG_READ32_UNHANDLED(PTIMER); - break; - } - - DEVICE_READ32_END(PTIMER); -} - - -DEVICE_WRITE32(PTIMER) -{ - switch (addr) { - - case NV_PTIMER_INTR_0: - ptimer.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PTIMER_INTR_EN_0: - ptimer.enabled_interrupts = value; - update_irq(); - break; - case NV_PTIMER_DENOMINATOR: - ptimer.denominator = value; - break; - case NV_PTIMER_NUMERATOR: - ptimer.numerator = value; - break; - case NV_PTIMER_ALARM_0: - ptimer.alarm_time = value; - break; - default: - //DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER); - break; - } - - DEVICE_WRITE32_END(PTIMER); -} - - -DEVICE_READ32(PVPE) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PVPE); // TODO : DEVICE_READ32_REG(pvpe); - break; - } - - DEVICE_READ32_END(PVPE); -} - - -DEVICE_WRITE32(PVPE) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PVPE); // TODO : DEVICE_WRITE32_REG(pvpe); - break; - } - - DEVICE_WRITE32_END(PVPE); -} - - -DEVICE_READ32(PTV) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PTV); // TODO : DEVICE_READ32_REG(ptv); - break; - } - - DEVICE_READ32_END(PTV); -} - -DEVICE_WRITE32(PTV) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PTV); // TODO : DEVICE_WRITE32_REG(ptv); - break; - } - - DEVICE_WRITE32_END(PTV); -} - - -DEVICE_READ32(PRMFB) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMFB); // TODO : DEVICE_READ32_REG(prmfb); - break; - } - - DEVICE_READ32_END(PRMFB); -} - -DEVICE_WRITE32(PRMFB) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMFB); // TODO : DEVICE_WRITE32_REG(prmfb); - break; - } - - DEVICE_WRITE32_END(PRMFB); -} - - -DEVICE_READ32(PRMVIO) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio); - break; - } - - DEVICE_READ32_END(PRMVIO); -} - -DEVICE_WRITE32(PRMVIO) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio); - break; - } - - DEVICE_WRITE32_END(PRMVIO); -} - - -DEVICE_READ32(PFB) -{ - DEVICE_READ32_SWITCH() { - case NV_PFB_CFG0: - result = 3; // = NV_PFB_CFG0_PART_4 - break; - case NV_PFB_CSTATUS: - { - if (g_bIsChihiro || g_bIsDebug) { result = CONTIGUOUS_MEMORY_CHIHIRO_SIZE; break; } - result = CONTIGUOUS_MEMORY_XBOX_SIZE; - } - break; - case NV_PFB_WBC: - result = 0; // = !NV_PFB_WBC_FLUSH - break; - default: - DEVICE_READ32_REG(pfb); - break; - } - - DEVICE_READ32_END(PFB); -} - -DEVICE_WRITE32(PFB) -{ - switch (addr) { - default: - DEVICE_WRITE32_REG(pfb); - break; - } - - DEVICE_WRITE32_END(PFB); -} - - -DEVICE_READ32(PSTRAPS) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PSTRAPS); - break; - } - - DEVICE_READ32_END(PSTRAPS); -} - -DEVICE_WRITE32(PSTRAPS) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PSTRAPS); - break; - } - - DEVICE_WRITE32_END(PSTRAPS); -} - - -DEVICE_READ32(PGRAPH) -{ - std::lock_guard lk(pgraph.mutex); - - DEVICE_READ32_SWITCH() { - case NV_PGRAPH_INTR: - result = pgraph.pending_interrupts; - break; - case NV_PGRAPH_INTR_EN: - result = pgraph.enabled_interrupts; - break; - case NV_PGRAPH_NSOURCE: - result = pgraph.notify_source; - break; - case NV_PGRAPH_CTX_USER: - SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D, pgraph.context[pgraph.channel_id].channel_3d); - SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D_VALID, 1); - SET_MASK(result, NV_PGRAPH_CTX_USER_SUBCH, pgraph.context[pgraph.channel_id].subchannel << 13); - SET_MASK(result, NV_PGRAPH_CTX_USER_CHID, pgraph.channel_id); - break; - case NV_PGRAPH_TRAPPED_ADDR: - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_CHID, pgraph.trapped_channel_id); - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_SUBCH, pgraph.trapped_subchannel); - SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_MTHD, pgraph.trapped_method); - break; - case NV_PGRAPH_TRAPPED_DATA_LOW: - result = pgraph.trapped_data[0]; - break; - case NV_PGRAPH_FIFO: - SET_MASK(result, NV_PGRAPH_FIFO_ACCESS, pgraph.fifo_access); - break; - case NV_PGRAPH_CHANNEL_CTX_TABLE: - result = pgraph.context_table >> 4; - break; - case NV_PGRAPH_CHANNEL_CTX_POINTER: - result = pgraph.context_address >> 4; - break; - default: - DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH); - } - - DEVICE_READ32_END(PGRAPH); -} - -static void pgraph_set_context_user(uint32_t value) -{ - pgraph.channel_id = (value & NV_PGRAPH_CTX_USER_CHID) >> 24; - pgraph.context[pgraph.channel_id].channel_3d = GET_MASK(value, NV_PGRAPH_CTX_USER_CHANNEL_3D); - pgraph.context[pgraph.channel_id].subchannel = GET_MASK(value, NV_PGRAPH_CTX_USER_SUBCH); -} - -DEVICE_WRITE32(PGRAPH) -{ - std::lock_guard lk(pgraph.mutex); - - switch (addr) { - case NV_PGRAPH_INTR: - pgraph.pending_interrupts &= ~value; - pgraph.interrupt_cond.notify_all(); - break; - case NV_PGRAPH_INTR_EN: - pgraph.enabled_interrupts = value; - break; - case NV_PGRAPH_CTX_CONTROL: - pgraph.channel_valid = (value & NV_PGRAPH_CTX_CONTROL_CHID); - break; - case NV_PGRAPH_CTX_USER: - pgraph_set_context_user(value); - break; - case NV_PGRAPH_INCREMENT: - if (value & NV_PGRAPH_INCREMENT_READ_3D) { - SET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_READ_3D, - (GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_READ_3D) + 1) - % GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], - NV_PGRAPH_SURFACE_MODULO_3D)); - - pgraph.flip_3d.notify_all(); - } - break; - case NV_PGRAPH_FIFO: - pgraph.fifo_access = GET_MASK(value, NV_PGRAPH_FIFO_ACCESS); - pgraph.fifo_access_cond.notify_all(); - break; - case NV_PGRAPH_CHANNEL_CTX_TABLE: - pgraph.context_table = (value & NV_PGRAPH_CHANNEL_CTX_TABLE_INST) << 4; - break; - case NV_PGRAPH_CHANNEL_CTX_POINTER: - pgraph.context_address = - (value & NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4; - break; - case NV_PGRAPH_CHANNEL_CTX_TRIGGER: - if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) { - printf("PGRAPH: read channel %d context from %0x08X\n", - pgraph.channel_id, pgraph.context_address); - - uint8_t *context_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + pgraph.context_address); - uint32_t context_user = ldl_le_p((uint32_t*)context_ptr); - - printf(" - CTX_USER = 0x%x\n", context_user); - - - pgraph_set_context_user(context_user); - } - if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT) { - /* do stuff ... */ - } - - break; - default: - DEVICE_WRITE32_REG(pgraph); // Was : DEBUG_WRITE32_UNHANDLED(PGRAPH); - break; - } - - DEVICE_WRITE32_END(PGRAPH); -} - - -DEVICE_READ32(PCRTC) -{ - DEVICE_READ32_SWITCH() { - - case NV_PCRTC_INTR_0: - result = pcrtc.pending_interrupts; - break; - case NV_PCRTC_INTR_EN_0: - result = pcrtc.enabled_interrupts; - break; - case NV_PCRTC_START: - result = pcrtc.start; - break; - default: - result = 0; - //DEVICE_READ32_REG(pcrtc); // Was : DEBUG_READ32_UNHANDLED(PCRTC); - break; - } - - DEVICE_READ32_END(PCRTC); -} - -DEVICE_WRITE32(PCRTC) -{ - switch (addr) { - - case NV_PCRTC_INTR_0: - pcrtc.pending_interrupts &= ~value; - update_irq(); - break; - case NV_PCRTC_INTR_EN_0: - pcrtc.enabled_interrupts = value; - update_irq(); - break; - case NV_PCRTC_START: - pcrtc.start = value &= 0x07FFFFFF; - break; - - default: - DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC); - break; - } - - DEVICE_WRITE32_END(PCRTC); -} - - -DEVICE_READ32(PRMCIO) -{ - DEVICE_READ32_SWITCH() { - case VGA_CRT_IM: - case VGA_CRT_IC: - result = prmcio.cr_index; - break; - case VGA_CRT_DM: - case VGA_CRT_DC: - result = prmcio.cr[prmcio.cr_index]; - - printf("vga: read CR%x = 0x%02x\n", prmcio.cr_index, result); - break; - default: - DEBUG_READ32_UNHANDLED(PRMCIO); - printf("vga: UNHANDLED ADDR %s\n", addr); - break; - } - - DEVICE_READ32_END(PRMCIO); -} - -DEVICE_WRITE32(PRMCIO) -{ - switch (addr) { - case VGA_CRT_IM: - case VGA_CRT_IC: - prmcio.cr_index = value; - break; - case VGA_CRT_DM: - case VGA_CRT_DC: - printf("vga: write CR%x = 0x%02x\n", prmcio.cr_index, value); - - /* handle CR0-7 protection */ - if ((prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && - prmcio.cr_index <= VGA_CRTC_OVERFLOW) { - /* can always write bit 4 of CR7 */ - if (prmcio.cr_index == VGA_CRTC_OVERFLOW) { - prmcio.cr[VGA_CRTC_OVERFLOW] = (prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) | - (value & 0x10); - EmuWarning("TODO: vbe_update_vgaregs"); - //vbe_update_vgaregs(); - } - return; - } - - prmcio.cr[prmcio.cr_index] = value; - EmuWarning("TODO: vbe_update_vgaregs"); - //vbe_update_vgaregs(); - - switch (prmcio.cr_index) { - case VGA_CRTC_H_TOTAL: - case VGA_CRTC_H_SYNC_START: - case VGA_CRTC_H_SYNC_END: - case VGA_CRTC_V_TOTAL: - case VGA_CRTC_OVERFLOW: - case VGA_CRTC_V_SYNC_END: - case VGA_CRTC_MODE: - // TODO: s->update_retrace_info(s); - EmuWarning("TODO: update_retrace_info"); - break; - } - break; - default: - DEBUG_WRITE32_UNHANDLED(PRMCIO); // TODO : DEVICE_WRITE32_REG(prmcio); - break; - } - - DEVICE_WRITE32_END(PRMCIO); -} - - -DEVICE_READ32(PRAMDAC) -{ - DEVICE_READ32_SWITCH() { - - case NV_PRAMDAC_NVPLL_COEFF: - result = pramdac.core_clock_coeff; - break; - case NV_PRAMDAC_MPLL_COEFF: - result = pramdac.memory_clock_coeff; - break; - case NV_PRAMDAC_VPLL_COEFF: - result = pramdac.video_clock_coeff; - break; - case NV_PRAMDAC_PLL_TEST_COUNTER: - /* emulated PLLs locked instantly? */ - result = NV_PRAMDAC_PLL_TEST_COUNTER_VPLL2_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK - | NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK; - break; - - default: - //DEVICE_READ32_REG(pramdac); // Was : DEBUG_READ32_UNHANDLED(PRAMDAC); - break; - } - - DEVICE_READ32_END(PRAMDAC); -} - -DEVICE_WRITE32(PRAMDAC) -{ - switch (addr) { - - uint32_t m, n, p; - case NV_PRAMDAC_NVPLL_COEFF: - pramdac.core_clock_coeff = value; - - m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV; - n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV) >> 8; - p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV) >> 16; - - if (m == 0) { - pramdac.core_clock_freq = 0; - } - else { - pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n) - / (1 << p) / m; - } - - break; - case NV_PRAMDAC_MPLL_COEFF: - pramdac.memory_clock_coeff = value; - break; - case NV_PRAMDAC_VPLL_COEFF: - pramdac.video_clock_coeff = value; - break; - - default: - //DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC); - break; - } - - DEVICE_WRITE32_END(PRAMDAC); -} - - -DEVICE_READ32(PRMDIO) -{ - DEVICE_READ32_SWITCH() { - default: - DEBUG_READ32_UNHANDLED(PRMDIO); - break; - } - - DEVICE_READ32_END(PRMDIO); -} - -DEVICE_WRITE32(PRMDIO) -{ - switch (addr) { - default: - DEBUG_WRITE32_UNHANDLED(PRMDIO); - break; - } - - DEVICE_WRITE32_END(PRMDIO); -} - - -DEVICE_READ32(PRAMIN) -{ - DEVICE_READ32_SWITCH() { - default: - DEVICE_READ32_REG(pramin); - break; - } - - DEVICE_READ32_END(PRAMIN); -} - -DEVICE_WRITE32(PRAMIN) -{ - switch (addr) { - default: - DEVICE_WRITE32_REG(pramin); - break; - } - - DEVICE_WRITE32_END(PRAMIN); -} - - -DEVICE_READ32(USER) -{ - unsigned int channel_id = addr >> 16; - assert(channel_id < NV2A_NUM_CHANNELS); - - ChannelControl *control = &user.channel_control[channel_id]; - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - - /* PIO Mode */ - if (!channel_modes & (1 << channel_id)) { - assert(false); - } - - /* DMA Mode */ - addr &= 0xFFFF; - DEVICE_READ32_SWITCH() { - case NV_USER_DMA_PUT: - result = control->dma_put; - break; - case NV_USER_DMA_GET: - result = control->dma_get; - break; - case NV_USER_REF: - result = control->ref; - break; - default: - DEBUG_READ32_UNHANDLED(USER); - break; - } - - DEVICE_READ32_END(USER); -} - -DEVICE_WRITE32(USER) -{ - unsigned int channel_id = addr >> 16; - assert(channel_id < NV2A_NUM_CHANNELS); - - ChannelControl *control = &user.channel_control[channel_id]; - - uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; - - if (channel_modes & (1 << channel_id)) { - /* DMA Mode */ - switch (addr & 0xFFFF) { - case NV_USER_DMA_PUT: - control->dma_put = value; - - if (pfifo.cache1.push_enabled) { - pfifo_run_pusher(); - } - break; - case NV_USER_DMA_GET: - control->dma_get = value; - break; - case NV_USER_REF: - control->ref = value; - break; - default: - DEBUG_WRITE32_UNHANDLED(USER); - break; - } - } - else { - /* PIO Mode */ - assert(false); - } - - DEVICE_WRITE32_END(USER); -} - - -typedef struct NV2ABlockInfo { - uint32_t offset; - uint32_t size; - uint32_t(*read)(xbaddr addr); - void(*write)(xbaddr addr, uint32_t value); -} NV2ABlockInfo; - -static const NV2ABlockInfo regions[] = {{ - /* card master control */ - NV_PMC_ADDR, // = 0x000000 - NV_PMC_SIZE, // = 0x001000 - EmuNV2A_PMC_Read32, - EmuNV2A_PMC_Write32, - }, { - /* bus control */ - NV_PBUS_ADDR, // = 0x001000 - NV_PBUS_SIZE, // = 0x001000 - EmuNV2A_PBUS_Read32, - EmuNV2A_PBUS_Write32, - }, { - /* MMIO and DMA FIFO submission to PGRAPH and VPE */ - NV_PFIFO_ADDR, // = 0x002000 - NV_PFIFO_SIZE, // = 0x002000 - EmuNV2A_PFIFO_Read32, - EmuNV2A_PFIFO_Write32, - }, { - /* access to BAR0/BAR1 from real mode */ - NV_PRMA_ADDR, // = 0x007000 - NV_PRMA_SIZE, // = 0x001000 - EmuNV2A_PRMA_Read32, - EmuNV2A_PRMA_Write32, - }, { - /* video overlay */ - NV_PVIDEO_ADDR, // = 0x008000 - NV_PVIDEO_SIZE, // = 0x001000 - EmuNV2A_PVIDEO_Read32, - EmuNV2A_PVIDEO_Write32, - }, { - /* time measurement and time-based alarms */ - NV_PTIMER_ADDR, // = 0x009000 - NV_PTIMER_SIZE, // = 0x001000 - EmuNV2A_PTIMER_Read32, - EmuNV2A_PTIMER_Write32, - }, { - /* performance monitoring counters */ - NV_PCOUNTER_ADDR, // = 0x00a000 - NV_PCOUNTER_SIZE, // = 0x001000 - EmuNV2A_PCOUNTER_Read32, - EmuNV2A_PCOUNTER_Write32, - }, { - /* MPEG2 decoding engine */ - NV_PVPE_ADDR, // = 0x00b000 - NV_PVPE_SIZE, // = 0x001000 - EmuNV2A_PVPE_Read32, - EmuNV2A_PVPE_Write32, - }, { - /* TV encoder */ - NV_PTV_ADDR, // = 0x00d000 - NV_PTV_SIZE, // = 0x001000 - EmuNV2A_PTV_Read32, - EmuNV2A_PTV_Write32, - }, { - /* aliases VGA memory window */ - NV_PRMFB_ADDR, // = 0x0a0000 - NV_PRMFB_SIZE, // = 0x020000 - EmuNV2A_PRMFB_Read32, - EmuNV2A_PRMFB_Write32, - }, { - /* aliases VGA sequencer and graphics controller registers */ - NV_PRMVIO_ADDR, // = 0x0c0000 - NV_PRMVIO_SIZE, // = 0x001000 - EmuNV2A_PRMVIO_Read32, - EmuNV2A_PRMVIO_Write32, - },{ - /* memory interface */ - NV_PFB_ADDR, // = 0x100000 - NV_PFB_SIZE, // = 0x001000 - EmuNV2A_PFB_Read32, - EmuNV2A_PFB_Write32, - }, { - /* straps readout / override */ - NV_PSTRAPS_ADDR, // = 0x101000 - NV_PSTRAPS_SIZE, // = 0x001000 - EmuNV2A_PSTRAPS_Read32, - EmuNV2A_PSTRAPS_Write32, - }, { - /* accelerated 2d/3d drawing engine */ - NV_PGRAPH_ADDR, // = 0x400000 - NV_PGRAPH_SIZE, // = 0x002000 - EmuNV2A_PGRAPH_Read32, - EmuNV2A_PGRAPH_Write32, - }, { - /* more CRTC controls */ - NV_PCRTC_ADDR, // = 0x600000 - NV_PCRTC_SIZE, // = 0x001000 - EmuNV2A_PCRTC_Read32, - EmuNV2A_PCRTC_Write32, - }, { - /* aliases VGA CRTC and attribute controller registers */ - NV_PRMCIO_ADDR, // = 0x601000 - NV_PRMCIO_SIZE, // = 0x001000 - EmuNV2A_PRMCIO_Read32, - EmuNV2A_PRMCIO_Write32, - }, { - /* RAMDAC, cursor, and PLL control */ - NV_PRAMDAC_ADDR, // = 0x680000 - NV_PRAMDAC_SIZE, // = 0x001000 - EmuNV2A_PRAMDAC_Read32, - EmuNV2A_PRAMDAC_Write32, - }, { - /* aliases VGA palette registers */ - NV_PRMDIO_ADDR, // = 0x681000 - NV_PRMDIO_SIZE, // = 0x001000 - EmuNV2A_PRMDIO_Read32, - EmuNV2A_PRMDIO_Write32, - }, { - /* RAMIN access */ - NV_PRAMIN_ADDR, // = 0x700000 - NV_PRAMIN_SIZE, // = 0x100000 - EmuNV2A_PRAMIN_Read32, - EmuNV2A_PRAMIN_Write32, - },{ - /* PFIFO MMIO and DMA submission area */ - NV_USER_ADDR, // = 0x800000, - NV_USER_SIZE, // = 0x800000, - EmuNV2A_USER_Read32, - EmuNV2A_USER_Write32, - }, { - 0xFFFFFFFF, - 0, - nullptr, - nullptr, - }, -}; - -const NV2ABlockInfo* EmuNV2A_Block(xbaddr addr) -{ - // Find the block in the block table - const NV2ABlockInfo* block = ®ions[0]; - int i = 0; - - while (block->read != nullptr) { - if (addr >= block->offset && addr < block->offset + block->size) { - return block; - } - - block = ®ions[++i]; - } - - return nullptr; -} - -uint32_t EmuNV2A_Read(xbaddr addr, int size) -{ - const NV2ABlockInfo* block = EmuNV2A_Block(addr); - - if (block != nullptr) { - switch (size) { - case sizeof(uint8_t): - return block->read(addr - block->offset) & 0xFF; - case sizeof(uint16_t) : - return block->read(addr - block->offset) & 0xFFFF; - case sizeof(uint32_t) : - return block->read(addr - block->offset); - default: - EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); - return 0; - } - } - - EmuWarning("EmuNV2A_Read%d: Unhandled Read Address %08X", size, addr); - return 0; -} - -void EmuNV2A_Write(xbaddr addr, uint32_t value, int size) -{ - const NV2ABlockInfo* block = EmuNV2A_Block(addr); - - if (block != nullptr) { - int shift = 0; - xbaddr aligned_addr = 0; - uint32_t aligned_value = 0; - uint32_t mask = 0; - switch (size) { - case sizeof(uint8_t) : - shift = (addr & 3) * 8; - aligned_addr = addr & ~3; - aligned_value = block->read(aligned_addr - block->offset); - mask = 0xFF << shift; - - // TODO : Must the second byte be written to the next DWORD? - block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); - return; - case sizeof(uint16_t) : - assert((addr & 1) == 0); - - shift = (addr & 2) * 16; - aligned_addr = addr & ~3; - aligned_value = block->read(addr - block->offset); - mask = 0xFFFF << shift; - - // TODO : Must the second byte be written to the next DWORD? - block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); - return; - case sizeof(uint32_t) : - block->write(addr - block->offset, value); - return; - default: - EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); - return; - } - } - - EmuWarning("EmuNV2A_Write%d: Unhandled Write Address %08X (value %08X)", size, addr, value); - return; -} - -// -// OPENGL -// - -// -#define X_D3DTS_STAGECOUNT 4 - -HDC g_EmuWindowsDC = 0; -GLuint VertexProgramIDs[4] = { 0, 0, 0, 0 }; -uint ActiveVertexProgramID = 0; -GLuint TextureIDs[X_D3DTS_STAGECOUNT]= { 0, 0, 0, 0 }; - -// Vertex shader header, mapping Xbox1 registers to the ARB syntax (original version by KingOfC). -// Note about the use of 'conventional' attributes in here: Since we prefer to use only one shader -// for both immediate and deferred mode rendering, we alias all attributes to conventional inputs -// as much as possible. Only when there's no conventional attribute available, we use generic attributes. -// So in the following header, we use conventional attributes first, and generic attributes for the -// rest of the vertex attribute slots. This makes it possible to support immediate and deferred mode -// rendering with the same shader, and the use of the OpenGL fixed-function pipeline without a shader. -std::string DxbxVertexShaderHeader = - "!!ARBvp1.0\n" - "TEMP R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12;\n" - "ADDRESS A0;\n" -#ifdef DXBX_OPENGL_CONVENTIONAL - "ATTRIB v0 = vertex.position;\n" // Was: vertex.attrib[0] (See "conventional" note above) - "ATTRIB v1 = vertex.%s;\n" // Note : We replace this with "weight" or "attrib[1]" depending GL_ARB_vertex_blend - "ATTRIB v2 = vertex.normal;\n" // Was: vertex.attrib[2] - "ATTRIB v3 = vertex.color.primary;\n" // Was: vertex.attrib[3] - "ATTRIB v4 = vertex.color.secondary;\n" // Was: vertex.attrib[4] - "ATTRIB v5 = vertex.fogcoord;\n" // Was: vertex.attrib[5] - "ATTRIB v6 = vertex.attrib[6];\n" - "ATTRIB v7 = vertex.attrib[7];\n" - "ATTRIB v8 = vertex.texcoord[0];\n" // Was: vertex.attrib[8] - "ATTRIB v9 = vertex.texcoord[1];\n" // Was: vertex.attrib[9] - "ATTRIB v10 = vertex.texcoord[2];\n" // Was: vertex.attrib[10] - "ATTRIB v11 = vertex.texcoord[3];\n" // Was: vertex.attrib[11] -#else - "ATTRIB v0 = vertex.attrib[0];\n" - "ATTRIB v1 = vertex.attrib[1];\n" - "ATTRIB v2 = vertex.attrib[2];\n" - "ATTRIB v3 = vertex.attrib[3];\n" - "ATTRIB v4 = vertex.attrib[4];\n" - "ATTRIB v5 = vertex.attrib[5];\n" - "ATTRIB v6 = vertex.attrib[6];\n" - "ATTRIB v7 = vertex.attrib[7];\n" - "ATTRIB v8 = vertex.attrib[8];\n" - "ATTRIB v9 = vertex.attrib[9];\n" - "ATTRIB v10 = vertex.attrib[10];\n" - "ATTRIB v11 = vertex.attrib[11];\n" -#endif - "ATTRIB v12 = vertex.attrib[12];\n" - "ATTRIB v13 = vertex.attrib[13];\n" - "ATTRIB v14 = vertex.attrib[14];\n" - "ATTRIB v15 = vertex.attrib[15];\n" - "OUTPUT oPos = result.position;\n" - "OUTPUT oD0 = result.color.front.primary;\n" - "OUTPUT oD1 = result.color.front.secondary;\n" - "OUTPUT oB0 = result.color.back.primary;\n" - "OUTPUT oB1 = result.color.back.secondary;\n" - "OUTPUT oPts = result.pointsize;\n" - "OUTPUT oFog = result.fogcoord;\n" - "OUTPUT oT0 = result.texcoord[0];\n" - "OUTPUT oT1 = result.texcoord[1];\n" - "OUTPUT oT2 = result.texcoord[2];\n" - "OUTPUT oT3 = result.texcoord[3];\n" - "PARAM c[] = { program.env[0..191] };\n" // All constants in 1 array declaration (requires NV_gpu_program4?) - "PARAM mvp[4] = { state.matrix.mvp };\n"; - -void SetupPixelFormat(HDC DC) -{ - const PIXELFORMATDESCRIPTOR pfd = { - /* .nSize = */ sizeof(PIXELFORMATDESCRIPTOR), // size - /* .nVersion = */ 1, // version - /* .dwFlags = */ PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, // support double-buffering - /* .iPixelType = */ PFD_TYPE_RGBA, // color type - /* .cColorBits = */ 32, // preferred color depth - /* .cRedBits = */ 0, - /* .cRedShift = */ 0, // color bits (ignored) - /* .cGreenBits = */ 0, - /* .cGreenShift = */ 0, - /* .cBlueBits = */ 0, - /* .cBlueShift = */ 0, - /* .cAlphaBits = */ 0, - /* .cAlphaShift = */ 0, // no alpha buffer - /* .cAccumBits = */ 0, - /* .cAccumRedBits = */ 0, // no accumulation buffer, - /* .cAccumGreenBits = */ 0, // accum bits (ignored) - /* .cAccumBlueBits = */ 0, - /* .cAccumAlphaBits = */ 0, - /* .cDepthBits = */ 16, // depth buffer - /* .cStencilBits = */ 0, // no stencil buffer - /* .cAuxBuffers = */ 0, // no auxiliary buffers - /* .iLayerType= */ PFD_MAIN_PLANE, // main layer - /* .bReserved = */ 0, - /* .dwLayerMask = */ 0, - /* .dwVisibleMask = */ 0, - /* .dwDamageMask = */ 0 // no layer, visible, damage masks - }; - - int PixelFormat = ChoosePixelFormat(DC, &pfd); - if (PixelFormat == 0) - return; - - if (SetPixelFormat(DC, PixelFormat, &pfd) != TRUE) - return; -} - -// From https://github.com/inolen/redream/blob/master/src/video/gl_backend.c -static int rb_compile_shader(const char *source, GLenum shader_type, GLuint *shader) -{ - size_t sourceLength = strlen(source); - - *shader = glCreateShader(shader_type); - glShaderSource(*shader, 1, (const GLchar **)&source, - (const GLint *)&sourceLength); - glCompileShader(*shader); - - GLint compiled; - glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); - - if (!compiled) { -// rb_print_shader_log(*shader); - glDeleteShader(*shader); - return 0; - } - - return 1; -} - -void DxbxCompileShader(std::string Shader) -{ - int GLErrorPos; - -// if (MayLog(lfUnit)) -// DbgPrintf(" NV2A: New vertex program :\n" + Shader); - -/* -glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, Shader.size(), Shader.c_str()); - - // errors are catched - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &GLErrorPos); - */ - GLuint shader; - - GLErrorPos = rb_compile_shader(Shader.c_str(), GL_VERTEX_SHADER, &shader); // TODO : GL_VERTEX_SHADER_ARB ?? - /* - if (GLErrorPos > 0) - { - Shader.insert(GLErrorPos, "{ERROR}"); - EmuWarning("Program error at position %d:", GLErrorPos); - EmuWarning((char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)); - EmuWarning(Shader.c_str()); - } - */ -} -void InitOpenGLContext() -{ - HGLRC RC; - std::string szCode; - - g_EmuWindowsDC = GetDC(g_hEmuWindow); // Actually, you can use any windowed control here - SetupPixelFormat(g_EmuWindowsDC); - - RC = wglCreateContext(g_EmuWindowsDC); // makes OpenGL window out of DC - wglMakeCurrent(g_EmuWindowsDC, RC); // makes OpenGL window active - //ReadImplementationProperties(); // Determine a set of booleans indicating which OpenGL extensions are available - //ReadExtensions(); // Assign all OpenGL extension API's (DON'T call them if the extension is not available!) - - // Initialize the viewport : - //Viewport.X = 0; - //Viewport.Y = 0; - //Viewport.Width = g_EmuCDPD.pPresentationParameters.BackBufferWidth; - //Viewport.Height = g_EmuCDPD.pPresentationParameters.BackBufferHeight; - //Viewport.MinZ = -1.0; - //Viewport.MaxZ = 1.0; - - //DxbxUpdateTransformProjection(); - //DxbxUpdateViewport(); - - - //glutInit(); - { // rb_init_context(); - /* link in gl functions at runtime */ - glewExperimental = GL_TRUE; - GLenum err = glewInit(); - if (err != GLEW_OK) { - EmuWarning("GLEW initialization failed: %s", glewGetErrorString(err)); - return; - } - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Switch to left-handed coordinate space (as per http://www.opengl.org/resources/faq/technical/transformations.htm) : - // glScalef(1.0, 1.0, -1.0); - - // Set some defaults : - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); // Nearer Z coordinates cover further Z - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glAlphaFunc(GL_GEQUAL, 0.5); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // GL_LINE for wireframe - -/* - // TODO : The following code only works on cards that support the - // vertex program extensions (NVidia cards mainly); So for ATI we - // have to come up with another solution !!! - glGenProgramsARB(4, &VertexProgramIDs[0]); -*/ - -#ifdef DXBX_OPENGL_CONVENTIONAL - if (GL_ARB_vertex_blend) - DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "weight"); - else - DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "attrib[1]"); -#endif - - // Precompiled shader for the fixed function pipeline : - szCode = DxbxVertexShaderHeader + - "# This part adjusts the vertex position by the super-sampling scale & offset :\n" - "MOV R0, v0;\n" - "RCP R0.w, R0.w;\n" - "MUL R0, R0, c[0];\n" // c[-96] in D3D speak - applies SuperSampleScale - // Note : Use R12 instead of oPos because this is not yet the final assignment : - "ADD R12, R0, c[1];\n" // c[-95] in D3D speak - applies SuperSampleOffset - - "# This part just reads all other components and passes them to the output :\n" - "MOV oD0, v3;\n" - "MOV oD1, v4;\n" - "MOV oFog, v4.w;\n" // specular fog - // "MOV oFog, v0.z;\n" // z fog - // "RCP oFog, v0.w;\n" // w fog - "MOV oPts, v1.x;\n" - "MOV oB0, v7;\n" - "MOV oB1, v8;\n" - "MOV oT0, v9;\n" - "MOV oT1, v10;\n" - "MOV oT2, v11;\n" - "MOV oT3, v12;\n" - - "# This part applies the screen-space transform (not present when '#pragma screenspace' was used) :\n" - "MUL R12.xyz, R12, c[58];\n" // c[-38] in D3D speak - see EmuNV2A_ViewportScale, - "RCP R1.x, R12.w;\n" // Originally RCC, but that"s not supported in ARBvp1.0 (use "MIN R1, R1, 0" and "MAX R1, R1, 1"?) - "MAD R12.xyz, R12, R1.x, c[59];\n" // c[-37] in D3D speak - see EmuNV2A_ViewportOffset - - "# Dxbx addition : Transform the vertex to clip coordinates :\n" - "DP4 R0.x, mvp[0], R12;\n" - "DP4 R0.y, mvp[1], R12;\n" - "DP4 R0.z, mvp[2], R12;\n" - "DP4 R0.w, mvp[3], R12;\n" - "MOV R12, R0;\n" - - "# Apply Z coord mapping\n" - "ADD R12.z, R12.z, R12.z;\n" - "ADD R12.z, R12.z, -R12.w;\n" - - "# Here""s the final assignment to oPos :\n" - "MOV oPos, R12;\n" - "END\n"; // TODO : Check if newline is required? - -// glBindProgramARB(GL_VERTEX_PROGRAM_ARB, VertexProgramIDs[0]); - DxbxCompileShader(szCode); -} - -// HACK: Until we implement VGA/proper interrupt generation -// we simulate VBLANK by calling the interrupt at 60Hz -std::thread vblank_thread; -extern std::chrono::time_point> GetNextVBlankTime(); -static void nv2a_vblank_thread() -{ - auto nextVBlankTime = GetNextVBlankTime(); - - while (true) { - // Handle VBlank - if (std::chrono::steady_clock::now() > nextVBlankTime) { - pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK; - update_irq(); - nextVBlankTime = GetNextVBlankTime(); - } - } -} - -void EmuNV2A_Init() -{ - // Allocate PRAMIN Region - VirtualAlloc((void*)(NV2A_ADDR + NV_PRAMIN_ADDR), NV_PRAMIN_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - - pcrtc.start = 0; - - pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */ - pramdac.core_clock_freq = 189000000; - pramdac.memory_clock_coeff = 0; - pramdac.video_clock_coeff = 0x0003C20D; /* 25182Khz...? */ - - pfifo.puller_thread = std::thread(pfifo_puller_thread); - - // Only spawn VBlank thread when LLE is enabled - if (bLLE_GPU) { - vblank_thread = std::thread(nv2a_vblank_thread);; - } -} +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Win32->CxbxKrnl->EmuNV2A.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * (c) 2016 Luke Usher +// * +// * EmuNV2A.cpp is heavily based on code from XQEMU +// * Copyright(c) 2012 espes +// * Copyright(c) 2015 Jannik Vogel +// * https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a.c +// * +// * All rights reserved +// * +// ****************************************************************** +#define _XBOXKRNL_DEFEXTRN_ + +#define LOG_PREFIX "NV2A" + +#include // For __beginthreadex(), etc. +#include "vga.h" + +// prevent name collisions +namespace xboxkrnl +{ + #include // For PKINTERRUPT, etc. +}; + + +#ifdef _MSC_VER // Check if MS Visual C compiler +# pragma comment(lib, "opengl32.lib") // Compiler-specific directive to avoid manually configuration +//# pragma comment(lib, "glu32.lib") // Link libraries +# pragma comment(lib, "glew32.lib") +#endif + +#include // For uint32_t +#include // For std::string +#include +#include +#include +#include + +#include "CxbxKrnl\CxbxKrnl.h" +#include "CxbxKrnl\Emu.h" +#include "CxbxKrnl\EmuFS.h" +#include "CxbxKrnl\EmuKrnl.h" +#include "CxbxKrnl\HLEIntercept.h" + +#include "EmuNV2A.h" +#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox + +#include +#include +#include +#include +//#include + + +// Public Domain ffs Implementation +// See: http://snipplr.com/view/22147/stringsh-implementation/ +int ffs(int v) +{ + unsigned int x = v; + int c = 1; + + /* + * adapted from from + * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch + * + * a modified binary search algorithm to count 0 bits from + * the right (lsb). This algorithm should work regardless + * of the size of ints on the platform. + * + */ + + /* a couple special cases */ + if (x == 0) return 0; + if (x & 1) return 1; /* probably pretty common */ + + c = 1; + while ((x & 0xffff) == 0) { + x >>= 16; + c += 16; + } + if ((x & 0xff) == 0) { + x >>= 8; + c += 8; + } + if ((x & 0x0f) == 0) { + x >>= 4; + c += 4; + } + if ((x & 0x03) == 0) { + x >>= 2; + c += 2; + } + + c -= (x & 1); + c += 1; /* ffs() requires indexing bits from 1 */ + /* ie., the lsb is bit 1, not bit 0 */ + return c; +} + +inline int GET_MASK(int v, int mask) { + return (((v) & (mask)) >> (ffs(mask) - 1)); +}; + +inline int SET_MASK(int v, int mask, int val) { + const unsigned int __val = (val); + const unsigned int __mask = (mask); + + (v) &= ~(__mask); + return (v) |= ((__val) << (ffs(__mask)-1)) & (__mask); +} + +#define CASE_4(v, step) \ + case (v): \ + case (v)+(step) : \ + case (v)+(step) * 2: \ + case (v)+(step) * 3 + + +enum FifoMode { + FIFO_PIO = 0, + FIFO_DMA = 1, +}; + +enum FIFOEngine { + ENGINE_SOFTWARE = 0, + ENGINE_GRAPHICS = 1, + ENGINE_DVD = 2, +}; + +typedef struct RAMHTEntry { + uint32_t handle; + xbaddr instance; + enum FIFOEngine engine; + unsigned int channel_id : 5; + bool valid; +} RAMHTEntry; + +typedef struct DMAObject { + unsigned int dma_class; + unsigned int dma_target; + xbaddr address; + xbaddr limit; +} DMAObject; + +typedef struct VertexAttribute { + bool dma_select; + xbaddr offset; + + /* inline arrays are packed in order? + * Need to pass the offset to converted attributes */ + unsigned int inline_array_offset; + + float inline_value[4]; + + unsigned int format; + unsigned int size; /* size of the data type */ + unsigned int count; /* number of components */ + uint32_t stride; + + bool needs_conversion; + uint8_t *converted_buffer; + unsigned int converted_elements; + unsigned int converted_size; + unsigned int converted_count; + + float *inline_buffer; + + GLint gl_count; + GLenum gl_type; + GLboolean gl_normalize; + + GLuint gl_converted_buffer; + GLuint gl_inline_buffer; +} VertexAttribute; + +typedef struct Surface { + bool draw_dirty; + bool buffer_dirty; + bool write_enabled_cache; + unsigned int pitch; + + xbaddr offset; +} Surface; + +typedef struct SurfaceShape { + unsigned int z_format; + unsigned int color_format; + unsigned int zeta_format; + unsigned int log_width, log_height; + unsigned int clip_x, clip_y; + unsigned int clip_width, clip_height; + unsigned int anti_aliasing; +} SurfaceShape; + +typedef struct TextureShape { + bool cubemap; + unsigned int dimensionality; + unsigned int color_format; + unsigned int levels; + unsigned int width, height, depth; + + unsigned int min_mipmap_level, max_mipmap_level; + unsigned int pitch; +} TextureShape; + +typedef struct TextureKey { + TextureShape state; + uint64_t data_hash; + uint8_t* texture_data; + uint8_t* palette_data; +} TextureKey; + +typedef struct TextureBinding { + GLenum gl_target; + GLuint gl_texture; + unsigned int refcnt; +} TextureBinding; + +typedef struct KelvinState { + xbaddr dma_notifies; + xbaddr dma_state; + xbaddr dma_semaphore; + unsigned int semaphore_offset; +} KelvinState; + +typedef struct ContextSurfaces2DState { + xbaddr dma_image_source; + xbaddr dma_image_dest; + unsigned int color_format; + unsigned int source_pitch, dest_pitch; + xbaddr source_offset, dest_offset; + +} ContextSurfaces2DState; + +typedef struct ImageBlitState { + xbaddr context_surfaces; + unsigned int operation; + unsigned int in_x, in_y; + unsigned int out_x, out_y; + unsigned int width, height; + +} ImageBlitState; + +typedef struct GraphicsObject { + uint8_t graphics_class; + union { + ContextSurfaces2DState context_surfaces_2d; + + ImageBlitState image_blit; + + KelvinState kelvin; + } data; +} GraphicsObject; + +typedef struct GraphicsSubchannel { + xbaddr object_instance; + GraphicsObject object; + uint32_t object_cache[5]; +} GraphicsSubchannel; + +typedef struct GraphicsContext { + bool channel_3d; + unsigned int subchannel; +} GraphicsContext; + +typedef struct CacheEntry { + unsigned int method : 14; + unsigned int subchannel : 3; + bool nonincreasing; + uint32_t parameter; +} CacheEntry; + +typedef struct Cache1State { + unsigned int channel_id; + FifoMode mode; + + /* Pusher state */ + bool push_enabled; + bool dma_push_enabled; + bool dma_push_suspended; + xbaddr dma_instance; + + bool method_nonincreasing; + unsigned int method : 14; + unsigned int subchannel : 3; + unsigned int method_count : 24; + uint32_t dcount; + + bool subroutine_active; + xbaddr subroutine_return; + xbaddr get_jmp_shadow; + uint32_t rsvd_shadow; + uint32_t data_shadow; + uint32_t error; + + bool pull_enabled; + enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS]; + enum FIFOEngine last_engine; + + /* The actual command queue */ + std::mutex mutex; + std::condition_variable cache_cond; + std::queue cache; + std::queue working_cache; +} Cache1State; + +typedef struct ChannelControl { + xbaddr dma_put; + xbaddr dma_get; + uint32_t ref; +} ChannelControl; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t regs[NV_PMC_SIZE]; // TODO : union +} pmc; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + std::thread puller_thread; + Cache1State cache1; + uint32_t regs[NV_PFIFO_SIZE]; // TODO : union +} pfifo; + +struct { + uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union +} pvideo; + + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t numerator; + uint32_t denominator; + uint32_t alarm_time; + uint32_t regs[NV_PTIMER_SIZE]; // TODO : union +} ptimer; + +struct { + uint32_t regs[NV_PFB_SIZE]; // TODO : union +} pfb; + +struct { + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + uint32_t start; + uint32_t regs[NV_PCRTC_SIZE]; // TODO : union +} pcrtc; + +struct { + uint32_t core_clock_coeff; + uint64_t core_clock_freq; + uint32_t memory_clock_coeff; + uint32_t video_clock_coeff; + uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union +} pramdac; + +struct { + uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union +} pramin; + +struct { + ChannelControl channel_control[NV2A_NUM_CHANNELS]; +} user; + +// PRMCIO (Actually the VGA controller) +struct { + uint8_t cr_index; + uint8_t cr[256]; /* CRT registers */ +} prmcio; + +struct { + std::mutex mutex; + + uint32_t pending_interrupts; + uint32_t enabled_interrupts; + std::condition_variable interrupt_cond; + + xbaddr context_table; + xbaddr context_address; + + + unsigned int trapped_method; + unsigned int trapped_subchannel; + unsigned int trapped_channel_id; + uint32_t trapped_data[2]; + uint32_t notify_source; + + bool fifo_access; + std::condition_variable fifo_access_cond; + std::condition_variable flip_3d; + + unsigned int channel_id; + bool channel_valid; + GraphicsContext context[NV2A_NUM_CHANNELS]; + + xbaddr dma_color, dma_zeta; + Surface surface_color, surface_zeta; + unsigned int surface_type; + SurfaceShape surface_shape; + SurfaceShape last_surface_shape; + + xbaddr dma_a, dma_b; + //GLruCache *texture_cache; + bool texture_dirty[NV2A_MAX_TEXTURES]; + TextureBinding *texture_binding[NV2A_MAX_TEXTURES]; + + //GHashTable *shader_cache; + //ShaderBinding *shader_binding; + + bool texture_matrix_enable[NV2A_MAX_TEXTURES]; + + /* FIXME: Move to NV_PGRAPH_BUMPMAT... */ + float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */ + + // wglContext *gl_context; + GLuint gl_framebuffer; + GLuint gl_color_buffer, gl_zeta_buffer; + GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS]; + + xbaddr dma_report; + xbaddr report_offset; + bool zpass_pixel_count_enable; + unsigned int zpass_pixel_count_result; + unsigned int gl_zpass_pixel_count_query_count; + GLuint* gl_zpass_pixel_count_queries; + + xbaddr dma_vertex_a, dma_vertex_b; + + unsigned int primitive_mode; + + bool enable_vertex_program_write; + + //uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE]; + + uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; + bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS]; + + /* lighting constant arrays */ + uint32_t ltctxa[NV2A_LTCTXA_COUNT][4]; + bool ltctxa_dirty[NV2A_LTCTXA_COUNT]; + uint32_t ltctxb[NV2A_LTCTXB_COUNT][4]; + bool ltctxb_dirty[NV2A_LTCTXB_COUNT]; + uint32_t ltc1[NV2A_LTC1_COUNT][4]; + bool ltc1_dirty[NV2A_LTC1_COUNT]; + + // should figure out where these are in lighting context + float light_infinite_half_vector[NV2A_MAX_LIGHTS][3]; + float light_infinite_direction[NV2A_MAX_LIGHTS][3]; + float light_local_position[NV2A_MAX_LIGHTS][3]; + float light_local_attenuation[NV2A_MAX_LIGHTS][3]; + + //VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES]; + + unsigned int inline_array_length; + uint32_t inline_array[NV2A_MAX_BATCH_LENGTH]; + GLuint gl_inline_array_buffer; + + unsigned int inline_elements_length; + uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH]; + + unsigned int inline_buffer_length; + + unsigned int draw_arrays_length; + unsigned int draw_arrays_max_count; + + /* FIXME: Unknown size, possibly endless, 1000 will do for now */ + GLint gl_draw_arrays_start[1000]; + GLsizei gl_draw_arrays_count[1000]; + + GLuint gl_element_buffer; + GLuint gl_memory_buffer; + GLuint gl_vertex_array; + + uint32_t regs[NV_PGRAPH_SIZE]; // TODO : union +} pgraph; + +static void update_irq() +{ + /* PFIFO */ + if (pfifo.pending_interrupts & pfifo.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO; + } + + /* PCRTC */ + if (pcrtc.pending_interrupts & pcrtc.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC; + } + + /* PGRAPH */ + if (pgraph.pending_interrupts & pgraph.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH; + } else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH; + } + + /* TODO : PBUS * / + if (pbus.pending_interrupts & pbus.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS; + } + else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS; + } */ + + /* TODO : SOFTWARE * / + if (user.pending_interrupts & user.enabled_interrupts) { + pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE; + } + else { + pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE; + } */ + + if (pmc.pending_interrupts && pmc.enabled_interrupts) { + HalSystemInterrupts[3].Assert(true); + } else { + HalSystemInterrupts[3].Assert(false); + } + + SwitchToThread(); +} + + +#define DEBUG_START(DEV) \ +const char *DebugNV_##DEV##(xbaddr addr) \ +{ \ + switch (addr) { +#define DEBUG_CASE(a) \ + case a: return #a; +#define DEBUG_CASE_EX(a, c) \ + case a: return #a##c; +#define DEBUG_END(DEV) \ + default: \ + return "Unknown " #DEV " Address"; \ + } \ +} + +DEBUG_START(PMC) + DEBUG_CASE(NV_PMC_BOOT_0); + DEBUG_CASE(NV_PMC_INTR_0); + DEBUG_CASE(NV_PMC_INTR_EN_0); + DEBUG_CASE(NV_PMC_ENABLE); +DEBUG_END(PMC) + +DEBUG_START(PBUS) + DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID"); + DEBUG_CASE(NV_PBUS_PCI_NV_1); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, ":LATENCY_TIMER"); + DEBUG_CASE(NV_PBUS_PCI_NV_4); + DEBUG_CASE(NV_PBUS_PCI_NV_5); + DEBUG_CASE(NV_PBUS_PCI_NV_6); + DEBUG_CASE(NV_PBUS_PCI_NV_7); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, ":SUBSYSTEM"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, ":ROM_BASE"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, ":CAP_PTR"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, ":RESERVED"); + DEBUG_CASE(NV_PBUS_PCI_NV_15); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, ":SUBSYSTEM"); + DEBUG_CASE(NV_PBUS_PCI_NV_17); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, ":AGP_STATUS"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, ":AGP_COMMAND"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, ":ROM_SHADOW"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, ":VGA"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, ":SCRATCH"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, ":DT_TIMEOUT"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, ":PME"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, ":POWER_STATE"); + DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, ":RESERVED"); +DEBUG_END(PBUS) + +DEBUG_START(PFIFO) + DEBUG_CASE(NV_PFIFO_INTR_0); + DEBUG_CASE(NV_PFIFO_INTR_EN_0); + DEBUG_CASE(NV_PFIFO_RAMHT); + DEBUG_CASE(NV_PFIFO_RAMFC); + DEBUG_CASE(NV_PFIFO_RAMRO); + DEBUG_CASE(NV_PFIFO_RUNOUT_STATUS); + DEBUG_CASE(NV_PFIFO_MODE); + DEBUG_CASE(NV_PFIFO_DMA); + DEBUG_CASE(NV_PFIFO_CACHE1_PUSH0); + DEBUG_CASE(NV_PFIFO_CACHE1_PUSH1); + DEBUG_CASE(NV_PFIFO_CACHE1_STATUS); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUSH); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_FETCH); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_STATE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_INSTANCE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUT); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_SUBROUTINE); + DEBUG_CASE(NV_PFIFO_CACHE1_PULL0); + DEBUG_CASE(NV_PFIFO_CACHE1_ENGINE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DCOUNT); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_RSVD_SHADOW); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DATA_SHADOW); +DEBUG_END(PFIFO) + +DEBUG_START(PRMA) +DEBUG_END(PRMA) + +DEBUG_START(PVIDEO) + DEBUG_CASE(NV_PVIDEO_INTR); + DEBUG_CASE(NV_PVIDEO_INTR_EN); + DEBUG_CASE(NV_PVIDEO_BUFFER); + DEBUG_CASE(NV_PVIDEO_STOP); + DEBUG_CASE(NV_PVIDEO_BASE); + DEBUG_CASE(NV_PVIDEO_LIMIT); + DEBUG_CASE(NV_PVIDEO_LUMINANCE); + DEBUG_CASE(NV_PVIDEO_CHROMINANCE); + DEBUG_CASE(NV_PVIDEO_OFFSET); + DEBUG_CASE(NV_PVIDEO_SIZE_IN); + DEBUG_CASE(NV_PVIDEO_POINT_IN); + DEBUG_CASE(NV_PVIDEO_DS_DX); + DEBUG_CASE(NV_PVIDEO_DT_DY); + DEBUG_CASE(NV_PVIDEO_POINT_OUT); + DEBUG_CASE(NV_PVIDEO_SIZE_OUT); + DEBUG_CASE(NV_PVIDEO_FORMAT); +DEBUG_END(PVIDEO) + +DEBUG_START(PTIMER) + DEBUG_CASE(NV_PTIMER_INTR_0); + DEBUG_CASE(NV_PTIMER_INTR_EN_0); + DEBUG_CASE(NV_PTIMER_NUMERATOR); + DEBUG_CASE(NV_PTIMER_DENOMINATOR); + DEBUG_CASE(NV_PTIMER_TIME_0); + DEBUG_CASE(NV_PTIMER_TIME_1); + DEBUG_CASE(NV_PTIMER_ALARM_0); + +DEBUG_END(PTIMER) + +DEBUG_START(PCOUNTER) +DEBUG_END(PCOUNTER) + +DEBUG_START(PVPE) +DEBUG_END(PVPE) + +DEBUG_START(PTV) +DEBUG_END(PTV) + +DEBUG_START(PRMFB) +DEBUG_END(PRMFB) + +DEBUG_START(PRMVIO) +DEBUG_END(PRMVIO) + +DEBUG_START(PFB) + DEBUG_CASE(NV_PFB_CFG0) + DEBUG_CASE(NV_PFB_CSTATUS) + DEBUG_CASE(NV_PFB_REFCTRL) + DEBUG_CASE(NV_PFB_NVM) // NV_PFB_NVM_MODE_DISABLE + DEBUG_CASE(NV_PFB_PIN) + DEBUG_CASE(NV_PFB_PAD) + DEBUG_CASE(NV_PFB_TIMING0) + DEBUG_CASE(NV_PFB_TIMING1) + DEBUG_CASE(NV_PFB_TIMING2) + DEBUG_CASE(NV_PFB_TILE) + DEBUG_CASE(NV_PFB_TLIMIT) + DEBUG_CASE(NV_PFB_TSIZE) + DEBUG_CASE(NV_PFB_TSTATUS) + DEBUG_CASE(NV_PFB_MRS) + DEBUG_CASE(NV_PFB_EMRS) + DEBUG_CASE(NV_PFB_MRS_EXT) + DEBUG_CASE(NV_PFB_EMRS_EXT) + DEBUG_CASE(NV_PFB_REF) + DEBUG_CASE(NV_PFB_PRE) + DEBUG_CASE(NV_PFB_ZCOMP) + DEBUG_CASE(NV_PFB_ARB_PREDIVIDER) + DEBUG_CASE(NV_PFB_ARB_TIMEOUT) + DEBUG_CASE(NV_PFB_ARB_XFER_REM) + DEBUG_CASE(NV_PFB_ARB_DIFF_BANK) + DEBUG_CASE(NV_PFB_CLOSE_PAGE0) + DEBUG_CASE(NV_PFB_CLOSE_PAGE1) + DEBUG_CASE(NV_PFB_CLOSE_PAGE2) + DEBUG_CASE(NV_PFB_BPARB) + DEBUG_CASE(NV_PFB_CMDQ0) + DEBUG_CASE(NV_PFB_CMDQ1) + DEBUG_CASE(NV_PFB_ILL_INSTR) + DEBUG_CASE(NV_PFB_RT) + DEBUG_CASE(NV_PFB_AUTOCLOSE) + DEBUG_CASE(NV_PFB_WBC) + DEBUG_CASE(NV_PFB_CMDQ_PRT) + DEBUG_CASE(NV_PFB_CPU_RRQ) + DEBUG_CASE(NV_PFB_BYPASS); +DEBUG_END(PFB) + +DEBUG_START(PSTRAPS) +DEBUG_END(PSTRAPS) + +DEBUG_START(PGRAPH) + DEBUG_CASE(NV_PGRAPH_INTR); + DEBUG_CASE(NV_PGRAPH_NSOURCE); + DEBUG_CASE(NV_PGRAPH_INTR_EN); + DEBUG_CASE(NV_PGRAPH_CTX_CONTROL); + DEBUG_CASE(NV_PGRAPH_CTX_USER); + DEBUG_CASE(NV_PGRAPH_CTX_SWITCH1); + DEBUG_CASE(NV_PGRAPH_TRAPPED_ADDR); + DEBUG_CASE(NV_PGRAPH_TRAPPED_DATA_LOW); + DEBUG_CASE(NV_PGRAPH_SURFACE); + DEBUG_CASE(NV_PGRAPH_INCREMENT); + DEBUG_CASE(NV_PGRAPH_FIFO); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TABLE); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_POINTER); + DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TRIGGER); + DEBUG_CASE(NV_PGRAPH_CSV0_D); + DEBUG_CASE(NV_PGRAPH_CSV0_C); + DEBUG_CASE(NV_PGRAPH_CSV1_B); + DEBUG_CASE(NV_PGRAPH_CSV1_A); + DEBUG_CASE(NV_PGRAPH_CHEOPS_OFFSET); + DEBUG_CASE(NV_PGRAPH_BLEND); + DEBUG_CASE(NV_PGRAPH_BLENDCOLOR); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR0); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR1); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR2); + DEBUG_CASE(NV_PGRAPH_BORDERCOLOR3); + DEBUG_CASE(NV_PGRAPH_BUMPOFFSET1); + DEBUG_CASE(NV_PGRAPH_BUMPSCALE1); + DEBUG_CASE(NV_PGRAPH_CLEARRECTX); + DEBUG_CASE(NV_PGRAPH_CLEARRECTY); + DEBUG_CASE(NV_PGRAPH_COLORCLEARVALUE); + DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR0); + DEBUG_CASE(NV_PGRAPH_COMBINEFACTOR1); + DEBUG_CASE(NV_PGRAPH_COMBINEALPHAI0); + DEBUG_CASE(NV_PGRAPH_COMBINEALPHAO0); + DEBUG_CASE(NV_PGRAPH_COMBINECOLORI0); + DEBUG_CASE(NV_PGRAPH_COMBINECOLORO0); + DEBUG_CASE(NV_PGRAPH_COMBINECTL); + DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG0); + DEBUG_CASE(NV_PGRAPH_COMBINESPECFOG1); + DEBUG_CASE(NV_PGRAPH_CONTROL_0); + DEBUG_CASE(NV_PGRAPH_CONTROL_2); + DEBUG_CASE(NV_PGRAPH_CONTROL_3); + DEBUG_CASE(NV_PGRAPH_FOGCOLOR); + DEBUG_CASE(NV_PGRAPH_FOGPARAM0); + DEBUG_CASE(NV_PGRAPH_FOGPARAM1); + DEBUG_CASE(NV_PGRAPH_SETUPRASTER); + DEBUG_CASE(NV_PGRAPH_SHADERCLIPMODE); + DEBUG_CASE(NV_PGRAPH_SHADERCTL); + DEBUG_CASE(NV_PGRAPH_SHADERPROG); + DEBUG_CASE(NV_PGRAPH_SHADOWZSLOPETHRESHOLD); + DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR0); + DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR1); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS0); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS0_ADDRV); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS1); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS2); + DEBUG_CASE(NV_PGRAPH_TEXADDRESS3); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_1); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_2); + DEBUG_CASE(NV_PGRAPH_TEXCTL0_3); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_1); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_2); + DEBUG_CASE(NV_PGRAPH_TEXCTL1_3); + DEBUG_CASE(NV_PGRAPH_TEXCTL2_0); + DEBUG_CASE(NV_PGRAPH_TEXCTL2_1); + DEBUG_CASE(NV_PGRAPH_TEXFILTER0); + DEBUG_CASE(NV_PGRAPH_TEXFILTER1); + DEBUG_CASE(NV_PGRAPH_TEXFILTER2); + DEBUG_CASE(NV_PGRAPH_TEXFILTER3); + DEBUG_CASE(NV_PGRAPH_TEXFMT0); + DEBUG_CASE(NV_PGRAPH_TEXFMT1); + DEBUG_CASE(NV_PGRAPH_TEXFMT2); + DEBUG_CASE(NV_PGRAPH_TEXFMT3); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT0); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT1); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT2); + DEBUG_CASE(NV_PGRAPH_TEXIMAGERECT3); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET0); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET1); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET2); + DEBUG_CASE(NV_PGRAPH_TEXOFFSET3); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE0); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE1); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE2); + DEBUG_CASE(NV_PGRAPH_TEXPALETTE3); + DEBUG_CASE(NV_PGRAPH_ZSTENCILCLEARVALUE); + DEBUG_CASE(NV_PGRAPH_ZCLIPMIN); + DEBUG_CASE(NV_PGRAPH_ZOFFSETBIAS); + DEBUG_CASE(NV_PGRAPH_ZOFFSETFACTOR); + DEBUG_CASE(NV_PGRAPH_EYEVEC0); + DEBUG_CASE(NV_PGRAPH_EYEVEC1); + DEBUG_CASE(NV_PGRAPH_EYEVEC2); + DEBUG_CASE(NV_PGRAPH_ZCLIPMAX); +DEBUG_END(PGRAPH) + +DEBUG_START(PCRTC) + DEBUG_CASE(NV_PCRTC_INTR_0); + DEBUG_CASE(NV_PCRTC_INTR_EN_0); + DEBUG_CASE(NV_PCRTC_START); + DEBUG_CASE(NV_PCRTC_CONFIG); + +DEBUG_END(PCRTC) + +DEBUG_START(PRMCIO) + DEBUG_CASE(VGA_CRT_DC); + DEBUG_CASE(VGA_CRT_DM); + DEBUG_CASE(VGA_ATT_R); + DEBUG_CASE(VGA_ATT_W); + DEBUG_CASE(VGA_GFX_D); + DEBUG_CASE(VGA_SEQ_D); + DEBUG_CASE(VGA_MIS_R); + DEBUG_CASE(VGA_MIS_W); + DEBUG_CASE(VGA_FTC_R); + DEBUG_CASE(VGA_IS1_RC); + DEBUG_CASE(VGA_IS1_RM); + DEBUG_CASE(VGA_PEL_D); + DEBUG_CASE(VGA_PEL_MSK); + DEBUG_CASE(VGA_CRT_IC); + DEBUG_CASE(VGA_CRT_IM); + DEBUG_CASE(VGA_GFX_I); + DEBUG_CASE(VGA_SEQ_I); + DEBUG_CASE(VGA_PEL_IW); + DEBUG_CASE(VGA_PEL_IR); +DEBUG_END(PRMCIO) + +DEBUG_START(PRAMDAC) + DEBUG_CASE(NV_PRAMDAC_NVPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_MPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_VPLL_COEFF); + DEBUG_CASE(NV_PRAMDAC_PLL_TEST_COUNTER); + +DEBUG_END(PRAMDAC) + +DEBUG_START(PRMDIO) +DEBUG_END(PRMDIO) + +DEBUG_START(PRAMIN) +DEBUG_END(PRAMIN) + +DEBUG_START(USER) + + DEBUG_CASE(NV_USER_DMA_PUT); + DEBUG_CASE(NV_USER_DMA_GET); + DEBUG_CASE(NV_USER_REF); + + DEBUG_END(USER) + + + + +#define DEBUG_READ32(DEV) DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr)) +#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } + +#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr)) +#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; } + +#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr) +#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr) +#define DEVICE_READ32_REG(dev) result = dev.regs[addr] +#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result + +#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(xbaddr addr, uint32_t value) +#define DEVICE_WRITE32_REG(dev) dev.regs[addr] = value +#define DEVICE_WRITE32_END(DEV) DEBUG_WRITE32(DEV) + +static inline uint32_t ldl_le_p(const void *p) +{ + return *(uint32_t*)p; +} + +static DMAObject nv_dma_load(xbaddr dma_obj_address) +{ + assert(dma_obj_address < NV_PRAMIN_SIZE); + + uint32_t *dma_obj = (uint32_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + dma_obj_address); + uint32_t flags = ldl_le_p(dma_obj); + uint32_t limit = ldl_le_p(dma_obj + 1); + uint32_t frame = ldl_le_p(dma_obj + 2); + + DMAObject object; + object.dma_class = GET_MASK(flags, NV_DMA_CLASS); + object.dma_target = GET_MASK(flags, NV_DMA_TARGET); + object.address = (frame & NV_DMA_ADDRESS) | GET_MASK(flags, NV_DMA_ADJUST); + object.limit = limit; + + return object; +} + +static void *nv_dma_map(xbaddr dma_obj_address, xbaddr *len) +{ + assert(dma_obj_address < NV_PRAMIN_SIZE); + + DMAObject dma = nv_dma_load(dma_obj_address); + + /* TODO: Handle targets and classes properly */ + printf("dma_map %x, %x, %x %x" "\n", + dma.dma_class, dma.dma_target, dma.address, dma.limit); + + dma.address &= 0x07FFFFFF; + + // assert(dma.address + dma.limit < memory_region_size(d->vram)); + *len = dma.limit; + return (void*)(MM_SYSTEM_PHYSICAL_MAP + dma.address); +} + +/* pusher should be fine to run from a mimo handler +* whenever's it's convenient */ +static void pfifo_run_pusher() { + uint8_t channel_id; + ChannelControl *control; + Cache1State *state; + CacheEntry *command; + uint8_t *dma; + xbaddr dma_len; + uint32_t word; + + /* TODO: How is cache1 selected? */ + state = &pfifo.cache1; + channel_id = state->channel_id; + control = &user.channel_control[channel_id]; + + if (!state->push_enabled) return; + + /* only handling DMA for now... */ + + /* Channel running DMA */ + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + assert(channel_modes & (1 << channel_id)); + assert(state->mode == FIFO_DMA); + + if (!state->dma_push_enabled) return; + if (state->dma_push_suspended) return; + + /* We're running so there should be no pending errors... */ + assert(state->error == NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE); + + dma = (uint8_t*)nv_dma_map(state->dma_instance, &dma_len); + + printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n", + dma_len, control->dma_get, control->dma_put); + + /* based on the convenient pseudocode in envytools */ + while (control->dma_get != control->dma_put) { + if (control->dma_get >= dma_len) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION; + break; + } + + word = ldl_le_p((uint32_t*)(dma + control->dma_get)); + control->dma_get += 4; + + if (state->method_count) { + /* data word of methods command */ + state->data_shadow = word; + + CacheEntry* command = (CacheEntry*)calloc(1, sizeof(CacheEntry)); + command->method = state->method; + command->subchannel = state->subchannel; + command->nonincreasing = state->method_nonincreasing; + command->parameter = word; + + std::lock_guard lk(state->mutex); + state->cache.push(command); + state->cache_cond.notify_all(); + + if (!state->method_nonincreasing) { + state->method += 4; + } + + state->method_count--; + state->dcount++; + } else { + /* no command active - this is the first word of a new one */ + state->rsvd_shadow = word; + /* match all forms */ + if ((word & 0xe0000003) == 0x20000000) { + /* old jump */ + state->get_jmp_shadow = control->dma_get; + control->dma_get = word & 0x1fffffff; + printf("pb OLD_JMP 0x%08X\n", control->dma_get); + } + else if ((word & 3) == 1) { + /* jump */ + state->get_jmp_shadow = control->dma_get; + control->dma_get = word & 0xfffffffc; + printf("pb JMP 0x%08X\n", control->dma_get); + } + else if ((word & 3) == 2) { + /* call */ + if (state->subroutine_active) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL; + break; + } + state->subroutine_return = control->dma_get; + state->subroutine_active = true; + control->dma_get = word & 0xfffffffc; + printf("pb CALL 0x%08X\n", control->dma_get); + } + else if (word == 0x00020000) { + /* return */ + if (!state->subroutine_active) { + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN; + break; + } + control->dma_get = state->subroutine_return; + state->subroutine_active = false; + printf("pb RET 0x%08X\n", control->dma_get); + } + else if ((word & 0xe0030003) == 0) { + /* increasing methods */ + state->method = word & 0x1fff; + state->subchannel = (word >> 13) & 7; + state->method_count = (word >> 18) & 0x7ff; + state->method_nonincreasing = false; + state->dcount = 0; + } + else if ((word & 0xe0030003) == 0x40000000) { + /* non-increasing methods */ + state->method = word & 0x1fff; + state->subchannel = (word >> 13) & 7; + state->method_count = (word >> 18) & 0x7ff; + state->method_nonincreasing = true; + state->dcount = 0; + } + else { + printf("pb reserved cmd 0x%08X - 0x%08X\n", + control->dma_get, word); + state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD; + break; + } + } + } + + printf("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n", + dma_len, control->dma_get, control->dma_put); + + if (state->error) { + printf("pb error: %d\n", state->error); + assert(false); + + state->dma_push_suspended = true; + + pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER; + update_irq(); + } +} + +static uint32_t ramht_hash(uint32_t handle) +{ + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + + /* XXX: Think this is different to what nouveau calculates... */ + unsigned int bits = ffs(ramht_size) - 2; + + uint32_t hash = 0; + while (handle) { + hash ^= (handle & ((1 << bits) - 1)); + handle >>= bits; + } + hash ^= pfifo.cache1.channel_id << (bits - 4); + + return hash; +} + + +static RAMHTEntry ramht_lookup(uint32_t handle) +{ + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + + uint32_t hash = ramht_hash(handle); + assert(hash * 8 < ramht_size); + + uint32_t ramht_address = + GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], + NV_PFIFO_RAMHT_BASE_ADDRESS) << 12; + + uint8_t *entry_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + ramht_address + hash * 8); + + uint32_t entry_handle = ldl_le_p((uint32_t*)entry_ptr); + uint32_t entry_context = ldl_le_p((uint32_t*)(entry_ptr + 4)); + + RAMHTEntry entry; + entry.handle = entry_handle; + entry.instance = (entry_context & NV_RAMHT_INSTANCE) << 4; + entry.engine = (FIFOEngine)((entry_context & NV_RAMHT_ENGINE) >> 16); + entry.channel_id = (entry_context & NV_RAMHT_CHID) >> 24; + entry.valid = entry_context & NV_RAMHT_STATUS; + + return entry; +} + +static void pgraph_context_switch(unsigned int channel_id) +{ + bool valid = false; + + // Scope the lock so that it gets unlocked at end of this block + { + std::lock_guard lk(pgraph.mutex); + + valid = pgraph.channel_valid && pgraph.channel_id == channel_id; + if (!valid) { + pgraph.trapped_channel_id = channel_id; + } + } + + if (!valid) { + printf("puller needs to switch to ch %d\n", channel_id); + + //qemu_mutex_lock_iothread(); + pgraph.pending_interrupts |= NV_PGRAPH_INTR_CONTEXT_SWITCH; + update_irq(); + + std::unique_lock lk(pgraph.mutex); + //qemu_mutex_unlock_iothread(); + + while (pgraph.pending_interrupts & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + pgraph.interrupt_cond.wait(lk); + } + } +} + +static void pgraph_wait_fifo_access() { + std::unique_lock lk(pgraph.mutex); + + while (!pgraph.fifo_access) { + pgraph.fifo_access_cond.wait(lk); + } +} + +static void pgraph_method_log(unsigned int subchannel, unsigned int graphics_class, unsigned int method, uint32_t parameter) { + static unsigned int last = 0; + static unsigned int count = 0; + + if (last == 0x1800 && method != last) { + printf("pgraph method (%d) 0x%08X * %d", subchannel, last, count); + } + if (method != 0x1800) { + const char* method_name = NULL; + unsigned int nmethod = 0; + switch (graphics_class) { + case NV_KELVIN_PRIMITIVE: + nmethod = method | (0x5c << 16); + break; + case NV_CONTEXT_SURFACES_2D: + nmethod = method | (0x6d << 16); + break; + default: + break; + } + /* + if (nmethod != 0 && nmethod < ARRAY_SIZE(nv2a_method_names)) { + method_name = nv2a_method_names[nmethod]; + } + if (method_name) { + printf("pgraph method (%d): %s (0x%x)\n", + subchannel, method_name, parameter); + } + else { + */ + printf("pgraph method (%d): 0x%x -> 0x%04x (0x%x)\n", + subchannel, graphics_class, method, parameter); + //} + + } + if (method == last) { count++; } + else { count = 0; } + last = method; +} + +static void load_graphics_object(xbaddr instance_address, GraphicsObject *obj) +{ + uint8_t *obj_ptr; + uint32_t switch1, switch2, switch3; + + assert(instance_address < NV_PRAMIN_SIZE); + obj_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + instance_address); + + switch1 = ldl_le_p((uint32_t*)obj_ptr); + switch2 = ldl_le_p((uint32_t*)(obj_ptr + 4)); + switch3 = ldl_le_p((uint32_t*)(obj_ptr + 8)); + + obj->graphics_class = switch1 & NV_PGRAPH_CTX_SWITCH1_GRCLASS; + + /* init graphics object */ + switch (obj->graphics_class) { + case NV_KELVIN_PRIMITIVE: + // kelvin->vertex_attributes[NV2A_VERTEX_ATTR_DIFFUSE].inline_value = 0xFFFFFFF; + break; + default: + break; + } +} + +static GraphicsObject* lookup_graphics_object(xbaddr instance_address) +{ + int i; + for (i = 0; i lk(pgraph.mutex); + + int i; + GraphicsSubchannel *subchannel_data; + GraphicsObject *object; + + unsigned int slot; + + assert(pgraph.channel_valid); + subchannel_data = &pgraph.subchannel_data[subchannel]; + object = &subchannel_data->object; + + ContextSurfaces2DState *context_surfaces_2d = &object->data.context_surfaces_2d; + ImageBlitState *image_blit = &object->data.image_blit; + KelvinState *kelvin = &object->data.kelvin; + + pgraph_method_log(subchannel, object->graphics_class, method, parameter); + + if (method == NV_SET_OBJECT) { + subchannel_data->object_instance = parameter; + + //qemu_mutex_lock_iothread(); + load_graphics_object(parameter, object); + //qemu_mutex_unlock_iothread(); + return; + } + + switch (object->graphics_class) { + case NV_CONTEXT_SURFACES_2D: { + switch (method) { + case NV062_SET_CONTEXT_DMA_IMAGE_SOURCE: + context_surfaces_2d->dma_image_source = parameter; + break; + case NV062_SET_CONTEXT_DMA_IMAGE_DESTIN: + context_surfaces_2d->dma_image_dest = parameter; + break; + case NV062_SET_COLOR_FORMAT: + context_surfaces_2d->color_format = parameter; + break; + case NV062_SET_PITCH: + context_surfaces_2d->source_pitch = parameter & 0xFFFF; + context_surfaces_2d->dest_pitch = parameter >> 16; + break; + case NV062_SET_OFFSET_SOURCE: + context_surfaces_2d->source_offset = parameter & 0x07FFFFFF; + break; + case NV062_SET_OFFSET_DESTIN: + context_surfaces_2d->dest_offset = parameter & 0x07FFFFFF; + break; + default: + EmuWarning("EmuNV2A: Unknown NV_CONTEXT_SURFACES_2D Method: 0x%08X\n", method); + } + + break; + } + + case NV_IMAGE_BLIT: { + switch (method) { + case NV09F_SET_CONTEXT_SURFACES: + image_blit->context_surfaces = parameter; + break; + case NV09F_SET_OPERATION: + image_blit->operation = parameter; + break; + case NV09F_CONTROL_POINT_IN: + image_blit->in_x = parameter & 0xFFFF; + image_blit->in_y = parameter >> 16; + break; + case NV09F_CONTROL_POINT_OUT: + image_blit->out_x = parameter & 0xFFFF; + image_blit->out_y = parameter >> 16; + break; + case NV09F_SIZE: + image_blit->width = parameter & 0xFFFF; + image_blit->height = parameter >> 16; + + /* I guess this kicks it off? */ + if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) { + + printf("NV09F_SET_OPERATION_SRCCOPY"); + + GraphicsObject *context_surfaces_obj = lookup_graphics_object(image_blit->context_surfaces); + assert(context_surfaces_obj); + assert(context_surfaces_obj->graphics_class == NV_CONTEXT_SURFACES_2D); + + ContextSurfaces2DState *context_surfaces = &context_surfaces_obj->data.context_surfaces_2d; + + unsigned int bytes_per_pixel; + switch (context_surfaces->color_format) { + case NV062_SET_COLOR_FORMAT_LE_Y8: + bytes_per_pixel = 1; + break; + case NV062_SET_COLOR_FORMAT_LE_R5G6B5: + bytes_per_pixel = 2; + break; + case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: + bytes_per_pixel = 4; + break; + default: + printf("Unknown blit surface format: 0x%x\n", context_surfaces->color_format); + assert(false); + break; + } + + xbaddr source_dma_len, dest_dma_len; + uint8_t *source, *dest; + + source = (uint8_t*)nv_dma_map(context_surfaces->dma_image_source, &source_dma_len); + assert(context_surfaces->source_offset < source_dma_len); + source += context_surfaces->source_offset; + + dest = (uint8_t*)nv_dma_map(context_surfaces->dma_image_dest, &dest_dma_len); + assert(context_surfaces->dest_offset < dest_dma_len); + dest += context_surfaces->dest_offset; + + printf(" - 0x%tx -> 0x%tx\n", source - MM_SYSTEM_PHYSICAL_MAP,dest - MM_SYSTEM_PHYSICAL_MAP); + + int y; + for (y = 0; yheight; y++) { + uint8_t *source_row = source + + (image_blit->in_y + y) * context_surfaces->source_pitch + + image_blit->in_x * bytes_per_pixel; + + uint8_t *dest_row = dest + + (image_blit->out_y + y) * context_surfaces->dest_pitch + + image_blit->out_x * bytes_per_pixel; + + memmove(dest_row, source_row, + image_blit->width * bytes_per_pixel); + } + } + else { + assert(false); + } + + break; + default: + EmuWarning("EmuNV2A: Unknown NV_IMAGE_BLIT Method: 0x%08X\n", method); + } + break; + } + + case NV_KELVIN_PRIMITIVE: { + switch (method) { + case NV097_SET_CONTEXT_DMA_NOTIFIES: + kelvin->dma_notifies = parameter; + break; + case NV097_SET_CONTEXT_DMA_A: + pgraph.dma_a = parameter; + break; + case NV097_SET_CONTEXT_DMA_B: + pgraph.dma_b = parameter; + break; + case NV097_SET_CONTEXT_DMA_STATE: + kelvin->dma_state = parameter; + break; + case NV097_SET_CONTEXT_DMA_COLOR: + printf("TODO: pgraph_update_surface\n"); + /* try to get any straggling draws in before the surface's changed :/ */ + //pgraph_update_surface(d, false, true, true); + + pgraph.dma_color = parameter; + break; + case NV097_SET_CONTEXT_DMA_ZETA: + pgraph.dma_zeta = parameter; + break; + case NV097_SET_CONTEXT_DMA_VERTEX_A: + pgraph.dma_vertex_a = parameter; + break; + case NV097_SET_CONTEXT_DMA_VERTEX_B: + pgraph.dma_vertex_b = parameter; + break; + case NV097_SET_CONTEXT_DMA_SEMAPHORE: + kelvin->dma_semaphore = parameter; + break; + case NV097_SET_CONTEXT_DMA_REPORT: + pgraph.dma_report = parameter; + break; + case NV097_SET_SURFACE_CLIP_HORIZONTAL: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.clip_x = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_X); + pgraph.surface_shape.clip_width = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_WIDTH); + break; + case NV097_SET_SURFACE_CLIP_VERTICAL: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.clip_y = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_Y); + pgraph.surface_shape.clip_height = + GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_HEIGHT); + break; + case NV097_SET_SURFACE_FORMAT: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_shape.color_format = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_COLOR); + pgraph.surface_shape.zeta_format = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ZETA); + pgraph.surface_type = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_TYPE); + pgraph.surface_shape.anti_aliasing = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_ANTI_ALIASING); + pgraph.surface_shape.log_width = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_WIDTH); + pgraph.surface_shape.log_height = + GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_HEIGHT); + break; + case NV097_SET_SURFACE_PITCH: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_color.pitch = + GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR); + pgraph.surface_zeta.pitch = + GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA); + break; + case NV097_SET_SURFACE_COLOR_OFFSET: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_color.offset = parameter; + break; + case NV097_SET_SURFACE_ZETA_OFFSET: + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + pgraph.surface_zeta.offset = parameter; + break; + case NV097_SET_COMBINER_SPECULAR_FOG_CW0: + pgraph.regs[NV_PGRAPH_COMBINESPECFOG0] = parameter; + break; + case NV097_SET_COMBINER_SPECULAR_FOG_CW1: + pgraph.regs[NV_PGRAPH_COMBINESPECFOG1] = parameter; + break; + CASE_4(NV097_SET_TEXTURE_ADDRESS, 64): + slot = (method - NV097_SET_TEXTURE_ADDRESS) / 64; + pgraph.regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; + break; + case NV097_SET_CONTROL0: { + printf("TODO: pgraph_update_surface\n"); + //pgraph_update_surface(d, false, true, true); + + bool stencil_write_enable = + parameter & NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE, + stencil_write_enable); + + uint32_t z_format = GET_MASK(parameter, NV097_SET_CONTROL0_Z_FORMAT); + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_Z_FORMAT, z_format); + + bool z_perspective = + parameter & NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE, + z_perspective); + break; + } + + case NV097_SET_FOG_MODE: { + /* FIXME: There is also NV_PGRAPH_CSV0_D_FOG_MODE */ + unsigned int mode; + switch (parameter) { + case NV097_SET_FOG_MODE_V_LINEAR: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR; break; + case NV097_SET_FOG_MODE_V_EXP: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP; break; + case NV097_SET_FOG_MODE_V_EXP2: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2; break; + case NV097_SET_FOG_MODE_V_EXP_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP_ABS; break; + case NV097_SET_FOG_MODE_V_EXP2_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_EXP2_ABS; break; + case NV097_SET_FOG_MODE_V_LINEAR_ABS: + mode = NV_PGRAPH_CONTROL_3_FOG_MODE_LINEAR_ABS; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOG_MODE, + mode); + break; + } + case NV097_SET_FOG_GEN_MODE: { + unsigned int mode; + switch (parameter) { + case NV097_SET_FOG_GEN_MODE_V_SPEC_ALPHA: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_SPEC_ALPHA; break; + case NV097_SET_FOG_GEN_MODE_V_RADIAL: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_RADIAL; break; + case NV097_SET_FOG_GEN_MODE_V_PLANAR: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_PLANAR; break; + case NV097_SET_FOG_GEN_MODE_V_ABS_PLANAR: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_ABS_PLANAR; break; + case NV097_SET_FOG_GEN_MODE_V_FOG_X: + mode = NV_PGRAPH_CSV0_D_FOGGENMODE_FOG_X; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGGENMODE, mode); + break; + } + case NV097_SET_FOG_ENABLE: + /* + FIXME: There is also: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_FOGENABLE, + parameter); + */ + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_3], NV_PGRAPH_CONTROL_3_FOGENABLE, + parameter); + break; + case NV097_SET_FOG_COLOR: { + /* PGRAPH channels are ARGB, parameter channels are ABGR */ + uint8_t red = GET_MASK(parameter, NV097_SET_FOG_COLOR_RED); + uint8_t green = GET_MASK(parameter, NV097_SET_FOG_COLOR_GREEN); + uint8_t blue = GET_MASK(parameter, NV097_SET_FOG_COLOR_BLUE); + uint8_t alpha = GET_MASK(parameter, NV097_SET_FOG_COLOR_ALPHA); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_RED, red); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_GREEN, green); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_BLUE, blue); + SET_MASK(pgraph.regs[NV_PGRAPH_FOGCOLOR], NV_PGRAPH_FOGCOLOR_ALPHA, alpha); + break; + } + case NV097_SET_ALPHA_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, parameter); + break; + case NV097_SET_BLEND_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EN, parameter); + break; + case NV097_SET_CULL_FACE_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_CULLENABLE, + parameter); + break; + case NV097_SET_DEPTH_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZENABLE, + parameter); + break; + case NV097_SET_DITHER_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_DITHERENABLE, parameter); + break; + case NV097_SET_LIGHTING_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], NV_PGRAPH_CSV0_C_LIGHTING, + parameter); + break; + case NV097_SET_SKIN_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_SKIN, + parameter); + break; + case NV097_SET_STENCIL_TEST_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_POINT_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_LINE_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE, parameter); + break; + case NV097_SET_POLY_OFFSET_FILL_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE, parameter); + break; + case NV097_SET_ALPHA_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAFUNC, parameter & 0xF); + break; + case NV097_SET_ALPHA_REF: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAREF, parameter); + break; + case NV097_SET_BLEND_FUNC_SFACTOR: { + unsigned int factor; + switch (parameter) { + case NV097_SET_BLEND_FUNC_SFACTOR_V_ZERO: + factor = NV_PGRAPH_BLEND_SFACTOR_ZERO; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_DST_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_DST_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_SRC_ALPHA_SATURATE: + factor = NV_PGRAPH_BLEND_SFACTOR_SRC_ALPHA_SATURATE; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_CONSTANT_ALPHA; break; + case NV097_SET_BLEND_FUNC_SFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_SFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; + default: + fprintf(stderr, "Unknown blend source factor: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_SFACTOR, factor); + + break; + } + + case NV097_SET_BLEND_FUNC_DFACTOR: { + unsigned int factor; + switch (parameter) { + case NV097_SET_BLEND_FUNC_DFACTOR_V_ZERO: + factor = NV_PGRAPH_BLEND_DFACTOR_ZERO; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_SRC_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_SRC_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_DST_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_DST_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_DST_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_SRC_ALPHA_SATURATE: + factor = NV_PGRAPH_BLEND_DFACTOR_SRC_ALPHA_SATURATE; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_COLOR: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_COLOR; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_CONSTANT_ALPHA; break; + case NV097_SET_BLEND_FUNC_DFACTOR_V_ONE_MINUS_CONSTANT_ALPHA: + factor = NV_PGRAPH_BLEND_DFACTOR_ONE_MINUS_CONSTANT_ALPHA; break; + default: + fprintf(stderr, "Unknown blend destination factor: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_DFACTOR, factor); + + break; + } + + case NV097_SET_BLEND_COLOR: + pgraph.regs[NV_PGRAPH_BLENDCOLOR] = parameter; + break; + + case NV097_SET_BLEND_EQUATION: { + unsigned int equation; + switch (parameter) { + case NV097_SET_BLEND_EQUATION_V_FUNC_SUBTRACT: + equation = 0; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT: + equation = 1; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_ADD: + equation = 2; break; + case NV097_SET_BLEND_EQUATION_V_MIN: + equation = 3; break; + case NV097_SET_BLEND_EQUATION_V_MAX: + equation = 4; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_REVERSE_SUBTRACT_SIGNED: + equation = 5; break; + case NV097_SET_BLEND_EQUATION_V_FUNC_ADD_SIGNED: + equation = 6; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EQN, equation); + + break; + } + + case NV097_SET_DEPTH_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], NV_PGRAPH_CONTROL_0_ZFUNC, + parameter & 0xF); + break; + + case NV097_SET_COLOR_MASK: { + pgraph.surface_color.write_enabled_cache |= pgraph_color_write_enabled(); + + bool alpha = parameter & NV097_SET_COLOR_MASK_ALPHA_WRITE_ENABLE; + bool red = parameter & NV097_SET_COLOR_MASK_RED_WRITE_ENABLE; + bool green = parameter & NV097_SET_COLOR_MASK_GREEN_WRITE_ENABLE; + bool blue = parameter & NV097_SET_COLOR_MASK_BLUE_WRITE_ENABLE; + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE, alpha); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE, red); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE, green); + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE, blue); + break; + } + case NV097_SET_DEPTH_MASK: + pgraph.surface_zeta.write_enabled_cache |= pgraph_zeta_write_enabled(); + + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ZWRITEENABLE, parameter); + break; + case NV097_SET_STENCIL_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_MASK_WRITE, parameter); + break; + case NV097_SET_STENCIL_FUNC: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_FUNC, parameter & 0xF); + break; + case NV097_SET_STENCIL_FUNC_REF: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_REF, parameter); + break; + case NV097_SET_STENCIL_FUNC_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_1], + NV_PGRAPH_CONTROL_1_STENCIL_MASK_READ, parameter); + break; + case NV097_SET_STENCIL_OP_FAIL: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_FAIL, + kelvin_map_stencil_op(parameter)); + break; + case NV097_SET_STENCIL_OP_ZFAIL: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_ZFAIL, + kelvin_map_stencil_op(parameter)); + break; + case NV097_SET_STENCIL_OP_ZPASS: + SET_MASK(pgraph.regs[NV_PGRAPH_CONTROL_2], + NV_PGRAPH_CONTROL_2_STENCIL_OP_ZPASS, + kelvin_map_stencil_op(parameter)); + break; + + case NV097_SET_POLYGON_OFFSET_SCALE_FACTOR: + pgraph.regs[NV_PGRAPH_ZOFFSETFACTOR] = parameter; + break; + case NV097_SET_POLYGON_OFFSET_BIAS: + pgraph.regs[NV_PGRAPH_ZOFFSETBIAS] = parameter; + break; + case NV097_SET_FRONT_POLYGON_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_FRONTFACEMODE, + kelvin_map_polygon_mode(parameter)); + break; + case NV097_SET_BACK_POLYGON_MODE: + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_BACKFACEMODE, + kelvin_map_polygon_mode(parameter)); + break; + case NV097_SET_CLIP_MIN: + pgraph.regs[NV_PGRAPH_ZCLIPMIN] = parameter; + break; + case NV097_SET_CLIP_MAX: + pgraph.regs[NV_PGRAPH_ZCLIPMAX] = parameter; + break; + case NV097_SET_CULL_FACE: { + unsigned int face; + switch (parameter) { + case NV097_SET_CULL_FACE_V_FRONT: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT; break; + case NV097_SET_CULL_FACE_V_BACK: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_BACK; break; + case NV097_SET_CULL_FACE_V_FRONT_AND_BACK: + face = NV_PGRAPH_SETUPRASTER_CULLCTRL_FRONT_AND_BACK; break; + default: + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_CULLCTRL, + face); + break; + } + case NV097_SET_FRONT_FACE: { + bool ccw; + switch (parameter) { + case NV097_SET_FRONT_FACE_V_CW: + ccw = false; break; + case NV097_SET_FRONT_FACE_V_CCW: + ccw = true; break; + default: + fprintf(stderr, "Unknown front face: 0x%x\n", parameter); + assert(false); + break; + } + SET_MASK(pgraph.regs[NV_PGRAPH_SETUPRASTER], + NV_PGRAPH_SETUPRASTER_FRONTFACE, + ccw ? 1 : 0); + break; + } + case NV097_SET_NORMALIZATION_ENABLE: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_C], + NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE, + parameter); + break; + + case NV097_SET_LIGHT_ENABLE_MASK: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], + NV_PGRAPH_CSV0_D_LIGHTS, + parameter); + break; + + CASE_4(NV097_SET_TEXGEN_S, 16) : { + slot = (method - NV097_SET_TEXGEN_S) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_S + : NV_PGRAPH_CSV1_A_T0_S; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 0)); + break; + } + CASE_4(NV097_SET_TEXGEN_T, 16) : { + slot = (method - NV097_SET_TEXGEN_T) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_T + : NV_PGRAPH_CSV1_A_T0_T; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 1)); + break; + } + CASE_4(NV097_SET_TEXGEN_R, 16) : { + slot = (method - NV097_SET_TEXGEN_R) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_R + : NV_PGRAPH_CSV1_A_T0_R; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 2)); + break; + } + CASE_4(NV097_SET_TEXGEN_Q, 16) : { + slot = (method - NV097_SET_TEXGEN_Q) / 16; + unsigned int reg = (slot < 2) ? NV_PGRAPH_CSV1_A + : NV_PGRAPH_CSV1_B; + unsigned int mask = (slot % 2) ? NV_PGRAPH_CSV1_A_T1_Q + : NV_PGRAPH_CSV1_A_T0_Q; + SET_MASK(pgraph.regs[reg], mask, kelvin_map_texgen(parameter, 3)); + break; + } + CASE_4(NV097_SET_TEXTURE_MATRIX_ENABLE, 4) : + slot = (method - NV097_SET_TEXTURE_MATRIX_ENABLE) / 4; + pgraph.texture_matrix_enable[slot] = parameter; + break; + + case NV097_SET_TEXGEN_VIEW_MODEL: + SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); + break; + default: + if (method >= NV097_SET_COMBINER_ALPHA_ICW && method <= NV097_SET_COMBINER_ALPHA_ICW + 28) { + slot = (method - NV097_SET_COMBINER_ALPHA_ICW) / 4; + pgraph.regs[NV_PGRAPH_COMBINEALPHAI0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_PROJECTION_MATRIX && method <= NV097_SET_PROJECTION_MATRIX + 0x3c) { + slot = (method - NV097_SET_PROJECTION_MATRIX) / 4; + // pg->projection_matrix[slot] = *(float*)¶meter; + unsigned int row = NV_IGRAPH_XF_XFCTX_PMAT0 + slot / 4; + pgraph.vsh_constants[row][slot % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_MODEL_VIEW_MATRIX && method <= NV097_SET_MODEL_VIEW_MATRIX + 0xfc) { + slot = (method - NV097_SET_MODEL_VIEW_MATRIX) / 4; + unsigned int matnum = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_MMAT0 + matnum * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_INVERSE_MODEL_VIEW_MATRIX && method <= NV097_SET_INVERSE_MODEL_VIEW_MATRIX + 0xfc) { + slot = (method - NV097_SET_INVERSE_MODEL_VIEW_MATRIX) / 4; + unsigned int matnum = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_IMMAT0 + matnum * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_COMPOSITE_MATRIX && method <= NV097_SET_COMPOSITE_MATRIX + 0x3c) { + slot = (method - NV097_SET_COMPOSITE_MATRIX) / 4; + unsigned int row = NV_IGRAPH_XF_XFCTX_CMAT0 + slot / 4; + pgraph.vsh_constants[row][slot % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_TEXTURE_MATRIX && method <= NV097_SET_TEXTURE_MATRIX + 0xfc) { + slot = (method - NV097_SET_TEXTURE_MATRIX) / 4; + unsigned int tex = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_T0MAT + tex * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_FOG_PARAMS && method <= NV097_SET_FOG_PARAMS + 8) { + slot = (method - NV097_SET_FOG_PARAMS) / 4; + if (slot < 2) { + pgraph.regs[NV_PGRAPH_FOGPARAM0 + slot * 4] = parameter; + } + else { + /* FIXME: No idea where slot = 2 is */ + } + + pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FOG_K][slot] = parameter; + pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FOG_K] = true; + break; + } + + /* Handles NV097_SET_TEXGEN_PLANE_S,T,R,Q */ + if (method >= NV097_SET_TEXGEN_PLANE_S && method <= NV097_SET_TEXGEN_PLANE_S + 0xfc) { + slot = (method - NV097_SET_TEXGEN_PLANE_S) / 4; + unsigned int tex = slot / 16; + unsigned int entry = slot % 16; + unsigned int row = NV_IGRAPH_XF_XFCTX_TG0MAT + tex * 8 + entry / 4; + pgraph.vsh_constants[row][entry % 4] = parameter; + pgraph.vsh_constants_dirty[row] = true; + break; + } + + if (method >= NV097_SET_FOG_PLANE && method <= NV097_SET_FOG_PLANE + 12) { + slot = (method - NV097_SET_FOG_PLANE) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_FOG][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true; + break; + } + + if (method >= NV097_SET_SCENE_AMBIENT_COLOR && method <= NV097_SET_SCENE_AMBIENT_COLOR + 8) { + slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4; + // ?? + pgraph.ltctxa[NV_IGRAPH_XF_LTCTXA_FR_AMB][slot] = parameter; + pgraph.ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_FR_AMB] = true; + break; + } + + if (method >= NV097_SET_VIEWPORT_OFFSET && method <= NV097_SET_VIEWPORT_OFFSET + 12) { + slot = (method - NV097_SET_VIEWPORT_OFFSET) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPOFF] = true; + break; + } + + if (method >= NV097_SET_EYE_POSITION && method <= NV097_SET_EYE_POSITION + 12) { + slot = (method - NV097_SET_EYE_POSITION) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_EYEP][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_EYEP] = true; + break; + } + + if (method >= NV097_SET_COMBINER_FACTOR0 && method <= NV097_SET_COMBINER_FACTOR0 + 28) { + slot = (method - NV097_SET_COMBINER_FACTOR0) / 4; + pgraph.regs[NV_PGRAPH_COMBINEFACTOR0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_FACTOR1 && method <= NV097_SET_COMBINER_FACTOR1 + 28) { + slot = (method - NV097_SET_COMBINER_FACTOR1) / 4; + pgraph.regs[NV_PGRAPH_COMBINEFACTOR1 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_ALPHA_OCW && method <= NV097_SET_COMBINER_ALPHA_OCW + 28) { + slot = (method - NV097_SET_COMBINER_ALPHA_OCW) / 4; + pgraph.regs[NV_PGRAPH_COMBINEALPHAO0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_COMBINER_COLOR_ICW && method <= NV097_SET_COMBINER_COLOR_ICW + 28) { + slot = (method - NV097_SET_COMBINER_COLOR_ICW) / 4; + pgraph.regs[NV_PGRAPH_COMBINECOLORI0 + slot * 4] = parameter; + break; + } + + if (method >= NV097_SET_VIEWPORT_SCALE && method <= NV097_SET_VIEWPORT_SCALE + 12) { + slot = (method - NV097_SET_VIEWPORT_SCALE) / 4; + pgraph.vsh_constants[NV_IGRAPH_XF_XFCTX_VPSCL][slot] = parameter; + pgraph.vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_VPSCL] = true; + break; + } + + EmuWarning("EmuNV2A: Unknown NV_KELVIN_PRIMITIVE Method: 0x%08X\n", method); + } + break; + } + + default: + EmuWarning("EmuNV2A: Unknown Graphics Class/Method 0x%08X/0x%08X\n", object->graphics_class, method); + break; + } +} + +static void* pfifo_puller_thread() +{ + Cache1State *state = &pfifo.cache1; + + while (true) { + // Scope the lock so that it automatically unlocks at tne end of this block + { + std::unique_lock lk(state->mutex); + + while (state->cache.empty() || !state->pull_enabled) { + state->cache_cond.wait(lk); + } + + // Copy cache to working_cache + while (!state->cache.empty()) { + state->working_cache.push(state->cache.front()); + state->cache.pop(); + } + } + + while (!state->working_cache.empty()) { + CacheEntry* command = state->working_cache.front(); + state->working_cache.pop(); + + if (command->method == 0) { + // qemu_mutex_lock_iothread(); + RAMHTEntry entry = ramht_lookup(command->parameter); + assert(entry.valid); + + assert(entry.channel_id == state->channel_id); + // qemu_mutex_unlock_iothread(); + + switch (entry.engine) { + case ENGINE_GRAPHICS: + pgraph_context_switch(entry.channel_id); + pgraph_wait_fifo_access(); + pgraph_method(command->subchannel, 0, entry.instance); + break; + default: + assert(false); + break; + } + + /* the engine is bound to the subchannel */ + std::lock_guard lk(pfifo.cache1.mutex); + state->bound_engines[command->subchannel] = entry.engine; + state->last_engine = entry.engine; + } else if (command->method >= 0x100) { + /* method passed to engine */ + + uint32_t parameter = command->parameter; + + /* methods that take objects. + * TODO: Check this range is correct for the nv2a */ + if (command->method >= 0x180 && command->method < 0x200) { + //qemu_mutex_lock_iothread(); + RAMHTEntry entry = ramht_lookup(parameter); + assert(entry.valid); + assert(entry.channel_id == state->channel_id); + parameter = entry.instance; + //qemu_mutex_unlock_iothread(); + } + + // qemu_mutex_lock(&state->cache_lock); + enum FIFOEngine engine = state->bound_engines[command->subchannel]; + // qemu_mutex_unlock(&state->cache_lock); + + switch (engine) { + case ENGINE_GRAPHICS: + pgraph_wait_fifo_access(); + pgraph_method(command->subchannel, command->method, parameter); + break; + default: + assert(false); + break; + } + + // qemu_mutex_lock(&state->cache_lock); + state->last_engine = state->bound_engines[command->subchannel]; + // qemu_mutex_unlock(&state->cache_lock); + } + + free(command); + } + } + + return NULL; +} + +DEVICE_READ32(PMC) +{ + DEVICE_READ32_SWITCH() { + case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 + result = 0x02A000A2; + break; + case NV_PMC_INTR_0: + result = pmc.pending_interrupts; + break; + case NV_PMC_INTR_EN_0: + result = pmc.enabled_interrupts; + break; + default: + result = 0; + //DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC); + break; + } + + DEVICE_READ32_END(PMC); +} + +DEVICE_WRITE32(PMC) +{ + switch(addr) { + case NV_PMC_INTR_0: + pmc.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PMC_INTR_EN_0: + pmc.enabled_interrupts = value; + update_irq(); + break; + + default: + //DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC); + break; + } + + DEVICE_WRITE32_END(PMC); +} + + +DEVICE_READ32(PBUS) +{ + DEVICE_READ32_SWITCH() { + case NV_PBUS_PCI_NV_0: + result = 0x10de; // PCI_VENDOR_ID_NVIDIA (?where to return PCI_DEVICE_ID_NVIDIA_NV2A = 0x01b7) + + break; + case NV_PBUS_PCI_NV_1: + result = 1; // NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED + break; + case NV_PBUS_PCI_NV_2: + result = (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1) + break; + + default: + DEBUG_READ32_UNHANDLED(PBUS); // TODO : DEVICE_READ32_REG(pbus); + break; + } + + DEVICE_READ32_END(PBUS); +} + +DEVICE_WRITE32(PBUS) +{ + switch(addr) { + case NV_PBUS_PCI_NV_1: + // TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED) + break; + default: + DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus); + break; + } + + DEVICE_WRITE32_END(PBUS); +} + + +DEVICE_READ32(PFIFO) +{ + DEVICE_READ32_SWITCH() { + case NV_PFIFO_RAMHT: + result = 0x03000100; // = NV_PFIFO_RAMHT_SIZE_4K | NV_PFIFO_RAMHT_BASE_ADDRESS(NumberOfPaddingBytes >> 12) | NV_PFIFO_RAMHT_SEARCH_128 + break; + case NV_PFIFO_RAMFC: + result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ? + break; + case NV_PFIFO_INTR_0: + result = pfifo.pending_interrupts; + break; + case NV_PFIFO_INTR_EN_0: + result = pfifo.enabled_interrupts; + break; + case NV_PFIFO_RUNOUT_STATUS: + result = NV_PFIFO_RUNOUT_STATUS_LOW_MARK; /* low mark empty */ + break; + case NV_PFIFO_CACHE1_PUSH0: + result = pfifo.cache1.push_enabled; + break; + case NV_PFIFO_CACHE1_PUSH1: + SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, pfifo.cache1.channel_id); + SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, pfifo.cache1.mode); + break; + case NV_PFIFO_CACHE1_STATUS: { + std::lock_guard lk(pfifo.cache1.mutex); + + if (pfifo.cache1.cache.empty()) { + result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */ + } + + } break; + case NV_PFIFO_CACHE1_DMA_PUSH: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS, + pfifo.cache1.dma_push_enabled); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, + pfifo.cache1.dma_push_suspended); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_BUFFER, 1); /* buffer emoty */ + break; + case NV_PFIFO_CACHE1_DMA_STATE: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE, + pfifo.cache1.method_nonincreasing); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD, + pfifo.cache1.method >> 2); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, + pfifo.cache1.subchannel); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, + pfifo.cache1.method_count); + SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR, + pfifo.cache1.error); + break; + case NV_PFIFO_CACHE1_DMA_INSTANCE: + SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS, + pfifo.cache1.dma_instance >> 4); + break; + case NV_PFIFO_CACHE1_DMA_PUT: + result = user.channel_control[pfifo.cache1.channel_id].dma_put; + break; + case NV_PFIFO_CACHE1_DMA_GET: + result = user.channel_control[pfifo.cache1.channel_id].dma_get; + break; + case NV_PFIFO_CACHE1_DMA_SUBROUTINE: + result = pfifo.cache1.subroutine_return + | pfifo.cache1.subroutine_active; + break; + case NV_PFIFO_CACHE1_PULL0: { + std::lock_guard lk(pfifo.cache1.mutex); + result = pfifo.cache1.pull_enabled; + } break; + case NV_PFIFO_CACHE1_ENGINE: { + std::lock_guard lk(pfifo.cache1.mutex); + for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { + result |= pfifo.cache1.bound_engines[i] << (i * 2); + } + + } break; + case NV_PFIFO_CACHE1_DMA_DCOUNT: + result = pfifo.cache1.dcount; + break; + case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: + result = pfifo.cache1.get_jmp_shadow; + break; + case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: + result = pfifo.cache1.rsvd_shadow; + break; + case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: + result = pfifo.cache1.data_shadow; + break; + default: + DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO); + break; + } + + DEVICE_READ32_END(PFIFO); +} + +DEVICE_WRITE32(PFIFO) +{ + switch(addr) { + case NV_PFIFO_INTR_0: + pfifo.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PFIFO_INTR_EN_0: + pfifo.enabled_interrupts = value; + update_irq(); + break; + case NV_PFIFO_CACHE1_PUSH0: + pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS; + break; + case NV_PFIFO_CACHE1_PUSH1: + pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID); + pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE); + assert(pfifo.cache1.channel_id < NV2A_NUM_CHANNELS); + break; + case NV_PFIFO_CACHE1_DMA_PUSH: + pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS); + if (pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) { + pfifo.cache1.dma_push_suspended = false; + pfifo_run_pusher(); + } + pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS); + break; + case NV_PFIFO_CACHE1_DMA_STATE: + pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE); + pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2; + pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL); + pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT); + pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR); + break; + case NV_PFIFO_CACHE1_DMA_INSTANCE: + pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS) << 4; + break; + case NV_PFIFO_CACHE1_DMA_PUT: + user.channel_control[pfifo.cache1.channel_id].dma_put = value; + break; + case NV_PFIFO_CACHE1_DMA_GET: + user.channel_control[pfifo.cache1.channel_id].dma_get = value; + break; + case NV_PFIFO_CACHE1_DMA_SUBROUTINE: + pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET); + pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE); + break; + case NV_PFIFO_CACHE1_PULL0: { + std::lock_guard lk(pfifo.cache1.mutex); + + if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS) + && !pfifo.cache1.pull_enabled) { + pfifo.cache1.pull_enabled = true; + + /* the puller thread should wake up */ + pfifo.cache1.cache_cond.notify_all(); + } else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS) + && pfifo.cache1.pull_enabled) { + pfifo.cache1.pull_enabled = false; + } + } break; + case NV_PFIFO_CACHE1_ENGINE: { + std::lock_guard lk(pfifo.cache1.mutex); + + for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) { + pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3); + } + + } break; + case NV_PFIFO_CACHE1_DMA_DCOUNT: + pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE); + break; + case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW: + pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET); + break; + case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW: + pfifo.cache1.rsvd_shadow = value; + break; + case NV_PFIFO_CACHE1_DMA_DATA_SHADOW: + pfifo.cache1.data_shadow = value; + break; + default: + DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO); + break; + } + + DEVICE_WRITE32_END(PFIFO); +} + +DEVICE_READ32(PRMA) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMA); // TODO : DEVICE_READ32_REG(prma); + break; + } + + DEVICE_READ32_END(PRMA); +} + +DEVICE_WRITE32(PRMA) +{ + switch(addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMA); // TODO : DEVICE_WRITE32_REG(prma); + break; + } + + DEVICE_WRITE32_END(PRMA); +} + + +DEVICE_READ32(PVIDEO) +{ + DEVICE_READ32_SWITCH() { + + case NV_PVIDEO_STOP: + result = 0; + break; + default: + DEVICE_READ32_REG(pvideo); + break; + } + + DEVICE_READ32_END(PVIDEO); +} + +DEVICE_WRITE32(PVIDEO) +{ + switch (addr) { + case NV_PVIDEO_BUFFER: + pvideo.regs[addr] = value; + // TODO: vga.enable_overlay = true; + // pvideo_vga_invalidate(d); + break; + case NV_PVIDEO_STOP: + pvideo.regs[NV_PVIDEO_BUFFER] = 0; + // TODO: vga.enable_overlay = false; + //pvideo_vga_invalidate(d); + break; + default: + DEVICE_WRITE32_REG(pvideo); + break; + } + + DEVICE_WRITE32_END(PVIDEO); +} + +DEVICE_READ32(PCOUNTER) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PCOUNTER); // TODO : DEVICE_READ32_REG(pcounter); + break; + } + + DEVICE_READ32_END(PCOUNTER); +} + +DEVICE_WRITE32(PCOUNTER) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PCOUNTER); // TODO : DEVICE_WRITE32_REG(pcounter); + break; + } + + DEVICE_WRITE32_END(PCOUNTER); +} + +static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { + uint32_t low, high; + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + +/* PIMTER - time measurement and time-based alarms */ +static uint32_t ptimer_get_clock() +{ + // Get time in nanoseconds + long int time = static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); + + return muldiv64(time, pramdac.core_clock_freq * ptimer.numerator, CLOCKS_PER_SEC * ptimer.denominator); +} + +DEVICE_READ32(PTIMER) +{ + DEVICE_READ32_SWITCH() { + case NV_PTIMER_INTR_0: + result = ptimer.pending_interrupts; + break; + case NV_PTIMER_INTR_EN_0: + result = ptimer.enabled_interrupts; + break; + case NV_PTIMER_NUMERATOR: + result = ptimer.numerator; + break; + case NV_PTIMER_DENOMINATOR: + result = ptimer.denominator; + break; + case NV_PTIMER_TIME_0: + result = (ptimer_get_clock() & 0x7ffffff) << 5; + break; + case NV_PTIMER_TIME_1: + result = (ptimer_get_clock() >> 27) & 0x1fffffff; + break; + default: + result = 0; + //DEVICE_READ32_REG(ptimer); // Was : DEBUG_READ32_UNHANDLED(PTIMER); + break; + } + + DEVICE_READ32_END(PTIMER); +} + + +DEVICE_WRITE32(PTIMER) +{ + switch (addr) { + + case NV_PTIMER_INTR_0: + ptimer.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PTIMER_INTR_EN_0: + ptimer.enabled_interrupts = value; + update_irq(); + break; + case NV_PTIMER_DENOMINATOR: + ptimer.denominator = value; + break; + case NV_PTIMER_NUMERATOR: + ptimer.numerator = value; + break; + case NV_PTIMER_ALARM_0: + ptimer.alarm_time = value; + break; + default: + //DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER); + break; + } + + DEVICE_WRITE32_END(PTIMER); +} + + +DEVICE_READ32(PVPE) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PVPE); // TODO : DEVICE_READ32_REG(pvpe); + break; + } + + DEVICE_READ32_END(PVPE); +} + + +DEVICE_WRITE32(PVPE) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PVPE); // TODO : DEVICE_WRITE32_REG(pvpe); + break; + } + + DEVICE_WRITE32_END(PVPE); +} + + +DEVICE_READ32(PTV) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PTV); // TODO : DEVICE_READ32_REG(ptv); + break; + } + + DEVICE_READ32_END(PTV); +} + +DEVICE_WRITE32(PTV) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PTV); // TODO : DEVICE_WRITE32_REG(ptv); + break; + } + + DEVICE_WRITE32_END(PTV); +} + + +DEVICE_READ32(PRMFB) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMFB); // TODO : DEVICE_READ32_REG(prmfb); + break; + } + + DEVICE_READ32_END(PRMFB); +} + +DEVICE_WRITE32(PRMFB) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMFB); // TODO : DEVICE_WRITE32_REG(prmfb); + break; + } + + DEVICE_WRITE32_END(PRMFB); +} + + +DEVICE_READ32(PRMVIO) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio); + break; + } + + DEVICE_READ32_END(PRMVIO); +} + +DEVICE_WRITE32(PRMVIO) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio); + break; + } + + DEVICE_WRITE32_END(PRMVIO); +} + + +DEVICE_READ32(PFB) +{ + DEVICE_READ32_SWITCH() { + case NV_PFB_CFG0: + result = 3; // = NV_PFB_CFG0_PART_4 + break; + case NV_PFB_CSTATUS: + { + if (g_bIsChihiro || g_bIsDebug) { result = CONTIGUOUS_MEMORY_CHIHIRO_SIZE; break; } + result = CONTIGUOUS_MEMORY_XBOX_SIZE; + } + break; + case NV_PFB_WBC: + result = 0; // = !NV_PFB_WBC_FLUSH + break; + default: + DEVICE_READ32_REG(pfb); + break; + } + + DEVICE_READ32_END(PFB); +} + +DEVICE_WRITE32(PFB) +{ + switch (addr) { + default: + DEVICE_WRITE32_REG(pfb); + break; + } + + DEVICE_WRITE32_END(PFB); +} + + +DEVICE_READ32(PSTRAPS) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PSTRAPS); + break; + } + + DEVICE_READ32_END(PSTRAPS); +} + +DEVICE_WRITE32(PSTRAPS) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PSTRAPS); + break; + } + + DEVICE_WRITE32_END(PSTRAPS); +} + + +DEVICE_READ32(PGRAPH) +{ + std::lock_guard lk(pgraph.mutex); + + DEVICE_READ32_SWITCH() { + case NV_PGRAPH_INTR: + result = pgraph.pending_interrupts; + break; + case NV_PGRAPH_INTR_EN: + result = pgraph.enabled_interrupts; + break; + case NV_PGRAPH_NSOURCE: + result = pgraph.notify_source; + break; + case NV_PGRAPH_CTX_USER: + SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D, pgraph.context[pgraph.channel_id].channel_3d); + SET_MASK(result, NV_PGRAPH_CTX_USER_CHANNEL_3D_VALID, 1); + SET_MASK(result, NV_PGRAPH_CTX_USER_SUBCH, pgraph.context[pgraph.channel_id].subchannel << 13); + SET_MASK(result, NV_PGRAPH_CTX_USER_CHID, pgraph.channel_id); + break; + case NV_PGRAPH_TRAPPED_ADDR: + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_CHID, pgraph.trapped_channel_id); + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_SUBCH, pgraph.trapped_subchannel); + SET_MASK(result, NV_PGRAPH_TRAPPED_ADDR_MTHD, pgraph.trapped_method); + break; + case NV_PGRAPH_TRAPPED_DATA_LOW: + result = pgraph.trapped_data[0]; + break; + case NV_PGRAPH_FIFO: + SET_MASK(result, NV_PGRAPH_FIFO_ACCESS, pgraph.fifo_access); + break; + case NV_PGRAPH_CHANNEL_CTX_TABLE: + result = pgraph.context_table >> 4; + break; + case NV_PGRAPH_CHANNEL_CTX_POINTER: + result = pgraph.context_address >> 4; + break; + default: + DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH); + } + + DEVICE_READ32_END(PGRAPH); +} + +static void pgraph_set_context_user(uint32_t value) +{ + pgraph.channel_id = (value & NV_PGRAPH_CTX_USER_CHID) >> 24; + pgraph.context[pgraph.channel_id].channel_3d = GET_MASK(value, NV_PGRAPH_CTX_USER_CHANNEL_3D); + pgraph.context[pgraph.channel_id].subchannel = GET_MASK(value, NV_PGRAPH_CTX_USER_SUBCH); +} + +DEVICE_WRITE32(PGRAPH) +{ + std::lock_guard lk(pgraph.mutex); + + switch (addr) { + case NV_PGRAPH_INTR: + pgraph.pending_interrupts &= ~value; + pgraph.interrupt_cond.notify_all(); + break; + case NV_PGRAPH_INTR_EN: + pgraph.enabled_interrupts = value; + break; + case NV_PGRAPH_CTX_CONTROL: + pgraph.channel_valid = (value & NV_PGRAPH_CTX_CONTROL_CHID); + break; + case NV_PGRAPH_CTX_USER: + pgraph_set_context_user(value); + break; + case NV_PGRAPH_INCREMENT: + if (value & NV_PGRAPH_INCREMENT_READ_3D) { + SET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_READ_3D, + (GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_READ_3D) + 1) + % GET_MASK(pgraph.regs[NV_PGRAPH_SURFACE], + NV_PGRAPH_SURFACE_MODULO_3D)); + + pgraph.flip_3d.notify_all(); + } + break; + case NV_PGRAPH_FIFO: + pgraph.fifo_access = GET_MASK(value, NV_PGRAPH_FIFO_ACCESS); + pgraph.fifo_access_cond.notify_all(); + break; + case NV_PGRAPH_CHANNEL_CTX_TABLE: + pgraph.context_table = (value & NV_PGRAPH_CHANNEL_CTX_TABLE_INST) << 4; + break; + case NV_PGRAPH_CHANNEL_CTX_POINTER: + pgraph.context_address = + (value & NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4; + break; + case NV_PGRAPH_CHANNEL_CTX_TRIGGER: + if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) { + printf("PGRAPH: read channel %d context from %0x08X\n", + pgraph.channel_id, pgraph.context_address); + + uint8_t *context_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + pgraph.context_address); + uint32_t context_user = ldl_le_p((uint32_t*)context_ptr); + + printf(" - CTX_USER = 0x%x\n", context_user); + + + pgraph_set_context_user(context_user); + } + if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT) { + /* do stuff ... */ + } + + break; + default: + DEVICE_WRITE32_REG(pgraph); // Was : DEBUG_WRITE32_UNHANDLED(PGRAPH); + break; + } + + DEVICE_WRITE32_END(PGRAPH); +} + + +DEVICE_READ32(PCRTC) +{ + DEVICE_READ32_SWITCH() { + + case NV_PCRTC_INTR_0: + result = pcrtc.pending_interrupts; + break; + case NV_PCRTC_INTR_EN_0: + result = pcrtc.enabled_interrupts; + break; + case NV_PCRTC_START: + result = pcrtc.start; + break; + default: + result = 0; + //DEVICE_READ32_REG(pcrtc); // Was : DEBUG_READ32_UNHANDLED(PCRTC); + break; + } + + DEVICE_READ32_END(PCRTC); +} + +DEVICE_WRITE32(PCRTC) +{ + switch (addr) { + + case NV_PCRTC_INTR_0: + pcrtc.pending_interrupts &= ~value; + update_irq(); + break; + case NV_PCRTC_INTR_EN_0: + pcrtc.enabled_interrupts = value; + update_irq(); + break; + case NV_PCRTC_START: + pcrtc.start = value &= 0x07FFFFFF; + break; + + default: + DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC); + break; + } + + DEVICE_WRITE32_END(PCRTC); +} + + +DEVICE_READ32(PRMCIO) +{ + DEVICE_READ32_SWITCH() { + case VGA_CRT_IM: + case VGA_CRT_IC: + result = prmcio.cr_index; + break; + case VGA_CRT_DM: + case VGA_CRT_DC: + result = prmcio.cr[prmcio.cr_index]; + + printf("vga: read CR%x = 0x%02x\n", prmcio.cr_index, result); + break; + default: + DEBUG_READ32_UNHANDLED(PRMCIO); + printf("vga: UNHANDLED ADDR %s\n", addr); + break; + } + + DEVICE_READ32_END(PRMCIO); +} + +DEVICE_WRITE32(PRMCIO) +{ + switch (addr) { + case VGA_CRT_IM: + case VGA_CRT_IC: + prmcio.cr_index = value; + break; + case VGA_CRT_DM: + case VGA_CRT_DC: + printf("vga: write CR%x = 0x%02x\n", prmcio.cr_index, value); + + /* handle CR0-7 protection */ + if ((prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && + prmcio.cr_index <= VGA_CRTC_OVERFLOW) { + /* can always write bit 4 of CR7 */ + if (prmcio.cr_index == VGA_CRTC_OVERFLOW) { + prmcio.cr[VGA_CRTC_OVERFLOW] = (prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) | + (value & 0x10); + EmuWarning("TODO: vbe_update_vgaregs"); + //vbe_update_vgaregs(); + } + return; + } + + prmcio.cr[prmcio.cr_index] = value; + EmuWarning("TODO: vbe_update_vgaregs"); + //vbe_update_vgaregs(); + + switch (prmcio.cr_index) { + case VGA_CRTC_H_TOTAL: + case VGA_CRTC_H_SYNC_START: + case VGA_CRTC_H_SYNC_END: + case VGA_CRTC_V_TOTAL: + case VGA_CRTC_OVERFLOW: + case VGA_CRTC_V_SYNC_END: + case VGA_CRTC_MODE: + // TODO: s->update_retrace_info(s); + EmuWarning("TODO: update_retrace_info"); + break; + } + break; + default: + DEBUG_WRITE32_UNHANDLED(PRMCIO); // TODO : DEVICE_WRITE32_REG(prmcio); + break; + } + + DEVICE_WRITE32_END(PRMCIO); +} + + +DEVICE_READ32(PRAMDAC) +{ + DEVICE_READ32_SWITCH() { + + case NV_PRAMDAC_NVPLL_COEFF: + result = pramdac.core_clock_coeff; + break; + case NV_PRAMDAC_MPLL_COEFF: + result = pramdac.memory_clock_coeff; + break; + case NV_PRAMDAC_VPLL_COEFF: + result = pramdac.video_clock_coeff; + break; + case NV_PRAMDAC_PLL_TEST_COUNTER: + /* emulated PLLs locked instantly? */ + result = NV_PRAMDAC_PLL_TEST_COUNTER_VPLL2_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK + | NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK; + break; + + default: + //DEVICE_READ32_REG(pramdac); // Was : DEBUG_READ32_UNHANDLED(PRAMDAC); + break; + } + + DEVICE_READ32_END(PRAMDAC); +} + +DEVICE_WRITE32(PRAMDAC) +{ + switch (addr) { + + uint32_t m, n, p; + case NV_PRAMDAC_NVPLL_COEFF: + pramdac.core_clock_coeff = value; + + m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV; + n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV) >> 8; + p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV) >> 16; + + if (m == 0) { + pramdac.core_clock_freq = 0; + } + else { + pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n) + / (1 << p) / m; + } + + break; + case NV_PRAMDAC_MPLL_COEFF: + pramdac.memory_clock_coeff = value; + break; + case NV_PRAMDAC_VPLL_COEFF: + pramdac.video_clock_coeff = value; + break; + + default: + //DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC); + break; + } + + DEVICE_WRITE32_END(PRAMDAC); +} + + +DEVICE_READ32(PRMDIO) +{ + DEVICE_READ32_SWITCH() { + default: + DEBUG_READ32_UNHANDLED(PRMDIO); + break; + } + + DEVICE_READ32_END(PRMDIO); +} + +DEVICE_WRITE32(PRMDIO) +{ + switch (addr) { + default: + DEBUG_WRITE32_UNHANDLED(PRMDIO); + break; + } + + DEVICE_WRITE32_END(PRMDIO); +} + + +DEVICE_READ32(PRAMIN) +{ + DEVICE_READ32_SWITCH() { + default: + DEVICE_READ32_REG(pramin); + break; + } + + DEVICE_READ32_END(PRAMIN); +} + +DEVICE_WRITE32(PRAMIN) +{ + switch (addr) { + default: + DEVICE_WRITE32_REG(pramin); + break; + } + + DEVICE_WRITE32_END(PRAMIN); +} + + +DEVICE_READ32(USER) +{ + unsigned int channel_id = addr >> 16; + assert(channel_id < NV2A_NUM_CHANNELS); + + ChannelControl *control = &user.channel_control[channel_id]; + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + + /* PIO Mode */ + if (!channel_modes & (1 << channel_id)) { + assert(false); + } + + /* DMA Mode */ + addr &= 0xFFFF; + DEVICE_READ32_SWITCH() { + case NV_USER_DMA_PUT: + result = control->dma_put; + break; + case NV_USER_DMA_GET: + result = control->dma_get; + break; + case NV_USER_REF: + result = control->ref; + break; + default: + DEBUG_READ32_UNHANDLED(USER); + break; + } + + DEVICE_READ32_END(USER); +} + +DEVICE_WRITE32(USER) +{ + unsigned int channel_id = addr >> 16; + assert(channel_id < NV2A_NUM_CHANNELS); + + ChannelControl *control = &user.channel_control[channel_id]; + + uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE]; + + if (channel_modes & (1 << channel_id)) { + /* DMA Mode */ + switch (addr & 0xFFFF) { + case NV_USER_DMA_PUT: + control->dma_put = value; + + if (pfifo.cache1.push_enabled) { + pfifo_run_pusher(); + } + break; + case NV_USER_DMA_GET: + control->dma_get = value; + break; + case NV_USER_REF: + control->ref = value; + break; + default: + DEBUG_WRITE32_UNHANDLED(USER); + break; + } + } + else { + /* PIO Mode */ + assert(false); + } + + DEVICE_WRITE32_END(USER); +} + + +typedef struct NV2ABlockInfo { + uint32_t offset; + uint32_t size; + uint32_t(*read)(xbaddr addr); + void(*write)(xbaddr addr, uint32_t value); +} NV2ABlockInfo; + +static const NV2ABlockInfo regions[] = {{ + /* card master control */ + NV_PMC_ADDR, // = 0x000000 + NV_PMC_SIZE, // = 0x001000 + EmuNV2A_PMC_Read32, + EmuNV2A_PMC_Write32, + }, { + /* bus control */ + NV_PBUS_ADDR, // = 0x001000 + NV_PBUS_SIZE, // = 0x001000 + EmuNV2A_PBUS_Read32, + EmuNV2A_PBUS_Write32, + }, { + /* MMIO and DMA FIFO submission to PGRAPH and VPE */ + NV_PFIFO_ADDR, // = 0x002000 + NV_PFIFO_SIZE, // = 0x002000 + EmuNV2A_PFIFO_Read32, + EmuNV2A_PFIFO_Write32, + }, { + /* access to BAR0/BAR1 from real mode */ + NV_PRMA_ADDR, // = 0x007000 + NV_PRMA_SIZE, // = 0x001000 + EmuNV2A_PRMA_Read32, + EmuNV2A_PRMA_Write32, + }, { + /* video overlay */ + NV_PVIDEO_ADDR, // = 0x008000 + NV_PVIDEO_SIZE, // = 0x001000 + EmuNV2A_PVIDEO_Read32, + EmuNV2A_PVIDEO_Write32, + }, { + /* time measurement and time-based alarms */ + NV_PTIMER_ADDR, // = 0x009000 + NV_PTIMER_SIZE, // = 0x001000 + EmuNV2A_PTIMER_Read32, + EmuNV2A_PTIMER_Write32, + }, { + /* performance monitoring counters */ + NV_PCOUNTER_ADDR, // = 0x00a000 + NV_PCOUNTER_SIZE, // = 0x001000 + EmuNV2A_PCOUNTER_Read32, + EmuNV2A_PCOUNTER_Write32, + }, { + /* MPEG2 decoding engine */ + NV_PVPE_ADDR, // = 0x00b000 + NV_PVPE_SIZE, // = 0x001000 + EmuNV2A_PVPE_Read32, + EmuNV2A_PVPE_Write32, + }, { + /* TV encoder */ + NV_PTV_ADDR, // = 0x00d000 + NV_PTV_SIZE, // = 0x001000 + EmuNV2A_PTV_Read32, + EmuNV2A_PTV_Write32, + }, { + /* aliases VGA memory window */ + NV_PRMFB_ADDR, // = 0x0a0000 + NV_PRMFB_SIZE, // = 0x020000 + EmuNV2A_PRMFB_Read32, + EmuNV2A_PRMFB_Write32, + }, { + /* aliases VGA sequencer and graphics controller registers */ + NV_PRMVIO_ADDR, // = 0x0c0000 + NV_PRMVIO_SIZE, // = 0x001000 + EmuNV2A_PRMVIO_Read32, + EmuNV2A_PRMVIO_Write32, + },{ + /* memory interface */ + NV_PFB_ADDR, // = 0x100000 + NV_PFB_SIZE, // = 0x001000 + EmuNV2A_PFB_Read32, + EmuNV2A_PFB_Write32, + }, { + /* straps readout / override */ + NV_PSTRAPS_ADDR, // = 0x101000 + NV_PSTRAPS_SIZE, // = 0x001000 + EmuNV2A_PSTRAPS_Read32, + EmuNV2A_PSTRAPS_Write32, + }, { + /* accelerated 2d/3d drawing engine */ + NV_PGRAPH_ADDR, // = 0x400000 + NV_PGRAPH_SIZE, // = 0x002000 + EmuNV2A_PGRAPH_Read32, + EmuNV2A_PGRAPH_Write32, + }, { + /* more CRTC controls */ + NV_PCRTC_ADDR, // = 0x600000 + NV_PCRTC_SIZE, // = 0x001000 + EmuNV2A_PCRTC_Read32, + EmuNV2A_PCRTC_Write32, + }, { + /* aliases VGA CRTC and attribute controller registers */ + NV_PRMCIO_ADDR, // = 0x601000 + NV_PRMCIO_SIZE, // = 0x001000 + EmuNV2A_PRMCIO_Read32, + EmuNV2A_PRMCIO_Write32, + }, { + /* RAMDAC, cursor, and PLL control */ + NV_PRAMDAC_ADDR, // = 0x680000 + NV_PRAMDAC_SIZE, // = 0x001000 + EmuNV2A_PRAMDAC_Read32, + EmuNV2A_PRAMDAC_Write32, + }, { + /* aliases VGA palette registers */ + NV_PRMDIO_ADDR, // = 0x681000 + NV_PRMDIO_SIZE, // = 0x001000 + EmuNV2A_PRMDIO_Read32, + EmuNV2A_PRMDIO_Write32, + }, { + /* RAMIN access */ + NV_PRAMIN_ADDR, // = 0x700000 + NV_PRAMIN_SIZE, // = 0x100000 + EmuNV2A_PRAMIN_Read32, + EmuNV2A_PRAMIN_Write32, + },{ + /* PFIFO MMIO and DMA submission area */ + NV_USER_ADDR, // = 0x800000, + NV_USER_SIZE, // = 0x800000, + EmuNV2A_USER_Read32, + EmuNV2A_USER_Write32, + }, { + 0xFFFFFFFF, + 0, + nullptr, + nullptr, + }, +}; + +const NV2ABlockInfo* EmuNV2A_Block(xbaddr addr) +{ + // Find the block in the block table + const NV2ABlockInfo* block = ®ions[0]; + int i = 0; + + while (block->read != nullptr) { + if (addr >= block->offset && addr < block->offset + block->size) { + return block; + } + + block = ®ions[++i]; + } + + return nullptr; +} + +uint32_t EmuNV2A_Read(xbaddr addr, int size) +{ + const NV2ABlockInfo* block = EmuNV2A_Block(addr); + + if (block != nullptr) { + switch (size) { + case sizeof(uint8_t): + return block->read(addr - block->offset) & 0xFF; + case sizeof(uint16_t) : + return block->read(addr - block->offset) & 0xFFFF; + case sizeof(uint32_t) : + return block->read(addr - block->offset); + default: + EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); + return 0; + } + } + + EmuWarning("EmuNV2A_Read%d: Unhandled Read Address %08X", size, addr); + return 0; +} + +void EmuNV2A_Write(xbaddr addr, uint32_t value, int size) +{ + const NV2ABlockInfo* block = EmuNV2A_Block(addr); + + if (block != nullptr) { + int shift = 0; + xbaddr aligned_addr = 0; + uint32_t aligned_value = 0; + uint32_t mask = 0; + switch (size) { + case sizeof(uint8_t) : + shift = (addr & 3) * 8; + aligned_addr = addr & ~3; + aligned_value = block->read(aligned_addr - block->offset); + mask = 0xFF << shift; + + // TODO : Must the second byte be written to the next DWORD? + block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); + return; + case sizeof(uint16_t) : + assert((addr & 1) == 0); + + shift = (addr & 2) * 16; + aligned_addr = addr & ~3; + aligned_value = block->read(addr - block->offset); + mask = 0xFFFF << shift; + + // TODO : Must the second byte be written to the next DWORD? + block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); + return; + case sizeof(uint32_t) : + block->write(addr - block->offset, value); + return; + default: + EmuWarning("EmuNV2A_Read: Invalid read size: %d", size); + return; + } + } + + EmuWarning("EmuNV2A_Write%d: Unhandled Write Address %08X (value %08X)", size, addr, value); + return; +} + +// +// OPENGL +// + +// +#define X_D3DTS_STAGECOUNT 4 + +HDC g_EmuWindowsDC = 0; +GLuint VertexProgramIDs[4] = { 0, 0, 0, 0 }; +uint ActiveVertexProgramID = 0; +GLuint TextureIDs[X_D3DTS_STAGECOUNT]= { 0, 0, 0, 0 }; + +// Vertex shader header, mapping Xbox1 registers to the ARB syntax (original version by KingOfC). +// Note about the use of 'conventional' attributes in here: Since we prefer to use only one shader +// for both immediate and deferred mode rendering, we alias all attributes to conventional inputs +// as much as possible. Only when there's no conventional attribute available, we use generic attributes. +// So in the following header, we use conventional attributes first, and generic attributes for the +// rest of the vertex attribute slots. This makes it possible to support immediate and deferred mode +// rendering with the same shader, and the use of the OpenGL fixed-function pipeline without a shader. +std::string DxbxVertexShaderHeader = + "!!ARBvp1.0\n" + "TEMP R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12;\n" + "ADDRESS A0;\n" +#ifdef DXBX_OPENGL_CONVENTIONAL + "ATTRIB v0 = vertex.position;\n" // Was: vertex.attrib[0] (See "conventional" note above) + "ATTRIB v1 = vertex.%s;\n" // Note : We replace this with "weight" or "attrib[1]" depending GL_ARB_vertex_blend + "ATTRIB v2 = vertex.normal;\n" // Was: vertex.attrib[2] + "ATTRIB v3 = vertex.color.primary;\n" // Was: vertex.attrib[3] + "ATTRIB v4 = vertex.color.secondary;\n" // Was: vertex.attrib[4] + "ATTRIB v5 = vertex.fogcoord;\n" // Was: vertex.attrib[5] + "ATTRIB v6 = vertex.attrib[6];\n" + "ATTRIB v7 = vertex.attrib[7];\n" + "ATTRIB v8 = vertex.texcoord[0];\n" // Was: vertex.attrib[8] + "ATTRIB v9 = vertex.texcoord[1];\n" // Was: vertex.attrib[9] + "ATTRIB v10 = vertex.texcoord[2];\n" // Was: vertex.attrib[10] + "ATTRIB v11 = vertex.texcoord[3];\n" // Was: vertex.attrib[11] +#else + "ATTRIB v0 = vertex.attrib[0];\n" + "ATTRIB v1 = vertex.attrib[1];\n" + "ATTRIB v2 = vertex.attrib[2];\n" + "ATTRIB v3 = vertex.attrib[3];\n" + "ATTRIB v4 = vertex.attrib[4];\n" + "ATTRIB v5 = vertex.attrib[5];\n" + "ATTRIB v6 = vertex.attrib[6];\n" + "ATTRIB v7 = vertex.attrib[7];\n" + "ATTRIB v8 = vertex.attrib[8];\n" + "ATTRIB v9 = vertex.attrib[9];\n" + "ATTRIB v10 = vertex.attrib[10];\n" + "ATTRIB v11 = vertex.attrib[11];\n" +#endif + "ATTRIB v12 = vertex.attrib[12];\n" + "ATTRIB v13 = vertex.attrib[13];\n" + "ATTRIB v14 = vertex.attrib[14];\n" + "ATTRIB v15 = vertex.attrib[15];\n" + "OUTPUT oPos = result.position;\n" + "OUTPUT oD0 = result.color.front.primary;\n" + "OUTPUT oD1 = result.color.front.secondary;\n" + "OUTPUT oB0 = result.color.back.primary;\n" + "OUTPUT oB1 = result.color.back.secondary;\n" + "OUTPUT oPts = result.pointsize;\n" + "OUTPUT oFog = result.fogcoord;\n" + "OUTPUT oT0 = result.texcoord[0];\n" + "OUTPUT oT1 = result.texcoord[1];\n" + "OUTPUT oT2 = result.texcoord[2];\n" + "OUTPUT oT3 = result.texcoord[3];\n" + "PARAM c[] = { program.env[0..191] };\n" // All constants in 1 array declaration (requires NV_gpu_program4?) + "PARAM mvp[4] = { state.matrix.mvp };\n"; + +void SetupPixelFormat(HDC DC) +{ + const PIXELFORMATDESCRIPTOR pfd = { + /* .nSize = */ sizeof(PIXELFORMATDESCRIPTOR), // size + /* .nVersion = */ 1, // version + /* .dwFlags = */ PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, // support double-buffering + /* .iPixelType = */ PFD_TYPE_RGBA, // color type + /* .cColorBits = */ 32, // preferred color depth + /* .cRedBits = */ 0, + /* .cRedShift = */ 0, // color bits (ignored) + /* .cGreenBits = */ 0, + /* .cGreenShift = */ 0, + /* .cBlueBits = */ 0, + /* .cBlueShift = */ 0, + /* .cAlphaBits = */ 0, + /* .cAlphaShift = */ 0, // no alpha buffer + /* .cAccumBits = */ 0, + /* .cAccumRedBits = */ 0, // no accumulation buffer, + /* .cAccumGreenBits = */ 0, // accum bits (ignored) + /* .cAccumBlueBits = */ 0, + /* .cAccumAlphaBits = */ 0, + /* .cDepthBits = */ 16, // depth buffer + /* .cStencilBits = */ 0, // no stencil buffer + /* .cAuxBuffers = */ 0, // no auxiliary buffers + /* .iLayerType= */ PFD_MAIN_PLANE, // main layer + /* .bReserved = */ 0, + /* .dwLayerMask = */ 0, + /* .dwVisibleMask = */ 0, + /* .dwDamageMask = */ 0 // no layer, visible, damage masks + }; + + int PixelFormat = ChoosePixelFormat(DC, &pfd); + if (PixelFormat == 0) + return; + + if (SetPixelFormat(DC, PixelFormat, &pfd) != TRUE) + return; +} + +// From https://github.com/inolen/redream/blob/master/src/video/gl_backend.c +static int rb_compile_shader(const char *source, GLenum shader_type, GLuint *shader) +{ + size_t sourceLength = strlen(source); + + *shader = glCreateShader(shader_type); + glShaderSource(*shader, 1, (const GLchar **)&source, + (const GLint *)&sourceLength); + glCompileShader(*shader); + + GLint compiled; + glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { +// rb_print_shader_log(*shader); + glDeleteShader(*shader); + return 0; + } + + return 1; +} + +void DxbxCompileShader(std::string Shader) +{ + int GLErrorPos; + +// if (MayLog(lfUnit)) +// DbgPrintf(" NV2A: New vertex program :\n" + Shader); + +/* +glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, Shader.size(), Shader.c_str()); + + // errors are catched + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &GLErrorPos); + */ + GLuint shader; + + GLErrorPos = rb_compile_shader(Shader.c_str(), GL_VERTEX_SHADER, &shader); // TODO : GL_VERTEX_SHADER_ARB ?? + /* + if (GLErrorPos > 0) + { + Shader.insert(GLErrorPos, "{ERROR}"); + EmuWarning("Program error at position %d:", GLErrorPos); + EmuWarning((char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)); + EmuWarning(Shader.c_str()); + } + */ +} +void InitOpenGLContext() +{ + HGLRC RC; + std::string szCode; + + g_EmuWindowsDC = GetDC(g_hEmuWindow); // Actually, you can use any windowed control here + SetupPixelFormat(g_EmuWindowsDC); + + RC = wglCreateContext(g_EmuWindowsDC); // makes OpenGL window out of DC + wglMakeCurrent(g_EmuWindowsDC, RC); // makes OpenGL window active + //ReadImplementationProperties(); // Determine a set of booleans indicating which OpenGL extensions are available + //ReadExtensions(); // Assign all OpenGL extension API's (DON'T call them if the extension is not available!) + + // Initialize the viewport : + //Viewport.X = 0; + //Viewport.Y = 0; + //Viewport.Width = g_EmuCDPD.pPresentationParameters.BackBufferWidth; + //Viewport.Height = g_EmuCDPD.pPresentationParameters.BackBufferHeight; + //Viewport.MinZ = -1.0; + //Viewport.MaxZ = 1.0; + + //DxbxUpdateTransformProjection(); + //DxbxUpdateViewport(); + + + //glutInit(); + { // rb_init_context(); + /* link in gl functions at runtime */ + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (err != GLEW_OK) { + EmuWarning("GLEW initialization failed: %s", glewGetErrorString(err)); + return; + } + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + // Switch to left-handed coordinate space (as per http://www.opengl.org/resources/faq/technical/transformations.htm) : + // glScalef(1.0, 1.0, -1.0); + + // Set some defaults : + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); // Nearer Z coordinates cover further Z + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glAlphaFunc(GL_GEQUAL, 0.5); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // GL_LINE for wireframe + +/* + // TODO : The following code only works on cards that support the + // vertex program extensions (NVidia cards mainly); So for ATI we + // have to come up with another solution !!! + glGenProgramsARB(4, &VertexProgramIDs[0]); +*/ + +#ifdef DXBX_OPENGL_CONVENTIONAL + if (GL_ARB_vertex_blend) + DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "weight"); + else + DxbxVertexShaderHeader = sprintf(DxbxVertexShaderHeader, "attrib[1]"); +#endif + + // Precompiled shader for the fixed function pipeline : + szCode = DxbxVertexShaderHeader + + "# This part adjusts the vertex position by the super-sampling scale & offset :\n" + "MOV R0, v0;\n" + "RCP R0.w, R0.w;\n" + "MUL R0, R0, c[0];\n" // c[-96] in D3D speak - applies SuperSampleScale + // Note : Use R12 instead of oPos because this is not yet the final assignment : + "ADD R12, R0, c[1];\n" // c[-95] in D3D speak - applies SuperSampleOffset + + "# This part just reads all other components and passes them to the output :\n" + "MOV oD0, v3;\n" + "MOV oD1, v4;\n" + "MOV oFog, v4.w;\n" // specular fog + // "MOV oFog, v0.z;\n" // z fog + // "RCP oFog, v0.w;\n" // w fog + "MOV oPts, v1.x;\n" + "MOV oB0, v7;\n" + "MOV oB1, v8;\n" + "MOV oT0, v9;\n" + "MOV oT1, v10;\n" + "MOV oT2, v11;\n" + "MOV oT3, v12;\n" + + "# This part applies the screen-space transform (not present when '#pragma screenspace' was used) :\n" + "MUL R12.xyz, R12, c[58];\n" // c[-38] in D3D speak - see EmuNV2A_ViewportScale, + "RCP R1.x, R12.w;\n" // Originally RCC, but that"s not supported in ARBvp1.0 (use "MIN R1, R1, 0" and "MAX R1, R1, 1"?) + "MAD R12.xyz, R12, R1.x, c[59];\n" // c[-37] in D3D speak - see EmuNV2A_ViewportOffset + + "# Dxbx addition : Transform the vertex to clip coordinates :\n" + "DP4 R0.x, mvp[0], R12;\n" + "DP4 R0.y, mvp[1], R12;\n" + "DP4 R0.z, mvp[2], R12;\n" + "DP4 R0.w, mvp[3], R12;\n" + "MOV R12, R0;\n" + + "# Apply Z coord mapping\n" + "ADD R12.z, R12.z, R12.z;\n" + "ADD R12.z, R12.z, -R12.w;\n" + + "# Here""s the final assignment to oPos :\n" + "MOV oPos, R12;\n" + "END\n"; // TODO : Check if newline is required? + +// glBindProgramARB(GL_VERTEX_PROGRAM_ARB, VertexProgramIDs[0]); + DxbxCompileShader(szCode); +} + +// HACK: Until we implement VGA/proper interrupt generation +// we simulate VBLANK by calling the interrupt at 60Hz +std::thread vblank_thread; +extern std::chrono::time_point> GetNextVBlankTime(); +static void nv2a_vblank_thread() +{ + auto nextVBlankTime = GetNextVBlankTime(); + + while (true) { + // Handle VBlank + if (std::chrono::steady_clock::now() > nextVBlankTime) { + pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK; + update_irq(); + nextVBlankTime = GetNextVBlankTime(); + } + } +} + +void EmuNV2A_Init() +{ + // Allocate PRAMIN Region + VirtualAlloc((void*)(NV2A_ADDR + NV_PRAMIN_ADDR), NV_PRAMIN_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + pcrtc.start = 0; + + pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */ + pramdac.core_clock_freq = 189000000; + pramdac.memory_clock_coeff = 0; + pramdac.video_clock_coeff = 0x0003C20D; /* 25182Khz...? */ + + pfifo.puller_thread = std::thread(pfifo_puller_thread); + + // Only spawn VBlank thread when LLE is enabled + if (bLLE_GPU) { + vblank_thread = std::thread(nv2a_vblank_thread);; + } +} diff --git a/src/CxbxKrnl/EmuNV2A.h b/src/devices/video/EmuNV2A.h similarity index 100% rename from src/CxbxKrnl/EmuNV2A.h rename to src/devices/video/EmuNV2A.h diff --git a/src/CxbxKrnl/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp similarity index 96% rename from src/CxbxKrnl/devices/video/nv2a.cpp rename to src/devices/video/nv2a.cpp index 3ea6c6972..25309a8e4 100644 --- a/src/CxbxKrnl/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -38,8 +38,8 @@ #define LOG_PREFIX "NV2A" -#include "../../CxbxKrnl/CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc -#include "../../CxbxKrnl/EmuNV2A.h" // For now, use EmuNV2A +#include "CxbxKrnl\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc +#include "EmuNV2A.h" // For now, use EmuNV2A #include "nv2a.h" diff --git a/src/CxbxKrnl/devices/video/nv2a.h b/src/devices/video/nv2a.h similarity index 97% rename from src/CxbxKrnl/devices/video/nv2a.h rename to src/devices/video/nv2a.h index be6c90324..1c35c7d8c 100644 --- a/src/CxbxKrnl/devices/video/nv2a.h +++ b/src/devices/video/nv2a.h @@ -34,7 +34,7 @@ // ****************************************************************** #pragma once -#include "../../CxbxKrnl/PCIDevice.h" // For PCIDevice +#include "devices\PCIDevice.h" // For PCIDevice #define NV2A_ADDR 0xFD000000 #define NV2A_SIZE 0x01000000 diff --git a/src/CxbxKrnl/nv2a_int.h b/src/devices/video/nv2a_int.h similarity index 100% rename from src/CxbxKrnl/nv2a_int.h rename to src/devices/video/nv2a_int.h diff --git a/src/CxbxKrnl/vga.h b/src/devices/video/vga.h similarity index 100% rename from src/CxbxKrnl/vga.h rename to src/devices/video/vga.h From 7eb82e0b53ecf3cc7109e3ebbbc8d253bf4e3298 Mon Sep 17 00:00:00 2001 From: blueshogun96 Date: Sun, 21 Jan 2018 15:38:34 -0800 Subject: [PATCH 10/37] Removed duplocate code --- src/CxbxKrnl/EmuFile.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/CxbxKrnl/EmuFile.cpp b/src/CxbxKrnl/EmuFile.cpp index 60f6b5b9e..72662e924 100644 --- a/src/CxbxKrnl/EmuFile.cpp +++ b/src/CxbxKrnl/EmuFile.cpp @@ -445,16 +445,6 @@ NTSTATUS CxbxConvertFilePath( else printf(" New:\"$XbePath\\%s\"\n", RelativePath.c_str()); } - - if (g_bPrintfOn) { - DbgPrintf("FILE: %s Corrected path...\n", aFileAPIName.c_str()); - printf(" Org:\"%s\"\n", OriginalPath.c_str()); - if (_strnicmp(HostPath.c_str(), CxbxBasePath.c_str(), CxbxBasePath.length()) == 0) { - printf(" New:\"$CxbxPath\\%s%s\"\n", (HostPath.substr(CxbxBasePath.length(), std::string::npos)).c_str(), RelativePath.c_str()); - } - else - printf(" New:\"$XbePath\\%s\"\n", RelativePath.c_str()); - } } else { From 4a3965d6445aaed1c8658eaf0b5fb61ba1fe793c Mon Sep 17 00:00:00 2001 From: Fisherman166 Date: Sat, 20 Jan 2018 14:36:59 -0800 Subject: [PATCH 11/37] Move Xbe dumping into its own class. Add game ratings string printout for issue #686. Cleanup GUI code so that the Xbe Printer is responsible for outputting Xbe info --- src/Common/Xbe.cpp | 724 +++++++++++++++++++++++++++---------------- src/Common/Xbe.h | 55 +++- src/Cxbx/WndMain.cpp | 46 +-- 3 files changed, 515 insertions(+), 310 deletions(-) diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index dee7364c1..0e3293f98 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -37,11 +37,13 @@ #include "CxbxVersion.h" #include "CxbxUtil.h" -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include #define PAGE_SIZE 0x1000 @@ -548,281 +550,32 @@ static char *BetterTime(uint32 x_timeDate) return x_ctime; } -// dump Xbe information to text file -void Xbe::DumpInformation(FILE *x_file) +bool Xbe::DumpInformationToFile(std::string out_filename) +{ + if(HasError()) { + return false; + } + + bool success = false; + XbePrinter printer(this); + std::ofstream out_file(out_filename); + if(out_file.is_open()) { + out_file << printer.GenXbeInfo(); + out_file.close(); + success = true; + } + return success; +} + +void Xbe::DumpInformationToConsole() { if(HasError()) return; - fprintf(x_file, "XBE information generated by Cxbx-Reloaded (Version " _CXBX_VERSION ")\n"); - fprintf(x_file, "\n"); - fprintf(x_file, "Title identified as \"%s\"\n", m_szAsciiTitle); - fprintf(x_file, "\n"); - fprintf(x_file, "Dumping XBE file header...\n"); - fprintf(x_file, "\n"); - fprintf(x_file, "Magic Number : XBEH\n"); - - // print digital signature - { - fprintf(x_file, "Digitial Signature : "); - for(int y=0;y<16;y++) - { - fprintf(x_file, "\n "); - for(int x=0;x<16;x++) - fprintf(x_file, "%.02X", m_Header.pbDigitalSignature[y*16+x]); - } - fprintf(x_file, "\n \n"); - } - - fprintf(x_file, "Base Address : 0x%.08X\n", m_Header.dwBaseAddr); - fprintf(x_file, "Size of Headers : 0x%.08X\n", m_Header.dwSizeofHeaders); - fprintf(x_file, "Size of Image : 0x%.08X\n", m_Header.dwSizeofImage); - fprintf(x_file, "Size of Image Header : 0x%.08X\n", m_Header.dwSizeofImageHeader); - fprintf(x_file, "TimeDate Stamp : 0x%.08X (%s)\n", m_Header.dwTimeDate, BetterTime(m_Header.dwTimeDate)); - fprintf(x_file, "Certificate Address : 0x%.08X\n", m_Header.dwCertificateAddr); - fprintf(x_file, "Number of Sections : 0x%.08X\n", m_Header.dwSections); - fprintf(x_file, "Section Headers Address : 0x%.08X\n", m_Header.dwSectionHeadersAddr); - - // print init flags - { - fprintf(x_file, "Init Flags : 0x%.08X ", m_Header.dwInitFlags_value); - - if(m_Header.dwInitFlags.bMountUtilityDrive) - fprintf(x_file, "[Mount Utility Drive] "); - - if(m_Header.dwInitFlags.bFormatUtilityDrive) - fprintf(x_file, "[Format Utility Drive] "); - - if(m_Header.dwInitFlags.bLimit64MB) - fprintf(x_file, "[Limit Devkit Run Time Memory to 64MB] "); - - if(!m_Header.dwInitFlags.bDontSetupHarddisk) - fprintf(x_file, "[Setup Harddisk] "); - - fprintf(x_file, "\n"); - } - - char AsciiFilename[40]; - - setlocale( LC_ALL, "English" ); - - const wchar_t *wszFilename = (const wchar_t *)GetAddr(m_Header.dwDebugUnicodeFilenameAddr); - - if(wszFilename != NULL) - wcstombs(AsciiFilename, wszFilename, 40); - else - AsciiFilename[0] = '\0'; - - fprintf(x_file, "Entry Point : 0x%.08X (Retail: 0x%.08X, Debug: 0x%.08X)\n", m_Header.dwEntryAddr, m_Header.dwEntryAddr ^ XOR_EP_RETAIL, m_Header.dwEntryAddr ^ XOR_EP_DEBUG); - fprintf(x_file, "TLS Address : 0x%.08X\n", m_Header.dwTLSAddr); - fprintf(x_file, "(PE) Stack Commit : 0x%.08X\n", m_Header.dwPeStackCommit); - fprintf(x_file, "(PE) Heap Reserve : 0x%.08X\n", m_Header.dwPeHeapReserve); - fprintf(x_file, "(PE) Heap Commit : 0x%.08X\n", m_Header.dwPeHeapCommit); - fprintf(x_file, "(PE) Base Address : 0x%.08X\n", m_Header.dwPeBaseAddr); - fprintf(x_file, "(PE) Size of Image : 0x%.08X\n", m_Header.dwPeSizeofImage); - fprintf(x_file, "(PE) Checksum : 0x%.08X\n", m_Header.dwPeChecksum); - fprintf(x_file, "(PE) TimeDate Stamp : 0x%.08X (%s)\n", m_Header.dwPeTimeDate, BetterTime(m_Header.dwPeTimeDate)); - fprintf(x_file, "Debug Pathname Address : 0x%.08X (\"%s\")\n", m_Header.dwDebugPathnameAddr, GetAddr(m_Header.dwDebugPathnameAddr)); - fprintf(x_file, "Debug Filename Address : 0x%.08X (\"%s\")\n", m_Header.dwDebugFilenameAddr, GetAddr(m_Header.dwDebugFilenameAddr)); - fprintf(x_file, "Debug Unicode filename Address : 0x%.08X (L\"%s\")\n", m_Header.dwDebugUnicodeFilenameAddr, AsciiFilename); - fprintf(x_file, "Kernel Image Thunk Address : 0x%.08X (Retail: 0x%.08X, Debug: 0x%.08X)\n", m_Header.dwKernelImageThunkAddr, m_Header.dwKernelImageThunkAddr ^ XOR_KT_RETAIL, m_Header.dwKernelImageThunkAddr ^ XOR_KT_DEBUG); - fprintf(x_file, "NonKernel Import Dir Address : 0x%.08X\n", m_Header.dwNonKernelImportDirAddr); - fprintf(x_file, "Library Versions : 0x%.08X\n", m_Header.dwLibraryVersions); - fprintf(x_file, "Library Versions Address : 0x%.08X\n", m_Header.dwLibraryVersionsAddr); - fprintf(x_file, "Kernel Library Version Address : 0x%.08X\n", m_Header.dwKernelLibraryVersionAddr); - fprintf(x_file, "XAPI Library Version Address : 0x%.08X\n", m_Header.dwXAPILibraryVersionAddr); - fprintf(x_file, "Logo Bitmap Address : 0x%.08X\n", m_Header.dwLogoBitmapAddr); - fprintf(x_file, "Logo Bitmap Size : 0x%.08X\n", m_Header.dwSizeofLogoBitmap); - fprintf(x_file, "\n"); - fprintf(x_file, "Dumping XBE Certificate...\n"); - fprintf(x_file, "\n"); - fprintf(x_file, "Size of Certificate : 0x%.08X\n", m_Certificate.dwSize); - fprintf(x_file, "TimeDate Stamp : 0x%.08X (%s)\n", m_Certificate.dwTimeDate, BetterTime(m_Certificate.dwTimeDate)); - fprintf(x_file, "Title ID : 0x%.08X\n", m_Certificate.dwTitleId); - fprintf(x_file, "Title : L\"%s\"\n", m_szAsciiTitle); - - // print alternate title IDs - { - fprintf(x_file, "Alternate Titles IDs : "); - - for(int v=0;v<0x10;v++) - { - if(v != 0) - fprintf(x_file, " "); - fprintf(x_file, "0x%.08X", m_Certificate.dwAlternateTitleId[v]); - if(v != 0x0F) - fprintf(x_file, "\n"); - } - - fprintf(x_file, "\n"); - } - - fprintf(x_file, "Allowed Media : 0x%.08X (%s)\n", m_Certificate.dwAllowedMedia, AllowedMediaToString().c_str()); - fprintf(x_file, "Game Region : 0x%.08X (%s)\n", m_Certificate.dwGameRegion, GameRegionToString()); - fprintf(x_file, "Game Ratings : 0x%.08X\n", m_Certificate.dwGameRatings); - fprintf(x_file, "Disk Number : 0x%.08X\n", m_Certificate.dwDiskNumber); - fprintf(x_file, "Version : 0x%.08X\n", m_Certificate.dwVersion); - - // print LAN key - { - fprintf(x_file, "LAN Key : "); - for(int x=0;x<16;x++) - fprintf(x_file, "%.02X", m_Certificate.bzLanKey[x]); - fprintf(x_file, "\n"); - } - - // print signature key - { - fprintf(x_file, "Signature Key : "); - for(int x=0;x<16;x++) - fprintf(x_file, "%.02X", m_Certificate.bzSignatureKey[x]); - fprintf(x_file, "\n"); - } - - // print alternate signature keys - { - fprintf(x_file, "Title Alternate Signature Keys : "); - for(int y=0;y<16;y++) - { - fprintf(x_file, "\n "); - for(int x=0;x<16;x++) - fprintf(x_file, "%.02X", m_Certificate.bzTitleAlternateSignatureKey[y][x]); - } - fprintf(x_file, "\n \n"); - } - - fprintf(x_file, "\n"); - fprintf(x_file, "Dumping XBE Section Headers...\n"); - fprintf(x_file, "\n"); - - // print section headers - { - for(uint32 v=0;vdwDataStartAddr); - fprintf(x_file, "Data End Address : 0x%.08X\n", m_TLS->dwDataEndAddr); - fprintf(x_file, "TLS Index Address : 0x%.08X\n", m_TLS->dwTLSIndexAddr); - fprintf(x_file, "TLS Callback Address : 0x%.08X\n", m_TLS->dwTLSCallbackAddr); - fprintf(x_file, "Size of Zero Fill : 0x%.08X\n", m_TLS->dwSizeofZeroFill); - fprintf(x_file, "Characteristics : 0x%.08X\n", m_TLS->dwCharacteristics); - } - else - { - fprintf(x_file, "(This XBE contains no TLS)\n"); - } + XbePrinter printer(this); + std::cout << printer.GenXbeInfo(); } - // import logo bitmap from raw monochrome data void Xbe::ImportLogoBitmap(const uint08 x_Gray[100*17]) { @@ -1037,9 +790,56 @@ const char *Xbe::GameRegionToString() return Region_text[index]; } -std::string Xbe::AllowedMediaToString() +const wchar_t *Xbe::GetUnicodeFilenameAddr() { - const uint32 dwAllowedMedia = m_Certificate.dwAllowedMedia; + return (const wchar_t *)GetAddr(m_Header.dwDebugUnicodeFilenameAddr); +} + +#define SSTREAM_SET_HEX(stream_name) stream_name << std::setfill('0') << std::uppercase << std::hex; + +XbePrinter::XbePrinter(Xbe* Xbe_object) +{ + Xbe_to_print = Xbe_object; + Xbe_header = &(Xbe_object->m_Header); + Xbe_certificate = &(Xbe_object->m_Certificate); +} + +std::string XbePrinter::GenXbeInfo() +{ + std::string info; + info.append(GenDumpHeader()); + info.append(GenXbeHeaderInfo()); + info.append(GenXbeCertificateInfo()); + info.append(GenSectionInfo()); + info.append(GenLibraryVersions()); + info.append(GenTLS()); + return info; +} + +std::string XbePrinter::GenHexRow( + uint08 *signature, const uint08 row, const uint08 row_size +) +{ + const uint16 offset = row * row_size; + std::stringstream text; + SSTREAM_SET_HEX(text); + for(uint08 x = 0; x < row_size; x++) { + text << std::setw(2) << static_cast(signature[offset + x]); + } + return text.str(); +} + +// https://stackoverflow.com/questions/4786292/converting-unicode-strings-and-vice-versa +std::string XbePrinter::utf8_to_ascii(const wchar_t* utf8_string) +{ + std::wstring_convert> utf8_to_ascii; + const std::wstring utf8_filename(utf8_string); + return utf8_to_ascii.to_bytes(utf8_filename); +} + +std::string XbePrinter::AllowedMediaToString() +{ + const uint32 dwAllowedMedia = Xbe_certificate->dwAllowedMedia; std::string text = "Media Types:"; if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) { @@ -1076,3 +876,377 @@ std::string Xbe::AllowedMediaToString() } return text; } + +std::string XbePrinter::GameRatingToString() +{ + std::string text; + // Info from: http://xboxdevwiki.net/EEPROM + switch(Xbe_certificate->dwGameRatings) { + case 0x0: + text.append("(RP) Rating Pending"); + break; + case 0x1: + text.append("(AO) Adults Only"); + break; + case 0x2: + text.append("(M) Mature"); + break; + case 0x3: + text.append("(T) Teen"); + break; + case 0x4: + text.append("(E) Everyone"); + break; + case 0x5: + text.append("(K-A) Kids to Adults"); + break; + case 0x6: + text.append("(EC) Early Childhood"); + break; + default: + text.append("ERROR: no rating"); + break; + } + return text; +} + +std::string XbePrinter::GenDumpHeader() +{ + std::string text; + text.append("XBE information generated by Cxbx-Reloaded (Version " _CXBX_VERSION ")\n\n"); + text.append("Title identified as \""); + text.append(Xbe_to_print->m_szAsciiTitle); + text.append("\"\n\n"); + text.append("Dumping XBE file header...\n\n"); + text.append("Magic Number : XBEH\n"); + return text; +} + +std::string XbePrinter::GenXbeHeaderInfo() +{ + std::string text; + text.append(GenDigitalSignature()); + text.append(GenGeneralHeaderInfo1()); + text.append(GenInitFlags()); + text.append(GenGeneralHeaderInfo2()); + return text; +} + +std::string XbePrinter::GenDigitalSignature() +{ + const uint08 row_size = 16; + std::string text; + text.append("Digital Signature : "); + for(int row = 0; row < 16; row++) { + text.append("\n "); + text.append(GenHexRow(&(Xbe_header->pbDigitalSignature[0]), row, row_size)); + } + text.append("\n \n"); + return text; +} + +std::string XbePrinter::GenGeneralHeaderInfo1() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Base Address : 0x" << std::setw(8) << Xbe_header->dwBaseAddr << "\n"; + text << "Size of Headers : 0x" << std::setw(8) << Xbe_header->dwSizeofHeaders << "\n"; + text << "Size of Image : 0x" << std::setw(8) << Xbe_header->dwSizeofImage << "\n"; + text << "Size of Image Header : 0x" << std::setw(8) << Xbe_header->dwSizeofImageHeader << "\n"; + text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwTimeDate << " (" << BetterTime(Xbe_header->dwTimeDate) << ")\n"; + text << "Certificate Address : 0x" << std::setw(8) << Xbe_header->dwCertificateAddr << "\n"; + text << "Number of Sections : 0x" << std::setw(8) << Xbe_header->dwSections << "\n"; + text << "Section Headers Address : 0x" << std::setw(8) << Xbe_header->dwSectionHeadersAddr << "\n"; + return text.str(); +} + +std::string XbePrinter::GenInitFlags() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Init Flags : 0x" << std::setw(8) << Xbe_header->dwInitFlags_value << " "; + + if(Xbe_header->dwInitFlags.bMountUtilityDrive) { + text << "[Mount Utility Drive] "; + } + if(Xbe_header->dwInitFlags.bFormatUtilityDrive) { + text << "[Format Utility Drive] "; + } + if(Xbe_header->dwInitFlags.bLimit64MB) { + text << "[Limit Devkit Run Time Memory to 64MB] "; + } + if(!Xbe_header->dwInitFlags.bDontSetupHarddisk) { + text << "[Setup Harddisk] "; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenGeneralHeaderInfo2() +{ + const uint32 retail_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_RETAIL; + const uint32 debug_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_DEBUG; + const uint32 retail_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_RETAIL; + const uint32 debug_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_DEBUG; + const std::string AsciiFilename = utf8_to_ascii(Xbe_to_print->GetUnicodeFilenameAddr()); + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Entry Point : 0x" << std::setw(8) << Xbe_header->dwEntryAddr << " (Retail: 0x" << std::setw(8) << retail_entry_point << ", Debug: 0x" << std::setw(8) << debug_entry_point << ")\n"; + text << "TLS Address : 0x" << std::setw(8) << Xbe_header->dwTLSAddr << "\n"; + text << "(PE) Stack Commit : 0x" << std::setw(8) << Xbe_header->dwPeStackCommit << "\n"; + text << "(PE) Heap Reserve : 0x" << std::setw(8) << Xbe_header->dwPeHeapReserve << "\n"; + text << "(PE) Heap Commit : 0x" << std::setw(8) << Xbe_header->dwPeHeapCommit << "\n"; + text << "(PE) Base Address : 0x" << std::setw(8) << Xbe_header->dwPeBaseAddr << "\n"; + text << "(PE) Size of Image : 0x" << std::setw(8) << Xbe_header->dwPeSizeofImage << "\n"; + text << "(PE) Checksum : 0x" << std::setw(8) << Xbe_header->dwPeChecksum << "\n"; + text << "(PE) TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwPeTimeDate << " (" << BetterTime(Xbe_header->dwPeTimeDate) << ")\n"; + text << "Debug Pathname Address : 0x" << std::setw(8) << Xbe_header->dwDebugPathnameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugPathnameAddr) << "\")\n"; + text << "Debug Filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugFilenameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugFilenameAddr) << "\")\n"; + text << "Debug Unicode filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugUnicodeFilenameAddr << " (L\"" << AsciiFilename << "\")\n"; + text << "Kernel Image Thunk Address : 0x" << std::setw(8) << Xbe_header->dwKernelImageThunkAddr << " (Retail: 0x" << std::setw(8) << retail_thunk_addr << ", Debug: 0x" << std::setw(8) << debug_thunk_addr << ")\n"; + text << "NonKernel Import Dir Address : 0x" << std::setw(8) << Xbe_header->dwNonKernelImportDirAddr << "\n"; + text << "Library Versions : 0x" << std::setw(8) << Xbe_header->dwLibraryVersions << "\n"; + text << "Library Versions Address : 0x" << std::setw(8) << Xbe_header->dwLibraryVersionsAddr << "\n"; + text << "Kernel Library Version Address : 0x" << std::setw(8) << Xbe_header->dwKernelLibraryVersionAddr << "\n"; + text << "XAPI Library Version Address : 0x" << std::setw(8) << Xbe_header->dwXAPILibraryVersionAddr << "\n"; + text << "Logo Bitmap Address : 0x" << std::setw(8) << Xbe_header->dwLogoBitmapAddr << "\n"; + text << "Logo Bitmap Size : 0x" << std::setw(8) << Xbe_header->dwSizeofLogoBitmap << "\n\n"; + return text.str(); +} + +std::string XbePrinter::GenXbeCertificateInfo() +{ + std::string text; + text.append(GenCertificateHeader()); + text.append(GenAlternateTitleIDs()); + text.append(GenMediaInfo()); + text.append(GenLANKey()); + text.append(GenSignatureKey()); + text.append(GenAlternateSignatureKeys()); + return text; +} + +std::string XbePrinter::GenCertificateHeader() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Dumping XBE Certificate...\n\n"; + text << "Size of Certificate : 0x" << std::setw(8) << Xbe_certificate->dwSize << "\n"; + text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_certificate->dwTimeDate << " (" << BetterTime(Xbe_certificate->dwTimeDate) << ")\n"; + text << "Title ID : 0x" << std::setw(8) << Xbe_certificate->dwTitleId << "\n"; + text << "Title : L\"" << Xbe_to_print->m_szAsciiTitle << "\"\n"; + return text.str(); +} + +std::string XbePrinter::GenAlternateTitleIDs() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Alternate Titles IDs : "; + + for(int v = 0; v < 0x10; v++) { + if(v != 0) { + text << " "; + } + text << "0x" << std::setw(8) << Xbe_certificate->dwAlternateTitleId[v]; + if(v != 0x0F) { + text << "\n"; + } + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenMediaInfo() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Allowed Media : 0x" << std::setw(8) << Xbe_certificate->dwAllowedMedia << " (" << AllowedMediaToString() << ")\n"; + text << "Game Region : 0x" << std::setw(8) << Xbe_certificate->dwGameRegion << " (" << Xbe_to_print->GameRegionToString() << ")\n"; + text << "Game Ratings : 0x" << std::setw(8) << Xbe_certificate->dwGameRatings << " (" << GameRatingToString() << ")\n"; + text << "Disk Number : 0x" << std::setw(8) << Xbe_certificate->dwDiskNumber << "\n"; + text << "Version : 0x" << std::setw(8) << Xbe_certificate->dwVersion << "\n"; + return text.str(); +} + +std::string XbePrinter::GenLANKey() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + text.append("LAN Key : "); + text.append(GenHexRow(&(Xbe_certificate->bzLanKey[0]), row, row_size)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenSignatureKey() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + text.append("Signature Key : "); + text.append(GenHexRow(&(Xbe_certificate->bzSignatureKey[0]), row, row_size)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenAlternateSignatureKeys() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + + text.append("Title Alternate Signature Keys : "); + for(int row = 0; row < 16; row++) + { + text.append("\n "); + text.append(GenHexRow(&(Xbe_certificate->bzTitleAlternateSignatureKey[0][0]), row, row_size)); + } + text.append("\n \n"); + return text; +} + +std::string XbePrinter::GenSectionInfo() +{ + std::string text; + text.append("\nDumping XBE Section Headers...\n\n"); + text.append(GenSectionHeaders()); + return text; +} + +std::string XbePrinter::GenSectionHeaders() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + for(uint32 v=0; v < Xbe_header->dwSections; v++) { + text << "Section Name : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << " (\"" << Xbe_to_print->m_szSectionName[v] << "\")\n"; + text << GenSectionFlags(Xbe_to_print->m_SectionHeader[v]); + text << "Virtual Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualAddr << "\n"; + text << "Virtual Size : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualSize << "\n"; + text << "Raw Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwRawAddr << "\n"; + text << "Size of Raw : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSizeofRaw << "\n"; + text << "Section Name Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << "\n"; + text << "Section Reference Count : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionRefCount << "\n"; + text << "Head Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwHeadSharedRefCountAddr << "\n"; + text << "Tail Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwTailSharedRefCountAddr << "\n"; + text << GenSectionDigest(Xbe_to_print->m_SectionHeader[v]) << "\n"; + } + return text.str(); +} + +std::string XbePrinter::GenSectionFlags(Xbe::SectionHeader section_header) +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Flags : 0x" << std::setw(8) << section_header.dwFlags_value << " "; + + if(section_header.dwFlags.bWritable) { + text << "(Writable) "; + } + if(section_header.dwFlags.bPreload) { + text << "(Preload) "; + } + if(section_header.dwFlags.bExecutable) { + text << "(Executable) "; + } + if(section_header.dwFlags.bInsertedFile) { + text << "(Inserted File) "; + } + if(section_header.dwFlags.bHeadPageRO) { + text << "(Head Page RO) "; + } + if(section_header.dwFlags.bTailPageRO) { + text << "(Tail Page RO) "; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenSectionDigest(Xbe::SectionHeader section_header) +{ + std::string text; + text.append("Section Digest : "); + text.append(GenHexRow(§ion_header.bzSectionDigest[0], 0, 20)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenLibraryVersions() +{ + std::stringstream text; + text << "Dumping XBE Library Versions...\n\n"; + + if(Xbe_to_print->m_LibraryVersion == 0 || Xbe_header->dwLibraryVersions == 0) { + text << "(This XBE contains no Library Versions)\n\n"; + } + else { + for(uint32 v = 0; v < Xbe_header->dwLibraryVersions; v++) { + char libname[9]; + for(uint32 c=0;c<8;c++) { + libname[c] = Xbe_to_print->m_LibraryVersion[v].szName[c]; + } + libname[8] = '\0'; + + text << "Library Name : " << libname << "\n"; + text << "Version : " + << Xbe_to_print->m_LibraryVersion[v].wMajorVersion << "." + << Xbe_to_print->m_LibraryVersion[v].wMinorVersion << "." + << Xbe_to_print->m_LibraryVersion[v].wBuildVersion << "\n"; + text << GenLibraryFlags(Xbe_to_print->m_LibraryVersion[v]); + text << "\n"; + } + } + return text.str(); +} + +std::string XbePrinter::GenLibraryFlags(Xbe::LibraryVersion libver) +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Flags : 0x" << std::setw(4) << libver.wFlags_value << " "; + text << "QFEVersion : 0x" << std::setw(4) << libver.wFlags.QFEVersion << ", "; + + if(libver.wFlags.bDebugBuild) { + text << "Debug, "; + } + else { + text << "Retail, "; + } + + switch(libver.wFlags.Approved) { + case 0: + text << "Unapproved"; + break; + case 1: + text << "Possibly Approved"; + break; + case 2: + text << "Approved"; + break; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenTLS() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + Xbe::TLS *local_TLS = Xbe_to_print->m_TLS; + + text << "Dumping XBE TLS...\n\n"; + // print thread local storage + if(local_TLS != 0) { + text << "Data Start Address : 0x" << std::setw(8) << local_TLS->dwDataStartAddr << "\n"; + text << "Data End Address : 0x" << std::setw(8) << local_TLS->dwDataEndAddr << "\n"; + text << "TLS Index Address : 0x" << std::setw(8) << local_TLS->dwTLSIndexAddr << "\n"; + text << "TLS Callback Address : 0x" << std::setw(8) << local_TLS->dwTLSCallbackAddr << "\n"; + text << "Size of Zero Fill : 0x" << std::setw(8) << local_TLS->dwSizeofZeroFill << "\n"; + text << "Characteristics : 0x" << std::setw(8) << local_TLS->dwCharacteristics << "\n"; + } + else { + text << "(This XBE contains no TLS)\n"; + } + return text.str(); +} diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index 344ee4a49..756b770d4 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -62,8 +62,8 @@ class Xbe : public Error // export to Xbe file void Export(const char *x_szXbeFilename); - // dump Xbe information to text file - void DumpInformation(FILE *x_file); + bool DumpInformationToFile(std::string); + void DumpInformationToConsole(); // import logo bitmap from raw monochrome data void ImportLogoBitmap(const uint08 x_Gray[100*17]); @@ -255,17 +255,17 @@ class Xbe : public Error // retrieve thread local storage index address uint32 *GetTLSIndex() { if(m_TLS == 0) return 0; else return (uint32*)GetAddr(m_TLS->dwTLSIndexAddr); } + // return a modifiable pointer inside this structure that corresponds to a virtual address + uint08 *GetAddr(uint32 x_dwVirtualAddress); + + const wchar_t *GetUnicodeFilenameAddr(); private: // constructor initialization void ConstructorInit(); - // return a modifiable pointer inside this structure that corresponds to a virtual address - uint08 *GetAddr(uint32 x_dwVirtualAddress); - // return a modifiable pointer to logo bitmap data uint08 *GetLogoBitmap(uint32 x_dwSize); - std::string AllowedMediaToString(); // used to encode/decode logo bitmap data union LogoRLE @@ -346,6 +346,49 @@ class Xbe : public Error *m_xprImage; }; +class XbePrinter +{ + public: + XbePrinter(Xbe*); + std::string GenXbeInfo(); + + private: + Xbe *Xbe_to_print; + Xbe::Header *Xbe_header; + Xbe::Certificate *Xbe_certificate; + + std::string GenHexRow(uint08*, const uint08, const uint08); + std::string utf8_to_ascii(const wchar_t*); + std::string AllowedMediaToString(); + std::string GameRatingToString(); + + std::string GenDumpHeader(); + + std::string GenXbeHeaderInfo(); + std::string GenDigitalSignature(); + std::string GenGeneralHeaderInfo1(); + std::string GenInitFlags(); + std::string GenGeneralHeaderInfo2(); + + std::string GenXbeCertificateInfo(); + std::string GenCertificateHeader(); + std::string GenAlternateTitleIDs(); + std::string GenMediaInfo(); + std::string GenLANKey(); + std::string GenSignatureKey(); + std::string GenAlternateSignatureKeys(); + + std::string GenSectionInfo(); + std::string GenSectionHeaders(); + std::string GenSectionFlags(Xbe::SectionHeader); + std::string GenSectionDigest(Xbe::SectionHeader); + + std::string GenLibraryVersions(); + std::string GenLibraryFlags(Xbe::LibraryVersion); + + std::string GenTLS(); +}; + // debug/retail XOR keys const uint32 XOR_EP_DEBUG = 0x94859D4B; // Entry Point (Debug) const uint32 XOR_EP_RETAIL = 0xA8FC57AB; // Entry Point (Retail) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index db200becb..e853f8cc4 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -1006,32 +1006,21 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // dump xbe information to file { - FILE *TxtFile = fopen(ofn.lpstrFile, "wt"); - - // verify file was opened - if (TxtFile == 0) - MessageBox(m_hwnd, "Could not open text file.", "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); - else - { - m_Xbe->DumpInformation(TxtFile); - - fclose(TxtFile); - - if (m_Xbe->HasError()) - { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); - } - else - { - char buffer[255]; - - sprintf(buffer, "%s's .xbe info was successfully dumped.", m_Xbe->m_szAsciiTitle); - - printf("WndMain: %s\n", buffer); - - MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); - } - } + bool success = m_Xbe->DumpInformationToFile(ofn.lpstrFile); + if (m_Xbe->HasError()) { + MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + } + else { + if(success) { + char buffer[255]; + sprintf(buffer, "%s's .xbe info was successfully dumped.", m_Xbe->m_szAsciiTitle); + printf("WndMain: %s\n", buffer); + MessageBox(m_hwnd, buffer, "Cxbx-Reloaded", MB_ICONINFORMATION | MB_OK); + } + else { + MessageBox(m_hwnd, "Could not open Xbe text file.", "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + } + } } } } @@ -1039,8 +1028,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_EDIT_DUMPXBEINFOTO_DEBUGCONSOLE: { - // dump xbe information to debug console - m_Xbe->DumpInformation(stdout); + m_Xbe->DumpInformationToConsole(); if (m_Xbe->HasError()) { @@ -1050,7 +1038,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP { char buffer[255]; - sprintf(buffer, "%s's .xbe info was successfully dumped.", m_Xbe->m_szAsciiTitle); + sprintf(buffer, "%s's .xbe info was successfully dumped to console.", m_Xbe->m_szAsciiTitle); printf("WndMain: %s\n", buffer); } From 641ec8fdfa091eae75cef54f0ab4428b9f889f10 Mon Sep 17 00:00:00 2001 From: Fisherman166 Date: Sun, 21 Jan 2018 17:12:21 -0800 Subject: [PATCH 12/37] Return a string from dumpinformation and let the caller decide how to output the info --- src/Common/Xbe.cpp | 25 +++---------------------- src/Common/Xbe.h | 3 +-- src/Cxbx/WndMain.cpp | 41 +++++++++++++++++++++-------------------- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index 0e3293f98..6c606f81c 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -40,8 +40,6 @@ #include #include #include -#include -#include #include #include @@ -550,30 +548,13 @@ static char *BetterTime(uint32 x_timeDate) return x_ctime; } -bool Xbe::DumpInformationToFile(std::string out_filename) +std::string Xbe::DumpInformation() { if(HasError()) { - return false; + return "ERROR"; } - - bool success = false; XbePrinter printer(this); - std::ofstream out_file(out_filename); - if(out_file.is_open()) { - out_file << printer.GenXbeInfo(); - out_file.close(); - success = true; - } - return success; -} - -void Xbe::DumpInformationToConsole() -{ - if(HasError()) - return; - - XbePrinter printer(this); - std::cout << printer.GenXbeInfo(); + return printer.GenXbeInfo(); } // import logo bitmap from raw monochrome data diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index 756b770d4..61fa22b10 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -62,8 +62,7 @@ class Xbe : public Error // export to Xbe file void Export(const char *x_szXbeFilename); - bool DumpInformationToFile(std::string); - void DumpInformationToConsole(); + std::string DumpInformation(); // import logo bitmap from raw monochrome data void ImportLogoBitmap(const uint08 x_Gray[100*17]); diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index e853f8cc4..1b16377ba 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -47,6 +47,8 @@ #include #include // for std::stringstream +#include +#include #include "CxbxKrnl/xxhash32.h" // for XXHash32::hash #define XBOX_LED_FLASH_PERIOD 176 // if you know a more accurate value, put it here @@ -1006,12 +1008,15 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // dump xbe information to file { - bool success = m_Xbe->DumpInformationToFile(ofn.lpstrFile); + std::string Xbe_info = m_Xbe->DumpInformation(); if (m_Xbe->HasError()) { MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); } else { - if(success) { + std::ofstream Xbe_dump_file(ofn.lpstrFile); + if(Xbe_dump_file.is_open()) { + Xbe_dump_file << Xbe_info; + Xbe_dump_file.close(); char buffer[255]; sprintf(buffer, "%s's .xbe info was successfully dumped.", m_Xbe->m_szAsciiTitle); printf("WndMain: %s\n", buffer); @@ -1026,24 +1031,20 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } break; - case ID_EDIT_DUMPXBEINFOTO_DEBUGCONSOLE: - { - m_Xbe->DumpInformationToConsole(); - - if (m_Xbe->HasError()) - { - MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); - } - else - { - char buffer[255]; - - sprintf(buffer, "%s's .xbe info was successfully dumped to console.", m_Xbe->m_szAsciiTitle); - - printf("WndMain: %s\n", buffer); - } - } - break; + case ID_EDIT_DUMPXBEINFOTO_DEBUGCONSOLE: + { + std::string Xbe_info = m_Xbe->DumpInformation(); + if (m_Xbe->HasError()) { + MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); + } + else { + std::cout << Xbe_info; + char buffer[255]; + sprintf(buffer, "%s's .xbe info was successfully dumped to console.", m_Xbe->m_szAsciiTitle); + printf("WndMain: %s\n", buffer); + } + } + break; case ID_SETTINGS_CONFIG_CONTROLLER: ShowControllerConfig(hwnd); From bf846b59befc2a4d0f11a265508d07d69bbb5e5b Mon Sep 17 00:00:00 2001 From: jarupxx Date: Mon, 22 Jan 2018 18:33:55 +0900 Subject: [PATCH 13/37] Separate XDK 5558/5659 with Integrated Hotfixes OOVPA to 5788 database XDK 5558/5659 with Integrated Hotfixes use 5788 database. Standard XDK 5659 still uses 5558 database. Verified with - [5558] NHL HITZ Pro 2004 - [5558 with Intergrated Hotfixes] XIII - [5659] NFL Blitz Pro - [5659 with Intergrated Hotfixes] Midway Arcade Treasures Paperboy - [5788] Digimon Battle Chronicle --- build/win32/Cxbx.vcxproj | 1 - build/win32/Cxbx.vcxproj.filters | 3 - src/CxbxKrnl/HLEDataBase/D3D8.1.0.5659.inl | 328 --------------------- src/CxbxKrnl/HLEDataBase/D3D8.1.0.5788.inl | 295 ++++++++++++++++++ src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl | 33 ++- src/CxbxKrnl/HLEIntercept.cpp | 9 + 6 files changed, 321 insertions(+), 348 deletions(-) delete mode 100644 src/CxbxKrnl/HLEDataBase/D3D8.1.0.5659.inl diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index b159a5d98..226861f85 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -289,7 +289,6 @@ - diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 9a9f24fdc..159900e97 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -539,9 +539,6 @@ HLEDatabase\D3D8 - - HLEDatabase\D3D8 - HLEDatabase\D3D8 diff --git a/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5659.inl b/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5659.inl deleted file mode 100644 index 434316872..000000000 --- a/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5659.inl +++ /dev/null @@ -1,328 +0,0 @@ -// ****************************************************************** -// * -// * .,-::::: .,:: .::::::::. .,:: .: -// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; -// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' -// * $$$ Y$$$P $$""""Y$$ Y$$$P -// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, -// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, -// * -// * Cxbx->Win32->CxbxKrnl->HLEDataBase->D3D8.1.0.5659.inl -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2017 jarupxx -// * -// * All rights reserved -// * -// ****************************************************************** - -// ****************************************************************** -// * D3DDevice_SetMaterial -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_SetMaterial, 5659, 11) - - { 0x04, 0x08 }, - - { 0x0C, 0x81 }, - { 0x0D, 0xC7 }, - { 0x0E, 0x00 }, - { 0x0F, 0x0F }, - { 0x10, 0x00 }, - - { 0x16, 0x00 }, - { 0x1F, 0x81 }, - { 0x22, 0x90 }, - { 0x2C, 0x5E }, - { 0x2E, 0x04 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetMaterial -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_GetMaterial, 5659, 8) - - { 0x05, 0x56 }, - { 0x06, 0x57 }, - { 0x0A, 0x0C }, - - { 0x0D, 0x00 }, - { 0x0E, 0x0F }, - - { 0x12, 0x11 }, - { 0x16, 0xF3 }, - { 0x1A, 0xC2 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_AddRef -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_AddRef, 5659, 10) - - // D3DDevice_AddRef+0x00 : mov eax, [addr] - { 0x00, 0xA1 }, - - // D3DDevice_AddRef+0x05 : mov ecx, [eax+0x0938] - { 0x05, 0x8B }, - { 0x06, 0x88 }, - { 0x07, 0x38 }, - { 0x08, 0x09 }, - - // D3DDevice_AddRef+0x0B : inc ecx - { 0x0B, 0x41 }, - - // D3DDevice_AddRef+0x0C : mov [eax+0x0938], ecx - { 0x0C, 0x89 }, - { 0x0D, 0x88 }, - { 0x0E, 0x38 }, - { 0x0F, 0x09 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_SetBackMaterial -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_SetBackMaterial, 5659, 11) - - { 0x04, 0x08 }, - - { 0x0C, 0x81 }, - { 0x0D, 0xC7 }, - { 0x0E, 0x44 }, - { 0x0F, 0x0F }, - { 0x10, 0x00 }, - - { 0x16, 0x00 }, - { 0x1F, 0x81 }, - { 0x22, 0x90 }, - { 0x2C, 0x5E }, - { 0x2E, 0x04 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetBackMaterial -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_GetBackMaterial, 5659, 8) - - { 0x05, 0x56 }, - { 0x06, 0x57 }, - { 0x0A, 0x0C }, - - { 0x0D, 0x44 }, - { 0x0E, 0x0F }, - - { 0x12, 0x11 }, - { 0x16, 0xF3 }, - { 0x1A, 0xC2 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_SetVerticalBlankCallback -// ****************************************************************** -OOVPA_XREF(D3DDevice_SetVerticalBlankCallback, 5659, 1+12, - - XRefNoSaveIndex, - XRefOne) - - XREF_ENTRY( 0x06, XREF_D3DDEVICE ), // Derived - - // D3DDevice_SetVerticalBlankCallback+0x00 : mov eax, [esp+0x04] - { 0x00, 0x8B }, - { 0x01, 0x44 }, - { 0x02, 0x24 }, - { 0x03, 0x04 }, - - // D3DDevice_SetVerticalBlankCallback+0x04 : mov ecx, [addr] - { 0x04, 0x8B }, - { 0x05, 0x0D }, - - // D3DDevice_SetVerticalBlankCallback+0x0A : mov [ecx+0x1DB4], eax - { 0x0A, 0x89 }, - { 0x0B, 0x81 }, - { 0x0C, 0xB8 }, // B4 vs B8 - { 0x0D, 0x1D }, - - // D3DDevice_SetVerticalBlankCallback+0x10 : retn 0x04 - { 0x10, 0xC2 }, - { 0x11, 0x04 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_SetSwapCallback -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_SetSwapCallback, 5659, 12) - - // D3DDevice_SetSwapCallback+0x00 : mov eax, [esp+0x04] - { 0x00, 0x8B }, - { 0x01, 0x44 }, - { 0x02, 0x24 }, - { 0x03, 0x04 }, - - // D3DDevice_SetSwapCallback+0x04 : mov ecx, [addr] - { 0x04, 0x8B }, - { 0x05, 0x0D }, - - // D3DDevice_SetSwapCallback+0x0A : mov [ecx+0x1DB4], eax - { 0x0A, 0x89 }, - { 0x0B, 0x81 }, - { 0x0C, 0xB4 }, // B4 vs B8 - { 0x0D, 0x1D }, - - // D3DDevice_SetSwapCallback+0x10 : retn 0x04 - { 0x10, 0xC2 }, - { 0x11, 0x04 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetVertexShader -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_GetVertexShader, 5659, 16) - - { 0x00, 0xA1 }, - - { 0x05, 0x8B }, - { 0x06, 0x88 }, - { 0x07, 0x98 }, - { 0x08, 0x07 }, - { 0x09, 0x00 }, - { 0x0A, 0x00 }, - { 0x0B, 0x8B }, - { 0x0C, 0x54 }, - { 0x0D, 0x24 }, - { 0x0E, 0x04 }, - { 0x0F, 0x89 }, - { 0x10, 0x0A }, - { 0x11, 0xC2 }, - { 0x12, 0x04 }, - { 0x13, 0x00 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetPixelShader -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_GetPixelShader, 5659, 16) - - { 0x00, 0xA1 }, - - { 0x05, 0x8B }, - { 0x06, 0x88 }, - { 0x07, 0x84 }, - { 0x08, 0x07 }, - { 0x09, 0x00 }, - { 0x0A, 0x00 }, - { 0x0B, 0x8B }, - { 0x0C, 0x54 }, - { 0x0D, 0x24 }, - { 0x0E, 0x04 }, - { 0x0F, 0x89 }, - { 0x10, 0x0A }, - { 0x11, 0xC2 }, - { 0x12, 0x04 }, - { 0x13, 0x00 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_BlockUntilVerticalBlank -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_BlockUntilVerticalBlank, 5659, 11) - - // D3DDevice_BlockUntilVerticalBlank+0x05 : push 0; push 0; push 1 - { 0x05, 0x6A }, - { 0x06, 0x00 }, - { 0x07, 0x6A }, - { 0x08, 0x00 }, - { 0x09, 0x6A }, - { 0x0A, 0x01 }, - - // D3DDevice_BlockUntilVerticalBlank+0x17 : add eax, 0x1DBC - { 0x17, 0x05 }, - { 0x18, 0xBC }, - { 0x19, 0x1D }, - - // D3DDevice_BlockUntilVerticalBlank+0x1D : call [KrnlImport] - { 0x1D, 0xFF }, - - // D3DDevice_BlockUntilVerticalBlank+0x23 : retn - { 0x23, 0xC3 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetShaderConstantMode -// ****************************************************************** -OOVPA_NO_XREF(D3DDevice_GetShaderConstantMode, 5659, 16) - - { 0x00, 0xA1 }, - - { 0x05, 0x8B }, - { 0x06, 0x88 }, - { 0x07, 0x28 }, - { 0x08, 0x19 }, - { 0x09, 0x00 }, - { 0x0A, 0x00 }, - { 0x0B, 0x8B }, - { 0x0C, 0x54 }, - { 0x0D, 0x24 }, - { 0x0E, 0x04 }, - { 0x0F, 0x89 }, - { 0x10, 0x0A }, - { 0x11, 0xC2 }, - { 0x12, 0x04 }, - { 0x13, 0x00 }, -OOVPA_END; - -// ****************************************************************** -// * D3DDevice_GetTexture, named with 2 suffix to match EMUPATCH(D3DDevice_GetTexture2) -// ****************************************************************** -#ifndef WIP_LessVertexPatching -OOVPA_NO_XREF(D3DDevice_GetTexture2, 5659, 23) // Up to 5849 -#else -OOVPA_XREF(D3DDevice_GetTexture2, 5659, 1+23, // Up to 5849 - - XRefNoSaveIndex, - XRefOne) - - XREF_ENTRY( 0x0E, XREF_OFFSET_D3DDEVICE_M_TEXTURES ), // Derived -#endif - { 0x00, 0x8B }, - { 0x01, 0x44 }, - { 0x02, 0x24 }, - { 0x03, 0x04 }, - { 0x04, 0x8B }, - { 0x05, 0x0D }, - - { 0x0A, 0x56 }, - { 0x0B, 0x8D }, - { 0x0C, 0xB4 }, - { 0x0D, 0x81 }, - { 0x0E, 0x88 }, // GetTexture2 880F vs GetPalette2 980F - { 0x0F, 0x0F }, - - { 0x10, 0x00 }, - { 0x11, 0x00 }, - { 0x12, 0x8B }, - { 0x13, 0x06 }, - { 0x14, 0x85 }, - { 0x15, 0xC0 }, - { 0x16, 0x74 }, - - { 0x18, 0x50 }, - { 0x19, 0xE8 }, - - { 0x1E, 0x8B }, - { 0x1F, 0x06 }, -// { 0x21, 0xC2 }, -OOVPA_END; diff --git a/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5788.inl b/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5788.inl index 5d091e37e..ef052219d 100644 --- a/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5788.inl +++ b/src/CxbxKrnl/HLEDataBase/D3D8.1.0.5788.inl @@ -56,3 +56,298 @@ OOVPA_XREF(D3D_RecordStateBlock, 5788, 10, { 0xD7, 0x0C }, { 0xD8, 0x01 }, OOVPA_END; + +// ****************************************************************** +// * D3DDevice_SetMaterial +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_SetMaterial, 5788, 11) + + { 0x04, 0x08 }, + + { 0x0C, 0x81 }, + { 0x0D, 0xC7 }, + { 0x0E, 0x00 }, + { 0x0F, 0x0F }, + { 0x10, 0x00 }, + + { 0x16, 0x00 }, + { 0x1F, 0x81 }, + { 0x22, 0x90 }, + { 0x2C, 0x5E }, + { 0x2E, 0x04 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetMaterial +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_GetMaterial, 5788, 8) + + { 0x05, 0x56 }, + { 0x06, 0x57 }, + { 0x0A, 0x0C }, + + { 0x0D, 0x00 }, + { 0x0E, 0x0F }, + + { 0x12, 0x11 }, + { 0x16, 0xF3 }, + { 0x1A, 0xC2 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_AddRef +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_AddRef, 5788, 10) + + // D3DDevice_AddRef+0x00 : mov eax, [addr] + { 0x00, 0xA1 }, + + // D3DDevice_AddRef+0x05 : mov ecx, [eax+0x0938] + { 0x05, 0x8B }, + { 0x06, 0x88 }, + { 0x07, 0x38 }, + { 0x08, 0x09 }, + + // D3DDevice_AddRef+0x0B : inc ecx + { 0x0B, 0x41 }, + + // D3DDevice_AddRef+0x0C : mov [eax+0x0938], ecx + { 0x0C, 0x89 }, + { 0x0D, 0x88 }, + { 0x0E, 0x38 }, + { 0x0F, 0x09 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_SetBackMaterial +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_SetBackMaterial, 5788, 11) + + { 0x04, 0x08 }, + + { 0x0C, 0x81 }, + { 0x0D, 0xC7 }, + { 0x0E, 0x44 }, + { 0x0F, 0x0F }, + { 0x10, 0x00 }, + + { 0x16, 0x00 }, + { 0x1F, 0x81 }, + { 0x22, 0x90 }, + { 0x2C, 0x5E }, + { 0x2E, 0x04 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetBackMaterial +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_GetBackMaterial, 5788, 8) + + { 0x05, 0x56 }, + { 0x06, 0x57 }, + { 0x0A, 0x0C }, + + { 0x0D, 0x44 }, + { 0x0E, 0x0F }, + + { 0x12, 0x11 }, + { 0x16, 0xF3 }, + { 0x1A, 0xC2 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_SetVerticalBlankCallback +// ****************************************************************** +OOVPA_XREF(D3DDevice_SetVerticalBlankCallback, 5788, 1+12, + + XRefNoSaveIndex, + XRefOne) + + XREF_ENTRY( 0x06, XREF_D3DDEVICE ), // Derived + + // D3DDevice_SetVerticalBlankCallback+0x00 : mov eax, [esp+0x04] + { 0x00, 0x8B }, + { 0x01, 0x44 }, + { 0x02, 0x24 }, + { 0x03, 0x04 }, + + // D3DDevice_SetVerticalBlankCallback+0x04 : mov ecx, [addr] + { 0x04, 0x8B }, + { 0x05, 0x0D }, + + // D3DDevice_SetVerticalBlankCallback+0x0A : mov [ecx+0x1DB4], eax + { 0x0A, 0x89 }, + { 0x0B, 0x81 }, + { 0x0C, 0xB8 }, // B4 vs B8 + { 0x0D, 0x1D }, + + // D3DDevice_SetVerticalBlankCallback+0x10 : retn 0x04 + { 0x10, 0xC2 }, + { 0x11, 0x04 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_SetSwapCallback +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_SetSwapCallback, 5788, 12) + + // D3DDevice_SetSwapCallback+0x00 : mov eax, [esp+0x04] + { 0x00, 0x8B }, + { 0x01, 0x44 }, + { 0x02, 0x24 }, + { 0x03, 0x04 }, + + // D3DDevice_SetSwapCallback+0x04 : mov ecx, [addr] + { 0x04, 0x8B }, + { 0x05, 0x0D }, + + // D3DDevice_SetSwapCallback+0x0A : mov [ecx+0x1DB4], eax + { 0x0A, 0x89 }, + { 0x0B, 0x81 }, + { 0x0C, 0xB4 }, // B4 vs B8 + { 0x0D, 0x1D }, + + // D3DDevice_SetSwapCallback+0x10 : retn 0x04 + { 0x10, 0xC2 }, + { 0x11, 0x04 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetVertexShader +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_GetVertexShader, 5788, 16) + + { 0x00, 0xA1 }, + + { 0x05, 0x8B }, + { 0x06, 0x88 }, + { 0x07, 0x98 }, + { 0x08, 0x07 }, + { 0x09, 0x00 }, + { 0x0A, 0x00 }, + { 0x0B, 0x8B }, + { 0x0C, 0x54 }, + { 0x0D, 0x24 }, + { 0x0E, 0x04 }, + { 0x0F, 0x89 }, + { 0x10, 0x0A }, + { 0x11, 0xC2 }, + { 0x12, 0x04 }, + { 0x13, 0x00 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetPixelShader +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_GetPixelShader, 5788, 16) + + { 0x00, 0xA1 }, + + { 0x05, 0x8B }, + { 0x06, 0x88 }, + { 0x07, 0x84 }, + { 0x08, 0x07 }, + { 0x09, 0x00 }, + { 0x0A, 0x00 }, + { 0x0B, 0x8B }, + { 0x0C, 0x54 }, + { 0x0D, 0x24 }, + { 0x0E, 0x04 }, + { 0x0F, 0x89 }, + { 0x10, 0x0A }, + { 0x11, 0xC2 }, + { 0x12, 0x04 }, + { 0x13, 0x00 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_BlockUntilVerticalBlank +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_BlockUntilVerticalBlank, 5788, 11) + + // D3DDevice_BlockUntilVerticalBlank+0x05 : push 0; push 0; push 1 + { 0x05, 0x6A }, + { 0x06, 0x00 }, + { 0x07, 0x6A }, + { 0x08, 0x00 }, + { 0x09, 0x6A }, + { 0x0A, 0x01 }, + + // D3DDevice_BlockUntilVerticalBlank+0x17 : add eax, 0x1DBC + { 0x17, 0x05 }, + { 0x18, 0xBC }, + { 0x19, 0x1D }, + + // D3DDevice_BlockUntilVerticalBlank+0x1D : call [KrnlImport] + { 0x1D, 0xFF }, + + // D3DDevice_BlockUntilVerticalBlank+0x23 : retn + { 0x23, 0xC3 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetShaderConstantMode +// ****************************************************************** +OOVPA_NO_XREF(D3DDevice_GetShaderConstantMode, 5788, 16) + + { 0x00, 0xA1 }, + + { 0x05, 0x8B }, + { 0x06, 0x88 }, + { 0x07, 0x28 }, + { 0x08, 0x19 }, + { 0x09, 0x00 }, + { 0x0A, 0x00 }, + { 0x0B, 0x8B }, + { 0x0C, 0x54 }, + { 0x0D, 0x24 }, + { 0x0E, 0x04 }, + { 0x0F, 0x89 }, + { 0x10, 0x0A }, + { 0x11, 0xC2 }, + { 0x12, 0x04 }, + { 0x13, 0x00 }, +OOVPA_END; + +// ****************************************************************** +// * D3DDevice_GetTexture, named with 2 suffix to match EMUPATCH(D3DDevice_GetTexture2) +// ****************************************************************** +#ifndef WIP_LessVertexPatching +OOVPA_NO_XREF(D3DDevice_GetTexture2, 5788, 23) // Up to 5849 +#else +OOVPA_XREF(D3DDevice_GetTexture2, 5788, 1+23, // Up to 5849 + + XRefNoSaveIndex, + XRefOne) + + XREF_ENTRY( 0x0E, XREF_OFFSET_D3DDEVICE_M_TEXTURES ), // Derived +#endif + { 0x00, 0x8B }, + { 0x01, 0x44 }, + { 0x02, 0x24 }, + { 0x03, 0x04 }, + { 0x04, 0x8B }, + { 0x05, 0x0D }, + + { 0x0A, 0x56 }, + { 0x0B, 0x8D }, + { 0x0C, 0xB4 }, + { 0x0D, 0x81 }, + { 0x0E, 0x88 }, // GetTexture2 880F vs GetPalette2 980F + { 0x0F, 0x0F }, + + { 0x10, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x8B }, + { 0x13, 0x06 }, + { 0x14, 0x85 }, + { 0x15, 0xC0 }, + { 0x16, 0x74 }, + + { 0x18, 0x50 }, + { 0x19, 0xE8 }, + + { 0x1E, 0x8B }, + { 0x1F, 0x06 }, +// { 0x21, 0xC2 }, +OOVPA_END; diff --git a/src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl b/src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl index 4e5c1548e..2b679800d 100644 --- a/src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl +++ b/src/CxbxKrnl/HLEDataBase/D3D8.OOVPA.inl @@ -53,9 +53,11 @@ // * [5233] Evil Dead | 100% | have 208/230 library. // * [5344] Gladius DEMO | 100% | have 202/229 library. // * [5455] Dinosaur Hunting | 100% | have 207/229 library. -// * [5558] NHL HITZ Pro 2004 | 100% | have 218/229 library. -// * [5659] Midway Arcade Treasures Paperboy | 100% | have 212/229 library. -// * [5788] Digimon Battle Chronicle | 100% | have 210/229 library. +// * [5558] NHL HITZ Pro 2004 | 100% | have 218/230 library. +// * [5558] XIII | 100% | With Intergrated Hotfixes. have 209/230 library. +// * [5659] NFL Blitz Pro | 100% | have 208/230 library. +// * [5659] Midway Arcade Treasures Paperboy | 100% | With Intergrated Hotfixes. have 212/230 library. +// * [5788] Digimon Battle Chronicle | 100% | have 210/230 library. // * [5849] Nickelodeon Tak 2 | 100% | have 210/229 library. // TODO: Known D3D8 OOVPA issue list @@ -181,7 +183,6 @@ #include "D3D8.1.0.5344.inl" #include "D3D8.1.0.5455.inl" #include "D3D8.1.0.5558.inl" -#include "D3D8.1.0.5659.inl" #include "D3D8.1.0.5788.inl" #include "D3D8.1.0.5849.inl" @@ -198,7 +199,7 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DCubeTexture_GetCubeMapSurface, PATCH, 3911, 4627), // Called D3DCubeTexture_GetCubeMapSurface2 (from 4627's comment) NOTE: Use D3DCubeTexture_GetCubeMapSurface2 for 4627 and above REGISTER_OOVPAS(D3DCubeTexture_GetCubeMapSurface2, PATCH, 4627), REGISTER_OOVPAS(D3DCubeTexture_LockRect, PATCH, 3911), // Just calls Lock2DSurface (from 4134, 4432's comment) - REGISTER_OOVPAS(D3DDevice_AddRef, PATCH, 3911, 4039, 4134, 4242, 4627, 5028, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_AddRef, PATCH, 3911, 4039, 4134, 4242, 4627, 5028, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_ApplyStateBlock, PATCH, 3911, 4627), REGISTER_OOVPAS(D3DDevice_Begin, PATCH, 3911, 4039), REGISTER_OOVPAS(D3DDevice_BeginPush, PATCH, 4134, 4627, 5028), @@ -207,7 +208,7 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_BeginStateBlock, PATCH, 3911, 4134), REGISTER_OOVPAS(D3DDevice_BeginVisibilityTest, PATCH, 3911, 4034), REGISTER_OOVPAS(D3DDevice_BlockOnFence, PATCH, 3911), - REGISTER_OOVPAS(D3DDevice_BlockUntilVerticalBlank, PATCH, 3911, 4034, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_BlockUntilVerticalBlank, PATCH, 3911, 4034, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5788), REGISTER_OOVPAS(D3DDevice_CaptureStateBlock, PATCH, 3911, 4134), REGISTER_OOVPAS(D3DDevice_Clear, PATCH, 3911, 4034), REGISTER_OOVPAS(D3DDevice_CopyRects, PATCH, 3911, 4034, 4627, 5120), @@ -244,7 +245,7 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_FlushVertexCache, PATCH, 3911, 4134), REGISTER_OOVPAS(D3DDevice_GetBackBuffer, PATCH, 3911, 4034, 4134, 4627), // Called D3DDevice_GetBackBuffer2 (from 4627's comment) NOTE: Use D3DDevice_GetBackBuffer2 for 4627 and above REGISTER_OOVPAS(D3DDevice_GetBackBuffer2, PATCH, 4627), // 5233 (from 5344's comment) - REGISTER_OOVPAS(D3DDevice_GetBackMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetBackMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetCreationParameters, PATCH, 3911), REGISTER_OOVPAS(D3DDevice_GetDepthStencilSurface, PATCH, 3911, 4627), // Called D3DDevice_GetDepthStencilSurface2 (from 4627's comment) NOTE: Use D3DDevice_GetDepthStencilSurface2 for 4627 and above REGISTER_OOVPAS(D3DDevice_GetDepthStencilSurface2, PATCH, 4627), @@ -254,22 +255,22 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_GetGammaRamp, PATCH, 3911), REGISTER_OOVPAS(D3DDevice_GetLight, PATCH, 3911), REGISTER_OOVPAS(D3DDevice_GetLightEnable, PATCH, 3911, 5344), - REGISTER_OOVPAS(D3DDevice_GetMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetModelView, PATCH, 3911, 4134), REGISTER_OOVPAS(D3DDevice_GetOverlayUpdateStatus, PATCH, 3911), REGISTER_OOVPAS(D3DDevice_GetPersistedSurface2, PATCH, 4928), // For only on Unreal Championship (from 4627's comment) - REGISTER_OOVPAS(D3DDevice_GetPixelShader, PATCH, 3911, 4039, 4134, 5028, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetPixelShader, PATCH, 3911, 4039, 4134, 5028, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetProjectionViewportMatrix, PATCH, 3911, 4134, 4627, 5344, 5558), // For 5455 (from 5558's comment) REGISTER_OOVPAS(D3DDevice_GetPushBufferOffset, PATCH, 3911, 4627),//TODO 4831 (from 4627's comment) REGISTER_OOVPAS(D3DDevice_GetRenderTarget, PATCH, 3911, 4627), // Called D3DDevice_GetRenderTarget2 (from 4627's comment) NOTE: Use D3DDevice_GetRenderTarget2 for 4627 and above REGISTER_OOVPAS(D3DDevice_GetRenderTarget2, PATCH, 4627), REGISTER_OOVPAS(D3DDevice_GetScissors, PATCH, 3911), - REGISTER_OOVPAS(D3DDevice_GetShaderConstantMode, PATCH, 3911, 4134, 4627, 5028, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetShaderConstantMode, PATCH, 3911, 4134, 4627, 5028, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetStreamSource2, PATCH, 4627), - REGISTER_OOVPAS(D3DDevice_GetTexture2, PATCH, 3911, 4134, 4627, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetTexture2, PATCH, 3911, 4134, 4627, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetTile, PATCH, 3911, 5455), REGISTER_OOVPAS(D3DDevice_GetTransform, PATCH, 3911, 4034), - REGISTER_OOVPAS(D3DDevice_GetVertexShader, PATCH, 3911, 4039, 4134, 5028, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_GetVertexShader, PATCH, 3911, 4039, 4134, 5028, 5558, 5788), REGISTER_OOVPAS(D3DDevice_GetVertexShaderConstant, PATCH, 3911, 4039, 5028), REGISTER_OOVPAS(D3DDevice_GetVertexShaderDeclaration, PATCH, 3911), REGISTER_OOVPAS(D3DDevice_GetVertexShaderFunction, PATCH, 3911), @@ -301,13 +302,13 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_SelectVertexShader, PATCH, 3911, 4034, 5455), REGISTER_OOVPAS(D3DDevice_SelectVertexShaderDirect, PATCH, 4361), REGISTER_OOVPAS(D3DDevice_SetBackBufferScale, PATCH, 4134), - REGISTER_OOVPAS(D3DDevice_SetBackMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_SetBackMaterial, PATCH, 3911, 4134, 4627, 5344, 5558, 5788), REGISTER_OOVPAS(D3DDevice_SetDepthClipPlanes, PATCH, 4432), REGISTER_OOVPAS(D3DDevice_SetFlickerFilter, PATCH, 3911, 4034, 4134), REGISTER_OOVPAS(D3DDevice_SetGammaRamp, PATCH, 3911, 4627), REGISTER_OOVPAS(D3DDevice_SetIndices, UNPATCHED, 3911, 4034), REGISTER_OOVPAS(D3DDevice_SetLight, PATCH, 3911, 5344), - REGISTER_OOVPAS(D3DDevice_SetMaterial, PATCH, 3911, 4034, 4134, 4627, 5344, 5558, 5659), // Was 4627 (from 5344's comment) + REGISTER_OOVPAS(D3DDevice_SetMaterial, PATCH, 3911, 4034, 4134, 4627, 5344, 5558, 5788), // Was 4627 (from 5344's comment) REGISTER_OOVPAS(D3DDevice_SetModelView, PATCH, 3911, 4134, 4627), REGISTER_OOVPAS(D3DDevice_SetPalette, PATCH, 3911, 4034), REGISTER_OOVPAS(D3DDevice_SetPixelShader, PATCH, 3911, 4034, 4627), @@ -355,7 +356,7 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_SetStateVB, UNPATCHED, 3911, 4034, 4134), REGISTER_OOVPAS(D3DDevice_SetStipple, PATCH, 4627), REGISTER_OOVPAS(D3DDevice_SetStreamSource, PATCH, 3911, 4034), - REGISTER_OOVPAS(D3DDevice_SetSwapCallback, PATCH, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5659), + REGISTER_OOVPAS(D3DDevice_SetSwapCallback, PATCH, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5788), REGISTER_OOVPAS(D3DDevice_SetTexture, PATCH, 3911, 4034, 4361, 4831), REGISTER_OOVPAS(D3DDevice_SetTextureState_BorderColor, PATCH, 3911, 4034), REGISTER_OOVPAS(D3DDevice_SetTextureState_BumpEnv, PATCH, 3911, 4034), @@ -378,7 +379,7 @@ OOVPATable D3D8_OOVPAV2[] = { REGISTER_OOVPAS(D3DDevice_SetVertexShaderConstantNotInlineFast, PATCH, 4627), REGISTER_OOVPAS(D3DDevice_SetVertexShaderInput, PATCH, 3911, 4134), REGISTER_OOVPAS(D3DDevice_SetVertexShaderInputDirect, PATCH, 4361), - REGISTER_OOVPAS(D3DDevice_SetVerticalBlankCallback, PATCH, 3911, 4039, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5659), // Was 5233 (from 5344's comment) + REGISTER_OOVPAS(D3DDevice_SetVerticalBlankCallback, PATCH, 3911, 4039, 4134, 4242, 4432, 4627, 5028, 5233, 5344, 5455, 5558, 5788), // Was 5233 (from 5344's comment) REGISTER_OOVPAS(D3DDevice_SetViewport, PATCH, 3911, 4034, 5344, 5455), // Was 5233 (from 5344's comment) REGISTER_OOVPAS(D3DDevice_Swap, PATCH, 4034, 4531, 4627), REGISTER_OOVPAS(D3DDevice_SwitchTexture, PATCH, 3911), diff --git a/src/CxbxKrnl/HLEIntercept.cpp b/src/CxbxKrnl/HLEIntercept.cpp index 62935f4f2..89be10cb5 100644 --- a/src/CxbxKrnl/HLEIntercept.cpp +++ b/src/CxbxKrnl/HLEIntercept.cpp @@ -348,6 +348,7 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader) for(uint32 v=0;v= 5558 && BuildVersion <=5659 && QFEVersion > 1) { + EmuWarning("D3D8 version 1.0.%d.%d Title Detected: This game uses an alias version 1.0.5788", BuildVersion, QFEVersion); + BuildVersion = 5788; + } } if (strcmp(LibraryName.c_str(), Lib_DSOUND) == 0) { From 0b5bcd6ddae787a835c29d37c04709464300f898 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Mon, 22 Jan 2018 12:45:39 +0100 Subject: [PATCH 14/37] Removed the LED sequence cycle reset feature. After at most 1/6th of a second, a new sequence will be active anyway, so resetting it won't be very useful anyway. This removes the need to check if a new sequence is set, and the need for the bLedHasChanged status boolean, simplifying the code further. This should fix https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/885 --- src/Cxbx/WndMain.cpp | 21 ++------------------- src/CxbxKrnl/EmuShared.h | 3 --- src/devices/SMCDevice.cpp | 2 -- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index db200becb..341fd41cb 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -470,11 +470,9 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP if (m_hwndChild == NULL) { float fps = 0; float mspf = 0; - bool LedHasChanged = false; int LedSequence[4] = { XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN }; g_EmuShared->SetCurrentMSpF(&mspf); g_EmuShared->SetCurrentFPS(&fps); - g_EmuShared->SetLedStatus(&LedHasChanged); g_EmuShared->SetLedSequence(LedSequence); SetTimer(hwnd, TIMERID_FPS, 1000, (TIMERPROC)NULL); SetTimer(hwnd, TIMERID_LED, XBOX_LED_FLASH_PERIOD, (TIMERPROC)NULL); @@ -2112,25 +2110,10 @@ void WndMain::DrawLedBitmap(HWND hwnd, bool bdefault) ActiveLEDColor = XBOX_LED_COLOUR_OFF; } else { // draw colored bitmap - static int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; + int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; static int LedSequenceOffset = 0; - bool bLedHasChanged; - - g_EmuShared->GetLedStatus(&bLedHasChanged); - if (bLedHasChanged) { - // To prevent restarting the sequence when identical sequences are set, check if the new sequence is actually different - int NewLedSequence[4]; - g_EmuShared->GetLedSequence(NewLedSequence); - if (LedSequence[0] != NewLedSequence[0] || LedSequence[1] != NewLedSequence[1] || LedSequence[2] != NewLedSequence[2] || LedSequence[3] != NewLedSequence[3]) { - // Only when the new sequence is different, restart it's cycle - g_EmuShared->GetLedSequence(LedSequence); - LedSequenceOffset = 0; - } - // Indicate we've handled the change - bLedHasChanged = false; - g_EmuShared->SetLedStatus(&bLedHasChanged); - } + g_EmuShared->GetLedSequence(LedSequence); // Select active color and cycle through all 4 phases in the sequence ActiveLEDColor = LedSequence[LedSequenceOffset & 3]; diff --git a/src/CxbxKrnl/EmuShared.h b/src/CxbxKrnl/EmuShared.h index 15ac8fbdb..45311670f 100644 --- a/src/CxbxKrnl/EmuShared.h +++ b/src/CxbxKrnl/EmuShared.h @@ -146,8 +146,6 @@ class EmuShared : public Mutex // ****************************************************************** // * Xbox LED values Accessors // ****************************************************************** - void GetLedStatus(bool *value) { Lock(); *value = m_bLedHasChanged; Unlock(); } - void SetLedStatus(bool *value) { Lock(); m_bLedHasChanged = *value; Unlock(); } void GetLedSequence(int *value) { Lock(); @@ -189,7 +187,6 @@ class EmuShared : public Mutex float m_FPS; bool m_bMultiXbe; PAddr m_LaunchDataPAddress; - bool m_bLedHasChanged; int m_LedSequence[4]; }; diff --git a/src/devices/SMCDevice.cpp b/src/devices/SMCDevice.cpp index 74aad143e..026e9e3bb 100644 --- a/src/devices/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -52,7 +52,6 @@ void SetLEDSequence(LED::Sequence aLEDSequence) // See http://xboxdevwiki.net/PIC#The_LED DbgPrintf("SMC : SetLEDSequence : %u\n", (byte)aLEDSequence); - bool bLedHasChanged = true; int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; LedSequence[0] = ((aLEDSequence >> 6) & 2) | ((aLEDSequence >> 3) & 1); @@ -60,7 +59,6 @@ void SetLEDSequence(LED::Sequence aLEDSequence) LedSequence[2] = ((aLEDSequence >> 4) & 2) | ((aLEDSequence >> 1) & 1); LedSequence[3] = ((aLEDSequence >> 3) & 2) | ((aLEDSequence >> 0) & 1); - g_EmuShared->SetLedStatus(&bLedHasChanged); g_EmuShared->SetLedSequence(LedSequence); } From f738bf47d4ba6209c5a179fe07db5772ab58faaa Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Mon, 22 Jan 2018 13:14:42 +0100 Subject: [PATCH 15/37] Isolated XbePrinter into it's own file, so the Xbe.h/.cpp files don't need to know about it. --- build/win32/Cxbx.vcxproj | 2 + build/win32/Cxbx.vcxproj.filters | 6 + src/Common/Xbe.cpp | 474 +--------------------------- src/Common/Xbe.h | 43 --- src/Common/XbePrinter.cpp | 523 +++++++++++++++++++++++++++++++ src/Common/XbePrinter.h | 87 +++++ src/Cxbx/WndMain.cpp | 5 +- 7 files changed, 623 insertions(+), 517 deletions(-) create mode 100644 src/Common/XbePrinter.cpp create mode 100644 src/Common/XbePrinter.h diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index 226861f85..5b67ca102 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -192,6 +192,7 @@ + @@ -362,6 +363,7 @@ + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 159900e97..feb128c93 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -229,6 +229,9 @@ Hardware + + Shared + @@ -450,6 +453,9 @@ Hardware + + Shared + diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index 6c606f81c..4b91fcaa5 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -34,14 +34,9 @@ // * // ****************************************************************** #include "Xbe.h" -#include "CxbxVersion.h" -#include "CxbxUtil.h" +#include "CxbxUtil.h" // For RoundUp -#include -#include -#include -#include -#include +#include // For ctime #define PAGE_SIZE 0x1000 @@ -548,15 +543,6 @@ static char *BetterTime(uint32 x_timeDate) return x_ctime; } -std::string Xbe::DumpInformation() -{ - if(HasError()) { - return "ERROR"; - } - XbePrinter printer(this); - return printer.GenXbeInfo(); -} - // import logo bitmap from raw monochrome data void Xbe::ImportLogoBitmap(const uint08 x_Gray[100*17]) { @@ -775,459 +761,3 @@ const wchar_t *Xbe::GetUnicodeFilenameAddr() { return (const wchar_t *)GetAddr(m_Header.dwDebugUnicodeFilenameAddr); } - -#define SSTREAM_SET_HEX(stream_name) stream_name << std::setfill('0') << std::uppercase << std::hex; - -XbePrinter::XbePrinter(Xbe* Xbe_object) -{ - Xbe_to_print = Xbe_object; - Xbe_header = &(Xbe_object->m_Header); - Xbe_certificate = &(Xbe_object->m_Certificate); -} - -std::string XbePrinter::GenXbeInfo() -{ - std::string info; - info.append(GenDumpHeader()); - info.append(GenXbeHeaderInfo()); - info.append(GenXbeCertificateInfo()); - info.append(GenSectionInfo()); - info.append(GenLibraryVersions()); - info.append(GenTLS()); - return info; -} - -std::string XbePrinter::GenHexRow( - uint08 *signature, const uint08 row, const uint08 row_size -) -{ - const uint16 offset = row * row_size; - std::stringstream text; - SSTREAM_SET_HEX(text); - for(uint08 x = 0; x < row_size; x++) { - text << std::setw(2) << static_cast(signature[offset + x]); - } - return text.str(); -} - -// https://stackoverflow.com/questions/4786292/converting-unicode-strings-and-vice-versa -std::string XbePrinter::utf8_to_ascii(const wchar_t* utf8_string) -{ - std::wstring_convert> utf8_to_ascii; - const std::wstring utf8_filename(utf8_string); - return utf8_to_ascii.to_bytes(utf8_filename); -} - -std::string XbePrinter::AllowedMediaToString() -{ - const uint32 dwAllowedMedia = Xbe_certificate->dwAllowedMedia; - std::string text = "Media Types:"; - - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) { - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_HARD_DISK) - text.append(" HARD_DISK"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_X2) - text.append(" DVD_X2"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_CD) - text.append(" DVD_CD"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_CD) - text.append(" CD"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_5_RO) - text.append(" DVD_5_RO"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_9_RO) - text.append(" DVD_9_RO"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_5_RW) - text.append(" DVD_5_RW"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_9_RW) - text.append(" DVD_9_RW"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DONGLE) - text.append(" DONGLE"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD) - text.append(" BOARD"); - if((dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) >= (XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD * 2)) - text.append(" UNKNOWN"); - } - - if(dwAllowedMedia & ~XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) { - text.append(" NONSECURE"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK) - text.append(" HARD_DISK"); - if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE) - text.append(" MODE"); - } - return text; -} - -std::string XbePrinter::GameRatingToString() -{ - std::string text; - // Info from: http://xboxdevwiki.net/EEPROM - switch(Xbe_certificate->dwGameRatings) { - case 0x0: - text.append("(RP) Rating Pending"); - break; - case 0x1: - text.append("(AO) Adults Only"); - break; - case 0x2: - text.append("(M) Mature"); - break; - case 0x3: - text.append("(T) Teen"); - break; - case 0x4: - text.append("(E) Everyone"); - break; - case 0x5: - text.append("(K-A) Kids to Adults"); - break; - case 0x6: - text.append("(EC) Early Childhood"); - break; - default: - text.append("ERROR: no rating"); - break; - } - return text; -} - -std::string XbePrinter::GenDumpHeader() -{ - std::string text; - text.append("XBE information generated by Cxbx-Reloaded (Version " _CXBX_VERSION ")\n\n"); - text.append("Title identified as \""); - text.append(Xbe_to_print->m_szAsciiTitle); - text.append("\"\n\n"); - text.append("Dumping XBE file header...\n\n"); - text.append("Magic Number : XBEH\n"); - return text; -} - -std::string XbePrinter::GenXbeHeaderInfo() -{ - std::string text; - text.append(GenDigitalSignature()); - text.append(GenGeneralHeaderInfo1()); - text.append(GenInitFlags()); - text.append(GenGeneralHeaderInfo2()); - return text; -} - -std::string XbePrinter::GenDigitalSignature() -{ - const uint08 row_size = 16; - std::string text; - text.append("Digital Signature : "); - for(int row = 0; row < 16; row++) { - text.append("\n "); - text.append(GenHexRow(&(Xbe_header->pbDigitalSignature[0]), row, row_size)); - } - text.append("\n \n"); - return text; -} - -std::string XbePrinter::GenGeneralHeaderInfo1() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Base Address : 0x" << std::setw(8) << Xbe_header->dwBaseAddr << "\n"; - text << "Size of Headers : 0x" << std::setw(8) << Xbe_header->dwSizeofHeaders << "\n"; - text << "Size of Image : 0x" << std::setw(8) << Xbe_header->dwSizeofImage << "\n"; - text << "Size of Image Header : 0x" << std::setw(8) << Xbe_header->dwSizeofImageHeader << "\n"; - text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwTimeDate << " (" << BetterTime(Xbe_header->dwTimeDate) << ")\n"; - text << "Certificate Address : 0x" << std::setw(8) << Xbe_header->dwCertificateAddr << "\n"; - text << "Number of Sections : 0x" << std::setw(8) << Xbe_header->dwSections << "\n"; - text << "Section Headers Address : 0x" << std::setw(8) << Xbe_header->dwSectionHeadersAddr << "\n"; - return text.str(); -} - -std::string XbePrinter::GenInitFlags() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Init Flags : 0x" << std::setw(8) << Xbe_header->dwInitFlags_value << " "; - - if(Xbe_header->dwInitFlags.bMountUtilityDrive) { - text << "[Mount Utility Drive] "; - } - if(Xbe_header->dwInitFlags.bFormatUtilityDrive) { - text << "[Format Utility Drive] "; - } - if(Xbe_header->dwInitFlags.bLimit64MB) { - text << "[Limit Devkit Run Time Memory to 64MB] "; - } - if(!Xbe_header->dwInitFlags.bDontSetupHarddisk) { - text << "[Setup Harddisk] "; - } - text << "\n"; - return text.str(); -} - -std::string XbePrinter::GenGeneralHeaderInfo2() -{ - const uint32 retail_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_RETAIL; - const uint32 debug_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_DEBUG; - const uint32 retail_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_RETAIL; - const uint32 debug_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_DEBUG; - const std::string AsciiFilename = utf8_to_ascii(Xbe_to_print->GetUnicodeFilenameAddr()); - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Entry Point : 0x" << std::setw(8) << Xbe_header->dwEntryAddr << " (Retail: 0x" << std::setw(8) << retail_entry_point << ", Debug: 0x" << std::setw(8) << debug_entry_point << ")\n"; - text << "TLS Address : 0x" << std::setw(8) << Xbe_header->dwTLSAddr << "\n"; - text << "(PE) Stack Commit : 0x" << std::setw(8) << Xbe_header->dwPeStackCommit << "\n"; - text << "(PE) Heap Reserve : 0x" << std::setw(8) << Xbe_header->dwPeHeapReserve << "\n"; - text << "(PE) Heap Commit : 0x" << std::setw(8) << Xbe_header->dwPeHeapCommit << "\n"; - text << "(PE) Base Address : 0x" << std::setw(8) << Xbe_header->dwPeBaseAddr << "\n"; - text << "(PE) Size of Image : 0x" << std::setw(8) << Xbe_header->dwPeSizeofImage << "\n"; - text << "(PE) Checksum : 0x" << std::setw(8) << Xbe_header->dwPeChecksum << "\n"; - text << "(PE) TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwPeTimeDate << " (" << BetterTime(Xbe_header->dwPeTimeDate) << ")\n"; - text << "Debug Pathname Address : 0x" << std::setw(8) << Xbe_header->dwDebugPathnameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugPathnameAddr) << "\")\n"; - text << "Debug Filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugFilenameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugFilenameAddr) << "\")\n"; - text << "Debug Unicode filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugUnicodeFilenameAddr << " (L\"" << AsciiFilename << "\")\n"; - text << "Kernel Image Thunk Address : 0x" << std::setw(8) << Xbe_header->dwKernelImageThunkAddr << " (Retail: 0x" << std::setw(8) << retail_thunk_addr << ", Debug: 0x" << std::setw(8) << debug_thunk_addr << ")\n"; - text << "NonKernel Import Dir Address : 0x" << std::setw(8) << Xbe_header->dwNonKernelImportDirAddr << "\n"; - text << "Library Versions : 0x" << std::setw(8) << Xbe_header->dwLibraryVersions << "\n"; - text << "Library Versions Address : 0x" << std::setw(8) << Xbe_header->dwLibraryVersionsAddr << "\n"; - text << "Kernel Library Version Address : 0x" << std::setw(8) << Xbe_header->dwKernelLibraryVersionAddr << "\n"; - text << "XAPI Library Version Address : 0x" << std::setw(8) << Xbe_header->dwXAPILibraryVersionAddr << "\n"; - text << "Logo Bitmap Address : 0x" << std::setw(8) << Xbe_header->dwLogoBitmapAddr << "\n"; - text << "Logo Bitmap Size : 0x" << std::setw(8) << Xbe_header->dwSizeofLogoBitmap << "\n\n"; - return text.str(); -} - -std::string XbePrinter::GenXbeCertificateInfo() -{ - std::string text; - text.append(GenCertificateHeader()); - text.append(GenAlternateTitleIDs()); - text.append(GenMediaInfo()); - text.append(GenLANKey()); - text.append(GenSignatureKey()); - text.append(GenAlternateSignatureKeys()); - return text; -} - -std::string XbePrinter::GenCertificateHeader() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Dumping XBE Certificate...\n\n"; - text << "Size of Certificate : 0x" << std::setw(8) << Xbe_certificate->dwSize << "\n"; - text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_certificate->dwTimeDate << " (" << BetterTime(Xbe_certificate->dwTimeDate) << ")\n"; - text << "Title ID : 0x" << std::setw(8) << Xbe_certificate->dwTitleId << "\n"; - text << "Title : L\"" << Xbe_to_print->m_szAsciiTitle << "\"\n"; - return text.str(); -} - -std::string XbePrinter::GenAlternateTitleIDs() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Alternate Titles IDs : "; - - for(int v = 0; v < 0x10; v++) { - if(v != 0) { - text << " "; - } - text << "0x" << std::setw(8) << Xbe_certificate->dwAlternateTitleId[v]; - if(v != 0x0F) { - text << "\n"; - } - } - text << "\n"; - return text.str(); -} - -std::string XbePrinter::GenMediaInfo() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Allowed Media : 0x" << std::setw(8) << Xbe_certificate->dwAllowedMedia << " (" << AllowedMediaToString() << ")\n"; - text << "Game Region : 0x" << std::setw(8) << Xbe_certificate->dwGameRegion << " (" << Xbe_to_print->GameRegionToString() << ")\n"; - text << "Game Ratings : 0x" << std::setw(8) << Xbe_certificate->dwGameRatings << " (" << GameRatingToString() << ")\n"; - text << "Disk Number : 0x" << std::setw(8) << Xbe_certificate->dwDiskNumber << "\n"; - text << "Version : 0x" << std::setw(8) << Xbe_certificate->dwVersion << "\n"; - return text.str(); -} - -std::string XbePrinter::GenLANKey() -{ - const uint08 row = 0; - const uint08 row_size = 16; - std::string text; - text.append("LAN Key : "); - text.append(GenHexRow(&(Xbe_certificate->bzLanKey[0]), row, row_size)); - text.append("\n"); - return text; -} - -std::string XbePrinter::GenSignatureKey() -{ - const uint08 row = 0; - const uint08 row_size = 16; - std::string text; - text.append("Signature Key : "); - text.append(GenHexRow(&(Xbe_certificate->bzSignatureKey[0]), row, row_size)); - text.append("\n"); - return text; -} - -std::string XbePrinter::GenAlternateSignatureKeys() -{ - const uint08 row = 0; - const uint08 row_size = 16; - std::string text; - - text.append("Title Alternate Signature Keys : "); - for(int row = 0; row < 16; row++) - { - text.append("\n "); - text.append(GenHexRow(&(Xbe_certificate->bzTitleAlternateSignatureKey[0][0]), row, row_size)); - } - text.append("\n \n"); - return text; -} - -std::string XbePrinter::GenSectionInfo() -{ - std::string text; - text.append("\nDumping XBE Section Headers...\n\n"); - text.append(GenSectionHeaders()); - return text; -} - -std::string XbePrinter::GenSectionHeaders() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - for(uint32 v=0; v < Xbe_header->dwSections; v++) { - text << "Section Name : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << " (\"" << Xbe_to_print->m_szSectionName[v] << "\")\n"; - text << GenSectionFlags(Xbe_to_print->m_SectionHeader[v]); - text << "Virtual Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualAddr << "\n"; - text << "Virtual Size : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualSize << "\n"; - text << "Raw Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwRawAddr << "\n"; - text << "Size of Raw : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSizeofRaw << "\n"; - text << "Section Name Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << "\n"; - text << "Section Reference Count : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionRefCount << "\n"; - text << "Head Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwHeadSharedRefCountAddr << "\n"; - text << "Tail Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwTailSharedRefCountAddr << "\n"; - text << GenSectionDigest(Xbe_to_print->m_SectionHeader[v]) << "\n"; - } - return text.str(); -} - -std::string XbePrinter::GenSectionFlags(Xbe::SectionHeader section_header) -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Flags : 0x" << std::setw(8) << section_header.dwFlags_value << " "; - - if(section_header.dwFlags.bWritable) { - text << "(Writable) "; - } - if(section_header.dwFlags.bPreload) { - text << "(Preload) "; - } - if(section_header.dwFlags.bExecutable) { - text << "(Executable) "; - } - if(section_header.dwFlags.bInsertedFile) { - text << "(Inserted File) "; - } - if(section_header.dwFlags.bHeadPageRO) { - text << "(Head Page RO) "; - } - if(section_header.dwFlags.bTailPageRO) { - text << "(Tail Page RO) "; - } - text << "\n"; - return text.str(); -} - -std::string XbePrinter::GenSectionDigest(Xbe::SectionHeader section_header) -{ - std::string text; - text.append("Section Digest : "); - text.append(GenHexRow(§ion_header.bzSectionDigest[0], 0, 20)); - text.append("\n"); - return text; -} - -std::string XbePrinter::GenLibraryVersions() -{ - std::stringstream text; - text << "Dumping XBE Library Versions...\n\n"; - - if(Xbe_to_print->m_LibraryVersion == 0 || Xbe_header->dwLibraryVersions == 0) { - text << "(This XBE contains no Library Versions)\n\n"; - } - else { - for(uint32 v = 0; v < Xbe_header->dwLibraryVersions; v++) { - char libname[9]; - for(uint32 c=0;c<8;c++) { - libname[c] = Xbe_to_print->m_LibraryVersion[v].szName[c]; - } - libname[8] = '\0'; - - text << "Library Name : " << libname << "\n"; - text << "Version : " - << Xbe_to_print->m_LibraryVersion[v].wMajorVersion << "." - << Xbe_to_print->m_LibraryVersion[v].wMinorVersion << "." - << Xbe_to_print->m_LibraryVersion[v].wBuildVersion << "\n"; - text << GenLibraryFlags(Xbe_to_print->m_LibraryVersion[v]); - text << "\n"; - } - } - return text.str(); -} - -std::string XbePrinter::GenLibraryFlags(Xbe::LibraryVersion libver) -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - text << "Flags : 0x" << std::setw(4) << libver.wFlags_value << " "; - text << "QFEVersion : 0x" << std::setw(4) << libver.wFlags.QFEVersion << ", "; - - if(libver.wFlags.bDebugBuild) { - text << "Debug, "; - } - else { - text << "Retail, "; - } - - switch(libver.wFlags.Approved) { - case 0: - text << "Unapproved"; - break; - case 1: - text << "Possibly Approved"; - break; - case 2: - text << "Approved"; - break; - } - text << "\n"; - return text.str(); -} - -std::string XbePrinter::GenTLS() -{ - std::stringstream text; - SSTREAM_SET_HEX(text); - Xbe::TLS *local_TLS = Xbe_to_print->m_TLS; - - text << "Dumping XBE TLS...\n\n"; - // print thread local storage - if(local_TLS != 0) { - text << "Data Start Address : 0x" << std::setw(8) << local_TLS->dwDataStartAddr << "\n"; - text << "Data End Address : 0x" << std::setw(8) << local_TLS->dwDataEndAddr << "\n"; - text << "TLS Index Address : 0x" << std::setw(8) << local_TLS->dwTLSIndexAddr << "\n"; - text << "TLS Callback Address : 0x" << std::setw(8) << local_TLS->dwTLSCallbackAddr << "\n"; - text << "Size of Zero Fill : 0x" << std::setw(8) << local_TLS->dwSizeofZeroFill << "\n"; - text << "Characteristics : 0x" << std::setw(8) << local_TLS->dwCharacteristics << "\n"; - } - else { - text << "(This XBE contains no TLS)\n"; - } - return text.str(); -} diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index 61fa22b10..f6b0e6f27 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -345,49 +345,6 @@ class Xbe : public Error *m_xprImage; }; -class XbePrinter -{ - public: - XbePrinter(Xbe*); - std::string GenXbeInfo(); - - private: - Xbe *Xbe_to_print; - Xbe::Header *Xbe_header; - Xbe::Certificate *Xbe_certificate; - - std::string GenHexRow(uint08*, const uint08, const uint08); - std::string utf8_to_ascii(const wchar_t*); - std::string AllowedMediaToString(); - std::string GameRatingToString(); - - std::string GenDumpHeader(); - - std::string GenXbeHeaderInfo(); - std::string GenDigitalSignature(); - std::string GenGeneralHeaderInfo1(); - std::string GenInitFlags(); - std::string GenGeneralHeaderInfo2(); - - std::string GenXbeCertificateInfo(); - std::string GenCertificateHeader(); - std::string GenAlternateTitleIDs(); - std::string GenMediaInfo(); - std::string GenLANKey(); - std::string GenSignatureKey(); - std::string GenAlternateSignatureKeys(); - - std::string GenSectionInfo(); - std::string GenSectionHeaders(); - std::string GenSectionFlags(Xbe::SectionHeader); - std::string GenSectionDigest(Xbe::SectionHeader); - - std::string GenLibraryVersions(); - std::string GenLibraryFlags(Xbe::LibraryVersion); - - std::string GenTLS(); -}; - // debug/retail XOR keys const uint32 XOR_EP_DEBUG = 0x94859D4B; // Entry Point (Debug) const uint32 XOR_EP_RETAIL = 0xA8FC57AB; // Entry Point (Retail) diff --git a/src/Common/XbePrinter.cpp b/src/Common/XbePrinter.cpp new file mode 100644 index 000000000..65c1660db --- /dev/null +++ b/src/Common/XbePrinter.cpp @@ -0,0 +1,523 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Common->Xbe.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * +// * All rights reserved +// * +// ****************************************************************** + +#include "XbePrinter.h" +#include "CxbxVersion.h" // For _CXBX_VERSION + +#include // For ctime +#include // For std::codecvt_utf8<> +#include // For std::stringstream +#include // For std::setfill, std::uppercase, std::hex + +// better time +static char *BetterTime(uint32 x_timeDate) +{ + time_t x_time = x_timeDate; + char *x_ctime = ctime(&x_time); + + int v=0; + + for(v=0;x_ctime[v] != '\n';v++); + + x_ctime[v] = '\0'; + + return x_ctime; +} + +std::string DumpInformation(Xbe* Xbe_object) +{ + if(Xbe_object->HasError()) { + return "ERROR"; + } + XbePrinter printer(Xbe_object); + return printer.GenXbeInfo(); +} + +#define SSTREAM_SET_HEX(stream_name) stream_name << std::setfill('0') << std::uppercase << std::hex; + +XbePrinter::XbePrinter(Xbe* Xbe_object) +{ + Xbe_to_print = Xbe_object; + Xbe_header = &(Xbe_object->m_Header); + Xbe_certificate = &(Xbe_object->m_Certificate); +} + +std::string XbePrinter::GenXbeInfo() +{ + std::string info; + info.append(GenDumpHeader()); + info.append(GenXbeHeaderInfo()); + info.append(GenXbeCertificateInfo()); + info.append(GenSectionInfo()); + info.append(GenLibraryVersions()); + info.append(GenTLS()); + return info; +} + +std::string XbePrinter::GenHexRow( + uint08 *signature, const uint08 row, const uint08 row_size +) +{ + const uint16 offset = row * row_size; + std::stringstream text; + SSTREAM_SET_HEX(text); + for(uint08 x = 0; x < row_size; x++) { + text << std::setw(2) << static_cast(signature[offset + x]); + } + return text.str(); +} + +// https://stackoverflow.com/questions/4786292/converting-unicode-strings-and-vice-versa +std::string XbePrinter::utf8_to_ascii(const wchar_t* utf8_string) +{ + std::wstring_convert> utf8_to_ascii; + const std::wstring utf8_filename(utf8_string); + return utf8_to_ascii.to_bytes(utf8_filename); +} + +std::string XbePrinter::AllowedMediaToString() +{ + const uint32 dwAllowedMedia = Xbe_certificate->dwAllowedMedia; + std::string text = "Media Types:"; + + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) { + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_HARD_DISK) + text.append(" HARD_DISK"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_X2) + text.append(" DVD_X2"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_CD) + text.append(" DVD_CD"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_CD) + text.append(" CD"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_5_RO) + text.append(" DVD_5_RO"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_9_RO) + text.append(" DVD_9_RO"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_5_RW) + text.append(" DVD_5_RW"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DVD_9_RW) + text.append(" DVD_9_RW"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_DONGLE) + text.append(" DONGLE"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD) + text.append(" BOARD"); + if((dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) >= (XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD * 2)) + text.append(" UNKNOWN"); + } + + if(dwAllowedMedia & ~XBEIMAGE_MEDIA_TYPE_MEDIA_MASK) { + text.append(" NONSECURE"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK) + text.append(" HARD_DISK"); + if(dwAllowedMedia & XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE) + text.append(" MODE"); + } + return text; +} + +std::string XbePrinter::GameRatingToString() +{ + std::string text; + // Info from: http://xboxdevwiki.net/EEPROM + switch(Xbe_certificate->dwGameRatings) { + case 0x0: + text.append("(RP) Rating Pending"); + break; + case 0x1: + text.append("(AO) Adults Only"); + break; + case 0x2: + text.append("(M) Mature"); + break; + case 0x3: + text.append("(T) Teen"); + break; + case 0x4: + text.append("(E) Everyone"); + break; + case 0x5: + text.append("(K-A) Kids to Adults"); + break; + case 0x6: + text.append("(EC) Early Childhood"); + break; + default: + text.append("ERROR: no rating"); + break; + } + return text; +} + +std::string XbePrinter::GenDumpHeader() +{ + std::string text; + text.append("XBE information generated by Cxbx-Reloaded (Version " _CXBX_VERSION ")\n\n"); + text.append("Title identified as \""); + text.append(Xbe_to_print->m_szAsciiTitle); + text.append("\"\n\n"); + text.append("Dumping XBE file header...\n\n"); + text.append("Magic Number : XBEH\n"); + return text; +} + +std::string XbePrinter::GenXbeHeaderInfo() +{ + std::string text; + text.append(GenDigitalSignature()); + text.append(GenGeneralHeaderInfo1()); + text.append(GenInitFlags()); + text.append(GenGeneralHeaderInfo2()); + return text; +} + +std::string XbePrinter::GenDigitalSignature() +{ + const uint08 row_size = 16; + std::string text; + text.append("Digital Signature : "); + for(int row = 0; row < 16; row++) { + text.append("\n "); + text.append(GenHexRow(&(Xbe_header->pbDigitalSignature[0]), row, row_size)); + } + text.append("\n \n"); + return text; +} + +std::string XbePrinter::GenGeneralHeaderInfo1() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Base Address : 0x" << std::setw(8) << Xbe_header->dwBaseAddr << "\n"; + text << "Size of Headers : 0x" << std::setw(8) << Xbe_header->dwSizeofHeaders << "\n"; + text << "Size of Image : 0x" << std::setw(8) << Xbe_header->dwSizeofImage << "\n"; + text << "Size of Image Header : 0x" << std::setw(8) << Xbe_header->dwSizeofImageHeader << "\n"; + text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwTimeDate << " (" << BetterTime(Xbe_header->dwTimeDate) << ")\n"; + text << "Certificate Address : 0x" << std::setw(8) << Xbe_header->dwCertificateAddr << "\n"; + text << "Number of Sections : 0x" << std::setw(8) << Xbe_header->dwSections << "\n"; + text << "Section Headers Address : 0x" << std::setw(8) << Xbe_header->dwSectionHeadersAddr << "\n"; + return text.str(); +} + +std::string XbePrinter::GenInitFlags() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Init Flags : 0x" << std::setw(8) << Xbe_header->dwInitFlags_value << " "; + + if(Xbe_header->dwInitFlags.bMountUtilityDrive) { + text << "[Mount Utility Drive] "; + } + if(Xbe_header->dwInitFlags.bFormatUtilityDrive) { + text << "[Format Utility Drive] "; + } + if(Xbe_header->dwInitFlags.bLimit64MB) { + text << "[Limit Devkit Run Time Memory to 64MB] "; + } + if(!Xbe_header->dwInitFlags.bDontSetupHarddisk) { + text << "[Setup Harddisk] "; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenGeneralHeaderInfo2() +{ + const uint32 retail_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_RETAIL; + const uint32 debug_entry_point = Xbe_header->dwEntryAddr ^ XOR_EP_DEBUG; + const uint32 retail_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_RETAIL; + const uint32 debug_thunk_addr = Xbe_header->dwKernelImageThunkAddr ^ XOR_KT_DEBUG; + const std::string AsciiFilename = utf8_to_ascii(Xbe_to_print->GetUnicodeFilenameAddr()); + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Entry Point : 0x" << std::setw(8) << Xbe_header->dwEntryAddr << " (Retail: 0x" << std::setw(8) << retail_entry_point << ", Debug: 0x" << std::setw(8) << debug_entry_point << ")\n"; + text << "TLS Address : 0x" << std::setw(8) << Xbe_header->dwTLSAddr << "\n"; + text << "(PE) Stack Commit : 0x" << std::setw(8) << Xbe_header->dwPeStackCommit << "\n"; + text << "(PE) Heap Reserve : 0x" << std::setw(8) << Xbe_header->dwPeHeapReserve << "\n"; + text << "(PE) Heap Commit : 0x" << std::setw(8) << Xbe_header->dwPeHeapCommit << "\n"; + text << "(PE) Base Address : 0x" << std::setw(8) << Xbe_header->dwPeBaseAddr << "\n"; + text << "(PE) Size of Image : 0x" << std::setw(8) << Xbe_header->dwPeSizeofImage << "\n"; + text << "(PE) Checksum : 0x" << std::setw(8) << Xbe_header->dwPeChecksum << "\n"; + text << "(PE) TimeDate Stamp : 0x" << std::setw(8) << Xbe_header->dwPeTimeDate << " (" << BetterTime(Xbe_header->dwPeTimeDate) << ")\n"; + text << "Debug Pathname Address : 0x" << std::setw(8) << Xbe_header->dwDebugPathnameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugPathnameAddr) << "\")\n"; + text << "Debug Filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugFilenameAddr << " (\"" << Xbe_to_print->GetAddr(Xbe_header->dwDebugFilenameAddr) << "\")\n"; + text << "Debug Unicode filename Address : 0x" << std::setw(8) << Xbe_header->dwDebugUnicodeFilenameAddr << " (L\"" << AsciiFilename << "\")\n"; + text << "Kernel Image Thunk Address : 0x" << std::setw(8) << Xbe_header->dwKernelImageThunkAddr << " (Retail: 0x" << std::setw(8) << retail_thunk_addr << ", Debug: 0x" << std::setw(8) << debug_thunk_addr << ")\n"; + text << "NonKernel Import Dir Address : 0x" << std::setw(8) << Xbe_header->dwNonKernelImportDirAddr << "\n"; + text << "Library Versions : 0x" << std::setw(8) << Xbe_header->dwLibraryVersions << "\n"; + text << "Library Versions Address : 0x" << std::setw(8) << Xbe_header->dwLibraryVersionsAddr << "\n"; + text << "Kernel Library Version Address : 0x" << std::setw(8) << Xbe_header->dwKernelLibraryVersionAddr << "\n"; + text << "XAPI Library Version Address : 0x" << std::setw(8) << Xbe_header->dwXAPILibraryVersionAddr << "\n"; + text << "Logo Bitmap Address : 0x" << std::setw(8) << Xbe_header->dwLogoBitmapAddr << "\n"; + text << "Logo Bitmap Size : 0x" << std::setw(8) << Xbe_header->dwSizeofLogoBitmap << "\n\n"; + return text.str(); +} + +std::string XbePrinter::GenXbeCertificateInfo() +{ + std::string text; + text.append(GenCertificateHeader()); + text.append(GenAlternateTitleIDs()); + text.append(GenMediaInfo()); + text.append(GenLANKey()); + text.append(GenSignatureKey()); + text.append(GenAlternateSignatureKeys()); + return text; +} + +std::string XbePrinter::GenCertificateHeader() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Dumping XBE Certificate...\n\n"; + text << "Size of Certificate : 0x" << std::setw(8) << Xbe_certificate->dwSize << "\n"; + text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_certificate->dwTimeDate << " (" << BetterTime(Xbe_certificate->dwTimeDate) << ")\n"; + text << "Title ID : 0x" << std::setw(8) << Xbe_certificate->dwTitleId << "\n"; + text << "Title : L\"" << Xbe_to_print->m_szAsciiTitle << "\"\n"; + return text.str(); +} + +std::string XbePrinter::GenAlternateTitleIDs() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Alternate Titles IDs : "; + + for(int v = 0; v < 0x10; v++) { + if(v != 0) { + text << " "; + } + text << "0x" << std::setw(8) << Xbe_certificate->dwAlternateTitleId[v]; + if(v != 0x0F) { + text << "\n"; + } + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenMediaInfo() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Allowed Media : 0x" << std::setw(8) << Xbe_certificate->dwAllowedMedia << " (" << AllowedMediaToString() << ")\n"; + text << "Game Region : 0x" << std::setw(8) << Xbe_certificate->dwGameRegion << " (" << Xbe_to_print->GameRegionToString() << ")\n"; + text << "Game Ratings : 0x" << std::setw(8) << Xbe_certificate->dwGameRatings << " (" << GameRatingToString() << ")\n"; + text << "Disk Number : 0x" << std::setw(8) << Xbe_certificate->dwDiskNumber << "\n"; + text << "Version : 0x" << std::setw(8) << Xbe_certificate->dwVersion << "\n"; + return text.str(); +} + +std::string XbePrinter::GenLANKey() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + text.append("LAN Key : "); + text.append(GenHexRow(&(Xbe_certificate->bzLanKey[0]), row, row_size)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenSignatureKey() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + text.append("Signature Key : "); + text.append(GenHexRow(&(Xbe_certificate->bzSignatureKey[0]), row, row_size)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenAlternateSignatureKeys() +{ + const uint08 row = 0; + const uint08 row_size = 16; + std::string text; + + text.append("Title Alternate Signature Keys : "); + for(int row = 0; row < 16; row++) + { + text.append("\n "); + text.append(GenHexRow(&(Xbe_certificate->bzTitleAlternateSignatureKey[0][0]), row, row_size)); + } + text.append("\n \n"); + return text; +} + +std::string XbePrinter::GenSectionInfo() +{ + std::string text; + text.append("\nDumping XBE Section Headers...\n\n"); + text.append(GenSectionHeaders()); + return text; +} + +std::string XbePrinter::GenSectionHeaders() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + for(uint32 v=0; v < Xbe_header->dwSections; v++) { + text << "Section Name : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << " (\"" << Xbe_to_print->m_szSectionName[v] << "\")\n"; + text << GenSectionFlags(Xbe_to_print->m_SectionHeader[v]); + text << "Virtual Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualAddr << "\n"; + text << "Virtual Size : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwVirtualSize << "\n"; + text << "Raw Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwRawAddr << "\n"; + text << "Size of Raw : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSizeofRaw << "\n"; + text << "Section Name Address : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionNameAddr << "\n"; + text << "Section Reference Count : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionRefCount << "\n"; + text << "Head Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwHeadSharedRefCountAddr << "\n"; + text << "Tail Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwTailSharedRefCountAddr << "\n"; + text << GenSectionDigest(Xbe_to_print->m_SectionHeader[v]) << "\n"; + } + return text.str(); +} + +std::string XbePrinter::GenSectionFlags(Xbe::SectionHeader section_header) +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Flags : 0x" << std::setw(8) << section_header.dwFlags_value << " "; + + if(section_header.dwFlags.bWritable) { + text << "(Writable) "; + } + if(section_header.dwFlags.bPreload) { + text << "(Preload) "; + } + if(section_header.dwFlags.bExecutable) { + text << "(Executable) "; + } + if(section_header.dwFlags.bInsertedFile) { + text << "(Inserted File) "; + } + if(section_header.dwFlags.bHeadPageRO) { + text << "(Head Page RO) "; + } + if(section_header.dwFlags.bTailPageRO) { + text << "(Tail Page RO) "; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenSectionDigest(Xbe::SectionHeader section_header) +{ + std::string text; + text.append("Section Digest : "); + text.append(GenHexRow(§ion_header.bzSectionDigest[0], 0, 20)); + text.append("\n"); + return text; +} + +std::string XbePrinter::GenLibraryVersions() +{ + std::stringstream text; + text << "Dumping XBE Library Versions...\n\n"; + + if(Xbe_to_print->m_LibraryVersion == 0 || Xbe_header->dwLibraryVersions == 0) { + text << "(This XBE contains no Library Versions)\n\n"; + } + else { + for(uint32 v = 0; v < Xbe_header->dwLibraryVersions; v++) { + char libname[9]; + for(uint32 c=0;c<8;c++) { + libname[c] = Xbe_to_print->m_LibraryVersion[v].szName[c]; + } + libname[8] = '\0'; + + text << "Library Name : " << libname << "\n"; + text << "Version : " + << Xbe_to_print->m_LibraryVersion[v].wMajorVersion << "." + << Xbe_to_print->m_LibraryVersion[v].wMinorVersion << "." + << Xbe_to_print->m_LibraryVersion[v].wBuildVersion << "\n"; + text << GenLibraryFlags(Xbe_to_print->m_LibraryVersion[v]); + text << "\n"; + } + } + return text.str(); +} + +std::string XbePrinter::GenLibraryFlags(Xbe::LibraryVersion libver) +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + text << "Flags : 0x" << std::setw(4) << libver.wFlags_value << " "; + text << "QFEVersion : 0x" << std::setw(4) << libver.wFlags.QFEVersion << ", "; + + if(libver.wFlags.bDebugBuild) { + text << "Debug, "; + } + else { + text << "Retail, "; + } + + switch(libver.wFlags.Approved) { + case 0: + text << "Unapproved"; + break; + case 1: + text << "Possibly Approved"; + break; + case 2: + text << "Approved"; + break; + } + text << "\n"; + return text.str(); +} + +std::string XbePrinter::GenTLS() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + Xbe::TLS *local_TLS = Xbe_to_print->m_TLS; + + text << "Dumping XBE TLS...\n\n"; + // print thread local storage + if(local_TLS != 0) { + text << "Data Start Address : 0x" << std::setw(8) << local_TLS->dwDataStartAddr << "\n"; + text << "Data End Address : 0x" << std::setw(8) << local_TLS->dwDataEndAddr << "\n"; + text << "TLS Index Address : 0x" << std::setw(8) << local_TLS->dwTLSIndexAddr << "\n"; + text << "TLS Callback Address : 0x" << std::setw(8) << local_TLS->dwTLSCallbackAddr << "\n"; + text << "Size of Zero Fill : 0x" << std::setw(8) << local_TLS->dwSizeofZeroFill << "\n"; + text << "Characteristics : 0x" << std::setw(8) << local_TLS->dwCharacteristics << "\n"; + } + else { + text << "(This XBE contains no TLS)\n"; + } + return text.str(); +} diff --git a/src/Common/XbePrinter.h b/src/Common/XbePrinter.h new file mode 100644 index 000000000..93a087210 --- /dev/null +++ b/src/Common/XbePrinter.h @@ -0,0 +1,87 @@ +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Common->XbePrinter.h +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * +// * All rights reserved +// * +// ****************************************************************** +#ifndef XBE_PRINTER_H +#define XBE_PRINTER_H + +#include "Common/Error.h" +#include "Common/Xbe.h" + +#include + +extern std::string DumpInformation(Xbe* Xbe_object); + +class XbePrinter +{ + public: + XbePrinter(Xbe*); + std::string GenXbeInfo(); + + private: + Xbe *Xbe_to_print; + Xbe::Header *Xbe_header; + Xbe::Certificate *Xbe_certificate; + + std::string GenHexRow(uint08*, const uint08, const uint08); + std::string utf8_to_ascii(const wchar_t*); + std::string AllowedMediaToString(); + std::string GameRatingToString(); + + std::string GenDumpHeader(); + + std::string GenXbeHeaderInfo(); + std::string GenDigitalSignature(); + std::string GenGeneralHeaderInfo1(); + std::string GenInitFlags(); + std::string GenGeneralHeaderInfo2(); + + std::string GenXbeCertificateInfo(); + std::string GenCertificateHeader(); + std::string GenAlternateTitleIDs(); + std::string GenMediaInfo(); + std::string GenLANKey(); + std::string GenSignatureKey(); + std::string GenAlternateSignatureKeys(); + + std::string GenSectionInfo(); + std::string GenSectionHeaders(); + std::string GenSectionFlags(Xbe::SectionHeader); + std::string GenSectionDigest(Xbe::SectionHeader); + + std::string GenLibraryVersions(); + std::string GenLibraryFlags(Xbe::LibraryVersion); + + std::string GenTLS(); +}; + +#endif // XBE_PRINTER_H diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 6e2b07efd..7613f4679 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -38,6 +38,7 @@ #include "DlgControllerConfig.h" #include "DlgVideoConfig.h" #include "DlgAudioConfig.h" +#include "Common/XbePrinter.h" // For DumpInformation #include "CxbxKrnl/EmuShared.h" #include "ResCxbx.h" #include "CxbxVersion.h" @@ -1006,7 +1007,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP // dump xbe information to file { - std::string Xbe_info = m_Xbe->DumpInformation(); + std::string Xbe_info = DumpInformation(m_Xbe); if (m_Xbe->HasError()) { MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); } @@ -1031,7 +1032,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_EDIT_DUMPXBEINFOTO_DEBUGCONSOLE: { - std::string Xbe_info = m_Xbe->DumpInformation(); + std::string Xbe_info = DumpInformation(m_Xbe); if (m_Xbe->HasError()) { MessageBox(m_hwnd, m_Xbe->GetError().c_str(), "Cxbx-Reloaded", MB_ICONSTOP | MB_OK); } From 1a4295c3da5f40fa9bc89185889adc533bdb50f7 Mon Sep 17 00:00:00 2001 From: ergo720 Date: Mon, 22 Jan 2018 16:06:17 +0100 Subject: [PATCH 16/37] HalIsResetOrShutdownPending implementation --- src/CxbxKrnl/EmuKrnlHal.cpp | 14 +++++++++++--- src/devices/SMCDevice.cpp | 14 ++++++++++++++ src/devices/SMCDevice.h | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index ac4b91247..216fd8ec2 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -684,9 +684,14 @@ XBSYSAPI EXPORTNUM(358) xboxkrnl::BOOLEAN NTAPI xboxkrnl::HalIsResetOrShutdownPe { LOG_FUNC(); - LOG_UNIMPLEMENTED(); + BOOLEAN ret = FALSE; + uint8_t CommandCode; + uint32_t DataValue; + g_SMC->GetResetOrShutdownCode(&CommandCode, &DataValue); - RETURN(FALSE); + if (CommandCode != 0) { ret = TRUE; } + + RETURN(ret); } // ****************************************************************** @@ -699,7 +704,10 @@ XBSYSAPI EXPORTNUM(360) xboxkrnl::NTSTATUS NTAPI xboxkrnl::HalInitiateShutdown { LOG_FUNC(); - xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, SMC_COMMAND_RESET, 0, SMC_RESET_ASSERT_SHUTDOWN); + uint8_t CommandCode = SMC_COMMAND_RESET; + uint32_t DataValue = SMC_RESET_ASSERT_SHUTDOWN; + g_SMC->SetResetOrShutdownCode(&CommandCode, &DataValue); + xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, CommandCode, 0, DataValue); RETURN(S_OK); } diff --git a/src/devices/SMCDevice.cpp b/src/devices/SMCDevice.cpp index 026e9e3bb..3b83ba6d1 100644 --- a/src/devices/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -75,6 +75,8 @@ void SMCDevice::Init() buffer[SMC_COMMAND_AV_PACK] = AV_PACK_HDTV; // see http://xboxdevwiki.net/PIC#The_AV_Pack buffer[SMC_COMMAND_LED_SEQUENCE] = LED::GREEN; buffer[SMC_COMMAND_SCRATCH] = 0; // http://xboxdevwiki.net/PIC#Scratch_register_values + ResetOrShutdownCommandCode.store(0); + ResetOrShutdownDataValue.store(0); } void SMCDevice::Reset() @@ -209,3 +211,15 @@ void SMCDevice::WriteBlock(uint8_t command, uint8_t* data, int length) { // TODO } + +void SMCDevice::GetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue) +{ + *CommandCode = ResetOrShutdownCommandCode.load(); + *DataValue = ResetOrShutdownDataValue.load(); +} + +void SMCDevice::SetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue) +{ + ResetOrShutdownCommandCode.store(*CommandCode); + ResetOrShutdownDataValue.store(*DataValue); +} diff --git a/src/devices/SMCDevice.h b/src/devices/SMCDevice.h index dd0cfabbb..a43cc0d40 100644 --- a/src/devices/SMCDevice.h +++ b/src/devices/SMCDevice.h @@ -36,6 +36,7 @@ #pragma once #include "SMDevice.h" +#include // This https://upload.wikimedia.org/wikipedia/commons/9/94/Xbox-Motherboard-FR.jpg shows : // PIC16LC63A-04/SO @@ -119,10 +120,15 @@ public: void WriteByte(uint8_t command, uint8_t value); void WriteWord(uint8_t command, uint16_t value); void WriteBlock(uint8_t command, uint8_t* data, int length); + void GetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue); + void SetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue); private: HardwareModel m_HardwareModel; int m_PICVersionStringIndex = 0; uint8_t buffer[256] = {}; + // variables used by the SMC to know a reset / shutdown is pending + std::atomic ResetOrShutdownCommandCode; + std::atomic ResetOrShutdownDataValue; }; extern SMCDevice* g_SMC; From f0f152ace5bb9ccfcef340b7fde64b57078dacaa Mon Sep 17 00:00:00 2001 From: ergo720 Date: Mon, 22 Jan 2018 19:08:08 +0100 Subject: [PATCH 17/37] Simplified HalIsResetOrShutdownPending implementation --- src/CxbxKrnl/EmuKrnlHal.cpp | 17 +++++++++-------- src/devices/SMCDevice.cpp | 13 ------------- src/devices/SMCDevice.h | 7 +------ 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index 216fd8ec2..dc82052a0 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -70,6 +70,11 @@ namespace NtDll static DWORD EmuSoftwareInterrupRequestRegister = 0; HalSystemInterrupt HalSystemInterrupts[MAX_BUS_INTERRUPT_LEVEL + 1]; +// variables used by the SMC to know a reset / shutdown is pending +uint8_t ResetOrShutdownCommandCode = 0; +uint32_t ResetOrShutdownDataValue = 0; + + // ****************************************************************** // * 0x0009 - HalReadSMCTrayState() // ****************************************************************** @@ -685,11 +690,8 @@ XBSYSAPI EXPORTNUM(358) xboxkrnl::BOOLEAN NTAPI xboxkrnl::HalIsResetOrShutdownPe LOG_FUNC(); BOOLEAN ret = FALSE; - uint8_t CommandCode; - uint32_t DataValue; - g_SMC->GetResetOrShutdownCode(&CommandCode, &DataValue); - if (CommandCode != 0) { ret = TRUE; } + if (ResetOrShutdownCommandCode != 0) { ret = TRUE; } RETURN(ret); } @@ -704,10 +706,9 @@ XBSYSAPI EXPORTNUM(360) xboxkrnl::NTSTATUS NTAPI xboxkrnl::HalInitiateShutdown { LOG_FUNC(); - uint8_t CommandCode = SMC_COMMAND_RESET; - uint32_t DataValue = SMC_RESET_ASSERT_SHUTDOWN; - g_SMC->SetResetOrShutdownCode(&CommandCode, &DataValue); - xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, CommandCode, 0, DataValue); + ResetOrShutdownCommandCode = SMC_COMMAND_RESET; + ResetOrShutdownDataValue = SMC_RESET_ASSERT_SHUTDOWN; + xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, ResetOrShutdownCommandCode, 0, ResetOrShutdownDataValue); RETURN(S_OK); } diff --git a/src/devices/SMCDevice.cpp b/src/devices/SMCDevice.cpp index 3b83ba6d1..d496ea7e3 100644 --- a/src/devices/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -75,8 +75,6 @@ void SMCDevice::Init() buffer[SMC_COMMAND_AV_PACK] = AV_PACK_HDTV; // see http://xboxdevwiki.net/PIC#The_AV_Pack buffer[SMC_COMMAND_LED_SEQUENCE] = LED::GREEN; buffer[SMC_COMMAND_SCRATCH] = 0; // http://xboxdevwiki.net/PIC#Scratch_register_values - ResetOrShutdownCommandCode.store(0); - ResetOrShutdownDataValue.store(0); } void SMCDevice::Reset() @@ -212,14 +210,3 @@ void SMCDevice::WriteBlock(uint8_t command, uint8_t* data, int length) // TODO } -void SMCDevice::GetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue) -{ - *CommandCode = ResetOrShutdownCommandCode.load(); - *DataValue = ResetOrShutdownDataValue.load(); -} - -void SMCDevice::SetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue) -{ - ResetOrShutdownCommandCode.store(*CommandCode); - ResetOrShutdownDataValue.store(*DataValue); -} diff --git a/src/devices/SMCDevice.h b/src/devices/SMCDevice.h index a43cc0d40..306b04ca7 100644 --- a/src/devices/SMCDevice.h +++ b/src/devices/SMCDevice.h @@ -36,7 +36,6 @@ #pragma once #include "SMDevice.h" -#include // This https://upload.wikimedia.org/wikipedia/commons/9/94/Xbox-Motherboard-FR.jpg shows : // PIC16LC63A-04/SO @@ -120,15 +119,11 @@ public: void WriteByte(uint8_t command, uint8_t value); void WriteWord(uint8_t command, uint16_t value); void WriteBlock(uint8_t command, uint8_t* data, int length); - void GetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue); - void SetResetOrShutdownCode(uint8_t* CommandCode, uint32_t* DataValue); + private: HardwareModel m_HardwareModel; int m_PICVersionStringIndex = 0; uint8_t buffer[256] = {}; - // variables used by the SMC to know a reset / shutdown is pending - std::atomic ResetOrShutdownCommandCode; - std::atomic ResetOrShutdownDataValue; }; extern SMCDevice* g_SMC; From 8139bd833d087a2e019bbbd3de2a5192498107e0 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Mon, 15 Jan 2018 22:19:21 +0000 Subject: [PATCH 18/37] Silent Hill 2 no longer overflows the g_IVBTable --- src/CxbxKrnl/EmuD3D8.cpp | 5 ----- src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp | 2 +- src/CxbxKrnl/EmuD3D8/VertexBuffer.h | 12 +++++++----- 3 files changed, 8 insertions(+), 11 deletions(-) mode change 100644 => 100755 src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp mode change 100644 => 100755 src/CxbxKrnl/EmuD3D8/VertexBuffer.h diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 600fe65ae..a4c04715b 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -4678,11 +4678,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_Begin) g_IVBPrimitiveType = PrimitiveType; - if(g_IVBTable == nullptr) - { - g_IVBTable = (struct XTL::_D3DIVB*)g_VMManager.Allocate(sizeof(XTL::_D3DIVB)*IVB_TABLE_SIZE); - } - g_IVBTblOffs = 0; g_IVBFVF = 0; diff --git a/src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp b/src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp old mode 100644 new mode 100755 index 43225c780..548475600 --- a/src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp +++ b/src/CxbxKrnl/EmuD3D8/VertexBuffer.cpp @@ -53,7 +53,7 @@ XTL::DWORD *XTL::g_pIVBVertexBuffer = nullptr; XTL::X_D3DPRIMITIVETYPE XTL::g_IVBPrimitiveType = XTL::X_D3DPT_INVALID; UINT XTL::g_IVBTblOffs = 0; -struct XTL::_D3DIVB *XTL::g_IVBTable = nullptr; +struct XTL::_D3DIVB XTL::g_IVBTable[IVB_TABLE_SIZE]; extern DWORD XTL::g_IVBFVF = 0; extern XTL::X_D3DVertexBuffer *g_pVertexBuffer = NULL; diff --git a/src/CxbxKrnl/EmuD3D8/VertexBuffer.h b/src/CxbxKrnl/EmuD3D8/VertexBuffer.h old mode 100644 new mode 100755 index 91d79dfbf..83422dd61 --- a/src/CxbxKrnl/EmuD3D8/VertexBuffer.h +++ b/src/CxbxKrnl/EmuD3D8/VertexBuffer.h @@ -130,12 +130,13 @@ extern DWORD *g_pIVBVertexBuffer; extern X_D3DPRIMITIVETYPE g_IVBPrimitiveType; extern DWORD g_IVBFVF; -#define IVB_TABLE_SIZE 1024 -#define IVB_BUFFER_SIZE sizeof(_D3DIVB)*1024 +#define IVB_TABLE_SIZE ONE_MB // This should be more than enough.. Tweak as necessary if it overflows +#define IVB_BUFFER_SIZE sizeof(_D3DIVB) * IVB_TABLE_SIZE + // TODO : Enlarge IVB_TABLE_SIZE and IVB_BUFFER_SIZE // TODO : Calculate IVB_BUFFER_SIZE using sizeof(DWORD) -extern struct _D3DIVB +struct _D3DIVB { XTL::D3DXVECTOR3 Position; // Position FLOAT Rhw; // Rhw @@ -147,8 +148,9 @@ extern struct _D3DIVB XTL::D3DXVECTOR2 TexCoord2; // TexCoord2 XTL::D3DXVECTOR2 TexCoord3; // TexCoord3 XTL::D3DXVECTOR2 TexCoord4; // TexCoord4 -} -*g_IVBTable; +}; + +extern _D3DIVB g_IVBTable[IVB_TABLE_SIZE]; extern UINT g_IVBTblOffs; From ec1172f68f521dc0c4fd098301d5374eb0509505 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Tue, 16 Jan 2018 08:23:25 +0000 Subject: [PATCH 19/37] Make Unknown IVB Register a Warning rather than a hard crash --- src/CxbxKrnl/EmuD3D8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index a4c04715b..eaa8f169c 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -4898,7 +4898,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) } default: - CxbxKrnlCleanup("Unknown IVB Register : %d", Register); + EmuWarning("Unknown IVB Register : %d", Register); } } From 6b4e529bd6374caeb94b2a1d631bfeff5b23fbc5 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Tue, 16 Jan 2018 20:45:45 +0000 Subject: [PATCH 20/37] Shrink IVB_TABLE_SIZE It was way too big and the vertex buffer was failing to allocate in some titles. --- src/CxbxKrnl/EmuD3D8/VertexBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CxbxKrnl/EmuD3D8/VertexBuffer.h b/src/CxbxKrnl/EmuD3D8/VertexBuffer.h index 83422dd61..f94fddc4b 100755 --- a/src/CxbxKrnl/EmuD3D8/VertexBuffer.h +++ b/src/CxbxKrnl/EmuD3D8/VertexBuffer.h @@ -130,7 +130,7 @@ extern DWORD *g_pIVBVertexBuffer; extern X_D3DPRIMITIVETYPE g_IVBPrimitiveType; extern DWORD g_IVBFVF; -#define IVB_TABLE_SIZE ONE_MB // This should be more than enough.. Tweak as necessary if it overflows +#define IVB_TABLE_SIZE 4096 // This should be more than enough. Tweak as necessary if it overflows or the resulting VertexBuffer fails to allocate #define IVB_BUFFER_SIZE sizeof(_D3DIVB) * IVB_TABLE_SIZE // TODO : Enlarge IVB_TABLE_SIZE and IVB_BUFFER_SIZE From 60e092885e9f0f603faf7d3501282a208ebedc87 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Tue, 23 Jan 2018 13:50:39 +0100 Subject: [PATCH 21/37] NV2A : Added Luke's comment at wrong RegisterBAR --- src/devices/video/nv2a.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp index 25309a8e4..805e1cd8f 100644 --- a/src/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -59,6 +59,14 @@ void NV2ADevice::Init() // Register physical memory on bar 1 r.Memory.address = 0; RegisterBAR(1, XBOX_MEMORY_SIZE, r.value); // TODO : Read g_PhysicalMemory->Size + /* LukeUsher commented at https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/pull/882#discussion_r162871029 + + This is not right: I should have done a better review ;) + The starting address here is the physical address in the Xbox memory the VRAM should be placed at, + and should point to the TILED memory region ((0xF0000000 >> 4)) + + This maps VRAM address 0 to 0xF0000000. (this is what our TILED memory is: VRAM accessed via the GPU device) + */ m_DeviceId = 0x02A5; m_VendorId = PCI_VENDOR_ID_NVIDIA; From 3314fc18fb14cb9e0a1b4dc283acc3c3ab20c44b Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Tue, 23 Jan 2018 16:26:01 +0100 Subject: [PATCH 22/37] NV2A : Added defines and code from my WIP_LessVertexPatching branch that wasn't yet in master. Also some defines from the OpenXbox repository. --- src/devices/video/EmuNV2A.cpp | 324 ++++++++++++++++++++++++------ src/devices/video/EmuNV2A.h | 59 +++++- src/devices/video/nv2a_int.h | 365 +++++++++++++++++++++++++++++++--- 3 files changed, 653 insertions(+), 95 deletions(-) diff --git a/src/devices/video/EmuNV2A.cpp b/src/devices/video/EmuNV2A.cpp index da222a46a..74bca68fc 100644 --- a/src/devices/video/EmuNV2A.cpp +++ b/src/devices/video/EmuNV2A.cpp @@ -351,7 +351,7 @@ struct { uint32_t enabled_interrupts; std::thread puller_thread; Cache1State cache1; - uint32_t regs[NV_PFIFO_SIZE]; // TODO : union + uint32_t regs[_NV_PFIFO_SIZE]; // TODO : union } pfifo; struct { @@ -572,12 +572,14 @@ const char *DebugNV_##DEV##(xbaddr addr) \ DEBUG_START(PMC) DEBUG_CASE(NV_PMC_BOOT_0); + DEBUG_CASE(NV_PMC_BOOT_1); DEBUG_CASE(NV_PMC_INTR_0); DEBUG_CASE(NV_PMC_INTR_EN_0); DEBUG_CASE(NV_PMC_ENABLE); DEBUG_END(PMC) DEBUG_START(PBUS) + DEBUG_CASE(NV_PBUS_FBIO_RAM) DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID"); DEBUG_CASE(NV_PBUS_PCI_NV_1); DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID"); @@ -605,25 +607,45 @@ DEBUG_START(PBUS) DEBUG_END(PBUS) DEBUG_START(PFIFO) + DEBUG_CASE(NV_PFIFO_DELAY_0); + DEBUG_CASE(NV_PFIFO_DMA_TIMESLICE); + DEBUG_CASE(NV_PFIFO_TIMESLICE); DEBUG_CASE(NV_PFIFO_INTR_0); DEBUG_CASE(NV_PFIFO_INTR_EN_0); DEBUG_CASE(NV_PFIFO_RAMHT); DEBUG_CASE(NV_PFIFO_RAMFC); DEBUG_CASE(NV_PFIFO_RAMRO); DEBUG_CASE(NV_PFIFO_RUNOUT_STATUS); + DEBUG_CASE(NV_PFIFO_RUNOUT_PUT_ADDRESS); + DEBUG_CASE(NV_PFIFO_RUNOUT_GET_ADDRESS); + DEBUG_CASE(NV_PFIFO_CACHES); DEBUG_CASE(NV_PFIFO_MODE); DEBUG_CASE(NV_PFIFO_DMA); + DEBUG_CASE(NV_PFIFO_SIZE) + DEBUG_CASE(NV_PFIFO_CACHE0_PUSH0); + DEBUG_CASE(NV_PFIFO_CACHE0_PULL0); + DEBUG_CASE(NV_PFIFO_CACHE0_HASH); DEBUG_CASE(NV_PFIFO_CACHE1_PUSH0); DEBUG_CASE(NV_PFIFO_CACHE1_PUSH1); + DEBUG_CASE(NV_PFIFO_CACHE1_PUT); DEBUG_CASE(NV_PFIFO_CACHE1_STATUS); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUSH); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_FETCH); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_STATE); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_INSTANCE); + DEBUG_CASE(NV_PFIFO_CACHE1_DMA_CTL); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_PUT); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET); + DEBUG_CASE(NV_PFIFO_CACHE1_REF); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_SUBROUTINE); DEBUG_CASE(NV_PFIFO_CACHE1_PULL0); + DEBUG_CASE(NV_PFIFO_CACHE1_PULL1); + DEBUG_CASE(NV_PFIFO_CACHE1_HASH); + DEBUG_CASE(NV_PFIFO_CACHE1_ACQUIRE_0); + DEBUG_CASE(NV_PFIFO_CACHE1_ACQUIRE_1); + DEBUG_CASE(NV_PFIFO_CACHE1_ACQUIRE_2); + DEBUG_CASE(NV_PFIFO_CACHE1_SEMAPHORE); + DEBUG_CASE(NV_PFIFO_CACHE1_GET); DEBUG_CASE(NV_PFIFO_CACHE1_ENGINE); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_DCOUNT); DEBUG_CASE(NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW); @@ -635,22 +657,36 @@ DEBUG_START(PRMA) DEBUG_END(PRMA) DEBUG_START(PVIDEO) + DEBUG_CASE(NV_PVIDEO_DEBUG_2); + DEBUG_CASE(NV_PVIDEO_DEBUG_3); DEBUG_CASE(NV_PVIDEO_INTR); DEBUG_CASE(NV_PVIDEO_INTR_EN); DEBUG_CASE(NV_PVIDEO_BUFFER); DEBUG_CASE(NV_PVIDEO_STOP); - DEBUG_CASE(NV_PVIDEO_BASE); - DEBUG_CASE(NV_PVIDEO_LIMIT); - DEBUG_CASE(NV_PVIDEO_LUMINANCE); - DEBUG_CASE(NV_PVIDEO_CHROMINANCE); - DEBUG_CASE(NV_PVIDEO_OFFSET); - DEBUG_CASE(NV_PVIDEO_SIZE_IN); - DEBUG_CASE(NV_PVIDEO_POINT_IN); - DEBUG_CASE(NV_PVIDEO_DS_DX); - DEBUG_CASE(NV_PVIDEO_DT_DY); - DEBUG_CASE(NV_PVIDEO_POINT_OUT); - DEBUG_CASE(NV_PVIDEO_SIZE_OUT); - DEBUG_CASE(NV_PVIDEO_FORMAT); + DEBUG_CASE(NV_PVIDEO_BASE(0)); + DEBUG_CASE(NV_PVIDEO_BASE(1)); + DEBUG_CASE(NV_PVIDEO_LIMIT(0)); + DEBUG_CASE(NV_PVIDEO_LIMIT(1)); + DEBUG_CASE(NV_PVIDEO_LUMINANCE(0)); + DEBUG_CASE(NV_PVIDEO_LUMINANCE(1)); + DEBUG_CASE(NV_PVIDEO_CHROMINANCE(0)); + DEBUG_CASE(NV_PVIDEO_CHROMINANCE(1)); + DEBUG_CASE(NV_PVIDEO_OFFSET(0)); + DEBUG_CASE(NV_PVIDEO_OFFSET(1)); + DEBUG_CASE(NV_PVIDEO_SIZE_IN(0)); + DEBUG_CASE(NV_PVIDEO_SIZE_IN(1)); + DEBUG_CASE(NV_PVIDEO_POINT_IN(0)); + DEBUG_CASE(NV_PVIDEO_POINT_IN(1)); + DEBUG_CASE(NV_PVIDEO_DS_DX(0)); + DEBUG_CASE(NV_PVIDEO_DS_DX(1)); + DEBUG_CASE(NV_PVIDEO_DT_DY(0)); + DEBUG_CASE(NV_PVIDEO_DT_DY(1)); + DEBUG_CASE(NV_PVIDEO_POINT_OUT(0)); + DEBUG_CASE(NV_PVIDEO_POINT_OUT(1)); + DEBUG_CASE(NV_PVIDEO_SIZE_OUT(0)); + DEBUG_CASE(NV_PVIDEO_SIZE_OUT(1)); + DEBUG_CASE(NV_PVIDEO_FORMAT(0)); + DEBUG_CASE(NV_PVIDEO_FORMAT(1)); DEBUG_END(PVIDEO) DEBUG_START(PTIMER) @@ -661,7 +697,6 @@ DEBUG_START(PTIMER) DEBUG_CASE(NV_PTIMER_TIME_0); DEBUG_CASE(NV_PTIMER_TIME_1); DEBUG_CASE(NV_PTIMER_ALARM_0); - DEBUG_END(PTIMER) DEBUG_START(PCOUNTER) @@ -681,6 +716,7 @@ DEBUG_END(PRMVIO) DEBUG_START(PFB) DEBUG_CASE(NV_PFB_CFG0) + DEBUG_CASE(NV_PFB_CFG1) DEBUG_CASE(NV_PFB_CSTATUS) DEBUG_CASE(NV_PFB_REFCTRL) DEBUG_CASE(NV_PFB_NVM) // NV_PFB_NVM_MODE_DISABLE @@ -689,17 +725,53 @@ DEBUG_START(PFB) DEBUG_CASE(NV_PFB_TIMING0) DEBUG_CASE(NV_PFB_TIMING1) DEBUG_CASE(NV_PFB_TIMING2) - DEBUG_CASE(NV_PFB_TILE) - DEBUG_CASE(NV_PFB_TLIMIT) - DEBUG_CASE(NV_PFB_TSIZE) - DEBUG_CASE(NV_PFB_TSTATUS) + DEBUG_CASE(NV_PFB_TILE(0)) + DEBUG_CASE(NV_PFB_TLIMIT(0)) + DEBUG_CASE(NV_PFB_TSIZE(0)) + DEBUG_CASE(NV_PFB_TSTATUS(0)) + DEBUG_CASE(NV_PFB_TILE(1)) + DEBUG_CASE(NV_PFB_TLIMIT(1)) + DEBUG_CASE(NV_PFB_TSIZE(1)) + DEBUG_CASE(NV_PFB_TSTATUS(1)) + DEBUG_CASE(NV_PFB_TILE(2)) + DEBUG_CASE(NV_PFB_TLIMIT(2)) + DEBUG_CASE(NV_PFB_TSIZE(2)) + DEBUG_CASE(NV_PFB_TSTATUS(2)) + DEBUG_CASE(NV_PFB_TILE(3)) + DEBUG_CASE(NV_PFB_TLIMIT(3)) + DEBUG_CASE(NV_PFB_TSIZE(3)) + DEBUG_CASE(NV_PFB_TSTATUS(3)) + DEBUG_CASE(NV_PFB_TILE(4)) + DEBUG_CASE(NV_PFB_TLIMIT(4)) + DEBUG_CASE(NV_PFB_TSIZE(4)) + DEBUG_CASE(NV_PFB_TSTATUS(4)) + DEBUG_CASE(NV_PFB_TILE(5)) + DEBUG_CASE(NV_PFB_TLIMIT(5)) + DEBUG_CASE(NV_PFB_TSIZE(5)) + DEBUG_CASE(NV_PFB_TSTATUS(5)) + DEBUG_CASE(NV_PFB_TILE(6)) + DEBUG_CASE(NV_PFB_TLIMIT(6)) + DEBUG_CASE(NV_PFB_TSIZE(6)) + DEBUG_CASE(NV_PFB_TSTATUS(6)) + DEBUG_CASE(NV_PFB_TILE(7)) + DEBUG_CASE(NV_PFB_TLIMIT(7)) + DEBUG_CASE(NV_PFB_TSIZE(7)) + DEBUG_CASE(NV_PFB_TSTATUS(7)) DEBUG_CASE(NV_PFB_MRS) DEBUG_CASE(NV_PFB_EMRS) DEBUG_CASE(NV_PFB_MRS_EXT) DEBUG_CASE(NV_PFB_EMRS_EXT) DEBUG_CASE(NV_PFB_REF) DEBUG_CASE(NV_PFB_PRE) - DEBUG_CASE(NV_PFB_ZCOMP) + DEBUG_CASE(NV_PFB_ZCOMP(0)) + DEBUG_CASE(NV_PFB_ZCOMP(1)) + DEBUG_CASE(NV_PFB_ZCOMP(2)) + DEBUG_CASE(NV_PFB_ZCOMP(3)) + DEBUG_CASE(NV_PFB_ZCOMP(4)) + DEBUG_CASE(NV_PFB_ZCOMP(5)) + DEBUG_CASE(NV_PFB_ZCOMP(6)) + DEBUG_CASE(NV_PFB_ZCOMP(7)) + DEBUG_CASE(NV_PFB_ZCOMP_OFFSET) DEBUG_CASE(NV_PFB_ARB_PREDIVIDER) DEBUG_CASE(NV_PFB_ARB_TIMEOUT) DEBUG_CASE(NV_PFB_ARB_XFER_REM) @@ -723,20 +795,81 @@ DEBUG_START(PSTRAPS) DEBUG_END(PSTRAPS) DEBUG_START(PGRAPH) + DEBUG_CASE(NV_PGRAPH_DEBUG_0); + DEBUG_CASE(NV_PGRAPH_DEBUG_1); + DEBUG_CASE(NV_PGRAPH_DEBUG_3); + DEBUG_CASE(NV_PGRAPH_DEBUG_4); + DEBUG_CASE(NV_PGRAPH_DEBUG_5); + DEBUG_CASE(NV_PGRAPH_DEBUG_8); + DEBUG_CASE(NV_PGRAPH_DEBUG_9); DEBUG_CASE(NV_PGRAPH_INTR); DEBUG_CASE(NV_PGRAPH_NSOURCE); DEBUG_CASE(NV_PGRAPH_INTR_EN); DEBUG_CASE(NV_PGRAPH_CTX_CONTROL); DEBUG_CASE(NV_PGRAPH_CTX_USER); DEBUG_CASE(NV_PGRAPH_CTX_SWITCH1); + DEBUG_CASE(NV_PGRAPH_CTX_SWITCH2); + DEBUG_CASE(NV_PGRAPH_CTX_SWITCH3); + DEBUG_CASE(NV_PGRAPH_CTX_SWITCH4); + DEBUG_CASE(NV_PGRAPH_STATUS); DEBUG_CASE(NV_PGRAPH_TRAPPED_ADDR); DEBUG_CASE(NV_PGRAPH_TRAPPED_DATA_LOW); DEBUG_CASE(NV_PGRAPH_SURFACE); DEBUG_CASE(NV_PGRAPH_INCREMENT); DEBUG_CASE(NV_PGRAPH_FIFO); + DEBUG_CASE(NV_PGRAPH_RDI_INDEX); + DEBUG_CASE(NV_PGRAPH_RDI_DATA); + DEBUG_CASE(NV_PGRAPH_FFINTFC_ST2); DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TABLE); DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_POINTER); DEBUG_CASE(NV_PGRAPH_CHANNEL_CTX_TRIGGER); + DEBUG_CASE(NV_PGRAPH_DEBUG_2); + DEBUG_CASE(NV_PGRAPH_TTILE(0)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(0)); + DEBUG_CASE(NV_PGRAPH_TSIZE(0)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(0)); + DEBUG_CASE(NV_PGRAPH_TTILE(1)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(1)); + DEBUG_CASE(NV_PGRAPH_TSIZE(1)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(1)); + DEBUG_CASE(NV_PGRAPH_TTILE(2)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(2)); + DEBUG_CASE(NV_PGRAPH_TSIZE(2)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(2)); + DEBUG_CASE(NV_PGRAPH_TTILE(3)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(3)); + DEBUG_CASE(NV_PGRAPH_TSIZE(3)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(3)); + DEBUG_CASE(NV_PGRAPH_TTILE(4)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(4)); + DEBUG_CASE(NV_PGRAPH_TSIZE(4)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(4)); + DEBUG_CASE(NV_PGRAPH_TTILE(5)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(5)); + DEBUG_CASE(NV_PGRAPH_TSIZE(5)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(5)); + DEBUG_CASE(NV_PGRAPH_TTILE(6)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(6)); + DEBUG_CASE(NV_PGRAPH_TSIZE(6)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(6)); + DEBUG_CASE(NV_PGRAPH_TTILE(7)); + DEBUG_CASE(NV_PGRAPH_TLIMIT(7)); + DEBUG_CASE(NV_PGRAPH_TSIZE(7)); + DEBUG_CASE(NV_PGRAPH_TSTATUS(7)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(0)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(1)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(2)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(3)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(4)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(5)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(6)); + DEBUG_CASE(NV_PGRAPH_ZCOMP(7)); + DEBUG_CASE(NV_PGRAPH_ZCOMP_OFFSET); + DEBUG_CASE(NV_PGRAPH_FBCFG0); + DEBUG_CASE(NV_PGRAPH_FBCFG1); + DEBUG_CASE(NV_PGRAPH_DEBUG_6); + DEBUG_CASE(NV_PGRAPH_DEBUG_7); + DEBUG_CASE(NV_PGRAPH_DEBUG_10); DEBUG_CASE(NV_PGRAPH_CSV0_D); DEBUG_CASE(NV_PGRAPH_CSV0_C); DEBUG_CASE(NV_PGRAPH_CSV1_B); @@ -775,8 +908,7 @@ DEBUG_START(PGRAPH) DEBUG_CASE(NV_PGRAPH_SHADOWZSLOPETHRESHOLD); DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR0); DEBUG_CASE(NV_PGRAPH_SPECFOGFACTOR1); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0); - DEBUG_CASE(NV_PGRAPH_TEXADDRESS0_ADDRV); + DEBUG_CASE_EX(NV_PGRAPH_TEXADDRESS0, ":_ADDRV"); DEBUG_CASE(NV_PGRAPH_TEXADDRESS1); DEBUG_CASE(NV_PGRAPH_TEXADDRESS2); DEBUG_CASE(NV_PGRAPH_TEXADDRESS3); @@ -825,7 +957,6 @@ DEBUG_START(PCRTC) DEBUG_CASE(NV_PCRTC_INTR_EN_0); DEBUG_CASE(NV_PCRTC_START); DEBUG_CASE(NV_PCRTC_CONFIG); - DEBUG_END(PCRTC) DEBUG_START(PRMCIO) @@ -865,21 +996,19 @@ DEBUG_START(PRAMIN) DEBUG_END(PRAMIN) DEBUG_START(USER) - DEBUG_CASE(NV_USER_DMA_PUT); DEBUG_CASE(NV_USER_DMA_GET); DEBUG_CASE(NV_USER_REF); - - DEBUG_END(USER) +DEBUG_END(USER) -#define DEBUG_READ32(DEV) DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr)) -#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } +#define DEBUG_READ32(DEV) DbgPrintf("X86 : Read32 NV2A " #DEV "(0x%08X) = 0x%08X [Handle%s]\n", addr, result, DebugNV_##DEV##(addr)) +#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("X86 : Read32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandle%s]\n", addr, result, DebugNV_##DEV##(addr)); return result; } -#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr)) -#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; } +#define DEBUG_WRITE32(DEV) DbgPrintf("X86 : Write32 NV2A " #DEV "(0x%08X, 0x%08X) [Handle%s]\n", addr, value, DebugNV_##DEV##(addr)) +#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("X86 : Write32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandle%s]\n", addr, value, DebugNV_##DEV##(addr)); return; } #define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr) #define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr) @@ -895,6 +1024,11 @@ static inline uint32_t ldl_le_p(const void *p) return *(uint32_t*)p; } +static inline void stl_le_p(uint32_t *p, uint32 v) +{ + *p = v; +} + static DMAObject nv_dma_load(xbaddr dma_obj_address) { assert(dma_obj_address < NV_PRAMIN_SIZE); @@ -920,7 +1054,7 @@ static void *nv_dma_map(xbaddr dma_obj_address, xbaddr *len) DMAObject dma = nv_dma_load(dma_obj_address); /* TODO: Handle targets and classes properly */ - printf("dma_map %x, %x, %x %x" "\n", + printf("dma_map %x, %x, %x %x\n", dma.dma_class, dma.dma_target, dma.address, dma.limit); dma.address &= 0x07FFFFFF; @@ -1074,7 +1208,7 @@ static void pfifo_run_pusher() { static uint32_t ramht_hash(uint32_t handle) { - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12); /* XXX: Think this is different to what nouveau calculates... */ unsigned int bits = ffs(ramht_size) - 2; @@ -1092,14 +1226,14 @@ static uint32_t ramht_hash(uint32_t handle) static RAMHTEntry ramht_lookup(uint32_t handle) { - unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE) + 12); + unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12); uint32_t hash = ramht_hash(handle); assert(hash * 8 < ramht_size); uint32_t ramht_address = GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], - NV_PFIFO_RAMHT_BASE_ADDRESS) << 12; + NV_PFIFO_RAMHT_BASE_ADDRESS_MASK) << 12; uint8_t *entry_ptr = (uint8_t*)(NV2A_ADDR + NV_PRAMIN_ADDR + ramht_address + hash * 8); @@ -1245,6 +1379,12 @@ static bool pgraph_zeta_write_enabled() | NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE); } +static void pgraph_update_surface(bool upload, + bool color_write, bool zeta_write) +{ + printf("TODO: pgraph_update_surface\n"); +} + static unsigned int kelvin_map_stencil_op(uint32_t parameter) { unsigned int op; @@ -1320,7 +1460,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t { std::lock_guard lk(pgraph.mutex); - int i; +// int i; GraphicsSubchannel *subchannel_data; GraphicsObject *object; @@ -1397,7 +1537,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t /* I guess this kicks it off? */ if (image_blit->operation == NV09F_SET_OPERATION_SRCCOPY) { - printf("NV09F_SET_OPERATION_SRCCOPY"); + printf("NV09F_SET_OPERATION_SRCCOPY\n"); GraphicsObject *context_surfaces_obj = lookup_graphics_object(image_blit->context_surfaces); assert(context_surfaces_obj); @@ -1435,7 +1575,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t printf(" - 0x%tx -> 0x%tx\n", source - MM_SYSTEM_PHYSICAL_MAP,dest - MM_SYSTEM_PHYSICAL_MAP); - int y; + unsigned int y; for (y = 0; yheight; y++) { uint8_t *source_row = source + (image_blit->in_y + y) * context_surfaces->source_pitch @@ -1475,9 +1615,8 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t kelvin->dma_state = parameter; break; case NV097_SET_CONTEXT_DMA_COLOR: - printf("TODO: pgraph_update_surface\n"); /* try to get any straggling draws in before the surface's changed :/ */ - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.dma_color = parameter; break; @@ -1497,8 +1636,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t pgraph.dma_report = parameter; break; case NV097_SET_SURFACE_CLIP_HORIZONTAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_shape.clip_x = GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_X); @@ -1506,8 +1644,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t GET_MASK(parameter, NV097_SET_SURFACE_CLIP_HORIZONTAL_WIDTH); break; case NV097_SET_SURFACE_CLIP_VERTICAL: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_shape.clip_y = GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_Y); @@ -1515,8 +1652,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t GET_MASK(parameter, NV097_SET_SURFACE_CLIP_VERTICAL_HEIGHT); break; case NV097_SET_SURFACE_FORMAT: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_shape.color_format = GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_COLOR); @@ -1532,8 +1668,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t GET_MASK(parameter, NV097_SET_SURFACE_FORMAT_HEIGHT); break; case NV097_SET_SURFACE_PITCH: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_color.pitch = GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR); @@ -1541,14 +1676,12 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA); break; case NV097_SET_SURFACE_COLOR_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_color.offset = parameter; break; case NV097_SET_SURFACE_ZETA_OFFSET: - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); pgraph.surface_zeta.offset = parameter; break; @@ -1563,8 +1696,7 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t pgraph.regs[NV_PGRAPH_TEXADDRESS0 + slot * 4] = parameter; break; case NV097_SET_CONTROL0: { - printf("TODO: pgraph_update_surface\n"); - //pgraph_update_surface(d, false, true, true); + pgraph_update_surface(false, true, true); bool stencil_write_enable = parameter & NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE; @@ -1990,6 +2122,29 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t case NV097_SET_TEXGEN_VIEW_MODEL: SET_MASK(pgraph.regs[NV_PGRAPH_CSV0_D], NV_PGRAPH_CSV0_D_TEXGEN_REF, parameter); break; + case NV097_SET_SEMAPHORE_OFFSET: + kelvin->semaphore_offset = parameter; + break; + case NV097_BACK_END_WRITE_SEMAPHORE_RELEASE: { + + pgraph_update_surface(false, true, true); + + //qemu_mutex_unlock(&d->pgraph.lock); + //qemu_mutex_lock_iothread(); + + xbaddr semaphore_dma_len; + uint8_t *semaphore_data = (uint8_t*)nv_dma_map(kelvin->dma_semaphore, + &semaphore_dma_len); + assert(kelvin->semaphore_offset < semaphore_dma_len); + semaphore_data += kelvin->semaphore_offset; + + stl_le_p((uint32_t*)semaphore_data, parameter); + + //qemu_mutex_lock(&d->pgraph.lock); + //qemu_mutex_unlock_iothread(); + + break; + } default: if (method >= NV097_SET_COMBINER_ALPHA_ICW && method <= NV097_SET_COMBINER_ALPHA_ICW + 28) { slot = (method - NV097_SET_COMBINER_ALPHA_ICW) / 4; @@ -2235,10 +2390,13 @@ DEVICE_READ32(PMC) case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 result = 0x02A000A2; break; - case NV_PMC_INTR_0: + case NV_PMC_BOOT_1: // Selects big/little endian mode for the card + result = 0; // When read, returns 0 if in little-endian mode, 0x01000001 if in big-endian mode. + break; + case NV_PMC_INTR_0: // Shows which functional units have pending IRQ result = pmc.pending_interrupts; break; - case NV_PMC_INTR_EN_0: + case NV_PMC_INTR_EN_0: // Selects which functional units can cause IRQs result = pmc.enabled_interrupts; break; default: @@ -2361,7 +2519,7 @@ DEVICE_READ32(PFIFO) pfifo.cache1.error); break; case NV_PFIFO_CACHE1_DMA_INSTANCE: - SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS, + SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK, pfifo.cache1.dma_instance >> 4); break; case NV_PFIFO_CACHE1_DMA_PUT: @@ -2440,7 +2598,7 @@ DEVICE_WRITE32(PFIFO) pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR); break; case NV_PFIFO_CACHE1_DMA_INSTANCE: - pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS) << 4; + pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK) << 4; break; case NV_PFIFO_CACHE1_DMA_PUT: user.channel_control[pfifo.cache1.channel_id].dma_put = value; @@ -3259,7 +3417,7 @@ static const NV2ABlockInfo regions[] = {{ }, { /* MMIO and DMA FIFO submission to PGRAPH and VPE */ NV_PFIFO_ADDR, // = 0x002000 - NV_PFIFO_SIZE, // = 0x002000 + _NV_PFIFO_SIZE, // = 0x002000 EmuNV2A_PFIFO_Read32, EmuNV2A_PFIFO_Write32, }, { @@ -3307,7 +3465,7 @@ static const NV2ABlockInfo regions[] = {{ }, { /* aliases VGA sequencer and graphics controller registers */ NV_PRMVIO_ADDR, // = 0x0c0000 - NV_PRMVIO_SIZE, // = 0x001000 + NV_PRMVIO_SIZE, // = 0x008000 // Was 0x001000 EmuNV2A_PRMVIO_Read32, EmuNV2A_PRMVIO_Write32, },{ @@ -3360,10 +3518,16 @@ static const NV2ABlockInfo regions[] = {{ EmuNV2A_PRAMIN_Write32, },{ /* PFIFO MMIO and DMA submission area */ - NV_USER_ADDR, // = 0x800000, - NV_USER_SIZE, // = 0x800000, + NV_USER_ADDR, // = 0x800000 + NV_USER_SIZE, // = 0x400000 // Was 0x800000 EmuNV2A_USER_Read32, EmuNV2A_USER_Write32, + }, { + /* User area remapped? */ + NV_UREMAP_ADDR, // = 0xC00000 + NV_UREMAP_SIZE, // = 0x400000 + EmuNV2A_USER_Read32, // NOTE : Re-used (*not* EmuNV2A_UREMAP_Read32) + EmuNV2A_USER_Write32, // NOTE : Re-used (*not* EmuNV2A_UREMAP_Write32) }, { 0xFFFFFFFF, 0, @@ -3436,7 +3600,7 @@ void EmuNV2A_Write(xbaddr addr, uint32_t value, int size) shift = (addr & 2) * 16; aligned_addr = addr & ~3; aligned_value = block->read(addr - block->offset); - mask = 0xFFFF << shift; + mask = 0xFFFF << shift; // TODO : Must the second byte be written to the next DWORD? block->write(aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift)); @@ -3741,10 +3905,42 @@ static void nv2a_vblank_thread() } } +void CxbxReserveNV2AMemory() +{ + // Reserve NV2A memory : + void *memory = (void *)VirtualAllocEx( + GetCurrentProcess(), + (void *)NV2A_ADDR, + NV2A_SIZE, + MEM_RESERVE, // Don't allocate actual physical storage in memory + PAGE_NOACCESS); // Any access must result in an access violation exception (handled in EmuException/EmuX86_DecodeException) + if (memory == NULL) { + EmuWarning("Couldn't reserve NV2A memory, continuing assuming we'll receive (and handle) access violation exceptions anyway..."); + return; + } + + printf("[0x%.4X] INIT: Reserved %d MiB of Xbox NV2A memory at 0x%.8X to 0x%.8X\n", + GetCurrentThreadId(), NV2A_SIZE / ONE_MB, NV2A_ADDR, NV2A_ADDR + NV2A_SIZE - 1); + + // Allocate PRAMIN Region + memory = VirtualAllocEx( + GetCurrentProcess(), + (void*)(NV2A_ADDR + NV_PRAMIN_ADDR), + NV_PRAMIN_SIZE, + MEM_COMMIT, // No MEM_RESERVE | + PAGE_READWRITE); + if (memory == NULL) { + EmuWarning("Couldn't allocate NV2A PRAMIN memory"); + return; + } + + printf("[0x%.4X] INIT: Allocated %d MiB of Xbox NV2A PRAMIN memory at 0x%.8X to 0x%.8X\n", + GetCurrentThreadId(), NV_PRAMIN_SIZE / ONE_MB, NV2A_ADDR + NV_PRAMIN_ADDR, NV2A_ADDR + NV_PRAMIN_ADDR + NV_PRAMIN_SIZE - 1); +} + void EmuNV2A_Init() { - // Allocate PRAMIN Region - VirtualAlloc((void*)(NV2A_ADDR + NV_PRAMIN_ADDR), NV_PRAMIN_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + CxbxReserveNV2AMemory(); pcrtc.start = 0; @@ -3757,6 +3953,6 @@ void EmuNV2A_Init() // Only spawn VBlank thread when LLE is enabled if (bLLE_GPU) { - vblank_thread = std::thread(nv2a_vblank_thread);; + vblank_thread = std::thread(nv2a_vblank_thread); } } diff --git a/src/devices/video/EmuNV2A.h b/src/devices/video/EmuNV2A.h index f931315e0..7e3f6cc10 100644 --- a/src/devices/video/EmuNV2A.h +++ b/src/devices/video/EmuNV2A.h @@ -45,7 +45,7 @@ #define NV_PBUS_ADDR 0x00001000 #define NV_PBUS_SIZE 0x001000 #define NV_PFIFO_ADDR 0x00002000 -#define NV_PFIFO_SIZE 0x002000 +#define _NV_PFIFO_SIZE 0x002000 // Underscore prefix to prevent clash with NV_PFIFO_SIZE #define NV_PRMA_ADDR 0x00007000 #define NV_PRMA_SIZE 0x001000 #define NV_PVIDEO_ADDR 0x00008000 @@ -61,7 +61,7 @@ #define NV_PRMFB_ADDR 0x000A0000 #define NV_PRMFB_SIZE 0x020000 #define NV_PRMVIO_ADDR 0x000C0000 -#define NV_PRMVIO_SIZE 0x001000 +#define NV_PRMVIO_SIZE 0x008000 // Was 0x001000 #define NV_PFB_ADDR 0x00100000 #define NV_PFB_SIZE 0x001000 #define NV_PSTRAPS_ADDR 0x00101000 @@ -79,18 +79,65 @@ #define NV_PRAMIN_ADDR 0x00700000 #define NV_PRAMIN_SIZE 0x100000 #define NV_USER_ADDR 0x00800000 -#define NV_USER_SIZE 0x800000 +#define NV_USER_SIZE 0x400000 +#define NV_UREMAP_ADDR 0x00C00000 // Looks like a mapping of NV_USER_ADDR +#define NV_UREMAP_SIZE 0x400000 + +typedef volatile DWORD *PPUSH; typedef struct { DWORD Ignored[0x10]; - DWORD* Put; // On Xbox1, this field is only written to by the CPU (the GPU uses this as a trigger to start executing from the given address) - DWORD* Get; // On Xbox1, this field is only read from by the CPU (the GPU reflects in here where it is/stopped executing) - DWORD Reference; // TODO : xbaddr / void* / DWORD ? + PPUSH Put; // On Xbox1, this field is only written to by the CPU (the GPU uses this as a trigger to start executing from the given address) + PPUSH Get; // On Xbox1, this field is only read from by the CPU (the GPU reflects in here where it is/stopped executing) + PPUSH Reference; // TODO : xbaddr / void* / DWORD ? DWORD Ignored2[0x7ED]; } Nv2AControlDma; uint32_t EmuNV2A_Read(xbaddr addr, int size); void EmuNV2A_Write(xbaddr addr, uint32_t value, int size); + +#define PUSH_TYPE_MASK 0x00000002 // 2 bits +#define PUSH_TYPE_SHIFT 0 +#define PUSH_TYPE_METHOD 0 // method +#define PUSH_TYPE_JMP_FAR 1 // jump far +#define PUSH_TYPE_CALL_FAR 2 // call far +#define PUSH_TYPE_METHOD_UNUSED 3 // method (unused) +#define PUSH_METHOD_MASK 0x00001FFC // 12 bits +#define PUSH_METHOD_SHIFT 0 // Dxbx note : Not 2, because methods are actually DWORD offsets (and thus defined with increments of 4) +#define PUSH_SUBCH_MASK 0x0000E000 // 3 bits +#define PUSH_SUBCH_SHIFT 13 +#define PUSH_COUNT_MASK 0x1FFC0000 // 11 bits +#define PUSH_COUNT_SHIFT 18 +#define PUSH_INSTR_MASK 0xE0000000 // 3 bits +#define PUSH_INSTR_SHIFT 29 +#define PUSH_INSTR_IMM_INCR 0 // immediate, increment +#define PUSH_INSTR_JMP_NEAR 1 // near jump +#define PUSH_INSTR_IMM_NOINC 2 // immediate, no-increment +#define PUSH_ADDR_FAR_MASK 0xFFFFFFFC // 30 bits +#define PUSH_ADDR_FAR_SHIFT 0 +#define PUSH_ADDR_NEAR_MASK 0x1FFFFFFC // 27 bits +#define PUSH_ADDR_NEAR_SHIFT 0 // Cxbx note : Not 2, because methods are actually DWORD offsets (and thus defined with increments of 4) + +#define PUSH_TYPE(dwPushCommand) ((dwPushCommand & PUSH_TYPE_MASK) >> PUSH_TYPE_SHIFT) +#define PUSH_METHOD(dwPushCommand) ((dwPushCommand & PUSH_METHOD_MASK) >> PUSH_METHOD_SHIFT) +#define PUSH_SUBCH(dwPushCommand) ((dwPushCommand & PUSH_SUBCH_MASK) >> PUSH_SUBCH_SHIFT) +#define PUSH_COUNT(dwPushCommand) ((dwPushCommand & PUSH_COUNT_MASK) >> PUSH_COUNT_SHIFT) +#define PUSH_INSTR(dwPushCommand) ((dwPushCommand & PUSH_INSTR_MASK) >> PUSH_INSTR_SHIFT) +#define PUSH_ADDR_FAR(dwPushCommand) ((dwPushCommand & PUSH_ADDR_FAR_MASK) >> PUSH_ADDR_FAR_SHIFT) +#define PUSH_ADDR_NEAR(dwPushCommand) ((dwPushCommand & PUSH_ADDR_NEAR_MASK) >> PUSH_ADDR_NEAR_SHIFT) + +#define PUSH_METHOD_MAX ((PUSH_METHOD_MASK | 3) >> PUSH_METHOD_SHIFT) // = 8191 +#define PUSH_SUBCH_MAX (PUSH_SUBCH_MASK >> PUSH_SUBCH_SHIFT) // = 7 +#define PUSH_COUNT_MAX (PUSH_COUNT_MASK >> PUSH_COUNT_SHIFT) // = 2047 + +// Decode push buffer conmmand (inverse of D3DPUSH_ENCODE) +inline void D3DPUSH_DECODE(const DWORD dwPushCommand, DWORD &dwMethod, DWORD &dwSubCh, DWORD &dwCount) +{ + dwMethod = PUSH_METHOD(dwPushCommand); + dwSubCh = PUSH_SUBCH(dwPushCommand); + dwCount = PUSH_COUNT(dwPushCommand); +} + void EmuNV2A_Init(); void InitOpenGLContext(); diff --git a/src/devices/video/nv2a_int.h b/src/devices/video/nv2a_int.h index 49f1bdffe..ca49d0275 100644 --- a/src/devices/video/nv2a_int.h +++ b/src/devices/video/nv2a_int.h @@ -1,3 +1,4 @@ +// Source : https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a_int.h /* * QEMU Geforce NV2A internal definitions * @@ -18,12 +19,38 @@ * along with this program; if not, see . */ +#define NV_NUM_BLOCKS 21 +#define NV_PMC 0 /* card master control */ +#define NV_PBUS 1 /* bus control */ +#define NV_PFIFO 2 /* MMIO and DMA FIFO submission to PGRAPH and VPE */ +#define NV_PFIFO_CACHE 3 +#define NV_PRMA 4 /* access to BAR0/BAR1 from real mode */ +#define NV_PVIDEO 5 /* video overlay */ +#define NV_PTIMER 6 /* time measurement and time-based alarms */ +#define NV_PCOUNTER 7 /* performance monitoring counters */ +#define NV_PVPE 8 /* MPEG2 decoding engine */ +#define NV_PTV 9 /* TV encoder */ +#define NV_PRMFB 10 /* aliases VGA memory window */ +#define NV_PRMVIO 11 /* aliases VGA sequencer and graphics controller registers */ +#define NV_PFB 12 /* memory interface */ +#define NV_PSTRAPS 13 /* straps readout / override */ +#define NV_PGRAPH 14 /* accelerated 2d/3d drawing engine */ +#define NV_PCRTC 15 /* more CRTC controls */ +#define NV_PRMCIO 16 /* aliases VGA CRTC and attribute controller registers */ +#define NV_PRAMDAC 17 /* RAMDAC, cursor, and PLL control */ +#define NV_PRMDIO 18 /* aliases VGA palette registers */ +#define NV_PRAMIN 19 /* RAMIN access */ +#define NV_USER 20 /* PFIFO MMIO and DMA submission area */ #define NV_PMC_BOOT_0 0x00000000 +#define NV_PMC_BOOT_1 0x00000004 #define NV_PMC_INTR_0 0x00000100 # define NV_PMC_INTR_0_PFIFO (1 << 8) # define NV_PMC_INTR_0_PGRAPH (1 << 12) +# define NV_PMC_INTR_0_PVIDEO (1 << 16) +# define NV_PMC_INTR_0_PTIMER (1 << 20) # define NV_PMC_INTR_0_PCRTC (1 << 24) +# define NV_PMC_INTR_0_PCRTC2 (1 << 25) # define NV_PMC_INTR_0_PBUS (1 << 28) # define NV_PMC_INTR_0_SOFTWARE (1 << 31) #define NV_PMC_INTR_EN_0 0x00000140 @@ -32,8 +59,16 @@ #define NV_PMC_ENABLE 0x00000200 # define NV_PMC_ENABLE_PFIFO (1 << 8) # define NV_PMC_ENABLE_PGRAPH (1 << 12) +# define NV_PMC_ENABLE_PFB (1 << 20) +# define NV_PMC_ENABLE_PCRTC (1 << 24) +# define NV_PMC_ENABLE_PCRTC2 (1 << 25) +# define NV_PMC_ENABLE_PVIDEO (1 << 28) +#define NV_PBUS_FBIO_RAM 0x00000218 +# define NV_PBUS_FBIO_RAM_TYPE 0x00000100 +# define NV_PBUS_FBIO_RAM_TYPE_DDR (0 << 8) +# define NV_PBUS_FBIO_RAM_TYPE_SDR (1 << 8) /* These map approximately to the pci registers */ #define NV_PBUS_PCI_NV_0 0x00000800 # define NV_PBUS_PCI_NV_0_VENDOR_ID 0x0000FFFF @@ -65,6 +100,9 @@ #define NV_PBUS_PCI_NV_26 0x00000868 +#define NV_PFIFO_DELAY_0 0x00000040 +#define NV_PFIFO_DMA_TIMESLICE 0x00000044 +#define NV_PFIFO_TIMESLICE 0x0000004C #define NV_PFIFO_INTR_0 0x00000100 # define NV_PFIFO_INTR_0_CACHE_ERROR (1 << 0) # define NV_PFIFO_INTR_0_RUNOUT (1 << 4) @@ -82,21 +120,37 @@ # define NV_PFIFO_INTR_EN_0_SEMAPHORE (1 << 20) # define NV_PFIFO_INTR_EN_0_ACQUIRE_TIMEOUT (1 << 24) #define NV_PFIFO_RAMHT 0x00000210 -# define NV_PFIFO_RAMHT_BASE_ADDRESS 0x000001F0 -# define NV_PFIFO_RAMHT_SIZE 0x00030000 +//# define NV_PFIFO_RAMHT_BASE_ADDRESS 0x000001F0 +# define NV_PFIFO_RAMHT_BASE_ADDRESS_MASK 0x000001F0 +# define NV_PFIFO_RAMHT_BASE_ADDRESS_SHIFT 4 +# define NV_PFIFO_RAMHT_BASE_ADDRESS_MOVE 12 +//# define NV_PFIFO_RAMHT_SIZE 0x00030000 +# define NV_PFIFO_RAMHT_SIZE_MASK 0x00030000 +# define NV_PFIFO_RAMHT_SIZE_SHIFT 16 # define NV_PFIFO_RAMHT_SIZE_4K 0 # define NV_PFIFO_RAMHT_SIZE_8K 1 # define NV_PFIFO_RAMHT_SIZE_16K 2 # define NV_PFIFO_RAMHT_SIZE_32K 3 -# define NV_PFIFO_RAMHT_SEARCH 0x03000000 +//# define NV_PFIFO_RAMHT_SEARCH 0x03000000 +# define NV_PFIFO_RAMHT_SEARCH_MASK 0x03000000 +# define NV_PFIFO_RAMHT_SEARCH_SHIFT 24 # define NV_PFIFO_RAMHT_SEARCH_16 0 # define NV_PFIFO_RAMHT_SEARCH_32 1 # define NV_PFIFO_RAMHT_SEARCH_64 2 # define NV_PFIFO_RAMHT_SEARCH_128 3 #define NV_PFIFO_RAMFC 0x00000214 -# define NV_PFIFO_RAMFC_BASE_ADDRESS1 0x000001FC -# define NV_PFIFO_RAMFC_SIZE 0x00010000 -# define NV_PFIFO_RAMFC_BASE_ADDRESS2 0x00FE0000 +//# define NV_PFIFO_RAMFC_BASE_ADDRESS1 0x000001FC +# define NV_PFIFO_RAMFC_BASE_ADDRESS1_MASK 0x000001FC +# define NV_PFIFO_RAMFC_BASE_ADDRESS1_SHIFT 2 +# define NV_PFIFO_RAMFC_BASE_ADDRESS1_MOVE 10 +//# define NV_PFIFO_RAMFC_SIZE 0x00010000 +# define NV_PFIFO_RAMFC_SIZE_MASK 0x00010000 +# define NV_PFIFO_RAMFC_SIZE_1K 0x00000000 +# define NV_PFIFO_RAMFC_SIZE_2K 0x00010000 +//# define NV_PFIFO_RAMFC_BASE_ADDRESS2 0x00FE0000 +# define NV_PFIFO_RAMFC_BASE_ADDRESS2_MASK 0x00FE0000 +# define NV_PFIFO_RAMFC_BASE_ADDRESS2_SHIFT 17 +# define NV_PFIFO_RAMFC_BASE_ADDRESS2_MOVE 10 #define NV_PFIFO_RAMRO 0x00000218 # define NV_PFIFO_RAMRO_BASE_ADDRESS 0x000001FE # define NV_PFIFO_RAMRO_SIZE 0x00010000 @@ -104,13 +158,21 @@ # define NV_PFIFO_RUNOUT_STATUS_RANOUT (1 << 0) # define NV_PFIFO_RUNOUT_STATUS_LOW_MARK (1 << 4) # define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK (1 << 8) +#define NV_PFIFO_RUNOUT_PUT_ADDRESS 0x00000410 +#define NV_PFIFO_RUNOUT_GET_ADDRESS 0x00000420 +#define NV_PFIFO_CACHES 0x00000500 #define NV_PFIFO_MODE 0x00000504 #define NV_PFIFO_DMA 0x00000508 +#define NV_PFIFO_SIZE 0x0000050C +#define NV_PFIFO_CACHE0_PUSH0 0x00001000 +#define NV_PFIFO_CACHE0_PULL0 0x00001050 +#define NV_PFIFO_CACHE0_HASH 0x00001058 #define NV_PFIFO_CACHE1_PUSH0 0x00001200 # define NV_PFIFO_CACHE1_PUSH0_ACCESS (1 << 0) #define NV_PFIFO_CACHE1_PUSH1 0x00001204 # define NV_PFIFO_CACHE1_PUSH1_CHID 0x0000001F # define NV_PFIFO_CACHE1_PUSH1_MODE 0x00000100 +#define NV_PFIFO_CACHE1_PUT 0x00001210 #define NV_PFIFO_CACHE1_STATUS 0x00001214 # define NV_PFIFO_CACHE1_STATUS_LOW_MARK (1 << 4) # define NV_PFIFO_CACHE1_STATUS_HIGH_MARK (1 << 8) @@ -137,14 +199,26 @@ # define NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD 4 # define NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION 6 #define NV_PFIFO_CACHE1_DMA_INSTANCE 0x0000122C -# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 0x0000FFFF +//# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 0x0000FFFF +# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK 0x0000FFFF +# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_SHIFT 0 +# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MOVE 4 +#define NV_PFIFO_CACHE1_DMA_CTL 0x00001230 #define NV_PFIFO_CACHE1_DMA_PUT 0x00001240 #define NV_PFIFO_CACHE1_DMA_GET 0x00001244 +#define NV_PFIFO_CACHE1_REF 0x00001248 #define NV_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000124C # define NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET 0x1FFFFFFC # define NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE (1 << 0) #define NV_PFIFO_CACHE1_PULL0 0x00001250 # define NV_PFIFO_CACHE1_PULL0_ACCESS (1 << 0) +#define NV_PFIFO_CACHE1_PULL1 0x00001254 +#define NV_PFIFO_CACHE1_HASH 0x00001258 +#define NV_PFIFO_CACHE1_ACQUIRE_0 0x00001260 +#define NV_PFIFO_CACHE1_ACQUIRE_1 0x00001264 +#define NV_PFIFO_CACHE1_ACQUIRE_2 0x00001268 +#define NV_PFIFO_CACHE1_SEMAPHORE 0x0000126C +#define NV_PFIFO_CACHE1_GET 0x00001270 #define NV_PFIFO_CACHE1_ENGINE 0x00001280 #define NV_PFIFO_CACHE1_DMA_DCOUNT 0x000012A0 # define NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE 0x00001FFC @@ -154,6 +228,13 @@ #define NV_PFIFO_CACHE1_DMA_DATA_SHADOW 0x000012AC +#define NV_PGRAPH_DEBUG_0 0x00000080 +#define NV_PGRAPH_DEBUG_1 0x00000084 +#define NV_PGRAPH_DEBUG_3 0x0000008C +#define NV_PGRAPH_DEBUG_4 0x00000090 +#define NV_PGRAPH_DEBUG_5 0x00000094 +#define NV_PGRAPH_DEBUG_8 0x00000098 +#define NV_PGRAPH_DEBUG_9 0x0000009C #define NV_PGRAPH_INTR 0x00000100 # define NV_PGRAPH_INTR_NOTIFY (1 << 0) # define NV_PGRAPH_INTR_MISSING_HW (1 << 4) @@ -212,6 +293,10 @@ # define NV_PGRAPH_CTX_SWITCH1_CONTEXT_BETA1 (1 << 29) # define NV_PGRAPH_CTX_SWITCH1_CONTEXT_BETA4 (1 << 30) # define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET (1 << 31) +#define NV_PGRAPH_CTX_SWITCH2 0x00000150 +#define NV_PGRAPH_CTX_SWITCH3 0x00000154 +#define NV_PGRAPH_CTX_SWITCH4 0x00000158 +#define NV_PGRAPH_STATUS 0x00000700 #define NV_PGRAPH_TRAPPED_ADDR 0x00000704 # define NV_PGRAPH_TRAPPED_ADDR_MTHD 0x00001FFF # define NV_PGRAPH_TRAPPED_ADDR_SUBCH 0x00070000 @@ -227,6 +312,9 @@ # define NV_PGRAPH_INCREMENT_READ_3D (1 << 1) #define NV_PGRAPH_FIFO 0x00000720 # define NV_PGRAPH_FIFO_ACCESS (1 << 0) +#define NV_PGRAPH_RDI_INDEX 0x00000750 +#define NV_PGRAPH_RDI_DATA 0x00000754 +#define NV_PGRAPH_FFINTFC_ST2 0x00000764 #define NV_PGRAPH_CHANNEL_CTX_TABLE 0x00000780 # define NV_PGRAPH_CHANNEL_CTX_TABLE_INST 0x0000FFFF #define NV_PGRAPH_CHANNEL_CTX_POINTER 0x00000784 @@ -234,6 +322,18 @@ #define NV_PGRAPH_CHANNEL_CTX_TRIGGER 0x00000788 # define NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN (1 << 0) # define NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT (1 << 1) +#define NV_PGRAPH_DEBUG_2 0x00000880 +#define NV_PGRAPH_TTILE(i) 0x00000900 + (i * 0x10) +#define NV_PGRAPH_TLIMIT(i) 0x00000904 + (i * 0x10) +#define NV_PGRAPH_TSIZE(i) 0x00000908 + (i * 0x10) +#define NV_PGRAPH_TSTATUS(i) 0x0000090C + (i * 0x10) +#define NV_PGRAPH_ZCOMP(i) 0x00000980 + (i * 4) +#define NV_PGRAPH_ZCOMP_OFFSET 0x000009A0 +#define NV_PGRAPH_FBCFG0 0x000009A4 +#define NV_PGRAPH_FBCFG1 0x000009A8 +#define NV_PGRAPH_DEBUG_6 0x00000B80 +#define NV_PGRAPH_DEBUG_7 0x00000B84 +#define NV_PGRAPH_DEBUG_10 0x00000B88 #define NV_PGRAPH_CSV0_D 0x00000FB4 # define NV_PGRAPH_CSV0_D_LIGHTS 0x0000FFFF # define NV_PGRAPH_CSV0_D_LIGHT0 0x00000003 @@ -544,6 +644,8 @@ #define NV_PCRTC_CONFIG 0x00000804 +#define NV_PVIDEO_DEBUG_2 0x00000088 +#define NV_PVIDEO_DEBUG_3 0x0000008C #define NV_PVIDEO_INTR 0x00000100 # define NV_PVIDEO_INTR_BUFFER_0 (1 << 0) # define NV_PVIDEO_INTR_BUFFER_1 (1 << 4) @@ -554,26 +656,26 @@ # define NV_PVIDEO_BUFFER_0_USE (1 << 0) # define NV_PVIDEO_BUFFER_1_USE (1 << 4) #define NV_PVIDEO_STOP 0x00000704 -#define NV_PVIDEO_BASE 0x00000900 -#define NV_PVIDEO_LIMIT 0x00000908 -#define NV_PVIDEO_LUMINANCE 0x00000910 -#define NV_PVIDEO_CHROMINANCE 0x00000918 -#define NV_PVIDEO_OFFSET 0x00000920 -#define NV_PVIDEO_SIZE_IN 0x00000928 +#define NV_PVIDEO_BASE(i) 0x00000900 + (i * 4) +#define NV_PVIDEO_LIMIT(i) 0x00000908 + (i * 4) +#define NV_PVIDEO_LUMINANCE(i) 0x00000910 + (i * 4) +#define NV_PVIDEO_CHROMINANCE(i) 0x00000918 + (i * 4) +#define NV_PVIDEO_OFFSET(i) 0x00000920 + (i * 4) +#define NV_PVIDEO_SIZE_IN(i) 0x00000928 + (i * 4) # define NV_PVIDEO_SIZE_IN_WIDTH 0x000007FF # define NV_PVIDEO_SIZE_IN_HEIGHT 0x07FF0000 -#define NV_PVIDEO_POINT_IN 0x00000930 +#define NV_PVIDEO_POINT_IN(i) 0x00000930 + (i * 4) # define NV_PVIDEO_POINT_IN_S 0x00007FFF # define NV_PVIDEO_POINT_IN_T 0xFFFE0000 -#define NV_PVIDEO_DS_DX 0x00000938 -#define NV_PVIDEO_DT_DY 0x00000940 -#define NV_PVIDEO_POINT_OUT 0x00000948 +#define NV_PVIDEO_DS_DX(i) 0x00000938 + (i * 4) +#define NV_PVIDEO_DT_DY(i) 0x00000940 + (i * 4) +#define NV_PVIDEO_POINT_OUT(i) 0x00000948 + (i * 4) # define NV_PVIDEO_POINT_OUT_X 0x00000FFF # define NV_PVIDEO_POINT_OUT_Y 0x0FFF0000 -#define NV_PVIDEO_SIZE_OUT 0x00000950 +#define NV_PVIDEO_SIZE_OUT(i) 0x00000950 + (i * 4) # define NV_PVIDEO_SIZE_OUT_WIDTH 0x00000FFF # define NV_PVIDEO_SIZE_OUT_HEIGHT 0x0FFF0000 -#define NV_PVIDEO_FORMAT 0x00000958 +#define NV_PVIDEO_FORMAT(i) 0x00000958 + (i * 4) # define NV_PVIDEO_FORMAT_PITCH 0x00001FFF # define NV_PVIDEO_FORMAT_COLOR 0x00030000 # define NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8 1 @@ -594,6 +696,7 @@ #define NV_PFB_DEBUG_0 0x00000080 #define NV_PFB_CFG0 0x00000200 # define NV_PFB_CFG0_PART 0x00000003 +#define NV_PFB_CFG1 0x00000204 #define NV_PFB_CSTATUS 0x0000020C #define NV_PFB_REFCTRL 0x00000210 #define NV_PFB_NVM 0x00000214 // NV_PFB_NVM_MODE_DISABLE @@ -602,17 +705,18 @@ #define NV_PFB_TIMING0 0x00000220 #define NV_PFB_TIMING1 0x00000224 #define NV_PFB_TIMING2 0x00000228 -#define NV_PFB_TILE 0x00000240 -#define NV_PFB_TLIMIT 0x00000244 -#define NV_PFB_TSIZE 0x00000248 -#define NV_PFB_TSTATUS 0x0000024C +#define NV_PFB_TILE(i) 0x00000240 + (i * 0x10) +#define NV_PFB_TLIMIT(i) 0x00000244 + (i * 0x10) +#define NV_PFB_TSIZE(i) 0x00000248 + (i * 0x10) +#define NV_PFB_TSTATUS(i) 0x0000024C + (i * 0x10) #define NV_PFB_MRS 0x000002C0 #define NV_PFB_EMRS 0x000002C4 #define NV_PFB_MRS_EXT 0x000002C8 #define NV_PFB_EMRS_EXT 0x000002CC #define NV_PFB_REF 0x000002D0 #define NV_PFB_PRE 0x000002D4 -#define NV_PFB_ZCOMP 0x00000300 +#define NV_PFB_ZCOMP(i) 0x00000300 + (i * 4) +#define NV_PFB_ZCOMP_OFFSET 0x00000324 #define NV_PFB_ARB_PREDIVIDER 0x00000328 #define NV_PFB_ARB_TIMEOUT 0x0000032C #define NV_PFB_ARB_XFER_REM 0x00000334 @@ -632,6 +736,10 @@ #define NV_PFB_CPU_RRQ 0x00000420 #define NV_PFB_BYPASS 0x00000424 +#define NV_PRAMIN_DMA_CLASS(i) 0x00000000 + (i * 0x10) +#define NV_PRAMIN_DMA_LIMIT(i) 0x00000004 + (i * 0x10) +#define NV_PRAMIN_DMA_START(i) 0x00000008 + (i * 0x10) +#define NV_PRAMIN_DMA_ADDRESS(i) 0x0000000C + (i * 0x10) #define NV_PRAMDAC_NVPLL_COEFF 0x00000500 # define NV_PRAMDAC_NVPLL_COEFF_MDIV 0x000000FF @@ -704,7 +812,7 @@ # define NV062_SET_CONTEXT_DMA_IMAGE_DESTIN 0x00000188 # define NV062_SET_COLOR_FORMAT 0x00000300 # define NV062_SET_COLOR_FORMAT_LE_Y8 0x01 -# define NV062_SET_COLOR_FORMAT_LE_R5G6B5 0x04 +# define NV062_SET_COLOR_FORMAT_LE_R5G6B5 0x04 # define NV062_SET_COLOR_FORMAT_LE_A8R8G8B8 0x0A # define NV062_SET_PITCH 0x00000304 # define NV062_SET_OFFSET_SOURCE 0x00000308 @@ -773,8 +881,84 @@ # define NV097_SET_SURFACE_COLOR_OFFSET 0x00000210 # define NV097_SET_SURFACE_ZETA_OFFSET 0x00000214 # define NV097_SET_COMBINER_ALPHA_ICW 0x00000260 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP 0xE0000000 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_UNSIGNED_IDENTITY 0 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_UNSIGNED_INVERT 1 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_EXPAND_NORMAL 2 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_EXPAND_NEGATE 3 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_HALFBIAS_NORMAL 4 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_HALFBIAS_NEGATE 5 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_SIGNED_IDENTITY 6 +# define NV097_SET_COMBINER_ALPHA_ICW_A_MAP_SIGNED_NEGATE 7 +# define NV097_SET_COMBINER_ALPHA_ICW_A_ALPHA (1<<28) +# define NV097_SET_COMBINER_ALPHA_ICW_A_SOURCE 0x0F000000 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP 0x00E00000 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_UNSIGNED_IDENTITY 0 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_UNSIGNED_INVERT 1 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_EXPAND_NORMAL 2 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_EXPAND_NEGATE 3 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_HALFBIAS_NORMAL 4 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_HALFBIAS_NEGATE 5 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_SIGNED_IDENTITY 6 +# define NV097_SET_COMBINER_ALPHA_ICW_B_MAP_SIGNED_NEGATE 7 +# define NV097_SET_COMBINER_ALPHA_ICW_B_ALPHA (1<<20) +# define NV097_SET_COMBINER_ALPHA_ICW_B_SOURCE 0x000F0000 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP 0x0000E000 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_UNSIGNED_IDENTITY 0 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_UNSIGNED_INVERT 1 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_EXPAND_NORMAL 2 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_EXPAND_NEGATE 3 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_HALFBIAS_NORMAL 4 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_HALFBIAS_NEGATE 5 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_SIGNED_IDENTITY 6 +# define NV097_SET_COMBINER_ALPHA_ICW_C_MAP_SIGNED_NEGATE 7 +# define NV097_SET_COMBINER_ALPHA_ICW_C_ALPHA (1<<12) +# define NV097_SET_COMBINER_ALPHA_ICW_C_SOURCE 0x00000F00 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP 0x000000E0 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_UNSIGNED_IDENTITY 0 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_UNSIGNED_INVERT 1 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_EXPAND_NORMAL 2 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_EXPAND_NEGATE 3 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_HALFBIAS_NORMAL 4 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_HALFBIAS_NEGATE 5 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_SIGNED_IDENTITY 6 +# define NV097_SET_COMBINER_ALPHA_ICW_D_MAP_SIGNED_NEGATE 7 +# define NV097_SET_COMBINER_ALPHA_ICW_D_ALPHA (1<<4) +# define NV097_SET_COMBINER_ALPHA_ICW_D_SOURCE 0x0000000F # define NV097_SET_COMBINER_SPECULAR_FOG_CW0 0x00000288 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_A_INVERSE 0xE0000000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_A_ALPHA (1<<28) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_A_SOURCE 0x0F000000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_A_SOURCE_REG_SPECLIT 0xE +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_A_SOURCE_REG_EF_PROD 0xF +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_B_INVERSE 0x00E00000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_B_ALPHA (1<<20) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_B_SOURCE 0x000F0000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_B_SOURCE_REG_SPECLIT 0xE +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_B_SOURCE_REG_EF_PROD 0xF +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_C_INVERSE 0x0000E000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_C_ALPHA (1<<12) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_C_SOURCE 0x00000F00 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_C_SOURCE_REG_SPECLIT 0xE +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_C_SOURCE_REG_EF_PROD 0xF +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_D_INVERSE 0x000000E0 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_D_ALPHA (1<<4) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_D_SOURCE 0x0000000F +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_D_SOURCE_REG_SPECLIT 0xE +# define NV097_SET_COMBINER_SPECULAR_FOG_CW0_D_SOURCE_REG_EF_PROD 0xF # define NV097_SET_COMBINER_SPECULAR_FOG_CW1 0x0000028C +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_E_INVERSE 0xE0000000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_E_ALPHA (1<<28) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_E_SOURCE 0x0F000000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_F_INVERSE 0x00E00000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_F_ALPHA (1<<20) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_F_SOURCE 0x000F0000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_G_INVERSE 0x0000E000 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_G_ALPHA (1<<12) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_G_SOURCE 0x00000F00 +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_SPECULAR_CLAMP (1<<7) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_SPECULAR_ADD_INVERT_R5 (1<<6) +# define NV097_SET_COMBINER_SPECULAR_FOG_CW1_SPECULAR_ADD_INVERT_R12 0x0000003F # define NV097_SET_CONTROL0 0x00000290 # define NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE (1 << 0) # define NV097_SET_CONTROL0_Z_FORMAT (1 << 12) @@ -928,13 +1112,37 @@ # define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0 # define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1 # define NV097_SET_FOG_PLANE 0x000009D0 +# define NV097_SET_FLAT_SHADE_OP 0x000009FC # define NV097_SET_SCENE_AMBIENT_COLOR 0x00000A10 # define NV097_SET_VIEWPORT_OFFSET 0x00000A20 # define NV097_SET_EYE_POSITION 0x00000A50 # define NV097_SET_COMBINER_FACTOR0 0x00000A60 # define NV097_SET_COMBINER_FACTOR1 0x00000A80 # define NV097_SET_COMBINER_ALPHA_OCW 0x00000AA0 +# define NV097_SET_COMBINER_ALPHA_OCW_OP 0xFFFF8000 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_NOSHIFT 0 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_NOSHIFT_BIAS 1 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_SHIFTLEFTBY1 2 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_SHIFTLEFTBY1_BIAS 3 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_SHIFTLEFTBY2 4 +# define NV097_SET_COMBINER_ALPHA_OCW_OP_SHIFTRIGHTBY1 6 +# define NV097_SET_COMBINER_ALPHA_OCW_MUX_ENABLE (1<<14) +# define NV097_SET_COMBINER_ALPHA_OCW_SUM_DST 0x00000F00 +# define NV097_SET_COMBINER_ALPHA_OCW_AB_DST 0x000000F0 +# define NV097_SET_COMBINER_ALPHA_OCW_CD_DST 0x0000000F # define NV097_SET_COMBINER_COLOR_ICW 0x00000AC0 +# define NV097_SET_COMBINER_COLOR_ICW_A_MAP 0xE0000000 +# define NV097_SET_COMBINER_COLOR_ICW_A_ALPHA (1<<28) +# define NV097_SET_COMBINER_COLOR_ICW_A_SOURCE 0x0F000000 +# define NV097_SET_COMBINER_COLOR_ICW_B_MAP 0x00E00000 +# define NV097_SET_COMBINER_COLOR_ICW_B_ALPHA (1<<20) +# define NV097_SET_COMBINER_COLOR_ICW_B_SOURCE 0x000F0000 +# define NV097_SET_COMBINER_COLOR_ICW_C_MAP 0x0000E000 +# define NV097_SET_COMBINER_COLOR_ICW_C_ALPHA (1<<12) +# define NV097_SET_COMBINER_COLOR_ICW_C_SOURCE 0x00000F00 +# define NV097_SET_COMBINER_COLOR_ICW_D_MAP 0x000000E0 +# define NV097_SET_COMBINER_COLOR_ICW_D_ALPHA (1<<4) +# define NV097_SET_COMBINER_COLOR_ICW_D_SOURCE 0x0000000F # define NV097_SET_VIEWPORT_SCALE 0x00000AF0 # define NV097_SET_TRANSFORM_PROGRAM 0x00000B00 # define NV097_SET_TRANSFORM_CONSTANT 0x00000B80 @@ -1081,6 +1289,8 @@ # define NV097_SET_TEXTURE_SET_BUMP_ENV_OFFSET 0x00001B3C # define NV097_SET_SEMAPHORE_OFFSET 0x00001D6C # define NV097_BACK_END_WRITE_SEMAPHORE_RELEASE 0x00001D70 +# define NV097_SET_ZMIN_MAX_CONTROL 0x00001D78 +# define NV097_SET_COMPRESS_ZBUFFER_EN 0x00001D80 # define NV097_SET_ZSTENCIL_CLEAR_VALUE 0x00001D8C # define NV097_SET_COLOR_CLEAR_VALUE 0x00001D90 # define NV097_CLEAR_SURFACE 0x00001D94 @@ -1095,13 +1305,118 @@ # define NV097_SET_CLEAR_RECT_VERTICAL 0x00001D9C # define NV097_SET_SPECULAR_FOG_FACTOR 0x00001E20 # define NV097_SET_COMBINER_COLOR_OCW 0x00001E40 +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_AB 0xFFF80000 +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_AB_DISABLE 0 +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_AB_AB_DST_ENABLE 1 +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_CD (1<<18) +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_CD_DISABLE 0 +# define NV097_SET_COMBINER_COLOR_OCW_BLUETOALPHA_CD_CD_DST_ENABLE 1 +# define NV097_SET_COMBINER_COLOR_OCW_OP 0x00038000 +# define NV097_SET_COMBINER_COLOR_OCW_OP_NOSHIFT 0 +# define NV097_SET_COMBINER_COLOR_OCW_OP_NOSHIFT_BIAS 1 +# define NV097_SET_COMBINER_COLOR_OCW_OP_SHIFTLEFTBY1 2 +# define NV097_SET_COMBINER_COLOR_OCW_OP_SHIFTLEFTBY1_BIAS 3 +# define NV097_SET_COMBINER_COLOR_OCW_OP_SHIFTLEFTBY2 4 +# define NV097_SET_COMBINER_COLOR_OCW_OP_SHIFTRIGHTBY1 6 +# define NV097_SET_COMBINER_COLOR_OCW_MUX_ENABLE (1 << 14) +# define NV097_SET_COMBINER_COLOR_OCW_AB_DOT_ENABLE (1 << 13) +# define NV097_SET_COMBINER_COLOR_OCW_CD_DOT_ENABLE (1<<12) +# define NV097_SET_COMBINER_COLOR_OCW_SUM_DST 0x00000F00 +# define NV097_SET_COMBINER_COLOR_OCW_AB_DST 0x000000F0 +# define NV097_SET_COMBINER_COLOR_OCW_CD_DST 0x0000000F # define NV097_SET_COMBINER_CONTROL 0x00001E60 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT 0x000000FF +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_ONE 1 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_TWO 2 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_THREE 3 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_FOUR 4 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_FIVE 5 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_SIX 6 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_SEVEN 7 +# define NV097_SET_COMBINER_CONTROL_ITERATION_COUNT_EIGHT 8 +# define NV097_SET_COMBINER_CONTROL_MUX_SELECT 0x00000F00 +# define NV097_SET_COMBINER_CONTROL_MUX_SELECT_LSB 0 +# define NV097_SET_COMBINER_CONTROL_MUX_SELECT_MSB 1 +# define NV097_SET_COMBINER_CONTROL_FACTOR0 0x0000F000 +# define NV097_SET_COMBINER_CONTROL_FACTOR0_SAME_FACTOR_ALL 0 +# define NV097_SET_COMBINER_CONTROL_FACTOR0_EACH_STAGE 1 +# define NV097_SET_COMBINER_CONTROL_FACTOR1 0xFFFF0000 +# define NV097_SET_COMBINER_CONTROL_FACTOR1_SAME_FACTOR_ALL 0 +# define NV097_SET_COMBINER_CONTROL_FACTOR1_EACH_STAGE 1 # define NV097_SET_SHADOW_ZSLOPE_THRESHOLD 0x00001E68 # define NV097_SET_SHADER_STAGE_PROGRAM 0x00001E70 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0 0x0000001F +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_PROGRAM_NONE 0 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_2D_PROJECTIVE 1 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_3D_PROJECTIVE 2 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_CUBE_MAP 3 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_PASS_THROUGH 4 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE0_CLIP_PLANE 5 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1 0x000003E0 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_PROGRAM_NONE 0x00 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_2D_PROJECTIVE 0x01 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_3D_PROJECTIVE 0x02 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_CUBE_MAP 0x03 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_PASS_THROUGH 0x04 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_CLIP_PLANE 0x05 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_BUMPENVMAP 0x06 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_BUMPENVMAP_LUMINANCE 0x07 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_DEPENDENT_AR 0x0F +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_DEPENDENT_GB 0x10 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE1_DOT_PRODUCT 0x11 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2 0x00007C00 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_PROGRAM_NONE 0x00 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_2D_PROJECTIVE 0x01 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_3D_PROJECTIVE 0x02 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_CUBE_MAP 0x03 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_PASS_THROUGH 0x04 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_CLIP_PLANE 0x05 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_BUMPENVMAP 0x06 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_BUMPENVMAP_LUMINANCE 0x07 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_BRDF 0x08 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DOT_ST 0x09 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DOT_ZW 0x0A +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DOT_REFLECT_DIFFUSE 0x0B +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DEPENDENT_AR 0x0F +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DEPENDENT_GB 0x10 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE2_DOT_PRODUCT 0x11 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3 0x000F8000 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_PROGRAM_NONE 0x00 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_2D_PROJECTIVE 0x01 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_3D_PROJECTIVE 0x02 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_CUBE_MAP 0x03 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_PASS_THROUGH 0x04 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_CLIP_PLANE 0x05 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_BUMPENVMAP 0x06 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_BUMPENVMAP_LUMINANCE 0x07 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_BRDF 0x08 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_ST 0x09 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_ZW 0x0A +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_REFLECT_SPECULAR 0x0C +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_STR_3D 0x0D +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_STR_CUBE 0x0E +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DEPENDENT_AR 0x0F +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DEPENDENT_GB 0x10 +# define NV097_SET_SHADER_STAGE_PROGRAM_STAGE3_DOT_REFLECT_SPECULAR_CONST 0x12 # define NV097_SET_SHADER_OTHER_STAGE_INPUT 0x00001E78 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE1 0x0000FFFF +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE1_INSTAGE_0 0 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE2 0x000F0000 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE2_INSTAGE_0 0 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE2_INSTAGE_1 1 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE3 0x00F00000 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE3_INSTAGE_0 0 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE3_INSTAGE_1 1 +# define NV097_SET_SHADER_OTHER_STAGE_INPUT_STAGE3_INSTAGE_2 2 +# define NV097_SET_TRANSFORM_DATA 0x00001E80 +# define NV097_LAUNCH_TRANSFORM_PROGRAM 0x00001E90 # define NV097_SET_TRANSFORM_EXECUTION_MODE 0x00001E94 # define NV097_SET_TRANSFORM_EXECUTION_MODE_MODE 0x00000003 +# define NV097_SET_TRANSFORM_EXECUTION_MODE_MODE_FIXED 0 +# define NV097_SET_TRANSFORM_EXECUTION_MODE_MODE_PROGRAM 2 # define NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE 0xFFFFFFFC +# define NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE_USER 0 +# define NV097_SET_TRANSFORM_EXECUTION_MODE_RANGE_MODE_PRIV 1 # define NV097_SET_TRANSFORM_PROGRAM_CXT_WRITE_EN 0x00001E98 # define NV097_SET_TRANSFORM_PROGRAM_LOAD 0x00001E9C # define NV097_SET_TRANSFORM_PROGRAM_START 0x00001EA0 From d3989024eade3d764eaf867cb38f4439f3b19d16 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jan 2018 20:10:20 +0000 Subject: [PATCH 23/37] Fix a crash when setting a debug filename for the first time This was caused by doing = on a string that was not a std::string, unintentially causing the pointer address to be changed. This tweak instead causes the first character of the string to be set to \0 (null) causing all string parsing functions to treat it as an empty string, without trashing the poiner. --- src/Cxbx/WndMain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 7613f4679..43990af2e 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -178,13 +178,13 @@ WndMain::WndMain(HINSTANCE x_hInstance) : dwType = REG_SZ; dwSize = MAX_PATH; ULONG lErrCodeCxbxDebugFilename; lErrCodeCxbxDebugFilename = RegQueryValueEx(hKey, "CxbxDebugFilename", NULL, &dwType, (PBYTE)m_CxbxDebugFilename, &dwSize); if (lErrCodeCxbxDebugFilename != ERROR_SUCCESS) { - m_CxbxDebugFilename = ""; + m_CxbxDebugFilename[0] = '\0'; } dwType = REG_SZ; dwSize = MAX_PATH; LONG lErrCodeKrnlDebugFilename; lErrCodeKrnlDebugFilename = RegQueryValueEx(hKey, "KrnlDebugFilename", NULL, &dwType, (PBYTE)m_KrnlDebugFilename, &dwSize); if (lErrCodeKrnlDebugFilename != ERROR_SUCCESS) { - m_KrnlDebugFilename = ""; + m_KrnlDebugFilename[0] = '\0'; } // Prevent using an incorrect path from the registry if the debug folders have been moved From 81b1d75b4a7f17b5719cad03f205813f947909ba Mon Sep 17 00:00:00 2001 From: ergo720 Date: Fri, 26 Jan 2018 09:56:26 +0100 Subject: [PATCH 24/37] Xbox fatal error implementation --- import/OpenXDK/include/xboxkrnl/xboxkrnl.h | 38 +++++++++ src/Common/Win32/EmuShared.cpp | 2 +- src/Cxbx/WndMain.cpp | 10 +-- src/CxbxKrnl/CxbxKrnl.cpp | 68 +++++++++++++++++ src/CxbxKrnl/CxbxKrnl.h | 14 ++++ src/CxbxKrnl/EmuD3D8.cpp | 89 ++++++++++++++++++++-- src/CxbxKrnl/EmuKrnlHal.cpp | 19 ++++- src/CxbxKrnl/EmuShared.h | 15 +++- src/devices/LED.h | 2 + src/devices/SMCDevice.cpp | 20 ++++- src/devices/SMCDevice.h | 10 ++- 11 files changed, 264 insertions(+), 23 deletions(-) diff --git a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h index ea61d4406..07616d4f4 100644 --- a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h +++ b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h @@ -2183,6 +2183,44 @@ typedef struct _XBOX_EEPROM } XBOX_EEPROM; +// ****************************************************************** +// * XBOX_UEM_INFO +// ****************************************************************** +typedef struct _XBOX_UEM_INFO +{ + UCHAR ErrorCode; + UCHAR Reserved; + USHORT History; +} +XBOX_UEM_INFO; + +// ****************************************************************** +// * Xbox UEM (fatal error) codes +// ****************************************************************** +#define FATAL_ERROR_NONE 0x00 +#define FATAL_ERROR_CORE_DIGITAL 0x01 +#define FATAL_ERROR_BAD_EEPROM 0x02 +#define FATAL_ERROR_UNUSED1 0x03 +#define FATAL_ERROR_BAD_RAM 0x04 +#define FATAL_ERROR_HDD_NOT_LOCKED 0x05 +#define FATAL_ERROR_HDD_CANNOT_UNLOCK 0x06 +#define FATAL_ERROR_HDD_TIMEOUT 0x07 +#define FATAL_ERROR_HDD_NOT_FOUND 0x08 +#define FATAL_ERROR_HDD_BAD_CONFIG 0x09 +#define FATAL_ERROR_DVD_TIMEOUT 0x0A +#define FATAL_ERROR_DVD_NOT_FOUND 0x0B +#define FATAL_ERROR_DVD_BAD_CONFIG 0x0C +#define FATAL_ERROR_XBE_DASH_GENERIC 0x0D +#define FATAL_ERROR_XBE_DASH_ERROR 0x0E +#define FATAL_ERROR_UNUSED2 0x0F +#define FATAL_ERROR_XBE_DASH_SETTINGS 0x10 +#define FATAL_ERROR_UNUSED3 0x11 +#define FATAL_ERROR_UNUSED4 0x12 +#define FATAL_ERROR_UNUSED5 0x13 +#define FATAL_ERROR_XBE_DASH_X2_PASS 0x14 +#define FATAL_ERROR_REBOOT_ROUTINE 0x15 +#define FATAL_ERROR_RESERVED 0xFF + // ****************************************************************** // * TIME_FIELDS // ****************************************************************** diff --git a/src/Common/Win32/EmuShared.cpp b/src/Common/Win32/EmuShared.cpp index 6253e8e0a..4e9a464e6 100644 --- a/src/Common/Win32/EmuShared.cpp +++ b/src/Common/Win32/EmuShared.cpp @@ -136,7 +136,7 @@ void EmuShared::Cleanup() EmuShared::EmuShared() { Load(); - m_bMultiXbe = false; + m_bKeQuickReboot = false; m_LaunchDataPAddress = NULL; } diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 7613f4679..56a34bfa0 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -2051,12 +2051,12 @@ DWORD WINAPI WndMain::CrashMonitorWrapper(LPVOID lpVoid) // monitor for crashes void WndMain::CrashMonitor() { - bool bMultiXbe; + bool bQuickReboot; HANDLE hCrashMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "CrashMutex"); DWORD state = WaitForSingleObject(hCrashMutex, INFINITE); - g_EmuShared->GetMultiXbeFlag(&bMultiXbe); + g_EmuShared->GetQuickRebootFlag(&bQuickReboot); if (state == WAIT_OBJECT_0) // StopEmulation { @@ -2064,7 +2064,7 @@ void WndMain::CrashMonitor() return; } - if (state == WAIT_ABANDONED && !bMultiXbe) // that's a crash + if (state == WAIT_ABANDONED && !bQuickReboot) // that's a crash { CloseHandle(hCrashMutex); if (m_bIsStarted) // that's a hard crash, Dr Watson is invoked @@ -2083,8 +2083,8 @@ void WndMain::CrashMonitor() // multi-xbe // destroy this thread and start a new one CloseHandle(hCrashMutex); - bMultiXbe = false; - g_EmuShared->SetMultiXbeFlag(&bMultiXbe); + bQuickReboot = false; + g_EmuShared->SetQuickRebootFlag(&bQuickReboot); return; } diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 160e4e51c..9f99cfb38 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -65,6 +65,7 @@ namespace xboxkrnl #include "devices\EEPROMDevice.h" // For g_EEPROM #include "devices\video\EmuNV2A.h" // For InitOpenGLContext #include "devices\Xbox.h" // For InitXboxHardware() +#include "devices\LED.h" // For LED::Sequence /* prevent name collisions */ namespace NtDll @@ -105,6 +106,9 @@ DWORD_PTR g_CPUOthers = 0; HANDLE g_CurrentProcessHandle = 0; // Set in CxbxKrnlMain bool g_IsWine = false; +bool g_CxbxPrintUEM = false; +ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE; + // Define function located in EmuXApi so we can call it from here void SetupXboxDeviceTypes(); @@ -1006,6 +1010,22 @@ __declspec(noreturn) void CxbxKrnlInit DbgPrintf("INIT: Initializing render window.\n"); XTL::CxbxInitWindow(pXbeHeader, dwXbeHeaderSize); + // Now process the boot flags to see if there are any special conditions to handle + int BootFlags = 0; + g_EmuShared->GetBootFlags(&BootFlags); + + if (BootFlags & BOOT_EJECT_PENDING) {} // TODO + if (BootFlags & BOOT_FATAL_ERROR) + { + // If we are here it means we have been rebooted to display the fatal error screen. The error code is set + // to 0x15 and the led flashes with the sequence green, red, red, red + + SetLEDSequence(0xE1); + CxbxKrnlPrintUEM(FATAL_ERROR_REBOOT_ROUTINE); // won't return + } + if (BootFlags & BOOT_SKIP_ANIMATION) {} // TODO + if (BootFlags & BOOT_RUN_DASHBOARD) {} // TODO + XTL::CxbxInitAudio(); EmuHLEIntercept(pXbeHeader); @@ -1270,6 +1290,54 @@ void CxbxKrnlShutDown() TerminateProcess(g_CurrentProcessHandle, 0); } +void CxbxKrnlPrintUEM(ULONG ErrorCode) +{ + ULONG Type; + xboxkrnl::XBOX_EEPROM Eeprom; + ULONG ResultSize; + + NTSTATUS status = xboxkrnl::ExQueryNonVolatileSetting(xboxkrnl::XC_MAX_ALL, &Type, &Eeprom, sizeof(Eeprom), &ResultSize); + + if (status == STATUS_SUCCESS) + { + xboxkrnl::XBOX_UEM_INFO* UEMInfo = (xboxkrnl::XBOX_UEM_INFO*)&(Eeprom.UEMInfo[0]); + + if (UEMInfo->ErrorCode == FATAL_ERROR_NONE) + { + // ergo720: the Xbox sets the error code and displays the UEM only for non-manufacturing xbe's (it power cycles + // otherwise). Considering that this flag can be easily tampered with in the xbe and the typical end user of cxbx + // can't fix the cause of the fatal error, I decided to always display it anyway. + + UEMInfo->ErrorCode = (UCHAR)ErrorCode; + UEMInfo->History |= (1 << (ErrorCode - 5)); + } + else { + UEMInfo->ErrorCode = FATAL_ERROR_NONE; + } + xboxkrnl::ExSaveNonVolatileSetting(xboxkrnl::XC_MAX_ALL, Type, &Eeprom, sizeof(Eeprom)); + } + else { + CxbxKrnlCleanup("Could not display the fatal error screen"); + } + + if (g_bIsChihiro) + { + // The Chihiro doesn't display the UEM + CxbxKrnlCleanup("The running Chihiro xbe has encountered a fatal error and needs to close"); + } + + g_CxbxFatalErrorCode = ErrorCode; + g_CxbxPrintUEM = true; // print the UEM + + int BootFlags; + g_EmuShared->GetBootFlags(&BootFlags); + BootFlags ^= BOOT_FATAL_ERROR; // clear the fatal error flag to avoid looping here endlessly + g_EmuShared->SetBootFlags(&BootFlags); + + // Sleep forever to prevent continuing the initialization + Sleep(INFINITE); +} + __declspec(noreturn) void CxbxKrnlTerminateThread() { TerminateThread(GetCurrentThread(), 0); diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index 1cf9fcf81..ed34fd26a 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -152,6 +152,14 @@ extern "C" { #define VECTOR2IRQ(vector) ((vector)-IRQ_BASE) #define VECTOR2IRQL(vector) (PROFILE_LEVEL - VECTOR2IRQ(vector)) +// Kernel boot flags +enum { + BOOT_EJECT_PENDING = 1 << 0, + BOOT_FATAL_ERROR = 1 << 1, + BOOT_SKIP_ANIMATION = 1 << 2, + BOOT_RUN_DASHBOARD = 1 << 3, +}; + void CxbxPopupMessage(const char *message, ...); #define LOG_TEST_CASE(message) do { static bool bPopupShown = false; \ @@ -186,6 +194,9 @@ void CxbxKrnlResume(); /*! terminate gracefully the emulation */ void CxbxKrnlShutDown(); +/*! display the fatal error message*/ +void CxbxKrnlPrintUEM(ULONG ErrorCode); + /*! terminate the calling thread */ __declspec(noreturn) void CxbxKrnlTerminateThread(); @@ -208,6 +219,9 @@ extern uint32 CxbxKrnl_KernelThunkTable[379]; extern bool g_IsWine; +extern bool g_CxbxPrintUEM; +extern ULONG g_CxbxFatalErrorCode; + void InitXboxThread(DWORD_PTR cores); /*! thread local storage structure */ diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 600fe65ae..7d832b6b1 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1,4 +1,4 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // ****************************************************************** // * @@ -394,7 +394,7 @@ const char *CxbxGetErrorDescription(HRESULT hResult) case DDERR_NOTLOCKED: return "An attempt was made to unlock a surface that was not locked."; case DDERR_NOTPAGELOCKED: return "An attempt was made to page-unlock a surface with no outstanding page locks."; case DDERR_NOTPALETTIZED: return "The surface being used is not a palette-based surface."; - case DDERR_NOVSYNCHW: return "There is no hardware support for vertical blank–synchronized operations."; + case DDERR_NOVSYNCHW: return "There is no hardware support for vertical blanksynchronized operations."; case DDERR_NOZBUFFERHW: return "The operation to create a z-buffer in display memory or to perform a blit, using a z-buffer cannot be carried out because there is no hardware support for z-buffers."; case DDERR_NOZOVERLAYHW: return "The overlay surfaces cannot be z-layered, based on the z-order because the hardware does not support z-ordering of overlays."; case DDERR_OUTOFCAPS: return "The hardware needed for the requested operation has already been allocated."; @@ -1191,13 +1191,13 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) RegisterClassEx(&wc); } - bool bMultiXbe; - g_EmuShared->GetMultiXbeFlag(&bMultiXbe); + bool bQuickReboot; + g_EmuShared->GetQuickRebootFlag(&bQuickReboot); // precaution for multi-xbe titles in the case CrashMonitor has still not destoyed the previous mutex - while (bMultiXbe) + while (bQuickReboot) { - g_EmuShared->GetMultiXbeFlag(&bMultiXbe); + g_EmuShared->GetQuickRebootFlag(&bQuickReboot); } HANDLE hCrashMutex = CreateMutex(NULL, TRUE, "CrashMutex"); @@ -1365,6 +1365,83 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } break; + case WM_PAINT: + { + if (g_CxbxPrintUEM) + { + // Draw the universal error message (UEM) + // See http://xboxdevwiki.net/Fatal_Error + + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + + HDC hDC = GetDC(hWnd); + HDC hMemDC = CreateCompatibleDC(hDC); + HBITMAP hUEMBmp = CreateCompatibleBitmap(hDC, 640, 480); + HBITMAP hOriUEMBmp = (HBITMAP)SelectObject(hMemDC, hUEMBmp); + + + int nHeight = -MulDiv(8, GetDeviceCaps(hMemDC, LOGPIXELSY), 72); + + HFONT hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_ROMAN, "Verdana"); + + HGDIOBJ tmpObj = SelectObject(hMemDC, hFont); + + SetBkColor(hMemDC, RGB(0, 0, 0)); + + SetTextColor(hMemDC, RGB(0, 204, 0)); + + std::wstring wstr( + L"Your Xbox requires service.\n\n\ +Please call Xbox Customer Support.\n\n\n\ +Ihre Xbox muss gewartet werden.\n\n\ +Bitte den Xbox-Kundendienst anrufen.\n\n\n\ +La consola Xbox requiere asistencia técnica.\n\n\ +Llame al servicio de soporte al cliente de la Xbox.\n\n\n\ +Xbox ha bisogno di manutenzione.\n\n\ +Chiamare l'Assistenza Clienti di Xbox.\n\n\n\ +Votre Xbox ne fonctionne pas correctement.\n\n\ +Veuillez contacter le Support à la clientèle Xbox.\n\n\n\ +不具合が生じました。お手数ですが、\n\n\ +Xboxカスタマー サポートにお問い合わせください。"); + + // Unfortunately, DrawTextW doesn't support vertical alignemnt, so we have to do the calculation + // ourselves. See here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/abd89aae-16a0-41c6-8db6-b119ea90b42a/win32-drawtext-how-center-in-vertical-with-new-lines-and-tabs?forum=vclanguage + + RECT rect = { 0, 0, 640, 480 }; + RECT textrect = { 0, 0, 640, 480 }; + DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &textrect, DT_CALCRECT); + rect.top = (rect.bottom - textrect.bottom) / 2; + DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &rect, DT_CENTER); + + + // Draw the Xbox error code + + SetTextColor(hMemDC, RGB(255, 255, 255)); + std::string err_str(std::to_string(g_CxbxFatalErrorCode)); + rect.left = 20; + DrawText(hMemDC, err_str.c_str(), err_str.length(), &rect, DT_LEFT); + + GetClientRect(hWnd, &rect); + SetStretchBltMode(hDC, COLORONCOLOR); + StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, 640, 480, SRCCOPY); + + SelectObject(hMemDC, hOriUEMBmp); + SelectObject(hDC, tmpObj); + + DeleteObject(hUEMBmp); + DeleteObject(hFont); + DeleteObject(hMemDC); + + if (hDC != NULL) + ReleaseDC(hWnd, hDC); + + EndPaint(hWnd, &ps); + } + } + break; + case WM_SYSKEYDOWN: { if(wParam == VK_RETURN) diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index dc82052a0..e74a2ec57 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -473,8 +473,8 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur // Relaunch Cxbx, to load another Xbe { - bool bMultiXbe = true; - g_EmuShared->SetMultiXbeFlag(&bMultiXbe); + bool bQuickReboot = true; + g_EmuShared->SetQuickRebootFlag(&bQuickReboot); char szArgsBuffer[4096]; @@ -495,8 +495,21 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur break; case ReturnFirmwareFatal: - CxbxPopupMessage("Emulated Xbox hit a fatal error (might be called by XapiBootToDash from within dashboard)"); + { + // NOTE: the error code is displayed by ExDisplayFatalError by other code paths so we cannot display it without + // an OOVPA for it; the only one we can support now is FATAL_ERROR_REBOOT_ROUTINE + + xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, SMC_COMMAND_SCRATCH, 0, SMC_SCRATCH_DISPLAY_FATAL_ERROR); + char szArgsBuffer[4096]; + char szWorkingDirectoy[MAX_PATH]; + bool bQuickReboot = true; + g_EmuShared->SetQuickRebootFlag(&bQuickReboot); + g_EmuShared->GetXbePath(szWorkingDirectoy); + snprintf(szArgsBuffer, 4096, "/load \"%s\" %u %d \"%s\"", szWorkingDirectoy, CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str()); + if ((int)ShellExecute(NULL, "open", szFilePath_CxbxReloaded_Exe, szArgsBuffer, szWorkingDirectoy, SW_SHOWDEFAULT) <= 32) + CxbxKrnlCleanup("Could not reboot"); break; + } case ReturnFirmwareAll: LOG_UNIMPLEMENTED(); diff --git a/src/CxbxKrnl/EmuShared.h b/src/CxbxKrnl/EmuShared.h index 45311670f..b9b6557a0 100644 --- a/src/CxbxKrnl/EmuShared.h +++ b/src/CxbxKrnl/EmuShared.h @@ -107,6 +107,12 @@ class EmuShared : public Mutex void GetFlagsLLE( int *flags) { Lock(); *flags = m_FlagsLLE; Unlock(); } void SetFlagsLLE(const int *flags) { Lock(); m_FlagsLLE = *flags; Unlock(); } + // ****************************************************************** + // * Boot flag Accessors + // ****************************************************************** + void GetBootFlags(int *value) { Lock(); *value = m_BootFlags; Unlock(); } + void SetBootFlags(int *value) { Lock(); m_BootFlags = *value; Unlock(); } + // ****************************************************************** // * XInput Flag Accessors // ****************************************************************** @@ -132,10 +138,10 @@ class EmuShared : public Mutex void SetCurrentFPS(float *value) { Lock(); m_FPS = *value; Unlock(); } // ****************************************************************** - // * MultiXbe flag Accessors + // * Kernel quick reboot flag Accessors // ****************************************************************** - void GetMultiXbeFlag(bool *value) { Lock(); *value = m_bMultiXbe; Unlock(); } - void SetMultiXbeFlag(bool *value) { Lock(); m_bMultiXbe = *value; Unlock(); } + void GetQuickRebootFlag(bool *value) { Lock(); *value = m_bKeQuickReboot; Unlock(); } + void SetQuickRebootFlag(bool *value) { Lock(); m_bKeQuickReboot = *value; Unlock(); } // ****************************************************************** // * Launch data physical address Accessors @@ -180,12 +186,13 @@ class EmuShared : public Mutex XBVideo m_XBVideo; XBAudio m_XBAudio; char m_XbePath[MAX_PATH]; + int m_BootFlags; int m_FlagsLLE; int m_XInputEnabled; int m_DisablePixelShaders; float m_MSpF; float m_FPS; - bool m_bMultiXbe; + bool m_bKeQuickReboot; PAddr m_LaunchDataPAddress; int m_LedSequence[4]; }; diff --git a/src/devices/LED.h b/src/devices/LED.h index f05668e82..16273a58a 100644 --- a/src/devices/LED.h +++ b/src/devices/LED.h @@ -90,3 +90,5 @@ namespace LED { constexpr Sequence FAST_GREEN_ORANGE = Phase0::Green | Phase1::Orange | Phase2::Green | Phase3::Orange; } + +extern void SetLEDSequence(LED::Sequence aLEDSequence); diff --git a/src/devices/SMCDevice.cpp b/src/devices/SMCDevice.cpp index d496ea7e3..919e431cd 100644 --- a/src/devices/SMCDevice.cpp +++ b/src/devices/SMCDevice.cpp @@ -156,8 +156,8 @@ void SMCDevice::WriteByte(uint8_t command, uint8_t value) case SMC_COMMAND_RESET: //0x02 reset and power off control // See http://xboxdevwiki.net/PIC#Reset_and_Power_Off switch (value) { - case SMC_RESET_ASSERT_RESET: return; //TODO - case SMC_RESET_ASSERT_POWERCYCLE: return; //TODO + case SMC_RESET_ASSERT_RESET: return; // TODO + case SMC_RESET_ASSERT_POWERCYCLE: return; // TODO case SMC_RESET_ASSERT_SHUTDOWN: CxbxKrnlShutDown(); return; // Power off, terminating the emulation } //0x05 power fan mode(0 = automatic; 1 = custom speed from reg 0x06) @@ -186,7 +186,21 @@ void SMCDevice::WriteByte(uint8_t command, uint8_t value) //0x0E another scratch register ? seems like an error code. //0x19 reset on eject(0 = enable; 1 = disable) //0x1A interrupt enable(write 0x01 to enable; can't disable once enabled) - //0x1B scratch register for the original kernel + case SMC_COMMAND_SCRATCH: //0x1B scratch register for the original kernel + // See http://xboxdevwiki.net/PIC#Scratch_register_values + switch (value) { + case SMC_SCRATCH_TRAY_EJECT_PENDING: return; // TODO + case SMC_SCRATCH_DISPLAY_FATAL_ERROR: + { + int FatalFlag; + g_EmuShared->GetBootFlags(&FatalFlag); + FatalFlag |= BOOT_FATAL_ERROR; + g_EmuShared->SetBootFlags(&FatalFlag); + break; + } + case SMC_SCRATCH_SHORT_ANIMATION: return; // TODO + case SMC_SCRATCH_DASHBOARD_BOOT: return; // TODO + } //0x20 response to PIC challenge(written first) //0x21 response to PIC challenge(written second) } diff --git a/src/devices/SMCDevice.h b/src/devices/SMCDevice.h index 306b04ca7..fc7af27a3 100644 --- a/src/devices/SMCDevice.h +++ b/src/devices/SMCDevice.h @@ -83,7 +83,7 @@ //0x0E another scratch register ? seems like an error code. //0x19 reset on eject(0 = enable; 1 = disable) //0x1A interrupt enable(write 0x01 to enable; can't disable once enabled) -//0x1B scratch register for the original kernel +#define SMC_COMMAND_SCRATCH 0x1B //0x1B scratch register for the original kernel //0x20 response to PIC challenge(written first) //0x21 response to PIC challenge(written second) @@ -94,6 +94,14 @@ #define SMC_RESET_ASSERT_POWERCYCLE 0x40 #define SMC_RESET_ASSERT_SHUTDOWN 0x80 +// +// Register values for SMC_COMMAND_SCRATCH +// +#define SMC_SCRATCH_TRAY_EJECT_PENDING 0x01 +#define SMC_SCRATCH_DISPLAY_FATAL_ERROR 0x02 +#define SMC_SCRATCH_SHORT_ANIMATION 0x04 +#define SMC_SCRATCH_DASHBOARD_BOOT 0x08 + typedef enum { // TODO : Move to it's own file Revision1_0, Revision1_1, From 576ce83e942a24777600244f1e28c5cd9120a1eb Mon Sep 17 00:00:00 2001 From: Eduardo C Date: Sat, 27 Jan 2018 22:04:55 +0100 Subject: [PATCH 25/37] Improved dumping of extended Xbe certificate information: Original Certificate Size, Online Service ID, Extra Security Flags, and Code Encryption Key --- src/Common/Xbe.h | 1 + src/Common/XbePrinter.cpp | 16 ++++++++++++++++ src/Common/XbePrinter.h | 1 + 3 files changed, 18 insertions(+) diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index f6b0e6f27..b937e09e8 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -157,6 +157,7 @@ class Xbe : public Error uint32 dwOriginalCertificateSize; // 0x01D0 - Original Certificate Size? uint32 dwOnlineService; // 0x01D4 - Online Service ID uint32 dwSecurityFlags; // 0x01D8 - Extra Security Flags + uint08 bzCodeEncKey[16]; // 0x01DC - Code Encryption Key? } #include "AlignPosfix1.h" m_Certificate; diff --git a/src/Common/XbePrinter.cpp b/src/Common/XbePrinter.cpp index 65c1660db..aacf05928 100644 --- a/src/Common/XbePrinter.cpp +++ b/src/Common/XbePrinter.cpp @@ -294,6 +294,7 @@ std::string XbePrinter::GenXbeCertificateInfo() text.append(GenLANKey()); text.append(GenSignatureKey()); text.append(GenAlternateSignatureKeys()); + text.append(GenExtraInfo()); return text; } @@ -378,6 +379,21 @@ std::string XbePrinter::GenAlternateSignatureKeys() return text; } +std::string XbePrinter::GenExtraInfo() +{ + std::stringstream text; + SSTREAM_SET_HEX(text); + if (Xbe_certificate->dwSize == 0x1EC) + { + text << "Original Certificate Size : 0x" << std::setw(8) << Xbe_certificate->dwOriginalCertificateSize << "\n"; + text << "Online Service ID : 0x" << std::setw(8) << Xbe_certificate->dwOnlineService << "\n"; + text << "Extra Security Flags : 0x" << std::setw(8) << Xbe_certificate->dwSecurityFlags << "\n"; + text << "Code Encryption Key : "; + text << GenHexRow(&(Xbe_certificate->bzCodeEncKey[0]), 0, 16) << "\n"; + } + return text.str(); +} + std::string XbePrinter::GenSectionInfo() { std::string text; diff --git a/src/Common/XbePrinter.h b/src/Common/XbePrinter.h index 93a087210..d5ca71af6 100644 --- a/src/Common/XbePrinter.h +++ b/src/Common/XbePrinter.h @@ -72,6 +72,7 @@ class XbePrinter std::string GenLANKey(); std::string GenSignatureKey(); std::string GenAlternateSignatureKeys(); + std::string GenExtraInfo(); std::string GenSectionInfo(); std::string GenSectionHeaders(); From b95f65be30c8cdb387a78635f6b4daabaf19b204 Mon Sep 17 00:00:00 2001 From: Eduardo C Date: Sat, 27 Jan 2018 22:11:37 +0100 Subject: [PATCH 26/37] Fix tabs... --- src/Common/Xbe.h | 2 +- src/Common/XbePrinter.cpp | 24 ++++++++++++------------ src/Common/XbePrinter.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index b937e09e8..fe61d834a 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -157,7 +157,7 @@ class Xbe : public Error uint32 dwOriginalCertificateSize; // 0x01D0 - Original Certificate Size? uint32 dwOnlineService; // 0x01D4 - Online Service ID uint32 dwSecurityFlags; // 0x01D8 - Extra Security Flags - uint08 bzCodeEncKey[16]; // 0x01DC - Code Encryption Key? + uint08 bzCodeEncKey[16]; // 0x01DC - Code Encryption Key? } #include "AlignPosfix1.h" m_Certificate; diff --git a/src/Common/XbePrinter.cpp b/src/Common/XbePrinter.cpp index aacf05928..164d300bc 100644 --- a/src/Common/XbePrinter.cpp +++ b/src/Common/XbePrinter.cpp @@ -294,7 +294,7 @@ std::string XbePrinter::GenXbeCertificateInfo() text.append(GenLANKey()); text.append(GenSignatureKey()); text.append(GenAlternateSignatureKeys()); - text.append(GenExtraInfo()); + text.append(GenExtraInfo()); return text; } @@ -381,17 +381,17 @@ std::string XbePrinter::GenAlternateSignatureKeys() std::string XbePrinter::GenExtraInfo() { - std::stringstream text; - SSTREAM_SET_HEX(text); - if (Xbe_certificate->dwSize == 0x1EC) - { - text << "Original Certificate Size : 0x" << std::setw(8) << Xbe_certificate->dwOriginalCertificateSize << "\n"; - text << "Online Service ID : 0x" << std::setw(8) << Xbe_certificate->dwOnlineService << "\n"; - text << "Extra Security Flags : 0x" << std::setw(8) << Xbe_certificate->dwSecurityFlags << "\n"; - text << "Code Encryption Key : "; - text << GenHexRow(&(Xbe_certificate->bzCodeEncKey[0]), 0, 16) << "\n"; - } - return text.str(); + std::stringstream text; + SSTREAM_SET_HEX(text); + if (Xbe_certificate->dwSize == 0x1EC) + { + text << "Original Certificate Size : 0x" << std::setw(8) << Xbe_certificate->dwOriginalCertificateSize << "\n"; + text << "Online Service ID : 0x" << std::setw(8) << Xbe_certificate->dwOnlineService << "\n"; + text << "Extra Security Flags : 0x" << std::setw(8) << Xbe_certificate->dwSecurityFlags << "\n"; + text << "Code Encryption Key : "; + text << GenHexRow(&(Xbe_certificate->bzCodeEncKey[0]), 0, 16) << "\n"; + } + return text.str(); } std::string XbePrinter::GenSectionInfo() diff --git a/src/Common/XbePrinter.h b/src/Common/XbePrinter.h index d5ca71af6..f23500f07 100644 --- a/src/Common/XbePrinter.h +++ b/src/Common/XbePrinter.h @@ -72,7 +72,7 @@ class XbePrinter std::string GenLANKey(); std::string GenSignatureKey(); std::string GenAlternateSignatureKeys(); - std::string GenExtraInfo(); + std::string GenExtraInfo(); std::string GenSectionInfo(); std::string GenSectionHeaders(); From 774f300b336fc4517eb13e4588ebef75d13cb6ef Mon Sep 17 00:00:00 2001 From: Eduardo C Date: Sun, 28 Jan 2018 00:44:12 +0100 Subject: [PATCH 27/37] Tweaks to GenExtraInfo() --- src/Common/XbePrinter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Common/XbePrinter.cpp b/src/Common/XbePrinter.cpp index 164d300bc..420a9990a 100644 --- a/src/Common/XbePrinter.cpp +++ b/src/Common/XbePrinter.cpp @@ -382,9 +382,10 @@ std::string XbePrinter::GenAlternateSignatureKeys() std::string XbePrinter::GenExtraInfo() { std::stringstream text; - SSTREAM_SET_HEX(text); - if (Xbe_certificate->dwSize == 0x1EC) + + if (Xbe_certificate->dwSize >= 0x1EC) { + SSTREAM_SET_HEX(text); text << "Original Certificate Size : 0x" << std::setw(8) << Xbe_certificate->dwOriginalCertificateSize << "\n"; text << "Online Service ID : 0x" << std::setw(8) << Xbe_certificate->dwOnlineService << "\n"; text << "Extra Security Flags : 0x" << std::setw(8) << Xbe_certificate->dwSecurityFlags << "\n"; From 753d9d89c21217f3f188b7b359291dce66488ece Mon Sep 17 00:00:00 2001 From: ergo720 Date: Sun, 28 Jan 2018 10:06:11 +0100 Subject: [PATCH 28/37] Dashboard fatal error + fix issue #878 --- import/OpenXDK/include/xboxkrnl/xboxkrnl.h | 12 ++ resource/Cxbx.rc | Bin 12494 -> 27016 bytes src/Common/Xbe.cpp | 53 +++++++- src/Common/Xbe.h | 2 +- src/Cxbx/ResCxbx.h | 1 + src/Cxbx/WndMain.cpp | 2 +- src/CxbxKrnl/CxbxKrnl.cpp | 23 ++-- src/CxbxKrnl/CxbxKrnl.h | 2 +- src/CxbxKrnl/EmuD3D8.cpp | 147 ++++++++++----------- src/CxbxKrnl/EmuD3D8.h | 2 +- src/CxbxKrnl/EmuKrnlHal.cpp | 4 + 11 files changed, 151 insertions(+), 97 deletions(-) diff --git a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h index 07616d4f4..9ee3acb04 100644 --- a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h +++ b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h @@ -1271,6 +1271,18 @@ typedef struct _LAUNCH_DATA_PAGE } LAUNCH_DATA_PAGE, *PLAUNCH_DATA_PAGE; +// ****************************************************************** +// * DASH_LAUNCH_DATA +// ****************************************************************** +typedef struct _DASH_LAUNCH_DATA +{ + DWORD dwReason; + DWORD dwContext; + DWORD dwParameter1; + DWORD dwParameter2; + BYTE Reserved[3072 - 16]; +} DASH_LAUNCH_DATA, *PDASH_LAUNCH_DATA; + // ****************************************************************** // * DISPATCHER_HEADER // ****************************************************************** diff --git a/resource/Cxbx.rc b/resource/Cxbx.rc index 2119e7eeee62d2b0d9c9c6fb1a2999ebf76c0129..cc0b630ce7574482bc41f60bb2a10b94a0e09d94 100644 GIT binary patch literal 27016 zcmd^|-Ev$<5yuZ)B~;}ZSmY`}3gN6ITXu3mm9+Y>V#yNPl@x=kge2RFuq+wLj-3?6 zEASv(bHNq2yaW`N@D3F4|4nae&exv(@Y#4xYU}9io{yRT^mO-h_weEP0k|)Wzj!RvCsqV!?RO*;%4$l@9_2`)$}Gg((x$S3FZ3l zo5`2SR49Y;ZiKg=hSI2UG1*SqNhjG&mXq~lD>=~HE4sR@?+=oV;H_(v=N; zcT^yoypN;vb0b+3HS&~yDwfH+S8d7At|Y9bnh(Tb8~RZ0@APT(e6yo6 zcEraAdh3DS|2WjTp{oycbyw%Lz^i`6o?BDd>yp=d$&AWw>$xRev3K%M9O$k|_6_MC zbkvEY<52G%OHSa016}9p6SZhoQgK^{;c#kBRv$YWN9X5;XhNILuk{#rigz2y>%a$a z#hIRet(ISj8+dqn(8cJE7y5RnQcbI)TQ9rMzSNryT|d`vv^-BA>UrK^)=^!cpo zNwj~z=luSZp0}~*X15h_yn(WeT~8}C3OaXBHQpB&FJJeC_uyomom2eWYvl0zoH=Gi z&0b>+_m|Z6HTBYi@N}fCjq!1mPml9uBmJYK*&XfC6-G_UXB-=){xZ8`Dk&e|reu3u z>NxKrh^^>_YJNmiy~?{0q~dYlH?JN3DI3R%T<3i?Ssa%}144fLxgow`v_ea~xW4M` zK<<|$_ZyO}H62coUgst8Uq_Z6V}7q^($}X{@`c8P3+b67VR(_UGaX?X{p5UibbiK? zN1whbrQwcf2vy*i&F&b?8#WqKM!EEEi{{%JS)t}sGA%pcR66=ePCClpbvk=3^vsIt zw34<&Yw$Lt&5!gAEpb!jGSXLn;E4kvSy$g-gMg5B9E7o9C8K@3q;d=`wFSS2G0jj6 zQa@$pF<@_R$^HNjBh*T0$C_-OMR^`RCO8^D7g15dw%*~rj!N7aqBU(v&{re0rP!Lb zYTpwQYl%~uo*BMHQ=&>1S3`WX7)JK~J)Wm?IkH97F&etT=$)4WydrERvtEpI8rQOM zm6Hzd?P@9Ur;0p*+%-k}&vayK-WLCw)%K=7UpJ2V5pdiZ1CCoG;J7^o9Jfcnu`mW43nSpTGX@-YM!<1* z3^?wNfaB9K;P|u@NAw-~Yqr5gfijJ_BHjEZ*sp_H4iQaWGc(>|Bc-)+u@(8TXhm8d z``P?eFTHxK$(G?3FynIC7Pl7l8}X}aay(_Un^tSFxG&^!5i9O*4R~p8v0zt0vFIP9 z?f(Pa+mtnh6_urGEXTf;qgzqWjuRdIU4^dL_l`T;f72?3D9mw)k`H1By-lAj%FeK8 zQX~0!vXC(H5Lxff|HkjJ&#-elio4uX|1HXX#)94tB~o5m3cTHZF7K~pS!74@e@+4- zi~03OMVVE|h@mgZ16ornx5RJd{zdP;Dq+hqHAS?xkrkWsfc*JXb`mGlr5!GAUR zDWlul^tXF_UVeZ7%zG(M)n!o;c{HyAPjpoj#mkA_Tp4;VuSiKO<8-gLL?d!gx<;?S$ly=mY zXi9YD;IXVcI`R>i!Hc6@9+S(AYn6WJ_Ja0V5w2>OJy5 z@c%&ED5cKm_*&w~9evPGF%7JX&TxPGg~>zqzL z7gu-0VQCtA3(L>Ftr{!!pj+m!y&f?!x3ya{CM$DvOlxDnWM!6N>dkdo?ztCq#IwS9 z={+~Pj#w5CUa9n>uH0?w_Z#u#nPjjnt#sIp#WPapdB-^9UeFQu!^nx&XJ&)!7UqA} z7b#J^lBEd|tLGZKm^tvwjjRT(rb@ZSv@9dyIFEF!Dz~QC zZpWNG_m&rO`p}!55$AT8d72iQ3ypAwYGGhhZbvX*nfFe>#hfGk+ABKNuNN4{;1-{6 zcAAVr`!%)DVgUTLT)-_w2C(jqb)X{|FW-n;-{{-EYCh7rt$XC)q&<7*O}KAcqt`vP zlpZHmLxxtFG!{8xFil^44}X49*vKa(qM4T*r&9Sjj~#h3|1pg^_RNQ&Wn`nJXQq+B zad zm+`x-u5wO?&dlzYc@JD&6=t{sjfwR{RtRXFBg#wlyY%0xWQ0rzvJpW^Y2`C2JG#Fn z2`D~4pUf*xnXcDsFwHPn`EVy56cUzyV^%d}=V!AV=k+!`;y8DaCj3 zTORAla~(Far76_Z$ZUBKt>%=PtHl>)koW<;0GKh&q`@*+4e0(m%V4}t$jmMVJnV0!K*)! z{y|R4=&&I!wXp^}bf??v^nSgVcGMRq>JjEm`lG@-$)hqJsTb95FjdM{o8n^vSTfjHt!V@{D8d0>I zz+_xgFQz5&OmEpHMro3bW~o!F#ArYn1=4=KaYnthJ3p8=%)I$gDW{@Q?nzq6Hi%qN zFP6v){m`IE(rAny>P6E_cerdENOO?I%t$_`krnNM&0ODjQ>8f~3Vg@4E{eOsTB#R> zb4VF?=22ilIW6kd>5(_8aaf-i4x>iBIC^nK)K6u6QLm<|;)^tnB4^Z#qlz<%IMTdP zucTJKJsRixJYEy$ep#c5*S3+8o>}<@b2aJ`Vui;67i-Pa zGSnLxV;;Eh50PuvE{@DJUbTNj%$K<0c8D()*CI{{7hazE)2weInn@g*+@v&48wv4L zTLBH)7F2V=i@MeIl-)1uUoU?AN$@2s<~vNyw{vx8<0Sp-&bFC2w2i#1^CS-aOt$M! z#1CfiGiR5!VTtrdI?Tx$GFqVbvDJpB#b9`%ob^M57i}~G6MTG2DARs(OD!PwLF}UJ zGbN5WQ~M9a17RUgSEABM*!xfF2Y)% z7~6M$*5WuWsm_5!7vMaoJ{LH_Vx0DSMt3d4BgSFKt+hFUnQq*LwiCsPeMuxeKWorG zy1?wabBwJ%HY&t;3v`0R&vYgu#xfYH+saHf^YJ$4j`dI5OzvrMRb(W_2GbF-V$8K) z9E^x4b~cen>ZCO2HE0~nGEiy3s#>!cB3Y9WCyN<6?;<(|PuuPuM2m|W*?E6YdY0@$ zW?Q#IwS{(rzHsKw46>NoEE$Fw%iI*Gpm*{ z79gug>$lMtM4c^zt*FtbWCNJ)CeMKA?(1+yJEi4eQ@WV!we*PB(i22qnOkO_A3j;p zhxw?fjK#oP7ON#c434qPB7Aq}_89xla+cHYj%YR`8s61ksF&xs>Q=4_zwhn?Pk$|q zdtA~Q?mY~4U%hRZ6>enFTCpGfM~H2Ay1DF^+mGF?N!5&w@sTP zVCZkBVIz{ub}Xv_?NP0-d)a7M$Y!e=ZH%{!Pt&tCX-*^FQf(huR*mgN^0kmHh8YvA zd!oXhWq2-aXMn{t1GsLBQ)U9Mqa|!k$ZV77Hw}*~OEa>uzY12$lL2sHON|3pTFY2Y zAlbWk8@3}$HN}uA_Q2sUnt`J(ifsu4nJ8pXveMrXT~$)cEKiej)A@sA%Fa)gY3mi~ zt(dV@)Y%WEU-trDR?%OIl80d@nxft&D{DuxvmeeY(t5mEuhz3s-2GD`P;j}~jOF%d z%pdj~fbXt78nd&j^&5Ji{@L0=?NKy7_NV84Po6DWZ5d=GYFn+@%;;!qpIsk^bl50e zZV?Qt557=8FvC^ehVEyu!4cyA~U^E$jgIOoz?VnFL^gX00~son6^I_jQ;b zW05@aWr#?P!xCk@8PyVXdz&cIiL~>v^fOk1uf!n#y*T4#?If)bJOx(9? zZ#IV)yQ-g6ZdO4#Ek?Izt+nsgo;3{oO~+ctZ_l>H@wW40wbuW3t=cqyPKrf4ntf(g z_Hfp0)>dJ>&F801&TmKO=Z4m5u(y=unC7$M*i*~z6Zf=;5?NZVx8vELi&v_@O{qNd zgV@#cX7U^TI*~pG8AtCNMaJZ}-w$+h`XrCUDd2sSzdsqj9i5-a+p)dRm=C!OQR`x^ zB|a@aDk~~2lEbJ)8QH8r;+e$bz03`9#>1fd@VD3>;38!Dx z?7e*6J*Xu=KjAU2_-(PnBJq;y*mf3=HmHA3@B>7Su<%XV# z`;+2F^EWQ11xa}B-EZ}z(&`sncl zyUM=4@DlSxm*GvGcoKM°OlpKM&D!d5ze(|waCu^xF7IbyDkRWfP*ZY2K*cZ^qJ zU;MNCwBt?J=`LMas{9ZH44k*2> zKQ{l|{7dui&3`NG{io*NbpC7encm#mU2cBR`9t$p&8_CIo4d_rm1iTw`#9$I-^u#E zdW^B{v3mKrR(%$CHGda-S+5BRz2*B-*R_}R{q8vb|Gt-Xuk}HU&Te7 zeb+0Gnu-uWlf3;{-^!yqxf!CUP2#uS_9ru`*fBAtg*}tq8{7MJGHkUn6d-gCVs-^Wde}j!5U)hMAp2dqY>j+H4|5D;(5Q3 zeStl;qY;!WC|eEvxa+?ZX!J?sOEpG*UI#dmZc;5W@j^( zh0n##^Bv(mQY)}DJo9E=kvZOCoen6NVd5YY(`E`6x^fw1|z|( z(z;~OLVOW&5YoIqSSeYb#`T%aPQTw&>`3-(O;w&!#0(;TuFJ2pIepgmI|ck~rTDM@ zXa8?H?5}TY=g+f=%L{GKzz z+a{%LvUjaE#=v}YUh~bFGxPBynFh;Uw2vNQG7t6#Z$sqYe3N{*k#J#o);OhfMiBxF>iZ|KKiKy_ZG{aF3-s zrc7N$(>{>D{vySPwq%Z7I&(g>G-)<=q%kFU0k_7QYE499Im6-&*RfjfwmWbAVldnPiNH)<|e;*T7Az!@B!6(~|w*+%M1UtAJ zN5l{Jhn-Kn?RFC^y*P+M5^x|e)sq*5dyqcd2m9C$V**dT&4%p1!Oy4tSxZ$^S6&Pk zr1DW^eO9@}ehO@CKnE~7(Eg>UP-k=fnksK%oWclTHtLqfL~BUL>a2w#;$UW@nGffD zJl}PM7M&@rRbBC_wQuRPCu`6z}kBL5tSW+5OWNUHiK9!Fg@!hlfNm)16A{Yzm{1;Gcr~ z4Bc=HBD6=r#^*NAU5j$!>#9ws@QS|mL$bK{&(6*Sv8s=%xFc1gu5QqoyBJdDz6yZ6 ziS|As95*L0;5dM+=@vx&C1^; zrcH%2K})xj*{K52Z4A+^gXlGe=+!~=8${Ip+;m>kK1ADXp*h!GndJ$JGSB2fbUi%$M-Xj@r>a``_|#&teaUmH3Nbt zrYLLLzV>&azj;$_ucMZM50A)SiFuc)MuoQ@yj-KO{1ssr4(%*tb8`ON|Aj6ZLTU*&)jz`mULJJjesOv z;U5DXQ$gN`gXyCh!U(7iKn$OvunTntQQQPQHU31SMD~`CNfwNNWe?z;T$HxF@x2|a z2IBx$gLz|aJ`hEg6?~taco20qNot5{|AS zlx~!eD$=(n{sz{yC`EY?<-N7XIGqz4s%`qiL$D06h6sf~a^v3<3rbL&)zF4iGu(+j zg;n1;pExq4;{eYd32o^c6kGo5dZ%jRU-w0Jz6KVnX11MchLpui1@ER=!4Y#%a&!|0`n>sPVgge zG5HIB$S?y?6RvM8mvaZZlqCamI)2}}wJ@k#=}lHugf(8CLf|E26$hx^Lq$_)G5jl$ z2y=h8@QdkJ0s>mpzyAUtMZdW|-h~0rWwA>M7nar_9 zwb5UWw={IZ!tDjWDq1e4>D&x%~P*UFXW&%YqP_Xx@iGo9@&wS1s zL)lxtMn#*o)_mAyv3J3GjpdzGc+G~vF{UO{y%~@htRGJxnHdsTqZyK7cq`&;b7>Sq zQe4LnFT{&R&SL;d^fjzNDEiF|E%O5?Xr2lR@*1sIXb zyA8)@IVc#yjE(`}YS0j&91tnOg2~V+fD^qDEQ;i2lr`Lo@+tPCBZO0W)K z!Bo>0`eu!JqH)wX>DR`AwvU75XYw9B^`R_5?*e4N!CNQ82^i+BD$XUdMYksoxI8j$ z?O}42d;|klvaqmTK1R4b6T$v_^uTt(msy1YwltwA8p0}ZPuM28cOQM>89L5KNudEq z%XTa@Uau=c;t1cOm1ZdF6tZ^_k`%gd@kLdpN|MeWB?K~Tt$xPMR*-;YC9vNLyQl%K z{MoV~@6<6V7A#@n>4MjL-BPx}vd~fnT1~Ec=bs?C>UC?9E2vyb+Q^iq^w*OuR$=+c zJWJN$_(LIfQUAG&>q3_ksQC#=+!hBgtfVl?q~ ztFInZX}AY?-I_(v+#NZZ1_q&YCJLMg1k6<>$JU{IBVVJJO`WK&g6z2bgz2Y!^L^p!|~`S&?y9g%t^F6;6tE6zFp){07#j$ zQwMOwU<%Z{mT_OHL^ID#IfKGvE%rbbuoT#nFH)Gnv?~2T4F%3vd?V7z+s6Lxj}i@H zT0aoaFU2ddlaL3SgX*9XxfK6Pu=J0h`u)aGJXWA87i|u>B&uM+1OxxBnu(>uk)j>Z zw}`VZ0|8NjvmxM5>6fhI^Ju0at2Si;ee2AL{>9&c`I7kyf^8z1%8g`Fc-S!HAf_?7 z>fsWKS2&O}S$!5)?SCU@vSM;2%9^fCPw|-q(asK*y%J+q#(v@-L!R;=hVJ0Hxffsv z=i|Q4`wK}acEEo&?*k^h#M2m8b)7ij=MYwBVEUDx@E9oL%&uoJnZSIn(58HbgxPzE zFp;7)f9)-S0&wpD_&QxILzfyIOES!G%xhRp{f?$dsZ}{*Z5aDGYrn{;(Ce>pDggW} zr&J-%5ef8!y} zUn!Wg4S-*)lXvpNNlohHmwBE1|D+1dj8L8H`>>!Q-OIY-b9H?*f*mdes?D5z8<(Tm zE)CoL`KRe`BG^S+6-v-k3wG9gSpO-THPoR8u(V;t=u##6Xd>e?Fr@8WQLw)4ZSOv* zcK3UN*m;J^8Y|yI&U?{+!)+ZrCe8O>Tv(~$J`)Bj%dc?Pi5x%A_i{RKD3`rRB{BJa xkqUKu-Lz81gy-pH>6;z*WyVe#0GX-^Vi>n@=%DoOcQ9Ck?{V=7B71Ez{x6nA&{F^a diff --git a/src/Common/Xbe.cpp b/src/Common/Xbe.cpp index 4b91fcaa5..904bcb849 100644 --- a/src/Common/Xbe.cpp +++ b/src/Common/Xbe.cpp @@ -33,15 +33,28 @@ // * All rights reserved // * // ****************************************************************** +#define _XBOXKRNL_DEFEXTRN_ + +// prevent name collisions +namespace xboxkrnl +{ + #include +}; + #include "Xbe.h" #include "CxbxUtil.h" // For RoundUp - +#include // filesystem related functions available on C++ 17 #include // For ctime +#include "devices\LED.h" // For LED::Sequence +#include "CxbxKrnl/CxbxKrnl.h" // For CxbxKrnlPrintUEM +#include "CxbxKrnl/EmuShared.h" // Include this to avoid including EmuXapi.h and EmuD3D8.h + +namespace fs = std::experimental::filesystem; + -#define PAGE_SIZE 0x1000 // construct via Xbe file -Xbe::Xbe(const char *x_szFilename) +Xbe::Xbe(const char *x_szFilename, bool bFromGUI) { char szBuffer[MAX_PATH]; @@ -54,8 +67,38 @@ Xbe::Xbe(const char *x_szFilename) // verify Xbe file was opened successfully if(XbeFile == 0) { - SetFatalError("Could not open Xbe file."); - return; + using namespace fs; // limit its scope inside here + + std::string XbeName = path(x_szFilename).filename().string(); // recover the xbe name + + // NOTE: the check for the existence of the child window is necessary because the user could have previously loaded the dashboard, + // removed/changed the path and attempt to load it again from the recent list, which will crash CxbxInitWindow below + // Note that GetHwnd(), CxbxKrnl_hEmuParent and HalReturnToFirmware are all not suitable here for various reasons + if (XbeName.compare(std::string("xboxdash.xbe")) == 0 && !bFromGUI) + { + // The dashboard could not be found on partition2. This is a fatal error on the Xbox so we display the UEM. The + // error code is different if we have a launch data page + + XTL::CxbxInitWindow(false); + + ULONG FatalErrorCode = FATAL_ERROR_XBE_DASH_GENERIC; + + if (xboxkrnl::LaunchDataPage && xboxkrnl::LaunchDataPage->Header.dwLaunchDataType == LDT_FROM_DASHBOARD) + { + xboxkrnl::PDASH_LAUNCH_DATA pLaunchDashboard = (xboxkrnl::PDASH_LAUNCH_DATA)&(xboxkrnl::LaunchDataPage->LaunchData[0]); + FatalErrorCode += pLaunchDashboard->dwReason; + } + SetLEDSequence(0xE1); // green, red, red, red + CxbxKrnlPrintUEM(FatalErrorCode); // won't return + + // TODO: FATAL_ERROR_XBE_DASH_X2_PASS (requires DVD drive authentication emulation...) + } + else + { + // Report which xbe could not be found + SetFatalError(std::string("Could not open the Xbe file ") + XbeName); + return; + } } printf("OK\n"); diff --git a/src/Common/Xbe.h b/src/Common/Xbe.h index f6b0e6f27..088dc276f 100644 --- a/src/Common/Xbe.h +++ b/src/Common/Xbe.h @@ -51,7 +51,7 @@ class Xbe : public Error { public: // construct via Xbe file - Xbe(const char *x_szFilename); + Xbe(const char *x_szFilename, bool bFromGUI); // deconstructor ~Xbe(); diff --git a/src/Cxbx/ResCxbx.h b/src/Cxbx/ResCxbx.h index 70b20c4e2..d18c0d8f9 100644 --- a/src/Cxbx/ResCxbx.h +++ b/src/Cxbx/ResCxbx.h @@ -14,6 +14,7 @@ #define IDD_ABOUT 119 #define IDR_CONTRIBUTORS 121 #define IDR_COPYING 122 +#define IDS_UEM 123 #define IDC_SET_X 1000 #define IDC_SET_Y 1001 #define IDC_SET_A 1002 diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 56a34bfa0..48b997715 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -1786,7 +1786,7 @@ void WndMain::OpenXbe(const char *x_filename) strcpy(m_XbeFilename, x_filename); - m_Xbe = new Xbe(m_XbeFilename); + m_Xbe = new Xbe(m_XbeFilename, true); if(m_Xbe->HasError()) { diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 9f99cfb38..91aefb75a 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -571,6 +571,9 @@ void CxbxKrnlMain(int argc, char* argv[]) } } + // We must save this handle now to keep the child window working in the case we need to display the UEM + CxbxKrnl_hEmuParent = IsWindow(hWnd) ? hWnd : NULL; + g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); // Write a header to the log @@ -600,6 +603,7 @@ void CxbxKrnlMain(int argc, char* argv[]) g_IsWine = true; } } + // Now we got the arguments, start by initializing the Xbox memory map : // PrepareXBoxMemoryMap() { @@ -670,7 +674,7 @@ void CxbxKrnlMain(int argc, char* argv[]) { // Load Xbe (this one will reside above WinMain's virtual_memory_placeholder) g_EmuShared->SetXbePath(xbePath.c_str()); - CxbxKrnl_Xbe = new Xbe(xbePath.c_str()); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() + CxbxKrnl_Xbe = new Xbe(xbePath.c_str(), false); // TODO : Instead of using the Xbe class, port Dxbx _ReadXbeBlock() if (CxbxKrnl_Xbe->HasFatalError()) { CxbxKrnlCleanup(CxbxKrnl_Xbe->GetError().c_str()); @@ -740,7 +744,6 @@ void CxbxKrnlMain(int argc, char* argv[]) EntryPoint ^= XOR_EP_KEY[g_XbeType]; // Launch XBE CxbxKrnlInit( - hWnd, XbeTlsData, XbeTls, CxbxKrnl_Xbe->m_LibraryVersion, @@ -790,7 +793,6 @@ void LoadXboxKeys(std::string path) __declspec(noreturn) void CxbxKrnlInit ( - HWND hwndParent, void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *pLibraryVersion, @@ -804,7 +806,6 @@ __declspec(noreturn) void CxbxKrnlInit CxbxKrnl_TLS = pTLS; CxbxKrnl_TLSData = pTLSData; CxbxKrnl_XbeHeader = pXbeHeader; - CxbxKrnl_hEmuParent = IsWindow(hwndParent) ? hwndParent : NULL; CxbxKrnl_DebugMode = DbgMode; CxbxKrnl_DebugFileName = (char*)szDebugFilename; @@ -837,7 +838,7 @@ __declspec(noreturn) void CxbxKrnlInit " pXBEHeaderSize : 0x%.08X\n" " Entry : 0x%.08X\n" ");\n", - GetCurrentThreadId(), hwndParent, pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry); + GetCurrentThreadId(), CxbxKrnl_hEmuParent, pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry); #else printf("[0x%X] INIT: Debug Trace Disabled.\n", GetCurrentThreadId()); #endif @@ -1008,7 +1009,7 @@ __declspec(noreturn) void CxbxKrnlInit // initialize grapchics DbgPrintf("INIT: Initializing render window.\n"); - XTL::CxbxInitWindow(pXbeHeader, dwXbeHeaderSize); + XTL::CxbxInitWindow(true); // Now process the boot flags to see if there are any special conditions to handle int BootFlags = 0; @@ -1296,6 +1297,11 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode) xboxkrnl::XBOX_EEPROM Eeprom; ULONG ResultSize; + int BootFlags; + g_EmuShared->GetBootFlags(&BootFlags); + BootFlags &= ~BOOT_FATAL_ERROR; // clear the fatal error flag to avoid looping here endlessly + g_EmuShared->SetBootFlags(&BootFlags); + NTSTATUS status = xboxkrnl::ExQueryNonVolatileSetting(xboxkrnl::XC_MAX_ALL, &Type, &Eeprom, sizeof(Eeprom), &ResultSize); if (status == STATUS_SUCCESS) @@ -1329,11 +1335,6 @@ void CxbxKrnlPrintUEM(ULONG ErrorCode) g_CxbxFatalErrorCode = ErrorCode; g_CxbxPrintUEM = true; // print the UEM - int BootFlags; - g_EmuShared->GetBootFlags(&BootFlags); - BootFlags ^= BOOT_FATAL_ERROR; // clear the fatal error flag to avoid looping here endlessly - g_EmuShared->SetBootFlags(&BootFlags); - // Sleep forever to prevent continuing the initialization Sleep(INFINITE); } diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index ed34fd26a..26931420b 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -177,7 +177,7 @@ bool CxbxKrnlVerifyVersion(const char *szVersion); void CxbxKrnlMain(int argc, char* argv[]); /*! initialize emulation */ -__declspec(noreturn) void CxbxKrnlInit(HWND hwndParent, void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); +__declspec(noreturn) void CxbxKrnlInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, const char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); /*! cleanup emulation */ __declspec(noreturn) void CxbxKrnlCleanup(const char *szErrorMessage, ...); diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 7d832b6b1..918dd6cd8 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -57,6 +57,7 @@ namespace xboxkrnl #include "Logging.h" #include "EmuD3D8Logging.h" #include "HLEIntercept.h" // for bLLE_GPU +#include "Cxbx\\ResCxbx.h" #include #include @@ -97,8 +98,6 @@ static XTL::DDCAPS g_DriverCaps = { 0 }; static DWORD g_dwOverlayW = 640; // Cached Overlay Width static DWORD g_dwOverlayH = 480; // Cached Overlay Height static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch -static Xbe::Header *g_XbeHeader = NULL; // XbeHeader -static uint32 g_XbeHeaderSize = 0; // XbeHeaderSize static HBRUSH g_hBgBrush = NULL; // Background Brush static volatile bool g_bRenderWindowActive = false; static XBVideo g_XBVideo; @@ -452,18 +451,15 @@ const char *D3DErrorString(HRESULT hResult) return buffer; } -VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize) +VOID XTL::CxbxInitWindow(bool bFullInit) { g_EmuShared->GetXBVideo(&g_XBVideo); if(g_XBVideo.GetFullscreen()) CxbxKrnl_hEmuParent = NULL; - // cache XbeHeader and size of XbeHeader - g_XbeHeader = XbeHeader; - g_XbeHeaderSize = XbeHeaderSize; - // create timing thread + if (bFullInit) { DWORD dwThreadId; @@ -499,7 +495,8 @@ VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize) // Ported from Dxbx : // If possible, assign this thread to another core than the one that runs Xbox1 code : - SetThreadAffinityMask(hRenderWindowThread, g_CPUOthers); + if (bFullInit) + SetThreadAffinityMask(hRenderWindowThread, g_CPUOthers); while(!g_bRenderWindowActive) SwitchToThread(); @@ -510,6 +507,70 @@ VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize) SetFocus(g_hEmuWindow); } +void DrawUEM(HWND hWnd) +{ + // Draw the universal error message (UEM) + // See http://xboxdevwiki.net/Fatal_Error + // Only call this from WM_PAINT message! + + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + + HDC hDC = GetDC(hWnd); + HDC hMemDC = CreateCompatibleDC(hDC); + HBITMAP hUEMBmp = CreateCompatibleBitmap(hDC, 640, 480); + HBITMAP hOriUEMBmp = (HBITMAP)SelectObject(hMemDC, hUEMBmp); + + + int nHeight = -MulDiv(8, GetDeviceCaps(hMemDC, LOGPIXELSY), 72); + + HFONT hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_ROMAN, "Verdana"); + + HGDIOBJ tmpObj = SelectObject(hMemDC, hFont); + + SetBkColor(hMemDC, RGB(0, 0, 0)); + + SetTextColor(hMemDC, RGB(0, 204, 0)); + + wchar_t buff[500]; + LoadStringW(GetModuleHandle(NULL), IDS_UEM, buff, sizeof(buff) / sizeof(wchar_t)); + std::wstring wstr(buff); + + // Unfortunately, DrawTextW doesn't support vertical alignemnt, so we have to do the calculation + // ourselves. See here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/abd89aae-16a0-41c6-8db6-b119ea90b42a/win32-drawtext-how-center-in-vertical-with-new-lines-and-tabs?forum=vclanguage + + RECT rect = { 0, 0, 640, 480 }; + RECT textrect = { 0, 0, 640, 480 }; + DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &textrect, DT_CALCRECT); + rect.top = (rect.bottom - textrect.bottom) / 2; + DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &rect, DT_CENTER); + + + // Draw the Xbox error code + + SetTextColor(hMemDC, RGB(255, 255, 255)); + std::string err_str(std::to_string(g_CxbxFatalErrorCode)); + rect.left = 20; + DrawText(hMemDC, err_str.c_str(), err_str.length(), &rect, DT_LEFT); + + GetClientRect(hWnd, &rect); + SetStretchBltMode(hDC, COLORONCOLOR); + StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, 640, 480, SRCCOPY); + + SelectObject(hMemDC, hOriUEMBmp); + SelectObject(hDC, tmpObj); + + DeleteObject(hUEMBmp); + DeleteObject(hFont); + DeleteObject(hMemDC); + + if (hDC != NULL) + ReleaseDC(hWnd, hDC); + + EndPaint(hWnd, &ps); +} + inline DWORD GetXboxCommonResourceType(const XTL::X_D3DResource *pXboxResource) { // Don't pass in unassigned Xbox resources @@ -1369,75 +1430,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar { if (g_CxbxPrintUEM) { - // Draw the universal error message (UEM) - // See http://xboxdevwiki.net/Fatal_Error - - PAINTSTRUCT ps; - - BeginPaint(hWnd, &ps); - - HDC hDC = GetDC(hWnd); - HDC hMemDC = CreateCompatibleDC(hDC); - HBITMAP hUEMBmp = CreateCompatibleBitmap(hDC, 640, 480); - HBITMAP hOriUEMBmp = (HBITMAP)SelectObject(hMemDC, hUEMBmp); - - - int nHeight = -MulDiv(8, GetDeviceCaps(hMemDC, LOGPIXELSY), 72); - - HFONT hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_ROMAN, "Verdana"); - - HGDIOBJ tmpObj = SelectObject(hMemDC, hFont); - - SetBkColor(hMemDC, RGB(0, 0, 0)); - - SetTextColor(hMemDC, RGB(0, 204, 0)); - - std::wstring wstr( - L"Your Xbox requires service.\n\n\ -Please call Xbox Customer Support.\n\n\n\ -Ihre Xbox muss gewartet werden.\n\n\ -Bitte den Xbox-Kundendienst anrufen.\n\n\n\ -La consola Xbox requiere asistencia técnica.\n\n\ -Llame al servicio de soporte al cliente de la Xbox.\n\n\n\ -Xbox ha bisogno di manutenzione.\n\n\ -Chiamare l'Assistenza Clienti di Xbox.\n\n\n\ -Votre Xbox ne fonctionne pas correctement.\n\n\ -Veuillez contacter le Support à la clientèle Xbox.\n\n\n\ -不具合が生じました。お手数ですが、\n\n\ -Xboxカスタマー サポートにお問い合わせください。"); - - // Unfortunately, DrawTextW doesn't support vertical alignemnt, so we have to do the calculation - // ourselves. See here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/abd89aae-16a0-41c6-8db6-b119ea90b42a/win32-drawtext-how-center-in-vertical-with-new-lines-and-tabs?forum=vclanguage - - RECT rect = { 0, 0, 640, 480 }; - RECT textrect = { 0, 0, 640, 480 }; - DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &textrect, DT_CALCRECT); - rect.top = (rect.bottom - textrect.bottom) / 2; - DrawTextW(hMemDC, wstr.c_str(), wstr.length(), &rect, DT_CENTER); - - - // Draw the Xbox error code - - SetTextColor(hMemDC, RGB(255, 255, 255)); - std::string err_str(std::to_string(g_CxbxFatalErrorCode)); - rect.left = 20; - DrawText(hMemDC, err_str.c_str(), err_str.length(), &rect, DT_LEFT); - - GetClientRect(hWnd, &rect); - SetStretchBltMode(hDC, COLORONCOLOR); - StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, 640, 480, SRCCOPY); - - SelectObject(hMemDC, hOriUEMBmp); - SelectObject(hDC, tmpObj); - - DeleteObject(hUEMBmp); - DeleteObject(hFont); - DeleteObject(hMemDC); - - if (hDC != NULL) - ReleaseDC(hWnd, hDC); - - EndPaint(hWnd, &ps); + DrawUEM(hWnd); } } break; diff --git a/src/CxbxKrnl/EmuD3D8.h b/src/CxbxKrnl/EmuD3D8.h index 68de8fcc2..596b6faba 100644 --- a/src/CxbxKrnl/EmuD3D8.h +++ b/src/CxbxKrnl/EmuD3D8.h @@ -43,7 +43,7 @@ #include // initialize render window -extern VOID CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize); +extern VOID CxbxInitWindow(bool bFullInit); extern VOID CxbxSetPixelContainerHeader ( diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index e74a2ec57..d4593bed8 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -507,7 +507,11 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur g_EmuShared->GetXbePath(szWorkingDirectoy); snprintf(szArgsBuffer, 4096, "/load \"%s\" %u %d \"%s\"", szWorkingDirectoy, CxbxKrnl_hEmuParent, CxbxKrnl_DebugMode, CxbxKrnl_DebugFileName.c_str()); if ((int)ShellExecute(NULL, "open", szFilePath_CxbxReloaded_Exe, szArgsBuffer, szWorkingDirectoy, SW_SHOWDEFAULT) <= 32) + { + int BootFlags = 0; + g_EmuShared->SetBootFlags(&BootFlags); // clear all boot flags in the case of failure CxbxKrnlCleanup("Could not reboot"); + } break; } From 12349e345d0d97fd47fdc9573f7922380a199d6c Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Tue, 16 Jan 2018 12:03:48 +0000 Subject: [PATCH 29/37] Don't attempt to compile empty pixel shaders (those with no instructions) This gets past the vs1.1 crash in Sonic Heroes E3 Demo. --- src/CxbxKrnl/EmuD3D8/VertexShader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/CxbxKrnl/EmuD3D8/VertexShader.cpp b/src/CxbxKrnl/EmuD3D8/VertexShader.cpp index e9c107bfc..285fd1ed4 100644 --- a/src/CxbxKrnl/EmuD3D8/VertexShader.cpp +++ b/src/CxbxKrnl/EmuD3D8/VertexShader.cpp @@ -2194,6 +2194,12 @@ extern HRESULT XTL::EmuRecompileVshFunction // The size of the shader is *pOriginalSize = (DWORD)pToken - (DWORD)pFunction; + // Do not attempt to compile empty shaders + if (pShader->IntermediateCount == 0) { + EmuWarning("Skipped empty Pixel Shader"); + return STATUS_INVALID_PARAMETER; + } + char* pShaderDisassembly = (char*)malloc(pShader->IntermediateCount * 100); // Should be plenty DbgVshPrintf("-- Before conversion --\n"); VshWriteShader(pShader, pShaderDisassembly, FALSE); From ccf287033b5136dc76d1003df1a548f40f45dca1 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Tue, 23 Jan 2018 22:18:26 +0000 Subject: [PATCH 30/37] Unpatch XWaveFileCreateMediaObject This fixes a hang in Crash Bandicoot: The Wrath of Cortex. --- src/CxbxKrnl/EmuDSound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CxbxKrnl/EmuDSound.cpp b/src/CxbxKrnl/EmuDSound.cpp index 74b677711..dbbaa646e 100755 --- a/src/CxbxKrnl/EmuDSound.cpp +++ b/src/CxbxKrnl/EmuDSound.cpp @@ -3370,7 +3370,7 @@ HRESULT WINAPI XTL::EMUPATCH(XWaveFileCreateMediaObject) LPCWAVEFORMATEX* ppwfxFormat, OUT void** ppMediaObject) //XFileMediaObject, include XMediaObject interface { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3937,7 +3937,7 @@ HRESULT WINAPI XTL::EMUPATCH(XWaveFileCreateMediaObjectEx) HANDLE hFile, OUT void** ppMediaObject) //XWaveFileMediaObject, include XFileMediaObject and XMediaObject interfaces { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; From ff857021e192383b5a5353d7293e9d6fb13d063b Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jan 2018 13:17:43 +0000 Subject: [PATCH 31/37] Unpatch D3D_CMiniport_GetDisplayCapabilities as it's just a wrapper around AvSendTvEncoderOption --- src/CxbxKrnl/EmuD3D8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index cc5946fc7..b83b614f1 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -9938,7 +9938,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_PersistDisplay)() // ****************************************************************** DWORD WINAPI XTL::EMUPATCH(D3D_CMiniport_GetDisplayCapabilities)() { - FUNC_EXPORTS + //FUNC_EXPORTS LOG_FUNC(); From 9760609c7599468a9b9ff3b13ae194620f81b808 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 26 Jan 2018 19:50:29 +0000 Subject: [PATCH 32/37] Unpatch XFileMediaObject API functions This fixes a hang in Atari Anthology and likely other titles. These functions do not actually need to be patched. --- src/CxbxKrnl/EmuDSound.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/CxbxKrnl/EmuDSound.cpp b/src/CxbxKrnl/EmuDSound.cpp index dbbaa646e..d3e3634f1 100755 --- a/src/CxbxKrnl/EmuDSound.cpp +++ b/src/CxbxKrnl/EmuDSound.cpp @@ -135,7 +135,6 @@ XTL::X_XFileMediaObject::_vtbl XTL::X_XFileMediaObject::vtbl = &XTL::EMUPATCH(XFileMediaObject_DoWork), // 0x24 }; - /* NOTE: SUCCEEDED define is only checking for is equal or greater than zero value. And FAILED check for less than zero value. Since DS_OK is only 0 base on DirectSound documentation, there is chance of failure which contain value greater than 0. @@ -3590,7 +3589,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileCreateMediaObjectAsync) DWORD dwMaxPackets, OUT void** ppMediaObject) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3619,7 +3618,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_Seek) DWORD dwOrigin, LPDWORD pdwAbsolute) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3642,7 +3641,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_Seek) // ****************************************************************** VOID WINAPI XTL::EMUPATCH(XFileMediaObject_DoWork)(X_XFileMediaObject* pThis) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3661,7 +3660,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_GetStatus) X_XFileMediaObject* pThis, OUT LPDWORD pdwStatus) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3685,7 +3684,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_GetInfo) X_XFileMediaObject* pThis, OUT XMEDIAINFO* pInfo) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3710,7 +3709,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_Process) LPXMEDIAPACKET pInputBuffer, LPXMEDIAPACKET pOutputBuffer) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3734,7 +3733,7 @@ ULONG WINAPI XTL::EMUPATCH(XFileMediaObject_AddRef) ( X_XFileMediaObject* pThis) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3758,7 +3757,7 @@ ULONG WINAPI XTL::EMUPATCH(XFileMediaObject_Release) ( X_XFileMediaObject* pThis) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3785,7 +3784,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileMediaObject_Discontinuity) ( X_XFileMediaObject *pThis) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; From 9e8725518dc33959996b67c4e02451ed8733f7ad Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 26 Jan 2018 21:10:59 +0000 Subject: [PATCH 33/37] Unpatch more of XFileMediaObject Fixes missing intro audio in Crash Twinsanity --- src/CxbxKrnl/EmuDSound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CxbxKrnl/EmuDSound.cpp b/src/CxbxKrnl/EmuDSound.cpp index d3e3634f1..1d75d732f 100755 --- a/src/CxbxKrnl/EmuDSound.cpp +++ b/src/CxbxKrnl/EmuDSound.cpp @@ -3344,7 +3344,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileCreateMediaObjectEx) HANDLE hFile, OUT void** ppMediaObject) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; @@ -3907,7 +3907,7 @@ HRESULT WINAPI XTL::EMUPATCH(XFileCreateMediaObject) DWORD dwFlagsAndAttributes, OUT void** ppMediaObject) { - FUNC_EXPORTS; + //FUNC_EXPORTS; enterCriticalSection; From 9bfae8be5d0d01cea5bd3c89c3236877dc5b0566 Mon Sep 17 00:00:00 2001 From: ergo720 Date: Tue, 30 Jan 2018 13:44:47 +0100 Subject: [PATCH 34/37] HalRegisterShutdownNotification implementation --- import/OpenXDK/include/xboxkrnl/hal.h | 2 +- import/OpenXDK/include/xboxkrnl/xboxkrnl.h | 43 +++++++++++- src/CxbxKrnl/EmuD3D8.cpp | 2 +- src/CxbxKrnl/EmuKrnlHal.cpp | 77 ++++++++++++++++++++-- 4 files changed, 117 insertions(+), 7 deletions(-) diff --git a/import/OpenXDK/include/xboxkrnl/hal.h b/import/OpenXDK/include/xboxkrnl/hal.h index 76fc08577..4abc2c4c0 100644 --- a/import/OpenXDK/include/xboxkrnl/hal.h +++ b/import/OpenXDK/include/xboxkrnl/hal.h @@ -84,7 +84,7 @@ typedef VOID (*PHAL_SHUTDOWN_NOTIFICATION)( IN struct _HAL_SHUTDOWN_REGISTRATION *ShutdownRegistration ); -typedef struct { +typedef struct _HAL_SHUTDOWN_REGISTRATION { PHAL_SHUTDOWN_NOTIFICATION NotificationRoutine; LONG Priority; LIST_ENTRY ListEntry; diff --git a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h index 9ee3acb04..c37a558bb 100644 --- a/import/OpenXDK/include/xboxkrnl/xboxkrnl.h +++ b/import/OpenXDK/include/xboxkrnl/xboxkrnl.h @@ -400,6 +400,46 @@ typedef struct _LIST_ENTRY } LIST_ENTRY, *PLIST_ENTRY; +// See the links below for the details about the kernel structure LIST_ENTRY and the related functions +// https://www.codeproject.com/Articles/800404/Understanding-LIST-ENTRY-Lists-and-Its-Importance +// https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/singly-and-doubly-linked-lists + +#define LIST_ENTRY_INITIALIZE_HEAD(ListHead) xboxkrnl::LIST_ENTRY ListHead = { &ListHead, &ListHead } + +#define LIST_ENTRY_ACCESS_RECORD(address, type, field) \ +((type*)((UCHAR*)(address) - (ULONG)(&((type*)0)->field))) + +#define LIST_ENTRY_INSERT_HEAD(ListHead, Entry) {\ +xboxkrnl::PLIST_ENTRY Flink;\ +Flink = ListHead->Flink;\ +(Entry)->Flink = Flink;\ +(Entry)->Blink = ListHead;\ +Flink->Blink = Entry;\ +ListHead->Flink = Entry;\ +} + +#define LIST_ENTRY_INSERT_TAIL(ListHead, Entry) {\ +xboxkrnl::PLIST_ENTRY Blink;\ +Blink = ListHead->Blink;\ +(Entry)->Flink = ListHead;\ +(Entry)->Blink = Blink;\ +Blink->Flink = Entry;\ +ListHead->Blink = Entry;\ +} + +#define LIST_ENTRY_REMOVE(Entry) {\ +xboxkrnl::PLIST_ENTRY ExFlink;\ +xboxkrnl::PLIST_ENTRY ExBlink;\ +ExFlink = (Entry)->Flink;\ +ExBlink = (Entry)->Blink;\ +ExFlink->Blink = ExBlink;\ +ExBlink->Flink = ExFlink;\ +} + +#define LIST_ENTRY_REMOVE_AT_HEAD(ListHead) \ +(ListHead)->Flink;\ +LIST_ENTRY_REMOVE((ListHead)->Flink) + typedef struct _SINGLE_LIST_ENTRY { struct _SINGLE_LIST_ENTRY *Next; } SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY, SLIST_ENTRY, *PSLIST_ENTRY; @@ -1281,7 +1321,8 @@ typedef struct _DASH_LAUNCH_DATA DWORD dwParameter1; DWORD dwParameter2; BYTE Reserved[3072 - 16]; -} DASH_LAUNCH_DATA, *PDASH_LAUNCH_DATA; +} +DASH_LAUNCH_DATA, *PDASH_LAUNCH_DATA; // ****************************************************************** // * DISPATCHER_HEADER diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index b83b614f1..4f175d560 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1,4 +1,4 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // ****************************************************************** // * diff --git a/src/CxbxKrnl/EmuKrnlHal.cpp b/src/CxbxKrnl/EmuKrnlHal.cpp index d4593bed8..e86f29413 100644 --- a/src/CxbxKrnl/EmuKrnlHal.cpp +++ b/src/CxbxKrnl/EmuKrnlHal.cpp @@ -74,6 +74,9 @@ HalSystemInterrupt HalSystemInterrupts[MAX_BUS_INTERRUPT_LEVEL + 1]; uint8_t ResetOrShutdownCommandCode = 0; uint32_t ResetOrShutdownDataValue = 0; +// global list of routines executed during a reboot +LIST_ENTRY_INITIALIZE_HEAD(ShutdownRoutineList); + // ****************************************************************** // * 0x0009 - HalReadSMCTrayState() @@ -377,9 +380,46 @@ XBSYSAPI EXPORTNUM(47) xboxkrnl::VOID NTAPI xboxkrnl::HalRegisterShutdownNotific LOG_FUNC_BEGIN LOG_FUNC_ARG(ShutdownRegistration) LOG_FUNC_ARG(Register) - LOG_FUNC_END; + LOG_FUNC_END; - LOG_UNIMPLEMENTED(); + PLIST_ENTRY ListEntry; + KIRQL OldIrql; + + OldIrql = KeRaiseIrqlToDpcLevel(); + + if (Register) + { + ListEntry = ShutdownRoutineList.Flink; + while (ListEntry != &ShutdownRoutineList) + { + if (ShutdownRegistration->Priority > LIST_ENTRY_ACCESS_RECORD(ListEntry, HAL_SHUTDOWN_REGISTRATION, ListEntry)->Priority) + { + LIST_ENTRY_INSERT_TAIL(ListEntry, &ShutdownRegistration->ListEntry) + break; + } + ListEntry = ListEntry->Flink; + } + + if (ListEntry == &ShutdownRoutineList) + { + LIST_ENTRY_INSERT_TAIL(ListEntry, &ShutdownRegistration->ListEntry) + } + } + else + { + ListEntry = ShutdownRoutineList.Flink; + while (ListEntry != &ShutdownRoutineList) + { + if (ShutdownRegistration == LIST_ENTRY_ACCESS_RECORD(ListEntry, HAL_SHUTDOWN_REGISTRATION, ListEntry)) + { + LIST_ENTRY_REMOVE(&ShutdownRegistration->ListEntry) + break; + } + ListEntry = ListEntry->Flink; + } + } + + KfLowerIrql(OldIrql); } // ****************************************************************** @@ -427,6 +467,35 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur // Commented out because XLaunchNewImage is disabled! // MmPersistContiguousMemory((PVOID)xboxkrnl::LaunchDataPage, sizeof(LAUNCH_DATA_PAGE), TRUE); + { + // ergo720: I tested this with Tenchu and Dead or Alive Ultimate, both of which register a single shutdown + // routine with HalRegisterShutdownNotification. The routines are correctly registered but when invoked they + // cause a crash. It's because these routines are registered by and act upon the Xbox hardware, most of it + // is not LLEd enough and so, until then, we don't try to execute the shutdown routines + + #if 0 + KIRQL OldIrql; + PLIST_ENTRY ListEntry; + PHAL_SHUTDOWN_REGISTRATION ShutdownRegistration; + + while (true) + { + OldIrql = KeRaiseIrqlToDpcLevel(); + + ListEntry = LIST_ENTRY_REMOVE_AT_HEAD(&ShutdownRoutineList) + + KfLowerIrql(OldIrql); + + if (ListEntry == &ShutdownRoutineList) + break; + + ShutdownRegistration = LIST_ENTRY_ACCESS_RECORD(ListEntry, HAL_SHUTDOWN_REGISTRATION, ListEntry); + ShutdownRegistration->NotificationRoutine(ShutdownRegistration); + } + #endif + } + + std::string TitlePath = xboxkrnl::LaunchDataPage->Header.szLaunchPath; char szWorkingDirectoy[MAX_PATH]; @@ -496,8 +565,8 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur case ReturnFirmwareFatal: { - // NOTE: the error code is displayed by ExDisplayFatalError by other code paths so we cannot display it without - // an OOVPA for it; the only one we can support now is FATAL_ERROR_REBOOT_ROUTINE + // NOTE: the error code is displayed by ExDisplayFatalError by other code paths so we need to change our corresponding + // paths if we want to emulate all the possible fatal errors xboxkrnl::HalWriteSMBusValue(SMBUS_SMC_SLAVE_ADDRESS, SMC_COMMAND_SCRATCH, 0, SMC_SCRATCH_DISPLAY_FATAL_ERROR); char szArgsBuffer[4096]; From 416a3a9a6823e6d702c8d10d5746b6d8f9aba6ab Mon Sep 17 00:00:00 2001 From: x1nixmzeng Date: Wed, 31 Jan 2018 23:17:33 +0000 Subject: [PATCH 35/37] Support for naming threads under Windows --- build/win32/Cxbx.vcxproj | 2 + build/win32/Cxbx.vcxproj.filters | 6 +++ src/Common/Win32/Threads.cpp | 73 ++++++++++++++++++++++++++++++++ src/Common/Win32/Threads.h | 37 ++++++++++++++++ src/Cxbx.h | 7 +++ 5 files changed, 125 insertions(+) create mode 100644 src/Common/Win32/Threads.cpp create mode 100644 src/Common/Win32/Threads.h diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index 5b67ca102..113af3df3 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -190,6 +190,7 @@ + @@ -362,6 +363,7 @@ + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index feb128c93..60a389439 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -232,6 +232,9 @@ Shared + + Shared + @@ -456,6 +459,9 @@ Shared + + Shared + diff --git a/src/Common/Win32/Threads.cpp b/src/Common/Win32/Threads.cpp new file mode 100644 index 000000000..7a6152c48 --- /dev/null +++ b/src/Common/Win32/Threads.cpp @@ -0,0 +1,73 @@ +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Win32->Threads.cpp +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * +// * All rights reserved +// * +// ****************************************************************** + +#include +#include "Threads.h" + +// Exception structure and method from: +// https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + +const DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(DWORD dwThreadID, const char* szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + } +#pragma warning(pop) +} + +void SetCurrentThreadName(const char* szThreadName) +{ + SetThreadName((DWORD)-1, szThreadName); +} diff --git a/src/Common/Win32/Threads.h b/src/Common/Win32/Threads.h new file mode 100644 index 000000000..6b4314d8c --- /dev/null +++ b/src/Common/Win32/Threads.h @@ -0,0 +1,37 @@ +// ****************************************************************** +// * +// * .,-::::: .,:: .::::::::. .,:: .: +// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; +// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' +// * $$$ Y$$$P $$""""Y$$ Y$$$P +// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, +// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, +// * +// * Cxbx->Win32->Threads.h +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2002-2003 Aaron Robinson +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +void SetCurrentThreadName(const char* szThreadName); diff --git a/src/Cxbx.h b/src/Cxbx.h index ba61341ca..dff6a2803 100644 --- a/src/Cxbx.h +++ b/src/Cxbx.h @@ -143,4 +143,11 @@ extern volatile bool g_bPrintfOn; #define DbgPrintf null_func #endif +#if WIN32 +#include "Win32\Threads.h" +#define CxbxSetThreadName(Name) SetCurrentThreadName(Name) +#else +#define CxbxSetThreadName(Name) +#endif + #endif From 58ca1159f1300fcda8044971fade2284d5727cc4 Mon Sep 17 00:00:00 2001 From: x1nixmzeng Date: Wed, 31 Jan 2018 23:31:28 +0000 Subject: [PATCH 36/37] Named all threaded methods --- src/Cxbx/WndMain.cpp | 2 ++ src/CxbxKrnl/CxbxKrnl.cpp | 7 +++++++ src/CxbxKrnl/EmuD3D8.cpp | 6 ++++++ src/CxbxKrnl/EmuKrnlKe.cpp | 2 ++ src/CxbxKrnl/EmuKrnlPs.cpp | 2 ++ src/devices/video/EmuNV2A.cpp | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 901fd99c6..5ff515ae7 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -2044,6 +2044,8 @@ void WndMain::StopEmulation() // wrapper function to call CrashMonitor DWORD WINAPI WndMain::CrashMonitorWrapper(LPVOID lpVoid) { + CxbxSetThreadName("Cxbx Crash Monitor"); + static_cast(lpVoid)->CrashMonitor(); return 0; } diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index 91aefb75a..66aa10df9 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -500,6 +500,8 @@ void PrintCurrentConfigurationLog() static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param) { + CxbxSetThreadName("CxbxKrnl Interrupts"); + // Make sure Xbox1 code runs on one core : InitXboxThread(g_CPUXbox); @@ -519,6 +521,11 @@ static unsigned int WINAPI CxbxKrnlInterruptThread(PVOID param) void CxbxKrnlMain(int argc, char* argv[]) { + // Treat this instance as the Xbox runtime entry point XBOXStartup() + // This is defined in OpenXDK: + // import/OpenXDK/include/xhal/xhal.h + CxbxSetThreadName("Cxbx XBOXStartup"); + // Skip '/load' switch // Get XBE Name : std::string xbePath = argv[2]; diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 4f175d560..56a035396 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1230,6 +1230,8 @@ static BOOL WINAPI EmuEnumDisplayDevices(GUID FAR *lpGUID, LPSTR lpDriverDescrip // window message processing thread static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) { + CxbxSetThreadName("Cxbx Render Window"); + // register window class { LOGBRUSH logBrush = {BS_SOLID, RGB(0,0,0)}; @@ -1572,6 +1574,8 @@ std::chrono::time_pointStartRoutine; diff --git a/src/devices/video/EmuNV2A.cpp b/src/devices/video/EmuNV2A.cpp index 74bca68fc..d0c9a5af2 100644 --- a/src/devices/video/EmuNV2A.cpp +++ b/src/devices/video/EmuNV2A.cpp @@ -2297,6 +2297,8 @@ static void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t static void* pfifo_puller_thread() { + CxbxSetThreadName("Cxbx NV2A FIFO"); + Cache1State *state = &pfifo.cache1; while (true) { @@ -3893,6 +3895,8 @@ std::thread vblank_thread; extern std::chrono::time_point> GetNextVBlankTime(); static void nv2a_vblank_thread() { + CxbxSetThreadName("Cxbx NV2A VBlank"); + auto nextVBlankTime = GetNextVBlankTime(); while (true) { From 59ad517149427dc5f45842f8c16977b3437fd4fd Mon Sep 17 00:00:00 2001 From: x1nixmzeng Date: Thu, 1 Feb 2018 08:49:34 +0000 Subject: [PATCH 37/37] Lookup current threadid And early-out when not debugging --- src/Common/Win32/Threads.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Common/Win32/Threads.cpp b/src/Common/Win32/Threads.cpp index 7a6152c48..393787cbb 100644 --- a/src/Common/Win32/Threads.cpp +++ b/src/Common/Win32/Threads.cpp @@ -52,6 +52,9 @@ typedef struct tagTHREADNAME_INFO void SetThreadName(DWORD dwThreadID, const char* szThreadName) { + if (!IsDebuggerPresent()) + return; + THREADNAME_INFO info; info.dwType = 0x1000; info.szName = szThreadName; @@ -69,5 +72,5 @@ void SetThreadName(DWORD dwThreadID, const char* szThreadName) void SetCurrentThreadName(const char* szThreadName) { - SetThreadName((DWORD)-1, szThreadName); + SetThreadName(GetCurrentThreadId(), szThreadName); }