commit
52679b9fac
|
@ -262,9 +262,9 @@
|
|||
<ClInclude Include="..\..\src\devices\SMBus.h" />
|
||||
<ClInclude Include="..\..\src\devices\SMCDevice.h" />
|
||||
<ClInclude Include="..\..\src\devices\SMDevice.h" />
|
||||
<ClInclude Include="..\..\src\devices\video\EmuNV2A.h" />
|
||||
<ClInclude Include="..\..\src\devices\video\nv2a.h" />
|
||||
<ClInclude Include="..\..\src\devices\video\nv2a_int.h" />
|
||||
<ClInclude Include="..\..\src\devices\video\swizzle.h" />
|
||||
<ClInclude Include="..\..\src\devices\video\vga.h" />
|
||||
<ClInclude Include="..\..\src\devices\Xbox.h" />
|
||||
</ItemGroup>
|
||||
|
@ -355,6 +355,27 @@
|
|||
<None Include="..\..\src\CxbxKrnl\HLEDataBase\XOnline.1.0.5788.inl" />
|
||||
<None Include="..\..\src\CxbxKrnl\HLEDataBase\XOnline.1.0.5849.inl" />
|
||||
<None Include="..\..\src\CxbxKrnl\HLEDataBase\XOnline.OOVPA.inl" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_DEBUG.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PBUS.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PCOUNTER.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PCRTC.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PFB.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PFIFO.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PGRAPH.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PMC.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRAMDAC.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRAMIN.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMA.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMCIO.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMDIO.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMFB.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMVIO.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PSTRAPS.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PTIMER.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PTV.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PVIDEO.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PVPE.cpp" />
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_USER.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\resource\Cxbx.rc">
|
||||
|
@ -607,8 +628,8 @@
|
|||
<ClCompile Include="..\..\src\devices\SMBus.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\SMCDevice.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\SMDevice.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\video\EmuNV2A.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\video\nv2a.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\video\swizzle.cpp" />
|
||||
<ClCompile Include="..\..\src\devices\Xbox.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -229,9 +229,6 @@
|
|||
<ClCompile Include="..\..\src\devices\EmuNVNet.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\devices\video\EmuNV2A.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\Common\XbePrinter.cpp">
|
||||
<Filter>Shared</Filter>
|
||||
</ClCompile>
|
||||
|
@ -241,6 +238,9 @@
|
|||
<ClCompile Include="..\..\src\devices\MCPXDevice.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\devices\video\swizzle.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\Cxbx\DlgControllerConfig.h">
|
||||
|
@ -453,9 +453,6 @@
|
|||
<ClInclude Include="..\..\src\devices\EmuNVNet.h">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\devices\video\EmuNV2A.h">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\devices\video\nv2a_int.h">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClInclude>
|
||||
|
@ -474,6 +471,9 @@
|
|||
<ClInclude Include="..\..\src\devices\MCPXDevice.h">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\devices\video\swizzle.h">
|
||||
<Filter>Hardware</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\resource\Splash.jpg">
|
||||
|
@ -728,6 +728,69 @@
|
|||
<None Include="..\..\src\CxbxKrnl\HLEDataBase\XOnline.OOVPA.inl">
|
||||
<Filter>HLEDatabase\XOnline</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_DEBUG.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PBUS.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PCOUNTER.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PCRTC.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PFB.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PFIFO.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PGRAPH.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PMC.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRAMDAC.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRAMIN.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMA.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMCIO.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMDIO.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMFB.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PRMVIO.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PSTRAPS.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PTIMER.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PTV.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PVIDEO.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_PVPE.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\devices\video\EmuNV2A_USER.cpp">
|
||||
<Filter>Hardware</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="GUI">
|
||||
|
|
|
@ -1708,6 +1708,7 @@ KINTERRUPT_MODE;
|
|||
// ******************************************************************
|
||||
// * IRQ (Interrupt ReQuest) Priority Levels
|
||||
// ******************************************************************
|
||||
#define PASSIVE_LEVEL 0
|
||||
#define APC_LEVEL 1
|
||||
#define DISPATCH_LEVEL 2
|
||||
#define PROFILE_LEVEL 26
|
||||
|
|
|
@ -231,6 +231,10 @@ extern thread_local std::string _logPrefix;
|
|||
#define LOG_FUNC_RESULT(r) \
|
||||
std::cout << _logFuncPrefix << " returns " << r << "\n";
|
||||
|
||||
// LOG_FUNC_RESULT_TYPE logs the function return result using the overloaded << operator of the given type
|
||||
#define LOG_FUNC_RESULT_TYPE(type, r) \
|
||||
std::cout << _logFuncPrefix << " returns " << (type)r << "\n";
|
||||
|
||||
// LOG_FORWARD indicates that an api is implemented by a forward to another API
|
||||
#define LOG_FORWARD(api) \
|
||||
LOG_INIT \
|
||||
|
@ -275,6 +279,7 @@ extern thread_local std::string _logPrefix;
|
|||
#define LOG_FUNC_ARG_OUT(arg)
|
||||
#define LOG_FUNC_END
|
||||
#define LOG_FUNC_RESULT(r)
|
||||
#define LOG_FUNC_RESULT_TYPE(type, r)
|
||||
#define LOG_FORWARD(arg)
|
||||
#define LOG_IGNORED()
|
||||
#define LOG_UNIMPLEMENTED()
|
||||
|
@ -303,6 +308,9 @@ extern thread_local std::string _logPrefix;
|
|||
// RETURN logs the given result and then returns it (so this should appear last in functions)
|
||||
#define RETURN(r) do { LOG_FUNC_RESULT(r) return r; } while (0)
|
||||
|
||||
// RETURN_TYPE logs the given typed result and then returns it (so this should appear last in functions)
|
||||
#define RETURN_TYPE(type, r) do { LOG_FUNC_RESULT_TYPE(type, r) return r; } while (0)
|
||||
|
||||
#define LOG_ONCE(msg, ...) { static bool bFirstTime = true; if(bFirstTime) { bFirstTime = false; DbgPrintf("TRAC: " ## msg, __VA_ARGS__); } }
|
||||
|
||||
#define LOG_XBOX_CALL(func) DbgPrintf("TRAC: Xbox " ## func ## "() call\n");
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace xboxkrnl
|
|||
#include <sstream> // For std::ostringstream
|
||||
|
||||
#include "devices\EEPROMDevice.h" // For g_EEPROM
|
||||
#include "devices\video\EmuNV2A.h" // For InitOpenGLContext
|
||||
#include "devices\video\nv2a.h" // For InitOpenGLContext
|
||||
#include "devices\Xbox.h" // For InitXboxHardware()
|
||||
#include "devices\LED.h" // For LED::Sequence
|
||||
|
||||
|
@ -540,7 +540,7 @@ void TriggerPendingConnectedInterrupts()
|
|||
{
|
||||
for (int i = 0; i < MAX_BUS_INTERRUPT_LEVEL; i++) {
|
||||
// If the interrupt is pending and connected, process it
|
||||
if (HalSystemInterrupts[i].IsPending() && EmuInterruptList[i]->Connected) {
|
||||
if (HalSystemInterrupts[i].IsPending() && EmuInterruptList[i] && EmuInterruptList[i]->Connected) {
|
||||
HalSystemInterrupts[i].Trigger(EmuInterruptList[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3079,7 +3079,7 @@ XTL::X_D3DSurface* WINAPI XTL::EMUPATCH(D3DDevice_GetBackBuffer2)
|
|||
// Rather than create a new surface, we should forward to the Xbox version of GetBackBuffer,
|
||||
// This gives us the correct Xbox surface to update.
|
||||
// We get signatures for both backbuffer functions as it changed in later XDKs
|
||||
XB_trampoline(X_D3DSurface, WINAPI, D3DDevice_GetBackBuffer2, (INT));
|
||||
XB_trampoline(X_D3DSurface *, WINAPI, D3DDevice_GetBackBuffer2, (INT));
|
||||
|
||||
XB_trampoline(VOID, WINAPI, D3DDevice_GetBackBuffer, (INT, D3DBACKBUFFER_TYPE, X_D3DSurface**));
|
||||
|
||||
|
@ -3896,7 +3896,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreatePixelShader)
|
|||
|
||||
#if 0 // PatrickvL Dxbx pixel shader translation
|
||||
// Attempt to recompile PixelShader
|
||||
hRet = DxbxUpdateActivePixelShader(pPSDef, hostShaderHandle);
|
||||
hRet = DxbxUpdateActivePixelShader(pPSDef, &hostShaderHandle);
|
||||
// redirect to windows d3d
|
||||
DEBUG_D3DRESULT(hRet, "g_pD3DDevice8->CreatePixelShader");
|
||||
#endif
|
||||
|
|
|
@ -541,7 +541,7 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData)
|
|||
InitializeListHead(&(Prcb->DpcListHead));
|
||||
Prcb->DpcRoutineActive = FALSE;
|
||||
|
||||
NewPcr->Irql = APC_LEVEL; // See KeLowerIrql;
|
||||
NewPcr->Irql = PASSIVE_LEVEL; // See KeLowerIrql;
|
||||
}
|
||||
|
||||
// Initialize a fake PrcbData.CurrentThread
|
||||
|
|
|
@ -178,7 +178,7 @@ void KiUnexpectedInterrupt()
|
|||
void CallSoftwareInterrupt(const xboxkrnl::KIRQL SoftwareIrql)
|
||||
{
|
||||
switch (SoftwareIrql) {
|
||||
case 0:
|
||||
case PASSIVE_LEVEL:
|
||||
KiUnexpectedInterrupt();
|
||||
break;
|
||||
case APC_LEVEL: // = 1 // HalpApcInterrupt
|
||||
|
@ -393,7 +393,7 @@ XBSYSAPI EXPORTNUM(160) xboxkrnl::KIRQL FASTCALL xboxkrnl::KfRaiseIrql
|
|||
IN KIRQL NewIrql
|
||||
)
|
||||
{
|
||||
LOG_FUNC_ONE_ARG(NewIrql);
|
||||
LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, NewIrql);
|
||||
|
||||
// Inlined KeGetCurrentIrql() :
|
||||
PKPCR Pcr = KeGetPcr();
|
||||
|
@ -407,7 +407,7 @@ XBSYSAPI EXPORTNUM(160) xboxkrnl::KIRQL FASTCALL xboxkrnl::KfRaiseIrql
|
|||
KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL, (PVOID)OldIrql, (PVOID)NewIrql, 0, 0);
|
||||
}
|
||||
|
||||
RETURN(OldIrql);
|
||||
RETURN_TYPE(KIRQL_TYPE, OldIrql);
|
||||
}
|
||||
|
||||
inline int bsr(const uint32_t a) { DWORD result; _BitScanReverse(&result, a); return result; }
|
||||
|
@ -422,7 +422,7 @@ XBSYSAPI EXPORTNUM(161) xboxkrnl::VOID FASTCALL xboxkrnl::KfLowerIrql
|
|||
IN KIRQL NewIrql
|
||||
)
|
||||
{
|
||||
LOG_FUNC_ONE_ARG(NewIrql);
|
||||
LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, NewIrql);
|
||||
|
||||
KPCR* Pcr = KeGetPcr();
|
||||
|
||||
|
@ -470,7 +470,7 @@ XBSYSAPI EXPORTNUM(163) xboxkrnl::VOID FASTCALL xboxkrnl::KiUnlockDispatcherData
|
|||
IN KIRQL OldIrql
|
||||
)
|
||||
{
|
||||
LOG_FUNC_ONE_ARG(OldIrql);
|
||||
LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, OldIrql);
|
||||
|
||||
if (!(KeGetCurrentPrcb()->DpcRoutineActive)) // Avoid KeIsExecutingDpc(), as that logs
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
// ******************************************************************
|
||||
#define _XBOXKRNL_DEFEXTRN_
|
||||
|
||||
#define LOG_PREFIX "KRNL"
|
||||
#define LOG_PREFIX "DBG "
|
||||
|
||||
// prevent name collisions
|
||||
namespace xboxkrnl
|
||||
|
@ -115,8 +115,7 @@ XBSYSAPI EXPORTNUM(8) xboxkrnl::ULONG _cdecl xboxkrnl::DbgPrint
|
|||
LOG_FUNC_ARG("...")
|
||||
LOG_FUNC_END;
|
||||
|
||||
if (Format != NULL)
|
||||
{
|
||||
if (Format != NULL) {
|
||||
char szBuffer[MAX_PATH];
|
||||
|
||||
va_list argp;
|
||||
|
@ -125,10 +124,8 @@ XBSYSAPI EXPORTNUM(8) xboxkrnl::ULONG _cdecl xboxkrnl::DbgPrint
|
|||
vsprintf(szBuffer, Format, argp);
|
||||
va_end(argp);
|
||||
|
||||
//LogPrintf("[EmuKrnl] DbgPrint: %s", szBuffer);
|
||||
|
||||
EmuWarning(szBuffer);
|
||||
//DbgPrintf(szBuffer);
|
||||
printf(szBuffer); // Note : missing newlines can occur
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
RETURN(STATUS_SUCCESS);
|
||||
|
|
|
@ -125,7 +125,7 @@ XBSYSAPI EXPORTNUM(38) xboxkrnl::VOID FASTCALL xboxkrnl::HalClearSoftwareInterru
|
|||
KIRQL Request
|
||||
)
|
||||
{
|
||||
LOG_FUNC_ONE_ARG(Request);
|
||||
LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, Request);
|
||||
|
||||
// Mask out this interrupt request
|
||||
DWORD InterruptMask = 1 << Request;
|
||||
|
@ -438,7 +438,7 @@ XBSYSAPI EXPORTNUM(48) xboxkrnl::VOID FASTCALL xboxkrnl::HalRequestSoftwareInter
|
|||
IN KIRQL Request
|
||||
)
|
||||
{
|
||||
LOG_FUNC_ONE_ARG(Request);
|
||||
LOG_FUNC_ONE_ARG_TYPE(KIRQL_TYPE, Request);
|
||||
|
||||
DWORD InterruptMask = 1 << Request;
|
||||
|
||||
|
|
|
@ -560,7 +560,7 @@ XBSYSAPI EXPORTNUM(103) xboxkrnl::KIRQL NTAPI xboxkrnl::KeGetCurrentIrql(void)
|
|||
KPCR* Pcr = KeGetPcr();
|
||||
KIRQL Irql = (KIRQL)Pcr->Irql;
|
||||
|
||||
RETURN(Irql);
|
||||
RETURN_TYPE(KIRQL_TYPE, Irql);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
|
@ -706,7 +706,7 @@ XBSYSAPI EXPORTNUM(109) xboxkrnl::VOID NTAPI xboxkrnl::KeInitializeInterrupt
|
|||
LOG_FUNC_ARG(ServiceRoutine)
|
||||
LOG_FUNC_ARG(ServiceContext)
|
||||
LOG_FUNC_ARG(Vector)
|
||||
LOG_FUNC_ARG(Irql)
|
||||
LOG_FUNC_ARG_TYPE(KIRQL_TYPE, Irql)
|
||||
LOG_FUNC_ARG(InterruptMode)
|
||||
LOG_FUNC_ARG(ShareVector)
|
||||
LOG_FUNC_END;
|
||||
|
|
|
@ -237,6 +237,15 @@ ENUM2STR_START(KINTERRUPT_MODE)
|
|||
ENUM2STR_CASE(Latched)
|
||||
ENUM2STR_END_and_LOGRENDER(KINTERRUPT_MODE)
|
||||
|
||||
ENUM2STR_START(KIRQL_TYPE)
|
||||
ENUM2STR_CASE_DEF(PASSIVE_LEVEL)
|
||||
ENUM2STR_CASE_DEF(APC_LEVEL)
|
||||
ENUM2STR_CASE_DEF(DISPATCH_LEVEL)
|
||||
ENUM2STR_CASE_DEF(PROFILE_LEVEL)
|
||||
ENUM2STR_CASE_DEF(SYNC_LEVEL)
|
||||
ENUM2STR_CASE_DEF(HIGH_LEVEL)
|
||||
ENUM2STR_END_and_LOGRENDER(KIRQL_TYPE)
|
||||
|
||||
ENUM2STR_START(KWAIT_REASON)
|
||||
ENUM2STR_CASE(Executive)
|
||||
ENUM2STR_CASE(FreePage)
|
||||
|
|
|
@ -46,6 +46,7 @@ enum ALLOCATION_TYPE;
|
|||
enum CREATE_DISPOSITION;
|
||||
enum CREATE_OPTION;
|
||||
//enum NTSTATUS;
|
||||
enum KIRQL_TYPE; // fake enum, since KIRQL is an unsigned char, which clashes with BOOLEAN
|
||||
enum PROTECTION_TYPE;
|
||||
};
|
||||
|
||||
|
@ -69,6 +70,7 @@ ENUM2STR_HEADER(EXCEPTION_DISPOSITION)
|
|||
ENUM2STR_HEADER(FILE_INFORMATION_CLASS)
|
||||
ENUM2STR_HEADER(FS_INFORMATION_CLASS)
|
||||
ENUM2STR_HEADER(KINTERRUPT_MODE)
|
||||
ENUM2STR_HEADER(KIRQL_TYPE) // Not really an enum
|
||||
ENUM2STR_HEADER(KWAIT_REASON)
|
||||
ENUM2STR_HEADER(KOBJECTS)
|
||||
ENUM2STR_HEADER(MODE)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,145 +0,0 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->Win32->CxbxKrnl->EmuX86.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 <caustik@caustik.com>
|
||||
// * (c) 2016 Luke Usher <luke.usher@outlook.com>
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#ifndef EMUNV2A_H
|
||||
#define EMUNV2A_H
|
||||
|
||||
// Valid after PCI init :
|
||||
#define NV20_REG_BASE_KERNEL 0xFD000000
|
||||
|
||||
#define NV2A_ADDR 0xFD000000
|
||||
#define NV2A_SIZE 0x01000000
|
||||
|
||||
#define NV_PMC_ADDR 0x00000000
|
||||
#define NV_PMC_SIZE 0x001000
|
||||
#define NV_PBUS_ADDR 0x00001000
|
||||
#define NV_PBUS_SIZE 0x001000
|
||||
#define NV_PFIFO_ADDR 0x00002000
|
||||
#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
|
||||
#define NV_PVIDEO_SIZE 0x001000
|
||||
#define NV_PTIMER_ADDR 0x00009000
|
||||
#define NV_PTIMER_SIZE 0x001000
|
||||
#define NV_PCOUNTER_ADDR 0x0000A000
|
||||
#define NV_PCOUNTER_SIZE 0x001000
|
||||
#define NV_PVPE_ADDR 0x0000B000
|
||||
#define NV_PVPE_SIZE 0x001000
|
||||
#define NV_PTV_ADDR 0x0000D000
|
||||
#define NV_PTV_SIZE 0x001000
|
||||
#define NV_PRMFB_ADDR 0x000A0000
|
||||
#define NV_PRMFB_SIZE 0x020000
|
||||
#define NV_PRMVIO_ADDR 0x000C0000
|
||||
#define NV_PRMVIO_SIZE 0x008000 // Was 0x001000
|
||||
#define NV_PFB_ADDR 0x00100000
|
||||
#define NV_PFB_SIZE 0x001000
|
||||
#define NV_PSTRAPS_ADDR 0x00101000
|
||||
#define NV_PSTRAPS_SIZE 0x001000
|
||||
#define NV_PGRAPH_ADDR 0x00400000
|
||||
#define NV_PGRAPH_SIZE 0x002000
|
||||
#define NV_PCRTC_ADDR 0x00600000
|
||||
#define NV_PCRTC_SIZE 0x001000
|
||||
#define NV_PRMCIO_ADDR 0x00601000
|
||||
#define NV_PRMCIO_SIZE 0x001000
|
||||
#define NV_PRAMDAC_ADDR 0x00680000
|
||||
#define NV_PRAMDAC_SIZE 0x001000
|
||||
#define NV_PRMDIO_ADDR 0x00681000
|
||||
#define NV_PRMDIO_SIZE 0x001000
|
||||
#define NV_PRAMIN_ADDR 0x00700000
|
||||
#define NV_PRAMIN_SIZE 0x100000
|
||||
#define NV_USER_ADDR 0x00800000
|
||||
#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];
|
||||
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();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,446 @@
|
|||
#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_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");
|
||||
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_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);
|
||||
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_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(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)
|
||||
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_CFG1)
|
||||
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(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(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)
|
||||
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_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);
|
||||
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_EX(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)
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* PBUS - bus control */
|
||||
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)
|
||||
// TODO : result = pci_get_long(d->dev.config + PCI_VENDOR_ID);
|
||||
break;
|
||||
case NV_PBUS_PCI_NV_1:
|
||||
result = 1; // NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED
|
||||
// TODO : result = pci_get_long(d->dev.config + PCI_COMMAND);
|
||||
break;
|
||||
case NV_PBUS_PCI_NV_2:
|
||||
result = (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1)
|
||||
// TODO : result = pci_get_long(d->dev.config + PCI_CLASS_REVISION);
|
||||
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)
|
||||
// pci_set_long(d->dev.config + PCI_COMMAND, val);
|
||||
break;
|
||||
default:
|
||||
DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PBUS);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
DEVICE_READ32(PCRTC)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
|
||||
case NV_PCRTC_INTR_0:
|
||||
result = d->pcrtc.pending_interrupts;
|
||||
break;
|
||||
case NV_PCRTC_INTR_EN_0:
|
||||
result = d->pcrtc.enabled_interrupts;
|
||||
break;
|
||||
case NV_PCRTC_START:
|
||||
result = d->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:
|
||||
d->pcrtc.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PCRTC_INTR_EN_0:
|
||||
d->pcrtc.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PCRTC_START:
|
||||
value &= 0x07FFFFFF;
|
||||
// assert(val < memory_region_size(d->vram));
|
||||
d->pcrtc.start = value;
|
||||
|
||||
NV2A_DPRINTF("PCRTC_START - %x %x %x %x\n",
|
||||
d->vram_ptr[value+64], d->vram_ptr[value+64+1],
|
||||
d->vram_ptr[value+64+2], d->vram_ptr[value+64+3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PCRTC);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
DEVICE_READ32(PFB)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case NV_PFB_CFG0:
|
||||
/* 3-4 memory partitions. The debug bios checks this. */
|
||||
result = 3; // = NV_PFB_CFG0_PART_4
|
||||
break;
|
||||
case NV_PFB_CSTATUS:
|
||||
result = d->vram_size;
|
||||
break;
|
||||
case NV_PFB_WBC:
|
||||
result = 0; // = !NV_PFB_WBC_FLUSH /* Flush not pending. */
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,516 @@
|
|||
typedef struct RAMHTEntry {
|
||||
uint32_t handle;
|
||||
xbaddr instance;
|
||||
enum FIFOEngine engine;
|
||||
unsigned int channel_id : 5;
|
||||
bool valid;
|
||||
} RAMHTEntry;
|
||||
|
||||
static void pfifo_run_pusher(NV2AState *d); // forward declaration
|
||||
int pfifo_puller_thread(NV2AState *d);
|
||||
static uint32_t ramht_hash(NV2AState *d, uint32_t handle);
|
||||
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle); // forward declaration
|
||||
|
||||
/* PFIFO - MMIO and DMA FIFO submission to PGRAPH and VPE */
|
||||
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 = d->pfifo.pending_interrupts;
|
||||
break;
|
||||
case NV_PFIFO_INTR_EN_0:
|
||||
result = d->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 = d->pfifo.cache1.push_enabled;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH1:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, d->pfifo.cache1.channel_id);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, d->pfifo.cache1.mode);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_STATUS: {
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock);
|
||||
|
||||
if (d->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,
|
||||
d->pfifo.cache1.dma_push_enabled);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS,
|
||||
d->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,
|
||||
d->pfifo.cache1.method_nonincreasing);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD,
|
||||
d->pfifo.cache1.method >> 2);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL,
|
||||
d->pfifo.cache1.subchannel);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT,
|
||||
d->pfifo.cache1.method_count);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR,
|
||||
d->pfifo.cache1.error);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_INSTANCE:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK,
|
||||
d->pfifo.cache1.dma_instance >> 4);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUT:
|
||||
result = d->user.channel_control[d->pfifo.cache1.channel_id].dma_put;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET:
|
||||
result = d->user.channel_control[d->pfifo.cache1.channel_id].dma_get;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_SUBROUTINE:
|
||||
result = d->pfifo.cache1.subroutine_return
|
||||
| d->pfifo.cache1.subroutine_active;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0: {
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock);
|
||||
result = d->pfifo.cache1.pull_enabled;
|
||||
break;
|
||||
}
|
||||
case NV_PFIFO_CACHE1_ENGINE: {
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock);
|
||||
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
|
||||
result |= d->pfifo.cache1.bound_engines[i] << (i * 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
result = d->pfifo.cache1.dcount;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW:
|
||||
result = d->pfifo.cache1.get_jmp_shadow;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW:
|
||||
result = d->pfifo.cache1.rsvd_shadow;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DATA_SHADOW:
|
||||
result = d->pfifo.cache1.data_shadow;
|
||||
break;
|
||||
default:
|
||||
DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_READ32_END(PFIFO);
|
||||
}
|
||||
|
||||
DEVICE_WRITE32(PFIFO)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(addr) {
|
||||
case NV_PFIFO_INTR_0:
|
||||
d->pfifo.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PFIFO_INTR_EN_0:
|
||||
d->pfifo.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH0:
|
||||
d->pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH1:
|
||||
d->pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID);
|
||||
d->pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE);
|
||||
assert(d->pfifo.cache1.channel_id < NV2A_NUM_CHANNELS);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUSH:
|
||||
d->pfifo.cache1.dma_push_enabled =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS);
|
||||
if (d->pfifo.cache1.dma_push_suspended
|
||||
&& !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) {
|
||||
d->pfifo.cache1.dma_push_suspended = false;
|
||||
pfifo_run_pusher(d);
|
||||
}
|
||||
d->pfifo.cache1.dma_push_suspended =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_STATE:
|
||||
d->pfifo.cache1.method_nonincreasing =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE);
|
||||
d->pfifo.cache1.method =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2;
|
||||
d->pfifo.cache1.subchannel =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL);
|
||||
d->pfifo.cache1.method_count =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT);
|
||||
d->pfifo.cache1.error =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_INSTANCE:
|
||||
d->pfifo.cache1.dma_instance =
|
||||
GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK) << 4;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUT:
|
||||
d->user.channel_control[d->pfifo.cache1.channel_id].dma_put = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET:
|
||||
d->user.channel_control[d->pfifo.cache1.channel_id].dma_get = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_SUBROUTINE:
|
||||
d->pfifo.cache1.subroutine_return =
|
||||
(value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET);
|
||||
d->pfifo.cache1.subroutine_active =
|
||||
(value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0: {
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock);
|
||||
|
||||
if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& !d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = true;
|
||||
|
||||
/* the puller thread should wake up */
|
||||
d->pfifo.cache1.cache_cond.notify_all();
|
||||
}
|
||||
else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NV_PFIFO_CACHE1_ENGINE: {
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock);
|
||||
|
||||
for (i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
|
||||
d->pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
d->pfifo.cache1.dcount =
|
||||
(value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW:
|
||||
d->pfifo.cache1.get_jmp_shadow =
|
||||
(value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW:
|
||||
d->pfifo.cache1.rsvd_shadow = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DATA_SHADOW:
|
||||
d->pfifo.cache1.data_shadow = value;
|
||||
break;
|
||||
default:
|
||||
DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PFIFO);
|
||||
}
|
||||
|
||||
|
||||
/* pusher should be fine to run from a mimo handler
|
||||
* whenever's it's convenient */
|
||||
static void pfifo_run_pusher(NV2AState *d) {
|
||||
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 = &d->pfifo.cache1;
|
||||
channel_id = state->channel_id;
|
||||
control = &d->user.channel_control[channel_id];
|
||||
|
||||
if (!state->push_enabled)
|
||||
return;
|
||||
|
||||
|
||||
/* only handling DMA for now... */
|
||||
|
||||
/* Channel running DMA */
|
||||
uint32_t channel_modes = d->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(d, state->dma_instance, &dma_len);
|
||||
|
||||
NV2A_DPRINTF("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;
|
||||
|
||||
command = (CacheEntry*)g_malloc0(sizeof(CacheEntry));
|
||||
command->method = state->method;
|
||||
command->subchannel = state->subchannel;
|
||||
command->nonincreasing = state->method_nonincreasing;
|
||||
command->parameter = word;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock); // UNTESTED
|
||||
state->cache.push(command);
|
||||
state->cache_cond.notify_all();
|
||||
} // end of cache_unique_lock scope
|
||||
|
||||
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;
|
||||
NV2A_DPRINTF("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;
|
||||
NV2A_DPRINTF("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;
|
||||
NV2A_DPRINTF("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;
|
||||
NV2A_DPRINTF("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 {
|
||||
NV2A_DPRINTF("pb reserved cmd 0x%08X - 0x%08X\n",
|
||||
control->dma_get, word);
|
||||
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NV2A_DPRINTF("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n",
|
||||
dma_len, control->dma_get, control->dma_put);
|
||||
|
||||
if (state->error) {
|
||||
NV2A_DPRINTF("pb error: %d\n", state->error);
|
||||
assert(false);
|
||||
|
||||
state->dma_push_suspended = true;
|
||||
|
||||
d->pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER;
|
||||
update_irq(d);
|
||||
}
|
||||
}
|
||||
|
||||
int pfifo_puller_thread(NV2AState *d)
|
||||
{
|
||||
CxbxSetThreadName("Cxbx NV2A FIFO");
|
||||
|
||||
Cache1State *state = &(d->pfifo.cache1);
|
||||
|
||||
#ifdef COMPILE_OPENGL
|
||||
glo_set_current(d->pgraph.gl_context);
|
||||
#endif
|
||||
|
||||
std::unique_lock<std::mutex> cache_unique_lock(d->pfifo.cache1.cache_lock, std::defer_lock);
|
||||
|
||||
while (true) {
|
||||
|
||||
cache_unique_lock.lock();
|
||||
|
||||
while (state->cache.empty() || !state->pull_enabled) {
|
||||
state->cache_cond.wait(cache_unique_lock);
|
||||
|
||||
if (d->exiting) {
|
||||
cache_unique_lock.unlock(); // UNTESTED
|
||||
#ifdef COMPILE_OPENGL
|
||||
glo_set_current(NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy cache to working_cache
|
||||
while (!state->cache.empty()) {
|
||||
state->working_cache.push(state->cache.front());
|
||||
state->cache.pop();
|
||||
}
|
||||
cache_unique_lock.unlock(); // UNTESTED
|
||||
|
||||
d->pgraph.pgraph_lock.lock(); // UNTESTED
|
||||
|
||||
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(d, 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(d, entry.channel_id);
|
||||
pgraph_wait_fifo_access(d);
|
||||
pgraph_method(d, command->subchannel, 0, entry.instance);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* the engine is bound to the subchannel */
|
||||
cache_unique_lock.lock(); // UNTESTED
|
||||
state->bound_engines[command->subchannel] = entry.engine;
|
||||
state->last_engine = entry.engine;
|
||||
cache_unique_lock.unlock(); // UNTESTED
|
||||
} 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(d, parameter);
|
||||
assert(entry.valid);
|
||||
assert(entry.channel_id == state->channel_id);
|
||||
parameter = entry.instance;
|
||||
//qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
// state->cache_lock.lock();
|
||||
enum FIFOEngine engine = state->bound_engines[command->subchannel];
|
||||
// state->cache_lock.unlock();
|
||||
|
||||
switch (engine) {
|
||||
case ENGINE_GRAPHICS:
|
||||
pgraph_wait_fifo_access(d);
|
||||
pgraph_method(d, command->subchannel,
|
||||
command->method, parameter);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// state->cache_lock.lock();
|
||||
state->last_engine = state->bound_engines[command->subchannel];
|
||||
// state->cache_lock.unlock();
|
||||
}
|
||||
|
||||
g_free(command);
|
||||
}
|
||||
|
||||
d->pgraph.pgraph_lock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ramht_hash(NV2AState *d, uint32_t handle)
|
||||
{
|
||||
unsigned int ramht_size =
|
||||
1 << (GET_MASK(d->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;
|
||||
|
||||
uint32_t hash = 0;
|
||||
while (handle) {
|
||||
hash ^= (handle & ((1 << bits) - 1));
|
||||
handle >>= bits;
|
||||
}
|
||||
hash ^= d->pfifo.cache1.channel_id << (bits - 4);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle)
|
||||
{
|
||||
unsigned int ramht_size =
|
||||
1 << (GET_MASK(d->pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12);
|
||||
|
||||
uint32_t hash = ramht_hash(d, handle);
|
||||
assert(hash * 8 < ramht_size);
|
||||
|
||||
uint32_t ramht_address =
|
||||
GET_MASK(d->pfifo.regs[NV_PFIFO_RAMHT],
|
||||
NV_PFIFO_RAMHT_BASE_ADDRESS_MASK) << 12;
|
||||
|
||||
uint8_t *entry_ptr = d->pramin.ramin_ptr + 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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
|||
/* PMC - card master control */
|
||||
DEVICE_READ32(PMC)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0
|
||||
result = 0x02A000A2;
|
||||
break;
|
||||
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 = d->pmc.pending_interrupts;
|
||||
break;
|
||||
case NV_PMC_INTR_EN_0: // Selects which functional units can cause IRQs
|
||||
result = d->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:
|
||||
/* the bits of the interrupts to clear are wrtten */
|
||||
d->pmc.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PMC_INTR_EN_0:
|
||||
d->pmc.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
|
||||
default:
|
||||
//DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PMC);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
DEVICE_READ32(PRAMDAC)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
|
||||
case NV_PRAMDAC_NVPLL_COEFF:
|
||||
result = d->pramdac.core_clock_coeff;
|
||||
break;
|
||||
case NV_PRAMDAC_MPLL_COEFF:
|
||||
result = d->pramdac.memory_clock_coeff;
|
||||
break;
|
||||
case NV_PRAMDAC_VPLL_COEFF:
|
||||
result = d->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;
|
||||
}
|
||||
|
||||
/* Surprisingly, QEMU doesn't handle unaligned access for you properly */
|
||||
// result >>= 32 - 8 * size - 8 * (addr & 3);
|
||||
|
||||
DEVICE_READ32_END(PRAMDAC);
|
||||
}
|
||||
|
||||
DEVICE_WRITE32(PRAMDAC)
|
||||
{
|
||||
switch (addr) {
|
||||
|
||||
uint32_t m, n, p;
|
||||
case NV_PRAMDAC_NVPLL_COEFF:
|
||||
d->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) {
|
||||
d->pramdac.core_clock_freq = 0;
|
||||
} else {
|
||||
d->pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n)
|
||||
/ (1 << p) / m;
|
||||
}
|
||||
|
||||
break;
|
||||
case NV_PRAMDAC_MPLL_COEFF:
|
||||
d->pramdac.memory_clock_coeff = value;
|
||||
break;
|
||||
case NV_PRAMDAC_VPLL_COEFF:
|
||||
d->pramdac.video_clock_coeff = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
//DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PRAMDAC);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
DEVICE_READ32(PRAMIN)
|
||||
{
|
||||
uint32_t result = *((uint32_t*)(d->pramin.ramin_ptr + addr));
|
||||
|
||||
DEVICE_READ32_END(PRAMIN);
|
||||
}
|
||||
|
||||
DEVICE_WRITE32(PRAMIN)
|
||||
{
|
||||
*((uint32_t*)(d->pramin.ramin_ptr + addr)) = value;
|
||||
|
||||
DEVICE_WRITE32_END(PRAMIN);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
DEVICE_READ32(PRMCIO)
|
||||
{
|
||||
// vga_ioport_read :
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case VGA_CRT_IM:
|
||||
case VGA_CRT_IC:
|
||||
result = d->prmcio.cr_index;
|
||||
break;
|
||||
case VGA_CRT_DM:
|
||||
case VGA_CRT_DC:
|
||||
result = d->prmcio.cr[d->prmcio.cr_index];
|
||||
|
||||
printf("vga: read CR%x = 0x%02x\n", d->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) {
|
||||
#if 0 // TODO : Enable
|
||||
case VGA_ATT_W:
|
||||
/* Cromwell sets attrs without enabling VGA_AR_ENABLE_DISPLAY
|
||||
* (which should result in a blank screen).
|
||||
* Either nvidia's hardware is lenient or it is set through
|
||||
* something else. The former seems more likely.
|
||||
*/
|
||||
if (d->vga.ar_flip_flop == 0) {
|
||||
value |= VGA_AR_ENABLE_DISPLAY;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
// vga_ioport_write :
|
||||
case VGA_CRT_IM:
|
||||
case VGA_CRT_IC:
|
||||
d->prmcio.cr_index = value;
|
||||
break;
|
||||
case VGA_CRT_DM:
|
||||
case VGA_CRT_DC:
|
||||
printf("vga: write CR%x = 0x%02x\n", d->prmcio.cr_index, value);
|
||||
|
||||
/* handle CR0-7 protection */
|
||||
if ((d->prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
|
||||
d->prmcio.cr_index <= VGA_CRTC_OVERFLOW) {
|
||||
/* can always write bit 4 of CR7 */
|
||||
if (d->prmcio.cr_index == VGA_CRTC_OVERFLOW) {
|
||||
d->prmcio.cr[VGA_CRTC_OVERFLOW] = (d->prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) |
|
||||
(value & 0x10);
|
||||
EmuWarning("TODO: vbe_update_vgaregs");
|
||||
//vbe_update_vgaregs();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
d->prmcio.cr[d->prmcio.cr_index] = value;
|
||||
EmuWarning("TODO: vbe_update_vgaregs");
|
||||
//vbe_update_vgaregs();
|
||||
|
||||
switch (d->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);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
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);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
DEVICE_READ32(PRMVIO)
|
||||
{
|
||||
// vga_ioport_read
|
||||
DEVICE_READ32_SWITCH() {
|
||||
default:
|
||||
DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_READ32_END(PRMVIO);
|
||||
}
|
||||
|
||||
DEVICE_WRITE32(PRMVIO)
|
||||
{
|
||||
// vga_ioport_write
|
||||
switch (addr) {
|
||||
default:
|
||||
DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PRMVIO);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
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;
|
||||
}
|
||||
|
||||
/* PTIMER - time measurement and time-based alarms */
|
||||
static uint64_t ptimer_get_clock(NV2AState * d)
|
||||
{
|
||||
// Get time in nanoseconds
|
||||
long int time = static_cast<long int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
|
||||
return muldiv64(time,
|
||||
d->pramdac.core_clock_freq * d->ptimer.numerator,
|
||||
CLOCKS_PER_SEC * d->ptimer.denominator);
|
||||
}
|
||||
|
||||
DEVICE_READ32(PTIMER)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case NV_PTIMER_INTR_0:
|
||||
result = d->ptimer.pending_interrupts;
|
||||
break;
|
||||
case NV_PTIMER_INTR_EN_0:
|
||||
result = d->ptimer.enabled_interrupts;
|
||||
break;
|
||||
case NV_PTIMER_NUMERATOR:
|
||||
result = d->ptimer.numerator;
|
||||
break;
|
||||
case NV_PTIMER_DENOMINATOR:
|
||||
result = d->ptimer.denominator;
|
||||
break;
|
||||
case NV_PTIMER_TIME_0:
|
||||
result = (ptimer_get_clock(d) & 0x7ffffff) << 5;
|
||||
break;
|
||||
case NV_PTIMER_TIME_1:
|
||||
result = (ptimer_get_clock(d) >> 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:
|
||||
d->ptimer.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PTIMER_INTR_EN_0:
|
||||
d->ptimer.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PTIMER_DENOMINATOR:
|
||||
d->ptimer.denominator = value;
|
||||
break;
|
||||
case NV_PTIMER_NUMERATOR:
|
||||
d->ptimer.numerator = value;
|
||||
break;
|
||||
case NV_PTIMER_ALARM_0:
|
||||
d->ptimer.alarm_time = value;
|
||||
break;
|
||||
default:
|
||||
//DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PTIMER);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
static void pvideo_vga_invalidate(NV2AState *d)
|
||||
{
|
||||
int y1 = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT(0)],
|
||||
NV_PVIDEO_POINT_OUT_Y);
|
||||
int y2 = y1 + GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(0)],
|
||||
NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
NV2A_DPRINTF("pvideo_vga_invalidate %d %d\n", y1, y2);
|
||||
// TODO : vga_invalidate_scanlines(&d->vga, y1, y2);
|
||||
}
|
||||
|
||||
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:
|
||||
d->pvideo.regs[addr] = value;
|
||||
// TODO : d->vga.enable_overlay = true;
|
||||
pvideo_vga_invalidate(d);
|
||||
break;
|
||||
case NV_PVIDEO_STOP:
|
||||
d->pvideo.regs[NV_PVIDEO_BUFFER] = 0;
|
||||
// TODO : d->vga.enable_overlay = false;
|
||||
pvideo_vga_invalidate(d);
|
||||
break;
|
||||
default:
|
||||
DEVICE_WRITE32_REG(pvideo);
|
||||
break;
|
||||
}
|
||||
|
||||
DEVICE_WRITE32_END(PVIDEO);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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);
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/* USER - PFIFO MMIO and DMA submission area */
|
||||
DEVICE_READ32(USER)
|
||||
{
|
||||
unsigned int channel_id = addr >> 16;
|
||||
assert(channel_id < NV2A_NUM_CHANNELS);
|
||||
|
||||
ChannelControl *control = &d->user.channel_control[channel_id];
|
||||
|
||||
uint32_t channel_modes = d->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 = &d->user.channel_control[channel_id];
|
||||
|
||||
uint32_t channel_modes = d->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 (d->pfifo.cache1.push_enabled) {
|
||||
pfifo_run_pusher(d);
|
||||
}
|
||||
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);
|
||||
}
|
|
@ -28,6 +28,10 @@
|
|||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * nv2a.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
|
||||
// * (c) 2017-2018 Luke Usher <luke.usher@outlook.com>
|
||||
// * (c) 2018 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
|
@ -38,13 +42,590 @@
|
|||
|
||||
#define LOG_PREFIX "NV2A"
|
||||
|
||||
#include "CxbxKrnl\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc
|
||||
#include "EmuNV2A.h" // For now, use EmuNV2A
|
||||
// prevent name collisions
|
||||
namespace xboxkrnl
|
||||
{
|
||||
#include <xboxkrnl/xboxkrnl.h> // For PKINTERRUPT, etc.
|
||||
};
|
||||
|
||||
#include "nv2a.h"
|
||||
#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 <string> // For std::string
|
||||
#include <distorm.h> // For uint32_t
|
||||
#include <process.h> // For __beginthreadex(), etc.
|
||||
|
||||
#include "CxbxKrnl\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc
|
||||
#include "CxbxKrnl\Emu.h"
|
||||
#include "CxbxKrnl\EmuFS.h"
|
||||
#include "CxbxKrnl\EmuKrnl.h"
|
||||
#include "CxbxKrnl\HLEIntercept.h"
|
||||
|
||||
#include "vga.h"
|
||||
#include "nv2a.h" // For NV2AState
|
||||
#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox
|
||||
|
||||
//#include <gl\glew.h>
|
||||
#include <gl\GL.h>
|
||||
#include <gl\GLU.h>
|
||||
#include <cassert>
|
||||
//#include <gl\glut.h>
|
||||
|
||||
|
||||
static void update_irq(NV2AState *d)
|
||||
{
|
||||
/* PFIFO */
|
||||
if (d->pfifo.pending_interrupts & d->pfifo.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO;
|
||||
}
|
||||
|
||||
/* PCRTC */
|
||||
if (d->pcrtc.pending_interrupts & d->pcrtc.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC;
|
||||
}
|
||||
|
||||
/* PGRAPH */
|
||||
if (d->pgraph.pending_interrupts & d->pgraph.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH;
|
||||
}
|
||||
|
||||
/* TODO : PBUS * /
|
||||
if (d->pbus.pending_interrupts & d->pbus.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_PBUS;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_PBUS;
|
||||
} */
|
||||
|
||||
/* TODO : SOFTWARE * /
|
||||
if (d->user.pending_interrupts & d->.enabled_interrupts) {
|
||||
d->pmc.pending_interrupts |= NV_PMC_INTR_0_SOFTWARE;
|
||||
}
|
||||
else {
|
||||
d->pmc.pending_interrupts &= ~NV_PMC_INTR_0_SOFTWARE;
|
||||
} */
|
||||
|
||||
if (d->pmc.pending_interrupts && d->pmc.enabled_interrupts) {
|
||||
HalSystemInterrupts[3].Assert(true);
|
||||
}
|
||||
else {
|
||||
HalSystemInterrupts[3].Assert(false);
|
||||
}
|
||||
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
|
||||
#include "EmuNV2A_DEBUG.cpp"
|
||||
|
||||
|
||||
#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 : 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(NV2AState *d, xbaddr addr)
|
||||
#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr)
|
||||
#define DEVICE_READ32_REG(dev) result = d->dev.regs[addr]
|
||||
#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result
|
||||
|
||||
#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(NV2AState *d, xbaddr addr, uint32_t value)
|
||||
#define DEVICE_WRITE32_REG(dev) d->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 inline void stl_le_p(uint32_t *p, uint32 v)
|
||||
{
|
||||
*p = v;
|
||||
}
|
||||
|
||||
static DMAObject nv_dma_load(NV2AState *d, xbaddr dma_obj_address)
|
||||
{
|
||||
assert(dma_obj_address < d->pramin.ramin_size);
|
||||
|
||||
uint32_t *dma_obj = (uint32_t*)(d->pramin.ramin_ptr + 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(NV2AState *d, xbaddr dma_obj_address, xbaddr *len)
|
||||
{
|
||||
assert(dma_obj_address < d->pramin.ramin_size);
|
||||
|
||||
DMAObject dma = nv_dma_load(d, dma_obj_address);
|
||||
|
||||
/* TODO: Handle targets and classes properly */
|
||||
NV2A_DPRINTF("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 d->vram_ptr + dma.address;
|
||||
}
|
||||
|
||||
#include "EmuNV2A_PBUS.cpp"
|
||||
#include "EmuNV2A_PCRTC.cpp"
|
||||
#include "EmuNV2A_PFB.cpp"
|
||||
#include "EmuNV2A_PGRAPH.cpp"
|
||||
#include "EmuNV2A_PFIFO.cpp"
|
||||
#include "EmuNV2A_PMC.cpp"
|
||||
#include "EmuNV2A_PRAMDAC.cpp"
|
||||
#include "EmuNV2A_PRMCIO.cpp"
|
||||
#include "EmuNV2A_PRMVIO.cpp"
|
||||
#include "EmuNV2A_PTIMER.cpp"
|
||||
#include "EmuNV2A_PVIDEO.cpp"
|
||||
#include "EmuNV2A_USER.cpp"
|
||||
|
||||
#include "EmuNV2A_PRMA.cpp"
|
||||
#include "EmuNV2A_PCOUNTER.cpp"
|
||||
#include "EmuNV2A_PVPE.cpp"
|
||||
#include "EmuNV2A_PTV.cpp"
|
||||
#include "EmuNV2A_PRMFB.cpp"
|
||||
#include "EmuNV2A_PSTRAPS.cpp"
|
||||
#include "EmuNV2A_PRMDIO.cpp"
|
||||
#include "EmuNV2A_PRAMIN.cpp"
|
||||
|
||||
const NV2ABlockInfo regions[] = { // blocktable
|
||||
|
||||
// Note : Avoid designated initializers to facilitate C++ builds
|
||||
#define ENTRY(OFFSET, SIZE, NAME, RDFUNC, WRFUNC) \
|
||||
{ \
|
||||
#NAME, OFFSET, SIZE, \
|
||||
{ RDFUNC, WRFUNC }, \
|
||||
}, \
|
||||
|
||||
/* card master control */
|
||||
ENTRY(0x000000, 0x001000, PMC, EmuNV2A_PMC_Read32, EmuNV2A_PMC_Write32)
|
||||
/* bus control */
|
||||
ENTRY(0x001000, 0x001000, PBUS, EmuNV2A_PBUS_Read32, EmuNV2A_PBUS_Write32)
|
||||
/* MMIO and DMA FIFO submission to PGRAPH and VPE */
|
||||
ENTRY(0x002000, 0x002000, PFIFO, EmuNV2A_PFIFO_Read32, EmuNV2A_PFIFO_Write32)
|
||||
/* access to BAR0/BAR1 from real mode */
|
||||
ENTRY(0x007000, 0x001000, PRMA, EmuNV2A_PRMA_Read32, EmuNV2A_PRMA_Write32)
|
||||
/* video overlay */
|
||||
ENTRY(0x008000, 0x001000, PVIDEO, EmuNV2A_PVIDEO_Read32, EmuNV2A_PVIDEO_Write32)
|
||||
/* time measurement and time-based alarms */
|
||||
ENTRY(0x009000, 0x001000, PTIMER, EmuNV2A_PTIMER_Read32, EmuNV2A_PTIMER_Write32)
|
||||
/* performance monitoring counters */
|
||||
ENTRY(0x00a000, 0x001000, PCOUNTER, EmuNV2A_PCOUNTER_Read32, EmuNV2A_PCOUNTER_Write32)
|
||||
/* MPEG2 decoding engine */
|
||||
ENTRY(0x00b000, 0x001000, PVPE, EmuNV2A_PVPE_Read32, EmuNV2A_PVPE_Write32)
|
||||
/* TV encoder */
|
||||
ENTRY(0x00d000, 0x001000, PTV, EmuNV2A_PTV_Read32, EmuNV2A_PTV_Write32)
|
||||
/* aliases VGA memory window */
|
||||
ENTRY(0x0a0000, 0x020000, PRMFB, EmuNV2A_PRMFB_Read32, EmuNV2A_PRMFB_Write32)
|
||||
/* aliases VGA sequencer and graphics controller registers */
|
||||
ENTRY(0x0c0000, 0x008000, PRMVIO, EmuNV2A_PRMVIO_Read32, EmuNV2A_PRMVIO_Write32) // Size was 0x001000
|
||||
/* memory interface */
|
||||
ENTRY(0x100000, 0x001000, PFB, EmuNV2A_PFB_Read32, EmuNV2A_PFB_Write32)
|
||||
/* straps readout / override */
|
||||
ENTRY(0x101000, 0x001000, PSTRAPS, EmuNV2A_PSTRAPS_Read32, EmuNV2A_PSTRAPS_Write32)
|
||||
/* accelerated 2d/3d drawing engine */
|
||||
ENTRY(0x400000, 0x002000, PGRAPH, EmuNV2A_PGRAPH_Read32, EmuNV2A_PGRAPH_Write32)
|
||||
/* more CRTC controls */
|
||||
ENTRY(0x600000, 0x001000, PCRTC, EmuNV2A_PCRTC_Read32, EmuNV2A_PCRTC_Write32)
|
||||
/* aliases VGA CRTC and attribute controller registers */
|
||||
ENTRY(0x601000, 0x001000, PRMCIO, EmuNV2A_PRMCIO_Read32, EmuNV2A_PRMCIO_Write32)
|
||||
/* RAMDAC, cursor, and PLL control */
|
||||
ENTRY(0x680000, 0x001000, PRAMDAC, EmuNV2A_PRAMDAC_Read32, EmuNV2A_PRAMDAC_Write32)
|
||||
/* aliases VGA palette registers */
|
||||
ENTRY(0x681000, 0x001000, PRMDIO, EmuNV2A_PRMDIO_Read32, EmuNV2A_PRMDIO_Write32)
|
||||
/* RAMIN access */
|
||||
ENTRY(0x700000, 0x100000, PRAMIN, EmuNV2A_PRAMIN_Read32, EmuNV2A_PRAMIN_Write32)
|
||||
/* PFIFO MMIO and DMA submission area */
|
||||
ENTRY(0x800000, 0x400000, USER, EmuNV2A_USER_Read32, EmuNV2A_USER_Write32) // Size was 0x800000
|
||||
/* UREMAP User area mirror - TODO : Confirm */
|
||||
ENTRY(0xC00000, 0x400000, UREMAP, EmuNV2A_USER_Read32, EmuNV2A_USER_Write32) // NOTE : Mirror of USER
|
||||
/* Terminating entry */
|
||||
ENTRY(0xFFFFFF, 0x000000, END, nullptr, nullptr)
|
||||
#undef ENTRY
|
||||
};
|
||||
|
||||
const NV2ABlockInfo* EmuNV2A_Block(xbaddr addr)
|
||||
{
|
||||
// Find the block in the block table
|
||||
const NV2ABlockInfo* block = ®ions[0];
|
||||
int i = 0;
|
||||
|
||||
while (block->size > 0) {
|
||||
if (addr >= block->offset && addr < block->offset + block->size) {
|
||||
return block;
|
||||
}
|
||||
|
||||
block = ®ions[++i];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// 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<std::chrono::steady_clock, std::chrono::duration<double, std::nano>> GetNextVBlankTime();
|
||||
static void nv2a_vblank_thread(NV2AState *d)
|
||||
{
|
||||
CxbxSetThreadName("Cxbx NV2A VBLANK");
|
||||
|
||||
auto nextVBlankTime = GetNextVBlankTime();
|
||||
|
||||
while (true) {
|
||||
// Handle VBlank
|
||||
if (std::chrono::steady_clock::now() > nextVBlankTime) {
|
||||
d->pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK;
|
||||
update_irq(d);
|
||||
nextVBlankTime = GetNextVBlankTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See NV2ABlockInfo regions[] PRAMIN
|
||||
#define NV_PRAMIN_ADDR 0x00700000
|
||||
#define NV_PRAMIN_SIZE 0x100000
|
||||
|
||||
void CxbxReserveNV2AMemory(NV2AState *d)
|
||||
{
|
||||
// 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
|
||||
d->pramin.ramin_size = NV_PRAMIN_SIZE;
|
||||
d->pramin.ramin_ptr = (uint8_t*)VirtualAllocEx(
|
||||
GetCurrentProcess(),
|
||||
(void*)(NV2A_ADDR + NV_PRAMIN_ADDR),
|
||||
d->pramin.ramin_size,
|
||||
MEM_COMMIT, // No MEM_RESERVE |
|
||||
PAGE_READWRITE);
|
||||
if (d->pramin.ramin_ptr == 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(), d->pramin.ramin_size / ONE_MB, d->pramin.ramin_ptr, d->pramin.ramin_ptr + d->pramin.ramin_size - 1);
|
||||
}
|
||||
|
||||
/* NV2ADevice */
|
||||
|
||||
NV2ADevice::NV2ADevice()
|
||||
{
|
||||
m_nv2a_state = new NV2AState();
|
||||
pgraph_init(m_nv2a_state);
|
||||
}
|
||||
|
||||
NV2ADevice::~NV2ADevice()
|
||||
{
|
||||
delete m_nv2a_state;
|
||||
}
|
||||
|
||||
// PCI Device functions
|
||||
|
||||
void NV2ADevice::Init()
|
||||
|
@ -71,8 +652,26 @@ void NV2ADevice::Init()
|
|||
m_DeviceId = 0x02A5;
|
||||
m_VendorId = PCI_VENDOR_ID_NVIDIA;
|
||||
|
||||
// For now, forward to EmuNv2A
|
||||
EmuNV2A_Init();
|
||||
NV2AState *d = m_nv2a_state; // glue
|
||||
|
||||
CxbxReserveNV2AMemory(d);
|
||||
|
||||
d->pcrtc.start = 0;
|
||||
|
||||
d->vram_ptr = (uint8_t*)MM_SYSTEM_PHYSICAL_MAP;
|
||||
d->vram_size = (g_bIsChihiro || g_bIsDebug) ? CONTIGUOUS_MEMORY_CHIHIRO_SIZE : CONTIGUOUS_MEMORY_XBOX_SIZE;
|
||||
|
||||
d->pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */
|
||||
d->pramdac.core_clock_freq = 189000000;
|
||||
d->pramdac.memory_clock_coeff = 0;
|
||||
d->pramdac.video_clock_coeff = 0x0003C20D; /* 25182Khz...? */
|
||||
|
||||
d->pfifo.puller_thread = std::thread(pfifo_puller_thread, d);
|
||||
|
||||
// Only spawn VBlank thread when LLE is enabled
|
||||
if (bLLE_GPU) {
|
||||
vblank_thread = std::thread(nv2a_vblank_thread, d);
|
||||
}
|
||||
}
|
||||
|
||||
void NV2ADevice::Reset()
|
||||
|
@ -90,41 +689,83 @@ void NV2ADevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned s
|
|||
|
||||
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
|
||||
case 0: {
|
||||
// Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU)
|
||||
const NV2ABlockInfo* block = EmuNV2A_Block(addr);
|
||||
|
||||
if (block != nullptr) {
|
||||
switch (size) {
|
||||
case sizeof(uint8_t) :
|
||||
return block->ops.read(m_nv2a_state, addr - block->offset) & 0xFF;
|
||||
case sizeof(uint16_t) :
|
||||
assert((addr & 1) == 0); // TODO : What if this fails?
|
||||
|
||||
return block->ops.read(m_nv2a_state, addr - block->offset) & 0xFFFF;
|
||||
case sizeof(uint32_t) :
|
||||
assert((addr & 3) == 0); // TODO : What if this fails?
|
||||
|
||||
return block->ops.read(m_nv2a_state, addr - block->offset);
|
||||
}
|
||||
}
|
||||
// TODO : call block handler
|
||||
return value;
|
||||
case 1:
|
||||
return 0; // TODO : access physical memory
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// TODO : access physical memory
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO : Log unexpected bar access
|
||||
EmuWarning("NV2ADevice::MMIORead: Unhandled barIndex %d, addr %08X, size %d", barIndex, addr, size);
|
||||
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
|
||||
case 0: {
|
||||
// Access NV2A regardless weither HLE is disabled or not (ignoring bLLE_GPU)
|
||||
const NV2ABlockInfo* block = EmuNV2A_Block(addr);
|
||||
|
||||
if (block != nullptr) {
|
||||
xbaddr aligned_addr;
|
||||
uint32_t aligned_value;
|
||||
int shift;
|
||||
uint32_t mask;
|
||||
|
||||
switch (size) {
|
||||
case sizeof(uint8_t) :
|
||||
aligned_addr = addr & ~3;
|
||||
aligned_value = block->ops.read(m_nv2a_state, aligned_addr - block->offset);
|
||||
shift = (addr & 3) * 8;
|
||||
mask = 0xFF << shift;
|
||||
block->ops.write(m_nv2a_state, aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift));
|
||||
return;
|
||||
case sizeof(uint16_t) :
|
||||
assert((addr & 1) == 0); // TODO : What if this fails?
|
||||
|
||||
aligned_addr = addr & ~3;
|
||||
aligned_value = block->ops.read(m_nv2a_state, aligned_addr - block->offset);
|
||||
shift = (addr & 2) * 16;
|
||||
mask = 0xFFFF << shift;
|
||||
block->ops.write(m_nv2a_state, aligned_addr - block->offset, (aligned_value & ~mask) | (value << shift));
|
||||
return;
|
||||
case sizeof(uint32_t) :
|
||||
assert((addr & 3) == 0); // TODO : What if this fails?
|
||||
|
||||
block->ops.write(m_nv2a_state, addr - block->offset, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO : call block handler
|
||||
return;
|
||||
case 1:
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// TODO : access physical memory
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO : Log unexpected bar access
|
||||
EmuWarning("NV2ADevice::MMIOWrite: Unhandled barIndex %d, addr %08X, value %08X, size %d", barIndex, addr, value, size);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2018 Luke Usher <luke.usher@outlook.com>
|
||||
// * (c) 2016-2018 Luke Usher <luke.usher@outlook.com>
|
||||
// * (c) 2018 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
|
@ -34,13 +34,597 @@
|
|||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include "Cxbx.h" // For xbaddr
|
||||
#include "devices\PCIDevice.h" // For PCIDevice
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "swizzle.h"
|
||||
#include "nv2a_int.h"
|
||||
|
||||
#define NV2A_ADDR 0xFD000000
|
||||
#define NV2A_SIZE 0x01000000
|
||||
|
||||
#define NV_PMC_SIZE 0x001000
|
||||
#define _NV_PFIFO_SIZE 0x002000 // Underscore prefix to prevent clash with NV_PFIFO_SIZE
|
||||
#define NV_PVIDEO_SIZE 0x001000
|
||||
#define NV_PTIMER_SIZE 0x001000
|
||||
#define NV_PFB_SIZE 0x001000
|
||||
#define NV_PGRAPH_SIZE 0x002000
|
||||
#define NV_PCRTC_SIZE 0x001000
|
||||
#define NV_PRAMDAC_SIZE 0x001000
|
||||
|
||||
typedef xbaddr hwaddr; // Compatibility; Cxbx uses xbaddr, xqemu and OpenXbox use hwaddr
|
||||
typedef uint32_t value_t; // Compatibility; Cxbx values are uint32_t (xqemu and OpenXbox use uint64_t)
|
||||
#define NV2A_DPRINTF(...) printf("[0x????] NV2A: " ## __VA_ARGS__) // Compatibility; TODO : Replace this by something equivalent
|
||||
#define NV2A_GL_DPRINTF EmuWarning // Compatibility; TODO : Replace this by something equivalent
|
||||
#define VSH_TOKEN_SIZE 4 // Compatibility; TODO : Move this to nv2a_vsh.h
|
||||
#define MAX(a,b) ((a)>(b) ? (a) : (b)) // Compatibility
|
||||
#define MIN(a,b) ((a)<(b) ? (a) : (b)) // Compatibility
|
||||
#undef COMPILE_OPENGL // Compatibility; define this to include all OpenGL calls
|
||||
#define HWADDR_PRIx "p" // Compatibility
|
||||
#define g_free(x) free(x) // Compatibility
|
||||
#define g_malloc(x) malloc(x) // Compatibility
|
||||
#define g_malloc0(x) calloc(1, x) // Compatibility
|
||||
#define g_realloc(x, y) realloc(x, y) // Compatibility
|
||||
|
||||
#define USE_TEXTURE_CACHE
|
||||
|
||||
// Public Domain ffs Implementation
|
||||
// See: http://snipplr.com/view/22147/stringsh-implementation/
|
||||
constexpr 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);
|
||||
}
|
||||
|
||||
// Power-of-two CASE statements
|
||||
#define CASE_1(v, step) case (v)
|
||||
#define CASE_2(v, step) CASE_1(v, step) : CASE_1(v + (step) * 1, step)
|
||||
#define CASE_4(v, step) CASE_2(v, step) : CASE_2(v + (step) * 2, step)
|
||||
#define CASE_8(v, step) CASE_4(v, step) : CASE_4(v + (step) * 4, step)
|
||||
#define CASE_16(v, step) CASE_8(v, step) : CASE_8(v + (step) * 8, step)
|
||||
#define CASE_32(v, step) CASE_16(v, step) : CASE_16(v + (step) * 16, step)
|
||||
#define CASE_64(v, step) CASE_32(v, step) : CASE_32(v + (step) * 32, step)
|
||||
#define CASE_128(v, step) CASE_64(v, step) : CASE_64(v + (step) * 64, step)
|
||||
|
||||
// Non-power-of-two CASE statements
|
||||
#define CASE_3(v, step) CASE_2(v, step) : CASE_1(v + (step) * 2, step)
|
||||
#define CASE_12(v, step) CASE_8(v, step) : CASE_4(v + (step) * 8, step)
|
||||
#define CASE_13(v, step) CASE_8(v, step) : CASE_3(v + (step) * 8, step)
|
||||
#define CASE_28(v, step) CASE_16(v, step) : CASE_12(v + (step) * 16, step)
|
||||
#define CASE_29(v, step) CASE_16(v, step) : CASE_13(v + (step) * 16, step)
|
||||
#define CASE_61(v, step) CASE_32(v, step) : CASE_29(v + (step) * 32, step)
|
||||
#define CASE_78(v, step) CASE_64(v, step) : CASE_12(v + (step) * 64, step)
|
||||
#define CASE_125(v, step) CASE_64(v, step) : CASE_61(v + (step) * 64, step)
|
||||
#define CASE_132(v, step) CASE_128(v, step) : CASE_4(v + (step) * 128, step)
|
||||
#define CASE_253(v, step) CASE_128(v, step) : CASE_125(v + (step) * 128, step)
|
||||
|
||||
#define NV2A_DEVICE(obj) \
|
||||
OBJECT_CHECK(NV2AState, (obj), "nv2a")
|
||||
|
||||
//void reg_log_read(int block, hwaddr addr, uint64_t val);
|
||||
//void reg_log_write(int block, hwaddr addr, uint64_t val);
|
||||
|
||||
enum FifoMode {
|
||||
FIFO_PIO = 0,
|
||||
FIFO_DMA = 1,
|
||||
};
|
||||
|
||||
enum FIFOEngine {
|
||||
ENGINE_SOFTWARE = 0,
|
||||
ENGINE_GRAPHICS = 1,
|
||||
ENGINE_DVD = 2,
|
||||
};
|
||||
|
||||
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 PGRAPHState {
|
||||
std::mutex pgraph_mutex;
|
||||
std::unique_lock<std::mutex> pgraph_lock;
|
||||
|
||||
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_cond; // Was 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
|
||||
} PGRAPHState;
|
||||
|
||||
|
||||
typedef struct CacheEntry {
|
||||
//QSIMPLEQ_ENTRY(CacheEntry) entry;
|
||||
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 cache_lock;
|
||||
std::condition_variable cache_cond;
|
||||
std::queue<CacheEntry*> cache;
|
||||
std::queue<CacheEntry*> working_cache;
|
||||
} Cache1State;
|
||||
|
||||
typedef struct ChannelControl {
|
||||
xbaddr dma_put;
|
||||
xbaddr dma_get;
|
||||
uint32_t ref;
|
||||
} ChannelControl;
|
||||
|
||||
typedef struct NV2AState {
|
||||
// PCIDevice dev;
|
||||
// qemu_irq irq;
|
||||
bool exiting;
|
||||
|
||||
// VGACommonState vga;
|
||||
// GraphicHwOps hw_ops;
|
||||
// QEMUTimer *vblank_timer;
|
||||
|
||||
// MemoryRegion *vram;
|
||||
// MemoryRegion vram_pci;
|
||||
uint8_t *vram_ptr;
|
||||
size_t vram_size;
|
||||
// MemoryRegion ramin;
|
||||
struct {
|
||||
uint8_t *ramin_ptr;
|
||||
size_t ramin_size;
|
||||
} pramin;
|
||||
|
||||
// MemoryRegion mmio;
|
||||
// MemoryRegion block_mmio[NV_NUM_BLOCKS];
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
uint32_t regs[NV_PMC_SIZE]; // Not in xqemu/openxbox? TODO : union
|
||||
} pmc;
|
||||
|
||||
struct {
|
||||
std::thread puller_thread;
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
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]; // Not in xqemu/openxbox? TODO : union
|
||||
} ptimer;
|
||||
|
||||
struct {
|
||||
uint32_t regs[NV_PFB_SIZE]; // TODO : union
|
||||
} pfb;
|
||||
|
||||
struct PGRAPHState pgraph;
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
hwaddr start;
|
||||
uint32_t regs[NV_PCRTC_SIZE]; // Not in xqemu/openxbox? 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]; // Not in xqemu/openxbox? TODO : union
|
||||
} pramdac;
|
||||
|
||||
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; // Not in xqemu/openxbox?
|
||||
|
||||
std::mutex io_lock;
|
||||
//SDL_Window *sdl_window;
|
||||
|
||||
} NV2AState;
|
||||
|
||||
typedef value_t(*read_func)(NV2AState *d, hwaddr addr); //, unsigned int size);
|
||||
typedef void(*write_func)(NV2AState *d, hwaddr addr, value_t val); //, unsigned int size);
|
||||
|
||||
typedef struct {
|
||||
read_func read;
|
||||
write_func write;
|
||||
} MemoryRegionOps;
|
||||
|
||||
typedef struct NV2ABlockInfo {
|
||||
const char* name;
|
||||
hwaddr offset;
|
||||
uint64_t size;
|
||||
MemoryRegionOps ops;
|
||||
} NV2ABlockInfo;
|
||||
|
||||
#if 0
|
||||
// Valid after PCI init :
|
||||
#define NV20_REG_BASE_KERNEL 0xFD000000
|
||||
|
||||
typedef volatile DWORD *PPUSH;
|
||||
|
||||
typedef struct {
|
||||
DWORD Ignored[0x10];
|
||||
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;
|
||||
|
||||
#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);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CxbxReserveNV2AMemory(NV2AState *d);
|
||||
|
||||
void InitOpenGLContext();
|
||||
|
||||
class NV2ADevice : public PCIDevice {
|
||||
public:
|
||||
// constructor
|
||||
NV2ADevice();
|
||||
// destructor
|
||||
~NV2ADevice();
|
||||
|
||||
// PCI Device functions
|
||||
void Init();
|
||||
void Reset();
|
||||
|
@ -49,4 +633,6 @@ public:
|
|||
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);
|
||||
private:
|
||||
NV2AState *m_nv2a_state;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* QEMU texture swizzling routines
|
||||
*
|
||||
* Copyright (c) 2015 Jannik Vogel
|
||||
* Copyright (c) 2013 espes
|
||||
* Copyright (c) 2007-2010 The Nouveau Project.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "swizzle.h"
|
||||
|
||||
/* This should be pretty straightforward.
|
||||
* It creates a bit pattern like ..zyxzyxzyx from ..xxx, ..yyy and ..zzz
|
||||
* If there are no bits left from any component it will pack the other masks
|
||||
* more tighly (Example: zzxzxzyx = Fewer x than z and even fewer y)
|
||||
*/
|
||||
static void generate_swizzle_masks(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int depth,
|
||||
uint32_t* mask_x,
|
||||
uint32_t* mask_y,
|
||||
uint32_t* mask_z)
|
||||
{
|
||||
uint32_t x = 0, y = 0, z = 0;
|
||||
uint32_t bit = 1;
|
||||
uint32_t mask_bit = 1;
|
||||
bool done;
|
||||
do {
|
||||
done = true;
|
||||
if (bit < width) { x |= mask_bit; mask_bit <<= 1; done = false; }
|
||||
if (bit < height) { y |= mask_bit; mask_bit <<= 1; done = false; }
|
||||
if (bit < depth) { z |= mask_bit; mask_bit <<= 1; done = false; }
|
||||
bit <<= 1;
|
||||
} while(!done);
|
||||
assert(((x ^ y) ^ z) == (mask_bit - 1));
|
||||
*mask_x = x;
|
||||
*mask_y = y;
|
||||
*mask_z = z;
|
||||
}
|
||||
|
||||
/* This fills a pattern with a value if your value has bits abcd and your
|
||||
* pattern is 11010100100 this will return: 0a0b0c00d00
|
||||
*/
|
||||
static uint32_t fill_pattern(uint32_t pattern, uint32_t value)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
uint32_t bit = 1;
|
||||
while(value) {
|
||||
if (pattern & bit) {
|
||||
/* Copy bit to result */
|
||||
result |= value & 1 ? bit : 0;
|
||||
value >>= 1;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned int get_swizzled_offset(
|
||||
unsigned int x, unsigned int y, unsigned int z,
|
||||
uint32_t mask_x, uint32_t mask_y, uint32_t mask_z,
|
||||
unsigned int bytes_per_pixel)
|
||||
{
|
||||
return bytes_per_pixel * (fill_pattern(mask_x, x)
|
||||
| fill_pattern(mask_y, y)
|
||||
| fill_pattern(mask_z, z));
|
||||
}
|
||||
|
||||
void swizzle_box(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int depth,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int row_pitch,
|
||||
unsigned int slice_pitch,
|
||||
unsigned int bytes_per_pixel)
|
||||
{
|
||||
uint32_t mask_x, mask_y, mask_z;
|
||||
generate_swizzle_masks(width, height, depth, &mask_x, &mask_y, &mask_z);
|
||||
|
||||
unsigned int x, y, z;
|
||||
for (z = 0; z < depth; z++) {
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
const uint8_t *src = src_buf
|
||||
+ y * row_pitch + x * bytes_per_pixel;
|
||||
uint8_t *dst = dst_buf + get_swizzled_offset(x, y, 0,
|
||||
mask_x, mask_y, 0,
|
||||
bytes_per_pixel);
|
||||
memcpy(dst, src, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
src_buf += slice_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void unswizzle_box(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int depth,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int row_pitch,
|
||||
unsigned int slice_pitch,
|
||||
unsigned int bytes_per_pixel)
|
||||
{
|
||||
uint32_t mask_x, mask_y, mask_z;
|
||||
generate_swizzle_masks(width, height, depth, &mask_x, &mask_y, &mask_z);
|
||||
|
||||
unsigned int x, y, z;
|
||||
for (z = 0; z < depth; z++) {
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
const uint8_t *src = src_buf
|
||||
+ get_swizzled_offset(x, y, z, mask_x, mask_y, mask_z,
|
||||
bytes_per_pixel);
|
||||
uint8_t *dst = dst_buf + y * row_pitch + x * bytes_per_pixel;
|
||||
memcpy(dst, src, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
dst_buf += slice_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void unswizzle_rect(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int pitch,
|
||||
unsigned int bytes_per_pixel)
|
||||
{
|
||||
unswizzle_box(src_buf, width, height, 1, dst_buf, pitch, 0, bytes_per_pixel);
|
||||
}
|
||||
|
||||
void swizzle_rect(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int pitch,
|
||||
unsigned int bytes_per_pixel)
|
||||
{
|
||||
swizzle_box(src_buf, width, height, 1, dst_buf, pitch, 0, bytes_per_pixel);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* QEMU texture swizzling routines
|
||||
*
|
||||
* Copyright (c) 2015 Jannik Vogel
|
||||
* Copyright (c) 2013 espes
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef HW_XBOX_SWIZZLE_H
|
||||
#define HW_XBOX_SWIZZLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void swizzle_box(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int depth,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int row_pitch,
|
||||
unsigned int slice_pitch,
|
||||
unsigned int bytes_per_pixel);
|
||||
|
||||
void unswizzle_box(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int depth,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int row_pitch,
|
||||
unsigned int slice_pitch,
|
||||
unsigned int bytes_per_pixel);
|
||||
|
||||
void unswizzle_rect(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int pitch,
|
||||
unsigned int bytes_per_pixel);
|
||||
|
||||
void swizzle_rect(
|
||||
const uint8_t *src_buf,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
uint8_t *dst_buf,
|
||||
unsigned int pitch,
|
||||
unsigned int bytes_per_pixel);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue