From b3a183dffefc1cb1701ee2a8a2cbe0080774aced Mon Sep 17 00:00:00 2001 From: Soren Jorvang Date: Sat, 29 Jan 2011 14:06:48 +0000 Subject: Core and DSPCore now have mutual dependencies, which breaks the assumption on the part of many linkers that static libraries make up a DAG, so merge libdspcore into libcore. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6967 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/CMakeLists.txt | 1 - Source/Core/Core/CMakeLists.txt | 35 +- Source/Core/Core/Core.vcproj | 224 ++- Source/Core/Core/Core.vcxproj | 52 +- Source/Core/Core/Src/DSP/DSPAccelerator.cpp | 176 ++ Source/Core/Core/Src/DSP/DSPAccelerator.h | 26 + Source/Core/Core/Src/DSP/DSPAnalyzer.cpp | 173 ++ Source/Core/Core/Src/DSP/DSPAnalyzer.h | 52 + Source/Core/Core/Src/DSP/DSPBreakpoints.h | 63 + Source/Core/Core/Src/DSP/DSPCodeUtil.cpp | 233 +++ Source/Core/Core/Src/DSP/DSPCodeUtil.h | 43 + Source/Core/Core/Src/DSP/DSPCommon.h | 8 + Source/Core/Core/Src/DSP/DSPCore.cpp | 443 +++++ Source/Core/Core/Src/DSP/DSPCore.h | 306 ++++ Source/Core/Core/Src/DSP/DSPEmitter.cpp | 446 +++++ Source/Core/Core/Src/DSP/DSPEmitter.h | 303 ++++ Source/Core/Core/Src/DSP/DSPHWInterface.cpp | 361 ++++ Source/Core/Core/Src/DSP/DSPHWInterface.h | 47 + Source/Core/Core/Src/DSP/DSPHost.h | 34 + Source/Core/Core/Src/DSP/DSPIntCCUtil.cpp | 197 +++ Source/Core/Core/Src/DSP/DSPIntCCUtil.h | 55 + Source/Core/Core/Src/DSP/DSPIntExtOps.cpp | 526 ++++++ Source/Core/Core/Src/DSP/DSPIntExtOps.h | 64 + Source/Core/Core/Src/DSP/DSPIntUtil.h | 386 ++++ Source/Core/Core/Src/DSP/DSPInterpreter.cpp | 261 +++ Source/Core/Core/Src/DSP/DSPInterpreter.h | 170 ++ Source/Core/Core/Src/DSP/DSPMemoryMap.cpp | 83 + Source/Core/Core/Src/DSP/DSPMemoryMap.h | 55 + Source/Core/Core/Src/DSP/DSPStacks.cpp | 58 + Source/Core/Core/Src/DSP/DSPStacks.h | 34 + Source/Core/Core/Src/DSP/DSPTables.cpp | 568 ++++++ Source/Core/Core/Src/DSP/DSPTables.h | 158 ++ Source/Core/Core/Src/DSP/DspIntArithmetic.cpp | 1152 ++++++++++++ Source/Core/Core/Src/DSP/DspIntBranch.cpp | 275 +++ Source/Core/Core/Src/DSP/DspIntLoadStore.cpp | 269 +++ Source/Core/Core/Src/DSP/DspIntMisc.cpp | 189 ++ Source/Core/Core/Src/DSP/DspIntMultiplier.cpp | 609 +++++++ Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp | 1862 ++++++++++++++++++++ Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp | 606 +++++++ Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp | 323 ++++ Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp | 639 +++++++ Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp | 294 ++++ Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp | 468 +++++ Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp | 885 ++++++++++ Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp | 540 ++++++ Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.h | 169 ++ Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp | 596 +++++++ Source/Core/Core/Src/DSP/Jit/DSPJitUtil.h | 21 + Source/Core/Core/Src/DSP/LabelMap.cpp | 85 + Source/Core/Core/Src/DSP/LabelMap.h | 55 + Source/Core/Core/Src/DSP/assemble.cpp | 1020 +++++++++++ Source/Core/Core/Src/DSP/assemble.h | 139 ++ Source/Core/Core/Src/DSP/disassemble.cpp | 360 ++++ Source/Core/Core/Src/DSP/disassemble.h | 87 + .../Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp | 6 +- Source/Core/Core/Src/HW/DSPLLE/DSPHost.cpp | 2 +- Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp | 10 +- Source/Core/Core/Src/HW/DSPLLE/DSPLLEGlobals.cpp | 2 +- Source/Core/Core/Src/HW/DSPLLE/DSPLLETools.cpp | 8 +- Source/Core/Core/Src/HW/DSPLLE/DSPSymbols.cpp | 4 +- Source/Core/Core/Src/SConscript | 35 +- Source/Core/DSPCore/CMakeLists.txt | 35 - Source/Core/DSPCore/DSPCore.vcproj | 621 ------- Source/Core/DSPCore/DSPCore.vcxproj | 239 --- Source/Core/DSPCore/Src/DSPAccelerator.cpp | 176 -- Source/Core/DSPCore/Src/DSPAccelerator.h | 26 - Source/Core/DSPCore/Src/DSPAnalyzer.cpp | 173 -- Source/Core/DSPCore/Src/DSPAnalyzer.h | 52 - Source/Core/DSPCore/Src/DSPBreakpoints.h | 63 - Source/Core/DSPCore/Src/DSPCodeUtil.cpp | 233 --- Source/Core/DSPCore/Src/DSPCodeUtil.h | 43 - Source/Core/DSPCore/Src/DSPCommon.h | 8 - Source/Core/DSPCore/Src/DSPCore.cpp | 443 ----- Source/Core/DSPCore/Src/DSPCore.h | 306 ---- Source/Core/DSPCore/Src/DSPEmitter.cpp | 446 ----- Source/Core/DSPCore/Src/DSPEmitter.h | 303 ---- Source/Core/DSPCore/Src/DSPHWInterface.cpp | 361 ---- Source/Core/DSPCore/Src/DSPHWInterface.h | 47 - Source/Core/DSPCore/Src/DSPHost.h | 34 - Source/Core/DSPCore/Src/DSPIntCCUtil.cpp | 197 --- Source/Core/DSPCore/Src/DSPIntCCUtil.h | 55 - Source/Core/DSPCore/Src/DSPIntExtOps.cpp | 526 ------ Source/Core/DSPCore/Src/DSPIntExtOps.h | 64 - Source/Core/DSPCore/Src/DSPIntUtil.h | 386 ---- Source/Core/DSPCore/Src/DSPInterpreter.cpp | 261 --- Source/Core/DSPCore/Src/DSPInterpreter.h | 170 -- Source/Core/DSPCore/Src/DSPMemoryMap.cpp | 83 - Source/Core/DSPCore/Src/DSPMemoryMap.h | 55 - Source/Core/DSPCore/Src/DSPStacks.cpp | 58 - Source/Core/DSPCore/Src/DSPStacks.h | 34 - Source/Core/DSPCore/Src/DSPTables.cpp | 568 ------ Source/Core/DSPCore/Src/DSPTables.h | 158 -- Source/Core/DSPCore/Src/DspIntArithmetic.cpp | 1152 ------------ Source/Core/DSPCore/Src/DspIntBranch.cpp | 275 --- Source/Core/DSPCore/Src/DspIntLoadStore.cpp | 269 --- Source/Core/DSPCore/Src/DspIntMisc.cpp | 189 -- Source/Core/DSPCore/Src/DspIntMultiplier.cpp | 609 ------- Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp | 1862 -------------------- Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp | 606 ------- Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp | 323 ---- Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp | 639 ------- Source/Core/DSPCore/Src/Jit/DSPJitLoadStore.cpp | 294 ---- Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp | 468 ----- Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp | 885 ---------- Source/Core/DSPCore/Src/Jit/DSPJitRegCache.cpp | 540 ------ Source/Core/DSPCore/Src/Jit/DSPJitRegCache.h | 169 -- Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp | 596 ------- Source/Core/DSPCore/Src/Jit/DSPJitUtil.h | 21 - Source/Core/DSPCore/Src/LabelMap.cpp | 85 - Source/Core/DSPCore/Src/LabelMap.h | 55 - Source/Core/DSPCore/Src/SConscript | 37 - Source/Core/DSPCore/Src/assemble.cpp | 1020 ----------- Source/Core/DSPCore/Src/assemble.h | 139 -- Source/Core/DSPCore/Src/disassemble.cpp | 360 ---- Source/Core/DSPCore/Src/disassemble.h | 87 - Source/Core/DebuggerWX/DebuggerWX.vcproj | 12 +- Source/Core/DebuggerWX/Src/DSPDebugWindow.h | 6 +- Source/Core/DolphinWX/Src/SConscript | 14 +- 118 files changed, 16340 insertions(+), 16947 deletions(-) create mode 100644 Source/Core/Core/Src/DSP/DSPAccelerator.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPAccelerator.h create mode 100644 Source/Core/Core/Src/DSP/DSPAnalyzer.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPAnalyzer.h create mode 100644 Source/Core/Core/Src/DSP/DSPBreakpoints.h create mode 100644 Source/Core/Core/Src/DSP/DSPCodeUtil.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPCodeUtil.h create mode 100644 Source/Core/Core/Src/DSP/DSPCommon.h create mode 100644 Source/Core/Core/Src/DSP/DSPCore.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPCore.h create mode 100644 Source/Core/Core/Src/DSP/DSPEmitter.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPEmitter.h create mode 100644 Source/Core/Core/Src/DSP/DSPHWInterface.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPHWInterface.h create mode 100644 Source/Core/Core/Src/DSP/DSPHost.h create mode 100644 Source/Core/Core/Src/DSP/DSPIntCCUtil.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPIntCCUtil.h create mode 100644 Source/Core/Core/Src/DSP/DSPIntExtOps.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPIntExtOps.h create mode 100644 Source/Core/Core/Src/DSP/DSPIntUtil.h create mode 100644 Source/Core/Core/Src/DSP/DSPInterpreter.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPInterpreter.h create mode 100644 Source/Core/Core/Src/DSP/DSPMemoryMap.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPMemoryMap.h create mode 100644 Source/Core/Core/Src/DSP/DSPStacks.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPStacks.h create mode 100644 Source/Core/Core/Src/DSP/DSPTables.cpp create mode 100644 Source/Core/Core/Src/DSP/DSPTables.h create mode 100644 Source/Core/Core/Src/DSP/DspIntArithmetic.cpp create mode 100644 Source/Core/Core/Src/DSP/DspIntBranch.cpp create mode 100644 Source/Core/Core/Src/DSP/DspIntLoadStore.cpp create mode 100644 Source/Core/Core/Src/DSP/DspIntMisc.cpp create mode 100644 Source/Core/Core/Src/DSP/DspIntMultiplier.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.h create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp create mode 100644 Source/Core/Core/Src/DSP/Jit/DSPJitUtil.h create mode 100644 Source/Core/Core/Src/DSP/LabelMap.cpp create mode 100644 Source/Core/Core/Src/DSP/LabelMap.h create mode 100644 Source/Core/Core/Src/DSP/assemble.cpp create mode 100644 Source/Core/Core/Src/DSP/assemble.h create mode 100644 Source/Core/Core/Src/DSP/disassemble.cpp create mode 100644 Source/Core/Core/Src/DSP/disassemble.h delete mode 100644 Source/Core/DSPCore/CMakeLists.txt delete mode 100644 Source/Core/DSPCore/DSPCore.vcproj delete mode 100644 Source/Core/DSPCore/DSPCore.vcxproj delete mode 100644 Source/Core/DSPCore/Src/DSPAccelerator.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPAccelerator.h delete mode 100644 Source/Core/DSPCore/Src/DSPAnalyzer.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPAnalyzer.h delete mode 100644 Source/Core/DSPCore/Src/DSPBreakpoints.h delete mode 100644 Source/Core/DSPCore/Src/DSPCodeUtil.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPCodeUtil.h delete mode 100644 Source/Core/DSPCore/Src/DSPCommon.h delete mode 100644 Source/Core/DSPCore/Src/DSPCore.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPCore.h delete mode 100644 Source/Core/DSPCore/Src/DSPEmitter.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPEmitter.h delete mode 100644 Source/Core/DSPCore/Src/DSPHWInterface.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPHWInterface.h delete mode 100644 Source/Core/DSPCore/Src/DSPHost.h delete mode 100644 Source/Core/DSPCore/Src/DSPIntCCUtil.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPIntCCUtil.h delete mode 100644 Source/Core/DSPCore/Src/DSPIntExtOps.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPIntExtOps.h delete mode 100644 Source/Core/DSPCore/Src/DSPIntUtil.h delete mode 100644 Source/Core/DSPCore/Src/DSPInterpreter.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPInterpreter.h delete mode 100644 Source/Core/DSPCore/Src/DSPMemoryMap.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPMemoryMap.h delete mode 100644 Source/Core/DSPCore/Src/DSPStacks.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPStacks.h delete mode 100644 Source/Core/DSPCore/Src/DSPTables.cpp delete mode 100644 Source/Core/DSPCore/Src/DSPTables.h delete mode 100644 Source/Core/DSPCore/Src/DspIntArithmetic.cpp delete mode 100644 Source/Core/DSPCore/Src/DspIntBranch.cpp delete mode 100644 Source/Core/DSPCore/Src/DspIntLoadStore.cpp delete mode 100644 Source/Core/DSPCore/Src/DspIntMisc.cpp delete mode 100644 Source/Core/DSPCore/Src/DspIntMultiplier.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitLoadStore.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitRegCache.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitRegCache.h delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp delete mode 100644 Source/Core/DSPCore/Src/Jit/DSPJitUtil.h delete mode 100644 Source/Core/DSPCore/Src/LabelMap.cpp delete mode 100644 Source/Core/DSPCore/Src/LabelMap.h delete mode 100644 Source/Core/DSPCore/Src/SConscript delete mode 100644 Source/Core/DSPCore/Src/assemble.cpp delete mode 100644 Source/Core/DSPCore/Src/assemble.h delete mode 100644 Source/Core/DSPCore/Src/disassemble.cpp delete mode 100644 Source/Core/DSPCore/Src/disassemble.h (limited to 'Source/Core') diff --git a/Source/Core/CMakeLists.txt b/Source/Core/CMakeLists.txt index 640d653f24..022eb4c524 100644 --- a/Source/Core/CMakeLists.txt +++ b/Source/Core/CMakeLists.txt @@ -10,6 +10,5 @@ endif() add_subdirectory(DiscIO) add_subdirectory(DolphinWX) -add_subdirectory(DSPCore) add_subdirectory(InputCommon) add_subdirectory(VideoCommon) diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 582d69b799..ff9326c482 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -27,6 +27,35 @@ set(SRCS Src/ActionReplay.cpp Src/Debugger/Debugger_SymbolMap.cpp Src/Debugger/Dump.cpp Src/Debugger/PPCDebugInterface.cpp + Src/DSP/assemble.cpp + Src/DSP/disassemble.cpp + Src/DSP/DSPAccelerator.cpp + Src/DSP/DSPIntCCUtil.cpp + Src/DSP/DSPIntExtOps.cpp + Src/DSP/DSPHWInterface.cpp + Src/DSP/DSPMemoryMap.cpp + Src/DSP/DSPStacks.cpp + Src/DSP/DSPAnalyzer.cpp + Src/DSP/DspIntArithmetic.cpp + Src/DSP/DspIntBranch.cpp + Src/DSP/DspIntLoadStore.cpp + Src/DSP/DspIntMisc.cpp + Src/DSP/DspIntMultiplier.cpp + Src/DSP/DSPEmitter.cpp + Src/DSP/DSPCodeUtil.cpp + Src/DSP/LabelMap.cpp + Src/DSP/DSPInterpreter.cpp + Src/DSP/DSPCore.cpp + Src/DSP/DSPTables.cpp + Src/DSP/Jit/DSPJitRegCache.cpp + Src/DSP/Jit/DSPJitExtOps.cpp + Src/DSP/Jit/DSPJitBranch.cpp + Src/DSP/Jit/DSPJitCCUtil.cpp + Src/DSP/Jit/DSPJitArithmetic.cpp + Src/DSP/Jit/DSPJitLoadStore.cpp + Src/DSP/Jit/DSPJitMultiplier.cpp + Src/DSP/Jit/DSPJitUtil.cpp + Src/DSP/Jit/DSPJitMisc.cpp Src/HLE/HLE.cpp Src/HLE/HLE_Misc.cpp Src/HLE/HLE_OS.cpp @@ -154,7 +183,7 @@ set(SRCS Src/ActionReplay.cpp Src/PowerPC/JitCommon/JitCache.cpp Src/PowerPC/JitCommon/Jit_Util.cpp) -set(LIBS bdisasm inputcommon dspcore lua sfml-network) +set(LIBS bdisasm inputcommon core lua sfml-network) if(WIN32) set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp @@ -181,4 +210,6 @@ endif(OPROFILE_FOUND) add_library(core STATIC ${SRCS}) target_link_libraries(core ${LIBS}) - +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + add_definitions(-fPIC) +endif() diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index e0ad0dca46..23b5d8b72e 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -45,7 +45,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 52de75e2e6..1f37d7e65d 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -275,6 +275,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -421,6 +450,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -542,4 +592,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/Src/DSP/DSPAccelerator.cpp b/Source/Core/Core/Src/DSP/DSPAccelerator.cpp new file mode 100644 index 0000000000..a45ab15e9d --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPAccelerator.cpp @@ -0,0 +1,176 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" + +#include "DSPCore.h" +#include "DSPHost.h" +#include "DSPHWInterface.h" +#include "DSPInterpreter.h" + +// The hardware adpcm decoder :) +static s16 ADPCM_Step(u32& _rSamplePos) +{ + const s16 *pCoefTable = (const s16 *)&g_dsp.ifx_regs[DSP_COEF_A1_0]; + + if (((_rSamplePos) & 15) == 0) + { + g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost_ReadHostMemory((_rSamplePos & ~15) >> 1); + _rSamplePos += 2; + } + + int scale = 1 << (g_dsp.ifx_regs[DSP_PRED_SCALE] & 0xF); + int coef_idx = (g_dsp.ifx_regs[DSP_PRED_SCALE] >> 4) & 0x7; + + s32 coef1 = pCoefTable[coef_idx * 2 + 0]; + s32 coef2 = pCoefTable[coef_idx * 2 + 1]; + + int temp = (_rSamplePos & 1) ? + (DSPHost_ReadHostMemory(_rSamplePos >> 1) & 0xF) : + (DSPHost_ReadHostMemory(_rSamplePos >> 1) >> 4); + + if (temp >= 8) + temp -= 16; + + // 0x400 = 0.5 in 11-bit fixed point + int val = (scale * temp) + ((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11); + + // Clamp values. + if (val > 0x7FFF) + val = 0x7FFF; + else if (val < -0x7FFF) + val = -0x7FFF; + + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; + + _rSamplePos++; + + // The advanced interpolation (linear, polyphase,...) is done by the UCode, + // so we don't need to bother with it here. + return val; +} + +u16 dsp_read_aram_d3() +{ + // Zelda ucode reads ARAM through 0xffd3. + const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + u16 val = 0; + + switch (g_dsp.ifx_regs[DSP_FORMAT]) { + case 0x5: // u8 reads + val = DSPHost_ReadHostMemory(Address); + Address++; + break; + case 0x6: // u16 reads + val = (DSPHost_ReadHostMemory(Address*2) << 8) | DSPHost_ReadHostMemory(Address*2 + 1); + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_read_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + break; + } + + if (Address >= EndAddress) + { + // Set address back to start address. (never seen this here!) + Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; + } + + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + return val; +} + +void dsp_write_aram_d3(u16 value) +{ + // Zelda ucode writes a bunch of zeros to ARAM through d3 during + // initialization. Don't know if it ever does it later, too. + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + + switch (g_dsp.ifx_regs[DSP_FORMAT]) { + case 0xA: // u16 writes + DSPHost_WriteHostMemory(value >> 8, Address*2); + DSPHost_WriteHostMemory(value & 0xFF, Address*2 + 1); + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_write_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + break; + } + + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; +} + +u16 dsp_read_accelerator() +{ + const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + u16 val; + + // let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda + // ucode seems to indicate that the bottom two bits specify the "read size" + // and the address multiplier. The bits above that may be things like sign + // extention and do/do not use ADPCM. It also remains to be figured out + // whether there's a difference between the usual accelerator "read + // address" and 0xd3. + switch (g_dsp.ifx_regs[DSP_FORMAT]) + { + case 0x00: // ADPCM audio + val = ADPCM_Step(Address); + break; + case 0x0A: // 16-bit PCM audio + val = (DSPHost_ReadHostMemory(Address*2) << 8) | DSPHost_ReadHostMemory(Address*2 + 1); + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; + Address++; + break; + case 0x19: // 8-bit PCM audio + val = DSPHost_ReadHostMemory(Address) << 8; + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_read_accelerator() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + Address++; + val = 0; + break; + } + + // TODO: Take GAIN into account + // adpcm = 0, pcm8 = 0x100, pcm16 = 0x800 + // games using pcm8 : Phoenix Wright Ace Attorney (Wiiware), Megaman 9-10 (WiiWare) + // games using pcm16: gc sega games, ... + + // Check for loop. + // Somehow, YN1 and YN2 must be initialized with their "loop" values, + // so yeah, it seems likely that we should raise an exception to let + // the DSP program do that, at least if DSP_FORMAT == 0x0A. + if (Address >= EndAddress) + { + // Set address back to start address. + Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; + DSPCore_SetException(EXP_ACCOV); + } + + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + return val; +} diff --git a/Source/Core/Core/Src/DSP/DSPAccelerator.h b/Source/Core/Core/Src/DSP/DSPAccelerator.h new file mode 100644 index 0000000000..a64516a036 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPAccelerator.h @@ -0,0 +1,26 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSP_ACCELERATOR_H +#define _DSP_ACCELERATOR_H + +u16 dsp_read_accelerator(); + +u16 dsp_read_aram_d3(); +void dsp_write_aram_d3(u16 value); + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPAnalyzer.cpp b/Source/Core/Core/Src/DSP/DSPAnalyzer.cpp new file mode 100644 index 0000000000..8f6b0d4e35 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPAnalyzer.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DSPAnalyzer.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "DSPMemoryMap.h" + +namespace DSPAnalyzer { + +// Holds data about all instructions in RAM. +u8 code_flags[ISPACE]; + +// Good candidates for idle skipping is mail wait loops. If we're time slicing +// between the main CPU and the DSP, if the DSP runs into one of these, it might +// as well give up its time slice immediately, after executing once. + +// Max signature length is 6. A 0 in a signature is ignored. +#define NUM_IDLE_SIGS 8 +#define MAX_IDLE_SIG_SIZE 6 + +// 0xFFFF means ignore. +const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = +{ + // From AX: + { 0x26fc, // LRS $30, @DMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x27fc, // LRS $31, @DMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0 }, // RET + { 0x26fe, // LRS $30, @CMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + { 0x27fe, // LRS $31, @CMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0 }, // RET + { 0x26fc, // lrs $AC0.M, @DMBH + 0x02a0, 0x8000, // andf $AC0.M, #0x8000 + 0x029c, 0xFFFF, // jlnz 0x???? + 0, 0 }, + { 0x27fc, // lrs $AC1.M, @DMBH + 0x03a0, 0x8000, // andf $AC1.M, #0x8000 + 0x029c, 0xFFFF, // jlnz 0x???? + 0, 0 }, + // From Zelda: + { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH + 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x05cf + 0 }, + // From Zelda - experimental + { 0x00da, 0x0352, // lr $AX0.H, @0x0352 + 0x8600, // tstaxh $AX0.H + 0x0295, 0xFFFF, // jz 0x???? + 0, 0 } +}; + +void Reset() +{ + memset(code_flags, 0, sizeof(code_flags)); +} + +void AnalyzeRange(int start_addr, int end_addr) +{ + // First we run an extremely simplified version of a disassembler to find + // where all instructions start. + + // This may not be 100% accurate in case of jump tables! + // It could get desynced, which would be bad. We'll see if that's an issue. + u16 last_arithmetic = 0; + for (int addr = start_addr; addr < end_addr;) + { + UDSPInstruction inst = dsp_imem_read(addr); + const DSPOPCTemplate *opcode = GetOpTemplate(inst); + if (!opcode) + { + addr++; + continue; + } + code_flags[addr] |= CODE_START_OF_INST; + // Look for loops. + if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) + { + // BLOOP, BLOOPI + u16 loop_end = dsp_imem_read(addr + 1); + code_flags[addr] |= CODE_LOOP_START; + code_flags[loop_end] |= CODE_LOOP_END; + } + else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) + { + // LOOP, LOOPI + code_flags[addr] |= CODE_LOOP_START; + code_flags[addr + 1] |= CODE_LOOP_END; + } + + // Mark the last arithmetic/multiplier instruction before a branch. + // We must update the SR reg at these instructions + if (opcode->updates_sr) + { + last_arithmetic = addr; + } + + if (opcode->branch && !opcode->uncond_branch) + { + code_flags[last_arithmetic] |= CODE_UPDATE_SR; + } + + // If an instruction potentially raises exceptions, mark the following + // instruction as needing to check for exceptions + if (opcode->opcode == 0x00c0 || + opcode->opcode == 0x1800 || + opcode->opcode == 0x1880 || + opcode->opcode == 0x1900 || + opcode->opcode == 0x1980 || + opcode->opcode == 0x2000 || + opcode->extended + ) + code_flags[addr + opcode->size] |= CODE_CHECK_INT; + + addr += opcode->size; + } + + // Next, we'll scan for potential idle skips. + for (int s = 0; s < NUM_IDLE_SIGS; s++) + { + for (int addr = start_addr; addr < end_addr; addr++) + { + bool found = false; + for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) + { + if (idle_skip_sigs[s][i] == 0) + found = true; + if (idle_skip_sigs[s][i] == 0xFFFF) + continue; + if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) + break; + } + if (found) + { + INFO_LOG(DSPLLE, "Idle skip location found at %02x (sigNum:%d)", addr, s+1); + code_flags[addr] |= CODE_IDLE_SKIP; + } + } + } + INFO_LOG(DSPLLE, "Finished analysis."); +} + +void Analyze() +{ + Reset(); + AnalyzeRange(0x0000, 0x1000); // IRAM + AnalyzeRange(0x8000, 0x9000); // IROM +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DSPAnalyzer.h b/Source/Core/Core/Src/DSP/DSPAnalyzer.h new file mode 100644 index 0000000000..9c05dae708 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPAnalyzer.h @@ -0,0 +1,52 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Basic code analysis. + +#include "DSPInterpreter.h" + +namespace DSPAnalyzer { + +#define ISPACE 65536 + +// Useful things to detect: +// * Loop endpoints - so that we can avoid checking for loops every cycle. + +enum +{ + CODE_START_OF_INST = 1, + CODE_IDLE_SKIP = 2, + CODE_LOOP_START = 4, + CODE_LOOP_END = 8, + CODE_UPDATE_SR = 16, + CODE_CHECK_INT = 32, +}; + +// Easy to query array covering the whole of instruction memory. +// Just index by address. +// This one will be helpful for debuggers and jits. +extern u8 code_flags[ISPACE]; + +// This one should be called every time IRAM changes - which is basically +// every time that a new ucode gets uploaded, and never else. At that point, +// we can do as much static analysis as we want - but we should always throw +// all old analysis away. Luckily the entire address space is only 64K code +// words and the actual code space 8K instructions in total, so we can do +// some pretty expensive analysis if necessary. +void Analyze(); + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DSPBreakpoints.h b/Source/Core/Core/Src/DSP/DSPBreakpoints.h new file mode 100644 index 0000000000..b366e760a7 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPBreakpoints.h @@ -0,0 +1,63 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSP_BREAKPOINTS +#define _DSP_BREAKPOINTS + +#include "Common.h" + +// super fast breakpoints for a limited range. +// To be used interchangably with the BreakPoints class. +class DSPBreakpoints +{ +public: + DSPBreakpoints() {Clear();} + // is address breakpoint + bool IsAddressBreakPoint(u32 addr) { + return b[addr] != 0; + } + + // AddBreakPoint + bool Add(u32 addr, bool temp=false) { + bool was_one = b[addr] != 0; + if (!was_one) { + b[addr] = temp ? 2 : 1; + return true; + } else { + return false; + } + } + // Remove Breakpoint + bool Remove(u32 addr) { + bool was_one = b[addr] != 0; + b[addr] = 0; + return was_one; + } + void Clear() { + for (int i = 0; i < 65536; i++) + b[i] = 0; + } + + void DeleteByAddress(u32 addr) { + b[addr] = 0; + } + +private: + u8 b[65536]; +}; + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPCodeUtil.cpp b/Source/Core/Core/Src/DSP/DSPCodeUtil.cpp new file mode 100644 index 0000000000..ca9c01d5dc --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPCodeUtil.cpp @@ -0,0 +1,233 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include + +#include "Common.h" +#include "FileUtil.h" +#include "StringUtil.h" +#include "DSPCodeUtil.h" +#include "assemble.h" +#include "disassemble.h" + + +bool Assemble(const char *text, std::vector &code, bool force) +{ + AssemblerSettings settings; + // settings.pc = 0; + // settings.decode_registers = false; + // settings.decode_names = false; + settings.force = force; + // settings.print_tabs = false; + // settings.ext_separator = '\''; + + // TODO: fix the terrible api of the assembler. + DSPAssembler assembler(settings); + if (!assembler.Assemble(text, code)) { + std::cerr << assembler.GetErrorString() << std::endl; + return false; + } + + return true; +} + +bool Disassemble(const std::vector &code, bool line_numbers, std::string &text) +{ + if (code.empty()) + return false; + + AssemblerSettings settings; + + // These two prevent roundtripping. + settings.show_hex = true; + settings.show_pc = line_numbers; + settings.ext_separator = '\''; + settings.decode_names = true; + settings.decode_registers = true; + + DSPDisassembler disasm(settings); + bool success = disasm.Disassemble(0, code, 0x0000, text); + return success; +} + +bool Compare(const std::vector &code1, const std::vector &code2) +{ + if (code1.size() != code2.size()) + printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size()); + u32 count_equal = 0; + const int min_size = (int)std::min(code1.size(), code2.size()); + + AssemblerSettings settings; + DSPDisassembler disassembler(settings); + for (int i = 0; i < min_size; i++) + { + if (code1[i] == code2[i]) + count_equal++; + else + { + std::string line1, line2; + u16 pc = i; + disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1); + pc = i; + disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2); + printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str()); + } + } + if (code2.size() != code1.size()) + { + printf("Extra code words:\n"); + const std::vector &longest = code1.size() > code2.size() ? code1 : code2; + for (int i = min_size; i < (int)longest.size(); i++) + { + u16 pc = i; + std::string line; + disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line); + printf("!! %s\n", line.c_str()); + } + } + printf("Equal instruction words: %i / %i\n", count_equal, min_size); + return code1.size() == code2.size() && code1.size() == count_equal; +} + +void GenRandomCode(int size, std::vector &code) +{ + code.resize(size); + for (int i = 0; i < size; i++) + { + code[i] = rand() ^ (rand() << 8); + } +} + +void CodeToHeader(const std::vector &code, std::string _filename, + const char *name, std::string &header) +{ + std::vector code_padded = code; + // Pad with nops to 32byte boundary + while (code_padded.size() & 0x7f) + code_padded.push_back(0); + + char buffer[1024]; + header.clear(); + header.reserve(code_padded.size() * 4); + header.append("#define NUM_UCODES 1\n\n"); + std::string filename; + SplitPath(_filename, NULL, &filename, NULL); + header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < code_padded.size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", code_padded[j]); + header.append(buffer); + } + header.append("\n\t},\n"); + + header.append("};\n"); +} + +void CodesToHeader(const std::vector *codes, const std::vector* filenames, + int numCodes, const char *name, std::string &header) +{ + std::vector > codes_padded; + char buffer[1024]; + int reserveSize = 0; + for(int i = 0; i < numCodes; i++) + { + codes_padded.push_back(codes[i]); + // Pad with nops to 32byte boundary + while (codes_padded.at(i).size() & 0x7f) + codes_padded.at(i).push_back(0); + + reserveSize += (int)codes_padded.at(i).size(); + } + + + header.clear(); + header.reserve(reserveSize * 4); + sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes); + header.append(buffer); + header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); + for (int i = 0; i < numCodes; i++) + { + std::string filename; + if (! SplitPath(filenames->at(i), NULL, &filename, NULL)) + filename = filenames->at(i); + sprintf(buffer, "\t\"%s\",\n", filename.c_str()); + header.append(buffer); + } + header.append("};\n\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + + for(int i = 0; i < numCodes; i++) + { + if(codes[i].size() == 0) + continue; + + header.append("\t{\n\t\t"); + for (u32 j = 0; j < codes_padded.at(i).size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + sprintf(buffer, "0x%04x, ", codes_padded.at(i).at(j)); + header.append(buffer); + } + header.append("\n\t},\n"); + } + header.append("};\n"); +} + +void CodeToBinaryStringBE(const std::vector &code, std::string &str) +{ + str.resize(code.size() * 2); + for (int i = 0; i < (int)code.size(); i++) + { + str[i * 2 + 0] = code[i] >> 8; + str[i * 2 + 1] = code[i] & 0xff; + } +} + +void BinaryStringBEToCode(const std::string &str, std::vector &code) +{ + code.resize(str.size() / 2); + for (int i = 0; i < (int)code.size(); i++) + { + code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); + } +} + +bool LoadBinary(const char *filename, std::vector &code) +{ + std::string buffer; + if (!File::ReadFileToString(false, filename, buffer)) + return false; + + BinaryStringBEToCode(buffer, code); + return true; +} + +bool SaveBinary(const std::vector &code, const char *filename) +{ + std::string buffer; + CodeToBinaryStringBE(code, buffer); + if (!File::WriteStringToFile(false, buffer, filename)) + return false; + return true; +} diff --git a/Source/Core/Core/Src/DSP/DSPCodeUtil.h b/Source/Core/Core/Src/DSP/DSPCodeUtil.h new file mode 100644 index 0000000000..2a2ebfb228 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPCodeUtil.h @@ -0,0 +1,43 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPCODEUTIL_H +#define _DSPCODEUTIL_H + +#include +#include + +#include "Common.h" + +bool Assemble(const char *text, std::vector &code, bool force = false); +bool Disassemble(const std::vector &code, bool line_numbers, std::string &text); +bool Compare(const std::vector &code1, const std::vector &code2); +void GenRandomCode(int size, std::vector &code); +void CodeToHeader(const std::vector &code, std::string _filename, + const char *name, std::string &header); +void CodesToHeader(const std::vector *codes, const std::vector *filenames, + int numCodes, const char *name, std::string &header); + +// Big-endian, for writing straight to file using File::WriteStringToFile. +void CodeToBinaryStringBE(const std::vector &code, std::string &str); +void BinaryStringBEToCode(const std::string &str, std::vector &code); + +// Load code (big endian binary). +bool LoadBinary(const char *filename, std::vector &code); +bool SaveBinary(const std::vector &code, const char *filename); + +#endif // _DSPCODEUTIL_H diff --git a/Source/Core/Core/Src/DSP/DSPCommon.h b/Source/Core/Core/Src/DSP/DSPCommon.h new file mode 100644 index 0000000000..8133cdc54e --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPCommon.h @@ -0,0 +1,8 @@ +#ifndef __DSPCOMMON_H +#define __DSPCOMMON_H +#include "CommonTypes.h" +typedef u16 UDSPInstruction; + + + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPCore.cpp b/Source/Core/Core/Src/DSP/DSPCore.cpp new file mode 100644 index 0000000000..b053395881 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPCore.cpp @@ -0,0 +1,443 @@ +/*==================================================================== + + filename: gdsp_interpreter.cpp + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "Common.h" +#include "Hash.h" +#include "Thread.h" +#include "DSPCore.h" +#include "DSPEmitter.h" +#include "DSPHost.h" +#include "DSPAnalyzer.h" +#include "MemoryUtil.h" + +#include "DSPHWInterface.h" +#include "DSPIntUtil.h" + +SDSP g_dsp; +DSPBreakpoints dsp_breakpoints; +DSPCoreState core_state = DSPCORE_STOP; +u16 cyclesLeft = 0; +DSPEmitter *dspjit = NULL; +Common::Event step_event; +Common::CriticalSection ExtIntCriticalSection; + +static bool LoadRom(const char *fname, int size_in_words, u16 *rom) +{ + FILE *pFile = fopen(fname, "rb"); + const size_t size_in_bytes = size_in_words * sizeof(u16); + if (pFile) + { + fread(rom, 1, size_in_bytes, pFile); + fclose(pFile); + + // Byteswap the rom. + for (int i = 0; i < size_in_words; i++) + rom[i] = Common::swap16(rom[i]); + + // Always keep ROMs write protected. + WriteProtectMemory(rom, size_in_bytes, false); + return true; + } + + PanicAlertT("Failed to load DSP ROM: %s", fname); + return false; +} + +// Returns false iff the hash fails and the user hits "Yes" +static bool VerifyRoms(const char *irom_filename, const char *coef_filename) +{ + static const u32 hash[] = { 0x66f334fe, 0xf3b93527 }; + static const int size[] = { DSP_IROM_BYTE_SIZE, DSP_COEF_BYTE_SIZE }; + const u16 *data[] = { g_dsp.irom, g_dsp.coef }; + + for (int i = 0; i < 2; i++) + { + if (HashAdler32((u8*)data[i], size[i]) != hash[i]) + { + if (AskYesNoT("%s has an incorrect hash.\n" + "Would you like to stop now to fix the problem?\n" + "If you select \"No\", audio will be garbled.", + (i == 0) ? irom_filename : coef_filename)) + return false; + } + } + + return true; +} + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename, + bool bUsingJIT) +{ + g_dsp.step_counter = 0; + cyclesLeft = 0; + dspjit = NULL; + + g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); + g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); + g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); + g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); + + // Fill roms with zeros. + memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); + memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); + + // Try to load real ROM contents. + LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom); + LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef); + if (!VerifyRoms(irom_filename, coef_filename)) + return false; + + memset(&g_dsp.r,0,sizeof(g_dsp.r)); + + for (int i = 0; i < 4; i++) + { + g_dsp.reg_stack_ptr[i] = 0; + for (int j = 0; j < DSP_STACK_DEPTH; j++) + { + g_dsp.reg_stack[i][j] = 0; + } + } + + // Fill IRAM with HALT opcodes. + for (int i = 0; i < DSP_IRAM_SIZE; i++) + { + g_dsp.iram[i] = 0x0021; // HALT opcode + } + + // Just zero out DRAM. + for (int i = 0; i < DSP_DRAM_SIZE; i++) + { + g_dsp.dram[i] = 0; + } + + // Copied from a real console after the custom UCode has been loaded. + // These are the indexing wrapping registers. + g_dsp.r.wr[0] = 0xffff; + g_dsp.r.wr[1] = 0xffff; + g_dsp.r.wr[2] = 0xffff; + g_dsp.r.wr[3] = 0xffff; + + g_dsp.r.sr |= SR_INT_ENABLE; + g_dsp.r.sr |= SR_EXT_INT_ENABLE; + + g_dsp.cr = 0x804; + gdsp_ifx_init(); + // Mostly keep IRAM write protected. We unprotect only when DMA-ing + // in new ucodes. + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + + // Initialize JIT, if necessary + if(bUsingJIT) + dspjit = new DSPEmitter(); + + DSPAnalyzer::Analyze(); + + step_event.Init(); + + core_state = DSPCORE_RUNNING; + + return true; +} + +void DSPCore_Shutdown() +{ + core_state = DSPCORE_STOP; + + if(dspjit) { + delete dspjit; + dspjit = NULL; + } + step_event.Shutdown(); + FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); + FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); +} + +void DSPCore_Reset() +{ + g_dsp.pc = DSP_RESET_VECTOR; + + g_dsp.r.wr[0] = 0xffff; + g_dsp.r.wr[1] = 0xffff; + g_dsp.r.wr[2] = 0xffff; + g_dsp.r.wr[3] = 0xffff; + +} + +void DSPCore_SetException(u8 level) +{ + g_dsp.exceptions |= 1 << level; +} + +// Notify that an external interrupt is pending (used by thread mode) +void DSPCore_SetExternalInterrupt(bool val) +{ + ExtIntCriticalSection.Enter(); + g_dsp.external_interrupt_waiting = val; + ExtIntCriticalSection.Leave(); +} + +// Coming from the CPU +void DSPCore_CheckExternalInterrupt() +{ + if (! dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) + return; + + // Signal the SPU about new mail + DSPCore_SetException(EXP_INT); + + g_dsp.cr &= ~CR_EXTERNAL_INT; +} + + +void DSPCore_CheckExceptions() +{ + // Early out to skip the loop in the common case. + if (g_dsp.exceptions == 0) + return; + + for (int i = 7; i > 0; i--) { + // Seems exp int are not masked by sr_int_enable + if (g_dsp.exceptions & (1 << i)) { + if (dsp_SR_is_flag_set(SR_INT_ENABLE) || (i == EXP_INT)) { + + // store pc and sr until RTI + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + dsp_reg_store_stack(DSP_STACK_D, g_dsp.r.sr); + + g_dsp.pc = i * 2; + g_dsp.exceptions &= ~(1 << i); + if (i == 7) + g_dsp.r.sr &= ~SR_EXT_INT_ENABLE; + else + g_dsp.r.sr &= ~SR_INT_ENABLE; + break; + } else { +#if defined(_DEBUG) || defined(DEBUGFAST) + ERROR_LOG(DSPLLE, "Firing exception %d failed", i); +#endif + } + } + } +} + +// Delegate to JIT or interpreter as appropriate. +// Handle state changes and stepping. +int DSPCore_RunCycles(int cycles) +{ + if (dspjit) + { + cyclesLeft = cycles; + CompiledCode pExecAddr = (CompiledCode)dspjit->enterDispatcher; + pExecAddr(); + + if (g_dsp.external_interrupt_waiting) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_CheckExceptions(); + DSPCore_SetExternalInterrupt(false); + } + + return cyclesLeft; + } + + while (cycles > 0) + { + reswitch: + switch (core_state) + { + case DSPCORE_RUNNING: + // Seems to slow things down +#if defined(_DEBUG) || defined(DEBUGFAST) + cycles = DSPInterpreter::RunCyclesDebug(cycles); +#else + cycles = DSPInterpreter::RunCycles(cycles); +#endif + break; + + case DSPCORE_STEPPING: + step_event.Wait(); + if (core_state != DSPCORE_STEPPING) + goto reswitch; + + DSPInterpreter::Step(); + cycles--; + + DSPHost_UpdateDebugger(); + break; + case DSPCORE_STOP: + break; + } + } + return cycles; +} + +void DSPCore_SetState(DSPCoreState new_state) +{ + core_state = new_state; + // kick the event, in case we are waiting + if (new_state == DSPCORE_RUNNING) + step_event.Set(); + // Sleep(10); + DSPHost_UpdateDebugger(); +} + +DSPCoreState DSPCore_GetState() +{ + return core_state; +} + +void DSPCore_Step() +{ + if (core_state == DSPCORE_STEPPING) + step_event.Set(); +} + +void CompileCurrent() +{ + dspjit->Compile(g_dsp.pc); + + bool retry = true; + + while (retry) + { + retry = false; + for(u16 i = 0x0000; i < 0xffff; ++i) + { + if (!dspjit->unresolvedJumps[i].empty()) + { + u16 addrToCompile = dspjit->unresolvedJumps[i].front(); + dspjit->Compile(addrToCompile); + if (!dspjit->unresolvedJumps[i].empty()) + retry = true; + } + } + } +} + +u16 DSPCore_ReadRegister(int reg) { + switch(reg) { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return g_dsp.r.st[reg - DSP_REG_ST0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: return g_dsp.r.cr; + case DSP_REG_SR: return g_dsp.r.sr; + case DSP_REG_PRODL: return g_dsp.r.prod.l; + case DSP_REG_PRODM: return g_dsp.r.prod.m; + case DSP_REG_PRODH: return g_dsp.r.prod.h; + case DSP_REG_PRODM2: return g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return g_dsp.r.ac[reg - DSP_REG_ACM0].m; + default: + _assert_msg_(DSP_CORE, 0, "cannot happen"); + return 0; + } +} + +void DSPCore_WriteRegister(int reg, u16 val) { + switch(reg) { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + g_dsp.r.ar[reg - DSP_REG_AR0] = val; + break; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + g_dsp.r.ix[reg - DSP_REG_IX0] = val; + break; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + g_dsp.r.wr[reg - DSP_REG_WR0] = val; + break; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + g_dsp.r.st[reg - DSP_REG_ST0] = val; + break; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + g_dsp.r.ac[reg - DSP_REG_ACH0].h = val; + break; + case DSP_REG_CR: g_dsp.r.cr = val; break; + case DSP_REG_SR: g_dsp.r.sr = val; break; + case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; + case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; + case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; + case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; + break; + } +} diff --git a/Source/Core/Core/Src/DSP/DSPCore.h b/Source/Core/Core/Src/DSP/DSPCore.h new file mode 100644 index 0000000000..2f69eb6ee6 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPCore.h @@ -0,0 +1,306 @@ +/*==================================================================== + + filename: DSPCore.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSPCORE_H +#define _DSPCORE_H + +#include "Thread.h" + +#include "DSPBreakpoints.h" +#include "DSPEmitter.h" + +#define DSP_IRAM_BYTE_SIZE 0x2000 +#define DSP_IRAM_SIZE 0x1000 +#define DSP_IRAM_MASK 0x0fff + +#define DSP_IROM_BYTE_SIZE 0x2000 +#define DSP_IROM_SIZE 0x1000 +#define DSP_IROM_MASK 0x0fff + +#define DSP_DRAM_BYTE_SIZE 0x2000 +#define DSP_DRAM_SIZE 0x1000 +#define DSP_DRAM_MASK 0x0fff + +#define DSP_COEF_BYTE_SIZE 0x1000 +#define DSP_COEF_SIZE 0x800 +#define DSP_COEF_MASK 0x7ff + +#define DSP_RESET_VECTOR 0x8000 + +#define DSP_STACK_DEPTH 0x20 +#define DSP_STACK_MASK 0x1f + +#define DSP_CR_IMEM 2 +#define DSP_CR_DMEM 0 +#define DSP_CR_TO_CPU 1 +#define DSP_CR_FROM_CPU 0 + + +// Register table taken from libasnd +#define DSP_REG_AR0 0x00 // address registers +#define DSP_REG_AR1 0x01 +#define DSP_REG_AR2 0x02 +#define DSP_REG_AR3 0x03 + +#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) +#define DSP_REG_IX1 0x05 +#define DSP_REG_IX2 0x06 +#define DSP_REG_IX3 0x07 + +#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. +#define DSP_REG_WR1 0x09 +#define DSP_REG_WR2 0x0a +#define DSP_REG_WR3 0x0b + +#define DSP_REG_ST0 0x0c // stacks. +#define DSP_REG_ST1 0x0d +#define DSP_REG_ST2 0x0e +#define DSP_REG_ST3 0x0f + +#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. +#define DSP_REG_SR 0x13 + +#define DSP_REG_PRODL 0x14 // product. +#define DSP_REG_PRODM 0x15 +#define DSP_REG_PRODH 0x16 +#define DSP_REG_PRODM2 0x17 + +#define DSP_REG_AXL0 0x18 +#define DSP_REG_AXL1 0x19 +#define DSP_REG_AXH0 0x1a +#define DSP_REG_AXH1 0x1b + +#define DSP_REG_ACC0 0x1c // accumulator (global) +#define DSP_REG_ACC1 0x1d + +#define DSP_REG_ACL0 0x1c // Low accumulator +#define DSP_REG_ACL1 0x1d +#define DSP_REG_ACM0 0x1e // Mid accumulator +#define DSP_REG_ACM1 0x1f +#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 +#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 + +// Hardware registers address + +#define DSP_COEF_A1_0 0xa0 + +#define DSP_DSCR 0xc9 // DSP DMA Control Reg +#define DSP_DSPA 0xcd // DSP DMA Address (DSP) +#define DSP_DSBL 0xcb // DSP DMA Block Length +#define DSP_DSMAH 0xce // DSP DMA Address High (External) +#define DSP_DSMAL 0xcf // DSP DMA Address Low (External) + +#define DSP_FORMAT 0xd1 // Sample format +#define DSP_ACUNK 0xd2 // Set to 3 on my dumps +#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes +#define DSP_ACSAH 0xd4 // Start of loop +#define DSP_ACSAL 0xd5 +#define DSP_ACEAH 0xd6 // End of sample (and loop) +#define DSP_ACEAL 0xd7 +#define DSP_ACCAH 0xd8 // Current playback position +#define DSP_ACCAL 0xd9 +#define DSP_PRED_SCALE 0xda // ADPCM predictor and scale +#define DSP_YN1 0xdb +#define DSP_YN2 0xdc +#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX. +#define DSP_GAIN 0xde +#define DSP_ACUNK2 0xdf // Set to 0xc on my dumps + +#define DSP_AMDM 0xef // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked + +#define DSP_DIRQ 0xfb // DSP Irq Rest +#define DSP_DMBH 0xfc // DSP Mailbox H +#define DSP_DMBL 0xfd // DSP Mailbox L +#define DSP_CMBH 0xfe // CPU Mailbox H +#define DSP_CMBL 0xff // CPU Mailbox L + +#define DMA_TO_DSP 0 +#define DMA_TO_CPU 1 + +// Stacks +#define DSP_STACK_C 0 +#define DSP_STACK_D 1 + +// cr (Not g_dsp.r[CR]) bits +// See HW/DSP.cpp. +#define CR_EXTERNAL_INT 0x0002 +#define CR_HALT 0x0004 +#define CR_INIT 0x0400 + + +// SR bits +#define SR_CARRY 0x0001 +#define SR_OVERFLOW 0x0002 +#define SR_ARITH_ZERO 0x0004 +#define SR_SIGN 0x0008 +#define SR_OVER_S32 0x0010 // set when there there was mod/tst/cmp on accu and result is over s32 +#define SR_TOP2BITS 0x0020 // if the upper (ac?.m/ax?.h) 2 bits are equal +#define SR_LOGIC_ZERO 0x0040 +#define SR_OVERFLOW_STICKY 0x0080 // set at the same time as 0x2 (under same conditions) - but not cleared the same +#define SR_100 0x0100 // unknown +#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. +#define SR_400 0x0400 // unknown +#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts +#define SR_1000 0x1000 // unknown +#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) +#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. +#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. + +// This should be the bits affected by CMP. Does not include logic zero. +#define SR_CMP_MASK 0x3f + +// exceptions vector +#define EXP_STOVF 1 // 0x0002 stack under/over flow +#define EXP_2 2 // 0x0004 +#define EXP_3 3 // 0x0006 +#define EXP_4 4 // 0x0008 +#define EXP_ACCOV 5 // 0x000a accelerator address overflow +#define EXP_6 6 // 0x000c +#define EXP_INT 7 // 0x000e external int (message from cpu) + +typedef struct { + u16 ar[4]; + u16 ix[4]; + u16 wr[4]; + u16 st[4]; + u16 cr; + u16 sr; + union { + u64 val; + struct { + u16 l; + u16 m; + u16 h; + u16 m2;//if this gets in the way, drop it. + }; + } prod; + union { + u32 val; + struct { + u16 l; + u16 h; + }; + } ax[2]; + union { + u64 val; + struct { + u16 l; + u16 m; + u16 h; + }; + } ac[2]; +} DSP_Regs; + +// All the state of the DSP should be in this struct. Any DSP state that is not filled on init +// should be moved here. +struct SDSP +{ + DSP_Regs r; + u16 pc; +#if PROFILE + u16 err_pc; +#endif + + // This is NOT the same cr as r.cr. + // This register is shared with the main emulation, see DSP.cpp + // The plugin has control over 0x0C07 of this reg. + // Bits are defined in a struct in DSP.cpp. + u16 cr; + + u8 reg_stack_ptr[4]; + u8 exceptions; // pending exceptions + bool external_interrupt_waiting; + + // DSP hardware stacks. They're mapped to a bunch of registers, such that writes + // to them push and reads pop. + // Let's make stack depth 32 for now, which is way more than what's needed. + // The real DSP has different depths for the different stacks, but it would + // be strange if any ucode relied on stack overflows since on the DSP, when + // the stack overflows, you're screwed. + u16 reg_stack[4][DSP_STACK_DEPTH]; + + // For debugging. + u32 iram_crc; + u64 step_counter; + + // Mailbox. + volatile u16 mbox[2][2]; + + // Mutex protecting the mailbox. + Common::CriticalSection g_CriticalSection; + + // Accelerator / DMA / other hardware registers. Not GPRs. + u16 ifx_regs[256]; + + // When state saving, all of the above can just be memcpy'd into the save state. + // The below needs special handling. + u16 *iram; + u16 *dram; + u16 *irom; + u16 *coef; + + // This one doesn't really belong here. + u8 *cpu_ram; +}; + +extern SDSP g_dsp; +extern DSPBreakpoints dsp_breakpoints; +extern DSPEmitter *dspjit; +extern u16 cyclesLeft; + +bool DSPCore_Init(const char *irom_filename, const char *coef_filename, + bool bUsingJIT); + +void DSPCore_Reset(); +void DSPCore_Shutdown(); // Frees all allocated memory. + +void DSPCore_CheckExternalInterrupt(); +void DSPCore_CheckExceptions(); +void DSPCore_SetExternalInterrupt(bool val); + +// sets a flag in the pending exception register. +void DSPCore_SetException(u8 level); + +void CompileCurrent(); + +enum DSPCoreState +{ + DSPCORE_STOP = 0, + DSPCORE_RUNNING, + DSPCORE_STEPPING, +}; + +int DSPCore_RunCycles(int cycles); + +// These are meant to be called from the UI thread. +void DSPCore_SetState(DSPCoreState new_state); +DSPCoreState DSPCore_GetState(); + +void DSPCore_Step(); + +u16 DSPCore_ReadRegister(int reg); +void DSPCore_WriteRegister(int reg, u16 val); + +#endif // _DSPCORE_H diff --git a/Source/Core/Core/Src/DSP/DSPEmitter.cpp b/Source/Core/Core/Src/DSP/DSPEmitter.cpp new file mode 100644 index 0000000000..e68fea7e18 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPEmitter.cpp @@ -0,0 +1,446 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "DSPEmitter.h" +#include "DSPMemoryMap.h" +#include "DSPCore.h" +#include "DSPInterpreter.h" +#include "DSPAnalyzer.h" +#include "Jit/DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" + +#define MAX_BLOCK_SIZE 250 +#define DSP_IDLE_SKIP_CYCLES 0x1000 + +using namespace Gen; + +DSPEmitter::DSPEmitter() : gpr(*this), storeIndex(-1), storeIndex2(-1) +{ + m_compiledCode = NULL; + + AllocCodeSpace(COMPILED_CODE_SIZE); + + blocks = new CompiledCode[MAX_BLOCKS]; + blockLinks = new Block[MAX_BLOCKS]; + blockSize = new u16[MAX_BLOCKS]; + unresolvedJumps = new std::list[MAX_BLOCKS]; + + compileSR = 0; + compileSR |= SR_INT_ENABLE; + compileSR |= SR_EXT_INT_ENABLE; + + CompileDispatcher(); + stubEntryPoint = CompileStub(); + + //clear all of the block references + for(int i = 0x0000; i < MAX_BLOCKS; i++) + { + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } +} + +DSPEmitter::~DSPEmitter() +{ + delete[] blocks; + delete[] blockLinks; + delete[] blockSize; + FreeCodeSpace(); +} + +void DSPEmitter::ClearIRAM() { + // ClearCodeSpace(); + for(int i = 0x0000; i < 0x1000; i++) + { + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } +} + +// Must go out of block if exception is detected +void DSPEmitter::checkExceptions(u32 retval) +{ + // Check for interrupts and exceptions +#ifdef _M_IX86 // All32 + TEST(8, M(&g_dsp.exceptions), Imm8(0xff)); +#else + MOV(64, R(RAX), ImmPtr(&g_dsp.exceptions)); + TEST(8, MatR(RAX), Imm8(0xff)); +#endif + FixupBranch skipCheck = J_CC(CC_Z); + +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC)); +#endif + + DSPJitRegCache c(gpr); + SaveDSPRegs(); + ABI_CallFunction((void *)&DSPCore_CheckExceptions); + MOV(32, R(EAX), Imm32(retval)); + JMP(returnDispatcher, true); + gpr.flushRegs(c,false); + + SetJumpTarget(skipCheck); +} + +void DSPEmitter::Default(UDSPInstruction inst) +{ + if (opTable[inst]->reads_pc) + { + // Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block. + // Fallbacks to interpreter need this for fetching immediate values + +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif + } + + // Fall back to interpreter + SaveDSPRegs(); + ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst); + LoadDSPRegs(); +} + +void DSPEmitter::EmitInstruction(UDSPInstruction inst) +{ + const DSPOPCTemplate *tinst = GetOpTemplate(inst); + bool ext_is_jit = false; + + // Call extended + if (tinst->extended) { + if ((inst >> 12) == 0x3) { + if (! extOpTable[inst & 0x7F]->jitFunc) { + // Fall back to interpreter + SaveDSPRegs(); + ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); + LoadDSPRegs(); + INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); + ext_is_jit = false; + } else { + (this->*extOpTable[inst & 0x7F]->jitFunc)(inst); + ext_is_jit = true; + } + } else { + if (!extOpTable[inst & 0xFF]->jitFunc) { + // Fall back to interpreter + SaveDSPRegs(); + ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); + LoadDSPRegs(); + INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); + ext_is_jit = false; + } else { + (this->*extOpTable[inst & 0xFF]->jitFunc)(inst); + ext_is_jit = true; + } + } + } + + // Main instruction + if (!opTable[inst]->jitFunc) { + Default(inst); + INFO_LOG(DSPLLE, "Instruction not JITed(main part): %04x\n", inst); + } + else + { + (this->*opTable[inst]->jitFunc)(inst); + } + + // Backlog + if (tinst->extended) { + if (!ext_is_jit) { + //need to call the online cleanup function because + //the writeBackLog gets populated at runtime + SaveDSPRegs(); + ABI_CallFunction((void*)::applyWriteBackLog); + LoadDSPRegs(); + } else { + popExtValueToReg(); + } + } +} + +void DSPEmitter::unknown_instruction(UDSPInstruction inst) +{ + PanicAlert("unknown_instruction %04x - Fix me ;)", inst); +} + +void DSPEmitter::Compile(u16 start_addr) +{ + // Remember the current block address for later + startAddr = start_addr; + unresolvedJumps[start_addr].clear(); + + const u8 *entryPoint = AlignCode16(); + + /* + // Check for other exceptions + if (dsp_SR_is_flag_set(SR_INT_ENABLE)) + return; + + if (g_dsp.exceptions == 0) + return; + */ + + LoadDSPRegs(); + + blockLinkEntry = GetCodePtr(); + + compilePC = start_addr; + bool fixup_pc = false; + blockSize[start_addr] = 0; + + while (compilePC < start_addr + MAX_BLOCK_SIZE) + { + if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT) + checkExceptions(blockSize[start_addr]); + + UDSPInstruction inst = dsp_imem_read(compilePC); + const DSPOPCTemplate *opcode = GetOpTemplate(inst); + + EmitInstruction(inst); + + blockSize[start_addr]++; + compilePC += opcode->size; + + // If the block was trying to link into itself, remove the link + unresolvedJumps[start_addr].remove(compilePC); + + fixup_pc = true; + + // Handle loop condition, only if current instruction was flagged as a loop destination + // by the analyzer. + if (DSPAnalyzer::code_flags[compilePC-1] & DSPAnalyzer::CODE_LOOP_END) + { +#ifdef _M_IX86 // All32 + MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2]))); +#else + MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[2]))); +#endif + CMP(32, R(EAX), Imm32(0)); + FixupBranch rLoopAddressExit = J_CC(CC_LE, true); + +#ifdef _M_IX86 // All32 + MOVZX(32, 16, EAX, M(&g_dsp.r.st[3])); +#else + MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3]))); +#endif + CMP(32, R(EAX), Imm32(0)); + FixupBranch rLoopCounterExit = J_CC(CC_LE, true); + + if (!opcode->branch) + { + //branch insns update the g_dsp.pc +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC)); +#endif + } + + // These functions branch and therefore only need to be called in the + // end of each block and in this order + DSPJitRegCache c(gpr); + HandleLoop(); + SaveDSPRegs(); + if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); + gpr.flushRegs(c,false); + + SetJumpTarget(rLoopAddressExit); + SetJumpTarget(rLoopCounterExit); + } + + if (opcode->branch) + { + //don't update g_dsp.pc -- the branch insn already did + fixup_pc = false; + if (opcode->uncond_branch) + { + break; + } + else if (!opcode->jitFunc) + { + //look at g_dsp.pc if we actually branched +#ifdef _M_IX86 // All32 + MOV(16, R(AX), M(&g_dsp.pc)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, R(AX), MatR(RAX)); +#endif + CMP(16, R(AX), Imm16(compilePC)); + FixupBranch rNoBranch = J_CC(CC_Z); + + DSPJitRegCache c(gpr); + //don't update g_dsp.pc -- the branch insn already did + SaveDSPRegs(); + if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); + gpr.flushRegs(c,false); + + SetJumpTarget(rNoBranch); + } + } + + // End the block if we're before an idle skip address + if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP) + { + break; + } + } + + if (fixup_pc) { +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC)); +#endif + } + + blocks[start_addr] = (CompiledCode)entryPoint; + + // Mark this block as a linkable destination if it does not contain + // any unresolved CALL's + if (unresolvedJumps[start_addr].empty()) + { + blockLinks[start_addr] = blockLinkEntry; + + for(u16 i = 0x0000; i < 0xffff; ++i) + { + if (!unresolvedJumps[i].empty()) + { + // Check if there were any blocks waiting for this block to be linkable + unsigned int size = unresolvedJumps[i].size(); + unresolvedJumps[i].remove(start_addr); + if (unresolvedJumps[i].size() < size) + { + // Mark the block to be recompiled again + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } + } + } + } + + if (blockSize[start_addr] == 0) + { + // just a safeguard, should never happen anymore. + // if it does we might get stuck over in RunForCycles. + ERROR_LOG(DSPLLE, "Block at 0x%04x has zero size", start_addr); + blockSize[start_addr] = 1; + } + + SaveDSPRegs(); + if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); +} + +const u8 *DSPEmitter::CompileStub() +{ + const u8 *entryPoint = AlignCode16(); + ABI_CallFunction((void *)&CompileCurrent); + //MOVZX(32, 16, ECX, M(&g_dsp.pc)); + XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed + JMP(returnDispatcher); + return entryPoint; +} + +void DSPEmitter::CompileDispatcher() +{ + enterDispatcher = AlignCode16(); + ABI_PushAllCalleeSavedRegsAndAdjustStack(); + + const u8 *dispatcherLoop = GetCodePtr(); + + // Check for DSP halt +#ifdef _M_IX86 + TEST(8, M(&g_dsp.cr), Imm8(CR_HALT)); +#else + MOV(64, R(RAX), ImmPtr(&g_dsp.cr)); + TEST(8, MatR(RAX), Imm8(CR_HALT)); +#endif + FixupBranch _halt = J_CC(CC_NE); + +#ifdef _M_IX86 + MOVZX(32, 16, ECX, M(&g_dsp.pc)); +#else + MOV(64, R(RCX), ImmPtr(&g_dsp.pc)); + MOVZX(64, 16, RCX, MatR(RCX)); +#endif + + // Execute block. Cycles executed returned in EAX. +#ifdef _M_IX86 + MOV(32, R(EBX), ImmPtr(blocks)); + JMPptr(MComplex(EBX, ECX, SCALE_4, 0)); +#else + MOV(64, R(RBX), ImmPtr(blocks)); + JMPptr(MComplex(RBX, RCX, SCALE_8, 0)); +#endif + + returnDispatcher = GetCodePtr(); + + // Decrement cyclesLeft +#ifdef _M_IX86 + SUB(16, M(&cyclesLeft), R(EAX)); +#else + MOV(64, R(R12), ImmPtr(&cyclesLeft)); + SUB(16, MatR(R12), R(EAX)); +#endif + + J_CC(CC_A, dispatcherLoop); + + // DSP gave up the remaining cycles. + SetJumpTarget(_halt); + //MOV(32, M(&cyclesLeft), Imm32(0)); + ABI_PopAllCalleeSavedRegsAndAdjustStack(); + RET(); +} diff --git a/Source/Core/Core/Src/DSP/DSPEmitter.h b/Source/Core/Core/Src/DSP/DSPEmitter.h new file mode 100644 index 0000000000..17f1850001 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPEmitter.h @@ -0,0 +1,303 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPEMITTER_H +#define _DSPEMITTER_H + +#include + +#include "DSPCommon.h" +#include "x64Emitter.h" +#include "Jit/DSPJitRegCache.h" + +#define COMPILED_CODE_SIZE sizeof(void *) * 0x200000 + +#define MAX_BLOCKS 0x10000 + +typedef u32 (*CompiledCode)(); +typedef const u8 *Block; + +class DSPEmitter : public Gen::XCodeBlock, NonCopyable +{ +public: + DSPEmitter(); + ~DSPEmitter(); + + Block m_compiledCode; + + void EmitInstruction(UDSPInstruction inst); + void unknown_instruction(UDSPInstruction inst); + void ClearIRAM(); + + void CompileDispatcher(); + Block CompileStub(); + void Compile(u16 start_addr); + void ClearCallFlag(); + + void Default(UDSPInstruction inst); + + // CC Util + void Update_SR_Register64(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register64_Carry(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register64_Carry2(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register16(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register16_OverS32(Gen::X64Reg val = Gen::EAX); + + // Register helpers + void setCompileSR(u16 bit); + void clrCompileSR(u16 bit); + void checkExceptions(u32 retval); + + // Memory helper functions + void increment_addr_reg(int reg); + void decrement_addr_reg(int reg); + void increase_addr_reg(int reg); + void decrease_addr_reg(int reg); + void imem_read(); + void dmem_read(); + void dmem_read_imm(u16 addr); + void dmem_write(); + void dmem_write_imm(u16 addr); + + // Ext command helpers + void pushExtValueFromReg(u16 dreg, u16 sreg); + void popExtValueToReg(); + void pushExtValueFromMem(u16 dreg, u16 sreg); + void pushExtValueFromMem2(u16 dreg, u16 sreg); + void zeroWriteBackLog(const UDSPInstruction opc); + + // Ext commands + void l(const UDSPInstruction opc); + void ln(const UDSPInstruction opc); + void ls(const UDSPInstruction opc); + void lsn(const UDSPInstruction opc); + void lsm(const UDSPInstruction opc); + void lsnm(const UDSPInstruction opc); + void sl(const UDSPInstruction opc); + void sln(const UDSPInstruction opc); + void slm(const UDSPInstruction opc); + void slnm(const UDSPInstruction opc); + void s(const UDSPInstruction opc); + void sn(const UDSPInstruction opc); + void ld(const UDSPInstruction opc); + void ldn(const UDSPInstruction opc); + void ldm(const UDSPInstruction opc); + void ldnm(const UDSPInstruction opc); + void mv(const UDSPInstruction opc); + void dr(const UDSPInstruction opc); + void ir(const UDSPInstruction opc); + void nr(const UDSPInstruction opc); + void nop(const UDSPInstruction opc) {} + + // Command helpers + void dsp_reg_stack_push(int stack_reg); + void dsp_reg_stack_pop(int stack_reg); + void dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg = Gen::EDX); + void dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg = Gen::EDX); + void dsp_reg_store_stack_imm(int stack_reg, u16 val); + void dsp_op_write_reg(int reg, Gen::X64Reg host_sreg); + void dsp_op_write_reg_imm(int reg, u16 val); + void dsp_conditional_extend_accum(int reg); + void dsp_conditional_extend_accum_imm(int reg, u16 val); + void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE); + + // Commands + void dar(const UDSPInstruction opc); + void iar(const UDSPInstruction opc); + void subarn(const UDSPInstruction opc); + void addarn(const UDSPInstruction opc); + void sbclr(const UDSPInstruction opc); + void sbset(const UDSPInstruction opc); + void srbith(const UDSPInstruction opc); + void lri(const UDSPInstruction opc); + void lris(const UDSPInstruction opc); + void mrr(const UDSPInstruction opc); + void nx(const UDSPInstruction opc); + + // Branch + void HandleLoop(); + void jcc(const UDSPInstruction opc); + void jmprcc(const UDSPInstruction opc); + void call(const UDSPInstruction opc); + void callr(const UDSPInstruction opc); + void ifcc(const UDSPInstruction opc); + void ret(const UDSPInstruction opc); + void rti(const UDSPInstruction opc); + void halt(const UDSPInstruction opc); + void loop(const UDSPInstruction opc); + void loopi(const UDSPInstruction opc); + void bloop(const UDSPInstruction opc); + void bloopi(const UDSPInstruction opc); + + // Load/Store + void srs(const UDSPInstruction opc); + void lrs(const UDSPInstruction opc); + void lr(const UDSPInstruction opc); + void sr(const UDSPInstruction opc); + void si(const UDSPInstruction opc); + void lrr(const UDSPInstruction opc); + void lrrd(const UDSPInstruction opc); + void lrri(const UDSPInstruction opc); + void lrrn(const UDSPInstruction opc); + void srr(const UDSPInstruction opc); + void srrd(const UDSPInstruction opc); + void srri(const UDSPInstruction opc); + void srrn(const UDSPInstruction opc); + void ilrr(const UDSPInstruction opc); + void ilrrd(const UDSPInstruction opc); + void ilrri(const UDSPInstruction opc); + void ilrrn(const UDSPInstruction opc); + + // Arithmetic + void clr(const UDSPInstruction opc); + void clrl(const UDSPInstruction opc); + void andcf(const UDSPInstruction opc); + void andf(const UDSPInstruction opc); + void tst(const UDSPInstruction opc); + void tstaxh(const UDSPInstruction opc); + void cmp(const UDSPInstruction opc); + void cmpar(const UDSPInstruction opc); + void cmpi(const UDSPInstruction opc); + void cmpis(const UDSPInstruction opc); + void xorr(const UDSPInstruction opc); + void andr(const UDSPInstruction opc); + void orr(const UDSPInstruction opc); + void andc(const UDSPInstruction opc); + void orc(const UDSPInstruction opc); + void xorc(const UDSPInstruction opc); + void notc(const UDSPInstruction opc); + void xori(const UDSPInstruction opc); + void andi(const UDSPInstruction opc); + void ori(const UDSPInstruction opc); + void addr(const UDSPInstruction opc); + void addax(const UDSPInstruction opc); + void add(const UDSPInstruction opc); + void addp(const UDSPInstruction opc); + void addaxl(const UDSPInstruction opc); + void addi(const UDSPInstruction opc); + void addis(const UDSPInstruction opc); + void incm(const UDSPInstruction opc); + void inc(const UDSPInstruction opc); + void subr(const UDSPInstruction opc); + void subax(const UDSPInstruction opc); + void sub(const UDSPInstruction opc); + void subp(const UDSPInstruction opc); + void decm(const UDSPInstruction opc); + void dec(const UDSPInstruction opc); + void neg(const UDSPInstruction opc); + void abs(const UDSPInstruction opc); + void movr(const UDSPInstruction opc); + void movax(const UDSPInstruction opc); + void mov(const UDSPInstruction opc); + void lsl16(const UDSPInstruction opc); + void lsr16(const UDSPInstruction opc); + void asr16(const UDSPInstruction opc); + void lsl(const UDSPInstruction opc); + void lsr(const UDSPInstruction opc); + void asl(const UDSPInstruction opc); + void asr(const UDSPInstruction opc); + void lsrn(const UDSPInstruction opc); + void asrn(const UDSPInstruction opc); + void lsrnrx(const UDSPInstruction opc); + void asrnrx(const UDSPInstruction opc); + void lsrnr(const UDSPInstruction opc); + void asrnr(const UDSPInstruction opc); + + // Multipliers + void multiply(); + void multiply_add(); + void multiply_sub(); + void multiply_mulx(u8 axh0, u8 axh1); + void clrp(const UDSPInstruction opc); + void tstprod(const UDSPInstruction opc); + void movp(const UDSPInstruction opc); + void movnp(const UDSPInstruction opc); + void movpz(const UDSPInstruction opc); + void addpaxz(const UDSPInstruction opc); + void mulaxh(const UDSPInstruction opc); + void mul(const UDSPInstruction opc); + void mulac(const UDSPInstruction opc); + void mulmv(const UDSPInstruction opc); + void mulmvz(const UDSPInstruction opc); + void mulx(const UDSPInstruction opc); + void mulxac(const UDSPInstruction opc); + void mulxmv(const UDSPInstruction opc); + void mulxmvz(const UDSPInstruction opc); + void mulc(const UDSPInstruction opc); + void mulcac(const UDSPInstruction opc); + void mulcmv(const UDSPInstruction opc); + void mulcmvz(const UDSPInstruction opc); + void maddx(const UDSPInstruction opc); + void msubx(const UDSPInstruction opc); + void maddc(const UDSPInstruction opc); + void msubc(const UDSPInstruction opc); + void madd(const UDSPInstruction opc); + void msub(const UDSPInstruction opc); + + // CALL this to start the dispatcher + const u8 *enterDispatcher; + const u8 *stubEntryPoint; + const u8 *returnDispatcher; + u16 compilePC; + u16 startAddr; + Block *blockLinks; + u16 *blockSize; + std::list *unresolvedJumps; + + DSPJitRegCache gpr; + + void LoadDSPRegs(); + void SaveDSPRegs(); + +private: + CompiledCode *blocks; + Block blockLinkEntry; + u16 compileSR; + + // The index of the last stored ext value (compile time). + int storeIndex; + int storeIndex2; + + // Counts down. + // int cycles; + + + void Update_SR_Register(Gen::X64Reg val = Gen::EAX); + + void ToMask(Gen::X64Reg value_reg = Gen::EDI); + void dsp_increment_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI); + void dsp_decrement_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI); + void get_long_prod(Gen::X64Reg long_prod = Gen::RAX); + void get_long_prod_round_prodl(Gen::X64Reg long_prod = Gen::RAX); + void set_long_prod(); + void round_long_acc(Gen::X64Reg long_acc = Gen::EAX); + void set_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); + void get_acc_h(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_h(int _reg, Gen::OpArg arg = R(Gen::EAX)); + void get_acc_m(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_m(int _reg, Gen::OpArg arg = R(Gen::EAX)); + void get_acc_l(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_l(int _reg, Gen::OpArg arg = R(Gen::EAX)); + void get_long_acx(int _reg, Gen::X64Reg acx = Gen::EAX); + void get_ax_l(int _reg, Gen::X64Reg acx = Gen::EAX); + void get_ax_h(int _reg, Gen::X64Reg acc = Gen::EAX); + void get_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); +}; + + +#endif // _DSPEMITTER_H + diff --git a/Source/Core/Core/Src/DSP/DSPHWInterface.cpp b/Source/Core/Core/Src/DSP/DSPHWInterface.cpp new file mode 100644 index 0000000000..a2862affe3 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPHWInterface.cpp @@ -0,0 +1,361 @@ +/*==================================================================== + + filename: gdsp_interface.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "Thread.h" +#include "MemoryUtil.h" + +#include "DSPCore.h" +#include "DSPHost.h" +#include "DSPTables.h" +#include "DSPAnalyzer.h" +#include "DSPAccelerator.h" +#include "DSPInterpreter.h" +#include "DSPHWInterface.h" +#include "CPUDetect.h" + +#if _M_SSE >= 0x301 && !(defined __GNUC__ && !defined __SSSE3__) +#include +#endif + +void gdsp_do_dma(); + +Common::CriticalSection g_CriticalSection; + +void gdsp_ifx_init() +{ + for (int i = 0; i < 256; i++) + { + g_dsp.ifx_regs[i] = 0; + } + + g_dsp.mbox[0][0] = 0; + g_dsp.mbox[0][1] = 0; + g_dsp.mbox[1][0] = 0; + g_dsp.mbox[1][1] = 0; +} + + +u32 gdsp_mbox_peek(u8 mbx) +{ + if (DSPHost_OnThread()) + g_CriticalSection.Enter(); + u32 value = ((g_dsp.mbox[mbx][0] << 16) | g_dsp.mbox[mbx][1]); + if (DSPHost_OnThread()) + g_CriticalSection.Leave(); + return value; +} + +void gdsp_mbox_write_h(u8 mbx, u16 val) +{ + if (DSPHost_OnThread()) + g_CriticalSection.Enter(); + g_dsp.mbox[mbx][0] = val & 0x7fff; + if (DSPHost_OnThread()) + g_CriticalSection.Leave(); +} + + +void gdsp_mbox_write_l(u8 mbx, u16 val) +{ + if (DSPHost_OnThread()) + g_CriticalSection.Enter(); + g_dsp.mbox[mbx][1] = val; + g_dsp.mbox[mbx][0] |= 0x8000; + if (DSPHost_OnThread()) + g_CriticalSection.Leave(); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (mbx == GDSP_MBOX_DSP) + { + NOTICE_LOG(DSP_MAIL, "DSP(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_DSP), g_dsp.pc); + } else { + NOTICE_LOG(DSP_MAIL, "CPU(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_CPU), g_dsp.pc); + } +#endif +} + + +u16 gdsp_mbox_read_h(u8 mbx) +{ + return g_dsp.mbox[mbx][0]; // TODO: mask away the top bit? +} + + +u16 gdsp_mbox_read_l(u8 mbx) +{ + if (DSPHost_OnThread()) + g_CriticalSection.Enter(); + + u16 val = g_dsp.mbox[mbx][1]; + g_dsp.mbox[mbx][0] &= ~0x8000; + + + if (DSPHost_OnThread()) + g_CriticalSection.Leave(); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (mbx == GDSP_MBOX_DSP) + { + NOTICE_LOG(DSP_MAIL, "DSP(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_DSP), g_dsp.pc); + } else { + NOTICE_LOG(DSP_MAIL, "CPU(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_CPU), g_dsp.pc); + } +#endif + + return val; +} + + +void gdsp_ifx_write(u32 addr, u32 val) +{ + switch (addr & 0xff) + { + case DSP_DIRQ: + if (val & 0x1) + DSPHost_InterruptRequest(); + else + INFO_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); + break; + + case DSP_DMBH: + gdsp_mbox_write_h(GDSP_MBOX_DSP, val); + break; + + case DSP_DMBL: + gdsp_mbox_write_l(GDSP_MBOX_DSP, val); + break; + + case DSP_CMBH: + return gdsp_mbox_write_h(GDSP_MBOX_CPU, val); + + case DSP_CMBL: + return gdsp_mbox_write_l(GDSP_MBOX_CPU, val); + + case DSP_DSBL: + g_dsp.ifx_regs[DSP_DSBL] = val; + g_dsp.ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly + if (!g_dsp.ifx_regs[DSP_AMDM]) + gdsp_do_dma(); + else + NOTICE_LOG(DSPLLE, "Masked DMA skipped"); + g_dsp.ifx_regs[DSP_DSCR] &= ~4; + g_dsp.ifx_regs[DSP_DSBL] = 0; + break; + + case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda" + dsp_write_aram_d3(val); + break; + + case DSP_GAIN: + if (val) { + INFO_LOG(DSPLLE,"Gain Written: 0x%04x", val); + } + case DSP_DSPA: + case DSP_DSMAH: + case DSP_DSMAL: + case DSP_DSCR: + g_dsp.ifx_regs[addr & 0xFF] = val; + break; +/* + case DSP_ACCAL: + dsp_step_accelerator(); + break; +*/ + default: + if ((addr & 0xff) >= 0xa0) { + if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) { + INFO_LOG(DSPLLE, "%04x MW %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, val); + } + else { + ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); + } + } + else { + ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); + } + g_dsp.ifx_regs[addr & 0xFF] = val; + break; + } +} + +u16 gdsp_ifx_read(u16 addr) +{ + switch (addr & 0xff) + { + case DSP_DMBH: + return gdsp_mbox_read_h(GDSP_MBOX_DSP); + + case DSP_DMBL: + return gdsp_mbox_read_l(GDSP_MBOX_DSP); + + case DSP_CMBH: + return gdsp_mbox_read_h(GDSP_MBOX_CPU); + + case DSP_CMBL: + return gdsp_mbox_read_l(GDSP_MBOX_CPU); + + case DSP_DSCR: + return g_dsp.ifx_regs[addr & 0xFF]; + + case DSP_ACCELERATOR: // ADPCM Accelerator reads + return dsp_read_accelerator(); + + case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda" + return dsp_read_aram_d3(); + + default: + if ((addr & 0xff) >= 0xa0) { + if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) { + INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, g_dsp.ifx_regs[addr & 0xFF]); + } + else { + ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); + } + } + else { + ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); + } + return g_dsp.ifx_regs[addr & 0xFF]; + } +} + +void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) +{ + UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + + u8* dst = ((u8*)g_dsp.iram); + for (u32 i = 0; i < size; i += 2) + { + // TODO : this may be different on Wii. + *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); + } + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + + g_dsp.iram_crc = DSPHost_CodeLoaded(g_dsp.cpu_ram + (addr & 0x0fffffff), size); + + NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); + + if (dspjit) + dspjit->ClearIRAM(); + + DSPAnalyzer::Analyze(); +} + + +void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size) +{ + ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); +} + +static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405L, 0x02030001L); + +// TODO: These should eat clock cycles. +void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) +{ + u8* dst = ((u8*)g_dsp.dram); + +#if _M_SSE >= 0x301 + if (cpu_info.bSSSE3 && !(size % 16)) + { + for (u32 i = 0; i < size; i += 16) + { + _mm_storeu_si128((__m128i *)&dst[dsp_addr + i], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]), s_mask)); + } + } + else +#endif + { + for (u32 i = 0; i < size; i += 2) + { + *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]); + } + } + INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)", addr, dsp_addr / 2, size); +} + + +void gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) +{ + const u8* src = ((const u8*)g_dsp.dram); + +#if _M_SSE >= 0x301 + if (cpu_info.bSSSE3 && !(size % 16)) + { + for (u32 i = 0; i < size; i += 16) + { + _mm_storeu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&src[dsp_addr + i]), s_mask)); + } + } + else +#endif + { + for (u32 i = 0; i < size; i += 2) + { + *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF] = Common::swap16(*(const u16*)&src[dsp_addr + i]); + } + } + + INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); +} + +void gdsp_do_dma() +{ + u16 ctl; + u32 addr; + u16 dsp_addr; + u16 len; + + addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL]; + ctl = g_dsp.ifx_regs[DSP_DSCR]; + dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2; + len = g_dsp.ifx_regs[DSP_DSBL]; + + if (len > 0x4000) + { + ERROR_LOG(DSPLLE, "DMA ERROR pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); + exit(0); + } +#if defined(_DEBUG) || defined(DEBUGFAST) + DEBUG_LOG(DSPLLE, "DMA pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); +#endif + switch (ctl & 0x3) + { + case (DSP_CR_DMEM | DSP_CR_TO_CPU): + gdsp_ddma_out(dsp_addr, addr, len); + break; + + case (DSP_CR_DMEM | DSP_CR_FROM_CPU): + gdsp_ddma_in(dsp_addr, addr, len); + break; + + case (DSP_CR_IMEM | DSP_CR_TO_CPU): + gdsp_idma_out(dsp_addr, addr, len); + break; + + case (DSP_CR_IMEM | DSP_CR_FROM_CPU): + gdsp_idma_in(dsp_addr, addr, len); + break; + } +} diff --git a/Source/Core/Core/Src/DSP/DSPHWInterface.h b/Source/Core/Core/Src/DSP/DSPHWInterface.h new file mode 100644 index 0000000000..df83f61e4b --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPHWInterface.h @@ -0,0 +1,47 @@ +/*==================================================================== + + filename: gdsp_interface.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _GDSP_INTERFACE_H +#define _GDSP_INTERFACE_H + +#include "Common.h" + +#define GDSP_MBOX_CPU 0 +#define GDSP_MBOX_DSP 1 + +u32 gdsp_mbox_peek(u8 mbx); +void gdsp_mbox_write_h(u8 mbx, u16 val); +void gdsp_mbox_write_l(u8 mbx, u16 val); +u16 gdsp_mbox_read_h(u8 mbx); +u16 gdsp_mbox_read_l(u8 mbx); + +void gdsp_ifx_init(); + +void gdsp_ifx_write(u32 addr, u32 val); +u16 gdsp_ifx_read(u16 addr); + +void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size); + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPHost.h b/Source/Core/Core/Src/DSP/DSPHost.h new file mode 100644 index 0000000000..b3361f50e1 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPHost.h @@ -0,0 +1,34 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPHOST_H +#define _DSPHOST_H + +// The user of the DSPCore library must supply a few functions so that the +// emulation core can access the environment it runs in. If the emulation +// core isn't used, for example in an asm/disasm tool, then most of these +// can be stubbed out. + +u8 DSPHost_ReadHostMemory(u32 addr); +void DSPHost_WriteHostMemory(u8 value, u32 addr); +bool DSPHost_OnThread(); +bool DSPHost_Running(); +void DSPHost_InterruptRequest(); +u32 DSPHost_CodeLoaded(const u8 *ptr, int size); +void DSPHost_UpdateDebugger(); + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPIntCCUtil.cpp b/Source/Core/Core/Src/DSP/DSPIntCCUtil.cpp new file mode 100644 index 0000000000..644ce60663 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPIntCCUtil.cpp @@ -0,0 +1,197 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// HELPER FUNCTIONS + +#include "DSPIntCCUtil.h" +#include "DSPCore.h" +#include "DSPInterpreter.h" + +namespace DSPInterpreter { + +void Update_SR_Register64(s64 _Value, bool carry, bool overflow) +{ + g_dsp.r.sr &= ~SR_CMP_MASK; + + // 0x01 + if (carry) + { + g_dsp.r.sr |= SR_CARRY; + } + + // 0x02 and 0x80 + if (overflow) + { + g_dsp.r.sr |= SR_OVERFLOW; + g_dsp.r.sr |= SR_OVERFLOW_STICKY; + } + + // 0x04 + if (_Value == 0) + { + g_dsp.r.sr |= SR_ARITH_ZERO; + } + + // 0x08 + if (_Value < 0) + { + g_dsp.r.sr |= SR_SIGN; + } + + // 0x10 + if (_Value != (s32)_Value) + { + g_dsp.r.sr |= SR_OVER_S32; + } + + // 0x20 - Checks if top bits of m are equal + if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) + { + g_dsp.r.sr |= SR_TOP2BITS; + } +} + + +void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) +{ + g_dsp.r.sr &= ~SR_CMP_MASK; + + // 0x01 + if (carry) + { + g_dsp.r.sr |= SR_CARRY; + } + + // 0x02 and 0x80 + if (overflow) + { + g_dsp.r.sr |= SR_OVERFLOW; + g_dsp.r.sr |= SR_OVERFLOW_STICKY; + } + + // 0x04 + if (_Value == 0) + { + g_dsp.r.sr |= SR_ARITH_ZERO; + } + + // 0x08 + if (_Value < 0) + { + g_dsp.r.sr |= SR_SIGN; + } + + // 0x10 + if (overS32) + { + g_dsp.r.sr |= SR_OVER_S32; + } + + // 0x20 - Checks if top bits of m are equal + if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + { + g_dsp.r.sr |= SR_TOP2BITS; + } +} + +void Update_SR_LZ(bool value) +{ + if (value == true) + g_dsp.r.sr |= SR_LOGIC_ZERO; + else + g_dsp.r.sr &= ~SR_LOGIC_ZERO; +} + +inline int GetMultiplyModifier() +{ + return (g_dsp.r.sr & SR_MUL_MODIFY)?1:2; +} + +inline bool isCarry() { + return (g_dsp.r.sr & SR_CARRY) ? true : false; +} + +inline bool isOverflow() { + return (g_dsp.r.sr & SR_OVERFLOW) ? true : false; +} + +inline bool isOverS32() { + return (g_dsp.r.sr & SR_OVER_S32) ? true : false; +} + +inline bool isLess() { + return (!(g_dsp.r.sr & SR_OVERFLOW) != !(g_dsp.r.sr & SR_SIGN)); +} + +inline bool isZero() { + return (g_dsp.r.sr & SR_ARITH_ZERO) ? true : false; +} + +inline bool isLogicZero() { + return (g_dsp.r.sr & SR_LOGIC_ZERO) ? true : false; +} + +inline bool isConditionA() { + return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) && !(g_dsp.r.sr & SR_ARITH_ZERO)) ? true : false; +} + +//see DSPCore.h for flags +bool CheckCondition(u8 _Condition) +{ + switch (_Condition & 0xf) + { + case 0xf: // Always true. + return true; + case 0x0: // GE - Greater Equal + return !isLess(); + case 0x1: // L - Less + return isLess(); + case 0x2: // G - Greater + return !isLess() && !isZero(); + case 0x3: // LE - Less Equal + return isLess() || isZero(); + case 0x4: // NZ - Not Zero + return !isZero(); + case 0x5: // Z - Zero + return isZero(); + case 0x6: // NC - Not carry + return !isCarry(); + case 0x7: // C - Carry + return isCarry(); + case 0x8: // ? - Not over s32 + return !isOverS32(); + case 0x9: // ? - Over s32 + return isOverS32(); + case 0xa: // ? + return isConditionA(); + case 0xb: // ? + return !isConditionA(); + case 0xc: // LNZ - Logic Not Zero + return !isLogicZero(); + case 0xd: // LZ - Logic Zero + return isLogicZero(); + case 0xe: // 0 - Overflow + return isOverflow(); + default: + return true; + } +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DSPIntCCUtil.h b/Source/Core/Core/Src/DSP/DSPIntCCUtil.h new file mode 100644 index 0000000000..0684cea2ba --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPIntCCUtil.h @@ -0,0 +1,55 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#ifndef _GDSP_CONDITION_CODES_H +#define _GDSP_CONDITION_CODES_H + +// Anything to do with SR and conditions goes here. + +#include "Common.h" + +namespace DSPInterpreter { + +bool CheckCondition(u8 _Condition); + +int GetMultiplyModifier(); + +void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, bool overS32 = false); +void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false); +void Update_SR_LZ(bool value); + +inline bool isCarry(u64 val, u64 result) { + return (val>result); +} + +inline bool isCarry2(u64 val, u64 result) { + return (val>=result); +} + +inline bool isOverflow(s64 val1, s64 val2, s64 res) { + return ((val1 ^ res) & (val2 ^ res)) < 0; +} + +inline bool isOverS32(s64 acc) { + return (acc != (s32)acc) ? true : false; +} + +} // namespace + +#endif // _GDSP_CONDITION_CODES_H diff --git a/Source/Core/Core/Src/DSP/DSPIntExtOps.cpp b/Source/Core/Core/Src/DSP/DSPIntExtOps.cpp new file mode 100644 index 0000000000..11eca9abac --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPIntExtOps.cpp @@ -0,0 +1,526 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ +#include "DSPIntUtil.h" +#include "DSPMemoryMap.h" +#include "DSPIntExtOps.h" + +// Extended opcodes do not exist on their own. These opcodes can only be +// attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by +// opcode). Extended opcodes do not modify program counter $pc register. + +// Most of the suffixes increment or decrement one or more addressing registers +// (the first four, ARx). The increment/decrement is either 1, or the +// corresponding "index" register (the second four, IXx). The addressing +// registers will wrap in odd ways, dictated by the corresponding wrapping +// register, WR0-3. + +// Needs comments. +inline static void writeToBackLog(int i, int idx, u16 value) +{ + writeBackLog[i] = value; + writeBackLogIdx[i] = idx; +} + +namespace DSPInterpreter +{ + +namespace Ext +{ + +inline bool IsSameMemArea(u16 a, u16 b) +{ +//LM: tested on WII + if ((a>>10)==(b>>10)) + return true; + else + return false; +} + +// DR $arR +// xxxx xxxx 0000 01rr +// Decrement addressing register $arR. +void dr(const UDSPInstruction opc) { + writeToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3)); +} + +// IR $arR +// xxxx xxxx 0000 10rr +// Increment addressing register $arR. +void ir(const UDSPInstruction opc) { + writeToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3)); +} + +// NR $arR +// xxxx xxxx 0000 11rr +// Add corresponding indexing register $ixR to addressing register $arR. +void nr(const UDSPInstruction opc) { + u8 reg = opc & 0x3; + + writeToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg])); +} + +// MV $axD.D, $acS.S +// xxxx xxxx 0001 ddss +// Move value of $acS.S to the $axD.D. +void mv(const UDSPInstruction opc) +{ + u8 sreg = (opc & 0x3) + DSP_REG_ACL0; + u8 dreg = ((opc >> 2) & 0x3); + + switch(sreg) { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg-DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg-DSP_REG_ACM0].m); + break; + } +} + +// S @$arD, $acS.S +// xxxx xxxx 001s s0dd +// Store value of $acS.S in the memory pointed by register $arD. +// Post increment register $arD. +void s(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + + switch(sreg) { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACM0].m); + break; + } + writeToBackLog(0, dreg, dsp_increment_addr_reg(dreg)); +} + +// SN @$arD, $acS.S +// xxxx xxxx 001s s1dd +// Store value of register $acS.S in the memory pointed by register $arD. +// Add indexing register $ixD to register $arD. +void sn(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + + switch(sreg) { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACM0].m); + break; + } + writeToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); +} + +// L $axD.D, @$arS +// xxxx xxxx 01dd d0ss +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Post increment register $arS. +void l(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + + if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) + { + u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); + writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); + writeToBackLog(1, dreg, val); + writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); + writeToBackLog(3, sreg, dsp_increment_addr_reg(sreg)); + } + else + { + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); + } +} + +// LN $axD.D, @$arS +// xxxx xxxx 01dd d0ss +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Add indexing register register $ixS to register $arS. +void ln(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + + if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) + { + u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); + writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); + writeToBackLog(1, dreg, val); + writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); + writeToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } + else + { + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } +} + +// LS $axD.D, $acS.m108 +// xxxx xxxx 10dd 000s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Increment both $ar0 and $ar3. +void ls(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); +} + + +// LSN $axD.D, $acS.m +// xxxx xxxx 10dd 010s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix0 to addressing +// register $ar0 and increment $ar3. +void lsn(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); +} + +// LSM $axD.D, $acS.m +// xxxx xxxx 10dd 100s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix3 to addressing +// register $ar3 and increment $ar0. +void lsm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); +} + +// LSMN $axD.D, $acS.m +// xxxx xxxx 10dd 110s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix0 to addressing +// register $ar0 and add corresponding indexing register $ix3 to addressing +// register $ar3. +void lsnm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); +} + +// SL $acS.m, $axD.D +// xxxx xxxx 10dd 001s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Increment both $ar0 and $ar3. +void sl(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); +} + +// SLN $acS.m, $axD.D +// xxxx xxxx 10dd 011s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 +// and increment $ar3. +void sln(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); +} + +// SLM $acS.m, $axD.D +// xxxx xxxx 10dd 101s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3 +// and increment $ar0. +void slm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); +} + +// SLMN $acS.m, $axD.D +// xxxx xxxx 10dd 111s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 +// and add corresponding indexing register $ix3 to addressing register $ar3. +void slnm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + + dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); + + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); +} + +// LD $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 00ss +// example for "nx'ld $AX0.L, $AX1.L, @$AR3" +// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L. +// Increments AR0 and AR3. +// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are not doing that!) +// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. +// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not implemented yet) +// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not implemented yet) +void ld(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + } else { + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); + + if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); + } + + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); +} + +// LDN $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 01ss +void ldn(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } else { + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); + + if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); + } + + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); +} + +// LDM $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 10ss +void ldm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + } else { + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); + + if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); + } + + writeToBackLog(3, DSP_REG_AR3, + dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); +} + +// LDNM $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 11ss +void ldnm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } else { + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); + + if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + + writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); + } + + writeToBackLog(3, DSP_REG_AR3, + dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); +} + + +void nop(const UDSPInstruction opc) +{ +} + +} // end namespace ext +} // end namespace DSPInterpeter + + +// The ext ops are calculated in parallel with the actual op. That means that +// both the main op and the ext op see the same register state as input. The +// output is simple as long as the main and ext ops don't change the same +// register. If they do the output is the bitwise or of the result of both the +// main and ext ops. + +// The ext op are writing their output into the backlog which is +// being applied to the real registers after the main op was executed +void applyWriteBackLog() +{ + // always make sure to have an extra entry at the end w/ -1 to avoid + // infinitive loops + for (int i = 0; writeBackLogIdx[i] != -1; i++) { + dsp_op_write_reg(writeBackLogIdx[i], dsp_op_read_reg(writeBackLogIdx[i]) | writeBackLog[i]); + // Clear back log + writeBackLogIdx[i] = -1; + } +} + +// This function is being called in the main op after all input regs were read +// and before it writes into any regs. This way we can always use bitwise or to +// apply the ext command output, because if the main op didn't change the value +// then 0 | ext output = ext output and if it did then bitwise or is still the +// right thing to do +void zeroWriteBackLog() +{ + // always make sure to have an extra entry at the end w/ -1 to avoid + // infinitive loops + for (int i = 0; writeBackLogIdx[i] != -1; i++) { + dsp_op_write_reg(writeBackLogIdx[i], 0); + } +} + +//needed for 0x3... cases when main and extended are modifying the same ACC +//games are not doing that + in motorola (similar dsp) dox this is forbidden to do +//ex. corner case -> 0x3060: main opcode modifies .m, and extended .l -> .l shoudnt be zeroed because of .m write... +void zeroWriteBackLogPreserveAcc(u8 acc) +{ + for (int i = 0; writeBackLogIdx[i] != -1; i++) { + + // acc0 + if ((acc == 0) && + ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || (writeBackLogIdx[i] == DSP_REG_ACH0))) + continue; + + // acc1 + if ((acc == 1) && + ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) || (writeBackLogIdx[i] == DSP_REG_ACH1))) + continue; + + dsp_op_write_reg(writeBackLogIdx[i], 0); + } +} diff --git a/Source/Core/Core/Src/DSP/DSPIntExtOps.h b/Source/Core/Core/Src/DSP/DSPIntExtOps.h new file mode 100644 index 0000000000..46b809ca14 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPIntExtOps.h @@ -0,0 +1,64 @@ +/*==================================================================== + + filename: opcodes.h + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _GDSP_EXT_OP_H +#define _GDSP_EXT_OP_H + +#include "DSPTables.h" + +// Extended opcode support. +// Many opcode have the lower 0xFF (some only 0x7f) free - there, an opcode extension +// can be stored. + +namespace DSPInterpreter +{ +namespace Ext +{ +void l(const UDSPInstruction opc); +void ln(const UDSPInstruction opc); +void ls(const UDSPInstruction opc); +void lsn(const UDSPInstruction opc); +void lsm(const UDSPInstruction opc); +void lsnm(const UDSPInstruction opc); +void sl(const UDSPInstruction opc); +void sln(const UDSPInstruction opc); +void slm(const UDSPInstruction opc); +void slnm(const UDSPInstruction opc); +void s(const UDSPInstruction opc); +void sn(const UDSPInstruction opc); +void ld(const UDSPInstruction opc); +void ldn(const UDSPInstruction opc); +void ldm(const UDSPInstruction opc); +void ldnm(const UDSPInstruction opc); +void mv(const UDSPInstruction opc); +void dr(const UDSPInstruction opc); +void ir(const UDSPInstruction opc); +void nr(const UDSPInstruction opc); +void nop(const UDSPInstruction opc); + +} // end namespace Ext +} // end namespace DSPinterpeter + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPIntUtil.h b/Source/Core/Core/Src/DSP/DSPIntUtil.h new file mode 100644 index 0000000000..712d79fdf8 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPIntUtil.h @@ -0,0 +1,386 @@ +/*==================================================================== + + filename: gdsp_opcodes_helper.h + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSP_INT_UTIL_H +#define _DSP_INT_UTIL_H + +#include "Common.h" + +#include "DSPInterpreter.h" +#include "DSPCore.h" +#include "DSPMemoryMap.h" +#include "DSPStacks.h" + + +// --------------------------------------------------------------------------------------- +// --- SR +// --------------------------------------------------------------------------------------- + +inline void dsp_SR_set_flag(int flag) +{ + g_dsp.r.sr |= flag; +} + +inline bool dsp_SR_is_flag_set(int flag) +{ + return (g_dsp.r.sr & flag) != 0; +} + +// --------------------------------------------------------------------------------------- +// --- AR increments, decrements +// --------------------------------------------------------------------------------------- + +inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix) +{ + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + s32 ix = _ix; + + u32 mx = (wr | 1) << 1; + u32 nar = ar + ix; + u32 dar = (nar ^ ar ^ ix) & mx; + + if (ix >= 0) + { + if (dar > wr) //overflow + nar -= wr + 1; + } + else + { + if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask + nar += wr + 1; + } + return nar; +} + +inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix) +{ + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + s32 ix = _ix; + + u32 mx = (wr | 1) << 1; + u32 nar = ar - ix; + u32 dar = (nar ^ ar ^ ~ix) & mx; + + if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000) + { + if (dar > wr) //overflow + nar -= wr + 1; + } + else + { + if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask + nar += wr + 1; + } + return nar; +} + +inline u16 dsp_increment_addr_reg(u16 reg) +{ + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + + u32 nar = ar + 1; + + if ((nar ^ ar) > ((wr | 1) << 1)) + nar -= wr + 1; + return nar; +} + +inline u16 dsp_decrement_addr_reg(u16 reg) +{ + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + + u32 nar = ar + wr; + + if (((nar ^ ar) & ((wr | 1) << 1)) > wr) + nar -= wr + 1; + return nar; +} + + +// --------------------------------------------------------------------------------------- +// --- reg +// --------------------------------------------------------------------------------------- + +inline u16 dsp_op_read_reg(int reg) +{ + switch (reg & 0x1f) { + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return dsp_reg_load_stack(reg - DSP_REG_ST0); + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: return g_dsp.r.cr; + case DSP_REG_SR: return g_dsp.r.sr; + case DSP_REG_PRODL: return g_dsp.r.prod.l; + case DSP_REG_PRODM: return g_dsp.r.prod.m; + case DSP_REG_PRODH: return g_dsp.r.prod.h; + case DSP_REG_PRODM2: return g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return g_dsp.r.ac[reg - DSP_REG_ACM0].m; + default: + _assert_msg_(DSP_INT, 0, "cannot happen"); + return 0; + } +} + +inline void dsp_op_write_reg(int reg, u16 val) +{ + switch (reg & 0x1f) { + // 8-bit sign extended registers. Should look at prod.h too... + case DSP_REG_ACH0: + case DSP_REG_ACH1: + // sign extend from the bottom 8 bits. + g_dsp.r.ac[reg-DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val; + break; + + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack(reg - DSP_REG_ST0, val); + break; + + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + g_dsp.r.ar[reg - DSP_REG_AR0] = val; + break; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + g_dsp.r.ix[reg - DSP_REG_IX0] = val; + break; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + g_dsp.r.wr[reg - DSP_REG_WR0] = val; + break; + case DSP_REG_CR: g_dsp.r.cr = val; break; + case DSP_REG_SR: g_dsp.r.sr = val; break; + case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; + case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; + case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; + case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; + break; + } +} + +inline void dsp_conditional_extend_accum(int reg) +{ + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + if (g_dsp.r.sr & SR_40_MODE_BIT) + { + // Sign extend into whole accum. + u16 val = g_dsp.r.ac[reg-DSP_REG_ACM0].m; + g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000; + g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0; + } + } +} + +// --------------------------------------------------------------------------------------- +// --- prod +// --------------------------------------------------------------------------------------- + +inline s64 dsp_get_long_prod() +{ +#if PROFILE + ProfilerAddDelta(g_dsp.err_pc, 1); +#endif + + s64 val = (s8)(u8)g_dsp.r.prod.h; + val <<= 32; + s64 low_prod = g_dsp.r.prod.m; + low_prod += g_dsp.r.prod.m2; + low_prod <<= 16; + low_prod |= g_dsp.r.prod.l; + val += low_prod; + return val; +} + +inline s64 dsp_get_long_prod_round_prodl() +{ + s64 prod = dsp_get_long_prod(); + + if (prod & 0x10000) + prod = (prod + 0x8000) & ~0xffff; + else + prod = (prod + 0x7fff) & ~0xffff; + + return prod; +} + +// For accurate emulation, this is wrong - but the real prod registers behave +// in completely bizarre ways. Not needed to emulate them correctly for game ucodes. +inline void dsp_set_long_prod(s64 val) +{ +#if PROFILE + ProfilerAddDelta(g_dsp.err_pc, 1); +#endif + + g_dsp.r.prod.l = (u16)val; + val >>= 16; + g_dsp.r.prod.m = (u16)val; + val >>= 16; + g_dsp.r.prod.h = /*(s16)(s8)*/(u8)val;//todo: check expansion + g_dsp.r.prod.m2 = 0; +} + +// --------------------------------------------------------------------------------------- +// --- ACC - main accumulators (40-bit) +// --------------------------------------------------------------------------------------- + +inline s64 dsp_get_long_acc(int reg) +{ +#if PROFILE + ProfilerAddDelta(g_dsp.err_pc, 1); +#endif + + s64 high = (s64)(s8)g_dsp.r.ac[reg].h << 32; + u32 mid_low = ((u32)g_dsp.r.ac[reg].m << 16) | g_dsp.r.ac[reg].l; + return high | mid_low; +} + +inline void dsp_set_long_acc(int _reg, s64 val) +{ +#if PROFILE + ProfilerAddDelta(g_dsp.err_pc, 1); +#endif + + g_dsp.r.ac[_reg].l = (u16)val; + val >>= 16; + g_dsp.r.ac[_reg].m = (u16)val; + val >>= 16; + g_dsp.r.ac[_reg].h = (u16)(s16)(s8)(u8)val; +} + +inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 +{ + return ((s64)(s8)(val >> 32))<<32 | (u32)val; +} + +inline s64 dsp_round_long_acc(s64 val) +{ + if (val & 0x10000) + val = (val + 0x8000) & ~0xffff; + else + val = (val + 0x7fff) & ~0xffff; + + return val; +} + +inline s16 dsp_get_acc_l(int _reg) +{ + return g_dsp.r.ac[_reg].l; +} + +inline s16 dsp_get_acc_m(int _reg) +{ + return g_dsp.r.ac[_reg].m; +} + +inline s16 dsp_get_acc_h(int _reg) +{ + return g_dsp.r.ac[_reg].h; +} + +// --------------------------------------------------------------------------------------- +// --- AX - extra accumulators (32-bit) +// --------------------------------------------------------------------------------------- + +inline s32 dsp_get_long_acx(int _reg) +{ +#if PROFILE + ProfilerAddDelta(g_dsp.err_pc, 1); +#endif + + return ((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l; +} + +inline s16 dsp_get_ax_l(int _reg) +{ + return (s16)g_dsp.r.ax[_reg].l; +} + +inline s16 dsp_get_ax_h(int _reg) +{ + return (s16)g_dsp.r.ax[_reg].h; +} + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPInterpreter.cpp b/Source/Core/Core/Src/DSP/DSPInterpreter.cpp new file mode 100644 index 0000000000..56e1834b9f --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPInterpreter.cpp @@ -0,0 +1,261 @@ +/*==================================================================== + + filename: gdsp_interpreter.cpp + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "DSPTables.h" +#include "DSPHost.h" +#include "DSPCore.h" +#include "DSPAnalyzer.h" + +#include "DSPHWInterface.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +volatile u32 gdsp_running; + +// NOTE: These have nothing to do with g_dsp.r[DSP_REG_CR]. + +// Hm, should instructions that change CR use this? Probably not (but they +// should call UpdateCachedCR()) +void WriteCR(u16 val) +{ + // reset + if (val & 1) + { + DSPCore_Reset(); + val &= ~1; + } + // init - can reset and init be done at the same time? + else if (val == 4) + { + // this looks like a hack! OSInitAudioSystem ucode + // should send this mail - not dsp core itself + gdsp_mbox_write_h(GDSP_MBOX_DSP, 0x8054); + gdsp_mbox_write_l(GDSP_MBOX_DSP, 0x4348); + val |= 0x800; + } + + // update cr + g_dsp.cr = val; +} + +// Hm, should instructions that read CR use this? (Probably not). +u16 ReadCR() +{ + if (g_dsp.pc & 0x8000) + { + g_dsp.cr |= 0x800; + } + else + { + g_dsp.cr &= ~0x800; + } + + return g_dsp.cr; +} + +void Step() +{ + DSPCore_CheckExceptions(); + + g_dsp.step_counter++; + +#if PROFILE + g_dsp.err_pc = g_dsp.pc; + + ProfilerAddDelta(g_dsp.err_pc, 1); + if (g_dsp.step_counter == 1) + { + ProfilerInit(); + } + + if ((g_dsp.step_counter & 0xFFFFF) == 0) + { + ProfilerDump(g_dsp.step_counter); + } +#endif + + u16 opc = dsp_fetch_code(); + ExecuteInstruction(UDSPInstruction(opc)); + + if (DSPAnalyzer::code_flags[g_dsp.pc - 1] & DSPAnalyzer::CODE_LOOP_END) + HandleLoop(); +} + +// Used by thread mode. +//void Run() +//{ +// int checkInterrupt = 0; +// gdsp_running = true; +// while (!(g_dsp.cr & CR_HALT) && gdsp_running) +// { +// if (jit) +// jit->RunForCycles(1); +// else { +// // Automatically let the other threads work if we're idle skipping +// if(DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) +// Common::YieldCPU(); +// +// Step(); +// +// // Turns out the less you check for external interrupts, the more +// // sound you hear, and it becomes slower +// checkInterrupt++; +// if(checkInterrupt == 500) { // <-- Arbitrary number. TODO: tweak +// DSPCore_CheckExternalInterrupt(); +// checkInterrupt = 0; +// } +// } +// } +// gdsp_running = false; +//} + +// This one has basic idle skipping, and checks breakpoints. +int RunCyclesDebug(int cycles) +{ + // First, let's run a few cycles with no idle skipping so that things can progress a bit. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + Step(); + cycles--; + if (cycles < 0) + return 0; + } + + // In thread mode, process external interrupts + if (g_dsp.external_interrupt_waiting) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_CheckExceptions(); + DSPCore_SetExternalInterrupt(false); + } + + while (true) + { + // Next, let's run a few cycles with idle skipping, so that we can skip + // idle loops. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + // Idle skipping. + if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } + + // Now, lets run some more without idle skipping. + for (int i = 0; i < 200; i++) + { + if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + Step(); + cycles--; + if (cycles < 0) + return 0; + + // We don't bother directly supporting pause - if the main emu pauses, + // it just won't call this function anymore. + } + } +} + +// Used by non-thread mode. Meant to be efficient. +int RunCycles(int cycles) +{ + // First, let's run a few cycles with no idle skipping so that things can + // progress a bit. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } + + // In thread mode, process external interrupts + if (g_dsp.external_interrupt_waiting) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_CheckExceptions(); + DSPCore_SetExternalInterrupt(false); + } + + while (true) + { + // Next, let's run a few cycles with idle skipping, so that we can skip + // idle loops. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + // Idle skipping. + if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } + + // Now, lets run some more without idle skipping. + for (int i = 0; i < 200; i++) + { + Step(); + cycles--; + if (cycles < 0) + return 0; + // We don't bother directly supporting pause - if the main emu pauses, + // it just won't call this function anymore. + } + } +} + +void Stop() +{ + gdsp_running = false; +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DSPInterpreter.h b/Source/Core/Core/Src/DSP/DSPInterpreter.h new file mode 100644 index 0000000000..35db43f5f2 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPInterpreter.h @@ -0,0 +1,170 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPINTERPRETER_H +#define _DSPINTERPRETER_H + +#include "DSPTables.h" + +#define DSP_REG_MASK 0x1f + +namespace DSPInterpreter { + +void Step(); +void Run(); + +// See: DspIntBranch.cpp +void HandleLoop(); + +// If these simply return the same number of cycles as was passed into them, +// chances are that the DSP is halted. +// The difference between them is that the debug one obeys breakpoints. +int RunCycles(int cycles); +int RunCyclesDebug(int cycles); + +void Stop(); + +void WriteCR(u16 val); +u16 ReadCR(); + + +typedef void (*DSPInterpreterFunc)(const UDSPInstruction opc); + +// All the opcode functions. +void unknown(const UDSPInstruction opc); +void call(const UDSPInstruction opc); +void callr(const UDSPInstruction opc); +void ifcc(const UDSPInstruction opc); +void jcc(const UDSPInstruction opc); +void jmprcc(const UDSPInstruction opc); +void ret(const UDSPInstruction opc); +void halt(const UDSPInstruction opc); +void loop(const UDSPInstruction opc); +void loopi(const UDSPInstruction opc); +void bloop(const UDSPInstruction opc); +void bloopi(const UDSPInstruction opc); +void mrr(const UDSPInstruction opc); +void lrr(const UDSPInstruction opc); +void lrrd(const UDSPInstruction opc); +void lrri(const UDSPInstruction opc); +void lrrn(const UDSPInstruction opc); +void srr(const UDSPInstruction opc); +void srrd(const UDSPInstruction opc); +void srri(const UDSPInstruction opc); +void srrn(const UDSPInstruction opc); +void lri(const UDSPInstruction opc); +void lris(const UDSPInstruction opc); +void lr(const UDSPInstruction opc); +void sr(const UDSPInstruction opc); +void si(const UDSPInstruction opc); +void tstaxh(const UDSPInstruction opc); +void clr(const UDSPInstruction opc); +void clrl(const UDSPInstruction opc); +void clrp(const UDSPInstruction opc); +void mulc(const UDSPInstruction opc); +void cmpar(const UDSPInstruction opc); +void cmp(const UDSPInstruction opc); +void tst(const UDSPInstruction opc); +void addaxl(const UDSPInstruction opc); +void addarn(const UDSPInstruction opc); +void mulcac(const UDSPInstruction opc); +void movr(const UDSPInstruction opc); +void movax(const UDSPInstruction opc); +void xorr(const UDSPInstruction opc); +void andr(const UDSPInstruction opc); +void orr(const UDSPInstruction opc); +void andc(const UDSPInstruction opc); +void orc(const UDSPInstruction opc); +void xorc(const UDSPInstruction opc); +void notc(const UDSPInstruction opc); +void lsrnrx(const UDSPInstruction opc); +void asrnrx(const UDSPInstruction opc); +void lsrnr(const UDSPInstruction opc); +void asrnr(const UDSPInstruction opc); +void add(const UDSPInstruction opc); +void addp(const UDSPInstruction opc); +void cmpis(const UDSPInstruction opc); +void addpaxz(const UDSPInstruction opc); +void movpz(const UDSPInstruction opc); +void decm(const UDSPInstruction opc); +void dec(const UDSPInstruction opc); +void inc(const UDSPInstruction opc); +void incm(const UDSPInstruction opc); +void neg(const UDSPInstruction opc); +void addax(const UDSPInstruction opc); +void addr(const UDSPInstruction opc); +void subr(const UDSPInstruction opc); +void subp(const UDSPInstruction opc); +void subax(const UDSPInstruction opc); +void addis(const UDSPInstruction opc); +void addi(const UDSPInstruction opc); +void lsl16(const UDSPInstruction opc); +void madd(const UDSPInstruction opc); +void msub(const UDSPInstruction opc); +void lsr16(const UDSPInstruction opc); +void asr16(const UDSPInstruction opc); +void lsl(const UDSPInstruction opc); +void lsr(const UDSPInstruction opc); +void asl(const UDSPInstruction opc); +void asr(const UDSPInstruction opc); +void lsrn(const UDSPInstruction opc); +void asrn(const UDSPInstruction opc); +void dar(const UDSPInstruction opc); +void iar(const UDSPInstruction opc); +void subarn(const UDSPInstruction opc); +void sbclr(const UDSPInstruction opc); +void sbset(const UDSPInstruction opc); +void mov(const UDSPInstruction opc); +void movp(const UDSPInstruction opc); +void mul(const UDSPInstruction opc); +void mulac(const UDSPInstruction opc); +void mulmv(const UDSPInstruction opc); +void mulmvz(const UDSPInstruction opc); +void mulx(const UDSPInstruction opc); +void mulxac(const UDSPInstruction opc); +void mulxmv(const UDSPInstruction opc); +void mulxmvz(const UDSPInstruction opc); +void mulcmvz(const UDSPInstruction opc); +void mulcmv(const UDSPInstruction opc); +void movnp(const UDSPInstruction opc); +void sub(const UDSPInstruction opc); +void maddx(const UDSPInstruction opc); +void msubx(const UDSPInstruction opc); +void maddc(const UDSPInstruction opc); +void msubc(const UDSPInstruction opc); +void srs(const UDSPInstruction opc); +void lrs(const UDSPInstruction opc); +void nx(const UDSPInstruction opc); +void cmpi(const UDSPInstruction opc); +void rti(const UDSPInstruction opc); +void ilrr(const UDSPInstruction opc); +void ilrrd(const UDSPInstruction opc); +void ilrri(const UDSPInstruction opc); +void ilrrn(const UDSPInstruction opc); +void andcf(const UDSPInstruction opc); +void andf(const UDSPInstruction opc); +void xori(const UDSPInstruction opc); +void andi(const UDSPInstruction opc); +void ori(const UDSPInstruction opc); +void srbith(const UDSPInstruction opc); +void mulaxh(const UDSPInstruction opc); +void tstprod(const UDSPInstruction opc); +void abs(const UDSPInstruction opc); + +} // namespace + +#endif // _DSPINTERPRETER_H diff --git a/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp b/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp new file mode 100644 index 0000000000..408cb48465 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp @@ -0,0 +1,83 @@ +/*==================================================================== + + filename: gdsp_memory.cpp + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "DSPInterpreter.h" +#include "DSPMemoryMap.h" +#include "DSPHWInterface.h" +#include "DSPCore.h" + +u16 dsp_imem_read(u16 addr) +{ + switch (addr >> 12) + { + case 0: // 0xxx IRAM + return g_dsp.iram[addr & DSP_IRAM_MASK]; + + case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops. + return g_dsp.irom[addr & DSP_IROM_MASK]; + + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Executing from invalid (%04x) memory", g_dsp.pc, addr); + return 0; + } +} + +u16 dsp_dmem_read(u16 addr) +{ + switch (addr >> 12) + { + case 0x0: // 0xxx DRAM + return g_dsp.dram[addr & DSP_DRAM_MASK]; + + case 0x1: // 1xxx COEF + DEBUG_LOG(DSPLLE, "%04x : Coef Read @ %04x", g_dsp.pc, addr); + return g_dsp.coef[addr & DSP_COEF_MASK]; + + case 0xf: // Fxxx HW regs + return gdsp_ifx_read(addr); + + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr); + return 0; + } +} + +void dsp_dmem_write(u16 addr, u16 val) +{ + switch (addr >> 12) + { + case 0x0: // 0xxx DRAM + g_dsp.dram[addr & DSP_DRAM_MASK] = val; + break; + + case 0xf: // Fxxx HW regs + gdsp_ifx_write(addr, val); + break; + + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, addr); + break; + } +} diff --git a/Source/Core/Core/Src/DSP/DSPMemoryMap.h b/Source/Core/Core/Src/DSP/DSPMemoryMap.h new file mode 100644 index 0000000000..8aa0d77647 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPMemoryMap.h @@ -0,0 +1,55 @@ +/*==================================================================== + + filename: gdsp_memory.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _GDSP_MEMORY_H +#define _GDSP_MEMORY_H + +#include "Common.h" +#include "DSPInterpreter.h" +#include "DSPCore.h" + +u16 dsp_imem_read(u16 addr); +void dsp_dmem_write(u16 addr, u16 val); +u16 dsp_dmem_read(u16 addr); + +inline u16 dsp_fetch_code() +{ + u16 opc = dsp_imem_read(g_dsp.pc); + + g_dsp.pc++; + return opc; +} + +inline u16 dsp_peek_code() +{ + return dsp_imem_read(g_dsp.pc); +} + +inline void dsp_skip_inst() +{ + g_dsp.pc += opTable[dsp_peek_code()]->size; +} + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPStacks.cpp b/Source/Core/Core/Src/DSP/DSPStacks.cpp new file mode 100644 index 0000000000..5bdae0241f --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPStacks.cpp @@ -0,0 +1,58 @@ +/*==================================================================== + + filename: gdsp_registers.cpp + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include "Common.h" + +#include "DSPCore.h" +#include "DSPStacks.h" + +// Stacks. The stacks are outside the DSP RAM, in dedicated hardware. + +void dsp_reg_stack_push(int stack_reg) +{ + g_dsp.reg_stack_ptr[stack_reg]++; + g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r.st[stack_reg]; +} + +void dsp_reg_stack_pop(int stack_reg) +{ + g_dsp.r.st[stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; + g_dsp.reg_stack_ptr[stack_reg]--; + g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; +} + +void dsp_reg_store_stack(int stack_reg, u16 val) +{ + dsp_reg_stack_push(stack_reg); + g_dsp.r.st[stack_reg] = val; +} + +u16 dsp_reg_load_stack(int stack_reg) +{ + u16 val = g_dsp.r.st[stack_reg]; + dsp_reg_stack_pop(stack_reg); + return val; +} diff --git a/Source/Core/Core/Src/DSP/DSPStacks.h b/Source/Core/Core/Src/DSP/DSPStacks.h new file mode 100644 index 0000000000..1a5b9e872c --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPStacks.h @@ -0,0 +1,34 @@ +/*==================================================================== + + filename: gdsp_registers.h + project: GCemu + created: 2004-6-18 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie & Tratax + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSP_STACKS_H +#define _DSP_STACKS_H + +#include "Common.h" + +void dsp_reg_store_stack(int stack_reg, u16 val); +u16 dsp_reg_load_stack(int stack_reg); + +#endif diff --git a/Source/Core/Core/Src/DSP/DSPTables.cpp b/Source/Core/Core/Src/DSP/DSPTables.cpp new file mode 100644 index 0000000000..80da03c190 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPTables.cpp @@ -0,0 +1,568 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +#include "Common.h" +#include "DSPTables.h" + +#include "DSPInterpreter.h" +#include "DSPIntExtOps.h" +#include "DSPEmitter.h" + +void nop(const UDSPInstruction opc) +{ + // The real nop is 0. Anything else is bad. + if (opc) + DSPInterpreter::unknown(opc); +} + +const DSPOPCTemplate opcodes[] = +{ + {"NOP", 0x0000, 0xfffc, nop, &DSPEmitter::nop, 1, 0, {}, false, false, false, false, false}, + + {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, &DSPEmitter::dar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, &DSPEmitter::iar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"SUBARN", 0x000c, 0xfffc, DSPInterpreter::subarn, &DSPEmitter::subarn, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, &DSPEmitter::addarn, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, false, false, false, false, false}, + + {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, &DSPEmitter::halt, 1, 0, {}, false, true, true, false, false}, + + {"RETGE", 0x02d0, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETL", 0x02d1, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, + {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETNC", 0x02d6, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETC", 0x02d7, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETx8", 0x02d8, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETx9", 0x02d9, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETxA", 0x02da, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, + {"RETxB", 0x02db, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, + {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RETO", 0x02de, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, + {"RET", 0x02df, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, true, false, false}, + + {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, &DSPEmitter::rti, 1, 0, {}, false, true, true, false, false}, + + {"CALLGE", 0x02b0, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLL", 0x02b1, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLNZ", 0x02b4, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLNC", 0x02b6, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLC", 0x02b7, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLx8", 0x02b8, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLx9", 0x02b9, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLxA", 0x02ba, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLxB", 0x02bb, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALLO", 0x02be, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, + + {"IFGE", 0x0270, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFL", 0x0271, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, + {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFNC", 0x0276, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFC", 0x0277, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFx8", 0x0278, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFx9", 0x0279, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFxA", 0x027a, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, + {"IFxB", 0x027b, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, + {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IFO", 0x027e, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, + {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, true, true, false}, + + {"JGE", 0x0290, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JL", 0x0291, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JNC", 0x0296, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JC", 0x0297, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JMPx8", 0x0298, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JMPx9", 0x0299, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JMPxA", 0x029a, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JMPxB", 0x029b, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JO", 0x029e, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, + + {"JRGE", 0x1700, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRL", 0x1701, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRNC", 0x1706, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRC", 0x1707, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JMPRx8", 0x1708, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JMPRx9", 0x1709, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JMPRxA", 0x170a, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JMPRxB", 0x170b, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JRO", 0x170e, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, + {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, false, false}, + + {"CALLRGE", 0x1710, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRL", 0x1711, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRNC", 0x1716, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRC", 0x1717, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRx8", 0x1718, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRx9", 0x1719, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRxA", 0x171a, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRxB", 0x171b, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLRO", 0x171e, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, + {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, true, false}, + + {"SBCLR", 0x1200, 0xff00, DSPInterpreter::sbclr, &DSPEmitter::sbclr, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, + {"SBSET", 0x1300, 0xff00, DSPInterpreter::sbset, &DSPEmitter::sbset, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, + + {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, &DSPEmitter::lsl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, + {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, &DSPEmitter::lsr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, + {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, &DSPEmitter::asl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, + {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, &DSPEmitter::asr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, + + {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, &DSPEmitter::lsrn, 1, 0, {}, false, false, false, false, true}, // discovered by ector! + {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, &DSPEmitter::asrn, 1, 0, {}, false, false, false, false, true}, // discovered by ector! + + {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, &DSPEmitter::lri, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, + {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, &DSPEmitter::lr, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, + {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, &DSPEmitter::sr, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, true, false}, + + {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, &DSPEmitter::mrr, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, + + {"SI", 0x1600, 0xff00, DSPInterpreter::si, &DSPEmitter::si, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, + + {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, &DSPEmitter::addis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, + {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, &DSPEmitter::cmpis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, + {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, &DSPEmitter::lris, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, + + {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, &DSPEmitter::addi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, &DSPEmitter::xori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, &DSPEmitter::andi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, &DSPEmitter::ori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, &DSPEmitter::cmpi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + + {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, &DSPEmitter::andf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, &DSPEmitter::andcf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, + + {"ILRR", 0x0210, 0xfefc, DSPInterpreter::ilrr, &DSPEmitter::ilrr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"ILRRD", 0x0214, 0xfefc, DSPInterpreter::ilrrd, &DSPEmitter::ilrrd, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"ILRRI", 0x0218, 0xfefc, DSPInterpreter::ilrri, &DSPEmitter::ilrri, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + {"ILRRN", 0x021c, 0xfefc, DSPInterpreter::ilrrn, &DSPEmitter::ilrrn, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, + + // LOOPS + {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, &DSPEmitter::loop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, false, true, false, true, false}, + {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, &DSPEmitter::bloop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, &DSPEmitter::loopi, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, false, true, false, true, false}, + {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, &DSPEmitter::bloopi, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, + + // load and store value pointed by indexing reg and increment; LRR/SRR variants + {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, &DSPEmitter::lrr, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, + {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, &DSPEmitter::lrrd, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, + {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, &DSPEmitter::lrri, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, + {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, &DSPEmitter::lrrn, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, + + {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, &DSPEmitter::srr, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, + {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, &DSPEmitter::srrd, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, + {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, &DSPEmitter::srri, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, + {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, &DSPEmitter::srrn, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, + + //2 + {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, &DSPEmitter::lrs, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, false, false, false, false, false}, + {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, &DSPEmitter::srs, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, false, false, false, false, false}, + +// opcodes that can be extended + + //3 - main opcode defined by 9 bits, extension defined by last 7 bits!! + {"XORR", 0x3000, 0xfc80, DSPInterpreter::xorr, &DSPEmitter::xorr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"ANDR", 0x3400, 0xfc80, DSPInterpreter::andr, &DSPEmitter::andr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"ORR", 0x3800, 0xfc80, DSPInterpreter::orr, &DSPEmitter::orr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"ANDC", 0x3c00, 0xfe80, DSPInterpreter::andc, &DSPEmitter::andc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"ORC", 0x3e00, 0xfe80, DSPInterpreter::orc, &DSPEmitter::orc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"XORC", 0x3080, 0xfe80, DSPInterpreter::xorc, &DSPEmitter::xorc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"NOT", 0x3280, 0xfe80, DSPInterpreter::notc, &DSPEmitter::notc, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"LSRNRX", 0x3480, 0xfc80, DSPInterpreter::lsrnrx, &DSPEmitter::lsrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"ASRNRX", 0x3880, 0xfc80, DSPInterpreter::asrnrx, &DSPEmitter::asrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"LSRNR", 0x3c80, 0xfe80, DSPInterpreter::lsrnr, &DSPEmitter::lsrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"ASRNR", 0x3e80, 0xfe80, DSPInterpreter::asrnr, &DSPEmitter::asrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //4 + {"ADDR", 0x4000, 0xf800, DSPInterpreter::addr, &DSPEmitter::addr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, + {"ADDAX", 0x4800, 0xfc00, DSPInterpreter::addax, &DSPEmitter::addax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"ADD", 0x4c00, 0xfe00, DSPInterpreter::add, &DSPEmitter::add, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"ADDP", 0x4e00, 0xfe00, DSPInterpreter::addp, &DSPEmitter::addp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //5 + {"SUBR", 0x5000, 0xf800, DSPInterpreter::subr, &DSPEmitter::subr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, + {"SUBAX", 0x5800, 0xfc00, DSPInterpreter::subax, &DSPEmitter::subax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"SUB", 0x5c00, 0xfe00, DSPInterpreter::sub, &DSPEmitter::sub, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"SUBP", 0x5e00, 0xfe00, DSPInterpreter::subp, &DSPEmitter::subp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //6 + {"MOVR", 0x6000, 0xf800, DSPInterpreter::movr, &DSPEmitter::movr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, + {"MOVAX", 0x6800, 0xfc00, DSPInterpreter::movax, &DSPEmitter::movax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"MOV", 0x6c00, 0xfe00, DSPInterpreter::mov, &DSPEmitter::mov, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MOVP", 0x6e00, 0xfe00, DSPInterpreter::movp, &DSPEmitter::movp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //7 + {"ADDAXL", 0x7000, 0xfc00, DSPInterpreter::addaxl, &DSPEmitter::addaxl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, true, false, false, false, true}, + {"INCM", 0x7400, 0xfe00, DSPInterpreter::incm, &DSPEmitter::incm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"INC", 0x7600, 0xfe00, DSPInterpreter::inc, &DSPEmitter::inc, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"DECM", 0x7800, 0xfe00, DSPInterpreter::decm, &DSPEmitter::decm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"DEC", 0x7a00, 0xfe00, DSPInterpreter::dec, &DSPEmitter::dec, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"NEG", 0x7c00, 0xfe00, DSPInterpreter::neg, &DSPEmitter::neg, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MOVNP", 0x7e00, 0xfe00, DSPInterpreter::movnp, &DSPEmitter::movnp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //8 + {"NX", 0x8000, 0xf700, DSPInterpreter::nx, &DSPEmitter::nx, 1, 0, {}, true, false, false, false, false}, + {"CLR", 0x8100, 0xf700, DSPInterpreter::clr, &DSPEmitter::clr, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"CMP", 0x8200, 0xff00, DSPInterpreter::cmp, &DSPEmitter::cmp, 1, 0, {}, true, false, false, false, true}, + {"MULAXH", 0x8300, 0xff00, DSPInterpreter::mulaxh, &DSPEmitter::mulaxh, 1, 0, {}, true, false, false, false, true}, + {"CLRP", 0x8400, 0xff00, DSPInterpreter::clrp, &DSPEmitter::clrp, 1, 0, {}, true, false, false, false, true}, + {"TSTPROD", 0x8500, 0xff00, DSPInterpreter::tstprod, &DSPEmitter::tstprod,1, 0, {}, true, false, false, false, true}, + {"TSTAXH", 0x8600, 0xfe00, DSPInterpreter::tstaxh, &DSPEmitter::tstaxh, 1, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"M2", 0x8a00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + {"M0", 0x8b00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + {"CLR15", 0x8c00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + {"SET15", 0x8d00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + {"SET16", 0x8e00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + {"SET40", 0x8f00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, + + //9 + {"MUL", 0x9000, 0xf700, DSPInterpreter::mul, &DSPEmitter::mul, 1, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"ASR16", 0x9100, 0xf700, DSPInterpreter::asr16, &DSPEmitter::asr16, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"MULMVZ", 0x9200, 0xf600, DSPInterpreter::mulmvz, &DSPEmitter::mulmvz, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULAC", 0x9400, 0xf600, DSPInterpreter::mulac, &DSPEmitter::mulac, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, &DSPEmitter::mulmv, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //a-b + {"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, &DSPEmitter::mulx, 1, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true, false, false, false, true}, + {"ABS", 0xa100, 0xf700, DSPInterpreter::abs, &DSPEmitter::abs, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"MULXMVZ", 0xa200, 0xe600, DSPInterpreter::mulxmvz, &DSPEmitter::mulxmvz,1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULXAC", 0xa400, 0xe600, DSPInterpreter::mulxac, &DSPEmitter::mulxac, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULXMV", 0xa600, 0xe600, DSPInterpreter::mulxmv, &DSPEmitter::mulxmv, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"TST", 0xb100, 0xf700, DSPInterpreter::tst, &DSPEmitter::tst, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + + //c-d + {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, &DSPEmitter::mulc, 1, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"CMPAR" , 0xc100, 0xe700, DSPInterpreter::cmpar, &DSPEmitter::cmpar, 1, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"MULCMVZ", 0xc200, 0xe600, DSPInterpreter::mulcmvz, &DSPEmitter::mulcmvz,1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULCAC", 0xc400, 0xe600, DSPInterpreter::mulcac, &DSPEmitter::mulcac, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MULCMV", 0xc600, 0xe600, DSPInterpreter::mulcmv, &DSPEmitter::mulcmv, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + + //e + {"MADDX", 0xe000, 0xfc00, DSPInterpreter::maddx, &DSPEmitter::maddx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, + {"MSUBX", 0xe400, 0xfc00, DSPInterpreter::msubx, &DSPEmitter::msubx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, + {"MADDC", 0xe800, 0xfc00, DSPInterpreter::maddc, &DSPEmitter::maddc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, + {"MSUBC", 0xec00, 0xfc00, DSPInterpreter::msubc, &DSPEmitter::msubc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, + + //f + {"LSL16", 0xf000, 0xfe00, DSPInterpreter::lsl16, &DSPEmitter::lsl16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MADD", 0xf200, 0xfe00, DSPInterpreter::madd, &DSPEmitter::madd, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"LSR16", 0xf400, 0xfe00, DSPInterpreter::lsr16, &DSPEmitter::lsr16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"MSUB", 0xf600, 0xfe00, DSPInterpreter::msub, &DSPEmitter::msub, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"ADDPAXZ", 0xf800, 0xfc00, DSPInterpreter::addpaxz, &DSPEmitter::addpaxz,1, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_AX, 1, 0, 8, 0x0100}}, true, false, false, false, true}, + {"CLRL", 0xfc00, 0xfe00, DSPInterpreter::clrl, &DSPEmitter::clrl, 1, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, true, false, false, false, true}, + {"MOVPZ", 0xfe00, 0xfe00, DSPInterpreter::movpz, &DSPEmitter::movpz, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, +}; + +const DSPOPCTemplate cw = + {"CW", 0x0000, 0x0000, NULL, NULL, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false}; + +// extended opcodes + +const DSPOPCTemplate opcodes_ext[] = +{ + {"XXX", 0x0000, 0x00fc, DSPInterpreter::Ext::nop, &DSPEmitter::nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, false, false, false}, + + {"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, &DSPEmitter::dr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, + {"IR", 0x0008, 0x00fc, DSPInterpreter::Ext::ir, &DSPEmitter::ir, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, + {"NR", 0x000c, 0x00fc, DSPInterpreter::Ext::nr, &DSPEmitter::nr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, + {"MV", 0x0010, 0x00f0, DSPInterpreter::Ext::mv, &DSPEmitter::mv, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, false, false, false}, + + {"S", 0x0020, 0x00e4, DSPInterpreter::Ext::s, &DSPEmitter::s, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false}, + {"SN", 0x0024, 0x00e4, DSPInterpreter::Ext::sn, &DSPEmitter::sn, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false}, + + {"L", 0x0040, 0x00c4, DSPInterpreter::Ext::l, &DSPEmitter::l, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, + {"LN", 0x0044, 0x00c4, DSPInterpreter::Ext::ln, &DSPEmitter::ln, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, + + {"LS", 0x0080, 0x00ce, DSPInterpreter::Ext::ls, &DSPEmitter::ls, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, + {"SL", 0x0082, 0x00ce, DSPInterpreter::Ext::sl, &DSPEmitter::sl, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, + {"LSN", 0x0084, 0x00ce, DSPInterpreter::Ext::lsn, &DSPEmitter::lsn, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, + {"SLN", 0x0086, 0x00ce, DSPInterpreter::Ext::sln, &DSPEmitter::sln, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, + {"LSM", 0x0088, 0x00ce, DSPInterpreter::Ext::lsm, &DSPEmitter::lsm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, + {"SLM", 0x008a, 0x00ce, DSPInterpreter::Ext::slm, &DSPEmitter::slm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, + {"LSNM", 0x008c, 0x00ce, DSPInterpreter::Ext::lsnm, &DSPEmitter::lsnm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, + {"SLNM", 0x008e, 0x00ce, DSPInterpreter::Ext::slnm, &DSPEmitter::slnm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, + + {"LD", 0x00c0, 0x00cc, DSPInterpreter::Ext::ld, &DSPEmitter::ld, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, + {"LDN", 0x00c4, 0x00cc, DSPInterpreter::Ext::ldn, &DSPEmitter::ldn, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, + {"LDM", 0x00c8, 0x00cc, DSPInterpreter::Ext::ldm, &DSPEmitter::ldm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, + {"LDNM", 0x00cc, 0x00cc, DSPInterpreter::Ext::ldnm, &DSPEmitter::ldnm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, +}; + +const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate); +const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate); + +const pdlabel_t pdlabels[] = +{ + {0xffa0, "COEF_A1_0", "COEF_A1_0",}, + {0xffa1, "COEF_A2_0", "COEF_A2_0",}, + {0xffa2, "COEF_A1_1", "COEF_A1_1",}, + {0xffa3, "COEF_A2_1", "COEF_A2_1",}, + {0xffa4, "COEF_A1_2", "COEF_A1_2",}, + {0xffa5, "COEF_A2_2", "COEF_A2_2",}, + {0xffa6, "COEF_A1_3", "COEF_A1_3",}, + {0xffa7, "COEF_A2_3", "COEF_A2_3",}, + {0xffa8, "COEF_A1_4", "COEF_A1_4",}, + {0xffa9, "COEF_A2_4", "COEF_A2_4",}, + {0xffaa, "COEF_A1_5", "COEF_A1_5",}, + {0xffab, "COEF_A2_5", "COEF_A2_5",}, + {0xffac, "COEF_A1_6", "COEF_A1_6",}, + {0xffad, "COEF_A2_6", "COEF_A2_6",}, + {0xffae, "COEF_A1_7", "COEF_A1_7",}, + {0xffaf, "COEF_A2_7", "COEF_A2_7",}, + + {0xffb0, "0xffb0", 0,}, + {0xffb1, "0xffb1", 0,}, + {0xffb2, "0xffb2", 0,}, + {0xffb3, "0xffb3", 0,}, + {0xffb4, "0xffb4", 0,}, + {0xffb5, "0xffb5", 0,}, + {0xffb6, "0xffb6", 0,}, + {0xffb7, "0xffb7", 0,}, + {0xffb8, "0xffb8", 0,}, + {0xffb9, "0xffb9", 0,}, + {0xffba, "0xffba", 0,}, + {0xffbb, "0xffbb", 0,}, + {0xffbc, "0xffbc", 0,}, + {0xffbd, "0xffbd", 0,}, + {0xffbe, "0xffbe", 0,}, + {0xffbf, "0xffbf", 0,}, + + {0xffc0, "0xffc0", 0,}, + {0xffc1, "0xffc1", 0,}, + {0xffc2, "0xffc2", 0,}, + {0xffc3, "0xffc3", 0,}, + {0xffc4, "0xffc4", 0,}, + {0xffc5, "0xffc5", 0,}, + {0xffc6, "0xffc6", 0,}, + {0xffc7, "0xffc7", 0,}, + {0xffc8, "0xffc8", 0,}, + {0xffc9, "DSCR", "DSP DMA Control Reg",}, + {0xffca, "0xffca", 0,}, + {0xffcb, "DSBL", "DSP DMA Block Length",}, + {0xffcc, "0xffcc", 0,}, + {0xffcd, "DSPA", "DSP DMA DMEM Address",}, + {0xffce, "DSMAH", "DSP DMA Mem Address H",}, + {0xffcf, "DSMAL", "DSP DMA Mem Address L",}, + + {0xffd0, "0xffd0",0,}, + {0xffd1, "SampleFormat", "SampleFormat",}, + {0xffd2, "0xffd2",0,}, + {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",}, + {0xffd4, "ACSAH", "Accelerator start address H",}, + {0xffd5, "ACSAL", "Accelerator start address L",}, + {0xffd6, "ACEAH", "Accelerator end address H",}, + {0xffd7, "ACEAL", "Accelerator end address L",}, + {0xffd8, "ACCAH", "Accelerator current address H",}, + {0xffd9, "ACCAL", "Accelerator current address L",}, + {0xffda, "pred_scale", "pred_scale",}, + {0xffdb, "yn1", "yn1",}, + {0xffdc, "yn2", "yn2",}, + {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",}, + {0xffde, "GAIN", "Gain",}, + {0xffdf, "0xffdf", 0,}, + + {0xffe0, "0xffe0",0,}, + {0xffe1, "0xffe1",0,}, + {0xffe2, "0xffe2",0,}, + {0xffe3, "0xffe3",0,}, + {0xffe4, "0xffe4",0,}, + {0xffe5, "0xffe5",0,}, + {0xffe6, "0xffe6",0,}, + {0xffe7, "0xffe7",0,}, + {0xffe8, "0xffe8",0,}, + {0xffe9, "0xffe9",0,}, + {0xffea, "0xffea",0,}, + {0xffeb, "0xffeb",0,}, + {0xffec, "0xffec",0,}, + {0xffed, "0xffed",0,}, + {0xffee, "0xffee",0,}, + {0xffef, "AMDM", "ARAM DMA Request Mask",}, + + {0xfff0, "0xfff0",0,}, + {0xfff1, "0xfff1",0,}, + {0xfff2, "0xfff2",0,}, + {0xfff3, "0xfff3",0,}, + {0xfff4, "0xfff4",0,}, + {0xfff5, "0xfff5",0,}, + {0xfff6, "0xfff6",0,}, + {0xfff7, "0xfff7",0,}, + {0xfff8, "0xfff8",0,}, + {0xfff9, "0xfff9",0,}, + {0xfffa, "0xfffa",0,}, + {0xfffb, "DIRQ", "DSP IRQ Request",}, + {0xfffc, "DMBH", "DSP Mailbox H",}, + {0xfffd, "DMBL", "DSP Mailbox L",}, + {0xfffe, "CMBH", "CPU Mailbox H",}, + {0xffff, "CMBL", "CPU Mailbox L",}, +}; + +const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t); + +const pdlabel_t regnames[] = +{ + {0x00, "AR0", "Addr Reg 00",}, + {0x01, "AR1", "Addr Reg 01",}, + {0x02, "AR2", "Addr Reg 02",}, + {0x03, "AR3", "Addr Reg 03",}, + {0x04, "IX0", "Index Reg 0",}, + {0x05, "IX1", "Index Reg 1",}, + {0x06, "IX2", "Index Reg 2",}, + {0x07, "IX3", "Index Reg 3",}, + {0x08, "WR0", "Wrapping Register 0",}, + {0x09, "WR1", "Wrapping Register 1",}, + {0x0a, "WR2", "Wrapping Register 2",}, + {0x0b, "WR3", "Wrapping Register 3",}, + {0x0c, "ST0", "Call stack",}, + {0x0d, "ST1", "Data stack",}, + {0x0e, "ST2", "Loop addr stack",}, + {0x0f, "ST3", "Loop counter",}, + {0x10, "AC0.H", "Accu High 0",}, + {0x11, "AC1.H", "Accu High 1",}, + {0x12, "CR", "Config Register",}, + {0x13, "SR", "Special Register",}, + {0x14, "PROD.L", "Prod L",}, + {0x15, "PROD.M1", "Prod M1",}, + {0x16, "PROD.H", "Prod H",}, + {0x17, "PROD.M2", "Prod M2",}, + {0x18, "AX0.L", "Extra Accu L 0",}, + {0x19, "AX1.L", "Extra Accu L 1",}, + {0x1a, "AX0.H", "Extra Accu H 0",}, + {0x1b, "AX1.H", "Extra Accu H 1",}, + {0x1c, "AC0.L", "Accu Low 0",}, + {0x1d, "AC1.L", "Accu Low 1",}, + {0x1e, "AC0.M", "Accu Mid 0",}, + {0x1f, "AC1.M", "Accu Mid 1",}, + + // To resolve combined register names. + {0x20, "ACC0", "Accu Full 0",}, + {0x21, "ACC1", "Accu Full 1",}, + {0x22, "AX0", "Extra Accu 0",}, + {0x23, "AX1", "Extra Accu 1",}, +}; + +const DSPOPCTemplate *opTable[OPTABLE_SIZE]; +const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; +u16 writeBackLog[WRITEBACKLOGSIZE]; +int writeBackLogIdx[WRITEBACKLOGSIZE]; + +const char* pdname(u16 val) +{ + static char tmpstr[12]; // nasty + + for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++) + { + if (pdlabels[i].addr == val) + return pdlabels[i].name; + } + + sprintf(tmpstr, "0x%04x", val); + return tmpstr; +} + +const char *pdregname(int val) +{ + return regnames[val].name; +} + +const char *pdregnamelong(int val) +{ + return regnames[val].description; +} + +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst) +{ + return opTable[inst]; +} + + +// This function could use the above GetOpTemplate, but then we'd lose the +// nice property that it catches colliding op masks. +void InitInstructionTable() +{ + // ext op table + for (int i = 0; i < EXT_OPTABLE_SIZE; i++) + extOpTable[i] = &cw; + + for (int i = 0; i < EXT_OPTABLE_SIZE; i++) + { + for (int j = 0; j < opcodes_ext_size; j++) + { + u16 mask = opcodes_ext[j].opcode_mask; + if ((mask & i) == opcodes_ext[j].opcode) + { + if (extOpTable[i] == &cw) + extOpTable[i] = &opcodes_ext[j]; + else + ERROR_LOG(DSPLLE, "opcode ext table place %d already in use for %s", i, opcodes_ext[j].name); + } + } + } + + // op table + for (int i = 0; i < OPTABLE_SIZE; i++) + opTable[i] = &cw; + + for (int i = 0; i < OPTABLE_SIZE; i++) + { + for (int j = 0; j < opcodes_size; j++) + { + u16 mask = opcodes[j].opcode_mask; + if ((mask & i) == opcodes[j].opcode) + { + if (opTable[i] == &cw) + opTable[i] = &opcodes[j]; + else + ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name); + } + } + } + + for (int i=0; i < WRITEBACKLOGSIZE; i++) + writeBackLogIdx[i] = -1; +} diff --git a/Source/Core/Core/Src/DSP/DSPTables.h b/Source/Core/Core/Src/DSP/DSPTables.h new file mode 100644 index 0000000000..56ad885d23 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DSPTables.h @@ -0,0 +1,158 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) + +#ifndef _DSPTABLES_H +#define _DSPTABLES_H + +//nclude "Common.h" +#include "DSPEmitter.h" +#include "DSPCommon.h" + +// The non-ADDR ones that end with _D are the opposite one - if the bit specify +// ACC0, then ACC_D will be ACC1. + +// The values of these are very important. +// For the reg ones, the value >> 8 is the base register. +// & 0x80 means it's a "D". + +enum partype_t +{ + P_NONE = 0x0000, + P_VAL = 0x0001, + P_IMM = 0x0002, + P_MEM = 0x0003, + P_STR = 0x0004, + P_ADDR_I = 0x0005, + P_ADDR_D = 0x0006, + P_REG = 0x8000, + P_REG04 = P_REG | 0x0400, // IX + P_REG08 = P_REG | 0x0800, + P_REG18 = P_REG | 0x1800, + P_REGM18 = P_REG | 0x1810, // used in multiply instructions + P_REG19 = P_REG | 0x1900, + P_REGM19 = P_REG | 0x1910, // used in multiply instructions + P_REG1A = P_REG | 0x1a80, + P_REG1C = P_REG | 0x1c00, +// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) + P_ACCL = P_REG | 0x1c00, // used for low part of accum + P_ACCM = P_REG | 0x1e00, // used for mid part of accum + // The following are not in gcdsptool + P_ACCM_D = P_REG | 0x1e80, + P_ACC = P_REG | 0x2000, // used for full accum. + P_ACC_D = P_REG | 0x2080, + P_AX = P_REG | 0x2200, + P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 + P_REF = P_REG | 0x4000, + P_PRG = P_REF | P_REG, + + // The following seem like junk: + // P_REG10 = P_REG | 0x1000, + // P_AX_D = P_REG | 0x2280, +}; + +#define OPTABLE_SIZE 0xffff + 1 +#define EXT_OPTABLE_SIZE 0xff + 1 + +typedef void (*dspIntFunc)(const UDSPInstruction); +typedef void (DSPEmitter::*dspJitFunc)(const UDSPInstruction); + +struct param2_t +{ + partype_t type; + u8 size; + u8 loc; + s8 lshift; + u16 mask; +}; + +typedef struct +{ + const char *name; + u16 opcode; + u16 opcode_mask; + + dspIntFunc intFunc; + dspJitFunc jitFunc; + + u8 size; + u8 param_count; + param2_t params[8]; + bool extended; + bool branch; + bool uncond_branch; + bool reads_pc; + bool updates_sr; +} DSPOPCTemplate; + +typedef DSPOPCTemplate opc_t; + +// Opcodes +extern const DSPOPCTemplate opcodes[]; +extern const int opcodes_size; +extern const DSPOPCTemplate opcodes_ext[]; +extern const int opcodes_ext_size; +extern const DSPOPCTemplate cw; + +#define WRITEBACKLOGSIZE 5 + +extern const DSPOPCTemplate *opTable[OPTABLE_SIZE]; +extern const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; +extern u16 writeBackLog[WRITEBACKLOGSIZE]; +extern int writeBackLogIdx[WRITEBACKLOGSIZE]; + +// Predefined labels +struct pdlabel_t +{ + u16 addr; + const char* name; + const char* description; +}; + +extern const pdlabel_t regnames[]; +extern const pdlabel_t pdlabels[]; +extern const u32 pdlabels_size; + +const char *pdname(u16 val); +const char *pdregname(int val); +const char *pdregnamelong(int val); + +void InitInstructionTable(); +void applyWriteBackLog(); +void zeroWriteBackLog(); +void zeroWriteBackLogPreserveAcc(u8 acc); + +const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst); + +inline void ExecuteInstruction(const UDSPInstruction inst) +{ + const DSPOPCTemplate *tinst = GetOpTemplate(inst); + + if (tinst->extended) { + if ((inst >> 12) == 0x3) + extOpTable[inst & 0x7F]->intFunc(inst); + else + extOpTable[inst & 0xFF]->intFunc(inst); + } + tinst->intFunc(inst); + if (tinst->extended) { + applyWriteBackLog(); + } +} + +#endif // _DSPTABLES_H diff --git a/Source/Core/Core/Src/DSP/DspIntArithmetic.cpp b/Source/Core/Core/Src/DSP/DspIntArithmetic.cpp new file mode 100644 index 0000000000..ba625395a1 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DspIntArithmetic.cpp @@ -0,0 +1,1152 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +// Arithmetic and accumulator control. + +namespace DSPInterpreter { + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +// +// flags out: --10 0100 +void clr(const UDSPInstruction opc) +{ + u8 reg = (opc >> 11) & 0x1; + + dsp_set_long_acc(reg, 0); + Update_SR_Register64(0); + zeroWriteBackLog(); +} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears (and rounds!) $acR.l - low 16 bits of accumulator $acR. +// +// flags out: --xx xx00 +void clrl(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); + + zeroWriteBackLog(); + + dsp_set_long_acc(reg, acc); + Update_SR_Register64(acc); +} + +//---- + +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +// +// flags out: -x-- ---- +void andcf(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == imm) ? true : false); +} + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +// +// flags out: -x-- ---- +void andf(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == 0) ? true : false); +} + +//---- + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +// +// flags out: --xx xx00 +void tst(const UDSPInstruction opc) +{ + u8 reg = (opc >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(reg); + Update_SR_Register64(acc); + zeroWriteBackLog(); +} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +// +// flags out: --x0 xx00 +void tstaxh(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + + s16 val = dsp_get_ax_h(reg); + Update_SR_Register16(val); + zeroWriteBackLog(); +} + +//---- + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +// +// flags out: x-xx xxxx +void cmp(const UDSPInstruction opc) +{ + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + s64 res = dsp_convert_long_acc(acc0 - acc1); + + Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 + zeroWriteBackLog(); +} + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +// +// flags out: x-xx xxxx +void cmpar(const UDSPInstruction opc) +{ + u8 rreg = ((opc >> 12) & 0x1) + DSP_REG_AXH0; + u8 sreg = (opc >> 11) & 0x1; + + s64 sr = dsp_get_long_acc(sreg); + s64 rr = (s16)g_dsp.r.ax[rreg-DSP_REG_AXH0].h; + rr <<= 16; + s64 res = dsp_convert_long_acc(sr - rr); + + Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); + zeroWriteBackLog(); +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +// +// flags out: x-xx xxxx +void cmpi(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + + s64 val = dsp_get_long_acc(reg); + s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. + s64 res = dsp_convert_long_acc(val - imm); + + Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); +} + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +// +// flags out: x-xx xxxx +void cmpis(const UDSPInstruction opc) +{ + u8 areg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc; + val <<= 16; + s64 res = dsp_convert_long_acc(acc - val); + + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); +} + +//---- + +// XORR $acD.m, $axS.h +// 0011 00sd 0xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void xorr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ax[sreg].h; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// ANDR $acD.m, $axS.h +// 0011 01sd 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void andr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ax[sreg].h; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// ORR $acD.m, $axS.h +// 0011 10sd 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void orr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ax[sreg].h; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void andc(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ac[1 - dreg].m; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void orc(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ac[1 - dreg].m; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// XORC $acD.m +// 0011 000d 1xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void xorc(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ac[1 - dreg].m; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// NOT $acD.m +// 0011 001d 1xxx xxxx +// Invert all bits in dest reg, aka xor with 0xffff +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void notc(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ 0xffff; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +// +// flags out: --xx xx00 +void xori(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m ^= imm; + + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void andi(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m &= imm; + + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); +} + +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void ori(const UDSPInstruction opc) +{ + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m |= imm; + + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); +} + +//---- + +// ADDR $acD.M, $axS.L +// 0100 0ssd xxxx xxxx +// Adds register $axS.L to accumulator $acD.M register. +// +// flags out: x-xx xxxx +void addr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = 0; + switch(sreg) { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } + ax <<= 16; + s64 res = acc + ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +// +// flags out: x-xx xxxx +void addax(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = dsp_get_long_acx(sreg); + s64 res = acc + ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); +} + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +// +// flags out: x-xx xxxx +void add(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc0 = dsp_get_long_acc(dreg); + s64 acc1 = dsp_get_long_acc(1 - dreg); + s64 res = acc0 + acc1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +// +// flags out: x-xx xxxx +void addp(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc + prod; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); +} + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +// should be unsigned values!! +// +// flags out: x-xx xxxx +void addaxl(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(dreg); + u16 acx = (u16)dsp_get_ax_l(sreg); + + u64 res = acc + acx; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, (s64)res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void addi(const UDSPInstruction opc) +{ + u8 areg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 imm = (s16)dsp_fetch_code(); + imm <<= 16; + s64 res = acc + imm; + + dsp_set_long_acc(areg, res); + res = dsp_get_long_acc(areg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void addis(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 imm = (s8)(u8)opc; + imm <<= 16; + s64 res = acc + imm; + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void incm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + sub; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +// +// flags out: x-xx xxxx +void inc(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + 1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); +} + +//---- + +// SUBR $acD.M, $axS.L +// 0101 0ssd xxxx xxxx +// Subtracts register $axS.L from accumulator $acD.M register. +// +// flags out: x-xx xxxx +void subr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = 0; + switch(sreg) { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } + ax <<= 16; + s64 res = acc - ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +// +// flags out: x-xx xxxx +void subax(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_long_acx(sreg); + s64 res = acc - acx; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); +} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +// +// flags out: x-xx xxxx +void sub(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc1 = dsp_get_long_acc(dreg); + s64 acc2 = dsp_get_long_acc(1 - dreg); + s64 res = acc1 - acc2; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); +} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +// +// flags out: x-xx xxxx +void subp(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc - prod; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); +} + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void decm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x01; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - sub; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +// +// flags out: x-xx xxxx +void dec(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x01; + + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - 1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); +} + +//---- + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +// +// flags out: --xx xx00 +void neg(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + acc = 0 - acc; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + +// ABS $acD +// 1010 d001 xxxx xxxx +// absolute value of $acD +// +// flags out: --xx xx00 +void abs(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + + if (acc < 0) + acc = 0 - acc; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} +//---- + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +// +// flags out: --xx xx00 +void movr(const UDSPInstruction opc) +{ + u8 areg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = 0; + switch(sreg) { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } + ax <<= 16; + ax &= ~0xffff; + + zeroWriteBackLog(); + + dsp_set_long_acc(areg, ax); + Update_SR_Register64(ax); +} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +// +// flags out: --xx xx00 +void movax(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s64 acx = dsp_get_long_acx(sreg); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acx); + Update_SR_Register64(acx); +} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +// +// flags out: --x0 xx00 +void mov(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - dreg); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); +} + +//---- + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +// +// flags out: --xx xx00 +void lsl16(const UDSPInstruction opc) +{ + u8 areg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc <<= 16; + + zeroWriteBackLog(); + + dsp_set_long_acc(areg, acc); + Update_SR_Register64(dsp_get_long_acc(areg)); +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +void lsr16(const UDSPInstruction opc) +{ + u8 areg = (opc >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(areg); + acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + acc >>= 16; + + zeroWriteBackLog(); + + dsp_set_long_acc(areg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(areg)); +} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +void asr16(const UDSPInstruction opc) +{ + u8 areg = (opc >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc >>= 16; + + zeroWriteBackLog(); + + dsp_set_long_acc(areg, acc); + Update_SR_Register64(dsp_get_long_acc(areg)); +} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +void lsl(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + u64 acc = dsp_get_long_acc(rreg); + + acc <<= shift; + + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts right accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +void lsr(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x01; + u16 shift; + u64 acc = dsp_get_long_acc(rreg); + acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); + + acc >>= shift; + + dsp_set_long_acc(rreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +void asl(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + u64 acc = dsp_get_long_acc(rreg); + + acc <<= shift; + + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +void asr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x01; + u16 shift; + + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); + + // arithmetic shift + s64 acc = dsp_get_long_acc(dreg); + acc >>= shift; + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + +// LSRN (fixed parameters) +// 0000 0010 1100 1010 +// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +void lsrn(const UDSPInstruction opc) +{ + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); + u64 acc = dsp_get_long_acc(0); + acc &= 0x000000FFFFFFFFFFULL; + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + + dsp_set_long_acc(0, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(0)); +} + +// ASRN (fixed parameters) +// 0000 0010 1100 1011 +// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +void asrn(const UDSPInstruction opc) +{ + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); + s64 acc = dsp_get_long_acc(0); + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + + if (shift > 0) { + acc >>= shift; + } else if (shift < 0) { + acc <<= -shift; + } + + dsp_set_long_acc(0, acc); + Update_SR_Register64(dsp_get_long_acc(0)); +} + +// LSRNRX $acD, $axS.h +// 0011 01sd 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void lsrnrx(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s16 shift; + u16 axh = g_dsp.r.ax[sreg].h; + u64 acc = dsp_get_long_acc(dreg); + acc &= 0x000000FFFFFFFFFFULL; + + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; + + if (shift > 0) { + acc <<= shift; + } else if (shift < 0) { + acc >>= -shift; + } + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + +// ASRNRX $acD, $axS.h +// 0011 10sd 1xxx xxxx +// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void asrnrx(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s16 shift; + u16 axh = g_dsp.r.ax[sreg].h; + s64 acc = dsp_get_long_acc(dreg); + + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; + + if (shift > 0) { + acc <<= shift; + } else if (shift < 0) { + acc >>= -shift; + } + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + +// LSRNR $acD +// 0011 110d 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void lsrnr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + u64 acc = dsp_get_long_acc(dreg); + acc &= 0x000000FFFFFFFFFFULL; + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + +// ASRNR $acD +// 0011 111d 1xxx xxxx +// Arithmeticaly shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void asrnr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + s64 acc = dsp_get_long_acc(dreg); + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); +} + + +} // namespace + diff --git a/Source/Core/Core/Src/DSP/DspIntBranch.cpp b/Source/Core/Core/Src/DSP/DspIntBranch.cpp new file mode 100644 index 0000000000..1113425a87 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DspIntBranch.cpp @@ -0,0 +1,275 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPCore.h" +#include "DSPMemoryMap.h" +#include "DSPStacks.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Generic call implementation +// CALLcc addressA +// 0000 0010 1011 cccc +// aaaa aaaa aaaa aaaa +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to $st0. Set program counter to address +// represented by value that follows this "call" instruction. +void call(const UDSPInstruction opc) +{ + // must be outside the if. + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc & 0xf)) + { + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = dest; + } +} + +// Generic callr implementation +// CALLRcc $R +// 0001 0111 rrr1 cccc +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to call stack $st0. Set program counter to +// register $R. +void callr(const UDSPInstruction opc) +{ + if (CheckCondition(opc & 0xf)) + { + u8 reg = (opc >> 5) & 0x7; + u16 addr = dsp_op_read_reg(reg); + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = addr; + } +} + +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +void ifcc(const UDSPInstruction opc) +{ + if (!CheckCondition(opc & 0xf)) + { + // skip the next opcode - we have to lookup its size. + dsp_skip_inst(); + } +} + +// Generic jmp implementation +// Jcc addressA +// 0000 0010 1001 cccc +// aaaa aaaa aaaa aaaa +// Jump to addressA if condition cc has been met. Set program counter to +// address represented by value that follows this "jmp" instruction. +void jcc(const UDSPInstruction opc) +{ + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc & 0xf)) + { + g_dsp.pc = dest; + } +} + +// Generic jmpr implementation +// JMPcc $R +// 0001 0111 rrr0 cccc +// Jump to address; set program counter to a value from register $R. +void jmprcc(const UDSPInstruction opc) +{ + if (CheckCondition(opc & 0xf)) + { + u8 reg = (opc >> 5) & 0x7; + g_dsp.pc = dsp_op_read_reg(reg); + } +} + +// Generic ret implementation +// RETcc +// 0000 0010 1101 cccc +// Return from subroutine if condition cc has been met. Pops stored PC +// from call stack $st0 and sets $pc to this location. +void ret(const UDSPInstruction opc) +{ + if (CheckCondition(opc & 0xf)) + { + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + } +} + +// RTI +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +void rti(const UDSPInstruction opc) +{ + g_dsp.r.sr = dsp_reg_load_stack(DSP_STACK_D); + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + +} + +// HALT +// 0000 0000 0020 0001 +// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. +void halt(const UDSPInstruction opc) +{ + g_dsp.cr |= 0x4; + g_dsp.pc--; +} + + +// LOOP handling: Loop stack is used to control execution of repeated blocks of +// instructions. Whenever there is value on stack $st2 and current PC is equal +// value at $st2, then value at stack $st3 is decremented. If value is not zero +// then PC is modified with value from call stack $st0. Otherwise values from +// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution +// continues at next opcode. +void HandleLoop() +{ + // Handle looping hardware. + const u16 rCallAddress = g_dsp.r.st[0]; + const u16 rLoopAddress = g_dsp.r.st[2]; + u16& rLoopCounter = g_dsp.r.st[3]; + + if (rLoopAddress > 0 && rLoopCounter > 0) + { + // FIXME: why -1? because we just read past it. + if (g_dsp.pc - 1 == rLoopAddress) + { + rLoopCounter--; + if (rLoopCounter > 0) + { + g_dsp.pc = rCallAddress; + } + else + { + // end of loop + dsp_reg_load_stack(0); + dsp_reg_load_stack(2); + dsp_reg_load_stack(3); + } + } + } +} + + +// LOOP $R +// 0000 0000 010r rrrr +// Repeatedly execute following opcode until counter specified by value +// from register $R reaches zero. Each execution decrement counter. Register +// $R remains unchanged. If register $R is set to zero at the beginning of loop +// then looped instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loop(const UDSPInstruction opc) +{ + u16 reg = opc & 0x1f; + u16 cnt = dsp_op_read_reg(reg); + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + +// LOOPI #I +// 0001 0000 iiii iiii +// Repeatedly execute following opcode until counter specified by +// immediate value I reaches zero. Each execution decrement counter. If +// immediate value I is set to zero at the beginning of loop then looped +// instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loopi(const UDSPInstruction opc) +{ + u16 cnt = opc & 0xff; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + + +// BLOOP $R, addrA +// 0000 0000 011r rrrr +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by value from register $R reaches zero. Block ends at +// specified address addrA inclusive, ie. opcode at addrA is the last opcode +// included in loop. Counter is pushed on loop stack $st3, end of block address +// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. +// Up to 4 nested loops are allowed. +void bloop(const UDSPInstruction opc) +{ + u16 reg = opc & 0x1f; + u16 cnt = dsp_op_read_reg(reg); + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + dsp_skip_inst(); + } +} + +// BLOOPI #I, addrA +// 0001 0001 iiii iiii +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by immediate value I reaches zero. Block ends at specified +// address addrA inclusive, ie. opcode at addrA is the last opcode included in +// loop. Counter is pushed on loop stack $st3, end of block address is pushed +// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 +// nested loops are allowed. +void bloopi(const UDSPInstruction opc) +{ + u16 cnt = opc & 0xff; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + dsp_skip_inst(); + } +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DspIntLoadStore.cpp b/Source/Core/Core/Src/DSP/DspIntLoadStore.cpp new file mode 100644 index 0000000000..b43d6707b3 --- /dev/null +++ b/Source/Core/Core/Src/DSP/DspIntLoadStore.cpp @@ -0,0 +1,269 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" + +#include "DSPMemoryMap.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// SRS @M, $(0x18+S) +// 0010 1sss mmmm mmmm +// Move value from register $(0x18+D) to data memory pointed by address +// CR[0-7] | M. That is, the upper 8 bits of the address are the +// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate. +// Note: pc+=2 in duddie's doc seems wrong +void srs(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + dsp_dmem_write(addr, dsp_op_read_reg(reg)); +} + +// LRS $(0x18+D), @M +// 0010 0ddd mmmm mmmm +// Move value from data memory pointed by address CR[0-7] | M to register +// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits +// from CR, and the lower 8 bits are from the 8-bit immediate. +void lrs(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + dsp_op_write_reg(reg, dsp_dmem_read(addr)); + dsp_conditional_extend_accum(reg); +} + +// LR $D, @M +// 0000 0000 110d dddd +// mmmm mmmm mmmm mmmm +// Move value from data memory pointed by address M to register $D. +// FIXME: Perform additional operation depending on destination register. +void lr(const UDSPInstruction opc) +{ + u8 reg = opc & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_dmem_read(addr); + dsp_op_write_reg(reg, val); + dsp_conditional_extend_accum(reg); +} + +// SR @M, $S +// 0000 0000 111s ssss +// mmmm mmmm mmmm mmmm +// Store value from register $S to a memory pointed by address M. +// FIXME: Perform additional operation depending on destination register. +void sr(const UDSPInstruction opc) +{ + u8 reg = opc & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_op_read_reg(reg); + dsp_dmem_write(addr, val); +} + +// SI @M, #I +// 0001 0110 mmmm mmmm +// iiii iiii iiii iiii +// Store 16-bit immediate value I to a memory location pointed by address +// M (M is 8-bit value sign extended). +void si(const UDSPInstruction opc) +{ + u16 addr = (s8)opc; + u16 imm = dsp_fetch_code(); + dsp_dmem_write(addr, imm); +} + +// LRR $D, @$S +// 0001 1000 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void lrr(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); +} + +// LRRD $D, @$S +// 0001 1000 1ssd dddd +// Move value from data memory pointed by addressing register $S toregister $D. +// Decrement register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrd(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg); +} + +// LRRI $D, @$S +// 0001 1001 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Increment register $S. +// FIXME: Perform additional operation depending on destination register. +void lrri(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg); +} + +// LRRN $D, @$S +// 0001 1001 1ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Add indexing register $(0x4+S) to register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrn(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]); +} + +// SRR @$D, $S +// 0001 1010 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. +// FIXME: Perform additional operation depending on source register. +void srr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r.ar[dreg], val); +} + +// SRRD @$D, $S +// 0001 1010 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Decrement register $D. +// FIXME: Perform additional operation depending on source register. +void srrd(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r.ar[dreg], val); + g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg); +} + +// SRRI @$D, $S +// 0001 1011 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Increment register $D. +// FIXME: Perform additional operation depending on source register. +void srri(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r.ar[dreg], val); + g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg); +} + +// SRRN @$D, $S +// 0001 1011 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Add DSP_REG_IX0 register to register $D. +// FIXME: Perform additional operation depending on source register. +void srrn(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r.ar[dreg], val); + g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); +} + +// ILRR $acD.m, @$arS +// 0000 001d 0001 00ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. +void ilrr(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + + g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); +} + +// ILRRD $acD.m, @$arS +// 0000 001d 0001 01ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. +void ilrrd(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + + g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg); +} + +// ILRRI $acD.m, @$S +// 0000 001d 0001 10ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Increment addressing register $arS. +void ilrri(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + + g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg); +} + +// ILRRN $acD.m, @$arS +// 0000 001d 0001 11ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Add corresponding indexing +// register $ixS to addressing register $arS. +void ilrrn(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + + g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]); +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DspIntMisc.cpp b/Source/Core/Core/Src/DSP/DspIntMisc.cpp new file mode 100644 index 0000000000..f2c1f921af --- /dev/null +++ b/Source/Core/Core/Src/DSP/DspIntMisc.cpp @@ -0,0 +1,189 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +#include "DSPInterpreter.h" + +#include "DSPCore.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// MRR $D, $S +// 0001 11dd ddds ssss +// Move value from register $S to register $D. +// todo: Perform additional operation depending on destination register. +void mrr(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); +} + +// LRI $D, #I +// 0000 0000 100d dddd +// iiii iiii iiii iiii +// Load immediate value I to register $D. +// +// DSPSpy discovery: This, and possibly other instructions that load a +// register, has a different behaviour in S40 mode if loaded to AC0.M: The +// value gets sign extended to the whole accumulator! This does not happen in +// S16 mode. +void lri(const UDSPInstruction opc) +{ + u8 reg = opc & DSP_REG_MASK; + u16 imm = dsp_fetch_code(); + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + +// LRIS $(0x18+D), #I +// 0000 1ddd iiii iiii +// Load immediate value I (8-bit sign extended) to accumulator register. +void lris(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc; + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + +//---- + +// NX +// 1000 -000 xxxx xxxx +// No operation, but can be extended with extended opcode. +// This opcode is supposed to do nothing - it's used if you want to use +// an opcode extension but not do anything. At least according to duddie. +void nx(const UDSPInstruction opc) +{ + zeroWriteBackLog(); +} + +//---- + +// DAR $arD +// 0000 0000 0000 01dd +// Decrement address register $arD. +void dar(const UDSPInstruction opc) +{ + g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); +} + +// IAR $arD +// 0000 0000 0000 10dd +// Increment address register $arD. +void iar(const UDSPInstruction opc) +{ + g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); +} + +// SUBARN $arD +// 0000 0000 0000 11dd +// Subtract indexing register $ixD from an addressing register $arD. +// used only in IPL-NTSC ucode +void subarn(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); +} + +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +// It is critical for the Zelda ucode that this one wraps correctly. +void addarn(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + u8 sreg = (opc >> 2) & 0x3; + g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]); +} + +//---- + +// SBCLR #I +// 0001 0011 aaaa aiii +// bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbclr(const UDSPInstruction opc) +{ + u8 bit = (opc & 0x7) + 6; + g_dsp.r.sr &= ~(1 << bit); +} + +// SBSET #I +// 0001 0010 aaaa aiii +// Set bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbset(const UDSPInstruction opc) +{ + u8 bit = (opc & 0x7) + 6; + g_dsp.r.sr |= (1 << bit); +} + +// This is a bunch of flag setters, flipping bits in SR. So far so good, +// but it's harder to know exactly what effect they have. +void srbith(const UDSPInstruction opc) +{ + zeroWriteBackLog(); + switch ((opc >> 8) & 0xf) + { + // M0/M2 change the multiplier mode (it can multiply by 2 for free). + case 0xa: // M2 + g_dsp.r.sr &= ~SR_MUL_MODIFY; + break; + case 0xb: // M0 + g_dsp.r.sr |= SR_MUL_MODIFY; + break; + + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + g_dsp.r.sr &= ~SR_MUL_UNSIGNED; + break; + case 0xd: // SET15 + g_dsp.r.sr |= SR_MUL_UNSIGNED; + break; + + // Automatic 40-bit sign extension when loading ACx.M. + // SET40 changes something very important: see the LRI instruction above. + case 0xe: // SET16 (CLR40) + g_dsp.r.sr &= ~SR_40_MODE_BIT; + break; + + case 0xf: // SET40 + g_dsp.r.sr |= SR_40_MODE_BIT; + break; + + default: + break; + } +} + +//---- + +void unknown(const UDSPInstruction opc) +{ + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc, g_dsp.pc); +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/DspIntMultiplier.cpp b/Source/Core/Core/Src/DSP/DspIntMultiplier.cpp new file mode 100644 index 0000000000..fbde7a645c --- /dev/null +++ b/Source/Core/Core/Src/DSP/DspIntMultiplier.cpp @@ -0,0 +1,609 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// Multiplier and product register control + +#include "DSPInterpreter.h" + +#include "DSPIntCCUtil.h" +#include "DSPIntUtil.h" + +namespace DSPInterpreter { + +// Only MULX family instructions have unsigned/mixed support. +inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) +{ + s64 prod; + + if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned + prod = (u32)(a * b); + else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //mixed + prod = a * (s16)b; + else + prod = (s16)a * (s16)b; //signed + + // Conditionally multiply by 2. + if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + prod <<= 1; + + return prod; +} + +inline s64 dsp_multiply(u16 a, u16 b, u8 sign = 0) +{ + s64 prod = dsp_get_multiply_prod(a, b, sign); + return prod; +} + +inline s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0) +{ + s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); + return prod; +} + +inline s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0) +{ + s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); + return prod; +} + +inline s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2) +{ + s64 result; + + if ((axh0==0) && (axh1==0)) + result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used + else if ((axh0==0) && (axh1==1)) + result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 + else if ((axh0==1) && (axh1==0)) + result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 + else + result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + + return result; +} + +//---- + +// CLRP +// 1000 0100 xxxx xxxx +// Clears product register $prod. +// Magic numbers taken from duddie's doc +// +// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 +// +// It's not ok, to just zero all of them, correct values should be set because of +// direct use of prod regs by AX/AXWII (look @that part of ucode). +void clrp(const UDSPInstruction opc) +{ + zeroWriteBackLog(); + + g_dsp.r.prod.l = 0x0000; + g_dsp.r.prod.m = 0xfff0; + g_dsp.r.prod.h = 0x00ff; + g_dsp.r.prod.m2 = 0x0010; +} + +// TSTPROD +// 1000 0101 xxxx xxxx +// Test prod regs value. +// +// flags out: --xx xx0x +void tstprod(const UDSPInstruction opc) +{ + s64 prod = dsp_get_long_prod(); + Update_SR_Register64(prod); + zeroWriteBackLog(); +} + +//---- + +// MOVP $acD +// 0110 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD register. +// +// flags out: --xx xx0x +void movp(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = dsp_get_long_prod(); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); +} + +// MOVNP $acD +// 0111 111d xxxx xxxx +// Moves negative of multiply product from $prod register to accumulator +// $acD register. +// +// flags out: --xx xx0x +void movnp(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + + s64 acc = -dsp_get_long_prod(); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets (rounds) $acD.l to 0 +// +// flags out: --xx xx0x +void movpz(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x01; + + s64 acc = dsp_get_long_prod_round_prodl(); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); +} + +// ADDPAXZ $acD, $axS +// 1111 10sd xxxx xxxx +// Adds secondary accumulator $axS to product register and stores result +// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0. +// +// TODO: ugly code and still small error here (+/- 1 in .m - randomly) +// flags out: --xx xx0x +void addpaxz(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + s64 oldprod = dsp_get_long_prod(); + s64 prod = dsp_get_long_prod_round_prodl(); + s64 ax = dsp_get_long_acx(sreg); + s64 res = prod + (ax & ~0xffff); + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(oldprod, res), false); +} + +//---- + +// MULAXH +// 1000 0011 xxxx xxxx +// Multiply $ax0.h by $ax0.h +void mulaxh(const UDSPInstruction opc) +{ + s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +//---- + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void mul(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 11) & 0x1; + + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axh, axl); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +// +// flags out: --xx xx0x +void mulac(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +// +// flags out: --xx xx0x +void mulmv(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 11) & 0x1); + + s64 acc = dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear (round) low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). +// +// flags out: --xx xx0x +void mulmvz(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; + + s64 acc = dsp_get_long_prod_round_prodl(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +//---- + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1. +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void mulx(const UDSPInstruction opc) +{ + u8 treg = ((opc >> 11) & 0x1); + u8 sreg = ((opc >> 12) & 0x1); + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1. Part is selected by S and +// T bits. Zero selects low part, one selects high part. +// +// flags out: --xx xx0x +void mulxac(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1. Part is selected by S and +// T bits. Zero selects low part, one selects high part. +// +// flags out: --xx xx0x +void mulxmv(const UDSPInstruction opc) +{ + u8 rreg = ((opc >> 8) & 0x1); + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_prod(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULXMVZ $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear (round) low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 +// Part is selected by S and T bits. Zero selects low part, +// one selects high part. +// +// flags out: --xx xx0x +void mulxmvz(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_prod_round_prodl(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +//---- + +// MULC $acS.m, $axT.h +// 110s t000 xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). +void mulc(const UDSPInstruction opc) +{ + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. +// +// flags out: --xx xx0x +void mulcac(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h +// +// flags out: --xx xx0x +void mulcmv(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +// MULCMVZ $acS.m, $axT.h, $acR +// 110s t01r xxxx xxxx +// (fixed possible bug in duddie's description, s->t) +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR, set (round) low part of +// accumulator $acR.l to zero. +// +// flags out: --xx xx0x +void mulcmvz(const UDSPInstruction opc) +{ + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + s64 acc = dsp_get_long_prod_round_prodl(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); +} + +//---- + +// MADDX ax0.S ax1.T +// 1110 00st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and add result to product register. +void maddx(const UDSPInstruction opc) +{ + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_add(val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MSUBX $(0x18+S*2), $(0x19+T*2) +// 1110 01st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and subtract result from product register. +void msubx(const UDSPInstruction opc) +{ + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_sub(val1, val2); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MADDC $acS.m, $axT.h +// 1110 10st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and add result to product +// register. +void maddc(const UDSPInstruction opc) +{ + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply_add(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MSUBC $acS.m, $axT.h +// 1110 11st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and subtract result from +// product register. +void msubc(const UDSPInstruction opc) +{ + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply_sub(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MADD $axS.l, $axS.h +// 1111 001s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and add +// result to product register. +void madd(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 8) & 0x1; + + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply_add(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MSUB $axS.l, $axS.h +// 1111 011s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and +// subtract result from product register. +void msub(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 8) & 0x1; + + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply_sub(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +} // namespace diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp new file mode 100644 index 0000000000..fe396c6b97 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp @@ -0,0 +1,1862 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "../DSPIntCCUtil.h" +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "../DSPAnalyzer.h" +#ifdef _M_X64 +#include "DSPJitUtil.h" +#endif +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +// +// flags out: --10 0100 +void DSPEmitter::clr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 reg = (opc >> 11) & 0x1; +// dsp_set_long_acc(reg, 0); + MOV(64, R(RAX), Imm64(0)); + set_long_acc(reg); +// Update_SR_Register64(0); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears (and rounds!) $acR.l - low 16 bits of accumulator $acR. +// +// flags out: --xx xx00 +void DSPEmitter::clrl(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 reg = (opc >> 8) & 0x1; +// s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); + get_long_acc(reg); + round_long_acc(); +// dsp_set_long_acc(reg, acc); + set_long_acc(reg); +// Update_SR_Register64(acc); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +//---- + +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +// +// flags out: -x-- ---- +void DSPEmitter::andcf(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC+1); +// u16 val = dsp_get_acc_m(reg); + get_acc_m(reg); +// Update_SR_LZ(((val & imm) == imm) ? true : false); +// if ((val & imm) == imm) +// g_dsp.r.sr |= SR_LOGIC_ZERO; +// else +// g_dsp.r.sr &= ~SR_LOGIC_ZERO; + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + AND(16, R(RAX), Imm16(imm)); + CMP(16, R(RAX), Imm16(imm)); + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + FixupBranch notLogicZero = J_CC(CC_NE); + OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); + FixupBranch exit = J(); + SetJumpTarget(notLogicZero); + AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); + SetJumpTarget(exit); + gpr.putReg(DSP_REG_SR); + } +#else + Default(opc); +#endif +} + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +// +// flags out: -x-- ---- +void DSPEmitter::andf(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC+1); +// u16 val = dsp_get_acc_m(reg); + get_acc_m(reg); +// Update_SR_LZ(((val & imm) == 0) ? true : false); +// if ((val & imm) == 0) +// g_dsp.r.sr |= SR_LOGIC_ZERO; +// else +// g_dsp.r.sr &= ~SR_LOGIC_ZERO; + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + TEST(16, R(RAX), Imm16(imm)); + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + FixupBranch notLogicZero = J_CC(CC_NE); + OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); + FixupBranch exit = J(); + SetJumpTarget(notLogicZero); + AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); + SetJumpTarget(exit); + gpr.putReg(DSP_REG_SR); + } +#else + Default(opc); +#endif +} + +//---- + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +// +// flags out: --xx xx00 +void DSPEmitter::tst(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 reg = (opc >> 11) & 0x1; +// s64 acc = dsp_get_long_acc(reg); + get_long_acc(reg); +// Update_SR_Register64(acc); + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +// +// flags out: --x0 xx00 +void DSPEmitter::tstaxh(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 reg = (opc >> 8) & 0x1; +// s16 val = dsp_get_ax_h(reg); + get_ax_h(reg); +// Update_SR_Register16(val); + Update_SR_Register16(); + } +#else + Default(opc); +#endif +} + +//---- + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +// +// flags out: x-xx xxxx +void DSPEmitter::cmp(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { +// s64 acc0 = dsp_get_long_acc(0); + get_long_acc(0, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 acc1 = dsp_get_long_acc(1); + get_long_acc(1, RDX); +// s64 res = dsp_convert_long_acc(acc0 - acc1); + SUB(64, R(RAX), R(RDX)); +// Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 + NEG(64, R(RDX)); + Update_SR_Register64_Carry2(); + } +#else + Default(opc); +#endif +} + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +// +// flags out: x-xx xxxx +void DSPEmitter::cmpar(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 rreg = ((opc >> 12) & 0x1); + u8 sreg = (opc >> 11) & 0x1; + +// s64 sr = dsp_get_long_acc(sreg); + get_long_acc(sreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 rr = (s16)g_dsp.r.axh[rreg]; + get_ax_h(rreg, RDX); +// rr <<= 16; + SHL(64, R(RDX), Imm8(16)); +// s64 res = dsp_convert_long_acc(sr - rr); + SUB(64, R(RAX), R(RDX)); +// Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry2(); + } +#else + Default(opc); +#endif +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +// +// flags out: x-xx xxxx +void DSPEmitter::cmpi(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 reg = (opc >> 8) & 0x1; +// s64 val = dsp_get_long_acc(reg); + get_long_acc(reg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. + u16 imm = dsp_imem_read(compilePC+1); + MOV(64, R(RDX), Imm64((s64)(s16)imm << 16)); +// s64 res = dsp_convert_long_acc(val - imm); + SUB(64, R(RAX), R(RDX)); +// Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry2(); + } +#else + Default(opc); +#endif +} + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::cmpis(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + u8 areg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 val = (s8)opc; +// val <<= 16; + MOV(64, R(RDX), Imm64((s64)(s8)opc << 16)); +// s64 res = dsp_convert_long_acc(acc - val); + SUB(64, R(RAX), R(RDX)); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry2(); + } +#else + Default(opc); +#endif +} + +//---- + +// XORR $acD.m, $axS.h +// 0011 00sd 0xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::xorr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; +// u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + XOR(64, R(RAX), R(RDX)); +// g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ANDR $acD.m, $axS.h +// 0011 01sd 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::andr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + AND(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ORR $acD.m, $axS.h +// 0011 10sd 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::orr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + OR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::andc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + AND(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::orc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + OR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// XORC $acD.m +// 0011 000d 1xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::xorc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + XOR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// NOT $acD.m +// 0011 001d 1xxx xxxx +// Invert all bits in dest reg, aka xor with 0xffff +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::notc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r.acm[dreg] ^ 0xffff; + get_acc_m(dreg, RAX); + XOR(16, R(RAX), Imm16(0xffff)); +// g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(dreg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +// +// flags out: --xx xx00 +void DSPEmitter::xori(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC+1); +// g_dsp.r.acm[reg] ^= imm; + get_acc_m(reg, RAX); + XOR(16, R(RAX), Imm16(imm)); + set_acc_m(reg); +// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(reg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void DSPEmitter::andi(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC+1); +// g_dsp.r.acm[reg] &= imm; + get_acc_m(reg, RAX); + AND(16, R(RAX), Imm16(imm)); + set_acc_m(reg); +// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(reg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void DSPEmitter::ori(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC+1); + // g_dsp.r.acm[reg] |= imm; + get_acc_m(reg, RAX); + OR(16, R(RAX), Imm16(imm)); + set_acc_m(reg); + // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_acc(reg, RSI); + Update_SR_Register16_OverS32(); + } +#else + Default(opc); +#endif +} + +//---- + +// ADDR $acD.M, $axS.L +// 0100 0ssd xxxx xxxx +// Adds register $axS.L to accumulator $acD.M register. +// +// flags out: x-xx xxxx +void DSPEmitter::addr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 ax = (s16)g_dsp.r[sreg]; + dsp_op_read_reg(sreg, RDX, SIGN); +// ax <<= 16; + SHL(64, R(RDX), Imm8(16)); +// s64 res = acc + ax; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } + +#else + Default(opc); +#endif +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::addax(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 ax = dsp_get_long_acx(sreg); + get_long_acx(sreg, RDX); +// s64 res = acc + ax; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::add(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s64 acc0 = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 acc1 = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg, RDX); +// s64 res = acc0 + acc1; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +// +// flags out: x-xx xxxx +void DSPEmitter::addp(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 prod = dsp_get_long_prod(); + get_long_prod(RDX); +// s64 res = acc + prod; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +// should be unsigned values!! +// +// flags out: x-xx xxxx +void DSPEmitter::addaxl(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + +// u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// u16 acx = (u16)dsp_get_ax_l(sreg); + get_ax_l(sreg, RDX); +// u64 res = acc + acx; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, (s64)res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void DSPEmitter::addi(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 imm = (s16)dsp_fetch_code(); + s16 imm = dsp_imem_read(compilePC+1); + //imm <<= 16; + MOV(16, R(RDX), Imm16(imm)); + MOVSX(64, 16, RDX, R(RDX)); + SHL(64, R(RDX), Imm8(16)); +// s64 res = acc + imm; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(areg, res); +// res = dsp_get_long_acc(areg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(areg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(areg, RAX); + } +#else + Default(opc); +#endif +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void DSPEmitter::addis(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 imm = (s8)(u8)opc; +// imm <<= 16; + MOV(8, R(RDX), Imm8((u8)opc)); + MOVSX(64, 8, RDX, R(RDX)); + SHL(64, R(RDX), Imm8(16)); +// s64 res = acc + imm; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void DSPEmitter::incm(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + s64 subtract = 0x10000; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 res = acc + sub; + ADD(64, R(RAX), Imm32((u32)subtract)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, subtract, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RDX), Imm32((u32)subtract)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg); + Update_SR_Register64_Carry(); + } +#else + Default(opc); +#endif +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::inc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 res = acc + 1; + ADD(64, R(RAX), Imm8(1)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RDX), Imm64(1)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg); + Update_SR_Register64_Carry(); + } +#else + Default(opc); +#endif +} + +//---- + +// SUBR $acD.M, $axS.L +// 0101 0ssd xxxx xxxx +// Subtracts register $axS.L from accumulator $acD.M register. +// +// flags out: x-xx xxxx +void DSPEmitter::subr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 ax = (s16)g_dsp.r[sreg]; + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + dsp_op_read_reg(sreg, RDX, SIGN); +// ax <<= 16; + SHL(64, R(RDX), Imm8(16)); +// s64 res = acc - ax; + SUB(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + NEG(64, R(RDX)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::subax(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 acx = dsp_get_long_acx(sreg); + get_long_acx(sreg, RDX); +// s64 res = acc - acx; + SUB(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + NEG(64, R(RDX)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::sub(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// s64 acc1 = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 acc2 = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg, RDX); +// s64 res = acc1 - acc2; + SUB(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + NEG(64, R(RDX)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +// +// flags out: x-xx xxxx +void DSPEmitter::subp(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 prod = dsp_get_long_prod(); + get_long_prod(RDX); +// s64 res = acc - prod; + SUB(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + NEG(64, R(RDX)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void DSPEmitter::decm(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x01; + s64 subtract = 0x10000; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 res = acc - sub; + SUB(64, R(RAX), Imm32((u32)subtract)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -subtract, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RDX), Imm64(-subtract)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +// +// flags out: x-xx xxxx +void DSPEmitter::dec(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x01; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RCX); + MOV(64, R(RAX), R(RCX)); +// s64 res = acc - 1; + SUB(64, R(RAX), Imm32(1)); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + MOV(64, R(RDX), Imm64(-1)); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry2(); + } + else + { + set_long_acc(dreg); + } +#else + Default(opc); +#endif +} + +//---- + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +// +// flags out: --xx xx00 +void DSPEmitter::neg(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); +// acc = 0 - acc; + NEG(64, R(RAX)); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// ABS $acD +// 1010 d001 xxxx xxxx +// absolute value of $acD +// +// flags out: --xx xx00 +void DSPEmitter::abs(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); +// if (acc < 0) acc = 0 - acc; + CMP(64, R(RAX), Imm8(0)); + FixupBranch lessThan = J_CC(CC_L); + NEG(64, R(RAX)); + set_long_acc(dreg); + SetJumpTarget(lessThan); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} +//---- + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +// +// flags out: --xx xx00 +void DSPEmitter::movr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + +// s64 acc = (s16)g_dsp.r[sreg]; + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + dsp_op_read_reg(sreg, RAX, SIGN); +// acc <<= 16; + SHL(64, R(RAX), Imm8(16)); +// acc &= ~0xffff; +// dsp_set_long_acc(areg, acc); + set_long_acc(areg); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +// +// flags out: --xx xx00 +void DSPEmitter::movax(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s64 acx = dsp_get_long_acx(sreg); + get_long_acx(sreg); +// dsp_set_long_acc(dreg, acx); + set_long_acc(dreg); +// Update_SR_Register64(acx); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +// +// flags out: --x0 xx00 +void DSPEmitter::mov(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; +// u64 acc = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(acc); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +//---- + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +// +// flags out: --xx xx00 +void DSPEmitter::lsl16(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); +// acc <<= 16; + SHL(64, R(RAX), Imm8(16)); +// dsp_set_long_acc(areg, acc); + set_long_acc(areg); +// Update_SR_Register64(dsp_get_long_acc(areg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +void DSPEmitter::lsr16(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 8) & 0x1; + +// u64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); +// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes +// acc >>= 16; + SHR(64, R(RAX), Imm8(16)); + AND(64, R(RAX), Imm32(0xffffff)); +// dsp_set_long_acc(areg, (s64)acc); + set_long_acc(areg); +// Update_SR_Register64(dsp_get_long_acc(areg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +void DSPEmitter::asr16(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); +// acc >>= 16; + SHR(64, R(RAX), Imm8(16)); +// dsp_set_long_acc(areg, acc); + set_long_acc(areg); +// Update_SR_Register64(dsp_get_long_acc(areg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +void DSPEmitter::lsl(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; +// u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); + +// acc <<= shift; + SHL(64, R(RAX), Imm8((u8)shift)); + +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts right accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +void DSPEmitter::lsr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x01; + u16 shift; +// u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); + + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); + + if (shift) + { + // acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + SHL(64, R(RAX), Imm8(24)); + // acc >>= shift; + SHR(64, R(RAX), Imm8(shift + 24)); + } + +// dsp_set_long_acc(rreg, (s64)acc); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +void DSPEmitter::asl(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; +// u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); +// acc <<= shift; + SHL(64, R(RAX), Imm8((u8)shift)); +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +void DSPEmitter::asr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x01; + u16 shift; + + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); + + // arithmetic shift +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); +// acc >>= shift; + SHR(64, R(RAX), Imm8((u8)shift)); + +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// LSRN (fixed parameters) +// 0000 0010 1100 1010 +// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +void DSPEmitter::lsrn(const UDSPInstruction opc) +{ +#ifdef _M_X64 +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1); + get_acc_m(1); +// u64 acc = dsp_get_long_acc(0); + get_long_acc(0, RDX); +// acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); + + // if ((accm & 0x3f) == 0) + // shift = 0; + // else if (accm & 0x40) + // shift = -0x40 + (accm & 0x3f); + // else + // shift = accm & 0x3f; + + // if (shift > 0) { + // acc >>= shift; + // } else if (shift < 0) { + // acc <<= -shift; + // } + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SHL(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SAR(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(0, (s64)acc); + set_long_acc(0, RDX); + SetJumpTarget(zero); +// Update_SR_Register64(dsp_get_long_acc(0)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +// ASRN (fixed parameters) +// 0000 0010 1100 1011 +// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +void DSPEmitter::asrn(const UDSPInstruction opc) +{ +#ifdef _M_X64 +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1); + get_acc_m(1); +// s64 acc = dsp_get_long_acc(0); + get_long_acc(0, RDX); + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) { +// acc >>= shift; +// } else if (shift < 0) { +// acc <<= -shift; +// } + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SHL(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SAR(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(0, acc); +// Update_SR_Register64(dsp_get_long_acc(0)); + set_long_acc(0, RDX); + SetJumpTarget(zero); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +// LSRNRX $acD, $axS.h +// 0011 01sd 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::lsrnrx(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s16 shift; +// u16 axh = g_dsp.r.axh[sreg]; + get_ax_h(sreg); +// u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); +// acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); + +// if ((axh & 0x3f) == 0) +// shift = 0; +// else if (axh & 0x40) +// shift = -0x40 + (axh & 0x3f); +// else +// shift = axh & 0x3f; + +// if (shift > 0) { +// acc <<= shift; +// } else if (shift < 0) { +// acc >>= -shift; +// } + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(dreg, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +// ASRNRX $acD, $axS.h +// 0011 10sd 1xxx xxxx +// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::asrnrx(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s16 shift; +// u16 axh = g_dsp.r.axh[sreg]; + get_ax_h(sreg); +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); + +// if ((axh & 0x3f) == 0) +// shift = 0; +// else if (axh & 0x40) +// shift = -0x40 + (axh & 0x3f); +// else +// shift = axh & 0x3f; + +// if (shift > 0) { +// acc <<= shift; +// } else if (shift < 0) { +// acc >>= -shift; +// } + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +// LSRNR $acD +// 0011 110d 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::lsrnr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1 - dreg); + get_acc_m(1 - dreg); +// u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); +// acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) +// acc <<= shift; +// else if (shift < 0) +// acc >>= -shift; + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(dreg, (s64)acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +// ASRNR $acD +// 0011 111d 1xxx xxxx +// Arithmetically shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void DSPEmitter::asrnr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1 - dreg); + get_acc_m(1 - dreg); +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) +// acc <<= shift; +// else if (shift < 0) +// acc >>= -shift; + + CMP(64, R(RDX), Imm8(0)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); + +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); +// Update_SR_Register64(dsp_get_long_acc(dreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + + +//} // namespace + +// diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp new file mode 100644 index 0000000000..4dd2476e70 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp @@ -0,0 +1,606 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "../DSPMemoryMap.h" +#include "../DSPEmitter.h" +#include "../DSPStacks.h" +#include "../DSPAnalyzer.h" +#include "DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" + +using namespace Gen; + +template +static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter) +{ + u8 cond = opc & 0xf; + if (cond == 0xf) {// Always true. + jitCode(opc,emitter); + return; + } + FixupBranch skipCode2; + emitter.dsp_op_read_reg(DSP_REG_SR, RAX); + DSPJitRegCache c2(emitter.gpr); + switch(cond) + { + case 0x0: // GE - Greater Equal + case 0x1: // L - Less + case 0x2: // G - Greater + case 0x3: // LE - Less Equal + emitter.MOV(16, R(EDX), R(EAX)); + emitter.SHR(16, R(EDX), Imm8(3)); //SR_SIGN flag + emitter.NOT(16, R(EDX)); + emitter.SHR(16, R(EAX), Imm8(1)); //SR_OVERFLOW flag + emitter.NOT(16, R(EAX)); + emitter.XOR(16, R(EAX), R(EDX)); + if (cond < 0x2) { + emitter.TEST(16, R(EAX), Imm16(1)); + break; + } + c2 = emitter.gpr; + emitter.TEST(16, R(EAX), Imm16(1)); + + //LE: problem in here, half the tests fail + skipCode2 = emitter.J_CC(CC_NE); + //skipCode2 = emitter.J_CC((CCFlags)(CC_NE - (cond & 1))); + emitter.dsp_op_read_reg(DSP_REG_SR, RAX); + emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); + break; + case 0x4: // NZ - Not Zero + case 0x5: // Z - Zero + emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); + break; + case 0x6: // NC - Not carry + case 0x7: // C - Carry + emitter.TEST(16, R(EAX), Imm16(SR_CARRY)); + break; + case 0x8: // ? - Not over s32 + case 0x9: // ? - Over s32 + emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32)); + break; + case 0xa: // ? + case 0xb: // ? + { + //full of fail, both + emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS)); + FixupBranch skipArithZero = emitter.J_CC(CC_E); + emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); + FixupBranch setZero = emitter.J_CC(CC_NE); + + emitter.MOV(16, R(EAX), Imm16(1)); + FixupBranch toEnd = emitter.J(); + + emitter.SetJumpTarget(skipArithZero); + emitter.SetJumpTarget(setZero); + emitter.XOR(16, R(EAX), R(EAX)); + emitter.SetJumpTarget(toEnd); + emitter.SETcc(CC_E, R(EAX)); + emitter.TEST(8, R(EAX), R(EAX)); + break; + //c2 = emitter.gpr; + //emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS)); + //skipCode2 = emitter.J_CC((CCFlags)(CC_E + (cond & 1))); + //emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); + //break; + } + case 0xc: // LNZ - Logic Not Zero + case 0xd: // LZ - Logic Zero + emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO)); + break; + case 0xe: // 0 - Overflow + emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW)); + break; + } + DSPJitRegCache c1(emitter.gpr); + FixupBranch skipCode = cond == 0xe ? emitter.J_CC(CC_E) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1))); + jitCode(opc,emitter); + emitter.gpr.flushRegs(c1); + emitter.SetJumpTarget(skipCode); + if ((cond | 1) == 0x3) {// || (cond | 1) == 0xb) + emitter.gpr.flushRegs(c2); + emitter.SetJumpTarget(skipCode2); + } else { + c2.drop(); + } +} + +static void WriteBranchExit(DSPEmitter& emitter) +{ + emitter.SaveDSPRegs(); + if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + emitter.MOV(16, R(EAX), Imm16(0x1000)); + } + else + { + emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr])); + } + emitter.JMP(emitter.returnDispatcher, true); +} + +static void WriteBlockLink(DSPEmitter& emitter, u16 dest) +{ + // Jump directly to the called block if it has already been compiled. + if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) + { + if (emitter.blockLinks[dest] != 0 ) + { + emitter.gpr.flushRegs(); +#ifdef _M_IX86 // All32 + // Check if we have enough cycles to execute the next block + emitter.MOV(16, R(ESI), M(&cyclesLeft)); + emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(16, M(&cyclesLeft), R(ESI)); +#else + // Check if we have enough cycles to execute the next block + emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); + emitter.CMP(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr])); +#endif + emitter.JMP(emitter.blockLinks[dest], true); + emitter.SetJumpTarget(notEnoughCycles); + } + else + { + // The destination has not been compiled yet. Add it to the list + // of blocks that this block is waiting on. + emitter.unresolvedJumps[emitter.startAddr].push_back(dest); + } + } +} + +void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) +{ + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); +#else + emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RAX), Imm16(dest)); +#endif + WriteBranchExit(emitter); +} +// Generic jmp implementation +// Jcc addressA +// 0000 0010 1001 cccc +// aaaa aaaa aaaa aaaa +// Jump to addressA if condition cc has been met. Set program counter to +// address represented by value that follows this "jmp" instruction. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::jcc(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); +#endif + ReJitConditional(opc, *this); +} + +void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) +{ + u8 reg = (opc >> 5) & 0x7; + //reg can only be DSP_REG_ARx and DSP_REG_IXx now, + //no need to handle DSP_REG_STx. + emitter.dsp_op_read_reg(reg, RAX, NONE); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&g_dsp.pc), R(EAX)); +#else + emitter.MOV(64, R(RSI), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RSI), R(RAX)); +#endif + WriteBranchExit(emitter); +} +// Generic jmpr implementation +// JMPcc $R +// 0001 0111 rrr0 cccc +// Jump to address; set program counter to a value from register $R. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::jmprcc(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif + ReJitConditional(opc, *this); +} + +void r_call(const UDSPInstruction opc, DSPEmitter& emitter) +{ + emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); + emitter.dsp_reg_store_stack(DSP_STACK_C); + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); +#else + emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RAX), Imm16(dest)); +#endif + WriteBranchExit(emitter); +} +// Generic call implementation +// CALLcc addressA +// 0000 0010 1011 cccc +// aaaa aaaa aaaa aaaa +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to $st0. Set program counter to address +// represented by value that follows this "call" instruction. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::call(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); +#endif + ReJitConditional(opc, *this); +} + +void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) +{ + u8 reg = (opc >> 5) & 0x7; + emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 1)); + emitter.dsp_reg_store_stack(DSP_STACK_C); + emitter.dsp_op_read_reg(reg, RAX, NONE); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&g_dsp.pc), R(EAX)); +#else + emitter.MOV(64, R(RSI), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RSI), R(RAX)); +#endif + WriteBranchExit(emitter); +} +// Generic callr implementation +// CALLRcc $R +// 0001 0111 rrr1 cccc +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to call stack $st0. Set program counter to +// register $R. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::callr(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif + ReJitConditional(opc, *this); +} + +void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter) +{ +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&g_dsp.pc), Imm16(emitter.compilePC + 1)); +#else + emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RAX), Imm16(emitter.compilePC + 1)); +#endif +} +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::ifcc(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16((compilePC + 1) + opTable[compilePC + 1]->size)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16((compilePC + 1) + opTable[compilePC + 1]->size)); +#endif + ReJitConditional(opc, *this); + WriteBranchExit(*this); +} + +void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) +{ + emitter.dsp_reg_load_stack(DSP_STACK_C); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(&g_dsp.pc), R(DX)); +#else + emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + emitter.MOV(16, MatR(RAX), R(DX)); +#endif + WriteBranchExit(emitter); +} + +// Generic ret implementation +// RETcc +// 0000 0010 1101 cccc +// Return from subroutine if condition cc has been met. Pops stored PC +// from call stack $st0 and sets $pc to this location. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit +void DSPEmitter::ret(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif + ReJitConditional(opc, *this); +} + +// RTI +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +void DSPEmitter::rti(const UDSPInstruction opc) +{ +// g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); + dsp_reg_load_stack(DSP_STACK_D); + dsp_op_write_reg(DSP_REG_SR, RDX); +// g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + dsp_reg_load_stack(DSP_STACK_C); +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), R(DX)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), R(DX)); +#endif +} + +// HALT +// 0000 0000 0020 0001 +// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. +void DSPEmitter::halt(const UDSPInstruction opc) +{ +#ifdef _M_IX86 // All32 + OR(16, M(&g_dsp.cr), Imm16(4)); +#else + MOV(64, R(RAX), ImmPtr(&g_dsp.cr)); + OR(16, MatR(RAX), Imm16(4)); +#endif + // g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + dsp_reg_load_stack(DSP_STACK_C); +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), R(DX)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), R(DX)); +#endif +} + +// LOOP handling: Loop stack is used to control execution of repeated blocks of +// instructions. Whenever there is value on stack $st2 and current PC is equal +// value at $st2, then value at stack $st3 is decremented. If value is not zero +// then PC is modified with value from call stack $st0. Otherwise values from +// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution +// continues at next opcode. +void DSPEmitter::HandleLoop() +{ +#ifdef _M_IX86 // All32 + MOVZX(32, 16, EAX, M(&g_dsp.r.st[2])); + MOVZX(32, 16, ECX, M(&g_dsp.r.st[3])); +#else + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[2]))); + MOVZX(32, 16, ECX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3]))); +#endif + + CMP(32, R(RCX), Imm32(0)); + FixupBranch rLoopCntG = J_CC(CC_LE, true); + CMP(16, R(RAX), Imm16(compilePC - 1)); + FixupBranch rLoopAddrG = J_CC(CC_NE, true); + +#ifdef _M_IX86 // All32 + SUB(16, M(&(g_dsp.r.st[3])), Imm16(1)); + CMP(16, M(&(g_dsp.r.st[3])), Imm16(0)); +#else + SUB(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3])), Imm16(1)); + CMP(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3])), Imm16(0)); +#endif + + FixupBranch loadStack = J_CC(CC_LE, true); +#ifdef _M_IX86 // All32 + MOVZX(32, 16, ECX, M(&(g_dsp.r.st[0]))); + MOV(16, M(&g_dsp.pc), R(RCX)); +#else + MOVZX(32, 16, RCX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[0]))); + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), R(RCX)); +#endif + FixupBranch loopUpdated = J(true); + + SetJumpTarget(loadStack); + dsp_reg_load_stack(0); + dsp_reg_load_stack(2); + dsp_reg_load_stack(3); + + SetJumpTarget(loopUpdated); + SetJumpTarget(rLoopAddrG); + SetJumpTarget(rLoopCntG); + +} + +// LOOP $R +// 0000 0000 010r rrrr +// Repeatedly execute following opcode until counter specified by value +// from register $R reaches zero. Each execution decrement counter. Register +// $R remains unchanged. If register $R is set to zero at the beginning of loop +// then looped instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void DSPEmitter::loop(const UDSPInstruction opc) +{ + u16 reg = opc & 0x1f; +// u16 cnt = g_dsp.r[reg]; + dsp_op_read_reg(reg, RDX, ZERO); + u16 loop_pc = compilePC + 1; + + CMP(16, R(EDX), Imm16(0)); + FixupBranch cnt = J_CC(CC_Z, true); + dsp_reg_store_stack(3); + MOV(16, R(RDX), Imm16(compilePC + 1)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + + SetJumpTarget(cnt); +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif +} + +// LOOPI #I +// 0001 0000 iiii iiii +// Repeatedly execute following opcode until counter specified by +// immediate value I reaches zero. Each execution decrement counter. If +// immediate value I is set to zero at the beginning of loop then looped +// instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void DSPEmitter::loopi(const UDSPInstruction opc) +{ + u16 cnt = opc & 0xff; + u16 loop_pc = compilePC + 1; + + if (cnt) + { + MOV(16, R(RDX), Imm16(compilePC + 1)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + MOV(16, R(RDX), Imm16(cnt)); + dsp_reg_store_stack(3); + +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif + } +} + + +// BLOOP $R, addrA +// 0000 0000 011r rrrr +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by value from register $R reaches zero. Block ends at +// specified address addrA inclusive, ie. opcode at addrA is the last opcode +// included in loop. Counter is pushed on loop stack $st3, end of block address +// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. +// Up to 4 nested loops are allowed. +void DSPEmitter::bloop(const UDSPInstruction opc) +{ + u16 reg = opc & 0x1f; +// u16 cnt = g_dsp.r[reg]; + dsp_op_read_reg(reg, RDX, ZERO); + u16 loop_pc = dsp_imem_read(compilePC + 1); + + CMP(16, R(EDX), Imm16(0)); + FixupBranch cnt = J_CC(CC_Z, true); + dsp_reg_store_stack(3); + MOV(16, R(RDX), Imm16(compilePC + 2)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); +#endif + FixupBranch exit = J(); + + SetJumpTarget(cnt); + // g_dsp.pc = loop_pc; + // dsp_skip_inst(); +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[loop_pc]->size)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); +#endif + DSPJitRegCache c(gpr); + WriteBranchExit(*this); + gpr.flushRegs(c,false); + SetJumpTarget(exit); +} + +// BLOOPI #I, addrA +// 0001 0001 iiii iiii +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by immediate value I reaches zero. Block ends at specified +// address addrA inclusive, ie. opcode at addrA is the last opcode included in +// loop. Counter is pushed on loop stack $st3, end of block address is pushed +// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 +// nested loops are allowed. +void DSPEmitter::bloopi(const UDSPInstruction opc) +{ + u16 cnt = opc & 0xff; +// u16 loop_pc = dsp_fetch_code(); + u16 loop_pc = dsp_imem_read(compilePC + 1); + + if (cnt) + { + MOV(16, R(RDX), Imm16(compilePC + 2)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + MOV(16, R(RDX), Imm16(cnt)); + dsp_reg_store_stack(3); + +#ifdef _M_IX86 // All32 + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); +#endif + } + else + { +// g_dsp.pc = loop_pc; +// dsp_skip_inst(); +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[loop_pc]->size)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); +#endif + WriteBranchExit(*this); + } +} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp new file mode 100644 index 0000000000..620c2a2c43 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp @@ -0,0 +1,323 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// HELPER FUNCTIONS + +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register(Gen::X64Reg val) +{ +#ifdef _M_X64 + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + // // 0x04 + // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + CMP(64, R(val), Imm8(0)); + FixupBranch notZero = J_CC(CC_NZ); + OR(16, sr_reg, Imm16(SR_ARITH_ZERO)); + SetJumpTarget(notZero); + + // // 0x08 + // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; + CMP(64, R(val), Imm8(0)); + FixupBranch greaterThanEqual = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_SIGN)); + SetJumpTarget(greaterThanEqual); + + // // 0x10 + // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; + MOVSX(64, 32, RDX, R(val)); + CMP(64, R(RDX), R(val)); + FixupBranch noOverS32 = J_CC(CC_E); + OR(16, sr_reg, Imm16(SR_OVER_S32)); + SetJumpTarget(noOverS32); + + // // 0x20 - Checks if top bits of m are equal + // if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) + AND(32, R(val), Imm32(0xc0000000)); + CMP(32, R(val), Imm32(0)); + FixupBranch zeroC = J_CC(CC_E); + CMP(32, R(val), Imm32(0xc0000000)); + FixupBranch cC = J_CC(CC_NE); + SetJumpTarget(zeroC); + // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; + OR(16, sr_reg, Imm16(SR_TOP2BITS)); + SetJumpTarget(cC); + gpr.putReg(DSP_REG_SR); +#endif +} + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register64(Gen::X64Reg val) +{ +#ifdef _M_X64 +// g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + gpr.putReg(DSP_REG_SR); + Update_SR_Register(val); +#endif +} + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register64_Carry(Gen::X64Reg val) +{ +#ifdef _M_X64 + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + + CMP(64, R(RCX), R(val)); + + // 0x01 + // g_dsp.r[DSP_REG_SR] |= SR_CARRY; + // Carry = (acc>res) + FixupBranch noCarry = J_CC(CC_BE); + OR(16, sr_reg, Imm16(SR_CARRY)); + SetJumpTarget(noCarry); + + // 0x02 and 0x80 + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; + // Overflow = ((acc ^ res) & (ax ^ res)) < 0 + XOR(64, R(RCX), R(val)); + XOR(64, R(RDX), R(val)); + AND(64, R(RCX), R(RDX)); + CMP(64, R(RCX), Imm8(0)); + FixupBranch noOverflow = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); + SetJumpTarget(noOverflow); + + gpr.putReg(DSP_REG_SR); + Update_SR_Register(val); +#endif +} + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register64_Carry2(Gen::X64Reg val) +{ +#ifdef _M_X64 + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + + CMP(64, R(RCX), R(val)); + + // 0x01 + // g_dsp.r[DSP_REG_SR] |= SR_CARRY; + // Carry2 = (acc>=res) + FixupBranch noCarry2 = J_CC(CC_B); + OR(16, sr_reg, Imm16(SR_CARRY)); + SetJumpTarget(noCarry2); + + // 0x02 and 0x80 + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; + // Overflow = ((acc ^ res) & (ax ^ res)) < 0 + XOR(64, R(RCX), R(val)); + XOR(64, R(RDX), R(val)); + AND(64, R(RCX), R(RDX)); + CMP(64, R(RCX), Imm8(0)); + FixupBranch noOverflow = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); + SetJumpTarget(noOverflow); + gpr.putReg(DSP_REG_SR); + + Update_SR_Register(); +#endif +} + +//void DSPEmitter::Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) +//{ + +// // 0x20 - Checks if top bits of m are equal +// if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) +// { +// g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; +// } +//} + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register16(Gen::X64Reg val) +{ +#ifdef _M_X64 + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + + // // 0x04 + // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + CMP(64, R(val), Imm8(0)); + FixupBranch notZero = J_CC(CC_NZ); + OR(16, sr_reg, Imm16(SR_ARITH_ZERO)); + SetJumpTarget(notZero); + + // // 0x08 + // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; + CMP(64, R(val), Imm8(0)); + FixupBranch greaterThanEqual = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_SIGN)); + SetJumpTarget(greaterThanEqual); + + // // 0x20 - Checks if top bits of m are equal + // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + //AND(32, R(val), Imm32(0xc0000000)); + SHR(16, R(val), Imm8(14)); + CMP(16, R(val), Imm16(0)); + FixupBranch nZero = J_CC(CC_NE); + OR(16, sr_reg, Imm16(SR_TOP2BITS)); + FixupBranch cC = J(); + SetJumpTarget(nZero); + CMP(16, R(val), Imm16(3)); + FixupBranch notThree = J_CC(CC_NE); + // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; + OR(16, sr_reg, Imm16(SR_TOP2BITS)); + SetJumpTarget(notThree); + SetJumpTarget(cC); + gpr.putReg(DSP_REG_SR); +#endif +} + +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow +// Clobbers RDX +void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val) +{ +#ifdef _M_X64 + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + + // // 0x10 + // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; + MOVSX(64, 32, RSI, R(val)); + CMP(64, R(RSI), R(val)); + FixupBranch noOverS32 = J_CC(CC_E); + OR(16, sr_reg, Imm16(SR_OVER_S32)); + SetJumpTarget(noOverS32); + + gpr.putReg(DSP_REG_SR); + // // 0x20 - Checks if top bits of m are equal + // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + //AND(32, R(val), Imm32(0xc0000000)); + Update_SR_Register16(val); +#endif +} + +//void DSPEmitter::Update_SR_LZ(bool value) { + +// if (value == true) +// g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO; +// else +// g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO; +//} + +//inline int GetMultiplyModifier() +//{ +// return (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)?1:2; +//} + +//inline bool isCarry() { +// return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false; +//} + +//inline bool isOverflow() { +// return (g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) ? true : false; +//} + +//inline bool isOverS32() { +// return (g_dsp.r[DSP_REG_SR] & SR_OVER_S32) ? true : false; +//} + +//inline bool isLess() { +// return (!(g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) != !(g_dsp.r[DSP_REG_SR] & SR_SIGN)); +//} + +//inline bool isZero() { +// return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false; +//} + +//inline bool isLogicZero() { +// return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) ? true : false; +//} + +//inline bool isConditionA() { +// return (((g_dsp.r[DSP_REG_SR] & SR_OVER_S32) || (g_dsp.r[DSP_REG_SR] & SR_TOP2BITS)) && !(g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO)) ? true : false; +//} + +//see DSPCore.h for flags +//bool CheckCondition(u8 _Condition) +//{ +// switch (_Condition & 0xf) +// { +// case 0xf: // Always true. +// return true; +// case 0x0: // GE - Greater Equal +// return !isLess(); +// case 0x1: // L - Less +// return isLess(); +// case 0x2: // G - Greater +// return !isLess() && !isZero(); +// case 0x3: // LE - Less Equal +// return isLess() || isZero(); +// case 0x4: // NZ - Not Zero +// return !isZero(); +// case 0x5: // Z - Zero +// return isZero(); +// case 0x6: // NC - Not carry +// return !isCarry(); +// case 0x7: // C - Carry +// return isCarry(); +// case 0x8: // ? - Not over s32 +// return !isOverS32(); +// case 0x9: // ? - Over s32 +// return isOverS32(); +// case 0xa: // ? +// return isConditionA(); +// case 0xb: // ? +// return !isConditionA(); +// case 0xc: // LNZ - Logic Not Zero +// return !isLogicZero(); +// case 0xd: // LZ - Logic Zero +// return isLogicZero(); +// case 0xe: // 0 - Overflow +// return isOverflow(); +// default: +// return true; +// } +//} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp new file mode 100644 index 0000000000..084385e2e4 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp @@ -0,0 +1,639 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ +#include "../DSPMemoryMap.h" +#include "../DSPEmitter.h" +#include "DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" + +using namespace Gen; + +/* It is safe to directly write to the address registers as they are + neither read not written by any extendable opcode. The same is true + for memory accesses. + It probably even is safe to write to all registers except for + SR, ACx.x, AXx.x and PROD, which may be modified by the main op. + + This code uses EBX to keep the values of the registers written by + the extended op so the main op can still access the old values. + storeIndex and storeIndex2 control where the lower and upper 16bits + of EBX are written to. Additionally, the upper 16bits can contain the + original SR so we can do sign extension in 40bit mode. There is only + the 'ld family of opcodes writing to two registers at the same time, + and those always are AXx.x, thus no need to leave space for SR for + sign extension. + */ + +// DR $arR +// xxxx xxxx 0000 01rr +// Decrement addressing register $arR. +void DSPEmitter::dr(const UDSPInstruction opc) { + decrement_addr_reg(opc & 0x3); +} + +// IR $arR +// xxxx xxxx 0000 10rr +// Increment addressing register $arR. +void DSPEmitter::ir(const UDSPInstruction opc) { + increment_addr_reg(opc & 0x3); +} + +// NR $arR +// xxxx xxxx 0000 11rr +// Add corresponding indexing register $ixR to addressing register $arR. +void DSPEmitter::nr(const UDSPInstruction opc) { + u8 reg = opc & 0x3; + + increase_addr_reg(reg); +} + +// MV $axD.D, $acS.S +// xxxx xxxx 0001 ddss +// Move value of $acS.S to the $axD.D. +void DSPEmitter::mv(const UDSPInstruction opc) +{ + u8 sreg = (opc & 0x3) + DSP_REG_ACL0; + u8 dreg = ((opc >> 2) & 0x3); + pushExtValueFromReg(dreg + DSP_REG_AXL0, sreg); +} + +// S @$arD, $acS.S +// xxxx xxxx 001s s0dd +// Store value of $acS.S in the memory pointed by register $arD. +// Post increment register $arD. +void DSPEmitter::s(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + // u16 addr = g_dsp.r[dest]; + dsp_op_read_reg(dreg, RAX, ZERO); + dsp_op_read_reg(sreg, RCX, ZERO); + // u16 val = g_dsp.r[src]; + dmem_write(); + increment_addr_reg(dreg); +} + +// SN @$arD, $acS.S +// xxxx xxxx 001s s1dd +// Store value of register $acS.S in the memory pointed by register $arD. +// Add indexing register $ixD to register $arD. +void DSPEmitter::sn(const UDSPInstruction opc) +{ + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + dsp_op_read_reg(dreg, RAX, ZERO); + dsp_op_read_reg(sreg, RCX, ZERO); + dmem_write(); + increase_addr_reg(dreg); +} + +// L $axD.D, @$arS +// xxxx xxxx 01dd d0ss +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Post increment register $arS. +void DSPEmitter::l(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; //AX?.?, AC?.[LM] + + pushExtValueFromMem(dreg, sreg); + + if (dreg >= DSP_REG_ACM0) { + //save SR too, so we can decide later. + //even if only for one bit, can only + //store (up to) two registers in EBX, + //so store all of SR +#ifdef _M_IX86 // All32 + MOV(16, R(EAX), M(&g_dsp.r.sr)); +#else + MOV(64, R(RAX), ImmPtr(&g_dsp.r.sr)); + MOV(16, R(RAX), MatR(RAX)); +#endif + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); + } + + increment_addr_reg(sreg); +} + +// LN $axD.D, @$arS +// xxxx xxxx 01dd d0ss +// Load $axD.D/$acD.D with value from memory pointed by register $arS. +// Add indexing register register $ixS to register $arS. +void DSPEmitter::ln(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + + pushExtValueFromMem(dreg, sreg); + + if (dreg >= DSP_REG_ACM0) { + //save SR too, so we can decide later. + //even if only for one bit, can only + //store (up to) two registers in EBX, + //so store all of SR +#ifdef _M_IX86 // All32 + MOV(16, R(EAX), M(&g_dsp.r.sr)); +#else + MOV(64, R(RAX), ImmPtr(&g_dsp.r.sr)); + MOV(16, R(RAX), MatR(RAX)); +#endif + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); + } + + increase_addr_reg(sreg); +} + +// LS $axD.D, $acS.m +// xxxx xxxx 10dd 000s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Increment both $ar0 and $ar3. +void DSPEmitter::ls(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR0); + + increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); +} + + +// LSN $axD.D, $acS.m +// xxxx xxxx 10dd 010s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix0 to addressing +// register $ar0 and increment $ar3. +void DSPEmitter::lsn(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR0); + + increment_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0); +} + +// LSM $axD.D, $acS.m +// xxxx xxxx 10dd 100s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix3 to addressing +// register $ar3 and increment $ar0. +void DSPEmitter::lsm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR0); + + increase_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); +} + +// LSMN $axD.D, $acS.m +// xxxx xxxx 10dd 110s +// Load register $axD.D with value from memory pointed by register +// $ar0. Store value from register $acS.m to memory location pointed by +// register $ar3. Add corresponding indexing register $ix0 to addressing +// register $ar0 and add corresponding indexing register $ix3 to addressing +// register $ar3. +void DSPEmitter::lsnm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR0); + + increase_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0); +} + +// SL $acS.m, $axD.D +// xxxx xxxx 10dd 001s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Increment both $ar0 and $ar3. +void DSPEmitter::sl(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR3); + + increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); +} + +// SLN $acS.m, $axD.D +// xxxx xxxx 10dd 011s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 +// and increment $ar3. +void DSPEmitter::sln(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR3); + + increment_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0); +} + +// SLM $acS.m, $axD.D +// xxxx xxxx 10dd 101s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3 +// and increment $ar0. +void DSPEmitter::slm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR3); + + increase_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); +} + +// SLMN $acS.m, $axD.D +// xxxx xxxx 10dd 111s +// Store value from register $acS.m to memory location pointed by register +// $ar0. Load register $axD.D with value from memory pointed by register +// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 +// and add corresponding indexing register $ix3 to addressing register $ar3. +void DSPEmitter::slnm(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + get_acc_m(sreg, ECX, false); + dmem_write(); + + pushExtValueFromMem(dreg, DSP_REG_AR3); + + increase_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0); +} + +// LD $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 00ss +// example for "nx'ld $AX0.L, $AX1.L, @$AR3" +// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 +// to AX0.L. Increments AR0 and AR3. If AR0 and AR3 point into the same +// memory page (upper 6 bits of addr are the same -> games are not doing that!) +// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. If AR0 +// points into an invalid memory page (ie 0x2000), then AX0.H keeps its old +// value. (not implemented yet) If AR3 points into an invalid memory page, then +// AX0.L gets the same value as AX0.H. (not implemented yet) +void DSPEmitter::ld(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.flushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increment_addr_reg(sreg); + + } else { + pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); + + //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(dreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); + gpr.flushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increment_addr_reg(dreg); + } + + increment_addr_reg(DSP_REG_AR3); +} + +// LDN $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 01ss +void DSPEmitter::ldn(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + + //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.flushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increase_addr_reg(sreg); + } else { + pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); + + //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(dreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); + gpr.flushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increase_addr_reg(dreg); + } + + increment_addr_reg(DSP_REG_AR3); +} + +// LDM $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 10ss +void DSPEmitter::ldm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + + //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.flushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increment_addr_reg(sreg); + } else { + pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); + + //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(dreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); + gpr.flushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increment_addr_reg(dreg); + } + + increase_addr_reg(DSP_REG_AR3); +} + +// LDNM $ax0.d, $ax1.r, @$arS +// xxxx xxxx 11dr 11ss +void DSPEmitter::ldnm(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; + + if (sreg != DSP_REG_AR3) { + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + + //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.flushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increase_addr_reg(sreg); + } else { + pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); + + //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(dreg, RSI, NONE); + dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); + SHR(16, R(ESI), Imm8(10)); + SHR(16, R(EDI), Imm8(10)); + DSPJitRegCache c(gpr); + CMP(16, R(ESI), R(EDI)); + FixupBranch not_equal = J_CC(CC_NE,true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); + gpr.flushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.flushRegs(c); + SetJumpTarget(after); + + increase_addr_reg(dreg); + } + + increase_addr_reg(DSP_REG_AR3); +} + + +// Push value from g_dsp.r[sreg] into EBX and stores the destinationindex in +// storeIndex +void DSPEmitter::pushExtValueFromReg(u16 dreg, u16 sreg) { + dsp_op_read_reg(sreg, RBX, ZERO); + storeIndex = dreg; +} + +void DSPEmitter::pushExtValueFromMem(u16 dreg, u16 sreg) { + // u16 addr = g_dsp.r[addr]; + dsp_op_read_reg(sreg, RCX, ZERO); + dmem_read(); + MOVZX(32, 16, EBX, R(EAX)); + + storeIndex = dreg; +} + +void DSPEmitter::pushExtValueFromMem2(u16 dreg, u16 sreg) { + // u16 addr = g_dsp.r[addr]; + dsp_op_read_reg(sreg, RCX, ZERO); + dmem_read(); + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); + + storeIndex2 = dreg; +} + +void DSPEmitter::popExtValueToReg() { + // in practise, we rarely ever have a non-NX main op + // with an extended op, so the OR here is either + // not run (storeIndex == -1) or ends up OR'ing + // EBX with 0 (becoming the MOV we have here) + // nakee wants to keep it clean, so lets do that. + // [nakeee] the or case never happens in real + // [nakeee] it's just how the hardware works so we added it + if (storeIndex != -1) { + dsp_op_write_reg(storeIndex, RBX); + if (storeIndex >= DSP_REG_ACM0 && storeIndex2 == -1) { + TEST(32, R(EBX), Imm32(SR_40_MODE_BIT << 16)); + FixupBranch not_40bit = J_CC(CC_Z); + DSPJitRegCache c(gpr); + //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + //u16 val = g_dsp.r[reg]; + MOVSX(32, 16, EAX, R(EBX)); + SHR(32, R(EAX), Imm8(16)); + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(storeIndex - DSP_REG_ACM0, R(RAX)); + set_acc_l(storeIndex - DSP_REG_ACM0, Imm16(0)); + //} + gpr.flushRegs(c); + SetJumpTarget(not_40bit); + } + } + + storeIndex = -1; + + if (storeIndex2 != -1) { + SHR(32, R(EBX), Imm8(16)); + dsp_op_write_reg(storeIndex2, RBX); + } + storeIndex2 = -1; +} + +// This function is being called in the main op after all input regs were read +// and before it writes into any regs. This way we can always use bitwise or to +// apply the ext command output, because if the main op didn't change the value +// then 0 | ext output = ext output and if it did then bitwise or is still the +// right thing to do +//this is only needed as long as we do fallback for ext ops +void DSPEmitter::zeroWriteBackLog(const UDSPInstruction opc) +{ + const DSPOPCTemplate *tinst = GetOpTemplate(opc); + + // Call extended + if (!tinst->extended) + return; + + if ((opc >> 12) == 0x3) { + if (! extOpTable[opc & 0x7F]->jitFunc) + { + SaveDSPRegs(); + ABI_CallFunction((void*)::zeroWriteBackLog); + LoadDSPRegs(); + } + } else { + if (! extOpTable[opc & 0xFF]->jitFunc) + { + SaveDSPRegs(); + ABI_CallFunction((void*)::zeroWriteBackLog); + LoadDSPRegs(); + } + } + return; +} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp new file mode 100644 index 0000000000..bd4a320bb3 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp @@ -0,0 +1,294 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "../DSPIntCCUtil.h" +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +// SRS @M, $(0x18+S) +// 0010 1sss mmmm mmmm +// Move value from register $(0x18+D) to data memory pointed by address +// CR[0-7] | M. That is, the upper 8 bits of the address are the +// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate. +// Note: pc+=2 in duddie's doc seems wrong +void DSPEmitter::srs(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + 0x18; + //u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + dsp_op_read_reg(reg, RCX, ZERO); + dsp_op_read_reg(DSP_REG_CR, RAX, ZERO); + SHL(16, R(EAX), Imm8(8)); + OR(8, R(EAX), Imm8(opc & 0xFF)); + dmem_write(); +} + +// LRS $(0x18+D), @M +// 0010 0ddd mmmm mmmm +// Move value from data memory pointed by address CR[0-7] | M to register +// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits +// from CR, and the lower 8 bits are from the 8-bit immediate. +void DSPEmitter::lrs(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + 0x18; + //u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF); + dsp_op_read_reg(DSP_REG_CR, RCX, ZERO); + SHL(16, R(ECX), Imm8(8)); + OR(8, R(ECX), Imm8(opc & 0xFF)); + dmem_read(); + dsp_op_write_reg(reg, RAX); + dsp_conditional_extend_accum(reg); +} + +// LR $D, @M +// 0000 0000 110d dddd +// mmmm mmmm mmmm mmmm +// Move value from data memory pointed by address M to register $D. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lr(const UDSPInstruction opc) +{ + int reg = opc & DSP_REG_MASK; + u16 address = dsp_imem_read(compilePC + 1); + dmem_read_imm(address); + dsp_op_write_reg(reg, EAX); + dsp_conditional_extend_accum(reg); +} + +// SR @M, $S +// 0000 0000 111s ssss +// mmmm mmmm mmmm mmmm +// Store value from register $S to a memory pointed by address M. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::sr(const UDSPInstruction opc) +{ + u8 reg = opc & DSP_REG_MASK; + u16 address = dsp_imem_read(compilePC + 1); + dsp_op_read_reg(reg, ECX); + dmem_write_imm(address); +} + +// SI @M, #I +// 0001 0110 mmmm mmmm +// iiii iiii iiii iiii +// Store 16-bit immediate value I to a memory location pointed by address +// M (M is 8-bit value sign extended). +void DSPEmitter::si(const UDSPInstruction opc) +{ + u16 address = (s8)opc; + u16 imm = dsp_imem_read(compilePC + 1); + MOV(32, R(ECX), Imm32((u32)imm)); + dmem_write_imm(address); +} + +// LRR $D, @$S +// 0001 1000 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lrr(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dmem_read(); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); +} + +// LRRD $D, @$S +// 0001 1000 1ssd dddd +// Move value from data memory pointed by addressing register $S toregister $D. +// Decrement register $S. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lrrd(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dmem_read(); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + decrement_addr_reg(sreg); +} + +// LRRI $D, @$S +// 0001 1001 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Increment register $S. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lrri(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dmem_read(); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + increment_addr_reg(sreg); +} + +// LRRN $D, @$S +// 0001 1001 1ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Add indexing register $(0x4+S) to register $S. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lrrn(const UDSPInstruction opc) +{ + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dmem_read(); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + increase_addr_reg(sreg); +} + +// SRR @$D, $S +// 0001 1010 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. +// FIXME: Perform additional operation depending on source register. +void DSPEmitter::srr(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(); +} + +// SRRD @$D, $S +// 0001 1010 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Decrement register $D. +// FIXME: Perform additional operation depending on source register. +void DSPEmitter::srrd(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(); + decrement_addr_reg(dreg); +} + +// SRRI @$D, $S +// 0001 1011 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Increment register $D. +// FIXME: Perform additional operation depending on source register. +void DSPEmitter::srri(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(); + increment_addr_reg(dreg); +} + +// SRRN @$D, $S +// 0001 1011 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Add DSP_REG_IX0 register to register $D. +// FIXME: Perform additional operation depending on source register. +void DSPEmitter::srrn(const UDSPInstruction opc) +{ + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; + + dsp_op_read_reg(sreg, ECX); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(); + increase_addr_reg(dreg); +} + +// ILRR $acD.m, @$arS +// 0000 001d 0001 00ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. +void DSPEmitter::ilrr(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; + + dsp_op_read_reg(reg, RCX, ZERO); + imem_read(); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg); +} + +// ILRRD $acD.m, @$arS +// 0000 001d 0001 01ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. +void DSPEmitter::ilrrd(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; + + dsp_op_read_reg(reg, RCX, ZERO); + imem_read(); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg); + decrement_addr_reg(reg); +} + +// ILRRI $acD.m, @$S +// 0000 001d 0001 10ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Increment addressing register $arS. +void DSPEmitter::ilrri(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; + + dsp_op_read_reg(reg, RCX, ZERO); + imem_read(); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg); + increment_addr_reg(reg); +} + +// ILRRN $acD.m, @$arS +// 0000 001d 0001 11ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Add corresponding indexing +// register $ixS to addressing register $arS. +void DSPEmitter::ilrrn(const UDSPInstruction opc) +{ + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; + + dsp_op_read_reg(reg, RCX, ZERO); + imem_read(); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg); + increase_addr_reg(reg); +} + diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp new file mode 100644 index 0000000000..2c8cc790de --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp @@ -0,0 +1,468 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +//clobbers: +//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] +//CX = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] +//expects: +//R11 = &g_dsp.r +void DSPEmitter::dsp_reg_stack_push(int stack_reg) +{ + //g_dsp.reg_stack_ptr[stack_reg]++; + //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; +#ifdef _M_IX86 // All32 + MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); +#else + MOV(8, R(AL), MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg], + &g_dsp.r))); +#endif + ADD(8, R(AL), Imm8(1)); + AND(8, R(AL), Imm8(DSP_STACK_MASK)); +#ifdef _M_IX86 // All32 + MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); +#else + MOV(8, MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg], + &g_dsp.r)), R(AL)); +#endif + + //g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg]; +#ifdef _M_IX86 // All32 + MOV(16, R(CX), M(&g_dsp.r.st[stack_reg])); + MOVZX(32, 8, EAX, R(AL)); + MOV(16, MComplex(EAX, EAX, 1, (u32)&g_dsp.reg_stack[stack_reg][0]), R(CX)); +#else + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOV(16, R(CX), MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg]))); + MOVZX(64, 8, RAX, R(AL)); + MOV(16, MComplex(R11, RAX, 2, + PtrOffset(&g_dsp.reg_stack[stack_reg][0],&g_dsp.r)), + R(CX)); +#endif +} + +//clobbers: +//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] +//CX = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] +//expects: +//R11 = &g_dsp.r +void DSPEmitter::dsp_reg_stack_pop(int stack_reg) +{ + //g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; +#ifdef _M_IX86 // All32 + MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); +#else + MOV(8, R(AL), + MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg],&g_dsp.r))); +#endif +#ifdef _M_IX86 // All32 + MOVZX(32, 8, EAX, R(AL)); + MOV(16, R(CX), MComplex(EAX, EAX, 1, (u32)&g_dsp.reg_stack[stack_reg][0])); + MOV(16, M(&g_dsp.r.st[stack_reg]), R(CX)); +#else + MOVZX(64, 8, RAX, R(AL)); + MOV(16, R(CX), MComplex(R11, RAX, 2, + PtrOffset(&g_dsp.reg_stack[stack_reg][0], + &g_dsp.r))); + MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), R(CX)); +#endif + + //g_dsp.reg_stack_ptr[stack_reg]--; + //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + SUB(8, R(AL), Imm8(1)); + AND(8, R(AL), Imm8(DSP_STACK_MASK)); +#ifdef _M_IX86 // All32 + MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); +#else + MOV(8, MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg],&g_dsp.r)), + R(AL)); +#endif +} + + +void DSPEmitter::dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg) +{ + if (host_sreg != EDX) { + MOV(16, R(EDX), R(host_sreg)); + } + dsp_reg_stack_push(stack_reg); + //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.r.st[stack_reg]), R(EDX)); +#else + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), R(EDX)); +#endif +} + +void DSPEmitter::dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg) +{ + //u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg]; +#ifdef _M_IX86 // All32 + MOV(16, R(EDX), M(&g_dsp.r.st[stack_reg])); +#else + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOV(16, R(EDX), MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg]))); +#endif + dsp_reg_stack_pop(stack_reg); + if (host_dreg != EDX) { + MOV(16, R(host_dreg), R(EDX)); + } +} + +void DSPEmitter::dsp_reg_store_stack_imm(int stack_reg, u16 val) +{ + dsp_reg_stack_push(stack_reg); + //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.r.st[stack_reg]), Imm16(val)); +#else + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), Imm16(val)); +#endif +} + +void DSPEmitter::dsp_op_write_reg(int reg, Gen::X64Reg host_sreg) +{ + switch (reg & 0x1f) { + // 8-bit sign extended registers. + case DSP_REG_ACH0: + case DSP_REG_ACH1: + gpr.writeReg(reg, R(host_sreg)); + break; + + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack(reg - DSP_REG_ST0, host_sreg); + break; + + default: + gpr.writeReg(reg, R(host_sreg)); + break; + } +} + +void DSPEmitter::dsp_op_write_reg_imm(int reg, u16 val) +{ + switch (reg & 0x1f) { + // 8-bit sign extended registers. Should look at prod.h too... + case DSP_REG_ACH0: + case DSP_REG_ACH1: + gpr.writeReg(reg, Imm16((u16)(s16)(s8)(u8)val)); + break; + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack_imm(reg - DSP_REG_ST0, val); + break; + + default: + gpr.writeReg(reg, Imm16(val)); + break; + } +} + +void DSPEmitter::dsp_conditional_extend_accum(int reg) +{ + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + DSPJitRegCache c(gpr); + TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); + FixupBranch not_40bit = J_CC(CC_Z,true); + //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + //u16 val = g_dsp.r[reg]; + get_acc_m(reg - DSP_REG_ACM0, EAX); + SHR(32, R(EAX), Imm8(16)); + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(reg - DSP_REG_ACM0, R(RAX)); + set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); + //} + gpr.flushRegs(c); + SetJumpTarget(not_40bit); + gpr.putReg(DSP_REG_SR); + } + } +} + +void DSPEmitter::dsp_conditional_extend_accum_imm(int reg, u16 val) +{ + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + DSPJitRegCache c(gpr); + TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); + FixupBranch not_40bit = J_CC(CC_Z); + //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(reg - DSP_REG_ACM0, Imm16((val & 0x8000)?0xffff:0x0000)); + set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); + //} + gpr.flushRegs(c); + SetJumpTarget(not_40bit); + gpr.putReg(DSP_REG_SR); + } + } +} + +void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend) +{ + switch (reg & 0x1f) { + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); + switch(extend) { + case SIGN: +#ifdef _M_IX86 // All32 + MOVSX(32, 16, host_dreg, R(host_dreg)); +#else + MOVSX(64, 16, host_dreg, R(host_dreg)); +#endif + break; + case ZERO: +#ifdef _M_IX86 // All32 + MOVZX(32, 16, host_dreg, R(host_dreg)); +#else + MOVZX(64, 16, host_dreg, R(host_dreg)); +#endif + break; + case NONE: + default: + break; + } + return; + default: + gpr.readReg(reg, host_dreg, extend); + return; + } +} + +// MRR $D, $S +// 0001 11dd ddds ssss +// Move value from register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::mrr(const UDSPInstruction opc) +{ + u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x1f; + + dsp_op_read_reg(sreg, EDX); + dsp_op_write_reg(dreg, EDX); + dsp_conditional_extend_accum(dreg); +} + +// LRI $D, #I +// 0000 0000 100d dddd +// iiii iiii iiii iiii +// Load immediate value I to register $D. +// +// DSPSpy discovery: This, and possibly other instructions that load a +// register, has a different behaviour in S40 mode if loaded to AC0.M: The +// value gets sign extended to the whole accumulator! This does not happen in +// S16 mode. +void DSPEmitter::lri(const UDSPInstruction opc) +{ + u8 reg = opc & DSP_REG_MASK; + u16 imm = dsp_imem_read(compilePC+1); + dsp_op_write_reg_imm(reg, imm); + dsp_conditional_extend_accum_imm(reg, imm); +} + +// LRIS $(0x18+D), #I +// 0000 1ddd iiii iiii +// Load immediate value I (8-bit sign extended) to accumulator register. +// FIXME: Perform additional operation depending on destination register. +void DSPEmitter::lris(const UDSPInstruction opc) +{ + u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc; + dsp_op_write_reg_imm(reg, imm); + dsp_conditional_extend_accum_imm(reg, imm); +} + +//---- + +// NX +// 1000 -000 xxxx xxxx +// No operation, but can be extended with extended opcode. +// This opcode is supposed to do nothing - it's used if you want to use +// an opcode extension but not do anything. At least according to duddie. +void DSPEmitter::nx(const UDSPInstruction opc) +{ + zeroWriteBackLog(opc); +} + +//---- + +// DAR $arD +// 0000 0000 0000 01dd +// Decrement address register $arD. +void DSPEmitter::dar(const UDSPInstruction opc) +{ + // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); + decrement_addr_reg(opc & 0x3); + +} + +// IAR $arD +// 0000 0000 0000 10dd +// Increment address register $arD. +void DSPEmitter::iar(const UDSPInstruction opc) +{ + // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); + increment_addr_reg(opc & 0x3); +} + +// SUBARN $arD +// 0000 0000 0000 11dd +// Subtract indexing register $ixD from an addressing register $arD. +// used only in IPL-NTSC ucode +void DSPEmitter::subarn(const UDSPInstruction opc) +{ + // u8 dreg = opc & 0x3; + // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); + decrease_addr_reg(opc & 0x3); +} + +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +// It is critical for the Zelda ucode that this one wraps correctly. +void DSPEmitter::addarn(const UDSPInstruction opc) +{ + // u8 dreg = opc & 0x3; + // u8 sreg = (opc >> 2) & 0x3; + // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); + + // From looking around it is always called with the matching index register + increase_addr_reg(opc & 0x3); +} + +//---- + + +void DSPEmitter::setCompileSR(u16 bit) { + + // g_dsp.r[DSP_REG_SR] |= bit + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + OR(16, sr_reg, Imm16(bit)); + gpr.putReg(DSP_REG_SR); + + compileSR |= bit; +} + +void DSPEmitter::clrCompileSR(u16 bit) { + + // g_dsp.r[DSP_REG_SR] &= bit + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + AND(16, sr_reg, Imm16(~bit)); + gpr.putReg(DSP_REG_SR); + + compileSR &= ~bit; +} +// SBCLR #I +// 0001 0011 aaaa aiii +// bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void DSPEmitter::sbclr(const UDSPInstruction opc) +{ + u8 bit = (opc & 0x7) + 6; + + clrCompileSR(1 << bit); +} + +// SBSET #I +// 0001 0010 aaaa aiii +// Set bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void DSPEmitter::sbset(const UDSPInstruction opc) +{ + u8 bit = (opc & 0x7) + 6; + + setCompileSR(1 << bit); +} + +// 1000 1bbb xxxx xxxx, bbb >= 010 +// This is a bunch of flag setters, flipping bits in SR. So far so good, +// but it's harder to know exactly what effect they have. +void DSPEmitter::srbith(const UDSPInstruction opc) +{ + zeroWriteBackLog(opc); + switch ((opc >> 8) & 0xf) + { + // M0/M2 change the multiplier mode (it can multiply by 2 for free). + case 0xa: // M2 + clrCompileSR(SR_MUL_MODIFY); + break; + case 0xb: // M0 + setCompileSR(SR_MUL_MODIFY); + break; + + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + clrCompileSR(SR_MUL_UNSIGNED); + break; + case 0xd: // SET15 + setCompileSR(SR_MUL_UNSIGNED); + break; + + // Automatic 40-bit sign extension when loading ACx.M. + // SET40 changes something very important: see the LRI instruction above. + case 0xe: // SET16 (CLR40) + clrCompileSR(SR_40_MODE_BIT); + break; + + case 0xf: // SET40 + setCompileSR(SR_40_MODE_BIT); + break; + + default: + break; + } +} + diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp new file mode 100644 index 0000000000..0004b33396 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp @@ -0,0 +1,885 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// Multiplier and product register control + +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "../DSPAnalyzer.h" +#ifdef _M_X64 +#include "DSPJitUtil.h" +#endif +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +// Returns s64 in RAX +// In: RSI = s16 a, RDI = s16 b +void DSPEmitter::multiply() +{ +#ifdef _M_X64 +// prod = (s16)a * (s16)b; //signed + MOV(64, R(EAX), R(RDI)); + IMUL(64, R(ESI)); + +// Conditionally multiply by 2. +// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); + FixupBranch noMult2 = J_CC(CC_NZ); +// prod <<= 1; + SHL(64, R(EAX), Imm8(1)); + SetJumpTarget(noMult2); + gpr.putReg(DSP_REG_SR); +// return prod; +#endif +} + +// Returns s64 in RAX +// Clobbers RDX +void DSPEmitter::multiply_add() +{ +// s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); + multiply(); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); +// return prod; +} + +// Returns s64 in RAX +// Clobbers RDX +void DSPEmitter::multiply_sub() +{ +// s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); + multiply(); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + SUB(64, R(RAX), R(RDX)); +// return prod; +} + +// Only MULX family instructions have unsigned/mixed support. +// Returns s64 in EAX +// In: RSI = s16 a, RDI = s16 b +// Returns s64 in RAX +void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1) +{ +// s64 result; + +// if ((axh0==0) && (axh1==0)) +// result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used +// else if ((axh0==0) && (axh1==1)) +// result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 +// else if ((axh0==1) && (axh1==0)) +// result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 +// else +// result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + + +// if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned + OpArg sr_reg; + gpr.getReg(DSP_REG_SR,sr_reg); + TEST(16, sr_reg, Imm16(SR_MUL_UNSIGNED)); + FixupBranch unsignedMul = J_CC(CC_NZ); + // prod = (s16)a * (s16)b; //signed + MOVSX(64, 16, RAX, R(RDI)); + IMUL(64, R(RSI)); + FixupBranch signedMul = J(); + + SetJumpTarget(unsignedMul); + if ((axh0==0) && (axh1==0)) + { + // unsigned support ON if both ax?.l regs are used +// prod = (u32)(a * b); + MOVZX(64, 16, RSI, R(RSI)); + MOVZX(64, 16, RAX, R(RDI)); + MUL(64, R(RSI)); + } + else if ((axh0==0) && (axh1==1)) + { + // mixed support ON (u16)axl.0 * (s16)axh.1 +// prod = a * (s16)b; + MOVZX(64, 16, RAX, R(RSI)); + IMUL(64, R(RDI)); + } + else if ((axh0==1) && (axh1==0)) + { + // mixed support ON (u16)axl.1 * (s16)axh.0 +// prod = (s16)a * b; + MOVZX(64, 16, RAX, R(RDI)); + IMUL(64, R(RSI)); + } + else + { + // unsigned support OFF if both ax?.h regs are used +// prod = (s16)a * (s16)b; //signed + MOVSX(64, 16, RAX, R(RDI)); + IMUL(64, R(RSI)); + } + + SetJumpTarget(signedMul); + + // Conditionally multiply by 2. +// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); + FixupBranch noMult2 = J_CC(CC_NZ); +// prod <<= 1; + SHL(64, R(RAX), Imm8(1)); + SetJumpTarget(noMult2); + gpr.putReg(DSP_REG_SR); +// return prod; +} + +//---- + +// CLRP +// 1000 0100 xxxx xxxx +// Clears product register $prod. +// Magic numbers taken from duddie's doc + +// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 + +// It's not ok, to just zero all of them, correct values should be set because of +// direct use of prod regs by AX/AXWII (look @that part of ucode). +void DSPEmitter::clrp(const UDSPInstruction opc) +{ +#ifdef _M_X64 +// g_dsp.r[DSP_REG_PRODL] = 0x0000; +// g_dsp.r[DSP_REG_PRODM] = 0xfff0; +// g_dsp.r[DSP_REG_PRODH] = 0x00ff; +// g_dsp.r[DSP_REG_PRODM2] = 0x0010; + //64bit move to memory does not work. use 2 32bits + MOV(32, MDisp(R11, STRUCT_OFFSET(g_dsp.r, prod.val)+0), Imm32(0xfff00000U)); + MOV(32, MDisp(R11, STRUCT_OFFSET(g_dsp.r, prod.val)+4), Imm32(0x001000ffU)); +#else + Default(opc); +#endif +} + +// TSTPROD +// 1000 0101 xxxx xxxx +// Test prod regs value. + +// flags out: --xx xx0x +void DSPEmitter::tstprod(const UDSPInstruction opc) +{ +#ifdef _M_X64 + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { +// s64 prod = dsp_get_long_prod(); + get_long_prod(); +// Update_SR_Register64(prod); + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +//---- + +// MOVP $acD +// 0110 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD register. + +// flags out: --xx xx0x +void DSPEmitter::movp(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_prod(); + get_long_prod(); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(acc); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MOVNP $acD +// 0111 111d xxxx xxxx +// Moves negative of multiply product from $prod register to accumulator +// $acD register. + +// flags out: --xx xx0x +void DSPEmitter::movnp(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = -dsp_get_long_prod(); + get_long_prod(); + NEG(64, R(EAX)); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(acc); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets (rounds) $acD.l to 0 + +// flags out: --xx xx0x +void DSPEmitter::movpz(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x01; + +// s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); +// dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); +// Update_SR_Register64(acc); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// ADDPAXZ $acD, $axS +// 1111 10sd xxxx xxxx +// Adds secondary accumulator $axS to product register and stores result +// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0. + +// flags out: --xx xx0x +void DSPEmitter::addpaxz(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// s64 ax = dsp_get_long_acx(sreg); + get_long_acx(sreg, RCX); + MOV(64, R(RDI), R(RCX)); +// s64 res = prod + (ax & ~0xffff); + MOV(64, R(RDX), Imm64(~0xffff)); + AND(64, R(RDI), R(RDX)); +// s64 prod = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); + ADD(64, R(RAX), R(RDI)); + +// s64 oldprod = dsp_get_long_prod(); +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(oldprod, res), false); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + get_long_prod(RDX); + MOV(64, R(RSI), R(RAX)); + set_long_acc(dreg, RSI); + Update_SR_Register64_Carry(); + } + else + { + set_long_acc(dreg, RAX); + } +#else + Default(opc); +#endif +} + +//---- + +// MULAXH +// 1000 0011 xxxx xxxx +// Multiply $ax0.h by $ax0.h +void DSPEmitter::mulaxh(const UDSPInstruction opc) +{ +#ifdef _M_X64 +// s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); + dsp_op_read_reg(DSP_REG_AXH0, RSI, SIGN); + MOV(64, R(RDI), R(RSI)); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +//---- + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void DSPEmitter::mul(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 sreg = (opc >> 11) & 0x1; + +// u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); +// u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); +// s64 prod = dsp_multiply(axh, axl); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). + +// flags out: --xx xx0x +void DSPEmitter::mulac(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + get_long_acc(rreg); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); + PUSH(64, R(RAX)); +// u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); +// u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); +// s64 prod = dsp_multiply(axl, axh); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). + +// flags out: --xx xx0x +void DSPEmitter::mulmv(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_prod(); + get_long_prod(); + PUSH(64, R(RAX)); + mul(opc); +// dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear (round) low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). + +// flags out: --xx xx0x +void DSPEmitter::mulmvz(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(RDX); +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, RDX); + mul(opc); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RDX); + } +#else + Default(opc); +#endif +} + +//---- + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1. +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void DSPEmitter::mulx(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = ((opc >> 11) & 0x1); + u8 sreg = ((opc >> 12) & 0x1); + + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); +// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); +// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); +// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1. Part is selected by S and +// T bits. Zero selects low part, one selects high part. + +// flags out: --xx xx0x +void DSPEmitter::mulxac(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + get_long_acc(rreg, RCX); + get_long_prod(); + ADD(64, R(RCX), R(RAX)); +// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); +// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); +// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); + +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, RCX); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RCX); + } +#else + Default(opc); +#endif +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1. Part is selected by S and +// T bits. Zero selects low part, one selects high part. + +// flags out: --xx xx0x +void DSPEmitter::mulxmv(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = ((opc >> 8) & 0x1); + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// s64 acc = dsp_get_long_prod(); + get_long_prod(RCX); +// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); +// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); +// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); + +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, RCX); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RCX); + } +#else + Default(opc); +#endif +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear (round) low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 +// Part is selected by S and T bits. Zero selects low part, +// one selects high part. + +// flags out: --xx xx0x +void DSPEmitter::mulxmvz(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(RCX); +// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); +// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); +// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); + +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, RCX); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(RCX); + } +#else + Default(opc); +#endif +} + +//---- + +// MULC $acS.m, $axT.h +// 110s t000 xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). +void DSPEmitter::mulc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply(accm, axh); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. + +// flags out: --xx xx0x +void DSPEmitter::mulcac(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + get_long_acc(rreg); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); + PUSH(64, R(RAX)); +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply(accm, axh); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h + +// flags out: --xx xx0x +void DSPEmitter::mulcmv(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + +// s64 acc = dsp_get_long_prod(); + get_long_prod(); + PUSH(64, R(RAX)); +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply(accm, axh); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +// MULCMVZ $acS.m, $axT.h, $acR +// 110s t01r xxxx xxxx +// (fixed possible bug in duddie's description, s->t) +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR, set (round) low part of +// accumulator $acR.l to zero. + +// flags out: --xx xx0x +void DSPEmitter::mulcmvz(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; + + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); +// s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); + PUSH(64, R(RAX)); +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply(accm, axh); + multiply(); +// dsp_set_long_prod(prod); + set_long_prod(); +// dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + { + Update_SR_Register64(); + } +#else + Default(opc); +#endif +} + +//---- + +// MADDX ax0.S ax1.T +// 1110 00st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and add result to product register. +void DSPEmitter::maddx(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); + // s64 prod = dsp_multiply_add(val1, val2); + multiply_add(); + // dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MSUBX $(0x18+S*2), $(0x19+T*2) +// 1110 01st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and subtract result from product register. +void DSPEmitter::msubx(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); + // s64 prod = dsp_multiply_sub(val1, val2); + multiply_sub(); + // dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MADDC $acS.m, $axT.h +// 1110 10st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and add result to product +// register. +void DSPEmitter::maddc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply_add(accm, axh); + multiply_add(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MSUBC $acS.m, $axT.h +// 1110 11st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and subtract result from +// product register. +void DSPEmitter::msubc(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + +// u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ESI); +// u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); +// s64 prod = dsp_multiply_sub(accm, axh); + multiply_sub(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MADD $axS.l, $axS.h +// 1111 001s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and add +// result to product register. +void DSPEmitter::madd(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 sreg = (opc >> 8) & 0x1; + +// u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); +// u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); +// s64 prod = dsp_multiply_add(axl, axh); + multiply_add(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} + +// MSUB $axS.l, $axS.h +// 1111 011s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and +// subtract result from product register. +void DSPEmitter::msub(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 sreg = (opc >> 8) & 0x1; + +// u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); +// u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); +// s64 prod = dsp_multiply_sub(axl, axh); + multiply_sub(); +// dsp_set_long_prod(prod); + set_long_prod(); +#else + Default(opc); +#endif +} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp new file mode 100644 index 0000000000..5a08db1982 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp @@ -0,0 +1,540 @@ +// Copyright (C) 2011 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DSPJitRegCache.h" +#include "../DSPEmitter.h" +#include "../DSPMemoryMap.h" + +using namespace Gen; + +static u16 *reg_ptr(int reg) { + switch(reg) { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return &g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return &g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return &g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return &g_dsp.r.st[reg - DSP_REG_ST0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return &g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: return &g_dsp.r.cr; + case DSP_REG_SR: return &g_dsp.r.sr; + case DSP_REG_PRODL: return &g_dsp.r.prod.l; + case DSP_REG_PRODM: return &g_dsp.r.prod.m; + case DSP_REG_PRODH: return &g_dsp.r.prod.h; + case DSP_REG_PRODM2: return &g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return &g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return &g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return &g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return &g_dsp.r.ac[reg - DSP_REG_ACM0].m; + default: + _assert_msg_(DSPLLE, 0, "cannot happen"); + return NULL; + } +} + +#define ROTATED_REG_ACCS +//#undef ROTATED_REG_ACCS + +DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter) + : emitter(_emitter), temporary(false), merged(false) { + for(unsigned int i = 0; i < NUMXREGS; i++) { + xregs[i].guest_reg = DSP_REG_STATIC; + } + xregs[RSP].guest_reg = DSP_REG_STATIC;//stack pointer + xregs[RBX].guest_reg = DSP_REG_STATIC;//extended op backing store + + xregs[RBP].guest_reg = DSP_REG_NONE;//definitely usable in dsplle because + //all external calls are protected + +#ifdef _M_X64 + xregs[R8].guest_reg = DSP_REG_STATIC;//acc0 + xregs[R9].guest_reg = DSP_REG_STATIC;//acc1 + xregs[R10].guest_reg = DSP_REG_NONE; + xregs[R11].guest_reg = DSP_REG_STATIC;//&g_dsp.r + xregs[R12].guest_reg = DSP_REG_STATIC;//used for cycle counting + xregs[R13].guest_reg = DSP_REG_NONE; + xregs[R14].guest_reg = DSP_REG_NONE; + xregs[R15].guest_reg = DSP_REG_NONE; +#endif + +#ifdef _M_X64 + acc[0].host_reg = R8; + acc[0].shift = 0; + acc[0].dirty = false; + acc[0].used = false; + acc[0].tmp_reg = INVALID_REG; + + acc[1].host_reg = R9; + acc[1].shift = 0; + acc[1].dirty = false; + acc[1].used = false; + acc[1].tmp_reg = INVALID_REG; +#endif + for(unsigned int i = 0; i < 32; i++) { + regs[i].mem = reg_ptr(i); + regs[i].size = 2; + } +#ifdef _M_X64 + regs[DSP_REG_ACC0_64].mem = &g_dsp.r.ac[0].val; + regs[DSP_REG_ACC0_64].size = 8; + regs[DSP_REG_ACC1_64].mem = &g_dsp.r.ac[1].val; + regs[DSP_REG_ACC1_64].size = 8; + regs[DSP_REG_PROD_64].mem = &g_dsp.r.prod.val; + regs[DSP_REG_PROD_64].size = 8; +#endif + regs[DSP_REG_AX0_32].mem = &g_dsp.r.ax[0].val; + regs[DSP_REG_AX0_32].size = 4; + regs[DSP_REG_AX1_32].mem = &g_dsp.r.ax[1].val; + regs[DSP_REG_AX1_32].size = 4; + for(unsigned int i = 0; i < DSP_REG_MAX_MEM_BACKED+1; i++) { + regs[i].dirty = false; +#ifdef _M_IX86 // All32 + regs[i].loc = M(regs[i].mem); +#else + regs[i].loc = MDisp(R11, PtrOffset(regs[i].mem, &g_dsp.r)); +#endif + } +} + +DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache &cache) + : emitter(cache.emitter), temporary(true), merged(false) +{ + memcpy(xregs,cache.xregs,sizeof(xregs)); +#ifdef _M_X64 + memcpy(acc,cache.acc,sizeof(acc)); +#endif + memcpy(regs,cache.regs,sizeof(regs)); +} + +DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache &cache) +{ + _assert_msg_(DSPLLE, &emitter == &cache.emitter, "emitter does not match"); + _assert_msg_(DSPLLE, temporary, "register cache not temporary??"); + merged = false; + memcpy(xregs,cache.xregs,sizeof(xregs)); +#ifdef _M_X64 + memcpy(acc,cache.acc,sizeof(acc)); +#endif + memcpy(regs,cache.regs,sizeof(regs)); + + return *this; +} + +DSPJitRegCache::~DSPJitRegCache() +{ + _assert_msg_(DSPLLE, !temporary || merged, "temporary cache not merged"); +} + +void DSPJitRegCache::flushRegs(DSPJitRegCache &cache, bool emit) +{ + cache.merged = true; + +#ifdef _M_X64 + for(unsigned int i = 0; i < 2; i++) { + if (acc[i].shift > cache.acc[i].shift) { + if (emit) + emitter.ROL(64, R(acc[i].host_reg), + Imm8(acc[i].shift-cache.acc[i].shift)); + acc[i].shift = cache.acc[i].shift; + } + if (acc[i].shift < cache.acc[i].shift) { + if (emit) + emitter.ROR(64, R(acc[i].host_reg), + Imm8(cache.acc[i].shift-acc[i].shift)); + acc[i].shift = cache.acc[i].shift; + } + } +#endif +} + +void DSPJitRegCache::drop() +{ + merged = true; +} + +void DSPJitRegCache::flushRegs() +{ + //also needs to undo any dynamic changes to static allocated regs + //this should have the same effect as + //merge(DSPJitRegCache(emitter)); +#ifdef _M_X64 +#ifdef ROTATED_REG_ACCS + for(unsigned int i = 0; i < 2; i++) { + if (acc[i].shift > 0) { + emitter.ROL(64, R(acc[i].host_reg), + Imm8(acc[i].shift)); + acc[i].shift = 0; + } + _assert_msg_(DSPLLE, !acc[i].used, + "accumulator still in use"); + if (acc[i].used) + emitter.INT3(); + } +#endif +#endif +} + +static u64 ebp_store; + +void DSPJitRegCache::loadStaticRegs() +{ +#ifdef _M_X64 +#ifdef ROTATED_REG_ACCS + emitter.MOV(64, R(R8), MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[0].val))); + emitter.MOV(64, R(R9), MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[1].val))); +#endif + emitter.MOV(64, MDisp(R11, PtrOffset(&ebp_store, &g_dsp.r)), R(RBP)); +#else + emitter.MOV(32, M(&ebp_store), R(EBP)); +#endif +} + +void DSPJitRegCache::saveStaticRegs() +{ + flushRegs(); +#ifdef _M_X64 +#ifdef ROTATED_REG_ACCS + emitter.MOV(64, MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[0].val)), R(R8)); + emitter.MOV(64, MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[1].val)), R(R9)); +#endif + emitter.MOV(64, R(RBP), MDisp(R11, PtrOffset(&ebp_store, &g_dsp.r))); +#else + emitter.MOV(32, R(EBP), M(&ebp_store)); +#endif +} + +void DSPJitRegCache::getReg(int reg, OpArg &oparg, bool load) +{ + switch(reg) { +#ifdef _M_X64 +#ifdef ROTATED_REG_ACCS + case DSP_REG_ACH0: + case DSP_REG_ACH1: + { + _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACH0].used, + "accumulator already in use"); + if (acc[reg-DSP_REG_ACH0].used) + emitter.INT3(); + oparg = R(acc[reg-DSP_REG_ACH0].host_reg); + if (acc[reg-DSP_REG_ACH0].shift < 32) { + emitter.ROR(64, oparg, Imm8(32-acc[reg-DSP_REG_ACH0].shift)); + acc[reg-DSP_REG_ACH0].shift = 32; + } + + acc[reg-DSP_REG_ACH0].used = true; + } + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACM0].used, + "accumulator already in use"); + if (acc[reg-DSP_REG_ACM0].used) + emitter.INT3(); + oparg = R(acc[reg-DSP_REG_ACM0].host_reg); + if (acc[reg-DSP_REG_ACM0].shift < 16) { + emitter.ROR(64, oparg, Imm8(16-acc[reg-DSP_REG_ACM0].shift)); + acc[reg-DSP_REG_ACM0].shift = 16; + } + if (acc[reg-DSP_REG_ACM0].shift > 16) { + emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACM0].shift-16)); + acc[reg-DSP_REG_ACM0].shift = 16; + } + acc[reg-DSP_REG_ACM0].used = true; + } + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + { + _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACL0].used, + "accumulator already in use"); + if (acc[reg-DSP_REG_ACL0].used) + emitter.INT3(); + oparg = R(acc[reg-DSP_REG_ACL0].host_reg); + if (acc[reg-DSP_REG_ACL0].shift > 0) { + emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACL0].shift)); + acc[reg-DSP_REG_ACL0].shift = 0; + } + acc[reg-DSP_REG_ACL0].used = true; + } + break; + case DSP_REG_ACC0_64: + case DSP_REG_ACC1_64: + { + if (acc[reg-DSP_REG_ACC0_64].used) + emitter.INT3(); + _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACC0_64].used, + "accumulator already in use"); + oparg = R(acc[reg-DSP_REG_ACC0_64].host_reg); + if (load) { + if (acc[reg-DSP_REG_ACC0_64].shift > 0) { + emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACC0_64].shift)); + } + emitter.SHL(64, oparg, Imm8(64-40));//sign extend + emitter.SAR(64, oparg, Imm8(64-40)); + } + //don't bother to rotate if caller replaces all data + acc[reg-DSP_REG_ACC0_64].shift = 0; + acc[reg-DSP_REG_ACC0_64].used = true; + } + break; +#endif +#endif + default: + { +/* + getFreeXReg(reg[reg].host_reg); + X64Reg tmp = reg[reg].host_reg; + oparg = R(tmp); + + if (load) { + u16 *regp = reg_ptr(reg); +#ifdef _M_IX86 // All32 + emitter.MOV(16, oparg, M(regp)); +#else + emitter.MOV(16, oparg, MDisp(R11, PtrOffset(regp, &g_dsp.r))); +#endif + } +*/ + oparg = regs[reg].loc; //when loading/storing from/to mem, need to consider regs[reg].size + } + break; + } +} + +void DSPJitRegCache::putReg(int reg, bool dirty) +{ + switch(reg) { +#ifdef _M_X64 +#ifdef ROTATED_REG_ACCS + case DSP_REG_ACH0: + case DSP_REG_ACH1: + { + + if (dirty) { + if (acc[reg-DSP_REG_ACH0].shift > 0) { + emitter.ROL(64, R(acc[reg-DSP_REG_ACH0].host_reg), + Imm8(acc[reg-DSP_REG_ACH0].shift)); + acc[reg-DSP_REG_ACH0].shift = 0; + } + emitter.SHL(64, R(acc[reg-DSP_REG_ACH0].host_reg), Imm8(64-40));//sign extend + emitter.SAR(64, R(acc[reg-DSP_REG_ACH0].host_reg), Imm8(64-40)); + } + acc[reg-DSP_REG_ACH0].used = false; + } + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + acc[reg-DSP_REG_ACM0].used = false; + } + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + acc[reg-DSP_REG_ACL0].used = false; + break; + case DSP_REG_ACC0_64: + case DSP_REG_ACC1_64: + { + if (dirty) { + OpArg _reg = R(acc[reg-DSP_REG_ACC0_64].host_reg); + + emitter.SHL(64, _reg, Imm8(64-40));//sign extend + emitter.SAR(64, _reg, Imm8(64-40)); + } + acc[reg-DSP_REG_ACC0_64].used = false; + } + break; +#else + case DSP_REG_ACH0: + case DSP_REG_ACH1: + { + //need to fix in memory for now. + u16 *regp = reg_ptr(reg); + OpArg mem; + mem = MDisp(R11,PtrOffset(regp,&g_dsp.r)); + X64Reg tmp; + getFreeXReg(tmp); + // sign extend from the bottom 8 bits. + emitter.MOVSX(16, 8, tmp, mem); + emitter.MOV(16, mem, R(tmp)); + putXReg(tmp); + } + break; +#endif +#else + case DSP_REG_ACH0: + case DSP_REG_ACH1: + { + //need to fix in memory for now. + u16 *regp = reg_ptr(reg); + OpArg mem; + mem = M(regp); + X64Reg tmp; + getFreeXReg(tmp); + // sign extend from the bottom 8 bits. + emitter.MOVSX(16, 8, tmp, mem); + emitter.MOV(16, mem, R(tmp)); + putXReg(tmp); + } + break; +#endif + default: + { +/* + X64Reg tmp = reg[reg].host_reg; + + if(dirty) { + u16 *regp = reg_ptr(reg); +#ifdef _M_IX86 // All32 + emitter.MOV(16, M(dregp), R(tmp)); +#else + emitter.MOV(16, MDisp(R11, PtrOffset(dregp, &g_dsp.r)), R(tmp)); +#endif + } +*/ + } + break; + } +} + +void DSPJitRegCache::readReg(int sreg, X64Reg host_dreg, DSPJitSignExtend extend) +{ + OpArg reg; + getReg(sreg, reg); + switch(regs[sreg].size) { + case 2: + switch(extend) { +#ifdef _M_X64 + case SIGN: emitter.MOVSX(64, 16, host_dreg, reg); break; + case ZERO: emitter.MOVZX(64, 16, host_dreg, reg); break; +#else + case SIGN: emitter.MOVSX(32, 16, host_dreg, reg); break; + case ZERO: emitter.MOVZX(32, 16, host_dreg, reg); break; +#endif + case NONE: emitter.MOV(16, R(host_dreg), reg); break; + } + break; + case 4: +#ifdef _M_X64 + switch(extend) { + case SIGN: emitter.MOVSX(64, 32, host_dreg, reg); break; + case ZERO: emitter.MOVZX(64, 32, host_dreg, reg); break; + case NONE: emitter.MOV(32, R(host_dreg), reg); break; + } +#else + emitter.MOV(32, R(host_dreg), reg); break; +#endif + break; +#ifdef _M_X64 + case 8: + emitter.MOV(64, R(host_dreg), reg); break; + break; +#endif + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + putReg(sreg, false); +} + +void DSPJitRegCache::writeReg(int dreg, OpArg arg) +{ + OpArg reg; + getReg(dreg, reg, false); + switch(regs[dreg].size) { + case 2: emitter.MOV(16, reg, arg); break; + case 4: emitter.MOV(32, reg, arg); break; +#ifdef _M_X64 + case 8: emitter.MOV(64, reg, arg); break; +#endif + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + putReg(dreg, true); +} + +X64Reg DSPJitRegCache::spillXReg() +{ + //todo: implement + return INVALID_REG; +} + +void DSPJitRegCache::spillXReg(X64Reg reg) +{ + //todo: implement +} + +X64Reg DSPJitRegCache::findFreeXReg() +{ + int i; + for(i = 0; i < NUMXREGS; i++) { + if (xregs[i].guest_reg == DSP_REG_NONE) { + return (X64Reg)i; + } + } + return INVALID_REG; +} + +void DSPJitRegCache::getFreeXReg(X64Reg ®) +{ + reg = findFreeXReg(); + if (reg == INVALID_REG) + reg = spillXReg(); + _assert_msg_(DSPLLE, reg != INVALID_REG, "could not find register"); + xregs[reg].guest_reg = DSP_REG_USED; +} + +void DSPJitRegCache::getXReg(X64Reg reg) +{ + if (xregs[reg].guest_reg != DSP_REG_NONE) + spillXReg(reg); + _assert_msg_(DSPLLE, xregs[reg].guest_reg != DSP_REG_NONE, "register already in use"); + xregs[reg].guest_reg = DSP_REG_USED; +} + +void DSPJitRegCache::putXReg(X64Reg reg) +{ + _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED, + "putXReg without get(Free)XReg"); + xregs[reg].guest_reg = DSP_REG_NONE; +} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.h b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.h new file mode 100644 index 0000000000..a230947c11 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.h @@ -0,0 +1,169 @@ +// Copyright (C) 2011 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DSPJITREGCACHE_H +#define _DSPJITREGCACHE_H + +#include "x64Emitter.h" + +class DSPEmitter; + +enum DSPJitRegSpecial { + DSP_REG_ACC0_64 =32, + DSP_REG_ACC1_64 =33, + DSP_REG_AX0_32 =34, + DSP_REG_AX1_32 =35, + DSP_REG_PROD_64 =36, + DSP_REG_MAX_MEM_BACKED = 36, + + DSP_REG_USED =253, + DSP_REG_STATIC =254, + DSP_REG_NONE =255 +}; + +enum DSPJitSignExtend { + SIGN, ZERO, NONE +}; + +#ifdef _M_X64 +#define NUMXREGS 16 +#elif _M_IX86 +#define NUMXREGS 8 +#endif + +class DSPJitRegCache { +private: + struct X64CachedReg + { + int guest_reg; //including DSPJitRegSpecial + }; + struct DynamicReg { + Gen::OpArg loc; + void *mem; + size_t size; + bool dirty; + }; + +#ifdef _M_X64 + //when there is a way to do this efficiently in x86, uncondition + struct { + Gen::X64Reg host_reg; + int shift; + bool dirty; + bool used; + Gen::X64Reg tmp_reg; + } acc[2]; +#endif + + DynamicReg regs[DSP_REG_MAX_MEM_BACKED+1]; + X64CachedReg xregs[NUMXREGS]; + + DSPEmitter &emitter; + bool temporary; + bool merged; +private: + //find a free host reg + Gen::X64Reg findFreeXReg(); + Gen::X64Reg spillXReg(); + void spillXReg(Gen::X64Reg reg); +public: + DSPJitRegCache(DSPEmitter &_emitter); + + //for branching into multiple control flows + DSPJitRegCache(const DSPJitRegCache &cache); + DSPJitRegCache& operator=(const DSPJitRegCache &cache); + + ~DSPJitRegCache(); + + //merge must be done _before_ leaving the code branch, so we can fix + //up any differences in state + void flushRegs(DSPJitRegCache &cache, bool emit = true); + /* since some use cases are non-trivial, some examples: + + //this does not modify the final state of gpr + + FixupBranch b = JCC(); + DSPJitRegCache c = gpr; + + gpr.flushRegs(c); + SetBranchTarget(b); + + + //this does not modify the final state of gpr + + DSPJitRegCache c = gpr; + FixupBranch b1 = JCC(); + + gpr.flushRegs(c); + FixupBranch b2 = JMP(); + SetBranchTarget(b1); + + gpr.flushRegs(c); + SetBranchTarget(b2); + + + //this allows gpr to be modified in the second branch + //and fixes gpr according to the results form in the first branch + + DSPJitRegCache c = gpr; + FixupBranch b1 = JCC(); + + FixupBranch b2 = JMP(); + SetBranchTarget(b1); + + gpr.flushRegs(c); + SetBranchTarget(b2); + + + //this does not modify the final state of gpr + + u8* b = GetCodePtr(); + DSPJitRegCache c = gpr; + + gpr.flushRegs(c); + JCC(b); + + + this all is not needed when gpr would not be used at all in the + conditional branch + */ + //drop this copy without warning + void drop(); + + //prepare state so that another flushed DSPJitRegCache can take over + void flushRegs(); + + void loadStaticRegs();//load statically allocated regs from memory + void saveStaticRegs();//save statically allocated regs to memory + + //gives no SCALE_RIP with abs(offset) >= 0x80000000 + void getReg(int reg, Gen::OpArg &oparg, bool load = true); + //done with all usages of OpArg above + void putReg(int reg, bool dirty = true); + + void readReg(int sreg, Gen::X64Reg host_dreg, DSPJitSignExtend extend); + void writeReg(int dreg, Gen::OpArg arg); + + //find a free host reg, spill if used, reserve + void getFreeXReg(Gen::X64Reg ®); + //spill a specific host reg if used, reserve + void getXReg(Gen::X64Reg reg); + //unreserve the given host reg + void putXReg(Gen::X64Reg reg); +}; + +#endif /*_DSPJITREGCACHE_H*/ diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp new file mode 100644 index 0000000000..35e5de9d9a --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp @@ -0,0 +1,596 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "../DSPMemoryMap.h" +#include "../DSPHWInterface.h" +#include "../DSPEmitter.h" +#include "DSPJitUtil.h" +#include "x64Emitter.h" +#include "ABI.h" + +using namespace Gen; + +// addr math +// +// These functions detect overflow by checking if +// the bit past the top of the mask(WR) has changed in AR. +// They detect values under the minimum for a mask by adding wr + 1 +// and checking if the bit past the top of the mask doesn't change. +// Both are done while ignoring changes due to values/holes in IX +// above the mask. + + +// EAX = g_dsp.r.ar[reg] +// EDX = g_dsp.r.wr[reg] +// EDI = temp +// ECX = temp +void DSPEmitter::increment_addr_reg(int reg) +{ + OpArg ar_reg; + OpArg wr_reg; + gpr.getReg(DSP_REG_WR0+reg,wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.putReg(DSP_REG_WR0+reg); + gpr.getReg(DSP_REG_AR0+reg,ar_reg); + MOVZX(32, 16, EAX, ar_reg); + + //u32 nar = ar + 1; + MOV(32, R(EDI), R(EAX)); + ADD(32, R(EAX), Imm8(1)); + + // if ((nar ^ ar) > ((wr | 1) << 1)) + // nar -= wr + 1; + XOR(32, R(EDI), R(EAX)); + LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); + OR(32, R(ECX), Imm8(2)); + CMP(32, R(EDI), R(ECX)); + FixupBranch nowrap = J_CC(CC_BE); + SUB(16, R(AX), R(DX)); + SUB(16, R(AX), Imm8(1)); + SetJumpTarget(nowrap); + // g_dsp.r.ar[reg] = nar; + + MOV(16, ar_reg, R(AX)); + gpr.putReg(DSP_REG_AR0+reg); +} + +// EAX = g_dsp.r.ar[reg] +// EDX = g_dsp.r.wr[reg] +// EDI = temp +// ECX = temp +void DSPEmitter::decrement_addr_reg(int reg) +{ + OpArg ar_reg; + OpArg wr_reg; + gpr.getReg(DSP_REG_WR0+reg,wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.putReg(DSP_REG_WR0+reg); + gpr.getReg(DSP_REG_AR0+reg,ar_reg); + MOVZX(32, 16, EAX, ar_reg); + + // u32 nar = ar + wr; + // edi = nar + LEA(32, EDI, MComplex(EAX, EDX, 1, 0)); + + // if (((nar ^ ar) & ((wr | 1) << 1)) > wr) + // nar -= wr + 1; + XOR(32, R(EAX), R(EDI)); + LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); + CMP(32, R(EAX), R(EDX)); + FixupBranch nowrap = J_CC(CC_BE); + SUB(16, R(DI), R(DX)); + SUB(16, R(DI), Imm8(1)); + SetJumpTarget(nowrap); + // g_dsp.r.ar[reg] = nar; + + MOV(16, ar_reg, R(DI)); + gpr.putReg(DSP_REG_AR0+reg); +} + +// Increase addr register according to the correspond ix register +// EAX = g_dsp.r.ar[reg] +// EDX = g_dsp.r.wr[reg] +// ESI = g_dsp.r.ix[reg] +// ECX = temp +// EDI = temp +void DSPEmitter::increase_addr_reg(int reg) +{ + OpArg ar_reg; + OpArg wr_reg; + OpArg ix_reg; + gpr.getReg(DSP_REG_WR0+reg,wr_reg); + gpr.getReg(DSP_REG_IX0+reg,ix_reg); + MOVZX(32, 16, EDX, wr_reg); + MOVSX(32, 16, ESI, ix_reg); + gpr.putReg(DSP_REG_WR0+reg); + gpr.putReg(DSP_REG_IX0+reg); + gpr.getReg(DSP_REG_AR0+reg,ar_reg); + MOVZX(32, 16, EAX, ar_reg); + + //u32 nar = ar + ix; + //edi = nar + LEA(32, EDI, MComplex(EAX, ESI, 1, 0)); + + //u32 dar = (nar ^ ar ^ ix) & ((wr | 1) << 1); + //eax = dar + XOR(32, R(EAX), R(ESI)); + XOR(32, R(EAX), R(EDI)); + LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); + + //if (ix >= 0) + TEST(32, R(ESI), R(ESI)); + FixupBranch negative = J_CC(CC_S); + //if (dar > wr) + CMP(32, R(EAX), R(EDX)); + FixupBranch done = J_CC(CC_BE); + //nar -= wr + 1; + SUB(16, R(DI), R(DX)); + SUB(16, R(DI), Imm8(1)); + FixupBranch done2 = J(); + + //else + SetJumpTarget(negative); + //if ((((nar + wr + 1) ^ nar) & dar) <= wr) + LEA(32, ECX, MComplex(EDI, EDX, 1, 1)); + XOR(32, R(ECX), R(EDI)); + AND(32, R(ECX), R(EAX)); + CMP(32, R(ECX), R(EDX)); + FixupBranch done3 = J_CC(CC_A); + //nar += wr + 1; + LEA(32, EDI, MComplex(EDI, EDX, 1, 1)); + + SetJumpTarget(done); + SetJumpTarget(done2); + SetJumpTarget(done3); + // g_dsp.r.ar[reg] = nar; + + MOV(16, ar_reg, R(DI)); + gpr.putReg(DSP_REG_AR0+reg); +} + +// Decrease addr register according to the correspond ix register +// EAX = g_dsp.r.ar[reg] +// EDX = g_dsp.r.wr[reg] +// ESI = g_dsp.r.ix[reg] +// ECX = temp +// EDI = temp +void DSPEmitter::decrease_addr_reg(int reg) +{ + OpArg ar_reg; + OpArg wr_reg; + OpArg ix_reg; + gpr.getReg(DSP_REG_WR0+reg,wr_reg); + gpr.getReg(DSP_REG_IX0+reg,ix_reg); + MOVZX(32, 16, EDX, wr_reg); + MOVSX(32, 16, ESI, ix_reg); + gpr.putReg(DSP_REG_WR0+reg); + gpr.putReg(DSP_REG_IX0+reg); + gpr.getReg(DSP_REG_AR0+reg,ar_reg); + MOVZX(32, 16, EAX, ar_reg); + + NOT(32, R(ESI)); //esi = ~ix + + //u32 nar = ar - ix; (ar + ~ix + 1) + LEA(32, EDI, MComplex(EAX, ESI, 1, 1)); + + //u32 dar = (nar ^ ar ^ ~ix) & ((wr | 1) << 1); + //eax = dar + XOR(32, R(EAX), R(ESI)); + XOR(32, R(EAX), R(EDI)); + LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); + + //if ((u32)ix > 0xFFFF8000) ==> (~ix < 0x00007FFF) + CMP(32, R(ESI), Imm32(0x00007FFF)); + FixupBranch positive = J_CC(CC_AE); + //if (dar > wr) + CMP(32, R(EAX), R(EDX)); + FixupBranch done = J_CC(CC_BE); + //nar -= wr + 1; + SUB(16, R(DI), R(DX)); + SUB(16, R(DI), Imm8(1)); + FixupBranch done2 = J(); + + //else + SetJumpTarget(positive); + //if ((((nar + wr + 1) ^ nar) & dar) <= wr) + LEA(32, ECX, MComplex(EDI, EDX, 1, 1)); + XOR(32, R(ECX), R(EDI)); + AND(32, R(ECX), R(EAX)); + CMP(32, R(ECX), R(EDX)); + FixupBranch done3 = J_CC(CC_A); + //nar += wr + 1; + LEA(32, EDI, MComplex(EDI, EDX, 1, 1)); + + SetJumpTarget(done); + SetJumpTarget(done2); + SetJumpTarget(done3); + //return nar + + MOV(16, ar_reg, R(DI)); + gpr.putReg(DSP_REG_AR0+reg); +} + + +// EAX - destination address +// ECX - value +// ESI - Base of dram +void DSPEmitter::dmem_write() +{ + // if (saddr == 0) + CMP(16, R(EAX), Imm16(0x0fff)); + FixupBranch ifx = J_CC(CC_A); + + // g_dsp.dram[addr & DSP_DRAM_MASK] = val; + AND(16, R(EAX), Imm16(DSP_DRAM_MASK)); +#ifdef _M_X64 + MOV(64, R(ESI), ImmPtr(g_dsp.dram)); +#else + MOV(32, R(ESI), ImmPtr(g_dsp.dram)); +#endif + MOV(16, MComplex(ESI, EAX, 2, 0), R(ECX)); + + FixupBranch end = J(); + // else if (saddr == 0xf) + SetJumpTarget(ifx); + // Does it mean gdsp_ifx_write needs u32 rather than u16? + DSPJitRegCache c(gpr); + SaveDSPRegs(); + ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, ECX); + LoadDSPRegs(); + gpr.flushRegs(c); + SetJumpTarget(end); +} + +// ECX - value +void DSPEmitter::dmem_write_imm(u16 address) +{ + switch (address >> 12) + { + case 0x0: // 0xxx DRAM +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.dram[address & DSP_DRAM_MASK]), R(ECX)); +#else + MOV(64, R(RDX), ImmPtr(g_dsp.dram)); + MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK)*2), R(ECX)); +#endif + break; + + case 0xf: // Fxxx HW regs + MOV(16, R(EAX), Imm16(address)); + SaveDSPRegs(); + ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, ECX); + LoadDSPRegs(); + break; + + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", + g_dsp.pc, address); + break; + } +} + +// In: ECX - the address to read +// Out: EAX - the result of the read (used by caller) +// ESI - Base +void DSPEmitter::imem_read() +{ + // if (addr == 0) + CMP(16, R(ECX), Imm16(0x0fff)); + FixupBranch irom = J_CC(CC_A); + // return g_dsp.iram[addr & DSP_IRAM_MASK]; + AND(16, R(ECX), Imm16(DSP_IRAM_MASK)); +#ifdef _M_X64 + MOV(64, R(ESI), ImmPtr(g_dsp.iram)); +#else + MOV(32, R(ESI), ImmPtr(g_dsp.iram)); +#endif + MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); + + FixupBranch end = J(); + SetJumpTarget(irom); + // else if (addr == 0x8) + // return g_dsp.irom[addr & DSP_IROM_MASK]; + AND(16, R(ECX), Imm16(DSP_IROM_MASK)); +#ifdef _M_X64 + MOV(64, R(ESI), ImmPtr(g_dsp.irom)); +#else + MOV(32, R(ESI), ImmPtr(g_dsp.irom)); +#endif + MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); + + SetJumpTarget(end); +} + +// In: ECX - the address to read +// Out: EAX - the result of the read (used by caller) +// ESI - Base +// Trashes R11 on gdsp_ifx_read +void DSPEmitter::dmem_read() +{ + // if (saddr == 0) + CMP(16, R(ECX), Imm16(0x0fff)); + FixupBranch dram = J_CC(CC_A); + // return g_dsp.dram[addr & DSP_DRAM_MASK]; +#ifdef _M_X64 + AND(16, R(ECX), Imm16(DSP_DRAM_MASK)); + MOVZX(64, 16, RCX, R(RCX)); + MOV(64, R(ESI), ImmPtr(g_dsp.dram)); +#else + AND(32, R(ECX), Imm32(DSP_DRAM_MASK)); + MOV(32, R(ESI), ImmPtr(g_dsp.dram)); +#endif + MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); + + FixupBranch end = J(); + SetJumpTarget(dram); + // else if (saddr == 0x1) + CMP(16, R(ECX), Imm16(0x1fff)); + FixupBranch ifx = J_CC(CC_A); + // return g_dsp.coef[addr & DSP_COEF_MASK]; +#ifdef _M_X64 + AND(16, R(ECX), Imm16(DSP_COEF_MASK)); + MOVZX(64, 16, RCX, R(RCX)); + MOV(64, R(ESI), ImmPtr(g_dsp.coef)); +#else + AND(32, R(ECX), Imm32(DSP_COEF_MASK)); + MOV(32, R(ESI), ImmPtr(g_dsp.coef)); +#endif + MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); + + FixupBranch end2 = J(); + SetJumpTarget(ifx); + // else if (saddr == 0xf) + // return gdsp_ifx_read(addr); + DSPJitRegCache c(gpr); + SaveDSPRegs(); + ABI_CallFunctionR((void *)gdsp_ifx_read, ECX); + LoadDSPRegs(); + gpr.flushRegs(c); + SetJumpTarget(end); + SetJumpTarget(end2); +} + +void DSPEmitter::dmem_read_imm(u16 address) +{ + switch (address >> 12) + { + case 0x0: // 0xxx DRAM +#ifdef _M_IX86 // All32 + MOV(16, R(EAX), M(&g_dsp.dram[address & DSP_DRAM_MASK])); +#else + MOV(64, R(RDX), ImmPtr(g_dsp.dram)); + MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK)*2)); +#endif + break; + + case 0x1: // 1xxx COEF +#ifdef _M_IX86 // All32 + MOV(16, R(EAX), Imm16(g_dsp.coef[address & DSP_COEF_MASK])); +#else + MOV(64, R(RDX), ImmPtr(g_dsp.coef)); + MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK)*2)); +#endif + break; + + case 0xf: // Fxxx HW regs + SaveDSPRegs(); + ABI_CallFunctionC16((void *)gdsp_ifx_read, address); + LoadDSPRegs(); + break; + + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", + g_dsp.pc, address); + } +} + +// Returns s64 in RAX +void DSPEmitter::get_long_prod(X64Reg long_prod) +{ +#ifdef _M_X64 + // MOV(64, R(R11), ImmPtr(&g_dsp.r)); + //s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH]; + OpArg reg; + gpr.getReg(DSP_REG_PROD_64, reg); + X64Reg tmp; + gpr.getFreeXReg(tmp); + MOV(64, R(long_prod), reg); + MOV(64, R(tmp), R(long_prod)); + SHL(64, R(long_prod), Imm8(64-40));//sign extend + SAR(64, R(long_prod), Imm8(64-40)); + SHR(64, R(tmp), Imm8(48)); + SHL(64, R(tmp), Imm8(16)); + ADD(64, R(long_prod), R(tmp)); + gpr.putXReg(tmp); + gpr.putReg(DSP_REG_PROD_64, false); + +#endif +} + +// Returns s64 in RAX +// Clobbers RSI +void DSPEmitter::get_long_prod_round_prodl(X64Reg long_prod) +{ +#ifdef _M_X64 + //s64 prod = dsp_get_long_prod(); + get_long_prod(long_prod); + + //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; + TEST(32, R(long_prod), Imm32(0x10000)); + FixupBranch jump = J_CC(CC_Z); + ADD(64, R(long_prod), Imm32(0x8000)); + MOV(64, R(ESI), Imm64(~0xffff)); + AND(64, R(long_prod), R(RSI)); + FixupBranch _ret = J(); + //else prod = (prod + 0x7fff) & ~0xffff; + SetJumpTarget(jump); + ADD(64, R(long_prod), Imm32(0x7fff)); + MOV(64, R(RSI), Imm64(~0xffff)); + AND(64, R(long_prod), R(RSI)); + SetJumpTarget(_ret); + //return prod; +#endif +} + +// For accurate emulation, this is wrong - but the real prod registers behave +// in completely bizarre ways. Probably not meaningful to emulate them accurately. +// In: RAX = s64 val +void DSPEmitter::set_long_prod() +{ +#ifdef _M_X64 + OpArg reg; + gpr.getReg(DSP_REG_PROD_64, reg, false); + X64Reg tmp; + gpr.getFreeXReg(tmp); + + MOV(64, R(tmp), Imm64(0x000000ffffffffffULL)); + AND(64, R(RAX), R(tmp)); + // g_dsp.r[DSP_REG_PRODL] = (u16)val; + MOV(64, reg, R(RAX)); + + gpr.putXReg(tmp); + gpr.putReg(DSP_REG_PROD_64, true); +#endif +} + +// Returns s64 in RAX +// Clobbers RSI +void DSPEmitter::round_long_acc(X64Reg long_acc) +{ +#ifdef _M_X64 + //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; + TEST(32, R(long_acc), Imm32(0x10000)); + FixupBranch jump = J_CC(CC_Z); + ADD(64, R(long_acc), Imm32(0x8000)); + MOV(64, R(ESI), Imm64(~0xffff)); + AND(64, R(long_acc), R(RSI)); + FixupBranch _ret = J(); + //else prod = (prod + 0x7fff) & ~0xffff; + SetJumpTarget(jump); + ADD(64, R(long_acc), Imm32(0x7fff)); + MOV(64, R(RSI), Imm64(~0xffff)); + AND(64, R(long_acc), R(RSI)); + SetJumpTarget(_ret); + //return prod; +#endif +} + +// Returns s64 in acc +void DSPEmitter::get_long_acc(int _reg, X64Reg acc) +{ +#ifdef _M_X64 + OpArg reg; + gpr.getReg(DSP_REG_ACC0_64+_reg, reg); + MOV(64, R(acc), reg); + gpr.putReg(DSP_REG_ACC0_64+_reg, false); +#endif +} + +// In: acc = s64 val +void DSPEmitter::set_long_acc(int _reg, X64Reg acc) +{ +#ifdef _M_X64 + OpArg reg; + gpr.getReg(DSP_REG_ACC0_64+_reg, reg, false); + MOV(64, reg, R(acc)); + gpr.putReg(DSP_REG_ACC0_64+_reg); +#endif +} + +// Returns s16 in AX +void DSPEmitter::get_acc_l(int _reg, X64Reg acl, bool sign) +{ + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.readReg(_reg+DSP_REG_ACL0, acl, sign?SIGN:ZERO); +} + +void DSPEmitter::set_acc_l(int _reg, OpArg arg) +{ + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.writeReg(_reg+DSP_REG_ACL0,arg); +} + +// Returns s16 in AX +void DSPEmitter::get_acc_m(int _reg, X64Reg acm, bool sign) +{ +// return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.readReg(_reg+DSP_REG_ACM0, acm, sign?SIGN:ZERO); +} + +// In: s16 in AX +void DSPEmitter::set_acc_m(int _reg, OpArg arg) +{ + // return g_dsp.r.ac[_reg].m; + gpr.writeReg(_reg+DSP_REG_ACM0,arg); +} + +// Returns s16 in AX +void DSPEmitter::get_acc_h(int _reg, X64Reg ach, bool sign) +{ +// return g_dsp.r.ac[_reg].h; + gpr.readReg(_reg+DSP_REG_ACH0, ach, sign?SIGN:ZERO); +} + +// In: s16 in AX +void DSPEmitter::set_acc_h(int _reg, OpArg arg) +{ + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.writeReg(_reg+DSP_REG_ACH0,arg); +} + +// Returns u32 in EAX +void DSPEmitter::get_long_acx(int _reg, X64Reg acx) +{ +// return ((u32)g_dsp.r[DSP_REG_AXH0 + _reg] << 16) | g_dsp.r[DSP_REG_AXL0 + _reg]; + gpr.readReg(_reg+DSP_REG_AX0_32, acx, SIGN); +} + +// Returns s16 in EAX +void DSPEmitter::get_ax_l(int _reg, X64Reg axl) +{ +// return (s16)g_dsp.r[DSP_REG_AXL0 + _reg]; + gpr.readReg(_reg+DSP_REG_AXL0, axl, SIGN); +} + +// Returns s16 in EAX +void DSPEmitter::get_ax_h(int _reg, X64Reg axh) +{ +// return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; + gpr.readReg(_reg+DSP_REG_AXH0, axh, SIGN); +} + +void DSPEmitter::LoadDSPRegs() +{ +#ifdef _M_X64 + MOV(64, R(R11), ImmPtr(&g_dsp.r)); +#endif + + // Load DSP register state here... + gpr.loadStaticRegs(); +} + +void DSPEmitter::SaveDSPRegs() +{ + // Save DSP register state here... + gpr.saveStaticRegs(); +} diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.h b/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.h new file mode 100644 index 0000000000..2d28b6d520 --- /dev/null +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitUtil.h @@ -0,0 +1,21 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef __DSPJITUTIL_H__ +#define __DSPJITUTIL_H__ + +#endif /*__DSPJITUTIL_H__*/ diff --git a/Source/Core/Core/Src/DSP/LabelMap.cpp b/Source/Core/Core/Src/DSP/LabelMap.cpp new file mode 100644 index 0000000000..bc6b8d7ba2 --- /dev/null +++ b/Source/Core/Core/Src/DSP/LabelMap.cpp @@ -0,0 +1,85 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "LabelMap.h" +#include "DSPTables.h" + +LabelMap::LabelMap() +{ + +} + +void LabelMap::RegisterDefaults() +{ + for (int i = 0; i < 0x24; i++) + { + if (regnames[i].name) + RegisterLabel(regnames[i].name, regnames[i].addr); + } + for (int i = 0; i < (int)pdlabels_size; i++) + { + if (pdlabels[i].name) + RegisterLabel(pdlabels[i].name, pdlabels[i].addr); + } +} + +void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type) +{ + u16 old_value; + if (GetLabelValue(label, &old_value) && old_value != lval) + { + printf("WARNING: Redefined label %s to %04x - old value %04x\n", + label.c_str(), lval, old_value); + DeleteLabel(label); + } + labels.push_back(label_t(label, lval, type)); +} + +void LabelMap::DeleteLabel(const std::string &label) +{ + for (std::vector::iterator iter = labels.begin(); + iter != labels.end(); ++iter) + { + if (!label.compare(iter->name)) + { + labels.erase(iter); + return; + } + } +} + +bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const +{ + for (u32 i = 0; i < labels.size(); i++) + { + if (!label.compare(labels[i].name)) + { + if (type & labels[i].type) { + *value = labels[i].addr; + return true; + } else { + printf("WARNING: Wrong label type requested. %s\n", label.c_str()); + } + } + } + return false; +} + +void LabelMap::Clear() +{ + labels.clear(); +} diff --git a/Source/Core/Core/Src/DSP/LabelMap.h b/Source/Core/Core/Src/DSP/LabelMap.h new file mode 100644 index 0000000000..2bdaee9049 --- /dev/null +++ b/Source/Core/Core/Src/DSP/LabelMap.h @@ -0,0 +1,55 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _LABELMAP_H +#define _LABELMAP_H + +#include +#include + +#include "Common.h" + +enum LabelType +{ + LABEL_IADDR = 1, // Jump addresses, etc + LABEL_DADDR = 2, // Data addresses, etc + LABEL_VALUE = 4, + LABEL_ANY = 0xFF, +}; + +class LabelMap +{ + struct label_t + { + label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {} + std::string name; + s32 addr; + LabelType type; + }; + std::vector labels; + +public: + LabelMap(); + ~LabelMap() { } + void RegisterDefaults(); + void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE); + void DeleteLabel(const std::string &label); + bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const; + void Clear(); +}; + +#endif // _LABELMAP_H diff --git a/Source/Core/Core/Src/DSP/assemble.cpp b/Source/Core/Core/Src/DSP/assemble.cpp new file mode 100644 index 0000000000..a8a24e45c2 --- /dev/null +++ b/Source/Core/Core/Src/DSP/assemble.cpp @@ -0,0 +1,1020 @@ +/*==================================================================== + +$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ + +project: GameCube DSP Tool (gcdsp) +mail: duddie@walla.com + +Copyright (c) 2005 Duddie + +This program is free software; you can redistribute it and/or +modify it 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 received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Revision 1.4 2008/10/04 10:30:00 Hermes +added function to export the code to .h file +added support for '/ *' '* /' and '//' for comentaries +added some sintax detection when use registers + +$Log: not supported by cvs2svn $ +Revision 1.2 2005/09/14 02:19:29 wntrmute +added header guards +use standard main function + +Revision 1.1 2005/08/24 22:13:34 wntrmute +Initial import + + +====================================================================*/ + +#include +#include + +#include +#include +#include + +#include "Common.h" +#include "FileUtil.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "disassemble.h" +#include "assemble.h" + +static const char *err_string[] = +{ + "", + "Unknown Error", + "Unknown opcode", + "Not enough parameters", + "Too many parameters", + "Wrong parameter", + "Expected parameter of type 'string'", + "Expected parameter of type 'value'", + "Expected parameter of type 'register'", + "Expected parameter of type 'memory pointer'", + "Expected parameter of type 'immediate'", + "Incorrect binary value", + "Incorrect hexadecimal value", + "Incorrect decimal value", + "Label already exists", + "Label not defined", + "No matching brackets", + "This opcode cannot be extended", + "Given extending params for non extensible opcode", + "Wrong parameter: must be accumulator register", + "Wrong parameter: must be mid accumulator register", + "Invalid register", + "Number out of range" +}; + +DSPAssembler::DSPAssembler(const AssemblerSettings &settings) : + gdg_buffer(NULL), + m_cur_addr(0), + m_cur_pass(0), + m_current_param(0), + settings_(settings) + +{ +} + +DSPAssembler::~DSPAssembler() +{ + if(gdg_buffer) + free(gdg_buffer); +} + +bool DSPAssembler::Assemble(const char *text, std::vector &code, std::vector *line_numbers) +{ + if (line_numbers) + line_numbers->clear(); + const char *fname = "tmp.asm"; + if (!File::WriteStringToFile(true, text, fname)) + return false; + InitPass(1); + if (!AssembleFile(fname, 1)) + return false; + + // We now have the size of the output buffer + if (m_totalSize > 0) + { + gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4); + if(!gdg_buffer) + return false; + + memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); + } else + return false; + + InitPass(2); + if (!AssembleFile(fname, 2)) + return false; + + code.resize(m_totalSize); + for (int i = 0; i < m_totalSize; i++) { + code[i] = *(u16 *)(gdg_buffer + i * 2); + } + + if(gdg_buffer) { + free(gdg_buffer); + gdg_buffer = NULL; + } + + last_error_str = "(no errors)"; + last_error = ERR_OK; + + return true; +} + +void DSPAssembler::ShowError(err_t err_code, const char *extra_info) +{ + + if (!settings_.force) + failed = true; + + char error_buffer[1024]; + char *buf_ptr = error_buffer; + buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); + if (!extra_info) + extra_info = "-"; + + if (m_current_param == 0) + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); + else + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", + err_string[err_code], code_line, m_current_param, extra_info); + last_error_str = error_buffer; + last_error = err_code; +} + +char *skip_spaces(char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +const char *skip_spaces(const char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +// Parse a standalone value - it can be a number in one of several formats or a label. +s32 DSPAssembler::ParseValue(const char *str) +{ + bool negative = false; + s32 val = 0; + const char *ptr = str; + + if (ptr[0] == '#') + { + ptr++; + negative = true; // Wow! Double # (needed one to get in here) negates??? + } + if (ptr[0] == '-') + { + ptr++; + negative = true; + } + if (ptr[0] == '0') + { + if (ptr[1] >= '0' && ptr[1] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else + { + switch (ptr[1]) + { + case 'X': // hex + for (int i = 2 ; ptr[i] != 0 ; i++) + { + val <<= 4; + if (ptr[i] >= 'a' && ptr[i] <= 'f') + val += (ptr[i]-'a'+10); + else if (ptr[i] >= 'A' && ptr[i] <= 'F') + val += (ptr[i]-'A'+10); + else if (ptr[i] >= '0' && ptr[i] <= '9') + val += (ptr[i] - '0'); + else + ShowError(ERR_INCORRECT_HEX, str); + } + break; + case '\'': // binary + for (int i = 2; ptr[i] != 0; i++) + { + val *=2; + if(ptr[i] >= '0' && ptr[i] <= '1') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_BIN, str); + } + break; + default: + // value is 0 or error + val = 0; + break; + } + } + } + else + { + // Symbol starts with a digit - it's a dec number. + if (ptr[0] >= '0' && ptr[0] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else // Everything else is a label. + { + // Lookup label + u16 value; + if (labels.GetLabelValue(ptr, &value)) + return value; + if (m_cur_pass == 2) + ShowError(ERR_UNKNOWN_LABEL, str); + } + } + if (negative) + return -val; + return val; +} + +// Modifies both src and dst! +// What does it do, really?? +char *DSPAssembler::FindBrackets(char *src, char *dst) +{ + s32 len = (s32) strlen(src); + s32 first = -1; + s32 count = 0; + s32 i, j; + j = 0; + for (i = 0 ; i < len ; i++) + { + if (src[i] == '(') + { + if (first < 0) + { + count = 1; + src[i] = 0x0; + first = i; + } + else + { + count++; + dst[j++] = src[i]; + } + } + else if (src[i] == ')') + { + if (--count == 0) + { + dst[j] = 0; + return &src[i+1]; + } + else + { + dst[j++] = src[i]; + } + } + else + { + if (first >= 0) + dst[j++] = src[i]; + } + } + if (count) + ShowError(ERR_NO_MATCHING_BRACKETS); + return NULL; +} + +// Bizarre in-place expression evaluator. +u32 DSPAssembler::ParseExpression(const char *ptr) +{ + char *pbuf; + s32 val = 0; + + char *d_buffer = (char *)malloc(1024); + char *s_buffer = (char *)malloc(1024); + strcpy(s_buffer, ptr); + + while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL) + { + val = ParseExpression(d_buffer); + sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); + strcpy(s_buffer, d_buffer); + } + + int j = 0; + for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) + { + char c = s_buffer[i]; + if (c != ' ') + d_buffer[j++] = c; + } + + for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) + { + char c = d_buffer[i]; + if (c == '-') + { + if (i == 0) + c = '#'; + else + { + switch (d_buffer[i - 1]) + { + case '/': + case '%': + case '*': + c = '#'; + } + } + } + d_buffer[i] = c; + } + + while ((pbuf = strstr(d_buffer, "+")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "-")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); + if (val < 0) + { + val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf + fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); + } + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "*")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "/")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "|")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "&")) != NULL) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + val = ParseValue(d_buffer); + free(d_buffer); + free(s_buffer); + return val; +} + +// Destroys parstr +u32 DSPAssembler::GetParams(char *parstr, param_t *par) +{ + u32 count = 0; + char *tmpstr = skip_spaces(parstr); + tmpstr = strtok(tmpstr, ",\x00"); + for (int i = 0; i < 10; i++) + { + if (tmpstr == NULL) + break; + tmpstr = skip_spaces(tmpstr); + if (strlen(tmpstr) == 0) + break; + if (tmpstr) + count++; + else + break; + + par[i].type = P_NONE; + switch (tmpstr[0]) + { + case '"': + par[i].str = strtok(tmpstr, "\""); + par[i].type = P_STR; + break; + case '#': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_IMM; + break; + case '@': + if (tmpstr[1] == '$') + { + par[i].val = ParseExpression(tmpstr + 2); + par[i].type = P_PRG; + } + else + { + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_MEM; + } + break; + case '$': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_REG; + break; + + default: + par[i].val = ParseExpression(tmpstr); + par[i].type = P_VAL; + break; + } + tmpstr = strtok(NULL, ",\x00"); + } + return count; +} + +const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +{ + if (opcode[0] == 'C' && opcode[1] == 'W') + return &cw; + + AliasMap::const_iterator alias_iter = aliases.find(opcode); + if (alias_iter != aliases.end()) + opcode = alias_iter->second.c_str(); + for (int i = 0; i < opcod_size; i++) + { + const opc_t *opc = &opcod[i]; + if (strcmp(opc->name, opcode) == 0) + { + if (par_count < opc->param_count) + { + ShowError(ERR_NOT_ENOUGH_PARAMETERS); + } + if (par_count > opc->param_count) + { + ShowError(ERR_TOO_MANY_PARAMETERS); + } + return opc; + } + } + ShowError(ERR_UNKNOWN_OPCODE); + return NULL; +} + +// weird... +u16 get_mask_shifted_down(u16 mask) +{ + while (!(mask & 1)) + mask >>= 1; + return mask; +} + +bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) +{ + for (int i = 0; i < count; i++) + { + const int current_param = i + 1; // just for display. + if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) + { + if (par[i].type == P_VAL && + (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) + { + // Data and instruction addresses are valid as VAL values. + continue; + } + + if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) + { + // Just a temp. Should be replaced with more purposeful vars. + int value; + + // modified by Hermes: test the register range + switch ((unsigned)opc->params[i].type) + { + case P_REG18: + case P_REG19: + case P_REG1A: + value = (opc->params[i].type >> 8) & 31; + if ((int)par[i].val < value || + (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_PRG: + if ((int)par[i].val < 0 || (int)par[i].val > 0x3) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_ACC: + if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) { + fprintf(stderr, "%i : %s ", code_line, cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); + } + else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + case P_ACCM: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1c && par[i].val <= 0x1d) + fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else if (par[i].val >= 0x20 && par[i].val <= 0x21) + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; + + case P_ACCL: + if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%s ", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) { + fprintf(stderr, "%s ", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + ShowError(ERR_WRONG_PARAMETER_ACC); + } + break; +/* case P_ACCM_D: //P_ACC_MID: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + ShowError(ERR_WRONG_PARAMETER_MID_ACC); + } + break;*/ + } + continue; + } + + switch (par[i].type & (P_REG | 7)) + { + case P_REG: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_REG); + break; + case P_MEM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_MEM); + break; + case P_VAL: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_VAL); + break; + case P_IMM: + if (ext) fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_IMM); + break; + } + ShowError(ERR_WRONG_PARAMETER); + break; + } + else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) + { + // modified by Hermes: test NUMBER range + int value = get_mask_shifted_down(opc->params[i].mask); + unsigned int valueu = 0xffff & ~(value >> 1); + if ((int)par[i].val < 0) + { + if (value == 7) // value 7 por sbclr/sbset + { + fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); + else + fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if ((int)par[i].val < -((value >> 1) + 1)) + { + if (value < 128) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, par[i].val); + else + fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, value, par[i].val); + + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value == 7) // value 7 por sbclr/sbset + { + if (par[i].val > (unsigned)value) + { + fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + value >>= 1; // addressing 8 bit with sign + if (par[i].val > (unsigned)value && + (par[i].val < valueu || par[i].val > (unsigned)0xffff)) + { + if (value < 256) + fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); + else + fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value < 128) + value >>= 1; // special case ASL/ASR/LSL/LSR + if (par[i].val > (unsigned)value) + { + if (value < 64) + fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); + else + fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + } + continue; + } + } + m_current_param = 0; + return true; +} + + +// Merge opcode with params. +void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +{ + outbuf[m_cur_addr] |= opc->opcode; + for (u32 i = 0; i < par_count; i++) + { + // Ignore the "reverse" parameters since they are implicit. + if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) + { + u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; + u16 v16 = par[i].val; + if (opc->params[i].lshift > 0) + v16 <<= opc->params[i].lshift; + else + v16 >>= -opc->params[i].lshift; + v16 &= opc->params[i].mask; + outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; + } + } +} + +void DSPAssembler::InitPass(int pass) +{ + failed = false; + if (pass == 1) + { + // Reset label table. Pre-populate with hw addresses and registers. + labels.Clear(); + labels.RegisterDefaults(); + aliases.clear(); + aliases["S15"] = "SET15"; + aliases["S16"] = "SET16"; + aliases["S40"] = "SET40"; + } + m_cur_addr = 0; + m_totalSize = 0; + cur_segment = SEGMENT_CODE; + segment_addr[SEGMENT_CODE] = 0; + segment_addr[SEGMENT_DATA] = 0; + segment_addr[SEGMENT_OVERLAY] = 0; +} + +bool DSPAssembler::AssembleFile(const char *fname, int pass) +{ + int disable_text = 0; // modified by Hermes + + std::ifstream fsrc(fname); + + if (fsrc.fail()) + { + std::cerr << "Cannot open file " << fname << std::endl; + return false; + } + + //printf("%s: Pass %d\n", fname, pass); + code_line = 0; + m_cur_pass = pass; + +#define LINEBUF_SIZE 1024 + char line[LINEBUF_SIZE] = {0}; + while (!failed && !fsrc.fail() && !fsrc.eof()) + { + int opcode_size = 0; + fsrc.getline(line, LINEBUF_SIZE); + if(fsrc.fail()) + break; + + cur_line = line; + //printf("A: %s\n", line); + code_line++; + + param_t params[10] = {{0}}; + param_t params_ext[10] = {{0}}; + + bool upper = true; + for (int i = 0; i < LINEBUF_SIZE; i++) + { + char c = line[i]; + // This stuff handles /**/ and // comments. + // modified by Hermes : added // and /* */ for long commentaries + if (c == '/') + { + if (i < 1023) + { + if (line[i+1] == '/') + c = 0x00; + else if (line[i+1] == '*') + { + // toggle comment mode. + disable_text = !disable_text; + } + } + } + else if (c == '*') + { + if (i < 1023 && line[i+1] == '/' && disable_text) + { + disable_text = 0; + c = 32; + line[i + 1] = 32; + } + } + + // turn text into spaces if disable_text is on (in a comment). + if (disable_text && ((unsigned char)c) > 32) c = 32; + + if (c == 0x0a || c == 0x0d || c == ';') + c = 0x00; + if (c == 0x09) // tabs to spaces + c = ' '; + if (c == '"') + upper = !upper; + if (upper && c >= 'a' && c <= 'z') // convert to uppercase + c = c - 'a' + 'A'; + line[i] = c; + if (c == 0) + break; // modified by Hermes + } + char *ptr = line; + + std::string label; + + size_t col_pos = std::string(line).find(":"); + if (col_pos != std::string::npos) + { + bool valid = true; + + for(int j = 0; j < (int)col_pos; j++) + { + if (j == 0) + if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + } + if (valid) + { + label = std::string(line).substr(0, col_pos); + ptr += col_pos + 1; + } + } + + char *opcode = NULL; + opcode = strtok(ptr, " "); + char *opcode_ext = NULL; + + u32 params_count = 0; + u32 params_count_ext = 0; + if (opcode) + { + if ((opcode_ext = strstr(opcode, "'")) != NULL) + { + opcode_ext[0] = '\0'; + opcode_ext++; + if (strlen(opcode_ext) == 0) + opcode_ext = NULL; + } + // now we have opcode and label + + params_count = 0; + params_count_ext = 0; + + char *paramstr = strtok(NULL, "\0"); + char *paramstr_ext = 0; + // there is valid opcode so probably we have parameters + + if (paramstr) + { + if ((paramstr_ext = strstr(paramstr, ":")) != NULL) + { + paramstr_ext[0] = '\0'; + paramstr_ext++; + } + } + + if (paramstr) + params_count = GetParams(paramstr, params); + if (paramstr_ext) + params_count_ext = GetParams(paramstr_ext, params_ext); + } + + if (!label.empty()) + { + // there is a valid label so lets store it in labels table + u32 lval = m_cur_addr; + if (opcode) + { + if (strcmp(opcode, "EQU") == 0) + { + lval = params[0].val; + opcode = NULL; + } + } + if (pass == 1) + labels.RegisterLabel(label, lval); + } + + if (opcode == NULL) + continue; + + // check if opcode is reserved compiler word + if (strcmp("INCLUDE", opcode) == 0) + { + if (params[0].type == P_STR) + { + char *tmpstr; + u32 thisCodeline = code_line; + + if (include_dir.size()) + { + tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); + sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); + } + else + { + tmpstr = (char *)malloc(strlen(params[0].str) + 1); + strcpy(tmpstr, params[0].str); + } + + AssembleFile(tmpstr, pass); + + code_line = thisCodeline; + + free(tmpstr); + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("INCDIR", opcode) == 0) + { + if (params[0].type == P_STR) + include_dir = params[0].str; + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("ORG", opcode) == 0) + { + if (params[0].type == P_VAL) + m_cur_addr = params[0].val; + else + ShowError(ERR_EXPECTED_PARAM_VAL); + continue; + } + + if (strcmp("SEGMENT", opcode) == 0) + { + if (params[0].type == P_STR) + { + segment_addr[cur_segment] = m_cur_addr; + if (strcmp("DATA", params[0].str) == 0) + cur_segment = SEGMENT_DATA; + if (strcmp("CODE", params[0].str) == 0) + cur_segment = SEGMENT_CODE; + m_cur_addr = segment_addr[cur_segment]; + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } + + const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); + if (!opc) + opc = &cw; + + opcode_size = opc->size; + + VerifyParams(opc, params, params_count); + + const opc_t *opc_ext = NULL; + // Check for opcode extensions. + if (opc->extended) + { + if (opcode_ext) + { + opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); + VerifyParams(opc_ext, params_ext, params_count_ext, true); + } + else if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + else + { + if (opcode_ext) + ShowError(ERR_EXT_CANT_EXTEND_OPCODE); + if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + + if (pass == 2) + { + // generate binary + ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000; + BuildCode(opc, params, params_count, (u16 *)gdg_buffer); + if (opc_ext) + BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); + } + + m_cur_addr += opcode_size; + m_totalSize += opcode_size; + }; + + if (!failed) + fsrc.close(); + + return !failed; +} diff --git a/Source/Core/Core/Src/DSP/assemble.h b/Source/Core/Core/Src/DSP/assemble.h new file mode 100644 index 0000000000..f140d0e69e --- /dev/null +++ b/Source/Core/Core/Src/DSP/assemble.h @@ -0,0 +1,139 @@ +/*==================================================================== + + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSP_ASSEMBLE_H +#define _DSP_ASSEMBLE_H + +#include +#include + +#include "Common.h" +#include "disassemble.h" +#include "DSPTables.h" +#include "LabelMap.h" + +enum err_t +{ + ERR_OK = 0, + ERR_UNKNOWN, + ERR_UNKNOWN_OPCODE, + ERR_NOT_ENOUGH_PARAMETERS, + ERR_TOO_MANY_PARAMETERS, + ERR_WRONG_PARAMETER, + ERR_EXPECTED_PARAM_STR, + ERR_EXPECTED_PARAM_VAL, + ERR_EXPECTED_PARAM_REG, + ERR_EXPECTED_PARAM_MEM, + ERR_EXPECTED_PARAM_IMM, + ERR_INCORRECT_BIN, + ERR_INCORRECT_HEX, + ERR_INCORRECT_DEC, + ERR_LABEL_EXISTS, + ERR_UNKNOWN_LABEL, + ERR_NO_MATCHING_BRACKETS, + ERR_EXT_CANT_EXTEND_OPCODE, + ERR_EXT_PAR_NOT_EXT, + ERR_WRONG_PARAMETER_ACC, + ERR_WRONG_PARAMETER_MID_ACC, + ERR_INVALID_REGISTER, + ERR_OUT_RANGE_NUMBER +}; + + +// Unless you want labels to carry over between files, you probably +// want to create a new DSPAssembler for every file you assemble. +class DSPAssembler +{ +public: + DSPAssembler(const AssemblerSettings &settings); + ~DSPAssembler(); + + // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, + // one for each word of code, indicating the source assembler code line number it came from. + + // If returns false, call GetErrorString to get some text to present to the user. + bool Assemble(const char *text, std::vector &code, std::vector *line_numbers = NULL); + + std::string GetErrorString() const { return last_error_str; } + err_t GetError() const { return last_error; } + +private: + struct param_t + { + u32 val; + partype_t type; + char *str; + }; + + enum segment_t + { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_OVERLAY, + SEGMENT_MAX + }; + + // Utility functions + s32 ParseValue(const char *str); + u32 ParseExpression(const char *ptr); + + u32 GetParams(char *parstr, param_t *par); + + void InitPass(int pass); + bool AssembleFile(const char *fname, int pass); + + void ShowError(err_t err_code, const char *extra_info = NULL); + // void ShowWarning(err_t err_code, const char *extra_info = NULL); + + char *FindBrackets(char *src, char *dst); + const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size); + bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false); + void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); + + char *gdg_buffer; + + std::string include_dir; + std::string cur_line; + + u32 m_cur_addr; + int m_totalSize; + u8 m_cur_pass; + + LabelMap labels; + + u32 code_line; + bool failed; + std::string last_error_str; + err_t last_error; + + typedef std::map AliasMap; + AliasMap aliases; + + segment_t cur_segment; + u32 segment_addr[SEGMENT_MAX]; + int m_current_param; + const AssemblerSettings settings_; +}; + +#endif // _DSP_ASSEMBLE_H diff --git a/Source/Core/Core/Src/DSP/disassemble.cpp b/Source/Core/Core/Src/DSP/disassemble.cpp new file mode 100644 index 0000000000..03a81ddb1a --- /dev/null +++ b/Source/Core/Core/Src/DSP/disassemble.cpp @@ -0,0 +1,360 @@ +/*==================================================================== + + filename: disassemble.cpp + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#include +#include + +#include "Common.h" +#include "FileUtil.h" +#include "disassemble.h" +#include "DSPTables.h" + +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + +#ifndef MAX_PATH +#include // For MAX_PATH +#endif + +extern void nop(const UDSPInstruction opc); + +DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings) + : settings_(settings) +{ +} + +DSPDisassembler::~DSPDisassembler() +{ + // Some old code for logging unknown ops. + char filename[MAX_PATH]; + sprintf(filename, "%sUnkOps.txt", File::GetUserPath(D_DUMPDSP_IDX)); + FILE *uo = fopen(filename, "w"); + if (!uo) + return; + + int count = 0; + for (std::map::const_iterator iter = unk_opcodes.begin(); + iter != unk_opcodes.end(); ++iter) + { + if (iter->second > 0) + { + count++; + fprintf(uo, "OP%04x\t%d", iter->first, iter->second); + for (int j = 15; j >= 0; j--) // print op bits + { + if ((j & 0x3) == 3) + fprintf(uo, "\tb"); + fprintf(uo, "%d", (iter->first >> j) & 0x1); + } + fprintf(uo, "\n"); + } + } + fprintf(uo, "Unknown opcodes count: %d\n", count); + fclose(uo); +} + +bool DSPDisassembler::Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text) +{ + const char *tmp1 = "tmp1.bin"; + + // First we have to dump the code to a bin file. + FILE *f = fopen(tmp1, "wb"); + fwrite(&code[0], 1, code.size() * 2, f); + fclose(f); + + // Run the two passes. + return DisFile(tmp1, base_addr, 1, text) && DisFile(tmp1, base_addr, 2, text); +} + +char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char *strbuf) +{ + char *buf = strbuf; + for (int j = 0; j < opc.param_count; j++) + { + if (j > 0) + buf += sprintf(buf, ", "); + + u32 val = (opc.params[j].loc >= 1) ? op2 : op1; + val &= opc.params[j].mask; + if (opc.params[j].lshift < 0) + val = val << (-opc.params[j].lshift); + else + val = val >> opc.params[j].lshift; + + u32 type = opc.params[j].type; + if ((type & 0xff) == 0x10) + type &= 0xff00; + + if (type & P_REG) + { + // Check for _D parameter - if so flip. + if ((type == P_ACC_D) || (type == P_ACCM_D)) // Used to be P_ACCM_D TODO verify + val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8); + else + val |= (type & P_REGS_MASK) >> 8; + type &= ~P_REGS_MASK; + } + + switch (type) + { + case P_REG: + if (settings_.decode_registers) + sprintf(buf, "$%s", pdregname(val)); + else + sprintf(buf, "$%d", val); + break; + + case P_PRG: + if (settings_.decode_registers) + sprintf(buf, "@$%s", pdregname(val)); + else + sprintf(buf, "@$%d", val); + break; + + case P_VAL: + case P_ADDR_I: + case P_ADDR_D: + if (settings_.decode_names) + { + sprintf(buf, "%s", pdname(val)); + } + else + sprintf(buf, "0x%04x", val); + break; + + case P_IMM: + if (opc.params[j].size != 2) + { + if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR + sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension + else + sprintf(buf, "#0x%02x", val); + } + else + { + sprintf(buf, "#0x%04x", val); + } + break; + + case P_MEM: + if (opc.params[j].size != 2) + val = (u16)(s16)(s8)val; + + if (settings_.decode_names) + sprintf(buf, "@%s", pdname(val)); + else + sprintf(buf, "@0x%04x", val); + break; + + default: + ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc.params[j].type); + break; + } + + buf += strlen(buf); + } + + return strbuf; +} + +static void MakeLowerCase(char *ptr) +{ + int i = 0; + while (ptr[i]) + { + ptr[i] = tolower(ptr[i]); + i++; + } +} + +bool DSPDisassembler::DisOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest) +{ + char buffer[256]; + char *buf = buffer; + + // Start with 8 spaces, if there's no label. + buf[0] = ' '; + buf[1] = '\0'; + buf++; + + if ((*pc & 0x7fff) >= 0x1000) + { + ++pc; + dest.append("; outside memory"); + return false; + } + + const u32 op1 = binbuf[*pc & 0x0fff]; + + const DSPOPCTemplate *opc = NULL; + const DSPOPCTemplate *opc_ext = NULL; + + // find opcode + for (int j = 0; j < opcodes_size; j++) + { + u16 mask = opcodes[j].opcode_mask; + + if ((op1 & mask) == opcodes[j].opcode) + { + opc = &opcodes[j]; + break; + } + } + const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, NULL, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false}; + if (!opc) + opc = &fake_op; + + bool extended = false; + bool only7bitext = false; + + if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f)) { + extended = true; + only7bitext = true; + } + else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff)) + extended = true; + else + extended = false; + + if (extended) + { + // opcode has an extension + // find opcode + for (int j = 0; j < opcodes_ext_size; j++) + { + if (only7bitext) { + if (((op1 & 0x7f) & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) + { + opc_ext = &opcodes_ext[j]; + break; + } + } + else { + if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) + { + opc_ext = &opcodes_ext[j]; + break; + } + } + } + } + + // printing + + if (settings_.show_pc) + buf += sprintf(buf, "%04x ", *pc); + + u32 op2; + + // Size 2 - the op has a large immediate. + if (opc->size == 2) + { + op2 = binbuf[(*pc + 1) & 0x0fff]; + if (settings_.show_hex) + buf += sprintf(buf, "%04x %04x ", op1, op2); + } + else + { + op2 = 0; + if (settings_.show_hex) + buf += sprintf(buf, "%04x ", op1); + } + + char opname[20]; + strcpy(opname, opc->name); + if (settings_.lower_case_ops) + MakeLowerCase(opname); + char ext_buf[20]; + if (extended) + sprintf(ext_buf, "%s%c%s", opname, settings_.ext_separator, opc_ext->name); + else + sprintf(ext_buf, "%s", opname); + if (settings_.lower_case_ops) + MakeLowerCase(ext_buf); + + if (settings_.print_tabs) + buf += sprintf(buf, "%s\t", ext_buf); + else + buf += sprintf(buf, "%-12s", ext_buf); + + if (opc->param_count > 0) + DisParams(*opc, op1, op2, buf); + + buf += strlen(buf); + + // Handle opcode extension. + if (extended) + { + if (opc->param_count > 0) + buf += sprintf(buf, " "); + buf += sprintf(buf, ": "); + if (opc_ext->param_count > 0) + DisParams(*opc_ext, op1, op2, buf); + + buf += strlen(buf); + } + + if (opc->opcode_mask == 0) + { + // unknown opcode + unk_opcodes[op1]++; + sprintf(buf, "\t\t; *** UNKNOWN OPCODE ***"); + } + + if (extended) + *pc += opc_ext->size; + else + *pc += opc->size; + + if (pass == 2) + dest.append(buffer); + return true; +} + +bool DSPDisassembler::DisFile(const char* name, int base_addr, int pass, std::string &output) +{ + FILE* in = fopen(name, "rb"); + if (in == NULL) + { + printf("gd_dis_file: No input\n"); + return false; + } + + int size = (int)File::GetSize(in) & ~1; + u16 *binbuf = new u16[size / 2]; + fread(binbuf, 1, size, in); + fclose(in); + + // Actually do the disassembly. + for (u16 pc = 0; pc < (size / 2);) + { + DisOpcode(binbuf, base_addr, pass, &pc, output); + if (pass == 2) + output.append("\n"); + } + delete [] binbuf; + return true; +} diff --git a/Source/Core/Core/Src/DSP/disassemble.h b/Source/Core/Core/Src/DSP/disassemble.h new file mode 100644 index 0000000000..dba9f36287 --- /dev/null +++ b/Source/Core/Core/Src/DSP/disassemble.h @@ -0,0 +1,87 @@ +/*==================================================================== + + project: GameCube DSP Tool (gcdsp) + created: 2005.03.04 + mail: duddie@walla.com + + Copyright (c) 2005 Duddie + + This program is free software; you can redistribute it and/or + modify it 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 received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ====================================================================*/ + +#ifndef _DSP_DISASSEMBLE_H +#define _DSP_DISASSEMBLE_H + +#include +#include + +#include "Common.h" +#include "DSPTables.h" +#include "LabelMap.h" + +struct AssemblerSettings +{ + AssemblerSettings() + : print_tabs(false), + show_hex(false), + show_pc(false), + force(false), + decode_names(true), + decode_registers(true), + ext_separator('\''), + lower_case_ops(true), + pc(0) + { + } + + bool print_tabs; + bool show_hex; + bool show_pc; + bool force; + bool decode_names; + bool decode_registers; + char ext_separator; + bool lower_case_ops; + + u16 pc; +}; + +class DSPDisassembler +{ +public: + DSPDisassembler(const AssemblerSettings &settings); + ~DSPDisassembler(); + + bool Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text); + + // Warning - this one is trickier to use right. + // Use pass == 2 if you're just using it by itself. + bool DisOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest); + +private: + // Moves PC forward and writes the result to dest. + bool DisFile(const char* name, int base_addr, int pass, std::string &output); + + char* DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char* strbuf); + std::map unk_opcodes; + + const AssemblerSettings settings_; + + LabelMap labels; +}; + +#endif // _DSP_DISASSEMBLE_H + diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp index e1b1147cd1..2e2816ae77 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp @@ -17,11 +17,11 @@ #include "DSPDebugInterface.h" -#include "DSPCore.h" -#include "disassemble.h" +#include "DSP/DSPCore.h" +#include "DSP/disassemble.h" #include "DSPSymbols.h" -#include "DSPMemoryMap.h" +#include "DSP/DSPMemoryMap.h" void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size) { diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPHost.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPHost.cpp index 94c7082b1f..fa9341159b 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPHost.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPHost.cpp @@ -17,7 +17,7 @@ #include "Common.h" #include "Hash.h" -#include "DSPHost.h" +#include "DSP/DSPHost.h" #include "DSPSymbols.h" #include "DSPLLETools.h" #include "../DSP.h" diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp index f9ab57a44d..f84d630559 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp @@ -26,16 +26,16 @@ #include "IniFile.h" #include "DSPLLEGlobals.h" // Local -#include "DSPInterpreter.h" -#include "DSPHWInterface.h" -#include "disassemble.h" +#include "DSP/DSPInterpreter.h" +#include "DSP/DSPHWInterface.h" +#include "DSP/disassemble.h" #include "DSPSymbols.h" #include "AudioCommon.h" #include "Mixer.h" -#include "DSPTables.h" -#include "DSPCore.h" +#include "DSP/DSPTables.h" +#include "DSP/DSPCore.h" #include "DSPLLE.h" #include "../Memmap.h" #include "../AudioInterface.h" diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPLLEGlobals.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPLLEGlobals.cpp index e102e0ff83..1113bd5014 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPLLEGlobals.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPLLEGlobals.cpp @@ -20,7 +20,7 @@ #include #include "Common.h" // for Common::swap -#include "DSPCore.h" +#include "DSP/DSPCore.h" #include "DSPLLEGlobals.h" #if PROFILE diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPLLETools.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPLLETools.cpp index 18c8628932..ddead22d43 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPLLETools.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPLLETools.cpp @@ -22,11 +22,11 @@ #include "DSPLLEGlobals.h" #include "FileUtil.h" -#include "DSPCore.h" -#include "DSPCodeUtil.h" +#include "DSP/DSPCore.h" +#include "DSP/DSPCodeUtil.h" #include "DSPLLETools.h" -#include "disassemble.h" -#include "DSPInterpreter.h" +#include "DSP/disassemble.h" +#include "DSP/DSPInterpreter.h" bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc) { diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPSymbols.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPSymbols.cpp index e67c48ba98..eb269b6b3b 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPSymbols.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPSymbols.cpp @@ -26,9 +26,9 @@ #include "Common.h" #include "StringUtil.h" -#include "DSPCore.h" +#include "DSP/DSPCore.h" #include "DSPSymbols.h" -#include "disassemble.h" +#include "DSP/disassemble.h" namespace DSPSymbols { diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index d545c2e6ca..950f04404f 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -6,8 +6,6 @@ import sys files = [ "ActionReplay.cpp", "ARDecrypt.cpp", - "GeckoCode.cpp", - "GeckoCodeConfig.cpp", "ConfigManager.cpp", "Console.cpp", "Core.cpp", @@ -32,6 +30,37 @@ files = [ "Debugger/Debugger_SymbolMap.cpp", "Debugger/Dump.cpp", "Debugger/PPCDebugInterface.cpp", + "DSP/assemble.cpp", + "DSP/disassemble.cpp", + "DSP/DSPAccelerator.cpp", + "DSP/DSPIntCCUtil.cpp", + "DSP/DSPIntExtOps.cpp", + "DSP/DSPHWInterface.cpp", + "DSP/DSPMemoryMap.cpp", + "DSP/DSPStacks.cpp", + "DSP/DSPAnalyzer.cpp", + "DSP/DspIntArithmetic.cpp", + "DSP/DspIntBranch.cpp", + "DSP/DspIntLoadStore.cpp", + "DSP/DspIntMisc.cpp", + "DSP/DspIntMultiplier.cpp", + "DSP/DSPEmitter.cpp", + "DSP/DSPCodeUtil.cpp", + "DSP/LabelMap.cpp", + "DSP/DSPInterpreter.cpp", + "DSP/DSPCore.cpp", + "DSP/DSPTables.cpp", + "DSP/Jit/DSPJitExtOps.cpp", + "DSP/Jit/DSPJitBranch.cpp", + "DSP/Jit/DSPJitUtil.cpp", + "DSP/Jit/DSPJitCCUtil.cpp", + "DSP/Jit/DSPJitArithmetic.cpp", + "DSP/Jit/DSPJitLoadStore.cpp", + "DSP/Jit/DSPJitMultiplier.cpp", + "DSP/Jit/DSPJitMisc.cpp", + "DSP/Jit/DSPJitRegCache.cpp", + "GeckoCode.cpp", + "GeckoCodeConfig.cpp", "HLE/HLE.cpp", "HLE/HLE_Misc.cpp", "HLE/HLE_OS.cpp", @@ -165,7 +194,7 @@ if sys.platform == 'win32': elif sys.platform == 'darwin': files += [ "HW/BBA-TAP/TAP_Apple.cpp", "HW/WiimoteReal/IOdarwin.mm" ] elif sys.platform == 'linux2' and env['HAVE_BLUEZ']: - files += [ "HW/BBA-TAP/TAP_Unix.cpp", "HW/WiimoteReal/IONix.cpp" ] + files += [ "HW/BBA-TAP/TAP_Unix.cpp", "HW/WiimoteReal/IODummy.cpp" ] else: files += [ "HW/BBA-TAP/TAP_Unix.cpp", "HW/WiimoteReal/IODummy.cpp" ] diff --git a/Source/Core/DSPCore/CMakeLists.txt b/Source/Core/DSPCore/CMakeLists.txt deleted file mode 100644 index ab379cd377..0000000000 --- a/Source/Core/DSPCore/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -set(SRCS Src/assemble.cpp - Src/disassemble.cpp - Src/DSPAccelerator.cpp - Src/DSPIntCCUtil.cpp - Src/DSPIntExtOps.cpp - Src/DSPHWInterface.cpp - Src/DSPMemoryMap.cpp - Src/DSPStacks.cpp - Src/DSPAnalyzer.cpp - Src/DspIntArithmetic.cpp - Src/DspIntBranch.cpp - Src/DspIntLoadStore.cpp - Src/DspIntMisc.cpp - Src/DspIntMultiplier.cpp - Src/DSPEmitter.cpp - Src/DSPCodeUtil.cpp - Src/LabelMap.cpp - Src/DSPInterpreter.cpp - Src/DSPCore.cpp - Src/DSPTables.cpp - Src/Jit/DSPJitRegCache.cpp - Src/Jit/DSPJitExtOps.cpp - Src/Jit/DSPJitBranch.cpp - Src/Jit/DSPJitCCUtil.cpp - Src/Jit/DSPJitArithmetic.cpp - Src/Jit/DSPJitLoadStore.cpp - Src/Jit/DSPJitMultiplier.cpp - Src/Jit/DSPJitUtil.cpp - Src/Jit/DSPJitMisc.cpp) - -add_library(dspcore STATIC ${SRCS}) -target_link_libraries(dspcore core) -if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_definitions(-fPIC) -endif() diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj deleted file mode 100644 index 43f7401e8a..0000000000 --- a/Source/Core/DSPCore/DSPCore.vcproj +++ /dev/null @@ -1,621 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/Core/DSPCore/DSPCore.vcxproj b/Source/Core/DSPCore/DSPCore.vcxproj deleted file mode 100644 index 77eeeea1f3..0000000000 --- a/Source/Core/DSPCore/DSPCore.vcxproj +++ /dev/null @@ -1,239 +0,0 @@ - - - - - DebugFast - Win32 - - - DebugFast - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {4ED3C8BE-91A7-4361-8D46-16D03B678D4C} - DSPCore - - - - StaticLibrary - true - Unicode - - - StaticLibrary - true - MultiByte - - - StaticLibrary - false - true - Unicode - - - StaticLibrary - false - true - Unicode - - - StaticLibrary - false - true - MultiByte - - - StaticLibrary - false - true - MultiByte - - - - - - - - - - - - - - - - - - - - - - - - - - - Level3 - Disabled - ..\Common\Src;%(AdditionalIncludeDirectories) - _SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - Level3 - Disabled - ..\Common\Src;%(AdditionalIncludeDirectories) - _SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - Level3 - MaxSpeed - true - true - ..\Common\Src;%(AdditionalIncludeDirectories) - _SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - ..\Common\Src;%(AdditionalIncludeDirectories) - DEBUGFAST;_SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - ..\Common\Src;%(AdditionalIncludeDirectories) - _SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - ..\Common\Src;%(AdditionalIncludeDirectories) - DEBUGFAST;_SECURE_SCL=0;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - - \ No newline at end of file diff --git a/Source/Core/DSPCore/Src/DSPAccelerator.cpp b/Source/Core/DSPCore/Src/DSPAccelerator.cpp deleted file mode 100644 index a45ab15e9d..0000000000 --- a/Source/Core/DSPCore/Src/DSPAccelerator.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "Common.h" - -#include "DSPCore.h" -#include "DSPHost.h" -#include "DSPHWInterface.h" -#include "DSPInterpreter.h" - -// The hardware adpcm decoder :) -static s16 ADPCM_Step(u32& _rSamplePos) -{ - const s16 *pCoefTable = (const s16 *)&g_dsp.ifx_regs[DSP_COEF_A1_0]; - - if (((_rSamplePos) & 15) == 0) - { - g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost_ReadHostMemory((_rSamplePos & ~15) >> 1); - _rSamplePos += 2; - } - - int scale = 1 << (g_dsp.ifx_regs[DSP_PRED_SCALE] & 0xF); - int coef_idx = (g_dsp.ifx_regs[DSP_PRED_SCALE] >> 4) & 0x7; - - s32 coef1 = pCoefTable[coef_idx * 2 + 0]; - s32 coef2 = pCoefTable[coef_idx * 2 + 1]; - - int temp = (_rSamplePos & 1) ? - (DSPHost_ReadHostMemory(_rSamplePos >> 1) & 0xF) : - (DSPHost_ReadHostMemory(_rSamplePos >> 1) >> 4); - - if (temp >= 8) - temp -= 16; - - // 0x400 = 0.5 in 11-bit fixed point - int val = (scale * temp) + ((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11); - - // Clamp values. - if (val > 0x7FFF) - val = 0x7FFF; - else if (val < -0x7FFF) - val = -0x7FFF; - - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; - - _rSamplePos++; - - // The advanced interpolation (linear, polyphase,...) is done by the UCode, - // so we don't need to bother with it here. - return val; -} - -u16 dsp_read_aram_d3() -{ - // Zelda ucode reads ARAM through 0xffd3. - const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - u16 val = 0; - - switch (g_dsp.ifx_regs[DSP_FORMAT]) { - case 0x5: // u8 reads - val = DSPHost_ReadHostMemory(Address); - Address++; - break; - case 0x6: // u16 reads - val = (DSPHost_ReadHostMemory(Address*2) << 8) | DSPHost_ReadHostMemory(Address*2 + 1); - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_read_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - break; - } - - if (Address >= EndAddress) - { - // Set address back to start address. (never seen this here!) - Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; - } - - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; - return val; -} - -void dsp_write_aram_d3(u16 value) -{ - // Zelda ucode writes a bunch of zeros to ARAM through d3 during - // initialization. Don't know if it ever does it later, too. - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - - switch (g_dsp.ifx_regs[DSP_FORMAT]) { - case 0xA: // u16 writes - DSPHost_WriteHostMemory(value >> 8, Address*2); - DSPHost_WriteHostMemory(value & 0xFF, Address*2 + 1); - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_write_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - break; - } - - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; -} - -u16 dsp_read_accelerator() -{ - const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - u16 val; - - // let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda - // ucode seems to indicate that the bottom two bits specify the "read size" - // and the address multiplier. The bits above that may be things like sign - // extention and do/do not use ADPCM. It also remains to be figured out - // whether there's a difference between the usual accelerator "read - // address" and 0xd3. - switch (g_dsp.ifx_regs[DSP_FORMAT]) - { - case 0x00: // ADPCM audio - val = ADPCM_Step(Address); - break; - case 0x0A: // 16-bit PCM audio - val = (DSPHost_ReadHostMemory(Address*2) << 8) | DSPHost_ReadHostMemory(Address*2 + 1); - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; - Address++; - break; - case 0x19: // 8-bit PCM audio - val = DSPHost_ReadHostMemory(Address) << 8; - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_read_accelerator() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - Address++; - val = 0; - break; - } - - // TODO: Take GAIN into account - // adpcm = 0, pcm8 = 0x100, pcm16 = 0x800 - // games using pcm8 : Phoenix Wright Ace Attorney (Wiiware), Megaman 9-10 (WiiWare) - // games using pcm16: gc sega games, ... - - // Check for loop. - // Somehow, YN1 and YN2 must be initialized with their "loop" values, - // so yeah, it seems likely that we should raise an exception to let - // the DSP program do that, at least if DSP_FORMAT == 0x0A. - if (Address >= EndAddress) - { - // Set address back to start address. - Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; - DSPCore_SetException(EXP_ACCOV); - } - - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; - return val; -} diff --git a/Source/Core/DSPCore/Src/DSPAccelerator.h b/Source/Core/DSPCore/Src/DSPAccelerator.h deleted file mode 100644 index a64516a036..0000000000 --- a/Source/Core/DSPCore/Src/DSPAccelerator.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSP_ACCELERATOR_H -#define _DSP_ACCELERATOR_H - -u16 dsp_read_accelerator(); - -u16 dsp_read_aram_d3(); -void dsp_write_aram_d3(u16 value); - -#endif diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp deleted file mode 100644 index 8f6b0d4e35..0000000000 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DSPAnalyzer.h" -#include "DSPInterpreter.h" -#include "DSPTables.h" -#include "DSPMemoryMap.h" - -namespace DSPAnalyzer { - -// Holds data about all instructions in RAM. -u8 code_flags[ISPACE]; - -// Good candidates for idle skipping is mail wait loops. If we're time slicing -// between the main CPU and the DSP, if the DSP runs into one of these, it might -// as well give up its time slice immediately, after executing once. - -// Max signature length is 6. A 0 in a signature is ignored. -#define NUM_IDLE_SIGS 8 -#define MAX_IDLE_SIG_SIZE 6 - -// 0xFFFF means ignore. -const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = -{ - // From AX: - { 0x26fc, // LRS $30, @DMBH - 0x02c0, 0x8000, // ANDCF $30, #0x8000 - 0x029d, 0xFFFF, // JLZ 0x027a - 0, 0 }, // RET - { 0x27fc, // LRS $31, @DMBH - 0x03c0, 0x8000, // ANDCF $31, #0x8000 - 0x029d, 0xFFFF, // JLZ 0x027a - 0, 0 }, // RET - { 0x26fe, // LRS $30, @CMBH - 0x02c0, 0x8000, // ANDCF $30, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x0280 - 0, 0 }, // RET - { 0x27fe, // LRS $31, @CMBH - 0x03c0, 0x8000, // ANDCF $31, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x0280 - 0, 0 }, // RET - { 0x26fc, // lrs $AC0.M, @DMBH - 0x02a0, 0x8000, // andf $AC0.M, #0x8000 - 0x029c, 0xFFFF, // jlnz 0x???? - 0, 0 }, - { 0x27fc, // lrs $AC1.M, @DMBH - 0x03a0, 0x8000, // andf $AC1.M, #0x8000 - 0x029c, 0xFFFF, // jlnz 0x???? - 0, 0 }, - // From Zelda: - { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH - 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x05cf - 0 }, - // From Zelda - experimental - { 0x00da, 0x0352, // lr $AX0.H, @0x0352 - 0x8600, // tstaxh $AX0.H - 0x0295, 0xFFFF, // jz 0x???? - 0, 0 } -}; - -void Reset() -{ - memset(code_flags, 0, sizeof(code_flags)); -} - -void AnalyzeRange(int start_addr, int end_addr) -{ - // First we run an extremely simplified version of a disassembler to find - // where all instructions start. - - // This may not be 100% accurate in case of jump tables! - // It could get desynced, which would be bad. We'll see if that's an issue. - u16 last_arithmetic = 0; - for (int addr = start_addr; addr < end_addr;) - { - UDSPInstruction inst = dsp_imem_read(addr); - const DSPOPCTemplate *opcode = GetOpTemplate(inst); - if (!opcode) - { - addr++; - continue; - } - code_flags[addr] |= CODE_START_OF_INST; - // Look for loops. - if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) - { - // BLOOP, BLOOPI - u16 loop_end = dsp_imem_read(addr + 1); - code_flags[addr] |= CODE_LOOP_START; - code_flags[loop_end] |= CODE_LOOP_END; - } - else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) - { - // LOOP, LOOPI - code_flags[addr] |= CODE_LOOP_START; - code_flags[addr + 1] |= CODE_LOOP_END; - } - - // Mark the last arithmetic/multiplier instruction before a branch. - // We must update the SR reg at these instructions - if (opcode->updates_sr) - { - last_arithmetic = addr; - } - - if (opcode->branch && !opcode->uncond_branch) - { - code_flags[last_arithmetic] |= CODE_UPDATE_SR; - } - - // If an instruction potentially raises exceptions, mark the following - // instruction as needing to check for exceptions - if (opcode->opcode == 0x00c0 || - opcode->opcode == 0x1800 || - opcode->opcode == 0x1880 || - opcode->opcode == 0x1900 || - opcode->opcode == 0x1980 || - opcode->opcode == 0x2000 || - opcode->extended - ) - code_flags[addr + opcode->size] |= CODE_CHECK_INT; - - addr += opcode->size; - } - - // Next, we'll scan for potential idle skips. - for (int s = 0; s < NUM_IDLE_SIGS; s++) - { - for (int addr = start_addr; addr < end_addr; addr++) - { - bool found = false; - for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) - { - if (idle_skip_sigs[s][i] == 0) - found = true; - if (idle_skip_sigs[s][i] == 0xFFFF) - continue; - if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) - break; - } - if (found) - { - INFO_LOG(DSPLLE, "Idle skip location found at %02x (sigNum:%d)", addr, s+1); - code_flags[addr] |= CODE_IDLE_SKIP; - } - } - } - INFO_LOG(DSPLLE, "Finished analysis."); -} - -void Analyze() -{ - Reset(); - AnalyzeRange(0x0000, 0x1000); // IRAM - AnalyzeRange(0x8000, 0x9000); // IROM -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h deleted file mode 100644 index 9c05dae708..0000000000 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Basic code analysis. - -#include "DSPInterpreter.h" - -namespace DSPAnalyzer { - -#define ISPACE 65536 - -// Useful things to detect: -// * Loop endpoints - so that we can avoid checking for loops every cycle. - -enum -{ - CODE_START_OF_INST = 1, - CODE_IDLE_SKIP = 2, - CODE_LOOP_START = 4, - CODE_LOOP_END = 8, - CODE_UPDATE_SR = 16, - CODE_CHECK_INT = 32, -}; - -// Easy to query array covering the whole of instruction memory. -// Just index by address. -// This one will be helpful for debuggers and jits. -extern u8 code_flags[ISPACE]; - -// This one should be called every time IRAM changes - which is basically -// every time that a new ucode gets uploaded, and never else. At that point, -// we can do as much static analysis as we want - but we should always throw -// all old analysis away. Luckily the entire address space is only 64K code -// words and the actual code space 8K instructions in total, so we can do -// some pretty expensive analysis if necessary. -void Analyze(); - -} // namespace diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.h b/Source/Core/DSPCore/Src/DSPBreakpoints.h deleted file mode 100644 index b366e760a7..0000000000 --- a/Source/Core/DSPCore/Src/DSPBreakpoints.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSP_BREAKPOINTS -#define _DSP_BREAKPOINTS - -#include "Common.h" - -// super fast breakpoints for a limited range. -// To be used interchangably with the BreakPoints class. -class DSPBreakpoints -{ -public: - DSPBreakpoints() {Clear();} - // is address breakpoint - bool IsAddressBreakPoint(u32 addr) { - return b[addr] != 0; - } - - // AddBreakPoint - bool Add(u32 addr, bool temp=false) { - bool was_one = b[addr] != 0; - if (!was_one) { - b[addr] = temp ? 2 : 1; - return true; - } else { - return false; - } - } - // Remove Breakpoint - bool Remove(u32 addr) { - bool was_one = b[addr] != 0; - b[addr] = 0; - return was_one; - } - void Clear() { - for (int i = 0; i < 65536; i++) - b[i] = 0; - } - - void DeleteByAddress(u32 addr) { - b[addr] = 0; - } - -private: - u8 b[65536]; -}; - -#endif diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp deleted file mode 100644 index ca9c01d5dc..0000000000 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -#include "Common.h" -#include "FileUtil.h" -#include "StringUtil.h" -#include "DSPCodeUtil.h" -#include "assemble.h" -#include "disassemble.h" - - -bool Assemble(const char *text, std::vector &code, bool force) -{ - AssemblerSettings settings; - // settings.pc = 0; - // settings.decode_registers = false; - // settings.decode_names = false; - settings.force = force; - // settings.print_tabs = false; - // settings.ext_separator = '\''; - - // TODO: fix the terrible api of the assembler. - DSPAssembler assembler(settings); - if (!assembler.Assemble(text, code)) { - std::cerr << assembler.GetErrorString() << std::endl; - return false; - } - - return true; -} - -bool Disassemble(const std::vector &code, bool line_numbers, std::string &text) -{ - if (code.empty()) - return false; - - AssemblerSettings settings; - - // These two prevent roundtripping. - settings.show_hex = true; - settings.show_pc = line_numbers; - settings.ext_separator = '\''; - settings.decode_names = true; - settings.decode_registers = true; - - DSPDisassembler disasm(settings); - bool success = disasm.Disassemble(0, code, 0x0000, text); - return success; -} - -bool Compare(const std::vector &code1, const std::vector &code2) -{ - if (code1.size() != code2.size()) - printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size()); - u32 count_equal = 0; - const int min_size = (int)std::min(code1.size(), code2.size()); - - AssemblerSettings settings; - DSPDisassembler disassembler(settings); - for (int i = 0; i < min_size; i++) - { - if (code1[i] == code2[i]) - count_equal++; - else - { - std::string line1, line2; - u16 pc = i; - disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1); - pc = i; - disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2); - printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str()); - } - } - if (code2.size() != code1.size()) - { - printf("Extra code words:\n"); - const std::vector &longest = code1.size() > code2.size() ? code1 : code2; - for (int i = min_size; i < (int)longest.size(); i++) - { - u16 pc = i; - std::string line; - disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line); - printf("!! %s\n", line.c_str()); - } - } - printf("Equal instruction words: %i / %i\n", count_equal, min_size); - return code1.size() == code2.size() && code1.size() == count_equal; -} - -void GenRandomCode(int size, std::vector &code) -{ - code.resize(size); - for (int i = 0; i < size; i++) - { - code[i] = rand() ^ (rand() << 8); - } -} - -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header) -{ - std::vector code_padded = code; - // Pad with nops to 32byte boundary - while (code_padded.size() & 0x7f) - code_padded.push_back(0); - - char buffer[1024]; - header.clear(); - header.reserve(code_padded.size() * 4); - header.append("#define NUM_UCODES 1\n\n"); - std::string filename; - SplitPath(_filename, NULL, &filename, NULL); - header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); - header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); - - header.append("\t{\n\t\t"); - for (u32 j = 0; j < code_padded.size(); j++) - { - if (j && ((j & 15) == 0)) - header.append("\n\t\t"); - sprintf(buffer, "0x%04x, ", code_padded[j]); - header.append(buffer); - } - header.append("\n\t},\n"); - - header.append("};\n"); -} - -void CodesToHeader(const std::vector *codes, const std::vector* filenames, - int numCodes, const char *name, std::string &header) -{ - std::vector > codes_padded; - char buffer[1024]; - int reserveSize = 0; - for(int i = 0; i < numCodes; i++) - { - codes_padded.push_back(codes[i]); - // Pad with nops to 32byte boundary - while (codes_padded.at(i).size() & 0x7f) - codes_padded.at(i).push_back(0); - - reserveSize += (int)codes_padded.at(i).size(); - } - - - header.clear(); - header.reserve(reserveSize * 4); - sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes); - header.append(buffer); - header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); - for (int i = 0; i < numCodes; i++) - { - std::string filename; - if (! SplitPath(filenames->at(i), NULL, &filename, NULL)) - filename = filenames->at(i); - sprintf(buffer, "\t\"%s\",\n", filename.c_str()); - header.append(buffer); - } - header.append("};\n\n"); - header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); - - for(int i = 0; i < numCodes; i++) - { - if(codes[i].size() == 0) - continue; - - header.append("\t{\n\t\t"); - for (u32 j = 0; j < codes_padded.at(i).size(); j++) - { - if (j && ((j & 15) == 0)) - header.append("\n\t\t"); - sprintf(buffer, "0x%04x, ", codes_padded.at(i).at(j)); - header.append(buffer); - } - header.append("\n\t},\n"); - } - header.append("};\n"); -} - -void CodeToBinaryStringBE(const std::vector &code, std::string &str) -{ - str.resize(code.size() * 2); - for (int i = 0; i < (int)code.size(); i++) - { - str[i * 2 + 0] = code[i] >> 8; - str[i * 2 + 1] = code[i] & 0xff; - } -} - -void BinaryStringBEToCode(const std::string &str, std::vector &code) -{ - code.resize(str.size() / 2); - for (int i = 0; i < (int)code.size(); i++) - { - code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); - } -} - -bool LoadBinary(const char *filename, std::vector &code) -{ - std::string buffer; - if (!File::ReadFileToString(false, filename, buffer)) - return false; - - BinaryStringBEToCode(buffer, code); - return true; -} - -bool SaveBinary(const std::vector &code, const char *filename) -{ - std::string buffer; - CodeToBinaryStringBE(code, buffer); - if (!File::WriteStringToFile(false, buffer, filename)) - return false; - return true; -} diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h deleted file mode 100644 index 2a2ebfb228..0000000000 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSPCODEUTIL_H -#define _DSPCODEUTIL_H - -#include -#include - -#include "Common.h" - -bool Assemble(const char *text, std::vector &code, bool force = false); -bool Disassemble(const std::vector &code, bool line_numbers, std::string &text); -bool Compare(const std::vector &code1, const std::vector &code2); -void GenRandomCode(int size, std::vector &code); -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header); -void CodesToHeader(const std::vector *codes, const std::vector *filenames, - int numCodes, const char *name, std::string &header); - -// Big-endian, for writing straight to file using File::WriteStringToFile. -void CodeToBinaryStringBE(const std::vector &code, std::string &str); -void BinaryStringBEToCode(const std::string &str, std::vector &code); - -// Load code (big endian binary). -bool LoadBinary(const char *filename, std::vector &code); -bool SaveBinary(const std::vector &code, const char *filename); - -#endif // _DSPCODEUTIL_H diff --git a/Source/Core/DSPCore/Src/DSPCommon.h b/Source/Core/DSPCore/Src/DSPCommon.h deleted file mode 100644 index 8133cdc54e..0000000000 --- a/Source/Core/DSPCore/Src/DSPCommon.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __DSPCOMMON_H -#define __DSPCOMMON_H -#include "CommonTypes.h" -typedef u16 UDSPInstruction; - - - -#endif diff --git a/Source/Core/DSPCore/Src/DSPCore.cpp b/Source/Core/DSPCore/Src/DSPCore.cpp deleted file mode 100644 index b053395881..0000000000 --- a/Source/Core/DSPCore/Src/DSPCore.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/*==================================================================== - - filename: gdsp_interpreter.cpp - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include "Common.h" -#include "Hash.h" -#include "Thread.h" -#include "DSPCore.h" -#include "DSPEmitter.h" -#include "DSPHost.h" -#include "DSPAnalyzer.h" -#include "MemoryUtil.h" - -#include "DSPHWInterface.h" -#include "DSPIntUtil.h" - -SDSP g_dsp; -DSPBreakpoints dsp_breakpoints; -DSPCoreState core_state = DSPCORE_STOP; -u16 cyclesLeft = 0; -DSPEmitter *dspjit = NULL; -Common::Event step_event; -Common::CriticalSection ExtIntCriticalSection; - -static bool LoadRom(const char *fname, int size_in_words, u16 *rom) -{ - FILE *pFile = fopen(fname, "rb"); - const size_t size_in_bytes = size_in_words * sizeof(u16); - if (pFile) - { - fread(rom, 1, size_in_bytes, pFile); - fclose(pFile); - - // Byteswap the rom. - for (int i = 0; i < size_in_words; i++) - rom[i] = Common::swap16(rom[i]); - - // Always keep ROMs write protected. - WriteProtectMemory(rom, size_in_bytes, false); - return true; - } - - PanicAlertT("Failed to load DSP ROM: %s", fname); - return false; -} - -// Returns false iff the hash fails and the user hits "Yes" -static bool VerifyRoms(const char *irom_filename, const char *coef_filename) -{ - static const u32 hash[] = { 0x66f334fe, 0xf3b93527 }; - static const int size[] = { DSP_IROM_BYTE_SIZE, DSP_COEF_BYTE_SIZE }; - const u16 *data[] = { g_dsp.irom, g_dsp.coef }; - - for (int i = 0; i < 2; i++) - { - if (HashAdler32((u8*)data[i], size[i]) != hash[i]) - { - if (AskYesNoT("%s has an incorrect hash.\n" - "Would you like to stop now to fix the problem?\n" - "If you select \"No\", audio will be garbled.", - (i == 0) ? irom_filename : coef_filename)) - return false; - } - } - - return true; -} - -bool DSPCore_Init(const char *irom_filename, const char *coef_filename, - bool bUsingJIT) -{ - g_dsp.step_counter = 0; - cyclesLeft = 0; - dspjit = NULL; - - g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); - g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); - g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); - g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); - - // Fill roms with zeros. - memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); - memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); - - // Try to load real ROM contents. - LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom); - LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef); - if (!VerifyRoms(irom_filename, coef_filename)) - return false; - - memset(&g_dsp.r,0,sizeof(g_dsp.r)); - - for (int i = 0; i < 4; i++) - { - g_dsp.reg_stack_ptr[i] = 0; - for (int j = 0; j < DSP_STACK_DEPTH; j++) - { - g_dsp.reg_stack[i][j] = 0; - } - } - - // Fill IRAM with HALT opcodes. - for (int i = 0; i < DSP_IRAM_SIZE; i++) - { - g_dsp.iram[i] = 0x0021; // HALT opcode - } - - // Just zero out DRAM. - for (int i = 0; i < DSP_DRAM_SIZE; i++) - { - g_dsp.dram[i] = 0; - } - - // Copied from a real console after the custom UCode has been loaded. - // These are the indexing wrapping registers. - g_dsp.r.wr[0] = 0xffff; - g_dsp.r.wr[1] = 0xffff; - g_dsp.r.wr[2] = 0xffff; - g_dsp.r.wr[3] = 0xffff; - - g_dsp.r.sr |= SR_INT_ENABLE; - g_dsp.r.sr |= SR_EXT_INT_ENABLE; - - g_dsp.cr = 0x804; - gdsp_ifx_init(); - // Mostly keep IRAM write protected. We unprotect only when DMA-ing - // in new ucodes. - WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - - // Initialize JIT, if necessary - if(bUsingJIT) - dspjit = new DSPEmitter(); - - DSPAnalyzer::Analyze(); - - step_event.Init(); - - core_state = DSPCORE_RUNNING; - - return true; -} - -void DSPCore_Shutdown() -{ - core_state = DSPCORE_STOP; - - if(dspjit) { - delete dspjit; - dspjit = NULL; - } - step_event.Shutdown(); - FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); - FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); - FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); - FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); -} - -void DSPCore_Reset() -{ - g_dsp.pc = DSP_RESET_VECTOR; - - g_dsp.r.wr[0] = 0xffff; - g_dsp.r.wr[1] = 0xffff; - g_dsp.r.wr[2] = 0xffff; - g_dsp.r.wr[3] = 0xffff; - -} - -void DSPCore_SetException(u8 level) -{ - g_dsp.exceptions |= 1 << level; -} - -// Notify that an external interrupt is pending (used by thread mode) -void DSPCore_SetExternalInterrupt(bool val) -{ - ExtIntCriticalSection.Enter(); - g_dsp.external_interrupt_waiting = val; - ExtIntCriticalSection.Leave(); -} - -// Coming from the CPU -void DSPCore_CheckExternalInterrupt() -{ - if (! dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) - return; - - // Signal the SPU about new mail - DSPCore_SetException(EXP_INT); - - g_dsp.cr &= ~CR_EXTERNAL_INT; -} - - -void DSPCore_CheckExceptions() -{ - // Early out to skip the loop in the common case. - if (g_dsp.exceptions == 0) - return; - - for (int i = 7; i > 0; i--) { - // Seems exp int are not masked by sr_int_enable - if (g_dsp.exceptions & (1 << i)) { - if (dsp_SR_is_flag_set(SR_INT_ENABLE) || (i == EXP_INT)) { - - // store pc and sr until RTI - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - dsp_reg_store_stack(DSP_STACK_D, g_dsp.r.sr); - - g_dsp.pc = i * 2; - g_dsp.exceptions &= ~(1 << i); - if (i == 7) - g_dsp.r.sr &= ~SR_EXT_INT_ENABLE; - else - g_dsp.r.sr &= ~SR_INT_ENABLE; - break; - } else { -#if defined(_DEBUG) || defined(DEBUGFAST) - ERROR_LOG(DSPLLE, "Firing exception %d failed", i); -#endif - } - } - } -} - -// Delegate to JIT or interpreter as appropriate. -// Handle state changes and stepping. -int DSPCore_RunCycles(int cycles) -{ - if (dspjit) - { - cyclesLeft = cycles; - CompiledCode pExecAddr = (CompiledCode)dspjit->enterDispatcher; - pExecAddr(); - - if (g_dsp.external_interrupt_waiting) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_CheckExceptions(); - DSPCore_SetExternalInterrupt(false); - } - - return cyclesLeft; - } - - while (cycles > 0) - { - reswitch: - switch (core_state) - { - case DSPCORE_RUNNING: - // Seems to slow things down -#if defined(_DEBUG) || defined(DEBUGFAST) - cycles = DSPInterpreter::RunCyclesDebug(cycles); -#else - cycles = DSPInterpreter::RunCycles(cycles); -#endif - break; - - case DSPCORE_STEPPING: - step_event.Wait(); - if (core_state != DSPCORE_STEPPING) - goto reswitch; - - DSPInterpreter::Step(); - cycles--; - - DSPHost_UpdateDebugger(); - break; - case DSPCORE_STOP: - break; - } - } - return cycles; -} - -void DSPCore_SetState(DSPCoreState new_state) -{ - core_state = new_state; - // kick the event, in case we are waiting - if (new_state == DSPCORE_RUNNING) - step_event.Set(); - // Sleep(10); - DSPHost_UpdateDebugger(); -} - -DSPCoreState DSPCore_GetState() -{ - return core_state; -} - -void DSPCore_Step() -{ - if (core_state == DSPCORE_STEPPING) - step_event.Set(); -} - -void CompileCurrent() -{ - dspjit->Compile(g_dsp.pc); - - bool retry = true; - - while (retry) - { - retry = false; - for(u16 i = 0x0000; i < 0xffff; ++i) - { - if (!dspjit->unresolvedJumps[i].empty()) - { - u16 addrToCompile = dspjit->unresolvedJumps[i].front(); - dspjit->Compile(addrToCompile); - if (!dspjit->unresolvedJumps[i].empty()) - retry = true; - } - } - } -} - -u16 DSPCore_ReadRegister(int reg) { - switch(reg) { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return g_dsp.r.st[reg - DSP_REG_ST0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: return g_dsp.r.cr; - case DSP_REG_SR: return g_dsp.r.sr; - case DSP_REG_PRODL: return g_dsp.r.prod.l; - case DSP_REG_PRODM: return g_dsp.r.prod.m; - case DSP_REG_PRODH: return g_dsp.r.prod.h; - case DSP_REG_PRODM2: return g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return g_dsp.r.ac[reg - DSP_REG_ACM0].m; - default: - _assert_msg_(DSP_CORE, 0, "cannot happen"); - return 0; - } -} - -void DSPCore_WriteRegister(int reg, u16 val) { - switch(reg) { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - g_dsp.r.ar[reg - DSP_REG_AR0] = val; - break; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - g_dsp.r.ix[reg - DSP_REG_IX0] = val; - break; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - g_dsp.r.wr[reg - DSP_REG_WR0] = val; - break; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - g_dsp.r.st[reg - DSP_REG_ST0] = val; - break; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - g_dsp.r.ac[reg - DSP_REG_ACH0].h = val; - break; - case DSP_REG_CR: g_dsp.r.cr = val; break; - case DSP_REG_SR: g_dsp.r.sr = val; break; - case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; - case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; - case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; - case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; - break; - } -} diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h deleted file mode 100644 index 2f69eb6ee6..0000000000 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ /dev/null @@ -1,306 +0,0 @@ -/*==================================================================== - - filename: DSPCore.h - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _DSPCORE_H -#define _DSPCORE_H - -#include "Thread.h" - -#include "DSPBreakpoints.h" -#include "DSPEmitter.h" - -#define DSP_IRAM_BYTE_SIZE 0x2000 -#define DSP_IRAM_SIZE 0x1000 -#define DSP_IRAM_MASK 0x0fff - -#define DSP_IROM_BYTE_SIZE 0x2000 -#define DSP_IROM_SIZE 0x1000 -#define DSP_IROM_MASK 0x0fff - -#define DSP_DRAM_BYTE_SIZE 0x2000 -#define DSP_DRAM_SIZE 0x1000 -#define DSP_DRAM_MASK 0x0fff - -#define DSP_COEF_BYTE_SIZE 0x1000 -#define DSP_COEF_SIZE 0x800 -#define DSP_COEF_MASK 0x7ff - -#define DSP_RESET_VECTOR 0x8000 - -#define DSP_STACK_DEPTH 0x20 -#define DSP_STACK_MASK 0x1f - -#define DSP_CR_IMEM 2 -#define DSP_CR_DMEM 0 -#define DSP_CR_TO_CPU 1 -#define DSP_CR_FROM_CPU 0 - - -// Register table taken from libasnd -#define DSP_REG_AR0 0x00 // address registers -#define DSP_REG_AR1 0x01 -#define DSP_REG_AR2 0x02 -#define DSP_REG_AR3 0x03 - -#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) -#define DSP_REG_IX1 0x05 -#define DSP_REG_IX2 0x06 -#define DSP_REG_IX3 0x07 - -#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. -#define DSP_REG_WR1 0x09 -#define DSP_REG_WR2 0x0a -#define DSP_REG_WR3 0x0b - -#define DSP_REG_ST0 0x0c // stacks. -#define DSP_REG_ST1 0x0d -#define DSP_REG_ST2 0x0e -#define DSP_REG_ST3 0x0f - -#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. -#define DSP_REG_SR 0x13 - -#define DSP_REG_PRODL 0x14 // product. -#define DSP_REG_PRODM 0x15 -#define DSP_REG_PRODH 0x16 -#define DSP_REG_PRODM2 0x17 - -#define DSP_REG_AXL0 0x18 -#define DSP_REG_AXL1 0x19 -#define DSP_REG_AXH0 0x1a -#define DSP_REG_AXH1 0x1b - -#define DSP_REG_ACC0 0x1c // accumulator (global) -#define DSP_REG_ACC1 0x1d - -#define DSP_REG_ACL0 0x1c // Low accumulator -#define DSP_REG_ACL1 0x1d -#define DSP_REG_ACM0 0x1e // Mid accumulator -#define DSP_REG_ACM1 0x1f -#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 -#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 - -// Hardware registers address - -#define DSP_COEF_A1_0 0xa0 - -#define DSP_DSCR 0xc9 // DSP DMA Control Reg -#define DSP_DSPA 0xcd // DSP DMA Address (DSP) -#define DSP_DSBL 0xcb // DSP DMA Block Length -#define DSP_DSMAH 0xce // DSP DMA Address High (External) -#define DSP_DSMAL 0xcf // DSP DMA Address Low (External) - -#define DSP_FORMAT 0xd1 // Sample format -#define DSP_ACUNK 0xd2 // Set to 3 on my dumps -#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes -#define DSP_ACSAH 0xd4 // Start of loop -#define DSP_ACSAL 0xd5 -#define DSP_ACEAH 0xd6 // End of sample (and loop) -#define DSP_ACEAL 0xd7 -#define DSP_ACCAH 0xd8 // Current playback position -#define DSP_ACCAL 0xd9 -#define DSP_PRED_SCALE 0xda // ADPCM predictor and scale -#define DSP_YN1 0xdb -#define DSP_YN2 0xdc -#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX. -#define DSP_GAIN 0xde -#define DSP_ACUNK2 0xdf // Set to 0xc on my dumps - -#define DSP_AMDM 0xef // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked - -#define DSP_DIRQ 0xfb // DSP Irq Rest -#define DSP_DMBH 0xfc // DSP Mailbox H -#define DSP_DMBL 0xfd // DSP Mailbox L -#define DSP_CMBH 0xfe // CPU Mailbox H -#define DSP_CMBL 0xff // CPU Mailbox L - -#define DMA_TO_DSP 0 -#define DMA_TO_CPU 1 - -// Stacks -#define DSP_STACK_C 0 -#define DSP_STACK_D 1 - -// cr (Not g_dsp.r[CR]) bits -// See HW/DSP.cpp. -#define CR_EXTERNAL_INT 0x0002 -#define CR_HALT 0x0004 -#define CR_INIT 0x0400 - - -// SR bits -#define SR_CARRY 0x0001 -#define SR_OVERFLOW 0x0002 -#define SR_ARITH_ZERO 0x0004 -#define SR_SIGN 0x0008 -#define SR_OVER_S32 0x0010 // set when there there was mod/tst/cmp on accu and result is over s32 -#define SR_TOP2BITS 0x0020 // if the upper (ac?.m/ax?.h) 2 bits are equal -#define SR_LOGIC_ZERO 0x0040 -#define SR_OVERFLOW_STICKY 0x0080 // set at the same time as 0x2 (under same conditions) - but not cleared the same -#define SR_100 0x0100 // unknown -#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. -#define SR_400 0x0400 // unknown -#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts -#define SR_1000 0x1000 // unknown -#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) -#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. -#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. - -// This should be the bits affected by CMP. Does not include logic zero. -#define SR_CMP_MASK 0x3f - -// exceptions vector -#define EXP_STOVF 1 // 0x0002 stack under/over flow -#define EXP_2 2 // 0x0004 -#define EXP_3 3 // 0x0006 -#define EXP_4 4 // 0x0008 -#define EXP_ACCOV 5 // 0x000a accelerator address overflow -#define EXP_6 6 // 0x000c -#define EXP_INT 7 // 0x000e external int (message from cpu) - -typedef struct { - u16 ar[4]; - u16 ix[4]; - u16 wr[4]; - u16 st[4]; - u16 cr; - u16 sr; - union { - u64 val; - struct { - u16 l; - u16 m; - u16 h; - u16 m2;//if this gets in the way, drop it. - }; - } prod; - union { - u32 val; - struct { - u16 l; - u16 h; - }; - } ax[2]; - union { - u64 val; - struct { - u16 l; - u16 m; - u16 h; - }; - } ac[2]; -} DSP_Regs; - -// All the state of the DSP should be in this struct. Any DSP state that is not filled on init -// should be moved here. -struct SDSP -{ - DSP_Regs r; - u16 pc; -#if PROFILE - u16 err_pc; -#endif - - // This is NOT the same cr as r.cr. - // This register is shared with the main emulation, see DSP.cpp - // The plugin has control over 0x0C07 of this reg. - // Bits are defined in a struct in DSP.cpp. - u16 cr; - - u8 reg_stack_ptr[4]; - u8 exceptions; // pending exceptions - bool external_interrupt_waiting; - - // DSP hardware stacks. They're mapped to a bunch of registers, such that writes - // to them push and reads pop. - // Let's make stack depth 32 for now, which is way more than what's needed. - // The real DSP has different depths for the different stacks, but it would - // be strange if any ucode relied on stack overflows since on the DSP, when - // the stack overflows, you're screwed. - u16 reg_stack[4][DSP_STACK_DEPTH]; - - // For debugging. - u32 iram_crc; - u64 step_counter; - - // Mailbox. - volatile u16 mbox[2][2]; - - // Mutex protecting the mailbox. - Common::CriticalSection g_CriticalSection; - - // Accelerator / DMA / other hardware registers. Not GPRs. - u16 ifx_regs[256]; - - // When state saving, all of the above can just be memcpy'd into the save state. - // The below needs special handling. - u16 *iram; - u16 *dram; - u16 *irom; - u16 *coef; - - // This one doesn't really belong here. - u8 *cpu_ram; -}; - -extern SDSP g_dsp; -extern DSPBreakpoints dsp_breakpoints; -extern DSPEmitter *dspjit; -extern u16 cyclesLeft; - -bool DSPCore_Init(const char *irom_filename, const char *coef_filename, - bool bUsingJIT); - -void DSPCore_Reset(); -void DSPCore_Shutdown(); // Frees all allocated memory. - -void DSPCore_CheckExternalInterrupt(); -void DSPCore_CheckExceptions(); -void DSPCore_SetExternalInterrupt(bool val); - -// sets a flag in the pending exception register. -void DSPCore_SetException(u8 level); - -void CompileCurrent(); - -enum DSPCoreState -{ - DSPCORE_STOP = 0, - DSPCORE_RUNNING, - DSPCORE_STEPPING, -}; - -int DSPCore_RunCycles(int cycles); - -// These are meant to be called from the UI thread. -void DSPCore_SetState(DSPCoreState new_state); -DSPCoreState DSPCore_GetState(); - -void DSPCore_Step(); - -u16 DSPCore_ReadRegister(int reg); -void DSPCore_WriteRegister(int reg, u16 val); - -#endif // _DSPCORE_H diff --git a/Source/Core/DSPCore/Src/DSPEmitter.cpp b/Source/Core/DSPCore/Src/DSPEmitter.cpp deleted file mode 100644 index e68fea7e18..0000000000 --- a/Source/Core/DSPCore/Src/DSPEmitter.cpp +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "DSPEmitter.h" -#include "DSPMemoryMap.h" -#include "DSPCore.h" -#include "DSPInterpreter.h" -#include "DSPAnalyzer.h" -#include "Jit/DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" - -#define MAX_BLOCK_SIZE 250 -#define DSP_IDLE_SKIP_CYCLES 0x1000 - -using namespace Gen; - -DSPEmitter::DSPEmitter() : gpr(*this), storeIndex(-1), storeIndex2(-1) -{ - m_compiledCode = NULL; - - AllocCodeSpace(COMPILED_CODE_SIZE); - - blocks = new CompiledCode[MAX_BLOCKS]; - blockLinks = new Block[MAX_BLOCKS]; - blockSize = new u16[MAX_BLOCKS]; - unresolvedJumps = new std::list[MAX_BLOCKS]; - - compileSR = 0; - compileSR |= SR_INT_ENABLE; - compileSR |= SR_EXT_INT_ENABLE; - - CompileDispatcher(); - stubEntryPoint = CompileStub(); - - //clear all of the block references - for(int i = 0x0000; i < MAX_BLOCKS; i++) - { - blocks[i] = (CompiledCode)stubEntryPoint; - blockLinks[i] = 0; - blockSize[i] = 0; - } -} - -DSPEmitter::~DSPEmitter() -{ - delete[] blocks; - delete[] blockLinks; - delete[] blockSize; - FreeCodeSpace(); -} - -void DSPEmitter::ClearIRAM() { - // ClearCodeSpace(); - for(int i = 0x0000; i < 0x1000; i++) - { - blocks[i] = (CompiledCode)stubEntryPoint; - blockLinks[i] = 0; - blockSize[i] = 0; - } -} - -// Must go out of block if exception is detected -void DSPEmitter::checkExceptions(u32 retval) -{ - // Check for interrupts and exceptions -#ifdef _M_IX86 // All32 - TEST(8, M(&g_dsp.exceptions), Imm8(0xff)); -#else - MOV(64, R(RAX), ImmPtr(&g_dsp.exceptions)); - TEST(8, MatR(RAX), Imm8(0xff)); -#endif - FixupBranch skipCheck = J_CC(CC_Z); - -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC)); -#endif - - DSPJitRegCache c(gpr); - SaveDSPRegs(); - ABI_CallFunction((void *)&DSPCore_CheckExceptions); - MOV(32, R(EAX), Imm32(retval)); - JMP(returnDispatcher, true); - gpr.flushRegs(c,false); - - SetJumpTarget(skipCheck); -} - -void DSPEmitter::Default(UDSPInstruction inst) -{ - if (opTable[inst]->reads_pc) - { - // Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block. - // Fallbacks to interpreter need this for fetching immediate values - -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif - } - - // Fall back to interpreter - SaveDSPRegs(); - ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst); - LoadDSPRegs(); -} - -void DSPEmitter::EmitInstruction(UDSPInstruction inst) -{ - const DSPOPCTemplate *tinst = GetOpTemplate(inst); - bool ext_is_jit = false; - - // Call extended - if (tinst->extended) { - if ((inst >> 12) == 0x3) { - if (! extOpTable[inst & 0x7F]->jitFunc) { - // Fall back to interpreter - SaveDSPRegs(); - ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); - LoadDSPRegs(); - INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); - ext_is_jit = false; - } else { - (this->*extOpTable[inst & 0x7F]->jitFunc)(inst); - ext_is_jit = true; - } - } else { - if (!extOpTable[inst & 0xFF]->jitFunc) { - // Fall back to interpreter - SaveDSPRegs(); - ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); - LoadDSPRegs(); - INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); - ext_is_jit = false; - } else { - (this->*extOpTable[inst & 0xFF]->jitFunc)(inst); - ext_is_jit = true; - } - } - } - - // Main instruction - if (!opTable[inst]->jitFunc) { - Default(inst); - INFO_LOG(DSPLLE, "Instruction not JITed(main part): %04x\n", inst); - } - else - { - (this->*opTable[inst]->jitFunc)(inst); - } - - // Backlog - if (tinst->extended) { - if (!ext_is_jit) { - //need to call the online cleanup function because - //the writeBackLog gets populated at runtime - SaveDSPRegs(); - ABI_CallFunction((void*)::applyWriteBackLog); - LoadDSPRegs(); - } else { - popExtValueToReg(); - } - } -} - -void DSPEmitter::unknown_instruction(UDSPInstruction inst) -{ - PanicAlert("unknown_instruction %04x - Fix me ;)", inst); -} - -void DSPEmitter::Compile(u16 start_addr) -{ - // Remember the current block address for later - startAddr = start_addr; - unresolvedJumps[start_addr].clear(); - - const u8 *entryPoint = AlignCode16(); - - /* - // Check for other exceptions - if (dsp_SR_is_flag_set(SR_INT_ENABLE)) - return; - - if (g_dsp.exceptions == 0) - return; - */ - - LoadDSPRegs(); - - blockLinkEntry = GetCodePtr(); - - compilePC = start_addr; - bool fixup_pc = false; - blockSize[start_addr] = 0; - - while (compilePC < start_addr + MAX_BLOCK_SIZE) - { - if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT) - checkExceptions(blockSize[start_addr]); - - UDSPInstruction inst = dsp_imem_read(compilePC); - const DSPOPCTemplate *opcode = GetOpTemplate(inst); - - EmitInstruction(inst); - - blockSize[start_addr]++; - compilePC += opcode->size; - - // If the block was trying to link into itself, remove the link - unresolvedJumps[start_addr].remove(compilePC); - - fixup_pc = true; - - // Handle loop condition, only if current instruction was flagged as a loop destination - // by the analyzer. - if (DSPAnalyzer::code_flags[compilePC-1] & DSPAnalyzer::CODE_LOOP_END) - { -#ifdef _M_IX86 // All32 - MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2]))); -#else - MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[2]))); -#endif - CMP(32, R(EAX), Imm32(0)); - FixupBranch rLoopAddressExit = J_CC(CC_LE, true); - -#ifdef _M_IX86 // All32 - MOVZX(32, 16, EAX, M(&g_dsp.r.st[3])); -#else - MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3]))); -#endif - CMP(32, R(EAX), Imm32(0)); - FixupBranch rLoopCounterExit = J_CC(CC_LE, true); - - if (!opcode->branch) - { - //branch insns update the g_dsp.pc -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC)); -#endif - } - - // These functions branch and therefore only need to be called in the - // end of each block and in this order - DSPJitRegCache c(gpr); - HandleLoop(); - SaveDSPRegs(); - if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); - gpr.flushRegs(c,false); - - SetJumpTarget(rLoopAddressExit); - SetJumpTarget(rLoopCounterExit); - } - - if (opcode->branch) - { - //don't update g_dsp.pc -- the branch insn already did - fixup_pc = false; - if (opcode->uncond_branch) - { - break; - } - else if (!opcode->jitFunc) - { - //look at g_dsp.pc if we actually branched -#ifdef _M_IX86 // All32 - MOV(16, R(AX), M(&g_dsp.pc)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, R(AX), MatR(RAX)); -#endif - CMP(16, R(AX), Imm16(compilePC)); - FixupBranch rNoBranch = J_CC(CC_Z); - - DSPJitRegCache c(gpr); - //don't update g_dsp.pc -- the branch insn already did - SaveDSPRegs(); - if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); - gpr.flushRegs(c,false); - - SetJumpTarget(rNoBranch); - } - } - - // End the block if we're before an idle skip address - if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP) - { - break; - } - } - - if (fixup_pc) { -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC)); -#endif - } - - blocks[start_addr] = (CompiledCode)entryPoint; - - // Mark this block as a linkable destination if it does not contain - // any unresolved CALL's - if (unresolvedJumps[start_addr].empty()) - { - blockLinks[start_addr] = blockLinkEntry; - - for(u16 i = 0x0000; i < 0xffff; ++i) - { - if (!unresolvedJumps[i].empty()) - { - // Check if there were any blocks waiting for this block to be linkable - unsigned int size = unresolvedJumps[i].size(); - unresolvedJumps[i].remove(start_addr); - if (unresolvedJumps[i].size() < size) - { - // Mark the block to be recompiled again - blocks[i] = (CompiledCode)stubEntryPoint; - blockLinks[i] = 0; - blockSize[i] = 0; - } - } - } - } - - if (blockSize[start_addr] == 0) - { - // just a safeguard, should never happen anymore. - // if it does we might get stuck over in RunForCycles. - ERROR_LOG(DSPLLE, "Block at 0x%04x has zero size", start_addr); - blockSize[start_addr] = 1; - } - - SaveDSPRegs(); - if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); -} - -const u8 *DSPEmitter::CompileStub() -{ - const u8 *entryPoint = AlignCode16(); - ABI_CallFunction((void *)&CompileCurrent); - //MOVZX(32, 16, ECX, M(&g_dsp.pc)); - XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed - JMP(returnDispatcher); - return entryPoint; -} - -void DSPEmitter::CompileDispatcher() -{ - enterDispatcher = AlignCode16(); - ABI_PushAllCalleeSavedRegsAndAdjustStack(); - - const u8 *dispatcherLoop = GetCodePtr(); - - // Check for DSP halt -#ifdef _M_IX86 - TEST(8, M(&g_dsp.cr), Imm8(CR_HALT)); -#else - MOV(64, R(RAX), ImmPtr(&g_dsp.cr)); - TEST(8, MatR(RAX), Imm8(CR_HALT)); -#endif - FixupBranch _halt = J_CC(CC_NE); - -#ifdef _M_IX86 - MOVZX(32, 16, ECX, M(&g_dsp.pc)); -#else - MOV(64, R(RCX), ImmPtr(&g_dsp.pc)); - MOVZX(64, 16, RCX, MatR(RCX)); -#endif - - // Execute block. Cycles executed returned in EAX. -#ifdef _M_IX86 - MOV(32, R(EBX), ImmPtr(blocks)); - JMPptr(MComplex(EBX, ECX, SCALE_4, 0)); -#else - MOV(64, R(RBX), ImmPtr(blocks)); - JMPptr(MComplex(RBX, RCX, SCALE_8, 0)); -#endif - - returnDispatcher = GetCodePtr(); - - // Decrement cyclesLeft -#ifdef _M_IX86 - SUB(16, M(&cyclesLeft), R(EAX)); -#else - MOV(64, R(R12), ImmPtr(&cyclesLeft)); - SUB(16, MatR(R12), R(EAX)); -#endif - - J_CC(CC_A, dispatcherLoop); - - // DSP gave up the remaining cycles. - SetJumpTarget(_halt); - //MOV(32, M(&cyclesLeft), Imm32(0)); - ABI_PopAllCalleeSavedRegsAndAdjustStack(); - RET(); -} diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h deleted file mode 100644 index 17f1850001..0000000000 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSPEMITTER_H -#define _DSPEMITTER_H - -#include - -#include "DSPCommon.h" -#include "x64Emitter.h" -#include "Jit/DSPJitRegCache.h" - -#define COMPILED_CODE_SIZE sizeof(void *) * 0x200000 - -#define MAX_BLOCKS 0x10000 - -typedef u32 (*CompiledCode)(); -typedef const u8 *Block; - -class DSPEmitter : public Gen::XCodeBlock, NonCopyable -{ -public: - DSPEmitter(); - ~DSPEmitter(); - - Block m_compiledCode; - - void EmitInstruction(UDSPInstruction inst); - void unknown_instruction(UDSPInstruction inst); - void ClearIRAM(); - - void CompileDispatcher(); - Block CompileStub(); - void Compile(u16 start_addr); - void ClearCallFlag(); - - void Default(UDSPInstruction inst); - - // CC Util - void Update_SR_Register64(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register64_Carry(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register64_Carry2(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register16(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register16_OverS32(Gen::X64Reg val = Gen::EAX); - - // Register helpers - void setCompileSR(u16 bit); - void clrCompileSR(u16 bit); - void checkExceptions(u32 retval); - - // Memory helper functions - void increment_addr_reg(int reg); - void decrement_addr_reg(int reg); - void increase_addr_reg(int reg); - void decrease_addr_reg(int reg); - void imem_read(); - void dmem_read(); - void dmem_read_imm(u16 addr); - void dmem_write(); - void dmem_write_imm(u16 addr); - - // Ext command helpers - void pushExtValueFromReg(u16 dreg, u16 sreg); - void popExtValueToReg(); - void pushExtValueFromMem(u16 dreg, u16 sreg); - void pushExtValueFromMem2(u16 dreg, u16 sreg); - void zeroWriteBackLog(const UDSPInstruction opc); - - // Ext commands - void l(const UDSPInstruction opc); - void ln(const UDSPInstruction opc); - void ls(const UDSPInstruction opc); - void lsn(const UDSPInstruction opc); - void lsm(const UDSPInstruction opc); - void lsnm(const UDSPInstruction opc); - void sl(const UDSPInstruction opc); - void sln(const UDSPInstruction opc); - void slm(const UDSPInstruction opc); - void slnm(const UDSPInstruction opc); - void s(const UDSPInstruction opc); - void sn(const UDSPInstruction opc); - void ld(const UDSPInstruction opc); - void ldn(const UDSPInstruction opc); - void ldm(const UDSPInstruction opc); - void ldnm(const UDSPInstruction opc); - void mv(const UDSPInstruction opc); - void dr(const UDSPInstruction opc); - void ir(const UDSPInstruction opc); - void nr(const UDSPInstruction opc); - void nop(const UDSPInstruction opc) {} - - // Command helpers - void dsp_reg_stack_push(int stack_reg); - void dsp_reg_stack_pop(int stack_reg); - void dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg = Gen::EDX); - void dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg = Gen::EDX); - void dsp_reg_store_stack_imm(int stack_reg, u16 val); - void dsp_op_write_reg(int reg, Gen::X64Reg host_sreg); - void dsp_op_write_reg_imm(int reg, u16 val); - void dsp_conditional_extend_accum(int reg); - void dsp_conditional_extend_accum_imm(int reg, u16 val); - void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE); - - // Commands - void dar(const UDSPInstruction opc); - void iar(const UDSPInstruction opc); - void subarn(const UDSPInstruction opc); - void addarn(const UDSPInstruction opc); - void sbclr(const UDSPInstruction opc); - void sbset(const UDSPInstruction opc); - void srbith(const UDSPInstruction opc); - void lri(const UDSPInstruction opc); - void lris(const UDSPInstruction opc); - void mrr(const UDSPInstruction opc); - void nx(const UDSPInstruction opc); - - // Branch - void HandleLoop(); - void jcc(const UDSPInstruction opc); - void jmprcc(const UDSPInstruction opc); - void call(const UDSPInstruction opc); - void callr(const UDSPInstruction opc); - void ifcc(const UDSPInstruction opc); - void ret(const UDSPInstruction opc); - void rti(const UDSPInstruction opc); - void halt(const UDSPInstruction opc); - void loop(const UDSPInstruction opc); - void loopi(const UDSPInstruction opc); - void bloop(const UDSPInstruction opc); - void bloopi(const UDSPInstruction opc); - - // Load/Store - void srs(const UDSPInstruction opc); - void lrs(const UDSPInstruction opc); - void lr(const UDSPInstruction opc); - void sr(const UDSPInstruction opc); - void si(const UDSPInstruction opc); - void lrr(const UDSPInstruction opc); - void lrrd(const UDSPInstruction opc); - void lrri(const UDSPInstruction opc); - void lrrn(const UDSPInstruction opc); - void srr(const UDSPInstruction opc); - void srrd(const UDSPInstruction opc); - void srri(const UDSPInstruction opc); - void srrn(const UDSPInstruction opc); - void ilrr(const UDSPInstruction opc); - void ilrrd(const UDSPInstruction opc); - void ilrri(const UDSPInstruction opc); - void ilrrn(const UDSPInstruction opc); - - // Arithmetic - void clr(const UDSPInstruction opc); - void clrl(const UDSPInstruction opc); - void andcf(const UDSPInstruction opc); - void andf(const UDSPInstruction opc); - void tst(const UDSPInstruction opc); - void tstaxh(const UDSPInstruction opc); - void cmp(const UDSPInstruction opc); - void cmpar(const UDSPInstruction opc); - void cmpi(const UDSPInstruction opc); - void cmpis(const UDSPInstruction opc); - void xorr(const UDSPInstruction opc); - void andr(const UDSPInstruction opc); - void orr(const UDSPInstruction opc); - void andc(const UDSPInstruction opc); - void orc(const UDSPInstruction opc); - void xorc(const UDSPInstruction opc); - void notc(const UDSPInstruction opc); - void xori(const UDSPInstruction opc); - void andi(const UDSPInstruction opc); - void ori(const UDSPInstruction opc); - void addr(const UDSPInstruction opc); - void addax(const UDSPInstruction opc); - void add(const UDSPInstruction opc); - void addp(const UDSPInstruction opc); - void addaxl(const UDSPInstruction opc); - void addi(const UDSPInstruction opc); - void addis(const UDSPInstruction opc); - void incm(const UDSPInstruction opc); - void inc(const UDSPInstruction opc); - void subr(const UDSPInstruction opc); - void subax(const UDSPInstruction opc); - void sub(const UDSPInstruction opc); - void subp(const UDSPInstruction opc); - void decm(const UDSPInstruction opc); - void dec(const UDSPInstruction opc); - void neg(const UDSPInstruction opc); - void abs(const UDSPInstruction opc); - void movr(const UDSPInstruction opc); - void movax(const UDSPInstruction opc); - void mov(const UDSPInstruction opc); - void lsl16(const UDSPInstruction opc); - void lsr16(const UDSPInstruction opc); - void asr16(const UDSPInstruction opc); - void lsl(const UDSPInstruction opc); - void lsr(const UDSPInstruction opc); - void asl(const UDSPInstruction opc); - void asr(const UDSPInstruction opc); - void lsrn(const UDSPInstruction opc); - void asrn(const UDSPInstruction opc); - void lsrnrx(const UDSPInstruction opc); - void asrnrx(const UDSPInstruction opc); - void lsrnr(const UDSPInstruction opc); - void asrnr(const UDSPInstruction opc); - - // Multipliers - void multiply(); - void multiply_add(); - void multiply_sub(); - void multiply_mulx(u8 axh0, u8 axh1); - void clrp(const UDSPInstruction opc); - void tstprod(const UDSPInstruction opc); - void movp(const UDSPInstruction opc); - void movnp(const UDSPInstruction opc); - void movpz(const UDSPInstruction opc); - void addpaxz(const UDSPInstruction opc); - void mulaxh(const UDSPInstruction opc); - void mul(const UDSPInstruction opc); - void mulac(const UDSPInstruction opc); - void mulmv(const UDSPInstruction opc); - void mulmvz(const UDSPInstruction opc); - void mulx(const UDSPInstruction opc); - void mulxac(const UDSPInstruction opc); - void mulxmv(const UDSPInstruction opc); - void mulxmvz(const UDSPInstruction opc); - void mulc(const UDSPInstruction opc); - void mulcac(const UDSPInstruction opc); - void mulcmv(const UDSPInstruction opc); - void mulcmvz(const UDSPInstruction opc); - void maddx(const UDSPInstruction opc); - void msubx(const UDSPInstruction opc); - void maddc(const UDSPInstruction opc); - void msubc(const UDSPInstruction opc); - void madd(const UDSPInstruction opc); - void msub(const UDSPInstruction opc); - - // CALL this to start the dispatcher - const u8 *enterDispatcher; - const u8 *stubEntryPoint; - const u8 *returnDispatcher; - u16 compilePC; - u16 startAddr; - Block *blockLinks; - u16 *blockSize; - std::list *unresolvedJumps; - - DSPJitRegCache gpr; - - void LoadDSPRegs(); - void SaveDSPRegs(); - -private: - CompiledCode *blocks; - Block blockLinkEntry; - u16 compileSR; - - // The index of the last stored ext value (compile time). - int storeIndex; - int storeIndex2; - - // Counts down. - // int cycles; - - - void Update_SR_Register(Gen::X64Reg val = Gen::EAX); - - void ToMask(Gen::X64Reg value_reg = Gen::EDI); - void dsp_increment_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI); - void dsp_decrement_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI); - void get_long_prod(Gen::X64Reg long_prod = Gen::RAX); - void get_long_prod_round_prodl(Gen::X64Reg long_prod = Gen::RAX); - void set_long_prod(); - void round_long_acc(Gen::X64Reg long_acc = Gen::EAX); - void set_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); - void get_acc_h(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_h(int _reg, Gen::OpArg arg = R(Gen::EAX)); - void get_acc_m(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_m(int _reg, Gen::OpArg arg = R(Gen::EAX)); - void get_acc_l(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_l(int _reg, Gen::OpArg arg = R(Gen::EAX)); - void get_long_acx(int _reg, Gen::X64Reg acx = Gen::EAX); - void get_ax_l(int _reg, Gen::X64Reg acx = Gen::EAX); - void get_ax_h(int _reg, Gen::X64Reg acc = Gen::EAX); - void get_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); -}; - - -#endif // _DSPEMITTER_H - diff --git a/Source/Core/DSPCore/Src/DSPHWInterface.cpp b/Source/Core/DSPCore/Src/DSPHWInterface.cpp deleted file mode 100644 index a2862affe3..0000000000 --- a/Source/Core/DSPCore/Src/DSPHWInterface.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/*==================================================================== - - filename: gdsp_interface.h - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include "Thread.h" -#include "MemoryUtil.h" - -#include "DSPCore.h" -#include "DSPHost.h" -#include "DSPTables.h" -#include "DSPAnalyzer.h" -#include "DSPAccelerator.h" -#include "DSPInterpreter.h" -#include "DSPHWInterface.h" -#include "CPUDetect.h" - -#if _M_SSE >= 0x301 && !(defined __GNUC__ && !defined __SSSE3__) -#include -#endif - -void gdsp_do_dma(); - -Common::CriticalSection g_CriticalSection; - -void gdsp_ifx_init() -{ - for (int i = 0; i < 256; i++) - { - g_dsp.ifx_regs[i] = 0; - } - - g_dsp.mbox[0][0] = 0; - g_dsp.mbox[0][1] = 0; - g_dsp.mbox[1][0] = 0; - g_dsp.mbox[1][1] = 0; -} - - -u32 gdsp_mbox_peek(u8 mbx) -{ - if (DSPHost_OnThread()) - g_CriticalSection.Enter(); - u32 value = ((g_dsp.mbox[mbx][0] << 16) | g_dsp.mbox[mbx][1]); - if (DSPHost_OnThread()) - g_CriticalSection.Leave(); - return value; -} - -void gdsp_mbox_write_h(u8 mbx, u16 val) -{ - if (DSPHost_OnThread()) - g_CriticalSection.Enter(); - g_dsp.mbox[mbx][0] = val & 0x7fff; - if (DSPHost_OnThread()) - g_CriticalSection.Leave(); -} - - -void gdsp_mbox_write_l(u8 mbx, u16 val) -{ - if (DSPHost_OnThread()) - g_CriticalSection.Enter(); - g_dsp.mbox[mbx][1] = val; - g_dsp.mbox[mbx][0] |= 0x8000; - if (DSPHost_OnThread()) - g_CriticalSection.Leave(); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (mbx == GDSP_MBOX_DSP) - { - NOTICE_LOG(DSP_MAIL, "DSP(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_DSP), g_dsp.pc); - } else { - NOTICE_LOG(DSP_MAIL, "CPU(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_CPU), g_dsp.pc); - } -#endif -} - - -u16 gdsp_mbox_read_h(u8 mbx) -{ - return g_dsp.mbox[mbx][0]; // TODO: mask away the top bit? -} - - -u16 gdsp_mbox_read_l(u8 mbx) -{ - if (DSPHost_OnThread()) - g_CriticalSection.Enter(); - - u16 val = g_dsp.mbox[mbx][1]; - g_dsp.mbox[mbx][0] &= ~0x8000; - - - if (DSPHost_OnThread()) - g_CriticalSection.Leave(); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (mbx == GDSP_MBOX_DSP) - { - NOTICE_LOG(DSP_MAIL, "DSP(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_DSP), g_dsp.pc); - } else { - NOTICE_LOG(DSP_MAIL, "CPU(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_CPU), g_dsp.pc); - } -#endif - - return val; -} - - -void gdsp_ifx_write(u32 addr, u32 val) -{ - switch (addr & 0xff) - { - case DSP_DIRQ: - if (val & 0x1) - DSPHost_InterruptRequest(); - else - INFO_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); - break; - - case DSP_DMBH: - gdsp_mbox_write_h(GDSP_MBOX_DSP, val); - break; - - case DSP_DMBL: - gdsp_mbox_write_l(GDSP_MBOX_DSP, val); - break; - - case DSP_CMBH: - return gdsp_mbox_write_h(GDSP_MBOX_CPU, val); - - case DSP_CMBL: - return gdsp_mbox_write_l(GDSP_MBOX_CPU, val); - - case DSP_DSBL: - g_dsp.ifx_regs[DSP_DSBL] = val; - g_dsp.ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly - if (!g_dsp.ifx_regs[DSP_AMDM]) - gdsp_do_dma(); - else - NOTICE_LOG(DSPLLE, "Masked DMA skipped"); - g_dsp.ifx_regs[DSP_DSCR] &= ~4; - g_dsp.ifx_regs[DSP_DSBL] = 0; - break; - - case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda" - dsp_write_aram_d3(val); - break; - - case DSP_GAIN: - if (val) { - INFO_LOG(DSPLLE,"Gain Written: 0x%04x", val); - } - case DSP_DSPA: - case DSP_DSMAH: - case DSP_DSMAL: - case DSP_DSCR: - g_dsp.ifx_regs[addr & 0xFF] = val; - break; -/* - case DSP_ACCAL: - dsp_step_accelerator(); - break; -*/ - default: - if ((addr & 0xff) >= 0xa0) { - if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) { - INFO_LOG(DSPLLE, "%04x MW %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, val); - } - else { - ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); - } - } - else { - ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); - } - g_dsp.ifx_regs[addr & 0xFF] = val; - break; - } -} - -u16 gdsp_ifx_read(u16 addr) -{ - switch (addr & 0xff) - { - case DSP_DMBH: - return gdsp_mbox_read_h(GDSP_MBOX_DSP); - - case DSP_DMBL: - return gdsp_mbox_read_l(GDSP_MBOX_DSP); - - case DSP_CMBH: - return gdsp_mbox_read_h(GDSP_MBOX_CPU); - - case DSP_CMBL: - return gdsp_mbox_read_l(GDSP_MBOX_CPU); - - case DSP_DSCR: - return g_dsp.ifx_regs[addr & 0xFF]; - - case DSP_ACCELERATOR: // ADPCM Accelerator reads - return dsp_read_accelerator(); - - case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda" - return dsp_read_aram_d3(); - - default: - if ((addr & 0xff) >= 0xa0) { - if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) { - INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, g_dsp.ifx_regs[addr & 0xFF]); - } - else { - ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); - } - } - else { - ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); - } - return g_dsp.ifx_regs[addr & 0xFF]; - } -} - -void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) -{ - UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - - u8* dst = ((u8*)g_dsp.iram); - for (u32 i = 0; i < size; i += 2) - { - // TODO : this may be different on Wii. - *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); - } - WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - - g_dsp.iram_crc = DSPHost_CodeLoaded(g_dsp.cpu_ram + (addr & 0x0fffffff), size); - - NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); - - if (dspjit) - dspjit->ClearIRAM(); - - DSPAnalyzer::Analyze(); -} - - -void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size) -{ - ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); -} - -static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405L, 0x02030001L); - -// TODO: These should eat clock cycles. -void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) -{ - u8* dst = ((u8*)g_dsp.dram); - -#if _M_SSE >= 0x301 - if (cpu_info.bSSSE3 && !(size % 16)) - { - for (u32 i = 0; i < size; i += 16) - { - _mm_storeu_si128((__m128i *)&dst[dsp_addr + i], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]), s_mask)); - } - } - else -#endif - { - for (u32 i = 0; i < size; i += 2) - { - *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]); - } - } - INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)", addr, dsp_addr / 2, size); -} - - -void gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) -{ - const u8* src = ((const u8*)g_dsp.dram); - -#if _M_SSE >= 0x301 - if (cpu_info.bSSSE3 && !(size % 16)) - { - for (u32 i = 0; i < size; i += 16) - { - _mm_storeu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&src[dsp_addr + i]), s_mask)); - } - } - else -#endif - { - for (u32 i = 0; i < size; i += 2) - { - *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF] = Common::swap16(*(const u16*)&src[dsp_addr + i]); - } - } - - INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); -} - -void gdsp_do_dma() -{ - u16 ctl; - u32 addr; - u16 dsp_addr; - u16 len; - - addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL]; - ctl = g_dsp.ifx_regs[DSP_DSCR]; - dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2; - len = g_dsp.ifx_regs[DSP_DSBL]; - - if (len > 0x4000) - { - ERROR_LOG(DSPLLE, "DMA ERROR pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); - exit(0); - } -#if defined(_DEBUG) || defined(DEBUGFAST) - DEBUG_LOG(DSPLLE, "DMA pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); -#endif - switch (ctl & 0x3) - { - case (DSP_CR_DMEM | DSP_CR_TO_CPU): - gdsp_ddma_out(dsp_addr, addr, len); - break; - - case (DSP_CR_DMEM | DSP_CR_FROM_CPU): - gdsp_ddma_in(dsp_addr, addr, len); - break; - - case (DSP_CR_IMEM | DSP_CR_TO_CPU): - gdsp_idma_out(dsp_addr, addr, len); - break; - - case (DSP_CR_IMEM | DSP_CR_FROM_CPU): - gdsp_idma_in(dsp_addr, addr, len); - break; - } -} diff --git a/Source/Core/DSPCore/Src/DSPHWInterface.h b/Source/Core/DSPCore/Src/DSPHWInterface.h deleted file mode 100644 index df83f61e4b..0000000000 --- a/Source/Core/DSPCore/Src/DSPHWInterface.h +++ /dev/null @@ -1,47 +0,0 @@ -/*==================================================================== - - filename: gdsp_interface.h - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _GDSP_INTERFACE_H -#define _GDSP_INTERFACE_H - -#include "Common.h" - -#define GDSP_MBOX_CPU 0 -#define GDSP_MBOX_DSP 1 - -u32 gdsp_mbox_peek(u8 mbx); -void gdsp_mbox_write_h(u8 mbx, u16 val); -void gdsp_mbox_write_l(u8 mbx, u16 val); -u16 gdsp_mbox_read_h(u8 mbx); -u16 gdsp_mbox_read_l(u8 mbx); - -void gdsp_ifx_init(); - -void gdsp_ifx_write(u32 addr, u32 val); -u16 gdsp_ifx_read(u16 addr); - -void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size); - -#endif diff --git a/Source/Core/DSPCore/Src/DSPHost.h b/Source/Core/DSPCore/Src/DSPHost.h deleted file mode 100644 index b3361f50e1..0000000000 --- a/Source/Core/DSPCore/Src/DSPHost.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSPHOST_H -#define _DSPHOST_H - -// The user of the DSPCore library must supply a few functions so that the -// emulation core can access the environment it runs in. If the emulation -// core isn't used, for example in an asm/disasm tool, then most of these -// can be stubbed out. - -u8 DSPHost_ReadHostMemory(u32 addr); -void DSPHost_WriteHostMemory(u8 value, u32 addr); -bool DSPHost_OnThread(); -bool DSPHost_Running(); -void DSPHost_InterruptRequest(); -u32 DSPHost_CodeLoaded(const u8 *ptr, int size); -void DSPHost_UpdateDebugger(); - -#endif diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp deleted file mode 100644 index 644ce60663..0000000000 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - - -// HELPER FUNCTIONS - -#include "DSPIntCCUtil.h" -#include "DSPCore.h" -#include "DSPInterpreter.h" - -namespace DSPInterpreter { - -void Update_SR_Register64(s64 _Value, bool carry, bool overflow) -{ - g_dsp.r.sr &= ~SR_CMP_MASK; - - // 0x01 - if (carry) - { - g_dsp.r.sr |= SR_CARRY; - } - - // 0x02 and 0x80 - if (overflow) - { - g_dsp.r.sr |= SR_OVERFLOW; - g_dsp.r.sr |= SR_OVERFLOW_STICKY; - } - - // 0x04 - if (_Value == 0) - { - g_dsp.r.sr |= SR_ARITH_ZERO; - } - - // 0x08 - if (_Value < 0) - { - g_dsp.r.sr |= SR_SIGN; - } - - // 0x10 - if (_Value != (s32)_Value) - { - g_dsp.r.sr |= SR_OVER_S32; - } - - // 0x20 - Checks if top bits of m are equal - if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) - { - g_dsp.r.sr |= SR_TOP2BITS; - } -} - - -void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) -{ - g_dsp.r.sr &= ~SR_CMP_MASK; - - // 0x01 - if (carry) - { - g_dsp.r.sr |= SR_CARRY; - } - - // 0x02 and 0x80 - if (overflow) - { - g_dsp.r.sr |= SR_OVERFLOW; - g_dsp.r.sr |= SR_OVERFLOW_STICKY; - } - - // 0x04 - if (_Value == 0) - { - g_dsp.r.sr |= SR_ARITH_ZERO; - } - - // 0x08 - if (_Value < 0) - { - g_dsp.r.sr |= SR_SIGN; - } - - // 0x10 - if (overS32) - { - g_dsp.r.sr |= SR_OVER_S32; - } - - // 0x20 - Checks if top bits of m are equal - if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - { - g_dsp.r.sr |= SR_TOP2BITS; - } -} - -void Update_SR_LZ(bool value) -{ - if (value == true) - g_dsp.r.sr |= SR_LOGIC_ZERO; - else - g_dsp.r.sr &= ~SR_LOGIC_ZERO; -} - -inline int GetMultiplyModifier() -{ - return (g_dsp.r.sr & SR_MUL_MODIFY)?1:2; -} - -inline bool isCarry() { - return (g_dsp.r.sr & SR_CARRY) ? true : false; -} - -inline bool isOverflow() { - return (g_dsp.r.sr & SR_OVERFLOW) ? true : false; -} - -inline bool isOverS32() { - return (g_dsp.r.sr & SR_OVER_S32) ? true : false; -} - -inline bool isLess() { - return (!(g_dsp.r.sr & SR_OVERFLOW) != !(g_dsp.r.sr & SR_SIGN)); -} - -inline bool isZero() { - return (g_dsp.r.sr & SR_ARITH_ZERO) ? true : false; -} - -inline bool isLogicZero() { - return (g_dsp.r.sr & SR_LOGIC_ZERO) ? true : false; -} - -inline bool isConditionA() { - return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) && !(g_dsp.r.sr & SR_ARITH_ZERO)) ? true : false; -} - -//see DSPCore.h for flags -bool CheckCondition(u8 _Condition) -{ - switch (_Condition & 0xf) - { - case 0xf: // Always true. - return true; - case 0x0: // GE - Greater Equal - return !isLess(); - case 0x1: // L - Less - return isLess(); - case 0x2: // G - Greater - return !isLess() && !isZero(); - case 0x3: // LE - Less Equal - return isLess() || isZero(); - case 0x4: // NZ - Not Zero - return !isZero(); - case 0x5: // Z - Zero - return isZero(); - case 0x6: // NC - Not carry - return !isCarry(); - case 0x7: // C - Carry - return isCarry(); - case 0x8: // ? - Not over s32 - return !isOverS32(); - case 0x9: // ? - Over s32 - return isOverS32(); - case 0xa: // ? - return isConditionA(); - case 0xb: // ? - return !isConditionA(); - case 0xc: // LNZ - Logic Not Zero - return !isLogicZero(); - case 0xd: // LZ - Logic Zero - return isLogicZero(); - case 0xe: // 0 - Overflow - return isOverflow(); - default: - return true; - } -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.h b/Source/Core/DSPCore/Src/DSPIntCCUtil.h deleted file mode 100644 index 0684cea2ba..0000000000 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#ifndef _GDSP_CONDITION_CODES_H -#define _GDSP_CONDITION_CODES_H - -// Anything to do with SR and conditions goes here. - -#include "Common.h" - -namespace DSPInterpreter { - -bool CheckCondition(u8 _Condition); - -int GetMultiplyModifier(); - -void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, bool overS32 = false); -void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false); -void Update_SR_LZ(bool value); - -inline bool isCarry(u64 val, u64 result) { - return (val>result); -} - -inline bool isCarry2(u64 val, u64 result) { - return (val>=result); -} - -inline bool isOverflow(s64 val1, s64 val2, s64 res) { - return ((val1 ^ res) & (val2 ^ res)) < 0; -} - -inline bool isOverS32(s64 acc) { - return (acc != (s32)acc) ? true : false; -} - -} // namespace - -#endif // _GDSP_CONDITION_CODES_H diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp deleted file mode 100644 index 11eca9abac..0000000000 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ -#include "DSPIntUtil.h" -#include "DSPMemoryMap.h" -#include "DSPIntExtOps.h" - -// Extended opcodes do not exist on their own. These opcodes can only be -// attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by -// opcode). Extended opcodes do not modify program counter $pc register. - -// Most of the suffixes increment or decrement one or more addressing registers -// (the first four, ARx). The increment/decrement is either 1, or the -// corresponding "index" register (the second four, IXx). The addressing -// registers will wrap in odd ways, dictated by the corresponding wrapping -// register, WR0-3. - -// Needs comments. -inline static void writeToBackLog(int i, int idx, u16 value) -{ - writeBackLog[i] = value; - writeBackLogIdx[i] = idx; -} - -namespace DSPInterpreter -{ - -namespace Ext -{ - -inline bool IsSameMemArea(u16 a, u16 b) -{ -//LM: tested on WII - if ((a>>10)==(b>>10)) - return true; - else - return false; -} - -// DR $arR -// xxxx xxxx 0000 01rr -// Decrement addressing register $arR. -void dr(const UDSPInstruction opc) { - writeToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3)); -} - -// IR $arR -// xxxx xxxx 0000 10rr -// Increment addressing register $arR. -void ir(const UDSPInstruction opc) { - writeToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3)); -} - -// NR $arR -// xxxx xxxx 0000 11rr -// Add corresponding indexing register $ixR to addressing register $arR. -void nr(const UDSPInstruction opc) { - u8 reg = opc & 0x3; - - writeToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg])); -} - -// MV $axD.D, $acS.S -// xxxx xxxx 0001 ddss -// Move value of $acS.S to the $axD.D. -void mv(const UDSPInstruction opc) -{ - u8 sreg = (opc & 0x3) + DSP_REG_ACL0; - u8 dreg = ((opc >> 2) & 0x3); - - switch(sreg) { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg-DSP_REG_ACM0].m); - break; - } -} - -// S @$arD, $acS.S -// xxxx xxxx 001s s0dd -// Store value of $acS.S in the memory pointed by register $arD. -// Post increment register $arD. -void s(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - - switch(sreg) { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACM0].m); - break; - } - writeToBackLog(0, dreg, dsp_increment_addr_reg(dreg)); -} - -// SN @$arD, $acS.S -// xxxx xxxx 001s s1dd -// Store value of register $acS.S in the memory pointed by register $arD. -// Add indexing register $ixD to register $arD. -void sn(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - - switch(sreg) { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACM0].m); - break; - } - writeToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); -} - -// L $axD.D, @$arS -// xxxx xxxx 01dd d0ss -// Load $axD.D/$acD.D with value from memory pointed by register $arS. -// Post increment register $arS. -void l(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - - if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) - { - u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); - writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); - writeToBackLog(1, dreg, val); - writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); - writeToBackLog(3, sreg, dsp_increment_addr_reg(sreg)); - } - else - { - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); - } -} - -// LN $axD.D, @$arS -// xxxx xxxx 01dd d0ss -// Load $axD.D/$acD.D with value from memory pointed by register $arS. -// Add indexing register register $ixS to register $arS. -void ln(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - - if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) - { - u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); - writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); - writeToBackLog(1, dreg, val); - writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); - writeToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } - else - { - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } -} - -// LS $axD.D, $acS.m108 -// xxxx xxxx 10dd 000s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Increment both $ar0 and $ar3. -void ls(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); -} - - -// LSN $axD.D, $acS.m -// xxxx xxxx 10dd 010s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix0 to addressing -// register $ar0 and increment $ar3. -void lsn(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); -} - -// LSM $axD.D, $acS.m -// xxxx xxxx 10dd 100s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix3 to addressing -// register $ar3 and increment $ar0. -void lsm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); -} - -// LSMN $axD.D, $acS.m -// xxxx xxxx 10dd 110s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix0 to addressing -// register $ar0 and add corresponding indexing register $ix3 to addressing -// register $ar3. -void lsnm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[3], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); -} - -// SL $acS.m, $axD.D -// xxxx xxxx 10dd 001s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Increment both $ar0 and $ar3. -void sl(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); -} - -// SLN $acS.m, $axD.D -// xxxx xxxx 10dd 011s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 -// and increment $ar3. -void sln(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); -} - -// SLM $acS.m, $axD.D -// xxxx xxxx 10dd 101s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3 -// and increment $ar0. -void slm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); -} - -// SLMN $acS.m, $axD.D -// xxxx xxxx 10dd 111s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 -// and add corresponding indexing register $ix3 to addressing register $ar3. -void slnm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - - dsp_dmem_write(g_dsp.r.ar[0], g_dsp.r.ac[sreg].m); - - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); -} - -// LD $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 00ss -// example for "nx'ld $AX0.L, $AX1.L, @$AR3" -// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L. -// Increments AR0 and AR3. -// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are not doing that!) -// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. -// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not implemented yet) -// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not implemented yet) -void ld(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - } else { - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); - - if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); - } - - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); -} - -// LDN $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 01ss -void ldn(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } else { - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); - - if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); - } - - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); -} - -// LDM $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 10ss -void ldm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - } else { - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); - - if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); - } - - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); -} - -// LDNM $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 11ss -void ldnm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } else { - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[dreg])); - - if (IsSameMemArea(g_dsp.r.ar[dreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[dreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - - writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); - } - - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); -} - - -void nop(const UDSPInstruction opc) -{ -} - -} // end namespace ext -} // end namespace DSPInterpeter - - -// The ext ops are calculated in parallel with the actual op. That means that -// both the main op and the ext op see the same register state as input. The -// output is simple as long as the main and ext ops don't change the same -// register. If they do the output is the bitwise or of the result of both the -// main and ext ops. - -// The ext op are writing their output into the backlog which is -// being applied to the real registers after the main op was executed -void applyWriteBackLog() -{ - // always make sure to have an extra entry at the end w/ -1 to avoid - // infinitive loops - for (int i = 0; writeBackLogIdx[i] != -1; i++) { - dsp_op_write_reg(writeBackLogIdx[i], dsp_op_read_reg(writeBackLogIdx[i]) | writeBackLog[i]); - // Clear back log - writeBackLogIdx[i] = -1; - } -} - -// This function is being called in the main op after all input regs were read -// and before it writes into any regs. This way we can always use bitwise or to -// apply the ext command output, because if the main op didn't change the value -// then 0 | ext output = ext output and if it did then bitwise or is still the -// right thing to do -void zeroWriteBackLog() -{ - // always make sure to have an extra entry at the end w/ -1 to avoid - // infinitive loops - for (int i = 0; writeBackLogIdx[i] != -1; i++) { - dsp_op_write_reg(writeBackLogIdx[i], 0); - } -} - -//needed for 0x3... cases when main and extended are modifying the same ACC -//games are not doing that + in motorola (similar dsp) dox this is forbidden to do -//ex. corner case -> 0x3060: main opcode modifies .m, and extended .l -> .l shoudnt be zeroed because of .m write... -void zeroWriteBackLogPreserveAcc(u8 acc) -{ - for (int i = 0; writeBackLogIdx[i] != -1; i++) { - - // acc0 - if ((acc == 0) && - ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || (writeBackLogIdx[i] == DSP_REG_ACH0))) - continue; - - // acc1 - if ((acc == 1) && - ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) || (writeBackLogIdx[i] == DSP_REG_ACH1))) - continue; - - dsp_op_write_reg(writeBackLogIdx[i], 0); - } -} diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.h b/Source/Core/DSPCore/Src/DSPIntExtOps.h deleted file mode 100644 index 46b809ca14..0000000000 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.h +++ /dev/null @@ -1,64 +0,0 @@ -/*==================================================================== - - filename: opcodes.h - project: GameCube DSP Tool (gcdsp) - created: 2005.03.04 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _GDSP_EXT_OP_H -#define _GDSP_EXT_OP_H - -#include "DSPTables.h" - -// Extended opcode support. -// Many opcode have the lower 0xFF (some only 0x7f) free - there, an opcode extension -// can be stored. - -namespace DSPInterpreter -{ -namespace Ext -{ -void l(const UDSPInstruction opc); -void ln(const UDSPInstruction opc); -void ls(const UDSPInstruction opc); -void lsn(const UDSPInstruction opc); -void lsm(const UDSPInstruction opc); -void lsnm(const UDSPInstruction opc); -void sl(const UDSPInstruction opc); -void sln(const UDSPInstruction opc); -void slm(const UDSPInstruction opc); -void slnm(const UDSPInstruction opc); -void s(const UDSPInstruction opc); -void sn(const UDSPInstruction opc); -void ld(const UDSPInstruction opc); -void ldn(const UDSPInstruction opc); -void ldm(const UDSPInstruction opc); -void ldnm(const UDSPInstruction opc); -void mv(const UDSPInstruction opc); -void dr(const UDSPInstruction opc); -void ir(const UDSPInstruction opc); -void nr(const UDSPInstruction opc); -void nop(const UDSPInstruction opc); - -} // end namespace Ext -} // end namespace DSPinterpeter - -#endif diff --git a/Source/Core/DSPCore/Src/DSPIntUtil.h b/Source/Core/DSPCore/Src/DSPIntUtil.h deleted file mode 100644 index 712d79fdf8..0000000000 --- a/Source/Core/DSPCore/Src/DSPIntUtil.h +++ /dev/null @@ -1,386 +0,0 @@ -/*==================================================================== - - filename: gdsp_opcodes_helper.h - project: GameCube DSP Tool (gcdsp) - created: 2005.03.04 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _DSP_INT_UTIL_H -#define _DSP_INT_UTIL_H - -#include "Common.h" - -#include "DSPInterpreter.h" -#include "DSPCore.h" -#include "DSPMemoryMap.h" -#include "DSPStacks.h" - - -// --------------------------------------------------------------------------------------- -// --- SR -// --------------------------------------------------------------------------------------- - -inline void dsp_SR_set_flag(int flag) -{ - g_dsp.r.sr |= flag; -} - -inline bool dsp_SR_is_flag_set(int flag) -{ - return (g_dsp.r.sr & flag) != 0; -} - -// --------------------------------------------------------------------------------------- -// --- AR increments, decrements -// --------------------------------------------------------------------------------------- - -inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix) -{ - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - s32 ix = _ix; - - u32 mx = (wr | 1) << 1; - u32 nar = ar + ix; - u32 dar = (nar ^ ar ^ ix) & mx; - - if (ix >= 0) - { - if (dar > wr) //overflow - nar -= wr + 1; - } - else - { - if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask - nar += wr + 1; - } - return nar; -} - -inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix) -{ - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - s32 ix = _ix; - - u32 mx = (wr | 1) << 1; - u32 nar = ar - ix; - u32 dar = (nar ^ ar ^ ~ix) & mx; - - if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000) - { - if (dar > wr) //overflow - nar -= wr + 1; - } - else - { - if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask - nar += wr + 1; - } - return nar; -} - -inline u16 dsp_increment_addr_reg(u16 reg) -{ - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - - u32 nar = ar + 1; - - if ((nar ^ ar) > ((wr | 1) << 1)) - nar -= wr + 1; - return nar; -} - -inline u16 dsp_decrement_addr_reg(u16 reg) -{ - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - - u32 nar = ar + wr; - - if (((nar ^ ar) & ((wr | 1) << 1)) > wr) - nar -= wr + 1; - return nar; -} - - -// --------------------------------------------------------------------------------------- -// --- reg -// --------------------------------------------------------------------------------------- - -inline u16 dsp_op_read_reg(int reg) -{ - switch (reg & 0x1f) { - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return dsp_reg_load_stack(reg - DSP_REG_ST0); - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: return g_dsp.r.cr; - case DSP_REG_SR: return g_dsp.r.sr; - case DSP_REG_PRODL: return g_dsp.r.prod.l; - case DSP_REG_PRODM: return g_dsp.r.prod.m; - case DSP_REG_PRODH: return g_dsp.r.prod.h; - case DSP_REG_PRODM2: return g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return g_dsp.r.ac[reg - DSP_REG_ACM0].m; - default: - _assert_msg_(DSP_INT, 0, "cannot happen"); - return 0; - } -} - -inline void dsp_op_write_reg(int reg, u16 val) -{ - switch (reg & 0x1f) { - // 8-bit sign extended registers. Should look at prod.h too... - case DSP_REG_ACH0: - case DSP_REG_ACH1: - // sign extend from the bottom 8 bits. - g_dsp.r.ac[reg-DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val; - break; - - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack(reg - DSP_REG_ST0, val); - break; - - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - g_dsp.r.ar[reg - DSP_REG_AR0] = val; - break; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - g_dsp.r.ix[reg - DSP_REG_IX0] = val; - break; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - g_dsp.r.wr[reg - DSP_REG_WR0] = val; - break; - case DSP_REG_CR: g_dsp.r.cr = val; break; - case DSP_REG_SR: g_dsp.r.sr = val; break; - case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; - case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; - case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; - case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; - break; - } -} - -inline void dsp_conditional_extend_accum(int reg) -{ - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - if (g_dsp.r.sr & SR_40_MODE_BIT) - { - // Sign extend into whole accum. - u16 val = g_dsp.r.ac[reg-DSP_REG_ACM0].m; - g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000; - g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0; - } - } -} - -// --------------------------------------------------------------------------------------- -// --- prod -// --------------------------------------------------------------------------------------- - -inline s64 dsp_get_long_prod() -{ -#if PROFILE - ProfilerAddDelta(g_dsp.err_pc, 1); -#endif - - s64 val = (s8)(u8)g_dsp.r.prod.h; - val <<= 32; - s64 low_prod = g_dsp.r.prod.m; - low_prod += g_dsp.r.prod.m2; - low_prod <<= 16; - low_prod |= g_dsp.r.prod.l; - val += low_prod; - return val; -} - -inline s64 dsp_get_long_prod_round_prodl() -{ - s64 prod = dsp_get_long_prod(); - - if (prod & 0x10000) - prod = (prod + 0x8000) & ~0xffff; - else - prod = (prod + 0x7fff) & ~0xffff; - - return prod; -} - -// For accurate emulation, this is wrong - but the real prod registers behave -// in completely bizarre ways. Not needed to emulate them correctly for game ucodes. -inline void dsp_set_long_prod(s64 val) -{ -#if PROFILE - ProfilerAddDelta(g_dsp.err_pc, 1); -#endif - - g_dsp.r.prod.l = (u16)val; - val >>= 16; - g_dsp.r.prod.m = (u16)val; - val >>= 16; - g_dsp.r.prod.h = /*(s16)(s8)*/(u8)val;//todo: check expansion - g_dsp.r.prod.m2 = 0; -} - -// --------------------------------------------------------------------------------------- -// --- ACC - main accumulators (40-bit) -// --------------------------------------------------------------------------------------- - -inline s64 dsp_get_long_acc(int reg) -{ -#if PROFILE - ProfilerAddDelta(g_dsp.err_pc, 1); -#endif - - s64 high = (s64)(s8)g_dsp.r.ac[reg].h << 32; - u32 mid_low = ((u32)g_dsp.r.ac[reg].m << 16) | g_dsp.r.ac[reg].l; - return high | mid_low; -} - -inline void dsp_set_long_acc(int _reg, s64 val) -{ -#if PROFILE - ProfilerAddDelta(g_dsp.err_pc, 1); -#endif - - g_dsp.r.ac[_reg].l = (u16)val; - val >>= 16; - g_dsp.r.ac[_reg].m = (u16)val; - val >>= 16; - g_dsp.r.ac[_reg].h = (u16)(s16)(s8)(u8)val; -} - -inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 -{ - return ((s64)(s8)(val >> 32))<<32 | (u32)val; -} - -inline s64 dsp_round_long_acc(s64 val) -{ - if (val & 0x10000) - val = (val + 0x8000) & ~0xffff; - else - val = (val + 0x7fff) & ~0xffff; - - return val; -} - -inline s16 dsp_get_acc_l(int _reg) -{ - return g_dsp.r.ac[_reg].l; -} - -inline s16 dsp_get_acc_m(int _reg) -{ - return g_dsp.r.ac[_reg].m; -} - -inline s16 dsp_get_acc_h(int _reg) -{ - return g_dsp.r.ac[_reg].h; -} - -// --------------------------------------------------------------------------------------- -// --- AX - extra accumulators (32-bit) -// --------------------------------------------------------------------------------------- - -inline s32 dsp_get_long_acx(int _reg) -{ -#if PROFILE - ProfilerAddDelta(g_dsp.err_pc, 1); -#endif - - return ((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l; -} - -inline s16 dsp_get_ax_l(int _reg) -{ - return (s16)g_dsp.r.ax[_reg].l; -} - -inline s16 dsp_get_ax_h(int _reg) -{ - return (s16)g_dsp.r.ax[_reg].h; -} - -#endif diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.cpp b/Source/Core/DSPCore/Src/DSPInterpreter.cpp deleted file mode 100644 index 56e1834b9f..0000000000 --- a/Source/Core/DSPCore/Src/DSPInterpreter.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/*==================================================================== - - filename: gdsp_interpreter.cpp - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include "DSPTables.h" -#include "DSPHost.h" -#include "DSPCore.h" -#include "DSPAnalyzer.h" - -#include "DSPHWInterface.h" -#include "DSPIntUtil.h" - -namespace DSPInterpreter { - -volatile u32 gdsp_running; - -// NOTE: These have nothing to do with g_dsp.r[DSP_REG_CR]. - -// Hm, should instructions that change CR use this? Probably not (but they -// should call UpdateCachedCR()) -void WriteCR(u16 val) -{ - // reset - if (val & 1) - { - DSPCore_Reset(); - val &= ~1; - } - // init - can reset and init be done at the same time? - else if (val == 4) - { - // this looks like a hack! OSInitAudioSystem ucode - // should send this mail - not dsp core itself - gdsp_mbox_write_h(GDSP_MBOX_DSP, 0x8054); - gdsp_mbox_write_l(GDSP_MBOX_DSP, 0x4348); - val |= 0x800; - } - - // update cr - g_dsp.cr = val; -} - -// Hm, should instructions that read CR use this? (Probably not). -u16 ReadCR() -{ - if (g_dsp.pc & 0x8000) - { - g_dsp.cr |= 0x800; - } - else - { - g_dsp.cr &= ~0x800; - } - - return g_dsp.cr; -} - -void Step() -{ - DSPCore_CheckExceptions(); - - g_dsp.step_counter++; - -#if PROFILE - g_dsp.err_pc = g_dsp.pc; - - ProfilerAddDelta(g_dsp.err_pc, 1); - if (g_dsp.step_counter == 1) - { - ProfilerInit(); - } - - if ((g_dsp.step_counter & 0xFFFFF) == 0) - { - ProfilerDump(g_dsp.step_counter); - } -#endif - - u16 opc = dsp_fetch_code(); - ExecuteInstruction(UDSPInstruction(opc)); - - if (DSPAnalyzer::code_flags[g_dsp.pc - 1] & DSPAnalyzer::CODE_LOOP_END) - HandleLoop(); -} - -// Used by thread mode. -//void Run() -//{ -// int checkInterrupt = 0; -// gdsp_running = true; -// while (!(g_dsp.cr & CR_HALT) && gdsp_running) -// { -// if (jit) -// jit->RunForCycles(1); -// else { -// // Automatically let the other threads work if we're idle skipping -// if(DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) -// Common::YieldCPU(); -// -// Step(); -// -// // Turns out the less you check for external interrupts, the more -// // sound you hear, and it becomes slower -// checkInterrupt++; -// if(checkInterrupt == 500) { // <-- Arbitrary number. TODO: tweak -// DSPCore_CheckExternalInterrupt(); -// checkInterrupt = 0; -// } -// } -// } -// gdsp_running = false; -//} - -// This one has basic idle skipping, and checks breakpoints. -int RunCyclesDebug(int cycles) -{ - // First, let's run a few cycles with no idle skipping so that things can progress a bit. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - Step(); - cycles--; - if (cycles < 0) - return 0; - } - - // In thread mode, process external interrupts - if (g_dsp.external_interrupt_waiting) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_CheckExceptions(); - DSPCore_SetExternalInterrupt(false); - } - - while (true) - { - // Next, let's run a few cycles with idle skipping, so that we can skip - // idle loops. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - // Idle skipping. - if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } - - // Now, lets run some more without idle skipping. - for (int i = 0; i < 200; i++) - { - if (dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - Step(); - cycles--; - if (cycles < 0) - return 0; - - // We don't bother directly supporting pause - if the main emu pauses, - // it just won't call this function anymore. - } - } -} - -// Used by non-thread mode. Meant to be efficient. -int RunCycles(int cycles) -{ - // First, let's run a few cycles with no idle skipping so that things can - // progress a bit. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } - - // In thread mode, process external interrupts - if (g_dsp.external_interrupt_waiting) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_CheckExceptions(); - DSPCore_SetExternalInterrupt(false); - } - - while (true) - { - // Next, let's run a few cycles with idle skipping, so that we can skip - // idle loops. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - // Idle skipping. - if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } - - // Now, lets run some more without idle skipping. - for (int i = 0; i < 200; i++) - { - Step(); - cycles--; - if (cycles < 0) - return 0; - // We don't bother directly supporting pause - if the main emu pauses, - // it just won't call this function anymore. - } - } -} - -void Stop() -{ - gdsp_running = false; -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h deleted file mode 100644 index 35db43f5f2..0000000000 --- a/Source/Core/DSPCore/Src/DSPInterpreter.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSPINTERPRETER_H -#define _DSPINTERPRETER_H - -#include "DSPTables.h" - -#define DSP_REG_MASK 0x1f - -namespace DSPInterpreter { - -void Step(); -void Run(); - -// See: DspIntBranch.cpp -void HandleLoop(); - -// If these simply return the same number of cycles as was passed into them, -// chances are that the DSP is halted. -// The difference between them is that the debug one obeys breakpoints. -int RunCycles(int cycles); -int RunCyclesDebug(int cycles); - -void Stop(); - -void WriteCR(u16 val); -u16 ReadCR(); - - -typedef void (*DSPInterpreterFunc)(const UDSPInstruction opc); - -// All the opcode functions. -void unknown(const UDSPInstruction opc); -void call(const UDSPInstruction opc); -void callr(const UDSPInstruction opc); -void ifcc(const UDSPInstruction opc); -void jcc(const UDSPInstruction opc); -void jmprcc(const UDSPInstruction opc); -void ret(const UDSPInstruction opc); -void halt(const UDSPInstruction opc); -void loop(const UDSPInstruction opc); -void loopi(const UDSPInstruction opc); -void bloop(const UDSPInstruction opc); -void bloopi(const UDSPInstruction opc); -void mrr(const UDSPInstruction opc); -void lrr(const UDSPInstruction opc); -void lrrd(const UDSPInstruction opc); -void lrri(const UDSPInstruction opc); -void lrrn(const UDSPInstruction opc); -void srr(const UDSPInstruction opc); -void srrd(const UDSPInstruction opc); -void srri(const UDSPInstruction opc); -void srrn(const UDSPInstruction opc); -void lri(const UDSPInstruction opc); -void lris(const UDSPInstruction opc); -void lr(const UDSPInstruction opc); -void sr(const UDSPInstruction opc); -void si(const UDSPInstruction opc); -void tstaxh(const UDSPInstruction opc); -void clr(const UDSPInstruction opc); -void clrl(const UDSPInstruction opc); -void clrp(const UDSPInstruction opc); -void mulc(const UDSPInstruction opc); -void cmpar(const UDSPInstruction opc); -void cmp(const UDSPInstruction opc); -void tst(const UDSPInstruction opc); -void addaxl(const UDSPInstruction opc); -void addarn(const UDSPInstruction opc); -void mulcac(const UDSPInstruction opc); -void movr(const UDSPInstruction opc); -void movax(const UDSPInstruction opc); -void xorr(const UDSPInstruction opc); -void andr(const UDSPInstruction opc); -void orr(const UDSPInstruction opc); -void andc(const UDSPInstruction opc); -void orc(const UDSPInstruction opc); -void xorc(const UDSPInstruction opc); -void notc(const UDSPInstruction opc); -void lsrnrx(const UDSPInstruction opc); -void asrnrx(const UDSPInstruction opc); -void lsrnr(const UDSPInstruction opc); -void asrnr(const UDSPInstruction opc); -void add(const UDSPInstruction opc); -void addp(const UDSPInstruction opc); -void cmpis(const UDSPInstruction opc); -void addpaxz(const UDSPInstruction opc); -void movpz(const UDSPInstruction opc); -void decm(const UDSPInstruction opc); -void dec(const UDSPInstruction opc); -void inc(const UDSPInstruction opc); -void incm(const UDSPInstruction opc); -void neg(const UDSPInstruction opc); -void addax(const UDSPInstruction opc); -void addr(const UDSPInstruction opc); -void subr(const UDSPInstruction opc); -void subp(const UDSPInstruction opc); -void subax(const UDSPInstruction opc); -void addis(const UDSPInstruction opc); -void addi(const UDSPInstruction opc); -void lsl16(const UDSPInstruction opc); -void madd(const UDSPInstruction opc); -void msub(const UDSPInstruction opc); -void lsr16(const UDSPInstruction opc); -void asr16(const UDSPInstruction opc); -void lsl(const UDSPInstruction opc); -void lsr(const UDSPInstruction opc); -void asl(const UDSPInstruction opc); -void asr(const UDSPInstruction opc); -void lsrn(const UDSPInstruction opc); -void asrn(const UDSPInstruction opc); -void dar(const UDSPInstruction opc); -void iar(const UDSPInstruction opc); -void subarn(const UDSPInstruction opc); -void sbclr(const UDSPInstruction opc); -void sbset(const UDSPInstruction opc); -void mov(const UDSPInstruction opc); -void movp(const UDSPInstruction opc); -void mul(const UDSPInstruction opc); -void mulac(const UDSPInstruction opc); -void mulmv(const UDSPInstruction opc); -void mulmvz(const UDSPInstruction opc); -void mulx(const UDSPInstruction opc); -void mulxac(const UDSPInstruction opc); -void mulxmv(const UDSPInstruction opc); -void mulxmvz(const UDSPInstruction opc); -void mulcmvz(const UDSPInstruction opc); -void mulcmv(const UDSPInstruction opc); -void movnp(const UDSPInstruction opc); -void sub(const UDSPInstruction opc); -void maddx(const UDSPInstruction opc); -void msubx(const UDSPInstruction opc); -void maddc(const UDSPInstruction opc); -void msubc(const UDSPInstruction opc); -void srs(const UDSPInstruction opc); -void lrs(const UDSPInstruction opc); -void nx(const UDSPInstruction opc); -void cmpi(const UDSPInstruction opc); -void rti(const UDSPInstruction opc); -void ilrr(const UDSPInstruction opc); -void ilrrd(const UDSPInstruction opc); -void ilrri(const UDSPInstruction opc); -void ilrrn(const UDSPInstruction opc); -void andcf(const UDSPInstruction opc); -void andf(const UDSPInstruction opc); -void xori(const UDSPInstruction opc); -void andi(const UDSPInstruction opc); -void ori(const UDSPInstruction opc); -void srbith(const UDSPInstruction opc); -void mulaxh(const UDSPInstruction opc); -void tstprod(const UDSPInstruction opc); -void abs(const UDSPInstruction opc); - -} // namespace - -#endif // _DSPINTERPRETER_H diff --git a/Source/Core/DSPCore/Src/DSPMemoryMap.cpp b/Source/Core/DSPCore/Src/DSPMemoryMap.cpp deleted file mode 100644 index 408cb48465..0000000000 --- a/Source/Core/DSPCore/Src/DSPMemoryMap.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*==================================================================== - - filename: gdsp_memory.cpp - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include "DSPInterpreter.h" -#include "DSPMemoryMap.h" -#include "DSPHWInterface.h" -#include "DSPCore.h" - -u16 dsp_imem_read(u16 addr) -{ - switch (addr >> 12) - { - case 0: // 0xxx IRAM - return g_dsp.iram[addr & DSP_IRAM_MASK]; - - case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops. - return g_dsp.irom[addr & DSP_IROM_MASK]; - - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Executing from invalid (%04x) memory", g_dsp.pc, addr); - return 0; - } -} - -u16 dsp_dmem_read(u16 addr) -{ - switch (addr >> 12) - { - case 0x0: // 0xxx DRAM - return g_dsp.dram[addr & DSP_DRAM_MASK]; - - case 0x1: // 1xxx COEF - DEBUG_LOG(DSPLLE, "%04x : Coef Read @ %04x", g_dsp.pc, addr); - return g_dsp.coef[addr & DSP_COEF_MASK]; - - case 0xf: // Fxxx HW regs - return gdsp_ifx_read(addr); - - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr); - return 0; - } -} - -void dsp_dmem_write(u16 addr, u16 val) -{ - switch (addr >> 12) - { - case 0x0: // 0xxx DRAM - g_dsp.dram[addr & DSP_DRAM_MASK] = val; - break; - - case 0xf: // Fxxx HW regs - gdsp_ifx_write(addr, val); - break; - - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, addr); - break; - } -} diff --git a/Source/Core/DSPCore/Src/DSPMemoryMap.h b/Source/Core/DSPCore/Src/DSPMemoryMap.h deleted file mode 100644 index 8aa0d77647..0000000000 --- a/Source/Core/DSPCore/Src/DSPMemoryMap.h +++ /dev/null @@ -1,55 +0,0 @@ -/*==================================================================== - - filename: gdsp_memory.h - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _GDSP_MEMORY_H -#define _GDSP_MEMORY_H - -#include "Common.h" -#include "DSPInterpreter.h" -#include "DSPCore.h" - -u16 dsp_imem_read(u16 addr); -void dsp_dmem_write(u16 addr, u16 val); -u16 dsp_dmem_read(u16 addr); - -inline u16 dsp_fetch_code() -{ - u16 opc = dsp_imem_read(g_dsp.pc); - - g_dsp.pc++; - return opc; -} - -inline u16 dsp_peek_code() -{ - return dsp_imem_read(g_dsp.pc); -} - -inline void dsp_skip_inst() -{ - g_dsp.pc += opTable[dsp_peek_code()]->size; -} - -#endif diff --git a/Source/Core/DSPCore/Src/DSPStacks.cpp b/Source/Core/DSPCore/Src/DSPStacks.cpp deleted file mode 100644 index 5bdae0241f..0000000000 --- a/Source/Core/DSPCore/Src/DSPStacks.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/*==================================================================== - - filename: gdsp_registers.cpp - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include "Common.h" - -#include "DSPCore.h" -#include "DSPStacks.h" - -// Stacks. The stacks are outside the DSP RAM, in dedicated hardware. - -void dsp_reg_stack_push(int stack_reg) -{ - g_dsp.reg_stack_ptr[stack_reg]++; - g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; - g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r.st[stack_reg]; -} - -void dsp_reg_stack_pop(int stack_reg) -{ - g_dsp.r.st[stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; - g_dsp.reg_stack_ptr[stack_reg]--; - g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; -} - -void dsp_reg_store_stack(int stack_reg, u16 val) -{ - dsp_reg_stack_push(stack_reg); - g_dsp.r.st[stack_reg] = val; -} - -u16 dsp_reg_load_stack(int stack_reg) -{ - u16 val = g_dsp.r.st[stack_reg]; - dsp_reg_stack_pop(stack_reg); - return val; -} diff --git a/Source/Core/DSPCore/Src/DSPStacks.h b/Source/Core/DSPCore/Src/DSPStacks.h deleted file mode 100644 index 1a5b9e872c..0000000000 --- a/Source/Core/DSPCore/Src/DSPStacks.h +++ /dev/null @@ -1,34 +0,0 @@ -/*==================================================================== - - filename: gdsp_registers.h - project: GCemu - created: 2004-6-18 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie & Tratax - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _DSP_STACKS_H -#define _DSP_STACKS_H - -#include "Common.h" - -void dsp_reg_store_stack(int stack_reg, u16 val); -u16 dsp_reg_load_stack(int stack_reg); - -#endif diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp deleted file mode 100644 index 80da03c190..0000000000 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) - -#include "Common.h" -#include "DSPTables.h" - -#include "DSPInterpreter.h" -#include "DSPIntExtOps.h" -#include "DSPEmitter.h" - -void nop(const UDSPInstruction opc) -{ - // The real nop is 0. Anything else is bad. - if (opc) - DSPInterpreter::unknown(opc); -} - -const DSPOPCTemplate opcodes[] = -{ - {"NOP", 0x0000, 0xfffc, nop, &DSPEmitter::nop, 1, 0, {}, false, false, false, false, false}, - - {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, &DSPEmitter::dar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, &DSPEmitter::iar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"SUBARN", 0x000c, 0xfffc, DSPInterpreter::subarn, &DSPEmitter::subarn, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, &DSPEmitter::addarn, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, false, false, false, false, false}, - - {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, &DSPEmitter::halt, 1, 0, {}, false, true, true, false, false}, - - {"RETGE", 0x02d0, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETL", 0x02d1, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, - {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETNC", 0x02d6, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETC", 0x02d7, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETx8", 0x02d8, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETx9", 0x02d9, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETxA", 0x02da, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, - {"RETxB", 0x02db, 0xffff, DSPInterpreter::ret, NULL/*&DSPEmitter::ret*/, 1, 0, {}, false, true, false, true, false}, - {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RETO", 0x02de, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, - {"RET", 0x02df, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, true, false, false}, - - {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, &DSPEmitter::rti, 1, 0, {}, false, true, true, false, false}, - - {"CALLGE", 0x02b0, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLL", 0x02b1, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLNZ", 0x02b4, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLNC", 0x02b6, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLC", 0x02b7, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLx8", 0x02b8, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLx9", 0x02b9, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLxA", 0x02ba, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLxB", 0x02bb, 0xffff, DSPInterpreter::call, NULL/*&DSPEmitter::call*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALLO", 0x02be, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, - - {"IFGE", 0x0270, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFL", 0x0271, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, - {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFNC", 0x0276, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFC", 0x0277, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFx8", 0x0278, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFx9", 0x0279, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFxA", 0x027a, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, - {"IFxB", 0x027b, 0xffff, DSPInterpreter::ifcc, NULL/*&DSPEmitter::ifcc*/, 1, 0, {}, false, true, false, true, false}, - {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IFO", 0x027e, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, - {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, true, true, false}, - - {"JGE", 0x0290, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JL", 0x0291, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JNC", 0x0296, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JC", 0x0297, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JMPx8", 0x0298, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JMPx9", 0x0299, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JMPxA", 0x029a, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JMPxB", 0x029b, 0xffff, DSPInterpreter::jcc, NULL/*&DSPEmitter::jcc*/, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JO", 0x029e, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, - - {"JRGE", 0x1700, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRL", 0x1701, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRNC", 0x1706, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRC", 0x1707, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JMPRx8", 0x1708, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JMPRx9", 0x1709, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JMPRxA", 0x170a, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JMPRxB", 0x170b, 0xff1f, DSPInterpreter::jmprcc, NULL/*&DSPEmitter::jmprcc*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JRO", 0x170e, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, - {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, false, false}, - - {"CALLRGE", 0x1710, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRL", 0x1711, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRNC", 0x1716, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRC", 0x1717, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRx8", 0x1718, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRx9", 0x1719, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRxA", 0x171a, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRxB", 0x171b, 0xff1f, DSPInterpreter::callr, NULL/*&DSPEmitter::callr*/, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLRO", 0x171e, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, - {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, true, false}, - - {"SBCLR", 0x1200, 0xff00, DSPInterpreter::sbclr, &DSPEmitter::sbclr, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, - {"SBSET", 0x1300, 0xff00, DSPInterpreter::sbset, &DSPEmitter::sbset, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, - - {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, &DSPEmitter::lsl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, - {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, &DSPEmitter::lsr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, - {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, &DSPEmitter::asl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, - {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, &DSPEmitter::asr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, - - {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, &DSPEmitter::lsrn, 1, 0, {}, false, false, false, false, true}, // discovered by ector! - {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, &DSPEmitter::asrn, 1, 0, {}, false, false, false, false, true}, // discovered by ector! - - {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, &DSPEmitter::lri, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, - {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, &DSPEmitter::lr, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, - {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, &DSPEmitter::sr, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, true, false}, - - {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, &DSPEmitter::mrr, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, - - {"SI", 0x1600, 0xff00, DSPInterpreter::si, &DSPEmitter::si, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, - - {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, &DSPEmitter::addis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, - {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, &DSPEmitter::cmpis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, - {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, &DSPEmitter::lris, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, - - {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, &DSPEmitter::addi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, &DSPEmitter::xori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, &DSPEmitter::andi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, &DSPEmitter::ori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, &DSPEmitter::cmpi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - - {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, &DSPEmitter::andf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, &DSPEmitter::andcf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, - - {"ILRR", 0x0210, 0xfefc, DSPInterpreter::ilrr, &DSPEmitter::ilrr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"ILRRD", 0x0214, 0xfefc, DSPInterpreter::ilrrd, &DSPEmitter::ilrrd, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"ILRRI", 0x0218, 0xfefc, DSPInterpreter::ilrri, &DSPEmitter::ilrri, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - {"ILRRN", 0x021c, 0xfefc, DSPInterpreter::ilrrn, &DSPEmitter::ilrrn, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, - - // LOOPS - {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, &DSPEmitter::loop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, false, true, false, true, false}, - {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, &DSPEmitter::bloop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, &DSPEmitter::loopi, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, false, true, false, true, false}, - {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, &DSPEmitter::bloopi, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, - - // load and store value pointed by indexing reg and increment; LRR/SRR variants - {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, &DSPEmitter::lrr, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, - {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, &DSPEmitter::lrrd, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, - {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, &DSPEmitter::lrri, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, - {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, &DSPEmitter::lrrn, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, - - {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, &DSPEmitter::srr, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, - {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, &DSPEmitter::srrd, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, - {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, &DSPEmitter::srri, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, - {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, &DSPEmitter::srrn, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, - - //2 - {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, &DSPEmitter::lrs, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, false, false, false, false, false}, - {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, &DSPEmitter::srs, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, false, false, false, false, false}, - -// opcodes that can be extended - - //3 - main opcode defined by 9 bits, extension defined by last 7 bits!! - {"XORR", 0x3000, 0xfc80, DSPInterpreter::xorr, &DSPEmitter::xorr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"ANDR", 0x3400, 0xfc80, DSPInterpreter::andr, &DSPEmitter::andr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"ORR", 0x3800, 0xfc80, DSPInterpreter::orr, &DSPEmitter::orr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"ANDC", 0x3c00, 0xfe80, DSPInterpreter::andc, &DSPEmitter::andc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"ORC", 0x3e00, 0xfe80, DSPInterpreter::orc, &DSPEmitter::orc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"XORC", 0x3080, 0xfe80, DSPInterpreter::xorc, &DSPEmitter::xorc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"NOT", 0x3280, 0xfe80, DSPInterpreter::notc, &DSPEmitter::notc, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"LSRNRX", 0x3480, 0xfc80, DSPInterpreter::lsrnrx, &DSPEmitter::lsrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"ASRNRX", 0x3880, 0xfc80, DSPInterpreter::asrnrx, &DSPEmitter::asrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"LSRNR", 0x3c80, 0xfe80, DSPInterpreter::lsrnr, &DSPEmitter::lsrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"ASRNR", 0x3e80, 0xfe80, DSPInterpreter::asrnr, &DSPEmitter::asrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //4 - {"ADDR", 0x4000, 0xf800, DSPInterpreter::addr, &DSPEmitter::addr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, - {"ADDAX", 0x4800, 0xfc00, DSPInterpreter::addax, &DSPEmitter::addax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"ADD", 0x4c00, 0xfe00, DSPInterpreter::add, &DSPEmitter::add, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"ADDP", 0x4e00, 0xfe00, DSPInterpreter::addp, &DSPEmitter::addp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //5 - {"SUBR", 0x5000, 0xf800, DSPInterpreter::subr, &DSPEmitter::subr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, - {"SUBAX", 0x5800, 0xfc00, DSPInterpreter::subax, &DSPEmitter::subax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"SUB", 0x5c00, 0xfe00, DSPInterpreter::sub, &DSPEmitter::sub, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"SUBP", 0x5e00, 0xfe00, DSPInterpreter::subp, &DSPEmitter::subp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //6 - {"MOVR", 0x6000, 0xf800, DSPInterpreter::movr, &DSPEmitter::movr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, - {"MOVAX", 0x6800, 0xfc00, DSPInterpreter::movax, &DSPEmitter::movax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"MOV", 0x6c00, 0xfe00, DSPInterpreter::mov, &DSPEmitter::mov, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MOVP", 0x6e00, 0xfe00, DSPInterpreter::movp, &DSPEmitter::movp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //7 - {"ADDAXL", 0x7000, 0xfc00, DSPInterpreter::addaxl, &DSPEmitter::addaxl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, true, false, false, false, true}, - {"INCM", 0x7400, 0xfe00, DSPInterpreter::incm, &DSPEmitter::incm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"INC", 0x7600, 0xfe00, DSPInterpreter::inc, &DSPEmitter::inc, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"DECM", 0x7800, 0xfe00, DSPInterpreter::decm, &DSPEmitter::decm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"DEC", 0x7a00, 0xfe00, DSPInterpreter::dec, &DSPEmitter::dec, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"NEG", 0x7c00, 0xfe00, DSPInterpreter::neg, &DSPEmitter::neg, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MOVNP", 0x7e00, 0xfe00, DSPInterpreter::movnp, &DSPEmitter::movnp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //8 - {"NX", 0x8000, 0xf700, DSPInterpreter::nx, &DSPEmitter::nx, 1, 0, {}, true, false, false, false, false}, - {"CLR", 0x8100, 0xf700, DSPInterpreter::clr, &DSPEmitter::clr, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"CMP", 0x8200, 0xff00, DSPInterpreter::cmp, &DSPEmitter::cmp, 1, 0, {}, true, false, false, false, true}, - {"MULAXH", 0x8300, 0xff00, DSPInterpreter::mulaxh, &DSPEmitter::mulaxh, 1, 0, {}, true, false, false, false, true}, - {"CLRP", 0x8400, 0xff00, DSPInterpreter::clrp, &DSPEmitter::clrp, 1, 0, {}, true, false, false, false, true}, - {"TSTPROD", 0x8500, 0xff00, DSPInterpreter::tstprod, &DSPEmitter::tstprod,1, 0, {}, true, false, false, false, true}, - {"TSTAXH", 0x8600, 0xfe00, DSPInterpreter::tstaxh, &DSPEmitter::tstaxh, 1, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"M2", 0x8a00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - {"M0", 0x8b00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - {"CLR15", 0x8c00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - {"SET15", 0x8d00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - {"SET16", 0x8e00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - {"SET40", 0x8f00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, - - //9 - {"MUL", 0x9000, 0xf700, DSPInterpreter::mul, &DSPEmitter::mul, 1, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"ASR16", 0x9100, 0xf700, DSPInterpreter::asr16, &DSPEmitter::asr16, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"MULMVZ", 0x9200, 0xf600, DSPInterpreter::mulmvz, &DSPEmitter::mulmvz, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULAC", 0x9400, 0xf600, DSPInterpreter::mulac, &DSPEmitter::mulac, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, &DSPEmitter::mulmv, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //a-b - {"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, &DSPEmitter::mulx, 1, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true, false, false, false, true}, - {"ABS", 0xa100, 0xf700, DSPInterpreter::abs, &DSPEmitter::abs, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"MULXMVZ", 0xa200, 0xe600, DSPInterpreter::mulxmvz, &DSPEmitter::mulxmvz,1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULXAC", 0xa400, 0xe600, DSPInterpreter::mulxac, &DSPEmitter::mulxac, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULXMV", 0xa600, 0xe600, DSPInterpreter::mulxmv, &DSPEmitter::mulxmv, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"TST", 0xb100, 0xf700, DSPInterpreter::tst, &DSPEmitter::tst, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - - //c-d - {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, &DSPEmitter::mulc, 1, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"CMPAR" , 0xc100, 0xe700, DSPInterpreter::cmpar, &DSPEmitter::cmpar, 1, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"MULCMVZ", 0xc200, 0xe600, DSPInterpreter::mulcmvz, &DSPEmitter::mulcmvz,1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULCAC", 0xc400, 0xe600, DSPInterpreter::mulcac, &DSPEmitter::mulcac, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MULCMV", 0xc600, 0xe600, DSPInterpreter::mulcmv, &DSPEmitter::mulcmv, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - - //e - {"MADDX", 0xe000, 0xfc00, DSPInterpreter::maddx, &DSPEmitter::maddx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, - {"MSUBX", 0xe400, 0xfc00, DSPInterpreter::msubx, &DSPEmitter::msubx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, - {"MADDC", 0xe800, 0xfc00, DSPInterpreter::maddc, &DSPEmitter::maddc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, - {"MSUBC", 0xec00, 0xfc00, DSPInterpreter::msubc, &DSPEmitter::msubc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, - - //f - {"LSL16", 0xf000, 0xfe00, DSPInterpreter::lsl16, &DSPEmitter::lsl16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MADD", 0xf200, 0xfe00, DSPInterpreter::madd, &DSPEmitter::madd, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"LSR16", 0xf400, 0xfe00, DSPInterpreter::lsr16, &DSPEmitter::lsr16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"MSUB", 0xf600, 0xfe00, DSPInterpreter::msub, &DSPEmitter::msub, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"ADDPAXZ", 0xf800, 0xfc00, DSPInterpreter::addpaxz, &DSPEmitter::addpaxz,1, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_AX, 1, 0, 8, 0x0100}}, true, false, false, false, true}, - {"CLRL", 0xfc00, 0xfe00, DSPInterpreter::clrl, &DSPEmitter::clrl, 1, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, true, false, false, false, true}, - {"MOVPZ", 0xfe00, 0xfe00, DSPInterpreter::movpz, &DSPEmitter::movpz, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, -}; - -const DSPOPCTemplate cw = - {"CW", 0x0000, 0x0000, NULL, NULL, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false}; - -// extended opcodes - -const DSPOPCTemplate opcodes_ext[] = -{ - {"XXX", 0x0000, 0x00fc, DSPInterpreter::Ext::nop, &DSPEmitter::nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, false, false, false}, - - {"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, &DSPEmitter::dr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, - {"IR", 0x0008, 0x00fc, DSPInterpreter::Ext::ir, &DSPEmitter::ir, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, - {"NR", 0x000c, 0x00fc, DSPInterpreter::Ext::nr, &DSPEmitter::nr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false}, - {"MV", 0x0010, 0x00f0, DSPInterpreter::Ext::mv, &DSPEmitter::mv, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, false, false, false}, - - {"S", 0x0020, 0x00e4, DSPInterpreter::Ext::s, &DSPEmitter::s, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false}, - {"SN", 0x0024, 0x00e4, DSPInterpreter::Ext::sn, &DSPEmitter::sn, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false}, - - {"L", 0x0040, 0x00c4, DSPInterpreter::Ext::l, &DSPEmitter::l, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, - {"LN", 0x0044, 0x00c4, DSPInterpreter::Ext::ln, &DSPEmitter::ln, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, - - {"LS", 0x0080, 0x00ce, DSPInterpreter::Ext::ls, &DSPEmitter::ls, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, - {"SL", 0x0082, 0x00ce, DSPInterpreter::Ext::sl, &DSPEmitter::sl, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, - {"LSN", 0x0084, 0x00ce, DSPInterpreter::Ext::lsn, &DSPEmitter::lsn, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, - {"SLN", 0x0086, 0x00ce, DSPInterpreter::Ext::sln, &DSPEmitter::sln, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, - {"LSM", 0x0088, 0x00ce, DSPInterpreter::Ext::lsm, &DSPEmitter::lsm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, - {"SLM", 0x008a, 0x00ce, DSPInterpreter::Ext::slm, &DSPEmitter::slm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, - {"LSNM", 0x008c, 0x00ce, DSPInterpreter::Ext::lsnm, &DSPEmitter::lsnm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false}, - {"SLNM", 0x008e, 0x00ce, DSPInterpreter::Ext::slnm, &DSPEmitter::slnm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false}, - - {"LD", 0x00c0, 0x00cc, DSPInterpreter::Ext::ld, &DSPEmitter::ld, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, - {"LDN", 0x00c4, 0x00cc, DSPInterpreter::Ext::ldn, &DSPEmitter::ldn, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, - {"LDM", 0x00c8, 0x00cc, DSPInterpreter::Ext::ldm, &DSPEmitter::ldm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, - {"LDNM", 0x00cc, 0x00cc, DSPInterpreter::Ext::ldnm, &DSPEmitter::ldnm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false}, -}; - -const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate); -const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate); - -const pdlabel_t pdlabels[] = -{ - {0xffa0, "COEF_A1_0", "COEF_A1_0",}, - {0xffa1, "COEF_A2_0", "COEF_A2_0",}, - {0xffa2, "COEF_A1_1", "COEF_A1_1",}, - {0xffa3, "COEF_A2_1", "COEF_A2_1",}, - {0xffa4, "COEF_A1_2", "COEF_A1_2",}, - {0xffa5, "COEF_A2_2", "COEF_A2_2",}, - {0xffa6, "COEF_A1_3", "COEF_A1_3",}, - {0xffa7, "COEF_A2_3", "COEF_A2_3",}, - {0xffa8, "COEF_A1_4", "COEF_A1_4",}, - {0xffa9, "COEF_A2_4", "COEF_A2_4",}, - {0xffaa, "COEF_A1_5", "COEF_A1_5",}, - {0xffab, "COEF_A2_5", "COEF_A2_5",}, - {0xffac, "COEF_A1_6", "COEF_A1_6",}, - {0xffad, "COEF_A2_6", "COEF_A2_6",}, - {0xffae, "COEF_A1_7", "COEF_A1_7",}, - {0xffaf, "COEF_A2_7", "COEF_A2_7",}, - - {0xffb0, "0xffb0", 0,}, - {0xffb1, "0xffb1", 0,}, - {0xffb2, "0xffb2", 0,}, - {0xffb3, "0xffb3", 0,}, - {0xffb4, "0xffb4", 0,}, - {0xffb5, "0xffb5", 0,}, - {0xffb6, "0xffb6", 0,}, - {0xffb7, "0xffb7", 0,}, - {0xffb8, "0xffb8", 0,}, - {0xffb9, "0xffb9", 0,}, - {0xffba, "0xffba", 0,}, - {0xffbb, "0xffbb", 0,}, - {0xffbc, "0xffbc", 0,}, - {0xffbd, "0xffbd", 0,}, - {0xffbe, "0xffbe", 0,}, - {0xffbf, "0xffbf", 0,}, - - {0xffc0, "0xffc0", 0,}, - {0xffc1, "0xffc1", 0,}, - {0xffc2, "0xffc2", 0,}, - {0xffc3, "0xffc3", 0,}, - {0xffc4, "0xffc4", 0,}, - {0xffc5, "0xffc5", 0,}, - {0xffc6, "0xffc6", 0,}, - {0xffc7, "0xffc7", 0,}, - {0xffc8, "0xffc8", 0,}, - {0xffc9, "DSCR", "DSP DMA Control Reg",}, - {0xffca, "0xffca", 0,}, - {0xffcb, "DSBL", "DSP DMA Block Length",}, - {0xffcc, "0xffcc", 0,}, - {0xffcd, "DSPA", "DSP DMA DMEM Address",}, - {0xffce, "DSMAH", "DSP DMA Mem Address H",}, - {0xffcf, "DSMAL", "DSP DMA Mem Address L",}, - - {0xffd0, "0xffd0",0,}, - {0xffd1, "SampleFormat", "SampleFormat",}, - {0xffd2, "0xffd2",0,}, - {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",}, - {0xffd4, "ACSAH", "Accelerator start address H",}, - {0xffd5, "ACSAL", "Accelerator start address L",}, - {0xffd6, "ACEAH", "Accelerator end address H",}, - {0xffd7, "ACEAL", "Accelerator end address L",}, - {0xffd8, "ACCAH", "Accelerator current address H",}, - {0xffd9, "ACCAL", "Accelerator current address L",}, - {0xffda, "pred_scale", "pred_scale",}, - {0xffdb, "yn1", "yn1",}, - {0xffdc, "yn2", "yn2",}, - {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",}, - {0xffde, "GAIN", "Gain",}, - {0xffdf, "0xffdf", 0,}, - - {0xffe0, "0xffe0",0,}, - {0xffe1, "0xffe1",0,}, - {0xffe2, "0xffe2",0,}, - {0xffe3, "0xffe3",0,}, - {0xffe4, "0xffe4",0,}, - {0xffe5, "0xffe5",0,}, - {0xffe6, "0xffe6",0,}, - {0xffe7, "0xffe7",0,}, - {0xffe8, "0xffe8",0,}, - {0xffe9, "0xffe9",0,}, - {0xffea, "0xffea",0,}, - {0xffeb, "0xffeb",0,}, - {0xffec, "0xffec",0,}, - {0xffed, "0xffed",0,}, - {0xffee, "0xffee",0,}, - {0xffef, "AMDM", "ARAM DMA Request Mask",}, - - {0xfff0, "0xfff0",0,}, - {0xfff1, "0xfff1",0,}, - {0xfff2, "0xfff2",0,}, - {0xfff3, "0xfff3",0,}, - {0xfff4, "0xfff4",0,}, - {0xfff5, "0xfff5",0,}, - {0xfff6, "0xfff6",0,}, - {0xfff7, "0xfff7",0,}, - {0xfff8, "0xfff8",0,}, - {0xfff9, "0xfff9",0,}, - {0xfffa, "0xfffa",0,}, - {0xfffb, "DIRQ", "DSP IRQ Request",}, - {0xfffc, "DMBH", "DSP Mailbox H",}, - {0xfffd, "DMBL", "DSP Mailbox L",}, - {0xfffe, "CMBH", "CPU Mailbox H",}, - {0xffff, "CMBL", "CPU Mailbox L",}, -}; - -const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t); - -const pdlabel_t regnames[] = -{ - {0x00, "AR0", "Addr Reg 00",}, - {0x01, "AR1", "Addr Reg 01",}, - {0x02, "AR2", "Addr Reg 02",}, - {0x03, "AR3", "Addr Reg 03",}, - {0x04, "IX0", "Index Reg 0",}, - {0x05, "IX1", "Index Reg 1",}, - {0x06, "IX2", "Index Reg 2",}, - {0x07, "IX3", "Index Reg 3",}, - {0x08, "WR0", "Wrapping Register 0",}, - {0x09, "WR1", "Wrapping Register 1",}, - {0x0a, "WR2", "Wrapping Register 2",}, - {0x0b, "WR3", "Wrapping Register 3",}, - {0x0c, "ST0", "Call stack",}, - {0x0d, "ST1", "Data stack",}, - {0x0e, "ST2", "Loop addr stack",}, - {0x0f, "ST3", "Loop counter",}, - {0x10, "AC0.H", "Accu High 0",}, - {0x11, "AC1.H", "Accu High 1",}, - {0x12, "CR", "Config Register",}, - {0x13, "SR", "Special Register",}, - {0x14, "PROD.L", "Prod L",}, - {0x15, "PROD.M1", "Prod M1",}, - {0x16, "PROD.H", "Prod H",}, - {0x17, "PROD.M2", "Prod M2",}, - {0x18, "AX0.L", "Extra Accu L 0",}, - {0x19, "AX1.L", "Extra Accu L 1",}, - {0x1a, "AX0.H", "Extra Accu H 0",}, - {0x1b, "AX1.H", "Extra Accu H 1",}, - {0x1c, "AC0.L", "Accu Low 0",}, - {0x1d, "AC1.L", "Accu Low 1",}, - {0x1e, "AC0.M", "Accu Mid 0",}, - {0x1f, "AC1.M", "Accu Mid 1",}, - - // To resolve combined register names. - {0x20, "ACC0", "Accu Full 0",}, - {0x21, "ACC1", "Accu Full 1",}, - {0x22, "AX0", "Extra Accu 0",}, - {0x23, "AX1", "Extra Accu 1",}, -}; - -const DSPOPCTemplate *opTable[OPTABLE_SIZE]; -const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; -u16 writeBackLog[WRITEBACKLOGSIZE]; -int writeBackLogIdx[WRITEBACKLOGSIZE]; - -const char* pdname(u16 val) -{ - static char tmpstr[12]; // nasty - - for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++) - { - if (pdlabels[i].addr == val) - return pdlabels[i].name; - } - - sprintf(tmpstr, "0x%04x", val); - return tmpstr; -} - -const char *pdregname(int val) -{ - return regnames[val].name; -} - -const char *pdregnamelong(int val) -{ - return regnames[val].description; -} - -const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst) -{ - return opTable[inst]; -} - - -// This function could use the above GetOpTemplate, but then we'd lose the -// nice property that it catches colliding op masks. -void InitInstructionTable() -{ - // ext op table - for (int i = 0; i < EXT_OPTABLE_SIZE; i++) - extOpTable[i] = &cw; - - for (int i = 0; i < EXT_OPTABLE_SIZE; i++) - { - for (int j = 0; j < opcodes_ext_size; j++) - { - u16 mask = opcodes_ext[j].opcode_mask; - if ((mask & i) == opcodes_ext[j].opcode) - { - if (extOpTable[i] == &cw) - extOpTable[i] = &opcodes_ext[j]; - else - ERROR_LOG(DSPLLE, "opcode ext table place %d already in use for %s", i, opcodes_ext[j].name); - } - } - } - - // op table - for (int i = 0; i < OPTABLE_SIZE; i++) - opTable[i] = &cw; - - for (int i = 0; i < OPTABLE_SIZE; i++) - { - for (int j = 0; j < opcodes_size; j++) - { - u16 mask = opcodes[j].opcode_mask; - if ((mask & i) == opcodes[j].opcode) - { - if (opTable[i] == &cw) - opTable[i] = &opcodes[j]; - else - ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name); - } - } - } - - for (int i=0; i < WRITEBACKLOGSIZE; i++) - writeBackLogIdx[i] = -1; -} diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h deleted file mode 100644 index 56ad885d23..0000000000 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com) - -#ifndef _DSPTABLES_H -#define _DSPTABLES_H - -//nclude "Common.h" -#include "DSPEmitter.h" -#include "DSPCommon.h" - -// The non-ADDR ones that end with _D are the opposite one - if the bit specify -// ACC0, then ACC_D will be ACC1. - -// The values of these are very important. -// For the reg ones, the value >> 8 is the base register. -// & 0x80 means it's a "D". - -enum partype_t -{ - P_NONE = 0x0000, - P_VAL = 0x0001, - P_IMM = 0x0002, - P_MEM = 0x0003, - P_STR = 0x0004, - P_ADDR_I = 0x0005, - P_ADDR_D = 0x0006, - P_REG = 0x8000, - P_REG04 = P_REG | 0x0400, // IX - P_REG08 = P_REG | 0x0800, - P_REG18 = P_REG | 0x1800, - P_REGM18 = P_REG | 0x1810, // used in multiply instructions - P_REG19 = P_REG | 0x1900, - P_REGM19 = P_REG | 0x1910, // used in multiply instructions - P_REG1A = P_REG | 0x1a80, - P_REG1C = P_REG | 0x1c00, -// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) - P_ACCL = P_REG | 0x1c00, // used for low part of accum - P_ACCM = P_REG | 0x1e00, // used for mid part of accum - // The following are not in gcdsptool - P_ACCM_D = P_REG | 0x1e80, - P_ACC = P_REG | 0x2000, // used for full accum. - P_ACC_D = P_REG | 0x2080, - P_AX = P_REG | 0x2200, - P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 - P_REF = P_REG | 0x4000, - P_PRG = P_REF | P_REG, - - // The following seem like junk: - // P_REG10 = P_REG | 0x1000, - // P_AX_D = P_REG | 0x2280, -}; - -#define OPTABLE_SIZE 0xffff + 1 -#define EXT_OPTABLE_SIZE 0xff + 1 - -typedef void (*dspIntFunc)(const UDSPInstruction); -typedef void (DSPEmitter::*dspJitFunc)(const UDSPInstruction); - -struct param2_t -{ - partype_t type; - u8 size; - u8 loc; - s8 lshift; - u16 mask; -}; - -typedef struct -{ - const char *name; - u16 opcode; - u16 opcode_mask; - - dspIntFunc intFunc; - dspJitFunc jitFunc; - - u8 size; - u8 param_count; - param2_t params[8]; - bool extended; - bool branch; - bool uncond_branch; - bool reads_pc; - bool updates_sr; -} DSPOPCTemplate; - -typedef DSPOPCTemplate opc_t; - -// Opcodes -extern const DSPOPCTemplate opcodes[]; -extern const int opcodes_size; -extern const DSPOPCTemplate opcodes_ext[]; -extern const int opcodes_ext_size; -extern const DSPOPCTemplate cw; - -#define WRITEBACKLOGSIZE 5 - -extern const DSPOPCTemplate *opTable[OPTABLE_SIZE]; -extern const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; -extern u16 writeBackLog[WRITEBACKLOGSIZE]; -extern int writeBackLogIdx[WRITEBACKLOGSIZE]; - -// Predefined labels -struct pdlabel_t -{ - u16 addr; - const char* name; - const char* description; -}; - -extern const pdlabel_t regnames[]; -extern const pdlabel_t pdlabels[]; -extern const u32 pdlabels_size; - -const char *pdname(u16 val); -const char *pdregname(int val); -const char *pdregnamelong(int val); - -void InitInstructionTable(); -void applyWriteBackLog(); -void zeroWriteBackLog(); -void zeroWriteBackLogPreserveAcc(u8 acc); - -const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst); - -inline void ExecuteInstruction(const UDSPInstruction inst) -{ - const DSPOPCTemplate *tinst = GetOpTemplate(inst); - - if (tinst->extended) { - if ((inst >> 12) == 0x3) - extOpTable[inst & 0x7F]->intFunc(inst); - else - extOpTable[inst & 0xFF]->intFunc(inst); - } - tinst->intFunc(inst); - if (tinst->extended) { - applyWriteBackLog(); - } -} - -#endif // _DSPTABLES_H diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp deleted file mode 100644 index ba625395a1..0000000000 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "DSPInterpreter.h" -#include "DSPIntCCUtil.h" -#include "DSPIntUtil.h" - -// Arithmetic and accumulator control. - -namespace DSPInterpreter { - -// CLR $acR -// 1000 r001 xxxx xxxx -// Clears accumulator $acR -// -// flags out: --10 0100 -void clr(const UDSPInstruction opc) -{ - u8 reg = (opc >> 11) & 0x1; - - dsp_set_long_acc(reg, 0); - Update_SR_Register64(0); - zeroWriteBackLog(); -} - -// CLRL $acR.l -// 1111 110r xxxx xxxx -// Clears (and rounds!) $acR.l - low 16 bits of accumulator $acR. -// -// flags out: --xx xx00 -void clrl(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); - - zeroWriteBackLog(); - - dsp_set_long_acc(reg, acc); - Update_SR_Register64(acc); -} - -//---- - -// ANDCF $acD.m, #I -// 0000 001r 1100 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logic AND of -// accumulator mid part $acD.m with immediate value I is equal I. -// -// flags out: -x-- ---- -void andcf(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - Update_SR_LZ(((val & imm) == imm) ? true : false); -} - -// ANDF $acD.m, #I -// 0000 001r 1010 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logical AND -// operation of accumulator mid part $acD.m with immediate value I is equal -// immediate value 0. -// -// flags out: -x-- ---- -void andf(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - Update_SR_LZ(((val & imm) == 0) ? true : false); -} - -//---- - -// TST -// 1011 r001 xxxx xxxx -// Test accumulator %acR. -// -// flags out: --xx xx00 -void tst(const UDSPInstruction opc) -{ - u8 reg = (opc >> 11) & 0x1; - - s64 acc = dsp_get_long_acc(reg); - Update_SR_Register64(acc); - zeroWriteBackLog(); -} - -// TSTAXH $axR.h -// 1000 011r xxxx xxxx -// Test high part of secondary accumulator $axR.h. -// -// flags out: --x0 xx00 -void tstaxh(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - - s16 val = dsp_get_ax_h(reg); - Update_SR_Register16(val); - zeroWriteBackLog(); -} - -//---- - -// CMP -// 1000 0010 xxxx xxxx -// Compares accumulator $ac0 with accumulator $ac1. -// -// flags out: x-xx xxxx -void cmp(const UDSPInstruction opc) -{ - s64 acc0 = dsp_get_long_acc(0); - s64 acc1 = dsp_get_long_acc(1); - s64 res = dsp_convert_long_acc(acc0 - acc1); - - Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 - zeroWriteBackLog(); -} - -// CMPAR $acS axR.h -// 1100 0001 xxxx xxxx -// Compares accumulator $acS with accumulator axR.h. -// Not described by Duddie's doc - at least not as a separate instruction. -// -// flags out: x-xx xxxx -void cmpar(const UDSPInstruction opc) -{ - u8 rreg = ((opc >> 12) & 0x1) + DSP_REG_AXH0; - u8 sreg = (opc >> 11) & 0x1; - - s64 sr = dsp_get_long_acc(sreg); - s64 rr = (s16)g_dsp.r.ax[rreg-DSP_REG_AXH0].h; - rr <<= 16; - s64 res = dsp_convert_long_acc(sr - rr); - - Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); - zeroWriteBackLog(); -} - -// CMPI $amD, #I -// 0000 001r 1000 0000 -// iiii iiii iiii iiii -// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. -// Although flags are being set regarding whole accumulator register. -// -// flags out: x-xx xxxx -void cmpi(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - - s64 val = dsp_get_long_acc(reg); - s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. - s64 res = dsp_convert_long_acc(val - imm); - - Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); -} - -// CMPIS $acD, #I -// 0000 011d iiii iiii -// Compares accumulator with short immediate. Comaprison is executed -// by subtracting short immediate (8bit sign extended) from mid accumulator -// $acD.hm and computing flags based on whole accumulator $acD. -// -// flags out: x-xx xxxx -void cmpis(const UDSPInstruction opc) -{ - u8 areg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - s64 val = (s8)opc; - val <<= 16; - s64 res = dsp_convert_long_acc(acc - val); - - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); -} - -//---- - -// XORR $acD.m, $axS.h -// 0011 00sd 0xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with -// high part of secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void xorr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ax[sreg].h; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// ANDR $acD.m, $axS.h -// 0011 01sd 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void andr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ax[sreg].h; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// ORR $acD.m, $axS.h -// 0011 10sd 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void orr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ax[sreg].h; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// ANDC $acD.m, $ac(1-D).m -// 0011 110d 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void andc(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ac[1 - dreg].m; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// ORC $acD.m, $ac(1-D).m -// 0011 111d 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void orc(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ac[1 - dreg].m; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// XORC $acD.m -// 0011 000d 1xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void xorc(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ac[1 - dreg].m; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// NOT $acD.m -// 0011 001d 1xxx xxxx -// Invert all bits in dest reg, aka xor with 0xffff -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void notc(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ 0xffff; - - zeroWriteBackLogPreserveAcc(dreg); - - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); -} - -// XORI $acD.m, #I -// 0000 001r 0010 0000 -// iiii iiii iiii iiii -// Logic exclusive or (XOR) of accumulator mid part $acD.m with -// immediate value I. -// -// flags out: --xx xx00 -void xori(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m ^= imm; - - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); -} - -// ANDI $acD.m, #I -// 0000 001r 0100 0000 -// iiii iiii iiii iiii -// Logic AND of accumulator mid part $acD.m with immediate value I. -// -// flags out: --xx xx00 -void andi(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m &= imm; - - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); -} - -// ORI $acD.m, #I -// 0000 001r 0110 0000 -// iiii iiii iiii iiii -// Logic OR of accumulator mid part $acD.m with immediate value I. -// -// flags out: --xx xx00 -void ori(const UDSPInstruction opc) -{ - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m |= imm; - - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); -} - -//---- - -// ADDR $acD.M, $axS.L -// 0100 0ssd xxxx xxxx -// Adds register $axS.L to accumulator $acD.M register. -// -// flags out: x-xx xxxx -void addr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - - s64 acc = dsp_get_long_acc(dreg); - s64 ax = 0; - switch(sreg) { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } - ax <<= 16; - s64 res = acc + ax; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); -} - -// ADDAX $acD, $axS -// 0100 10sd xxxx xxxx -// Adds secondary accumulator $axS to accumulator register $acD. -// -// flags out: x-xx xxxx -void addax(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 ax = dsp_get_long_acx(sreg); - s64 res = acc + ax; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); -} - -// ADD $acD, $ac(1-D) -// 0100 110d xxxx xxxx -// Adds accumulator $ac(1-D) to accumulator register $acD. -// -// flags out: x-xx xxxx -void add(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc0 = dsp_get_long_acc(dreg); - s64 acc1 = dsp_get_long_acc(1 - dreg); - s64 res = acc0 + acc1; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); -} - -// ADDP $acD -// 0100 111d xxxx xxxx -// Adds product register to accumulator register. -// -// flags out: x-xx xxxx -void addp(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 prod = dsp_get_long_prod(); - s64 res = acc + prod; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); -} - -// ADDAXL $acD, $axS.l -// 0111 00sd xxxx xxxx -// Adds secondary accumulator $axS.l to accumulator register $acD. -// should be unsigned values!! -// -// flags out: x-xx xxxx -void addaxl(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 9) & 0x1; - u8 dreg = (opc >> 8) & 0x1; - - u64 acc = dsp_get_long_acc(dreg); - u16 acx = (u16)dsp_get_ax_l(sreg); - - u64 res = acc + acx; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, (s64)res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); -} - -// ADDI $amR, #I -// 0000 001r 0000 0000 -// iiii iiii iiii iiii -// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. -// -// flags out: x-xx xxxx -void addi(const UDSPInstruction opc) -{ - u8 areg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - s64 imm = (s16)dsp_fetch_code(); - imm <<= 16; - s64 res = acc + imm; - - dsp_set_long_acc(areg, res); - res = dsp_get_long_acc(areg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); -} - -// ADDIS $acD, #I -// 0000 010d iiii iiii -// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. -// -// flags out: x-xx xxxx -void addis(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 imm = (s8)(u8)opc; - imm <<= 16; - s64 res = acc + imm; - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); -} - -// INCM $acsD -// 0111 010d xxxx xxxx -// Increment 24-bit mid-accumulator $acsD. -// -// flags out: x-xx xxxx -void incm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc + sub; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); -} - -// INC $acD -// 0111 011d xxxx xxxx -// Increment accumulator $acD. -// -// flags out: x-xx xxxx -void inc(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc + 1; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); -} - -//---- - -// SUBR $acD.M, $axS.L -// 0101 0ssd xxxx xxxx -// Subtracts register $axS.L from accumulator $acD.M register. -// -// flags out: x-xx xxxx -void subr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - - s64 acc = dsp_get_long_acc(dreg); - s64 ax = 0; - switch(sreg) { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } - ax <<= 16; - s64 res = acc - ax; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); -} - -// SUBAX $acD, $axS -// 0101 10sd xxxx xxxx -// Subtracts secondary accumulator $axS from accumulator register $acD. -// -// flags out: x-xx xxxx -void subax(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 acx = dsp_get_long_acx(sreg); - s64 res = acc - acx; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); -} - -// SUB $acD, $ac(1-D) -// 0101 110d xxxx xxxx -// Subtracts accumulator $ac(1-D) from accumulator register $acD. -// -// flags out: x-xx xxxx -void sub(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc1 = dsp_get_long_acc(dreg); - s64 acc2 = dsp_get_long_acc(1 - dreg); - s64 res = acc1 - acc2; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); -} - -// SUBP $acD -// 0101 111d xxxx xxxx -// Subtracts product register from accumulator register. -// -// flags out: x-xx xxxx -void subp(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 prod = dsp_get_long_prod(); - s64 res = acc - prod; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); -} - -// DECM $acsD -// 0111 100d xxxx xxxx -// Decrement 24-bit mid-accumulator $acsD. -// -// flags out: x-xx xxxx -void decm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x01; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc - sub; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); -} - -// DEC $acD -// 0111 101d xxxx xxxx -// Decrement accumulator $acD. -// -// flags out: x-xx xxxx -void dec(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x01; - - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc - 1; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); -} - -//---- - -// NEG $acD -// 0111 110d xxxx xxxx -// Negate accumulator $acD. -// -// flags out: --xx xx00 -void neg(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - acc = 0 - acc; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - -// ABS $acD -// 1010 d001 xxxx xxxx -// absolute value of $acD -// -// flags out: --xx xx00 -void abs(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 11) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - - if (acc < 0) - acc = 0 - acc; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} -//---- - -// MOVR $acD, $axS.R -// 0110 0srd xxxx xxxx -// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. -// Sets $acD.l to 0. -// TODO: Check what happens to acD.h. -// -// flags out: --xx xx00 -void movr(const UDSPInstruction opc) -{ - u8 areg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - - s64 ax = 0; - switch(sreg) { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } - ax <<= 16; - ax &= ~0xffff; - - zeroWriteBackLog(); - - dsp_set_long_acc(areg, ax); - Update_SR_Register64(ax); -} - -// MOVAX $acD, $axS -// 0110 10sd xxxx xxxx -// Moves secondary accumulator $axS to accumulator $axD. -// -// flags out: --xx xx00 -void movax(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s64 acx = dsp_get_long_acx(sreg); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acx); - Update_SR_Register64(acx); -} - -// MOV $acD, $ac(1-D) -// 0110 110d xxxx xxxx -// Moves accumulator $ax(1-D) to accumulator $axD. -// -// flags out: --x0 xx00 -void mov(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u64 acc = dsp_get_long_acc(1 - dreg); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); -} - -//---- - -// LSL16 $acR -// 1111 000r xxxx xxxx -// Logically shifts left accumulator $acR by 16. -// -// flags out: --xx xx00 -void lsl16(const UDSPInstruction opc) -{ - u8 areg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - acc <<= 16; - - zeroWriteBackLog(); - - dsp_set_long_acc(areg, acc); - Update_SR_Register64(dsp_get_long_acc(areg)); -} - -// LSR16 $acR -// 1111 010r xxxx xxxx -// Logically shifts right accumulator $acR by 16. -// -// flags out: --xx xx00 -void lsr16(const UDSPInstruction opc) -{ - u8 areg = (opc >> 8) & 0x1; - - u64 acc = dsp_get_long_acc(areg); - acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - acc >>= 16; - - zeroWriteBackLog(); - - dsp_set_long_acc(areg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(areg)); -} - -// ASR16 $acR -// 1001 r001 xxxx xxxx -// Arithmetically shifts right accumulator $acR by 16. -// -// flags out: --xx xx00 -void asr16(const UDSPInstruction opc) -{ - u8 areg = (opc >> 11) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - acc >>= 16; - - zeroWriteBackLog(); - - dsp_set_long_acc(areg, acc); - Update_SR_Register64(dsp_get_long_acc(areg)); -} - -// LSL $acR, #I -// 0001 010r 00ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -// -// flags out: --xx xx00 -void lsl(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; - u64 acc = dsp_get_long_acc(rreg); - - acc <<= shift; - - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// LSR $acR, #I -// 0001 010r 01ii iiii -// Logically shifts right accumulator $acR by number specified by value -// calculated by negating sign extended bits 0-6. -// -// flags out: --xx xx00 -void lsr(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x01; - u16 shift; - u64 acc = dsp_get_long_acc(rreg); - acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); - - acc >>= shift; - - dsp_set_long_acc(rreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// ASL $acR, #I -// 0001 010r 10ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -// -// flags out: --xx xx00 -void asl(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; - u64 acc = dsp_get_long_acc(rreg); - - acc <<= shift; - - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// ASR $acR, #I -// 0001 010r 11ii iiii -// Arithmetically shifts right accumulator $acR by number specified by -// value calculated by negating sign extended bits 0-6. -// -// flags out: --xx xx00 -void asr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x01; - u16 shift; - - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); - - // arithmetic shift - s64 acc = dsp_get_long_acc(dreg); - acc >>= shift; - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - -// LSRN (fixed parameters) -// 0000 0010 1100 1010 -// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M -// (if value negative, becomes left shift). -// -// flags out: --xx xx00 -void lsrn(const UDSPInstruction opc) -{ - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1); - u64 acc = dsp_get_long_acc(0); - acc &= 0x000000FFFFFFFFFFULL; - - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; - - if (shift > 0) { - acc >>= shift; - } else if (shift < 0) { - acc <<= -shift; - } - - dsp_set_long_acc(0, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(0)); -} - -// ASRN (fixed parameters) -// 0000 0010 1100 1011 -// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M -// (if value negative, becomes left shift). -// -// flags out: --xx xx00 -void asrn(const UDSPInstruction opc) -{ - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1); - s64 acc = dsp_get_long_acc(0); - - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; - - if (shift > 0) { - acc >>= shift; - } else if (shift < 0) { - acc <<= -shift; - } - - dsp_set_long_acc(0, acc); - Update_SR_Register64(dsp_get_long_acc(0)); -} - -// LSRNRX $acD, $axS.h -// 0011 01sd 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void lsrnrx(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s16 shift; - u16 axh = g_dsp.r.ax[sreg].h; - u64 acc = dsp_get_long_acc(dreg); - acc &= 0x000000FFFFFFFFFFULL; - - if ((axh & 0x3f) == 0) - shift = 0; - else if (axh & 0x40) - shift = -0x40 + (axh & 0x3f); - else - shift = axh & 0x3f; - - if (shift > 0) { - acc <<= shift; - } else if (shift < 0) { - acc >>= -shift; - } - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - -// ASRNRX $acD, $axS.h -// 0011 10sd 1xxx xxxx -// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void asrnrx(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s16 shift; - u16 axh = g_dsp.r.ax[sreg].h; - s64 acc = dsp_get_long_acc(dreg); - - if ((axh & 0x3f) == 0) - shift = 0; - else if (axh & 0x40) - shift = -0x40 + (axh & 0x3f); - else - shift = axh & 0x3f; - - if (shift > 0) { - acc <<= shift; - } else if (shift < 0) { - acc >>= -shift; - } - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - -// LSRNR $acD -// 0011 110d 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void lsrnr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1 - dreg); - u64 acc = dsp_get_long_acc(dreg); - acc &= 0x000000FFFFFFFFFFULL; - - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; - - if (shift > 0) - acc <<= shift; - else if (shift < 0) - acc >>= -shift; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - -// ASRNR $acD -// 0011 111d 1xxx xxxx -// Arithmeticaly shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void asrnr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1 - dreg); - s64 acc = dsp_get_long_acc(dreg); - - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; - - if (shift > 0) - acc <<= shift; - else if (shift < 0) - acc >>= -shift; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); -} - - -} // namespace - diff --git a/Source/Core/DSPCore/Src/DspIntBranch.cpp b/Source/Core/DSPCore/Src/DspIntBranch.cpp deleted file mode 100644 index 1113425a87..0000000000 --- a/Source/Core/DSPCore/Src/DspIntBranch.cpp +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "DSPInterpreter.h" -#include "DSPCore.h" -#include "DSPMemoryMap.h" -#include "DSPStacks.h" - -#include "DSPIntCCUtil.h" -#include "DSPIntUtil.h" - -namespace DSPInterpreter { - -// Generic call implementation -// CALLcc addressA -// 0000 0010 1011 cccc -// aaaa aaaa aaaa aaaa -// Call function if condition cc has been met. Push program counter of -// instruction following "call" to $st0. Set program counter to address -// represented by value that follows this "call" instruction. -void call(const UDSPInstruction opc) -{ - // must be outside the if. - u16 dest = dsp_fetch_code(); - if (CheckCondition(opc & 0xf)) - { - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = dest; - } -} - -// Generic callr implementation -// CALLRcc $R -// 0001 0111 rrr1 cccc -// Call function if condition cc has been met. Push program counter of -// instruction following "call" to call stack $st0. Set program counter to -// register $R. -void callr(const UDSPInstruction opc) -{ - if (CheckCondition(opc & 0xf)) - { - u8 reg = (opc >> 5) & 0x7; - u16 addr = dsp_op_read_reg(reg); - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = addr; - } -} - -// Generic if implementation -// IFcc -// 0000 0010 0111 cccc -// Execute following opcode if the condition has been met. -void ifcc(const UDSPInstruction opc) -{ - if (!CheckCondition(opc & 0xf)) - { - // skip the next opcode - we have to lookup its size. - dsp_skip_inst(); - } -} - -// Generic jmp implementation -// Jcc addressA -// 0000 0010 1001 cccc -// aaaa aaaa aaaa aaaa -// Jump to addressA if condition cc has been met. Set program counter to -// address represented by value that follows this "jmp" instruction. -void jcc(const UDSPInstruction opc) -{ - u16 dest = dsp_fetch_code(); - if (CheckCondition(opc & 0xf)) - { - g_dsp.pc = dest; - } -} - -// Generic jmpr implementation -// JMPcc $R -// 0001 0111 rrr0 cccc -// Jump to address; set program counter to a value from register $R. -void jmprcc(const UDSPInstruction opc) -{ - if (CheckCondition(opc & 0xf)) - { - u8 reg = (opc >> 5) & 0x7; - g_dsp.pc = dsp_op_read_reg(reg); - } -} - -// Generic ret implementation -// RETcc -// 0000 0010 1101 cccc -// Return from subroutine if condition cc has been met. Pops stored PC -// from call stack $st0 and sets $pc to this location. -void ret(const UDSPInstruction opc) -{ - if (CheckCondition(opc & 0xf)) - { - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - } -} - -// RTI -// 0000 0010 1111 1111 -// Return from exception. Pops stored status register $sr from data stack -// $st1 and program counter PC from call stack $st0 and sets $pc to this -// location. -void rti(const UDSPInstruction opc) -{ - g_dsp.r.sr = dsp_reg_load_stack(DSP_STACK_D); - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - -} - -// HALT -// 0000 0000 0020 0001 -// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. -void halt(const UDSPInstruction opc) -{ - g_dsp.cr |= 0x4; - g_dsp.pc--; -} - - -// LOOP handling: Loop stack is used to control execution of repeated blocks of -// instructions. Whenever there is value on stack $st2 and current PC is equal -// value at $st2, then value at stack $st3 is decremented. If value is not zero -// then PC is modified with value from call stack $st0. Otherwise values from -// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution -// continues at next opcode. -void HandleLoop() -{ - // Handle looping hardware. - const u16 rCallAddress = g_dsp.r.st[0]; - const u16 rLoopAddress = g_dsp.r.st[2]; - u16& rLoopCounter = g_dsp.r.st[3]; - - if (rLoopAddress > 0 && rLoopCounter > 0) - { - // FIXME: why -1? because we just read past it. - if (g_dsp.pc - 1 == rLoopAddress) - { - rLoopCounter--; - if (rLoopCounter > 0) - { - g_dsp.pc = rCallAddress; - } - else - { - // end of loop - dsp_reg_load_stack(0); - dsp_reg_load_stack(2); - dsp_reg_load_stack(3); - } - } - } -} - - -// LOOP $R -// 0000 0000 010r rrrr -// Repeatedly execute following opcode until counter specified by value -// from register $R reaches zero. Each execution decrement counter. Register -// $R remains unchanged. If register $R is set to zero at the beginning of loop -// then looped instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void loop(const UDSPInstruction opc) -{ - u16 reg = opc & 0x1f; - u16 cnt = dsp_op_read_reg(reg); - u16 loop_pc = g_dsp.pc; - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } -} - -// LOOPI #I -// 0001 0000 iiii iiii -// Repeatedly execute following opcode until counter specified by -// immediate value I reaches zero. Each execution decrement counter. If -// immediate value I is set to zero at the beginning of loop then looped -// instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void loopi(const UDSPInstruction opc) -{ - u16 cnt = opc & 0xff; - u16 loop_pc = g_dsp.pc; - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } -} - - -// BLOOP $R, addrA -// 0000 0000 011r rrrr -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by value from register $R reaches zero. Block ends at -// specified address addrA inclusive, ie. opcode at addrA is the last opcode -// included in loop. Counter is pushed on loop stack $st3, end of block address -// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. -// Up to 4 nested loops are allowed. -void bloop(const UDSPInstruction opc) -{ - u16 reg = opc & 0x1f; - u16 cnt = dsp_op_read_reg(reg); - u16 loop_pc = dsp_fetch_code(); - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - dsp_skip_inst(); - } -} - -// BLOOPI #I, addrA -// 0001 0001 iiii iiii -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by immediate value I reaches zero. Block ends at specified -// address addrA inclusive, ie. opcode at addrA is the last opcode included in -// loop. Counter is pushed on loop stack $st3, end of block address is pushed -// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 -// nested loops are allowed. -void bloopi(const UDSPInstruction opc) -{ - u16 cnt = opc & 0xff; - u16 loop_pc = dsp_fetch_code(); - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - dsp_skip_inst(); - } -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp deleted file mode 100644 index b43d6707b3..0000000000 --- a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "DSPInterpreter.h" - -#include "DSPMemoryMap.h" -#include "DSPIntUtil.h" - -namespace DSPInterpreter { - -// SRS @M, $(0x18+S) -// 0010 1sss mmmm mmmm -// Move value from register $(0x18+D) to data memory pointed by address -// CR[0-7] | M. That is, the upper 8 bits of the address are the -// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate. -// Note: pc+=2 in duddie's doc seems wrong -void srs(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + 0x18; - u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - dsp_dmem_write(addr, dsp_op_read_reg(reg)); -} - -// LRS $(0x18+D), @M -// 0010 0ddd mmmm mmmm -// Move value from data memory pointed by address CR[0-7] | M to register -// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits -// from CR, and the lower 8 bits are from the 8-bit immediate. -void lrs(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + 0x18; - u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - dsp_op_write_reg(reg, dsp_dmem_read(addr)); - dsp_conditional_extend_accum(reg); -} - -// LR $D, @M -// 0000 0000 110d dddd -// mmmm mmmm mmmm mmmm -// Move value from data memory pointed by address M to register $D. -// FIXME: Perform additional operation depending on destination register. -void lr(const UDSPInstruction opc) -{ - u8 reg = opc & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); - u16 val = dsp_dmem_read(addr); - dsp_op_write_reg(reg, val); - dsp_conditional_extend_accum(reg); -} - -// SR @M, $S -// 0000 0000 111s ssss -// mmmm mmmm mmmm mmmm -// Store value from register $S to a memory pointed by address M. -// FIXME: Perform additional operation depending on destination register. -void sr(const UDSPInstruction opc) -{ - u8 reg = opc & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); - u16 val = dsp_op_read_reg(reg); - dsp_dmem_write(addr, val); -} - -// SI @M, #I -// 0001 0110 mmmm mmmm -// iiii iiii iiii iiii -// Store 16-bit immediate value I to a memory location pointed by address -// M (M is 8-bit value sign extended). -void si(const UDSPInstruction opc) -{ - u16 addr = (s8)opc; - u16 imm = dsp_fetch_code(); - dsp_dmem_write(addr, imm); -} - -// LRR $D, @$S -// 0001 1000 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// FIXME: Perform additional operation depending on destination register. -void lrr(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); -} - -// LRRD $D, @$S -// 0001 1000 1ssd dddd -// Move value from data memory pointed by addressing register $S toregister $D. -// Decrement register $S. -// FIXME: Perform additional operation depending on destination register. -void lrrd(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg); -} - -// LRRI $D, @$S -// 0001 1001 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Increment register $S. -// FIXME: Perform additional operation depending on destination register. -void lrri(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg); -} - -// LRRN $D, @$S -// 0001 1001 1ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Add indexing register $(0x4+S) to register $S. -// FIXME: Perform additional operation depending on destination register. -void lrrn(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]); -} - -// SRR @$D, $S -// 0001 1010 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. -// FIXME: Perform additional operation depending on source register. -void srr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r.ar[dreg], val); -} - -// SRRD @$D, $S -// 0001 1010 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Decrement register $D. -// FIXME: Perform additional operation depending on source register. -void srrd(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r.ar[dreg], val); - g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg); -} - -// SRRI @$D, $S -// 0001 1011 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Increment register $D. -// FIXME: Perform additional operation depending on source register. -void srri(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r.ar[dreg], val); - g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg); -} - -// SRRN @$D, $S -// 0001 1011 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Add DSP_REG_IX0 register to register $D. -// FIXME: Perform additional operation depending on source register. -void srrn(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r.ar[dreg], val); - g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); -} - -// ILRR $acD.m, @$arS -// 0000 001d 0001 00ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. -void ilrr(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); -} - -// ILRRD $acD.m, @$arS -// 0000 001d 0001 01ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. -void ilrrd(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg); -} - -// ILRRI $acD.m, @$S -// 0000 001d 0001 10ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Increment addressing register $arS. -void ilrri(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg); -} - -// ILRRN $acD.m, @$arS -// 0000 001d 0001 11ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Add corresponding indexing -// register $ixS to addressing register $arS. -void ilrrn(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]); -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp deleted file mode 100644 index f2c1f921af..0000000000 --- a/Source/Core/DSPCore/Src/DspIntMisc.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - - -#include "DSPInterpreter.h" - -#include "DSPCore.h" -#include "DSPIntUtil.h" - -namespace DSPInterpreter { - -// MRR $D, $S -// 0001 11dd ddds ssss -// Move value from register $S to register $D. -// todo: Perform additional operation depending on destination register. -void mrr(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1f; - u8 dreg = (opc >> 5) & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); -} - -// LRI $D, #I -// 0000 0000 100d dddd -// iiii iiii iiii iiii -// Load immediate value I to register $D. -// -// DSPSpy discovery: This, and possibly other instructions that load a -// register, has a different behaviour in S40 mode if loaded to AC0.M: The -// value gets sign extended to the whole accumulator! This does not happen in -// S16 mode. -void lri(const UDSPInstruction opc) -{ - u8 reg = opc & DSP_REG_MASK; - u16 imm = dsp_fetch_code(); - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); -} - -// LRIS $(0x18+D), #I -// 0000 1ddd iiii iiii -// Load immediate value I (8-bit sign extended) to accumulator register. -void lris(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; - u16 imm = (s8)opc; - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); -} - -//---- - -// NX -// 1000 -000 xxxx xxxx -// No operation, but can be extended with extended opcode. -// This opcode is supposed to do nothing - it's used if you want to use -// an opcode extension but not do anything. At least according to duddie. -void nx(const UDSPInstruction opc) -{ - zeroWriteBackLog(); -} - -//---- - -// DAR $arD -// 0000 0000 0000 01dd -// Decrement address register $arD. -void dar(const UDSPInstruction opc) -{ - g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); -} - -// IAR $arD -// 0000 0000 0000 10dd -// Increment address register $arD. -void iar(const UDSPInstruction opc) -{ - g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); -} - -// SUBARN $arD -// 0000 0000 0000 11dd -// Subtract indexing register $ixD from an addressing register $arD. -// used only in IPL-NTSC ucode -void subarn(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); -} - -// ADDARN $arD, $ixS -// 0000 0000 0001 ssdd -// Adds indexing register $ixS to an addressing register $arD. -// It is critical for the Zelda ucode that this one wraps correctly. -void addarn(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - u8 sreg = (opc >> 2) & 0x3; - g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]); -} - -//---- - -// SBCLR #I -// 0001 0011 aaaa aiii -// bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void sbclr(const UDSPInstruction opc) -{ - u8 bit = (opc & 0x7) + 6; - g_dsp.r.sr &= ~(1 << bit); -} - -// SBSET #I -// 0001 0010 aaaa aiii -// Set bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void sbset(const UDSPInstruction opc) -{ - u8 bit = (opc & 0x7) + 6; - g_dsp.r.sr |= (1 << bit); -} - -// This is a bunch of flag setters, flipping bits in SR. So far so good, -// but it's harder to know exactly what effect they have. -void srbith(const UDSPInstruction opc) -{ - zeroWriteBackLog(); - switch ((opc >> 8) & 0xf) - { - // M0/M2 change the multiplier mode (it can multiply by 2 for free). - case 0xa: // M2 - g_dsp.r.sr &= ~SR_MUL_MODIFY; - break; - case 0xb: // M0 - g_dsp.r.sr |= SR_MUL_MODIFY; - break; - - // If set, treat multiplicands as unsigned. - // If clear, treat them as signed. - case 0xc: // CLR15 - g_dsp.r.sr &= ~SR_MUL_UNSIGNED; - break; - case 0xd: // SET15 - g_dsp.r.sr |= SR_MUL_UNSIGNED; - break; - - // Automatic 40-bit sign extension when loading ACx.M. - // SET40 changes something very important: see the LRI instruction above. - case 0xe: // SET16 (CLR40) - g_dsp.r.sr &= ~SR_40_MODE_BIT; - break; - - case 0xf: // SET40 - g_dsp.r.sr |= SR_40_MODE_BIT; - break; - - default: - break; - } -} - -//---- - -void unknown(const UDSPInstruction opc) -{ - ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc, g_dsp.pc); -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp deleted file mode 100644 index fbde7a645c..0000000000 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - - -// Multiplier and product register control - -#include "DSPInterpreter.h" - -#include "DSPIntCCUtil.h" -#include "DSPIntUtil.h" - -namespace DSPInterpreter { - -// Only MULX family instructions have unsigned/mixed support. -inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) -{ - s64 prod; - - if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned - prod = (u32)(a * b); - else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //mixed - prod = a * (s16)b; - else - prod = (s16)a * (s16)b; //signed - - // Conditionally multiply by 2. - if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - prod <<= 1; - - return prod; -} - -inline s64 dsp_multiply(u16 a, u16 b, u8 sign = 0) -{ - s64 prod = dsp_get_multiply_prod(a, b, sign); - return prod; -} - -inline s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0) -{ - s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); - return prod; -} - -inline s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0) -{ - s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); - return prod; -} - -inline s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2) -{ - s64 result; - - if ((axh0==0) && (axh1==0)) - result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used - else if ((axh0==0) && (axh1==1)) - result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 - else if ((axh0==1) && (axh1==0)) - result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 - else - result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used - - return result; -} - -//---- - -// CLRP -// 1000 0100 xxxx xxxx -// Clears product register $prod. -// Magic numbers taken from duddie's doc -// -// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 -// -// It's not ok, to just zero all of them, correct values should be set because of -// direct use of prod regs by AX/AXWII (look @that part of ucode). -void clrp(const UDSPInstruction opc) -{ - zeroWriteBackLog(); - - g_dsp.r.prod.l = 0x0000; - g_dsp.r.prod.m = 0xfff0; - g_dsp.r.prod.h = 0x00ff; - g_dsp.r.prod.m2 = 0x0010; -} - -// TSTPROD -// 1000 0101 xxxx xxxx -// Test prod regs value. -// -// flags out: --xx xx0x -void tstprod(const UDSPInstruction opc) -{ - s64 prod = dsp_get_long_prod(); - Update_SR_Register64(prod); - zeroWriteBackLog(); -} - -//---- - -// MOVP $acD -// 0110 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD register. -// -// flags out: --xx xx0x -void movp(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = dsp_get_long_prod(); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); -} - -// MOVNP $acD -// 0111 111d xxxx xxxx -// Moves negative of multiply product from $prod register to accumulator -// $acD register. -// -// flags out: --xx xx0x -void movnp(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - - s64 acc = -dsp_get_long_prod(); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); -} - -// MOVPZ $acD -// 1111 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD -// register and sets (rounds) $acD.l to 0 -// -// flags out: --xx xx0x -void movpz(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x01; - - s64 acc = dsp_get_long_prod_round_prodl(); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); -} - -// ADDPAXZ $acD, $axS -// 1111 10sd xxxx xxxx -// Adds secondary accumulator $axS to product register and stores result -// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0. -// -// TODO: ugly code and still small error here (+/- 1 in .m - randomly) -// flags out: --xx xx0x -void addpaxz(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - s64 oldprod = dsp_get_long_prod(); - s64 prod = dsp_get_long_prod_round_prodl(); - s64 ax = dsp_get_long_acx(sreg); - s64 res = prod + (ax & ~0xffff); - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(oldprod, res), false); -} - -//---- - -// MULAXH -// 1000 0011 xxxx xxxx -// Multiply $ax0.h by $ax0.h -void mulaxh(const UDSPInstruction opc) -{ - s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -//---- - -// MUL $axS.l, $axS.h -// 1001 s000 xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed). -void mul(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 11) & 0x1; - - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axh, axl); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MULAC $axS.l, $axS.h, $acR -// 1001 s10r xxxx xxxx -// Add product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -// -// flags out: --xx xx0x -void mulac(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; - - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULMV $axS.l, $axS.h, $acR -// 1001 s11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -// -// flags out: --xx xx0x -void mulmv(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 11) & 0x1); - - s64 acc = dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULMVZ $axS.l, $axS.h, $acR -// 1001 s01r xxxx xxxx -// Move product register to accumulator register $acR and clear (round) low part -// of accumulator register $acR.l. Multiply low part $axS.l of secondary -// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat -// them both as signed). -// -// flags out: --xx xx0x -void mulmvz(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; - - s64 acc = dsp_get_long_prod_round_prodl(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -//---- - -// MULX $ax0.S, $ax1.T -// 101s t000 xxxx xxxx -// Multiply one part $ax0 by one part $ax1. -// Part is selected by S and T bits. Zero selects low part, one selects high part. -void mulx(const UDSPInstruction opc) -{ - u8 treg = ((opc >> 11) & 0x1); - u8 sreg = ((opc >> 12) & 0x1); - - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MULXAC $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Add product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1. Part is selected by S and -// T bits. Zero selects low part, one selects high part. -// -// flags out: --xx xx0x -void mulxac(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1. Part is selected by S and -// T bits. Zero selects low part, one selects high part. -// -// flags out: --xx xx0x -void mulxmv(const UDSPInstruction opc) -{ - u8 rreg = ((opc >> 8) & 0x1); - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_prod(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULXMVZ $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Move product register to accumulator register $acR and clear (round) low part -// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 -// Part is selected by S and T bits. Zero selects low part, -// one selects high part. -// -// flags out: --xx xx0x -void mulxmvz(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_prod_round_prodl(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -//---- - -// MULC $acS.m, $axT.h -// 110s t000 xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). -void mulc(const UDSPInstruction opc) -{ - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MULCAC $acS.m, $axT.h, $acR -// 110s t10r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). Add product -// register before multiplication to accumulator $acR. -// -// flags out: --xx xx0x -void mulcac(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULCMV $acS.m, $axT.h, $acR -// 110s t11r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR. -// possible mistake in duddie's doc axT.h rather than axS.h -// -// flags out: --xx xx0x -void mulcmv(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_prod(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -// MULCMVZ $acS.m, $axT.h, $acR -// 110s t01r xxxx xxxx -// (fixed possible bug in duddie's description, s->t) -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR, set (round) low part of -// accumulator $acR.l to zero. -// -// flags out: --xx xx0x -void mulcmvz(const UDSPInstruction opc) -{ - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - s64 acc = dsp_get_long_prod_round_prodl(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); -} - -//---- - -// MADDX ax0.S ax1.T -// 1110 00st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and add result to product register. -void maddx(const UDSPInstruction opc) -{ - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_add(val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MSUBX $(0x18+S*2), $(0x19+T*2) -// 1110 01st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and subtract result from product register. -void msubx(const UDSPInstruction opc) -{ - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_sub(val1, val2); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MADDC $acS.m, $axT.h -// 1110 10st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and add result to product -// register. -void maddc(const UDSPInstruction opc) -{ - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply_add(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MSUBC $acS.m, $axT.h -// 1110 11st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and subtract result from -// product register. -void msubc(const UDSPInstruction opc) -{ - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply_sub(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MADD $axS.l, $axS.h -// 1111 001s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and add -// result to product register. -void madd(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 8) & 0x1; - - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply_add(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -// MSUB $axS.l, $axS.h -// 1111 011s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and -// subtract result from product register. -void msub(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 8) & 0x1; - - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply_sub(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp deleted file mode 100644 index fe396c6b97..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp +++ /dev/null @@ -1,1862 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "../DSPIntCCUtil.h" -#include "../DSPIntUtil.h" -#include "../DSPEmitter.h" -#include "../DSPAnalyzer.h" -#ifdef _M_X64 -#include "DSPJitUtil.h" -#endif -#include "x64Emitter.h" -#include "ABI.h" -using namespace Gen; - -// CLR $acR -// 1000 r001 xxxx xxxx -// Clears accumulator $acR -// -// flags out: --10 0100 -void DSPEmitter::clr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 reg = (opc >> 11) & 0x1; -// dsp_set_long_acc(reg, 0); - MOV(64, R(RAX), Imm64(0)); - set_long_acc(reg); -// Update_SR_Register64(0); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// CLRL $acR.l -// 1111 110r xxxx xxxx -// Clears (and rounds!) $acR.l - low 16 bits of accumulator $acR. -// -// flags out: --xx xx00 -void DSPEmitter::clrl(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 reg = (opc >> 8) & 0x1; -// s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); - get_long_acc(reg); - round_long_acc(); -// dsp_set_long_acc(reg, acc); - set_long_acc(reg); -// Update_SR_Register64(acc); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -//---- - -// ANDCF $acD.m, #I -// 0000 001r 1100 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logic AND of -// accumulator mid part $acD.m with immediate value I is equal I. -// -// flags out: -x-- ---- -void DSPEmitter::andcf(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); -// Update_SR_LZ(((val & imm) == imm) ? true : false); -// if ((val & imm) == imm) -// g_dsp.r.sr |= SR_LOGIC_ZERO; -// else -// g_dsp.r.sr &= ~SR_LOGIC_ZERO; - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - AND(16, R(RAX), Imm16(imm)); - CMP(16, R(RAX), Imm16(imm)); - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - FixupBranch notLogicZero = J_CC(CC_NE); - OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); - FixupBranch exit = J(); - SetJumpTarget(notLogicZero); - AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); - SetJumpTarget(exit); - gpr.putReg(DSP_REG_SR); - } -#else - Default(opc); -#endif -} - -// ANDF $acD.m, #I -// 0000 001r 1010 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logical AND -// operation of accumulator mid part $acD.m with immediate value I is equal -// immediate value 0. -// -// flags out: -x-- ---- -void DSPEmitter::andf(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); -// Update_SR_LZ(((val & imm) == 0) ? true : false); -// if ((val & imm) == 0) -// g_dsp.r.sr |= SR_LOGIC_ZERO; -// else -// g_dsp.r.sr &= ~SR_LOGIC_ZERO; - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - TEST(16, R(RAX), Imm16(imm)); - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - FixupBranch notLogicZero = J_CC(CC_NE); - OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); - FixupBranch exit = J(); - SetJumpTarget(notLogicZero); - AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); - SetJumpTarget(exit); - gpr.putReg(DSP_REG_SR); - } -#else - Default(opc); -#endif -} - -//---- - -// TST -// 1011 r001 xxxx xxxx -// Test accumulator %acR. -// -// flags out: --xx xx00 -void DSPEmitter::tst(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 reg = (opc >> 11) & 0x1; -// s64 acc = dsp_get_long_acc(reg); - get_long_acc(reg); -// Update_SR_Register64(acc); - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// TSTAXH $axR.h -// 1000 011r xxxx xxxx -// Test high part of secondary accumulator $axR.h. -// -// flags out: --x0 xx00 -void DSPEmitter::tstaxh(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 reg = (opc >> 8) & 0x1; -// s16 val = dsp_get_ax_h(reg); - get_ax_h(reg); -// Update_SR_Register16(val); - Update_SR_Register16(); - } -#else - Default(opc); -#endif -} - -//---- - -// CMP -// 1000 0010 xxxx xxxx -// Compares accumulator $ac0 with accumulator $ac1. -// -// flags out: x-xx xxxx -void DSPEmitter::cmp(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { -// s64 acc0 = dsp_get_long_acc(0); - get_long_acc(0, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 acc1 = dsp_get_long_acc(1); - get_long_acc(1, RDX); -// s64 res = dsp_convert_long_acc(acc0 - acc1); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 - NEG(64, R(RDX)); - Update_SR_Register64_Carry2(); - } -#else - Default(opc); -#endif -} - -// CMPAR $acS axR.h -// 1100 0001 xxxx xxxx -// Compares accumulator $acS with accumulator axR.h. -// Not described by Duddie's doc - at least not as a separate instruction. -// -// flags out: x-xx xxxx -void DSPEmitter::cmpar(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 rreg = ((opc >> 12) & 0x1); - u8 sreg = (opc >> 11) & 0x1; - -// s64 sr = dsp_get_long_acc(sreg); - get_long_acc(sreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 rr = (s16)g_dsp.r.axh[rreg]; - get_ax_h(rreg, RDX); -// rr <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = dsp_convert_long_acc(sr - rr); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry2(); - } -#else - Default(opc); -#endif -} - -// CMPI $amD, #I -// 0000 001r 1000 0000 -// iiii iiii iiii iiii -// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. -// Although flags are being set regarding whole accumulator register. -// -// flags out: x-xx xxxx -void DSPEmitter::cmpi(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 reg = (opc >> 8) & 0x1; -// s64 val = dsp_get_long_acc(reg); - get_long_acc(reg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. - u16 imm = dsp_imem_read(compilePC+1); - MOV(64, R(RDX), Imm64((s64)(s16)imm << 16)); -// s64 res = dsp_convert_long_acc(val - imm); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry2(); - } -#else - Default(opc); -#endif -} - -// CMPIS $acD, #I -// 0000 011d iiii iiii -// Compares accumulator with short immediate. Comaprison is executed -// by subtracting short immediate (8bit sign extended) from mid accumulator -// $acD.hm and computing flags based on whole accumulator $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::cmpis(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - u8 areg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 val = (s8)opc; -// val <<= 16; - MOV(64, R(RDX), Imm64((s64)(s8)opc << 16)); -// s64 res = dsp_convert_long_acc(acc - val); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry2(); - } -#else - Default(opc); -#endif -} - -//---- - -// XORR $acD.m, $axS.h -// 0011 00sd 0xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with -// high part of secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::xorr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - XOR(64, R(RAX), R(RDX)); -// g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); -// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ANDR $acD.m, $axS.h -// 0011 01sd 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::andr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - AND(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ORR $acD.m, $axS.h -// 0011 10sd 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::orr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - OR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ANDC $acD.m, $ac(1-D).m -// 0011 110d 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::andc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - AND(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ORC $acD.m, $ac(1-D).m -// 0011 111d 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m. -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::orc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - OR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// XORC $acD.m -// 0011 000d 1xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::xorc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - XOR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// NOT $acD.m -// 0011 001d 1xxx xxxx -// Invert all bits in dest reg, aka xor with 0xffff -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::notc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] ^ 0xffff; - get_acc_m(dreg, RAX); - XOR(16, R(RAX), Imm16(0xffff)); -// g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); -// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(dreg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// XORI $acD.m, #I -// 0000 001r 0010 0000 -// iiii iiii iiii iiii -// Logic exclusive or (XOR) of accumulator mid part $acD.m with -// immediate value I. -// -// flags out: --xx xx00 -void DSPEmitter::xori(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// g_dsp.r.acm[reg] ^= imm; - get_acc_m(reg, RAX); - XOR(16, R(RAX), Imm16(imm)); - set_acc_m(reg); -// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(reg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ANDI $acD.m, #I -// 0000 001r 0100 0000 -// iiii iiii iiii iiii -// Logic AND of accumulator mid part $acD.m with immediate value I. -// -// flags out: --xx xx00 -void DSPEmitter::andi(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// g_dsp.r.acm[reg] &= imm; - get_acc_m(reg, RAX); - AND(16, R(RAX), Imm16(imm)); - set_acc_m(reg); -// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(reg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -// ORI $acD.m, #I -// 0000 001r 0110 0000 -// iiii iiii iiii iiii -// Logic OR of accumulator mid part $acD.m with immediate value I. -// -// flags out: --xx xx00 -void DSPEmitter::ori(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 reg = (opc >> 8) & 0x1; - // u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); - // g_dsp.r.acm[reg] |= imm; - get_acc_m(reg, RAX); - OR(16, R(RAX), Imm16(imm)); - set_acc_m(reg); - // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_acc(reg, RSI); - Update_SR_Register16_OverS32(); - } -#else - Default(opc); -#endif -} - -//---- - -// ADDR $acD.M, $axS.L -// 0100 0ssd xxxx xxxx -// Adds register $axS.L to accumulator $acD.M register. -// -// flags out: x-xx xxxx -void DSPEmitter::addr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 ax = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RDX, SIGN); -// ax <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } - -#else - Default(opc); -#endif -} - -// ADDAX $acD, $axS -// 0100 10sd xxxx xxxx -// Adds secondary accumulator $axS to accumulator register $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::addax(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 ax = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); -// s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// ADD $acD, $ac(1-D) -// 0100 110d xxxx xxxx -// Adds accumulator $ac(1-D) to accumulator register $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::add(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s64 acc0 = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 acc1 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); -// s64 res = acc0 + acc1; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// ADDP $acD -// 0100 111d xxxx xxxx -// Adds product register to accumulator register. -// -// flags out: x-xx xxxx -void DSPEmitter::addp(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); -// s64 res = acc + prod; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// ADDAXL $acD, $axS.l -// 0111 00sd xxxx xxxx -// Adds secondary accumulator $axS.l to accumulator register $acD. -// should be unsigned values!! -// -// flags out: x-xx xxxx -void DSPEmitter::addaxl(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 sreg = (opc >> 9) & 0x1; - u8 dreg = (opc >> 8) & 0x1; - -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// u16 acx = (u16)dsp_get_ax_l(sreg); - get_ax_l(sreg, RDX); -// u64 res = acc + acx; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, (s64)res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// ADDI $amR, #I -// 0000 001r 0000 0000 -// iiii iiii iiii iiii -// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. -// -// flags out: x-xx xxxx -void DSPEmitter::addi(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 areg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 imm = (s16)dsp_fetch_code(); - s16 imm = dsp_imem_read(compilePC+1); - //imm <<= 16; - MOV(16, R(RDX), Imm16(imm)); - MOVSX(64, 16, RDX, R(RDX)); - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(areg, res); -// res = dsp_get_long_acc(areg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(areg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(areg, RAX); - } -#else - Default(opc); -#endif -} - -// ADDIS $acD, #I -// 0000 010d iiii iiii -// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. -// -// flags out: x-xx xxxx -void DSPEmitter::addis(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 imm = (s8)(u8)opc; -// imm <<= 16; - MOV(8, R(RDX), Imm8((u8)opc)); - MOVSX(64, 8, RDX, R(RDX)); - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// INCM $acsD -// 0111 010d xxxx xxxx -// Increment 24-bit mid-accumulator $acsD. -// -// flags out: x-xx xxxx -void DSPEmitter::incm(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - s64 subtract = 0x10000; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 res = acc + sub; - ADD(64, R(RAX), Imm32((u32)subtract)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, subtract, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RDX), Imm32((u32)subtract)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg); - Update_SR_Register64_Carry(); - } -#else - Default(opc); -#endif -} - -// INC $acD -// 0111 011d xxxx xxxx -// Increment accumulator $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::inc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 res = acc + 1; - ADD(64, R(RAX), Imm8(1)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RDX), Imm64(1)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg); - Update_SR_Register64_Carry(); - } -#else - Default(opc); -#endif -} - -//---- - -// SUBR $acD.M, $axS.L -// 0101 0ssd xxxx xxxx -// Subtracts register $axS.L from accumulator $acD.M register. -// -// flags out: x-xx xxxx -void DSPEmitter::subr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 ax = (s16)g_dsp.r[sreg]; - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - dsp_op_read_reg(sreg, RDX, SIGN); -// ax <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc - ax; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - NEG(64, R(RDX)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// SUBAX $acD, $axS -// 0101 10sd xxxx xxxx -// Subtracts secondary accumulator $axS from accumulator register $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::subax(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 acx = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); -// s64 res = acc - acx; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - NEG(64, R(RDX)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// SUB $acD, $ac(1-D) -// 0101 110d xxxx xxxx -// Subtracts accumulator $ac(1-D) from accumulator register $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::sub(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// s64 acc1 = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 acc2 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); -// s64 res = acc1 - acc2; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - NEG(64, R(RDX)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// SUBP $acD -// 0101 111d xxxx xxxx -// Subtracts product register from accumulator register. -// -// flags out: x-xx xxxx -void DSPEmitter::subp(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); -// s64 res = acc - prod; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - NEG(64, R(RDX)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// DECM $acsD -// 0111 100d xxxx xxxx -// Decrement 24-bit mid-accumulator $acsD. -// -// flags out: x-xx xxxx -void DSPEmitter::decm(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x01; - s64 subtract = 0x10000; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 res = acc - sub; - SUB(64, R(RAX), Imm32((u32)subtract)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -subtract, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RDX), Imm64(-subtract)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -// DEC $acD -// 0111 101d xxxx xxxx -// Decrement accumulator $acD. -// -// flags out: x-xx xxxx -void DSPEmitter::dec(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x01; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RCX); - MOV(64, R(RAX), R(RCX)); -// s64 res = acc - 1; - SUB(64, R(RAX), Imm32(1)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - MOV(64, R(RDX), Imm64(-1)); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry2(); - } - else - { - set_long_acc(dreg); - } -#else - Default(opc); -#endif -} - -//---- - -// NEG $acD -// 0111 110d xxxx xxxx -// Negate accumulator $acD. -// -// flags out: --xx xx00 -void DSPEmitter::neg(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// acc = 0 - acc; - NEG(64, R(RAX)); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// ABS $acD -// 1010 d001 xxxx xxxx -// absolute value of $acD -// -// flags out: --xx xx00 -void DSPEmitter::abs(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 11) & 0x1; - -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// if (acc < 0) acc = 0 - acc; - CMP(64, R(RAX), Imm8(0)); - FixupBranch lessThan = J_CC(CC_L); - NEG(64, R(RAX)); - set_long_acc(dreg); - SetJumpTarget(lessThan); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} -//---- - -// MOVR $acD, $axS.R -// 0110 0srd xxxx xxxx -// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. -// Sets $acD.l to 0. -// TODO: Check what happens to acD.h. -// -// flags out: --xx xx00 -void DSPEmitter::movr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 areg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - -// s64 acc = (s16)g_dsp.r[sreg]; - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - dsp_op_read_reg(sreg, RAX, SIGN); -// acc <<= 16; - SHL(64, R(RAX), Imm8(16)); -// acc &= ~0xffff; -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MOVAX $acD, $axS -// 0110 10sd xxxx xxxx -// Moves secondary accumulator $axS to accumulator $axD. -// -// flags out: --xx xx00 -void DSPEmitter::movax(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s64 acx = dsp_get_long_acx(sreg); - get_long_acx(sreg); -// dsp_set_long_acc(dreg, acx); - set_long_acc(dreg); -// Update_SR_Register64(acx); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MOV $acD, $ac(1-D) -// 0110 110d xxxx xxxx -// Moves accumulator $ax(1-D) to accumulator $axD. -// -// flags out: --x0 xx00 -void DSPEmitter::mov(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; -// u64 acc = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -//---- - -// LSL16 $acR -// 1111 000r xxxx xxxx -// Logically shifts left accumulator $acR by 16. -// -// flags out: --xx xx00 -void DSPEmitter::lsl16(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 areg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc <<= 16; - SHL(64, R(RAX), Imm8(16)); -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// LSR16 $acR -// 1111 010r xxxx xxxx -// Logically shifts right accumulator $acR by 16. -// -// flags out: --xx xx00 -void DSPEmitter::lsr16(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 areg = (opc >> 8) & 0x1; - -// u64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes -// acc >>= 16; - SHR(64, R(RAX), Imm8(16)); - AND(64, R(RAX), Imm32(0xffffff)); -// dsp_set_long_acc(areg, (s64)acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// ASR16 $acR -// 1001 r001 xxxx xxxx -// Arithmetically shifts right accumulator $acR by 16. -// -// flags out: --xx xx00 -void DSPEmitter::asr16(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 areg = (opc >> 11) & 0x1; - -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc >>= 16; - SHR(64, R(RAX), Imm8(16)); -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// LSL $acR, #I -// 0001 010r 00ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -// -// flags out: --xx xx00 -void DSPEmitter::lsl(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); - -// acc <<= shift; - SHL(64, R(RAX), Imm8((u8)shift)); - -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// LSR $acR, #I -// 0001 010r 01ii iiii -// Logically shifts right accumulator $acR by number specified by value -// calculated by negating sign extended bits 0-6. -// -// flags out: --xx xx00 -void DSPEmitter::lsr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x01; - u16 shift; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); - - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); - - if (shift) - { - // acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - SHL(64, R(RAX), Imm8(24)); - // acc >>= shift; - SHR(64, R(RAX), Imm8(shift + 24)); - } - -// dsp_set_long_acc(rreg, (s64)acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// ASL $acR, #I -// 0001 010r 10ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -// -// flags out: --xx xx00 -void DSPEmitter::asl(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); -// acc <<= shift; - SHL(64, R(RAX), Imm8((u8)shift)); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// ASR $acR, #I -// 0001 010r 11ii iiii -// Arithmetically shifts right accumulator $acR by number specified by -// value calculated by negating sign extended bits 0-6. -// -// flags out: --xx xx00 -void DSPEmitter::asr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x01; - u16 shift; - - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); - - // arithmetic shift -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// acc >>= shift; - SHR(64, R(RAX), Imm8((u8)shift)); - -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// LSRN (fixed parameters) -// 0000 0010 1100 1010 -// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M -// (if value negative, becomes left shift). -// -// flags out: --xx xx00 -void DSPEmitter::lsrn(const UDSPInstruction opc) -{ -#ifdef _M_X64 -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1); - get_acc_m(1); -// u64 acc = dsp_get_long_acc(0); - get_long_acc(0, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); - - // if ((accm & 0x3f) == 0) - // shift = 0; - // else if (accm & 0x40) - // shift = -0x40 + (accm & 0x3f); - // else - // shift = accm & 0x3f; - - // if (shift > 0) { - // acc >>= shift; - // } else if (shift < 0) { - // acc <<= -shift; - // } - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SHL(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SAR(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(0, (s64)acc); - set_long_acc(0, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(0)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -// ASRN (fixed parameters) -// 0000 0010 1100 1011 -// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M -// (if value negative, becomes left shift). -// -// flags out: --xx xx00 -void DSPEmitter::asrn(const UDSPInstruction opc) -{ -#ifdef _M_X64 -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1); - get_acc_m(1); -// s64 acc = dsp_get_long_acc(0); - get_long_acc(0, RDX); - -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; - -// if (shift > 0) { -// acc >>= shift; -// } else if (shift < 0) { -// acc <<= -shift; -// } - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SHL(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SAR(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(0, acc); -// Update_SR_Register64(dsp_get_long_acc(0)); - set_long_acc(0, RDX); - SetJumpTarget(zero); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -// LSRNRX $acD, $axS.h -// 0011 01sd 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::lsrnrx(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s16 shift; -// u16 axh = g_dsp.r.axh[sreg]; - get_ax_h(sreg); -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); - -// if ((axh & 0x3f) == 0) -// shift = 0; -// else if (axh & 0x40) -// shift = -0x40 + (axh & 0x3f); -// else -// shift = axh & 0x3f; - -// if (shift > 0) { -// acc <<= shift; -// } else if (shift < 0) { -// acc >>= -shift; -// } - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(dreg, (s64)acc); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -// ASRNRX $acD, $axS.h -// 0011 10sd 1xxx xxxx -// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::asrnrx(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s16 shift; -// u16 axh = g_dsp.r.axh[sreg]; - get_ax_h(sreg); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); - -// if ((axh & 0x3f) == 0) -// shift = 0; -// else if (axh & 0x40) -// shift = -0x40 + (axh & 0x3f); -// else -// shift = axh & 0x3f; - -// if (shift > 0) { -// acc <<= shift; -// } else if (shift < 0) { -// acc >>= -shift; -// } - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -// LSRNR $acD -// 0011 110d 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::lsrnr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1 - dreg); - get_acc_m(1 - dreg); -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); - -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; - -// if (shift > 0) -// acc <<= shift; -// else if (shift < 0) -// acc >>= -shift; - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(dreg, (s64)acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -// ASRNR $acD -// 0011 111d 1xxx xxxx -// Arithmetically shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M -// x = extension (7 bits!!) -// -// flags out: --xx xx00 -void DSPEmitter::asrnr(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1 - dreg); - get_acc_m(1 - dreg); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); - -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; - -// if (shift > 0) -// acc <<= shift; -// else if (shift < 0) -// acc >>= -shift; - - CMP(64, R(RDX), Imm8(0)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); - -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - - -//} // namespace - -// diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp deleted file mode 100644 index 4dd2476e70..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "../DSPMemoryMap.h" -#include "../DSPEmitter.h" -#include "../DSPStacks.h" -#include "../DSPAnalyzer.h" -#include "DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" - -using namespace Gen; - -template -static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter) -{ - u8 cond = opc & 0xf; - if (cond == 0xf) {// Always true. - jitCode(opc,emitter); - return; - } - FixupBranch skipCode2; - emitter.dsp_op_read_reg(DSP_REG_SR, RAX); - DSPJitRegCache c2(emitter.gpr); - switch(cond) - { - case 0x0: // GE - Greater Equal - case 0x1: // L - Less - case 0x2: // G - Greater - case 0x3: // LE - Less Equal - emitter.MOV(16, R(EDX), R(EAX)); - emitter.SHR(16, R(EDX), Imm8(3)); //SR_SIGN flag - emitter.NOT(16, R(EDX)); - emitter.SHR(16, R(EAX), Imm8(1)); //SR_OVERFLOW flag - emitter.NOT(16, R(EAX)); - emitter.XOR(16, R(EAX), R(EDX)); - if (cond < 0x2) { - emitter.TEST(16, R(EAX), Imm16(1)); - break; - } - c2 = emitter.gpr; - emitter.TEST(16, R(EAX), Imm16(1)); - - //LE: problem in here, half the tests fail - skipCode2 = emitter.J_CC(CC_NE); - //skipCode2 = emitter.J_CC((CCFlags)(CC_NE - (cond & 1))); - emitter.dsp_op_read_reg(DSP_REG_SR, RAX); - emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); - break; - case 0x4: // NZ - Not Zero - case 0x5: // Z - Zero - emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); - break; - case 0x6: // NC - Not carry - case 0x7: // C - Carry - emitter.TEST(16, R(EAX), Imm16(SR_CARRY)); - break; - case 0x8: // ? - Not over s32 - case 0x9: // ? - Over s32 - emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32)); - break; - case 0xa: // ? - case 0xb: // ? - { - //full of fail, both - emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS)); - FixupBranch skipArithZero = emitter.J_CC(CC_E); - emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); - FixupBranch setZero = emitter.J_CC(CC_NE); - - emitter.MOV(16, R(EAX), Imm16(1)); - FixupBranch toEnd = emitter.J(); - - emitter.SetJumpTarget(skipArithZero); - emitter.SetJumpTarget(setZero); - emitter.XOR(16, R(EAX), R(EAX)); - emitter.SetJumpTarget(toEnd); - emitter.SETcc(CC_E, R(EAX)); - emitter.TEST(8, R(EAX), R(EAX)); - break; - //c2 = emitter.gpr; - //emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS)); - //skipCode2 = emitter.J_CC((CCFlags)(CC_E + (cond & 1))); - //emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); - //break; - } - case 0xc: // LNZ - Logic Not Zero - case 0xd: // LZ - Logic Zero - emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO)); - break; - case 0xe: // 0 - Overflow - emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW)); - break; - } - DSPJitRegCache c1(emitter.gpr); - FixupBranch skipCode = cond == 0xe ? emitter.J_CC(CC_E) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1))); - jitCode(opc,emitter); - emitter.gpr.flushRegs(c1); - emitter.SetJumpTarget(skipCode); - if ((cond | 1) == 0x3) {// || (cond | 1) == 0xb) - emitter.gpr.flushRegs(c2); - emitter.SetJumpTarget(skipCode2); - } else { - c2.drop(); - } -} - -static void WriteBranchExit(DSPEmitter& emitter) -{ - emitter.SaveDSPRegs(); - if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - emitter.MOV(16, R(EAX), Imm16(0x1000)); - } - else - { - emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr])); - } - emitter.JMP(emitter.returnDispatcher, true); -} - -static void WriteBlockLink(DSPEmitter& emitter, u16 dest) -{ - // Jump directly to the called block if it has already been compiled. - if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) - { - if (emitter.blockLinks[dest] != 0 ) - { - emitter.gpr.flushRegs(); -#ifdef _M_IX86 // All32 - // Check if we have enough cycles to execute the next block - emitter.MOV(16, R(ESI), M(&cyclesLeft)); - emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); - emitter.MOV(16, M(&cyclesLeft), R(ESI)); -#else - // Check if we have enough cycles to execute the next block - emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); - emitter.CMP(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - emitter.SUB(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr])); -#endif - emitter.JMP(emitter.blockLinks[dest], true); - emitter.SetJumpTarget(notEnoughCycles); - } - else - { - // The destination has not been compiled yet. Add it to the list - // of blocks that this block is waiting on. - emitter.unresolvedJumps[emitter.startAddr].push_back(dest); - } - } -} - -void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) -{ - u16 dest = dsp_imem_read(emitter.compilePC + 1); - const DSPOPCTemplate *opcode = GetOpTemplate(opc); - - // If the block is unconditional, attempt to link block - if (opcode->uncond_branch) - WriteBlockLink(emitter, dest); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); -#else - emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RAX), Imm16(dest)); -#endif - WriteBranchExit(emitter); -} -// Generic jmp implementation -// Jcc addressA -// 0000 0010 1001 cccc -// aaaa aaaa aaaa aaaa -// Jump to addressA if condition cc has been met. Set program counter to -// address represented by value that follows this "jmp" instruction. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::jcc(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 2)); -#endif - ReJitConditional(opc, *this); -} - -void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) -{ - u8 reg = (opc >> 5) & 0x7; - //reg can only be DSP_REG_ARx and DSP_REG_IXx now, - //no need to handle DSP_REG_STx. - emitter.dsp_op_read_reg(reg, RAX, NONE); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&g_dsp.pc), R(EAX)); -#else - emitter.MOV(64, R(RSI), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RSI), R(RAX)); -#endif - WriteBranchExit(emitter); -} -// Generic jmpr implementation -// JMPcc $R -// 0001 0111 rrr0 cccc -// Jump to address; set program counter to a value from register $R. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::jmprcc(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif - ReJitConditional(opc, *this); -} - -void r_call(const UDSPInstruction opc, DSPEmitter& emitter) -{ - emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); - emitter.dsp_reg_store_stack(DSP_STACK_C); - u16 dest = dsp_imem_read(emitter.compilePC + 1); - const DSPOPCTemplate *opcode = GetOpTemplate(opc); - - // If the block is unconditional, attempt to link block - if (opcode->uncond_branch) - WriteBlockLink(emitter, dest); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); -#else - emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RAX), Imm16(dest)); -#endif - WriteBranchExit(emitter); -} -// Generic call implementation -// CALLcc addressA -// 0000 0010 1011 cccc -// aaaa aaaa aaaa aaaa -// Call function if condition cc has been met. Push program counter of -// instruction following "call" to $st0. Set program counter to address -// represented by value that follows this "call" instruction. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::call(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 2)); -#endif - ReJitConditional(opc, *this); -} - -void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) -{ - u8 reg = (opc >> 5) & 0x7; - emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 1)); - emitter.dsp_reg_store_stack(DSP_STACK_C); - emitter.dsp_op_read_reg(reg, RAX, NONE); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&g_dsp.pc), R(EAX)); -#else - emitter.MOV(64, R(RSI), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RSI), R(RAX)); -#endif - WriteBranchExit(emitter); -} -// Generic callr implementation -// CALLRcc $R -// 0001 0111 rrr1 cccc -// Call function if condition cc has been met. Push program counter of -// instruction following "call" to call stack $st0. Set program counter to -// register $R. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::callr(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif - ReJitConditional(opc, *this); -} - -void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter) -{ -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&g_dsp.pc), Imm16(emitter.compilePC + 1)); -#else - emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RAX), Imm16(emitter.compilePC + 1)); -#endif -} -// Generic if implementation -// IFcc -// 0000 0010 0111 cccc -// Execute following opcode if the condition has been met. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::ifcc(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16((compilePC + 1) + opTable[compilePC + 1]->size)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16((compilePC + 1) + opTable[compilePC + 1]->size)); -#endif - ReJitConditional(opc, *this); - WriteBranchExit(*this); -} - -void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) -{ - emitter.dsp_reg_load_stack(DSP_STACK_C); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(&g_dsp.pc), R(DX)); -#else - emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - emitter.MOV(16, MatR(RAX), R(DX)); -#endif - WriteBranchExit(emitter); -} - -// Generic ret implementation -// RETcc -// 0000 0010 1101 cccc -// Return from subroutine if condition cc has been met. Pops stored PC -// from call stack $st0 and sets $pc to this location. -// NOTE: Cannot use Default(opc) here because of the need to write branch exit -void DSPEmitter::ret(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif - ReJitConditional(opc, *this); -} - -// RTI -// 0000 0010 1111 1111 -// Return from exception. Pops stored status register $sr from data stack -// $st1 and program counter PC from call stack $st0 and sets $pc to this -// location. -void DSPEmitter::rti(const UDSPInstruction opc) -{ -// g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); - dsp_reg_load_stack(DSP_STACK_D); - dsp_op_write_reg(DSP_REG_SR, RDX); -// g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - dsp_reg_load_stack(DSP_STACK_C); -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), R(DX)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), R(DX)); -#endif -} - -// HALT -// 0000 0000 0020 0001 -// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. -void DSPEmitter::halt(const UDSPInstruction opc) -{ -#ifdef _M_IX86 // All32 - OR(16, M(&g_dsp.cr), Imm16(4)); -#else - MOV(64, R(RAX), ImmPtr(&g_dsp.cr)); - OR(16, MatR(RAX), Imm16(4)); -#endif - // g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - dsp_reg_load_stack(DSP_STACK_C); -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), R(DX)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), R(DX)); -#endif -} - -// LOOP handling: Loop stack is used to control execution of repeated blocks of -// instructions. Whenever there is value on stack $st2 and current PC is equal -// value at $st2, then value at stack $st3 is decremented. If value is not zero -// then PC is modified with value from call stack $st0. Otherwise values from -// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution -// continues at next opcode. -void DSPEmitter::HandleLoop() -{ -#ifdef _M_IX86 // All32 - MOVZX(32, 16, EAX, M(&g_dsp.r.st[2])); - MOVZX(32, 16, ECX, M(&g_dsp.r.st[3])); -#else - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOVZX(32, 16, EAX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[2]))); - MOVZX(32, 16, ECX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3]))); -#endif - - CMP(32, R(RCX), Imm32(0)); - FixupBranch rLoopCntG = J_CC(CC_LE, true); - CMP(16, R(RAX), Imm16(compilePC - 1)); - FixupBranch rLoopAddrG = J_CC(CC_NE, true); - -#ifdef _M_IX86 // All32 - SUB(16, M(&(g_dsp.r.st[3])), Imm16(1)); - CMP(16, M(&(g_dsp.r.st[3])), Imm16(0)); -#else - SUB(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3])), Imm16(1)); - CMP(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[3])), Imm16(0)); -#endif - - FixupBranch loadStack = J_CC(CC_LE, true); -#ifdef _M_IX86 // All32 - MOVZX(32, 16, ECX, M(&(g_dsp.r.st[0]))); - MOV(16, M(&g_dsp.pc), R(RCX)); -#else - MOVZX(32, 16, RCX, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[0]))); - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), R(RCX)); -#endif - FixupBranch loopUpdated = J(true); - - SetJumpTarget(loadStack); - dsp_reg_load_stack(0); - dsp_reg_load_stack(2); - dsp_reg_load_stack(3); - - SetJumpTarget(loopUpdated); - SetJumpTarget(rLoopAddrG); - SetJumpTarget(rLoopCntG); - -} - -// LOOP $R -// 0000 0000 010r rrrr -// Repeatedly execute following opcode until counter specified by value -// from register $R reaches zero. Each execution decrement counter. Register -// $R remains unchanged. If register $R is set to zero at the beginning of loop -// then looped instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void DSPEmitter::loop(const UDSPInstruction opc) -{ - u16 reg = opc & 0x1f; -// u16 cnt = g_dsp.r[reg]; - dsp_op_read_reg(reg, RDX, ZERO); - u16 loop_pc = compilePC + 1; - - CMP(16, R(EDX), Imm16(0)); - FixupBranch cnt = J_CC(CC_Z, true); - dsp_reg_store_stack(3); - MOV(16, R(RDX), Imm16(compilePC + 1)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - - SetJumpTarget(cnt); -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif -} - -// LOOPI #I -// 0001 0000 iiii iiii -// Repeatedly execute following opcode until counter specified by -// immediate value I reaches zero. Each execution decrement counter. If -// immediate value I is set to zero at the beginning of loop then looped -// instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void DSPEmitter::loopi(const UDSPInstruction opc) -{ - u16 cnt = opc & 0xff; - u16 loop_pc = compilePC + 1; - - if (cnt) - { - MOV(16, R(RDX), Imm16(compilePC + 1)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - MOV(16, R(RDX), Imm16(cnt)); - dsp_reg_store_stack(3); - -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); -#endif - } -} - - -// BLOOP $R, addrA -// 0000 0000 011r rrrr -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by value from register $R reaches zero. Block ends at -// specified address addrA inclusive, ie. opcode at addrA is the last opcode -// included in loop. Counter is pushed on loop stack $st3, end of block address -// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. -// Up to 4 nested loops are allowed. -void DSPEmitter::bloop(const UDSPInstruction opc) -{ - u16 reg = opc & 0x1f; -// u16 cnt = g_dsp.r[reg]; - dsp_op_read_reg(reg, RDX, ZERO); - u16 loop_pc = dsp_imem_read(compilePC + 1); - - CMP(16, R(EDX), Imm16(0)); - FixupBranch cnt = J_CC(CC_Z, true); - dsp_reg_store_stack(3); - MOV(16, R(RDX), Imm16(compilePC + 2)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 2)); -#endif - FixupBranch exit = J(); - - SetJumpTarget(cnt); - // g_dsp.pc = loop_pc; - // dsp_skip_inst(); -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[loop_pc]->size)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); -#endif - DSPJitRegCache c(gpr); - WriteBranchExit(*this); - gpr.flushRegs(c,false); - SetJumpTarget(exit); -} - -// BLOOPI #I, addrA -// 0001 0001 iiii iiii -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by immediate value I reaches zero. Block ends at specified -// address addrA inclusive, ie. opcode at addrA is the last opcode included in -// loop. Counter is pushed on loop stack $st3, end of block address is pushed -// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 -// nested loops are allowed. -void DSPEmitter::bloopi(const UDSPInstruction opc) -{ - u16 cnt = opc & 0xff; -// u16 loop_pc = dsp_fetch_code(); - u16 loop_pc = dsp_imem_read(compilePC + 1); - - if (cnt) - { - MOV(16, R(RDX), Imm16(compilePC + 2)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - MOV(16, R(RDX), Imm16(cnt)); - dsp_reg_store_stack(3); - -#ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 2)); -#endif - } - else - { -// g_dsp.pc = loop_pc; -// dsp_skip_inst(); -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[loop_pc]->size)); -#else - MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); -#endif - WriteBranchExit(*this); - } -} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp deleted file mode 100644 index 620c2a2c43..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - - -// HELPER FUNCTIONS - -#include "../DSPIntUtil.h" -#include "../DSPEmitter.h" -#include "x64Emitter.h" -#include "ABI.h" -using namespace Gen; - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register(Gen::X64Reg val) -{ -#ifdef _M_X64 - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - // // 0x04 - // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; - CMP(64, R(val), Imm8(0)); - FixupBranch notZero = J_CC(CC_NZ); - OR(16, sr_reg, Imm16(SR_ARITH_ZERO)); - SetJumpTarget(notZero); - - // // 0x08 - // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; - CMP(64, R(val), Imm8(0)); - FixupBranch greaterThanEqual = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_SIGN)); - SetJumpTarget(greaterThanEqual); - - // // 0x10 - // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; - MOVSX(64, 32, RDX, R(val)); - CMP(64, R(RDX), R(val)); - FixupBranch noOverS32 = J_CC(CC_E); - OR(16, sr_reg, Imm16(SR_OVER_S32)); - SetJumpTarget(noOverS32); - - // // 0x20 - Checks if top bits of m are equal - // if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) - AND(32, R(val), Imm32(0xc0000000)); - CMP(32, R(val), Imm32(0)); - FixupBranch zeroC = J_CC(CC_E); - CMP(32, R(val), Imm32(0xc0000000)); - FixupBranch cC = J_CC(CC_NE); - SetJumpTarget(zeroC); - // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; - OR(16, sr_reg, Imm16(SR_TOP2BITS)); - SetJumpTarget(cC); - gpr.putReg(DSP_REG_SR); -#endif -} - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register64(Gen::X64Reg val) -{ -#ifdef _M_X64 -// g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - gpr.putReg(DSP_REG_SR); - Update_SR_Register(val); -#endif -} - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register64_Carry(Gen::X64Reg val) -{ -#ifdef _M_X64 - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - - CMP(64, R(RCX), R(val)); - - // 0x01 - // g_dsp.r[DSP_REG_SR] |= SR_CARRY; - // Carry = (acc>res) - FixupBranch noCarry = J_CC(CC_BE); - OR(16, sr_reg, Imm16(SR_CARRY)); - SetJumpTarget(noCarry); - - // 0x02 and 0x80 - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; - // Overflow = ((acc ^ res) & (ax ^ res)) < 0 - XOR(64, R(RCX), R(val)); - XOR(64, R(RDX), R(val)); - AND(64, R(RCX), R(RDX)); - CMP(64, R(RCX), Imm8(0)); - FixupBranch noOverflow = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); - SetJumpTarget(noOverflow); - - gpr.putReg(DSP_REG_SR); - Update_SR_Register(val); -#endif -} - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register64_Carry2(Gen::X64Reg val) -{ -#ifdef _M_X64 - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - - CMP(64, R(RCX), R(val)); - - // 0x01 - // g_dsp.r[DSP_REG_SR] |= SR_CARRY; - // Carry2 = (acc>=res) - FixupBranch noCarry2 = J_CC(CC_B); - OR(16, sr_reg, Imm16(SR_CARRY)); - SetJumpTarget(noCarry2); - - // 0x02 and 0x80 - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; - // Overflow = ((acc ^ res) & (ax ^ res)) < 0 - XOR(64, R(RCX), R(val)); - XOR(64, R(RDX), R(val)); - AND(64, R(RCX), R(RDX)); - CMP(64, R(RCX), Imm8(0)); - FixupBranch noOverflow = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); - SetJumpTarget(noOverflow); - gpr.putReg(DSP_REG_SR); - - Update_SR_Register(); -#endif -} - -//void DSPEmitter::Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) -//{ - -// // 0x20 - Checks if top bits of m are equal -// if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) -// { -// g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; -// } -//} - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register16(Gen::X64Reg val) -{ -#ifdef _M_X64 - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - - // // 0x04 - // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; - CMP(64, R(val), Imm8(0)); - FixupBranch notZero = J_CC(CC_NZ); - OR(16, sr_reg, Imm16(SR_ARITH_ZERO)); - SetJumpTarget(notZero); - - // // 0x08 - // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; - CMP(64, R(val), Imm8(0)); - FixupBranch greaterThanEqual = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_SIGN)); - SetJumpTarget(greaterThanEqual); - - // // 0x20 - Checks if top bits of m are equal - // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - //AND(32, R(val), Imm32(0xc0000000)); - SHR(16, R(val), Imm8(14)); - CMP(16, R(val), Imm16(0)); - FixupBranch nZero = J_CC(CC_NE); - OR(16, sr_reg, Imm16(SR_TOP2BITS)); - FixupBranch cC = J(); - SetJumpTarget(nZero); - CMP(16, R(val), Imm16(3)); - FixupBranch notThree = J_CC(CC_NE); - // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; - OR(16, sr_reg, Imm16(SR_TOP2BITS)); - SetJumpTarget(notThree); - SetJumpTarget(cC); - gpr.putReg(DSP_REG_SR); -#endif -} - -// In: RAX: s64 _Value -// In: RCX: 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val) -{ -#ifdef _M_X64 - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - - // // 0x10 - // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; - MOVSX(64, 32, RSI, R(val)); - CMP(64, R(RSI), R(val)); - FixupBranch noOverS32 = J_CC(CC_E); - OR(16, sr_reg, Imm16(SR_OVER_S32)); - SetJumpTarget(noOverS32); - - gpr.putReg(DSP_REG_SR); - // // 0x20 - Checks if top bits of m are equal - // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - //AND(32, R(val), Imm32(0xc0000000)); - Update_SR_Register16(val); -#endif -} - -//void DSPEmitter::Update_SR_LZ(bool value) { - -// if (value == true) -// g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO; -// else -// g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO; -//} - -//inline int GetMultiplyModifier() -//{ -// return (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)?1:2; -//} - -//inline bool isCarry() { -// return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false; -//} - -//inline bool isOverflow() { -// return (g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) ? true : false; -//} - -//inline bool isOverS32() { -// return (g_dsp.r[DSP_REG_SR] & SR_OVER_S32) ? true : false; -//} - -//inline bool isLess() { -// return (!(g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) != !(g_dsp.r[DSP_REG_SR] & SR_SIGN)); -//} - -//inline bool isZero() { -// return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false; -//} - -//inline bool isLogicZero() { -// return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) ? true : false; -//} - -//inline bool isConditionA() { -// return (((g_dsp.r[DSP_REG_SR] & SR_OVER_S32) || (g_dsp.r[DSP_REG_SR] & SR_TOP2BITS)) && !(g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO)) ? true : false; -//} - -//see DSPCore.h for flags -//bool CheckCondition(u8 _Condition) -//{ -// switch (_Condition & 0xf) -// { -// case 0xf: // Always true. -// return true; -// case 0x0: // GE - Greater Equal -// return !isLess(); -// case 0x1: // L - Less -// return isLess(); -// case 0x2: // G - Greater -// return !isLess() && !isZero(); -// case 0x3: // LE - Less Equal -// return isLess() || isZero(); -// case 0x4: // NZ - Not Zero -// return !isZero(); -// case 0x5: // Z - Zero -// return isZero(); -// case 0x6: // NC - Not carry -// return !isCarry(); -// case 0x7: // C - Carry -// return isCarry(); -// case 0x8: // ? - Not over s32 -// return !isOverS32(); -// case 0x9: // ? - Over s32 -// return isOverS32(); -// case 0xa: // ? -// return isConditionA(); -// case 0xb: // ? -// return !isConditionA(); -// case 0xc: // LNZ - Logic Not Zero -// return !isLogicZero(); -// case 0xd: // LZ - Logic Zero -// return isLogicZero(); -// case 0xe: // 0 - Overflow -// return isOverflow(); -// default: -// return true; -// } -//} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp deleted file mode 100644 index 084385e2e4..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ -#include "../DSPMemoryMap.h" -#include "../DSPEmitter.h" -#include "DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" - -using namespace Gen; - -/* It is safe to directly write to the address registers as they are - neither read not written by any extendable opcode. The same is true - for memory accesses. - It probably even is safe to write to all registers except for - SR, ACx.x, AXx.x and PROD, which may be modified by the main op. - - This code uses EBX to keep the values of the registers written by - the extended op so the main op can still access the old values. - storeIndex and storeIndex2 control where the lower and upper 16bits - of EBX are written to. Additionally, the upper 16bits can contain the - original SR so we can do sign extension in 40bit mode. There is only - the 'ld family of opcodes writing to two registers at the same time, - and those always are AXx.x, thus no need to leave space for SR for - sign extension. - */ - -// DR $arR -// xxxx xxxx 0000 01rr -// Decrement addressing register $arR. -void DSPEmitter::dr(const UDSPInstruction opc) { - decrement_addr_reg(opc & 0x3); -} - -// IR $arR -// xxxx xxxx 0000 10rr -// Increment addressing register $arR. -void DSPEmitter::ir(const UDSPInstruction opc) { - increment_addr_reg(opc & 0x3); -} - -// NR $arR -// xxxx xxxx 0000 11rr -// Add corresponding indexing register $ixR to addressing register $arR. -void DSPEmitter::nr(const UDSPInstruction opc) { - u8 reg = opc & 0x3; - - increase_addr_reg(reg); -} - -// MV $axD.D, $acS.S -// xxxx xxxx 0001 ddss -// Move value of $acS.S to the $axD.D. -void DSPEmitter::mv(const UDSPInstruction opc) -{ - u8 sreg = (opc & 0x3) + DSP_REG_ACL0; - u8 dreg = ((opc >> 2) & 0x3); - pushExtValueFromReg(dreg + DSP_REG_AXL0, sreg); -} - -// S @$arD, $acS.S -// xxxx xxxx 001s s0dd -// Store value of $acS.S in the memory pointed by register $arD. -// Post increment register $arD. -void DSPEmitter::s(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - // u16 addr = g_dsp.r[dest]; - dsp_op_read_reg(dreg, RAX, ZERO); - dsp_op_read_reg(sreg, RCX, ZERO); - // u16 val = g_dsp.r[src]; - dmem_write(); - increment_addr_reg(dreg); -} - -// SN @$arD, $acS.S -// xxxx xxxx 001s s1dd -// Store value of register $acS.S in the memory pointed by register $arD. -// Add indexing register $ixD to register $arD. -void DSPEmitter::sn(const UDSPInstruction opc) -{ - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - dsp_op_read_reg(dreg, RAX, ZERO); - dsp_op_read_reg(sreg, RCX, ZERO); - dmem_write(); - increase_addr_reg(dreg); -} - -// L $axD.D, @$arS -// xxxx xxxx 01dd d0ss -// Load $axD.D/$acD.D with value from memory pointed by register $arS. -// Post increment register $arS. -void DSPEmitter::l(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; //AX?.?, AC?.[LM] - - pushExtValueFromMem(dreg, sreg); - - if (dreg >= DSP_REG_ACM0) { - //save SR too, so we can decide later. - //even if only for one bit, can only - //store (up to) two registers in EBX, - //so store all of SR -#ifdef _M_IX86 // All32 - MOV(16, R(EAX), M(&g_dsp.r.sr)); -#else - MOV(64, R(RAX), ImmPtr(&g_dsp.r.sr)); - MOV(16, R(RAX), MatR(RAX)); -#endif - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); - } - - increment_addr_reg(sreg); -} - -// LN $axD.D, @$arS -// xxxx xxxx 01dd d0ss -// Load $axD.D/$acD.D with value from memory pointed by register $arS. -// Add indexing register register $ixS to register $arS. -void DSPEmitter::ln(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - - pushExtValueFromMem(dreg, sreg); - - if (dreg >= DSP_REG_ACM0) { - //save SR too, so we can decide later. - //even if only for one bit, can only - //store (up to) two registers in EBX, - //so store all of SR -#ifdef _M_IX86 // All32 - MOV(16, R(EAX), M(&g_dsp.r.sr)); -#else - MOV(64, R(RAX), ImmPtr(&g_dsp.r.sr)); - MOV(16, R(RAX), MatR(RAX)); -#endif - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); - } - - increase_addr_reg(sreg); -} - -// LS $axD.D, $acS.m -// xxxx xxxx 10dd 000s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Increment both $ar0 and $ar3. -void DSPEmitter::ls(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR0); - - increment_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); -} - - -// LSN $axD.D, $acS.m -// xxxx xxxx 10dd 010s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix0 to addressing -// register $ar0 and increment $ar3. -void DSPEmitter::lsn(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR0); - - increment_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0); -} - -// LSM $axD.D, $acS.m -// xxxx xxxx 10dd 100s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix3 to addressing -// register $ar3 and increment $ar0. -void DSPEmitter::lsm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR0); - - increase_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); -} - -// LSMN $axD.D, $acS.m -// xxxx xxxx 10dd 110s -// Load register $axD.D with value from memory pointed by register -// $ar0. Store value from register $acS.m to memory location pointed by -// register $ar3. Add corresponding indexing register $ix0 to addressing -// register $ar0 and add corresponding indexing register $ix3 to addressing -// register $ar3. -void DSPEmitter::lsnm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR0); - - increase_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0); -} - -// SL $acS.m, $axD.D -// xxxx xxxx 10dd 001s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Increment both $ar0 and $ar3. -void DSPEmitter::sl(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR3); - - increment_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); -} - -// SLN $acS.m, $axD.D -// xxxx xxxx 10dd 011s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 -// and increment $ar3. -void DSPEmitter::sln(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR3); - - increment_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0); -} - -// SLM $acS.m, $axD.D -// xxxx xxxx 10dd 101s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3 -// and increment $ar0. -void DSPEmitter::slm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR3); - - increase_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); -} - -// SLMN $acS.m, $axD.D -// xxxx xxxx 10dd 111s -// Store value from register $acS.m to memory location pointed by register -// $ar0. Load register $axD.D with value from memory pointed by register -// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0 -// and add corresponding indexing register $ix3 to addressing register $ar3. -void DSPEmitter::slnm(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - get_acc_m(sreg, ECX, false); - dmem_write(); - - pushExtValueFromMem(dreg, DSP_REG_AR3); - - increase_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0); -} - -// LD $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 00ss -// example for "nx'ld $AX0.L, $AX1.L, @$AR3" -// Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 -// to AX0.L. Increments AR0 and AR3. If AR0 and AR3 point into the same -// memory page (upper 6 bits of addr are the same -> games are not doing that!) -// then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. If AR0 -// points into an invalid memory page (ie 0x2000), then AX0.H keeps its old -// value. (not implemented yet) If AR3 points into an invalid memory page, then -// AX0.L gets the same value as AX0.H. (not implemented yet) -void DSPEmitter::ld(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - - // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.flushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increment_addr_reg(sreg); - - } else { - pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); - - //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(dreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE, true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); - gpr.flushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increment_addr_reg(dreg); - } - - increment_addr_reg(DSP_REG_AR3); -} - -// LDN $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 01ss -void DSPEmitter::ldn(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.flushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increase_addr_reg(sreg); - } else { - pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); - - //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(dreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); - gpr.flushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increase_addr_reg(dreg); - } - - increment_addr_reg(DSP_REG_AR3); -} - -// LDM $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 10ss -void DSPEmitter::ldm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.flushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increment_addr_reg(sreg); - } else { - pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); - - //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(dreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); - gpr.flushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increment_addr_reg(dreg); - } - - increase_addr_reg(DSP_REG_AR3); -} - -// LDNM $ax0.d, $ax1.r, @$arS -// xxxx xxxx 11dr 11ss -void DSPEmitter::ldnm(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; - - if (sreg != DSP_REG_AR3) { - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.flushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increase_addr_reg(sreg); - } else { - pushExtValueFromMem(rreg + DSP_REG_AXH0, dreg); - - //if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(dreg, RSI, NONE); - dsp_op_read_reg(DSP_REG_AR3, RDI, NONE); - SHR(16, R(ESI), Imm8(10)); - SHR(16, R(EDI), Imm8(10)); - DSPJitRegCache c(gpr); - CMP(16, R(ESI), R(EDI)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, dreg); - gpr.flushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.flushRegs(c); - SetJumpTarget(after); - - increase_addr_reg(dreg); - } - - increase_addr_reg(DSP_REG_AR3); -} - - -// Push value from g_dsp.r[sreg] into EBX and stores the destinationindex in -// storeIndex -void DSPEmitter::pushExtValueFromReg(u16 dreg, u16 sreg) { - dsp_op_read_reg(sreg, RBX, ZERO); - storeIndex = dreg; -} - -void DSPEmitter::pushExtValueFromMem(u16 dreg, u16 sreg) { - // u16 addr = g_dsp.r[addr]; - dsp_op_read_reg(sreg, RCX, ZERO); - dmem_read(); - MOVZX(32, 16, EBX, R(EAX)); - - storeIndex = dreg; -} - -void DSPEmitter::pushExtValueFromMem2(u16 dreg, u16 sreg) { - // u16 addr = g_dsp.r[addr]; - dsp_op_read_reg(sreg, RCX, ZERO); - dmem_read(); - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); - - storeIndex2 = dreg; -} - -void DSPEmitter::popExtValueToReg() { - // in practise, we rarely ever have a non-NX main op - // with an extended op, so the OR here is either - // not run (storeIndex == -1) or ends up OR'ing - // EBX with 0 (becoming the MOV we have here) - // nakee wants to keep it clean, so lets do that. - // [nakeee] the or case never happens in real - // [nakeee] it's just how the hardware works so we added it - if (storeIndex != -1) { - dsp_op_write_reg(storeIndex, RBX); - if (storeIndex >= DSP_REG_ACM0 && storeIndex2 == -1) { - TEST(32, R(EBX), Imm32(SR_40_MODE_BIT << 16)); - FixupBranch not_40bit = J_CC(CC_Z); - DSPJitRegCache c(gpr); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //u16 val = g_dsp.r[reg]; - MOVSX(32, 16, EAX, R(EBX)); - SHR(32, R(EAX), Imm8(16)); - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(storeIndex - DSP_REG_ACM0, R(RAX)); - set_acc_l(storeIndex - DSP_REG_ACM0, Imm16(0)); - //} - gpr.flushRegs(c); - SetJumpTarget(not_40bit); - } - } - - storeIndex = -1; - - if (storeIndex2 != -1) { - SHR(32, R(EBX), Imm8(16)); - dsp_op_write_reg(storeIndex2, RBX); - } - storeIndex2 = -1; -} - -// This function is being called in the main op after all input regs were read -// and before it writes into any regs. This way we can always use bitwise or to -// apply the ext command output, because if the main op didn't change the value -// then 0 | ext output = ext output and if it did then bitwise or is still the -// right thing to do -//this is only needed as long as we do fallback for ext ops -void DSPEmitter::zeroWriteBackLog(const UDSPInstruction opc) -{ - const DSPOPCTemplate *tinst = GetOpTemplate(opc); - - // Call extended - if (!tinst->extended) - return; - - if ((opc >> 12) == 0x3) { - if (! extOpTable[opc & 0x7F]->jitFunc) - { - SaveDSPRegs(); - ABI_CallFunction((void*)::zeroWriteBackLog); - LoadDSPRegs(); - } - } else { - if (! extOpTable[opc & 0xFF]->jitFunc) - { - SaveDSPRegs(); - ABI_CallFunction((void*)::zeroWriteBackLog); - LoadDSPRegs(); - } - } - return; -} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitLoadStore.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitLoadStore.cpp deleted file mode 100644 index bd4a320bb3..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitLoadStore.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "../DSPIntCCUtil.h" -#include "../DSPIntUtil.h" -#include "../DSPEmitter.h" -#include "DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" -using namespace Gen; - -// SRS @M, $(0x18+S) -// 0010 1sss mmmm mmmm -// Move value from register $(0x18+D) to data memory pointed by address -// CR[0-7] | M. That is, the upper 8 bits of the address are the -// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate. -// Note: pc+=2 in duddie's doc seems wrong -void DSPEmitter::srs(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + 0x18; - //u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - dsp_op_read_reg(reg, RCX, ZERO); - dsp_op_read_reg(DSP_REG_CR, RAX, ZERO); - SHL(16, R(EAX), Imm8(8)); - OR(8, R(EAX), Imm8(opc & 0xFF)); - dmem_write(); -} - -// LRS $(0x18+D), @M -// 0010 0ddd mmmm mmmm -// Move value from data memory pointed by address CR[0-7] | M to register -// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits -// from CR, and the lower 8 bits are from the 8-bit immediate. -void DSPEmitter::lrs(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + 0x18; - //u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF); - dsp_op_read_reg(DSP_REG_CR, RCX, ZERO); - SHL(16, R(ECX), Imm8(8)); - OR(8, R(ECX), Imm8(opc & 0xFF)); - dmem_read(); - dsp_op_write_reg(reg, RAX); - dsp_conditional_extend_accum(reg); -} - -// LR $D, @M -// 0000 0000 110d dddd -// mmmm mmmm mmmm mmmm -// Move value from data memory pointed by address M to register $D. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lr(const UDSPInstruction opc) -{ - int reg = opc & DSP_REG_MASK; - u16 address = dsp_imem_read(compilePC + 1); - dmem_read_imm(address); - dsp_op_write_reg(reg, EAX); - dsp_conditional_extend_accum(reg); -} - -// SR @M, $S -// 0000 0000 111s ssss -// mmmm mmmm mmmm mmmm -// Store value from register $S to a memory pointed by address M. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::sr(const UDSPInstruction opc) -{ - u8 reg = opc & DSP_REG_MASK; - u16 address = dsp_imem_read(compilePC + 1); - dsp_op_read_reg(reg, ECX); - dmem_write_imm(address); -} - -// SI @M, #I -// 0001 0110 mmmm mmmm -// iiii iiii iiii iiii -// Store 16-bit immediate value I to a memory location pointed by address -// M (M is 8-bit value sign extended). -void DSPEmitter::si(const UDSPInstruction opc) -{ - u16 address = (s8)opc; - u16 imm = dsp_imem_read(compilePC + 1); - MOV(32, R(ECX), Imm32((u32)imm)); - dmem_write_imm(address); -} - -// LRR $D, @$S -// 0001 1000 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lrr(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dmem_read(); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); -} - -// LRRD $D, @$S -// 0001 1000 1ssd dddd -// Move value from data memory pointed by addressing register $S toregister $D. -// Decrement register $S. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lrrd(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dmem_read(); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - decrement_addr_reg(sreg); -} - -// LRRI $D, @$S -// 0001 1001 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Increment register $S. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lrri(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dmem_read(); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - increment_addr_reg(sreg); -} - -// LRRN $D, @$S -// 0001 1001 1ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Add indexing register $(0x4+S) to register $S. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lrrn(const UDSPInstruction opc) -{ - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dmem_read(); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - increase_addr_reg(sreg); -} - -// SRR @$D, $S -// 0001 1010 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. -// FIXME: Perform additional operation depending on source register. -void DSPEmitter::srr(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(); -} - -// SRRD @$D, $S -// 0001 1010 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Decrement register $D. -// FIXME: Perform additional operation depending on source register. -void DSPEmitter::srrd(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(); - decrement_addr_reg(dreg); -} - -// SRRI @$D, $S -// 0001 1011 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Increment register $D. -// FIXME: Perform additional operation depending on source register. -void DSPEmitter::srri(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(); - increment_addr_reg(dreg); -} - -// SRRN @$D, $S -// 0001 1011 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Add DSP_REG_IX0 register to register $D. -// FIXME: Perform additional operation depending on source register. -void DSPEmitter::srrn(const UDSPInstruction opc) -{ - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; - - dsp_op_read_reg(sreg, ECX); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(); - increase_addr_reg(dreg); -} - -// ILRR $acD.m, @$arS -// 0000 001d 0001 00ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. -void DSPEmitter::ilrr(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; - - dsp_op_read_reg(reg, RCX, ZERO); - imem_read(); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg); -} - -// ILRRD $acD.m, @$arS -// 0000 001d 0001 01ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. -void DSPEmitter::ilrrd(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; - - dsp_op_read_reg(reg, RCX, ZERO); - imem_read(); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg); - decrement_addr_reg(reg); -} - -// ILRRI $acD.m, @$S -// 0000 001d 0001 10ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Increment addressing register $arS. -void DSPEmitter::ilrri(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; - - dsp_op_read_reg(reg, RCX, ZERO); - imem_read(); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg); - increment_addr_reg(reg); -} - -// ILRRN $acD.m, @$arS -// 0000 001d 0001 11ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Add corresponding indexing -// register $ixS to addressing register $arS. -void DSPEmitter::ilrrn(const UDSPInstruction opc) -{ - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; - - dsp_op_read_reg(reg, RCX, ZERO); - imem_read(); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg); - increase_addr_reg(reg); -} - diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp deleted file mode 100644 index 2c8cc790de..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - - -#include "../DSPIntUtil.h" -#include "../DSPEmitter.h" -#include "DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" -using namespace Gen; - -//clobbers: -//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] -//CX = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] -//expects: -//R11 = &g_dsp.r -void DSPEmitter::dsp_reg_stack_push(int stack_reg) -{ - //g_dsp.reg_stack_ptr[stack_reg]++; - //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; -#ifdef _M_IX86 // All32 - MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); -#else - MOV(8, R(AL), MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg], - &g_dsp.r))); -#endif - ADD(8, R(AL), Imm8(1)); - AND(8, R(AL), Imm8(DSP_STACK_MASK)); -#ifdef _M_IX86 // All32 - MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); -#else - MOV(8, MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg], - &g_dsp.r)), R(AL)); -#endif - - //g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg]; -#ifdef _M_IX86 // All32 - MOV(16, R(CX), M(&g_dsp.r.st[stack_reg])); - MOVZX(32, 8, EAX, R(AL)); - MOV(16, MComplex(EAX, EAX, 1, (u32)&g_dsp.reg_stack[stack_reg][0]), R(CX)); -#else - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOV(16, R(CX), MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg]))); - MOVZX(64, 8, RAX, R(AL)); - MOV(16, MComplex(R11, RAX, 2, - PtrOffset(&g_dsp.reg_stack[stack_reg][0],&g_dsp.r)), - R(CX)); -#endif -} - -//clobbers: -//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] -//CX = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] -//expects: -//R11 = &g_dsp.r -void DSPEmitter::dsp_reg_stack_pop(int stack_reg) -{ - //g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; -#ifdef _M_IX86 // All32 - MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); -#else - MOV(8, R(AL), - MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg],&g_dsp.r))); -#endif -#ifdef _M_IX86 // All32 - MOVZX(32, 8, EAX, R(AL)); - MOV(16, R(CX), MComplex(EAX, EAX, 1, (u32)&g_dsp.reg_stack[stack_reg][0])); - MOV(16, M(&g_dsp.r.st[stack_reg]), R(CX)); -#else - MOVZX(64, 8, RAX, R(AL)); - MOV(16, R(CX), MComplex(R11, RAX, 2, - PtrOffset(&g_dsp.reg_stack[stack_reg][0], - &g_dsp.r))); - MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), R(CX)); -#endif - - //g_dsp.reg_stack_ptr[stack_reg]--; - //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; - SUB(8, R(AL), Imm8(1)); - AND(8, R(AL), Imm8(DSP_STACK_MASK)); -#ifdef _M_IX86 // All32 - MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); -#else - MOV(8, MDisp(R11, PtrOffset(&g_dsp.reg_stack_ptr[stack_reg],&g_dsp.r)), - R(AL)); -#endif -} - - -void DSPEmitter::dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg) -{ - if (host_sreg != EDX) { - MOV(16, R(EDX), R(host_sreg)); - } - dsp_reg_stack_push(stack_reg); - //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.r.st[stack_reg]), R(EDX)); -#else - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), R(EDX)); -#endif -} - -void DSPEmitter::dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg) -{ - //u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg]; -#ifdef _M_IX86 // All32 - MOV(16, R(EDX), M(&g_dsp.r.st[stack_reg])); -#else - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOV(16, R(EDX), MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg]))); -#endif - dsp_reg_stack_pop(stack_reg); - if (host_dreg != EDX) { - MOV(16, R(host_dreg), R(EDX)); - } -} - -void DSPEmitter::dsp_reg_store_stack_imm(int stack_reg, u16 val) -{ - dsp_reg_stack_push(stack_reg); - //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.r.st[stack_reg]), Imm16(val)); -#else - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - MOV(16, MDisp(R11, STRUCT_OFFSET(g_dsp.r, st[stack_reg])), Imm16(val)); -#endif -} - -void DSPEmitter::dsp_op_write_reg(int reg, Gen::X64Reg host_sreg) -{ - switch (reg & 0x1f) { - // 8-bit sign extended registers. - case DSP_REG_ACH0: - case DSP_REG_ACH1: - gpr.writeReg(reg, R(host_sreg)); - break; - - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack(reg - DSP_REG_ST0, host_sreg); - break; - - default: - gpr.writeReg(reg, R(host_sreg)); - break; - } -} - -void DSPEmitter::dsp_op_write_reg_imm(int reg, u16 val) -{ - switch (reg & 0x1f) { - // 8-bit sign extended registers. Should look at prod.h too... - case DSP_REG_ACH0: - case DSP_REG_ACH1: - gpr.writeReg(reg, Imm16((u16)(s16)(s8)(u8)val)); - break; - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack_imm(reg - DSP_REG_ST0, val); - break; - - default: - gpr.writeReg(reg, Imm16(val)); - break; - } -} - -void DSPEmitter::dsp_conditional_extend_accum(int reg) -{ - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - DSPJitRegCache c(gpr); - TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); - FixupBranch not_40bit = J_CC(CC_Z,true); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //u16 val = g_dsp.r[reg]; - get_acc_m(reg - DSP_REG_ACM0, EAX); - SHR(32, R(EAX), Imm8(16)); - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(reg - DSP_REG_ACM0, R(RAX)); - set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); - //} - gpr.flushRegs(c); - SetJumpTarget(not_40bit); - gpr.putReg(DSP_REG_SR); - } - } -} - -void DSPEmitter::dsp_conditional_extend_accum_imm(int reg, u16 val) -{ - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - DSPJitRegCache c(gpr); - TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); - FixupBranch not_40bit = J_CC(CC_Z); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(reg - DSP_REG_ACM0, Imm16((val & 0x8000)?0xffff:0x0000)); - set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); - //} - gpr.flushRegs(c); - SetJumpTarget(not_40bit); - gpr.putReg(DSP_REG_SR); - } - } -} - -void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend) -{ - switch (reg & 0x1f) { - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); - switch(extend) { - case SIGN: -#ifdef _M_IX86 // All32 - MOVSX(32, 16, host_dreg, R(host_dreg)); -#else - MOVSX(64, 16, host_dreg, R(host_dreg)); -#endif - break; - case ZERO: -#ifdef _M_IX86 // All32 - MOVZX(32, 16, host_dreg, R(host_dreg)); -#else - MOVZX(64, 16, host_dreg, R(host_dreg)); -#endif - break; - case NONE: - default: - break; - } - return; - default: - gpr.readReg(reg, host_dreg, extend); - return; - } -} - -// MRR $D, $S -// 0001 11dd ddds ssss -// Move value from register $S to register $D. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::mrr(const UDSPInstruction opc) -{ - u8 sreg = opc & 0x1f; - u8 dreg = (opc >> 5) & 0x1f; - - dsp_op_read_reg(sreg, EDX); - dsp_op_write_reg(dreg, EDX); - dsp_conditional_extend_accum(dreg); -} - -// LRI $D, #I -// 0000 0000 100d dddd -// iiii iiii iiii iiii -// Load immediate value I to register $D. -// -// DSPSpy discovery: This, and possibly other instructions that load a -// register, has a different behaviour in S40 mode if loaded to AC0.M: The -// value gets sign extended to the whole accumulator! This does not happen in -// S16 mode. -void DSPEmitter::lri(const UDSPInstruction opc) -{ - u8 reg = opc & DSP_REG_MASK; - u16 imm = dsp_imem_read(compilePC+1); - dsp_op_write_reg_imm(reg, imm); - dsp_conditional_extend_accum_imm(reg, imm); -} - -// LRIS $(0x18+D), #I -// 0000 1ddd iiii iiii -// Load immediate value I (8-bit sign extended) to accumulator register. -// FIXME: Perform additional operation depending on destination register. -void DSPEmitter::lris(const UDSPInstruction opc) -{ - u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; - u16 imm = (s8)opc; - dsp_op_write_reg_imm(reg, imm); - dsp_conditional_extend_accum_imm(reg, imm); -} - -//---- - -// NX -// 1000 -000 xxxx xxxx -// No operation, but can be extended with extended opcode. -// This opcode is supposed to do nothing - it's used if you want to use -// an opcode extension but not do anything. At least according to duddie. -void DSPEmitter::nx(const UDSPInstruction opc) -{ - zeroWriteBackLog(opc); -} - -//---- - -// DAR $arD -// 0000 0000 0000 01dd -// Decrement address register $arD. -void DSPEmitter::dar(const UDSPInstruction opc) -{ - // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); - decrement_addr_reg(opc & 0x3); - -} - -// IAR $arD -// 0000 0000 0000 10dd -// Increment address register $arD. -void DSPEmitter::iar(const UDSPInstruction opc) -{ - // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); - increment_addr_reg(opc & 0x3); -} - -// SUBARN $arD -// 0000 0000 0000 11dd -// Subtract indexing register $ixD from an addressing register $arD. -// used only in IPL-NTSC ucode -void DSPEmitter::subarn(const UDSPInstruction opc) -{ - // u8 dreg = opc & 0x3; - // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); - decrease_addr_reg(opc & 0x3); -} - -// ADDARN $arD, $ixS -// 0000 0000 0001 ssdd -// Adds indexing register $ixS to an addressing register $arD. -// It is critical for the Zelda ucode that this one wraps correctly. -void DSPEmitter::addarn(const UDSPInstruction opc) -{ - // u8 dreg = opc & 0x3; - // u8 sreg = (opc >> 2) & 0x3; - // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); - - // From looking around it is always called with the matching index register - increase_addr_reg(opc & 0x3); -} - -//---- - - -void DSPEmitter::setCompileSR(u16 bit) { - - // g_dsp.r[DSP_REG_SR] |= bit - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - OR(16, sr_reg, Imm16(bit)); - gpr.putReg(DSP_REG_SR); - - compileSR |= bit; -} - -void DSPEmitter::clrCompileSR(u16 bit) { - - // g_dsp.r[DSP_REG_SR] &= bit - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~bit)); - gpr.putReg(DSP_REG_SR); - - compileSR &= ~bit; -} -// SBCLR #I -// 0001 0011 aaaa aiii -// bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void DSPEmitter::sbclr(const UDSPInstruction opc) -{ - u8 bit = (opc & 0x7) + 6; - - clrCompileSR(1 << bit); -} - -// SBSET #I -// 0001 0010 aaaa aiii -// Set bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void DSPEmitter::sbset(const UDSPInstruction opc) -{ - u8 bit = (opc & 0x7) + 6; - - setCompileSR(1 << bit); -} - -// 1000 1bbb xxxx xxxx, bbb >= 010 -// This is a bunch of flag setters, flipping bits in SR. So far so good, -// but it's harder to know exactly what effect they have. -void DSPEmitter::srbith(const UDSPInstruction opc) -{ - zeroWriteBackLog(opc); - switch ((opc >> 8) & 0xf) - { - // M0/M2 change the multiplier mode (it can multiply by 2 for free). - case 0xa: // M2 - clrCompileSR(SR_MUL_MODIFY); - break; - case 0xb: // M0 - setCompileSR(SR_MUL_MODIFY); - break; - - // If set, treat multiplicands as unsigned. - // If clear, treat them as signed. - case 0xc: // CLR15 - clrCompileSR(SR_MUL_UNSIGNED); - break; - case 0xd: // SET15 - setCompileSR(SR_MUL_UNSIGNED); - break; - - // Automatic 40-bit sign extension when loading ACx.M. - // SET40 changes something very important: see the LRI instruction above. - case 0xe: // SET16 (CLR40) - clrCompileSR(SR_40_MODE_BIT); - break; - - case 0xf: // SET40 - setCompileSR(SR_40_MODE_BIT); - break; - - default: - break; - } -} - diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp deleted file mode 100644 index 0004b33396..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp +++ /dev/null @@ -1,885 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - - -// Multiplier and product register control - -#include "../DSPIntUtil.h" -#include "../DSPEmitter.h" -#include "../DSPAnalyzer.h" -#ifdef _M_X64 -#include "DSPJitUtil.h" -#endif -#include "x64Emitter.h" -#include "ABI.h" -using namespace Gen; - -// Returns s64 in RAX -// In: RSI = s16 a, RDI = s16 b -void DSPEmitter::multiply() -{ -#ifdef _M_X64 -// prod = (s16)a * (s16)b; //signed - MOV(64, R(EAX), R(RDI)); - IMUL(64, R(ESI)); - -// Conditionally multiply by 2. -// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); - FixupBranch noMult2 = J_CC(CC_NZ); -// prod <<= 1; - SHL(64, R(EAX), Imm8(1)); - SetJumpTarget(noMult2); - gpr.putReg(DSP_REG_SR); -// return prod; -#endif -} - -// Returns s64 in RAX -// Clobbers RDX -void DSPEmitter::multiply_add() -{ -// s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); - multiply(); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); -// return prod; -} - -// Returns s64 in RAX -// Clobbers RDX -void DSPEmitter::multiply_sub() -{ -// s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); - multiply(); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - SUB(64, R(RAX), R(RDX)); -// return prod; -} - -// Only MULX family instructions have unsigned/mixed support. -// Returns s64 in EAX -// In: RSI = s16 a, RDI = s16 b -// Returns s64 in RAX -void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1) -{ -// s64 result; - -// if ((axh0==0) && (axh1==0)) -// result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used -// else if ((axh0==0) && (axh1==1)) -// result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 -// else if ((axh0==1) && (axh1==0)) -// result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 -// else -// result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used - - -// if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned - OpArg sr_reg; - gpr.getReg(DSP_REG_SR,sr_reg); - TEST(16, sr_reg, Imm16(SR_MUL_UNSIGNED)); - FixupBranch unsignedMul = J_CC(CC_NZ); - // prod = (s16)a * (s16)b; //signed - MOVSX(64, 16, RAX, R(RDI)); - IMUL(64, R(RSI)); - FixupBranch signedMul = J(); - - SetJumpTarget(unsignedMul); - if ((axh0==0) && (axh1==0)) - { - // unsigned support ON if both ax?.l regs are used -// prod = (u32)(a * b); - MOVZX(64, 16, RSI, R(RSI)); - MOVZX(64, 16, RAX, R(RDI)); - MUL(64, R(RSI)); - } - else if ((axh0==0) && (axh1==1)) - { - // mixed support ON (u16)axl.0 * (s16)axh.1 -// prod = a * (s16)b; - MOVZX(64, 16, RAX, R(RSI)); - IMUL(64, R(RDI)); - } - else if ((axh0==1) && (axh1==0)) - { - // mixed support ON (u16)axl.1 * (s16)axh.0 -// prod = (s16)a * b; - MOVZX(64, 16, RAX, R(RDI)); - IMUL(64, R(RSI)); - } - else - { - // unsigned support OFF if both ax?.h regs are used -// prod = (s16)a * (s16)b; //signed - MOVSX(64, 16, RAX, R(RDI)); - IMUL(64, R(RSI)); - } - - SetJumpTarget(signedMul); - - // Conditionally multiply by 2. -// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); - FixupBranch noMult2 = J_CC(CC_NZ); -// prod <<= 1; - SHL(64, R(RAX), Imm8(1)); - SetJumpTarget(noMult2); - gpr.putReg(DSP_REG_SR); -// return prod; -} - -//---- - -// CLRP -// 1000 0100 xxxx xxxx -// Clears product register $prod. -// Magic numbers taken from duddie's doc - -// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 - -// It's not ok, to just zero all of them, correct values should be set because of -// direct use of prod regs by AX/AXWII (look @that part of ucode). -void DSPEmitter::clrp(const UDSPInstruction opc) -{ -#ifdef _M_X64 -// g_dsp.r[DSP_REG_PRODL] = 0x0000; -// g_dsp.r[DSP_REG_PRODM] = 0xfff0; -// g_dsp.r[DSP_REG_PRODH] = 0x00ff; -// g_dsp.r[DSP_REG_PRODM2] = 0x0010; - //64bit move to memory does not work. use 2 32bits - MOV(32, MDisp(R11, STRUCT_OFFSET(g_dsp.r, prod.val)+0), Imm32(0xfff00000U)); - MOV(32, MDisp(R11, STRUCT_OFFSET(g_dsp.r, prod.val)+4), Imm32(0x001000ffU)); -#else - Default(opc); -#endif -} - -// TSTPROD -// 1000 0101 xxxx xxxx -// Test prod regs value. - -// flags out: --xx xx0x -void DSPEmitter::tstprod(const UDSPInstruction opc) -{ -#ifdef _M_X64 - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { -// s64 prod = dsp_get_long_prod(); - get_long_prod(); -// Update_SR_Register64(prod); - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -//---- - -// MOVP $acD -// 0110 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD register. - -// flags out: --xx xx0x -void DSPEmitter::movp(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s64 acc = dsp_get_long_prod(); - get_long_prod(); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MOVNP $acD -// 0111 111d xxxx xxxx -// Moves negative of multiply product from $prod register to accumulator -// $acD register. - -// flags out: --xx xx0x -void DSPEmitter::movnp(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - -// s64 acc = -dsp_get_long_prod(); - get_long_prod(); - NEG(64, R(EAX)); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MOVPZ $acD -// 1111 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD -// register and sets (rounds) $acD.l to 0 - -// flags out: --xx xx0x -void DSPEmitter::movpz(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x01; - -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// ADDPAXZ $acD, $axS -// 1111 10sd xxxx xxxx -// Adds secondary accumulator $axS to product register and stores result -// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0. - -// flags out: --xx xx0x -void DSPEmitter::addpaxz(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// s64 ax = dsp_get_long_acx(sreg); - get_long_acx(sreg, RCX); - MOV(64, R(RDI), R(RCX)); -// s64 res = prod + (ax & ~0xffff); - MOV(64, R(RDX), Imm64(~0xffff)); - AND(64, R(RDI), R(RDX)); -// s64 prod = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); - ADD(64, R(RAX), R(RDI)); - -// s64 oldprod = dsp_get_long_prod(); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(oldprod, res), false); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - get_long_prod(RDX); - MOV(64, R(RSI), R(RAX)); - set_long_acc(dreg, RSI); - Update_SR_Register64_Carry(); - } - else - { - set_long_acc(dreg, RAX); - } -#else - Default(opc); -#endif -} - -//---- - -// MULAXH -// 1000 0011 xxxx xxxx -// Multiply $ax0.h by $ax0.h -void DSPEmitter::mulaxh(const UDSPInstruction opc) -{ -#ifdef _M_X64 -// s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); - dsp_op_read_reg(DSP_REG_AXH0, RSI, SIGN); - MOV(64, R(RDI), R(RSI)); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -//---- - -// MUL $axS.l, $axS.h -// 1001 s000 xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed). -void DSPEmitter::mul(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 sreg = (opc >> 11) & 0x1; - -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); -// s64 prod = dsp_multiply(axh, axl); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MULAC $axS.l, $axS.h, $acR -// 1001 s10r xxxx xxxx -// Add product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). - -// flags out: --xx xx0x -void DSPEmitter::mulac(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; - -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - get_long_acc(rreg); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); - PUSH(64, R(RAX)); -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); -// s64 prod = dsp_multiply(axl, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MULMV $axS.l, $axS.h, $acR -// 1001 s11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). - -// flags out: --xx xx0x -void DSPEmitter::mulmv(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - -// s64 acc = dsp_get_long_prod(); - get_long_prod(); - PUSH(64, R(RAX)); - mul(opc); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MULMVZ $axS.l, $axS.h, $acR -// 1001 s01r xxxx xxxx -// Move product register to accumulator register $acR and clear (round) low part -// of accumulator register $acR.l. Multiply low part $axS.l of secondary -// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat -// them both as signed). - -// flags out: --xx xx0x -void DSPEmitter::mulmvz(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(RDX); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, RDX); - mul(opc); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RDX); - } -#else - Default(opc); -#endif -} - -//---- - -// MULX $ax0.S, $ax1.T -// 101s t000 xxxx xxxx -// Multiply one part $ax0 by one part $ax1. -// Part is selected by S and T bits. Zero selects low part, one selects high part. -void DSPEmitter::mulx(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = ((opc >> 11) & 0x1); - u8 sreg = ((opc >> 12) & 0x1); - - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MULXAC $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Add product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1. Part is selected by S and -// T bits. Zero selects low part, one selects high part. - -// flags out: --xx xx0x -void DSPEmitter::mulxac(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - get_long_acc(rreg, RCX); - get_long_prod(); - ADD(64, R(RCX), R(RAX)); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); - -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, RCX); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RCX); - } -#else - Default(opc); -#endif -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1. Part is selected by S and -// T bits. Zero selects low part, one selects high part. - -// flags out: --xx xx0x -void DSPEmitter::mulxmv(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = ((opc >> 8) & 0x1); - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// s64 acc = dsp_get_long_prod(); - get_long_prod(RCX); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); - -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, RCX); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RCX); - } -#else - Default(opc); -#endif -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Move product register to accumulator register $acR and clear (round) low part -// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 -// Part is selected by S and T bits. Zero selects low part, -// one selects high part. - -// flags out: --xx xx0x -void DSPEmitter::mulxmvz(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(RCX); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); - -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, RCX); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(RCX); - } -#else - Default(opc); -#endif -} - -//---- - -// MULC $acS.m, $axT.h -// 110s t000 xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). -void DSPEmitter::mulc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MULCAC $acS.m, $axT.h, $acR -// 110s t10r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). Add product -// register before multiplication to accumulator $acR. - -// flags out: --xx xx0x -void DSPEmitter::mulcac(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - get_long_acc(rreg); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MULCMV $acS.m, $axT.h, $acR -// 110s t11r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR. -// possible mistake in duddie's doc axT.h rather than axS.h - -// flags out: --xx xx0x -void DSPEmitter::mulcmv(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - -// s64 acc = dsp_get_long_prod(); - get_long_prod(); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -// MULCMVZ $acS.m, $axT.h, $acR -// 110s t01r xxxx xxxx -// (fixed possible bug in duddie's description, s->t) -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR, set (round) low part of -// accumulator $acR.l to zero. - -// flags out: --xx xx0x -void DSPEmitter::mulcmvz(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; - - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - { - Update_SR_Register64(); - } -#else - Default(opc); -#endif -} - -//---- - -// MADDX ax0.S ax1.T -// 1110 00st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and add result to product register. -void DSPEmitter::maddx(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); - // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); - // s64 prod = dsp_multiply_add(val1, val2); - multiply_add(); - // dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MSUBX $(0x18+S*2), $(0x19+T*2) -// 1110 01st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and subtract result from product register. -void DSPEmitter::msubx(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - - // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RSI, SIGN); - // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RDI, SIGN); - // s64 prod = dsp_multiply_sub(val1, val2); - multiply_sub(); - // dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MADDC $acS.m, $axT.h -// 1110 10st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and add result to product -// register. -void DSPEmitter::maddc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply_add(accm, axh); - multiply_add(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MSUBC $acS.m, $axT.h -// 1110 11st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and subtract result from -// product register. -void DSPEmitter::msubc(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ESI); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RDI, SIGN); -// s64 prod = dsp_multiply_sub(accm, axh); - multiply_sub(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MADD $axS.l, $axS.h -// 1111 001s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and add -// result to product register. -void DSPEmitter::madd(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 sreg = (opc >> 8) & 0x1; - -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); -// s64 prod = dsp_multiply_add(axl, axh); - multiply_add(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} - -// MSUB $axS.l, $axS.h -// 1111 011s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and -// subtract result from product register. -void DSPEmitter::msub(const UDSPInstruction opc) -{ -#ifdef _M_X64 - u8 sreg = (opc >> 8) & 0x1; - -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RSI, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RDI, SIGN); -// s64 prod = dsp_multiply_sub(axl, axh); - multiply_sub(); -// dsp_set_long_prod(prod); - set_long_prod(); -#else - Default(opc); -#endif -} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.cpp deleted file mode 100644 index 5a08db1982..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.cpp +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (C) 2011 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DSPJitRegCache.h" -#include "../DSPEmitter.h" -#include "../DSPMemoryMap.h" - -using namespace Gen; - -static u16 *reg_ptr(int reg) { - switch(reg) { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return &g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return &g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return &g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return &g_dsp.r.st[reg - DSP_REG_ST0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return &g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: return &g_dsp.r.cr; - case DSP_REG_SR: return &g_dsp.r.sr; - case DSP_REG_PRODL: return &g_dsp.r.prod.l; - case DSP_REG_PRODM: return &g_dsp.r.prod.m; - case DSP_REG_PRODH: return &g_dsp.r.prod.h; - case DSP_REG_PRODM2: return &g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return &g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return &g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return &g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return &g_dsp.r.ac[reg - DSP_REG_ACM0].m; - default: - _assert_msg_(DSPLLE, 0, "cannot happen"); - return NULL; - } -} - -#define ROTATED_REG_ACCS -//#undef ROTATED_REG_ACCS - -DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter) - : emitter(_emitter), temporary(false), merged(false) { - for(unsigned int i = 0; i < NUMXREGS; i++) { - xregs[i].guest_reg = DSP_REG_STATIC; - } - xregs[RSP].guest_reg = DSP_REG_STATIC;//stack pointer - xregs[RBX].guest_reg = DSP_REG_STATIC;//extended op backing store - - xregs[RBP].guest_reg = DSP_REG_NONE;//definitely usable in dsplle because - //all external calls are protected - -#ifdef _M_X64 - xregs[R8].guest_reg = DSP_REG_STATIC;//acc0 - xregs[R9].guest_reg = DSP_REG_STATIC;//acc1 - xregs[R10].guest_reg = DSP_REG_NONE; - xregs[R11].guest_reg = DSP_REG_STATIC;//&g_dsp.r - xregs[R12].guest_reg = DSP_REG_STATIC;//used for cycle counting - xregs[R13].guest_reg = DSP_REG_NONE; - xregs[R14].guest_reg = DSP_REG_NONE; - xregs[R15].guest_reg = DSP_REG_NONE; -#endif - -#ifdef _M_X64 - acc[0].host_reg = R8; - acc[0].shift = 0; - acc[0].dirty = false; - acc[0].used = false; - acc[0].tmp_reg = INVALID_REG; - - acc[1].host_reg = R9; - acc[1].shift = 0; - acc[1].dirty = false; - acc[1].used = false; - acc[1].tmp_reg = INVALID_REG; -#endif - for(unsigned int i = 0; i < 32; i++) { - regs[i].mem = reg_ptr(i); - regs[i].size = 2; - } -#ifdef _M_X64 - regs[DSP_REG_ACC0_64].mem = &g_dsp.r.ac[0].val; - regs[DSP_REG_ACC0_64].size = 8; - regs[DSP_REG_ACC1_64].mem = &g_dsp.r.ac[1].val; - regs[DSP_REG_ACC1_64].size = 8; - regs[DSP_REG_PROD_64].mem = &g_dsp.r.prod.val; - regs[DSP_REG_PROD_64].size = 8; -#endif - regs[DSP_REG_AX0_32].mem = &g_dsp.r.ax[0].val; - regs[DSP_REG_AX0_32].size = 4; - regs[DSP_REG_AX1_32].mem = &g_dsp.r.ax[1].val; - regs[DSP_REG_AX1_32].size = 4; - for(unsigned int i = 0; i < DSP_REG_MAX_MEM_BACKED+1; i++) { - regs[i].dirty = false; -#ifdef _M_IX86 // All32 - regs[i].loc = M(regs[i].mem); -#else - regs[i].loc = MDisp(R11, PtrOffset(regs[i].mem, &g_dsp.r)); -#endif - } -} - -DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache &cache) - : emitter(cache.emitter), temporary(true), merged(false) -{ - memcpy(xregs,cache.xregs,sizeof(xregs)); -#ifdef _M_X64 - memcpy(acc,cache.acc,sizeof(acc)); -#endif - memcpy(regs,cache.regs,sizeof(regs)); -} - -DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache &cache) -{ - _assert_msg_(DSPLLE, &emitter == &cache.emitter, "emitter does not match"); - _assert_msg_(DSPLLE, temporary, "register cache not temporary??"); - merged = false; - memcpy(xregs,cache.xregs,sizeof(xregs)); -#ifdef _M_X64 - memcpy(acc,cache.acc,sizeof(acc)); -#endif - memcpy(regs,cache.regs,sizeof(regs)); - - return *this; -} - -DSPJitRegCache::~DSPJitRegCache() -{ - _assert_msg_(DSPLLE, !temporary || merged, "temporary cache not merged"); -} - -void DSPJitRegCache::flushRegs(DSPJitRegCache &cache, bool emit) -{ - cache.merged = true; - -#ifdef _M_X64 - for(unsigned int i = 0; i < 2; i++) { - if (acc[i].shift > cache.acc[i].shift) { - if (emit) - emitter.ROL(64, R(acc[i].host_reg), - Imm8(acc[i].shift-cache.acc[i].shift)); - acc[i].shift = cache.acc[i].shift; - } - if (acc[i].shift < cache.acc[i].shift) { - if (emit) - emitter.ROR(64, R(acc[i].host_reg), - Imm8(cache.acc[i].shift-acc[i].shift)); - acc[i].shift = cache.acc[i].shift; - } - } -#endif -} - -void DSPJitRegCache::drop() -{ - merged = true; -} - -void DSPJitRegCache::flushRegs() -{ - //also needs to undo any dynamic changes to static allocated regs - //this should have the same effect as - //merge(DSPJitRegCache(emitter)); -#ifdef _M_X64 -#ifdef ROTATED_REG_ACCS - for(unsigned int i = 0; i < 2; i++) { - if (acc[i].shift > 0) { - emitter.ROL(64, R(acc[i].host_reg), - Imm8(acc[i].shift)); - acc[i].shift = 0; - } - _assert_msg_(DSPLLE, !acc[i].used, - "accumulator still in use"); - if (acc[i].used) - emitter.INT3(); - } -#endif -#endif -} - -static u64 ebp_store; - -void DSPJitRegCache::loadStaticRegs() -{ -#ifdef _M_X64 -#ifdef ROTATED_REG_ACCS - emitter.MOV(64, R(R8), MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[0].val))); - emitter.MOV(64, R(R9), MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[1].val))); -#endif - emitter.MOV(64, MDisp(R11, PtrOffset(&ebp_store, &g_dsp.r)), R(RBP)); -#else - emitter.MOV(32, M(&ebp_store), R(EBP)); -#endif -} - -void DSPJitRegCache::saveStaticRegs() -{ - flushRegs(); -#ifdef _M_X64 -#ifdef ROTATED_REG_ACCS - emitter.MOV(64, MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[0].val)), R(R8)); - emitter.MOV(64, MDisp(R11, STRUCT_OFFSET(g_dsp.r, ac[1].val)), R(R9)); -#endif - emitter.MOV(64, R(RBP), MDisp(R11, PtrOffset(&ebp_store, &g_dsp.r))); -#else - emitter.MOV(32, R(EBP), M(&ebp_store)); -#endif -} - -void DSPJitRegCache::getReg(int reg, OpArg &oparg, bool load) -{ - switch(reg) { -#ifdef _M_X64 -#ifdef ROTATED_REG_ACCS - case DSP_REG_ACH0: - case DSP_REG_ACH1: - { - _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACH0].used, - "accumulator already in use"); - if (acc[reg-DSP_REG_ACH0].used) - emitter.INT3(); - oparg = R(acc[reg-DSP_REG_ACH0].host_reg); - if (acc[reg-DSP_REG_ACH0].shift < 32) { - emitter.ROR(64, oparg, Imm8(32-acc[reg-DSP_REG_ACH0].shift)); - acc[reg-DSP_REG_ACH0].shift = 32; - } - - acc[reg-DSP_REG_ACH0].used = true; - } - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACM0].used, - "accumulator already in use"); - if (acc[reg-DSP_REG_ACM0].used) - emitter.INT3(); - oparg = R(acc[reg-DSP_REG_ACM0].host_reg); - if (acc[reg-DSP_REG_ACM0].shift < 16) { - emitter.ROR(64, oparg, Imm8(16-acc[reg-DSP_REG_ACM0].shift)); - acc[reg-DSP_REG_ACM0].shift = 16; - } - if (acc[reg-DSP_REG_ACM0].shift > 16) { - emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACM0].shift-16)); - acc[reg-DSP_REG_ACM0].shift = 16; - } - acc[reg-DSP_REG_ACM0].used = true; - } - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - { - _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACL0].used, - "accumulator already in use"); - if (acc[reg-DSP_REG_ACL0].used) - emitter.INT3(); - oparg = R(acc[reg-DSP_REG_ACL0].host_reg); - if (acc[reg-DSP_REG_ACL0].shift > 0) { - emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACL0].shift)); - acc[reg-DSP_REG_ACL0].shift = 0; - } - acc[reg-DSP_REG_ACL0].used = true; - } - break; - case DSP_REG_ACC0_64: - case DSP_REG_ACC1_64: - { - if (acc[reg-DSP_REG_ACC0_64].used) - emitter.INT3(); - _assert_msg_(DSPLLE, !acc[reg-DSP_REG_ACC0_64].used, - "accumulator already in use"); - oparg = R(acc[reg-DSP_REG_ACC0_64].host_reg); - if (load) { - if (acc[reg-DSP_REG_ACC0_64].shift > 0) { - emitter.ROL(64, oparg, Imm8(acc[reg-DSP_REG_ACC0_64].shift)); - } - emitter.SHL(64, oparg, Imm8(64-40));//sign extend - emitter.SAR(64, oparg, Imm8(64-40)); - } - //don't bother to rotate if caller replaces all data - acc[reg-DSP_REG_ACC0_64].shift = 0; - acc[reg-DSP_REG_ACC0_64].used = true; - } - break; -#endif -#endif - default: - { -/* - getFreeXReg(reg[reg].host_reg); - X64Reg tmp = reg[reg].host_reg; - oparg = R(tmp); - - if (load) { - u16 *regp = reg_ptr(reg); -#ifdef _M_IX86 // All32 - emitter.MOV(16, oparg, M(regp)); -#else - emitter.MOV(16, oparg, MDisp(R11, PtrOffset(regp, &g_dsp.r))); -#endif - } -*/ - oparg = regs[reg].loc; //when loading/storing from/to mem, need to consider regs[reg].size - } - break; - } -} - -void DSPJitRegCache::putReg(int reg, bool dirty) -{ - switch(reg) { -#ifdef _M_X64 -#ifdef ROTATED_REG_ACCS - case DSP_REG_ACH0: - case DSP_REG_ACH1: - { - - if (dirty) { - if (acc[reg-DSP_REG_ACH0].shift > 0) { - emitter.ROL(64, R(acc[reg-DSP_REG_ACH0].host_reg), - Imm8(acc[reg-DSP_REG_ACH0].shift)); - acc[reg-DSP_REG_ACH0].shift = 0; - } - emitter.SHL(64, R(acc[reg-DSP_REG_ACH0].host_reg), Imm8(64-40));//sign extend - emitter.SAR(64, R(acc[reg-DSP_REG_ACH0].host_reg), Imm8(64-40)); - } - acc[reg-DSP_REG_ACH0].used = false; - } - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - acc[reg-DSP_REG_ACM0].used = false; - } - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - acc[reg-DSP_REG_ACL0].used = false; - break; - case DSP_REG_ACC0_64: - case DSP_REG_ACC1_64: - { - if (dirty) { - OpArg _reg = R(acc[reg-DSP_REG_ACC0_64].host_reg); - - emitter.SHL(64, _reg, Imm8(64-40));//sign extend - emitter.SAR(64, _reg, Imm8(64-40)); - } - acc[reg-DSP_REG_ACC0_64].used = false; - } - break; -#else - case DSP_REG_ACH0: - case DSP_REG_ACH1: - { - //need to fix in memory for now. - u16 *regp = reg_ptr(reg); - OpArg mem; - mem = MDisp(R11,PtrOffset(regp,&g_dsp.r)); - X64Reg tmp; - getFreeXReg(tmp); - // sign extend from the bottom 8 bits. - emitter.MOVSX(16, 8, tmp, mem); - emitter.MOV(16, mem, R(tmp)); - putXReg(tmp); - } - break; -#endif -#else - case DSP_REG_ACH0: - case DSP_REG_ACH1: - { - //need to fix in memory for now. - u16 *regp = reg_ptr(reg); - OpArg mem; - mem = M(regp); - X64Reg tmp; - getFreeXReg(tmp); - // sign extend from the bottom 8 bits. - emitter.MOVSX(16, 8, tmp, mem); - emitter.MOV(16, mem, R(tmp)); - putXReg(tmp); - } - break; -#endif - default: - { -/* - X64Reg tmp = reg[reg].host_reg; - - if(dirty) { - u16 *regp = reg_ptr(reg); -#ifdef _M_IX86 // All32 - emitter.MOV(16, M(dregp), R(tmp)); -#else - emitter.MOV(16, MDisp(R11, PtrOffset(dregp, &g_dsp.r)), R(tmp)); -#endif - } -*/ - } - break; - } -} - -void DSPJitRegCache::readReg(int sreg, X64Reg host_dreg, DSPJitSignExtend extend) -{ - OpArg reg; - getReg(sreg, reg); - switch(regs[sreg].size) { - case 2: - switch(extend) { -#ifdef _M_X64 - case SIGN: emitter.MOVSX(64, 16, host_dreg, reg); break; - case ZERO: emitter.MOVZX(64, 16, host_dreg, reg); break; -#else - case SIGN: emitter.MOVSX(32, 16, host_dreg, reg); break; - case ZERO: emitter.MOVZX(32, 16, host_dreg, reg); break; -#endif - case NONE: emitter.MOV(16, R(host_dreg), reg); break; - } - break; - case 4: -#ifdef _M_X64 - switch(extend) { - case SIGN: emitter.MOVSX(64, 32, host_dreg, reg); break; - case ZERO: emitter.MOVZX(64, 32, host_dreg, reg); break; - case NONE: emitter.MOV(32, R(host_dreg), reg); break; - } -#else - emitter.MOV(32, R(host_dreg), reg); break; -#endif - break; -#ifdef _M_X64 - case 8: - emitter.MOV(64, R(host_dreg), reg); break; - break; -#endif - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - putReg(sreg, false); -} - -void DSPJitRegCache::writeReg(int dreg, OpArg arg) -{ - OpArg reg; - getReg(dreg, reg, false); - switch(regs[dreg].size) { - case 2: emitter.MOV(16, reg, arg); break; - case 4: emitter.MOV(32, reg, arg); break; -#ifdef _M_X64 - case 8: emitter.MOV(64, reg, arg); break; -#endif - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - putReg(dreg, true); -} - -X64Reg DSPJitRegCache::spillXReg() -{ - //todo: implement - return INVALID_REG; -} - -void DSPJitRegCache::spillXReg(X64Reg reg) -{ - //todo: implement -} - -X64Reg DSPJitRegCache::findFreeXReg() -{ - int i; - for(i = 0; i < NUMXREGS; i++) { - if (xregs[i].guest_reg == DSP_REG_NONE) { - return (X64Reg)i; - } - } - return INVALID_REG; -} - -void DSPJitRegCache::getFreeXReg(X64Reg ®) -{ - reg = findFreeXReg(); - if (reg == INVALID_REG) - reg = spillXReg(); - _assert_msg_(DSPLLE, reg != INVALID_REG, "could not find register"); - xregs[reg].guest_reg = DSP_REG_USED; -} - -void DSPJitRegCache::getXReg(X64Reg reg) -{ - if (xregs[reg].guest_reg != DSP_REG_NONE) - spillXReg(reg); - _assert_msg_(DSPLLE, xregs[reg].guest_reg != DSP_REG_NONE, "register already in use"); - xregs[reg].guest_reg = DSP_REG_USED; -} - -void DSPJitRegCache::putXReg(X64Reg reg) -{ - _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED, - "putXReg without get(Free)XReg"); - xregs[reg].guest_reg = DSP_REG_NONE; -} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.h b/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.h deleted file mode 100644 index a230947c11..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitRegCache.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2011 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DSPJITREGCACHE_H -#define _DSPJITREGCACHE_H - -#include "x64Emitter.h" - -class DSPEmitter; - -enum DSPJitRegSpecial { - DSP_REG_ACC0_64 =32, - DSP_REG_ACC1_64 =33, - DSP_REG_AX0_32 =34, - DSP_REG_AX1_32 =35, - DSP_REG_PROD_64 =36, - DSP_REG_MAX_MEM_BACKED = 36, - - DSP_REG_USED =253, - DSP_REG_STATIC =254, - DSP_REG_NONE =255 -}; - -enum DSPJitSignExtend { - SIGN, ZERO, NONE -}; - -#ifdef _M_X64 -#define NUMXREGS 16 -#elif _M_IX86 -#define NUMXREGS 8 -#endif - -class DSPJitRegCache { -private: - struct X64CachedReg - { - int guest_reg; //including DSPJitRegSpecial - }; - struct DynamicReg { - Gen::OpArg loc; - void *mem; - size_t size; - bool dirty; - }; - -#ifdef _M_X64 - //when there is a way to do this efficiently in x86, uncondition - struct { - Gen::X64Reg host_reg; - int shift; - bool dirty; - bool used; - Gen::X64Reg tmp_reg; - } acc[2]; -#endif - - DynamicReg regs[DSP_REG_MAX_MEM_BACKED+1]; - X64CachedReg xregs[NUMXREGS]; - - DSPEmitter &emitter; - bool temporary; - bool merged; -private: - //find a free host reg - Gen::X64Reg findFreeXReg(); - Gen::X64Reg spillXReg(); - void spillXReg(Gen::X64Reg reg); -public: - DSPJitRegCache(DSPEmitter &_emitter); - - //for branching into multiple control flows - DSPJitRegCache(const DSPJitRegCache &cache); - DSPJitRegCache& operator=(const DSPJitRegCache &cache); - - ~DSPJitRegCache(); - - //merge must be done _before_ leaving the code branch, so we can fix - //up any differences in state - void flushRegs(DSPJitRegCache &cache, bool emit = true); - /* since some use cases are non-trivial, some examples: - - //this does not modify the final state of gpr - - FixupBranch b = JCC(); - DSPJitRegCache c = gpr; - - gpr.flushRegs(c); - SetBranchTarget(b); - - - //this does not modify the final state of gpr - - DSPJitRegCache c = gpr; - FixupBranch b1 = JCC(); - - gpr.flushRegs(c); - FixupBranch b2 = JMP(); - SetBranchTarget(b1); - - gpr.flushRegs(c); - SetBranchTarget(b2); - - - //this allows gpr to be modified in the second branch - //and fixes gpr according to the results form in the first branch - - DSPJitRegCache c = gpr; - FixupBranch b1 = JCC(); - - FixupBranch b2 = JMP(); - SetBranchTarget(b1); - - gpr.flushRegs(c); - SetBranchTarget(b2); - - - //this does not modify the final state of gpr - - u8* b = GetCodePtr(); - DSPJitRegCache c = gpr; - - gpr.flushRegs(c); - JCC(b); - - - this all is not needed when gpr would not be used at all in the - conditional branch - */ - //drop this copy without warning - void drop(); - - //prepare state so that another flushed DSPJitRegCache can take over - void flushRegs(); - - void loadStaticRegs();//load statically allocated regs from memory - void saveStaticRegs();//save statically allocated regs to memory - - //gives no SCALE_RIP with abs(offset) >= 0x80000000 - void getReg(int reg, Gen::OpArg &oparg, bool load = true); - //done with all usages of OpArg above - void putReg(int reg, bool dirty = true); - - void readReg(int sreg, Gen::X64Reg host_dreg, DSPJitSignExtend extend); - void writeReg(int dreg, Gen::OpArg arg); - - //find a free host reg, spill if used, reserve - void getFreeXReg(Gen::X64Reg ®); - //spill a specific host reg if used, reserve - void getXReg(Gen::X64Reg reg); - //unreserve the given host reg - void putXReg(Gen::X64Reg reg); -}; - -#endif /*_DSPJITREGCACHE_H*/ diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp deleted file mode 100644 index 35e5de9d9a..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "../DSPMemoryMap.h" -#include "../DSPHWInterface.h" -#include "../DSPEmitter.h" -#include "DSPJitUtil.h" -#include "x64Emitter.h" -#include "ABI.h" - -using namespace Gen; - -// addr math -// -// These functions detect overflow by checking if -// the bit past the top of the mask(WR) has changed in AR. -// They detect values under the minimum for a mask by adding wr + 1 -// and checking if the bit past the top of the mask doesn't change. -// Both are done while ignoring changes due to values/holes in IX -// above the mask. - - -// EAX = g_dsp.r.ar[reg] -// EDX = g_dsp.r.wr[reg] -// EDI = temp -// ECX = temp -void DSPEmitter::increment_addr_reg(int reg) -{ - OpArg ar_reg; - OpArg wr_reg; - gpr.getReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.putReg(DSP_REG_WR0+reg); - gpr.getReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); - - //u32 nar = ar + 1; - MOV(32, R(EDI), R(EAX)); - ADD(32, R(EAX), Imm8(1)); - - // if ((nar ^ ar) > ((wr | 1) << 1)) - // nar -= wr + 1; - XOR(32, R(EDI), R(EAX)); - LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); - OR(32, R(ECX), Imm8(2)); - CMP(32, R(EDI), R(ECX)); - FixupBranch nowrap = J_CC(CC_BE); - SUB(16, R(AX), R(DX)); - SUB(16, R(AX), Imm8(1)); - SetJumpTarget(nowrap); - // g_dsp.r.ar[reg] = nar; - - MOV(16, ar_reg, R(AX)); - gpr.putReg(DSP_REG_AR0+reg); -} - -// EAX = g_dsp.r.ar[reg] -// EDX = g_dsp.r.wr[reg] -// EDI = temp -// ECX = temp -void DSPEmitter::decrement_addr_reg(int reg) -{ - OpArg ar_reg; - OpArg wr_reg; - gpr.getReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.putReg(DSP_REG_WR0+reg); - gpr.getReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); - - // u32 nar = ar + wr; - // edi = nar - LEA(32, EDI, MComplex(EAX, EDX, 1, 0)); - - // if (((nar ^ ar) & ((wr | 1) << 1)) > wr) - // nar -= wr + 1; - XOR(32, R(EAX), R(EDI)); - LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); - CMP(32, R(EAX), R(EDX)); - FixupBranch nowrap = J_CC(CC_BE); - SUB(16, R(DI), R(DX)); - SUB(16, R(DI), Imm8(1)); - SetJumpTarget(nowrap); - // g_dsp.r.ar[reg] = nar; - - MOV(16, ar_reg, R(DI)); - gpr.putReg(DSP_REG_AR0+reg); -} - -// Increase addr register according to the correspond ix register -// EAX = g_dsp.r.ar[reg] -// EDX = g_dsp.r.wr[reg] -// ESI = g_dsp.r.ix[reg] -// ECX = temp -// EDI = temp -void DSPEmitter::increase_addr_reg(int reg) -{ - OpArg ar_reg; - OpArg wr_reg; - OpArg ix_reg; - gpr.getReg(DSP_REG_WR0+reg,wr_reg); - gpr.getReg(DSP_REG_IX0+reg,ix_reg); - MOVZX(32, 16, EDX, wr_reg); - MOVSX(32, 16, ESI, ix_reg); - gpr.putReg(DSP_REG_WR0+reg); - gpr.putReg(DSP_REG_IX0+reg); - gpr.getReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); - - //u32 nar = ar + ix; - //edi = nar - LEA(32, EDI, MComplex(EAX, ESI, 1, 0)); - - //u32 dar = (nar ^ ar ^ ix) & ((wr | 1) << 1); - //eax = dar - XOR(32, R(EAX), R(ESI)); - XOR(32, R(EAX), R(EDI)); - LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); - - //if (ix >= 0) - TEST(32, R(ESI), R(ESI)); - FixupBranch negative = J_CC(CC_S); - //if (dar > wr) - CMP(32, R(EAX), R(EDX)); - FixupBranch done = J_CC(CC_BE); - //nar -= wr + 1; - SUB(16, R(DI), R(DX)); - SUB(16, R(DI), Imm8(1)); - FixupBranch done2 = J(); - - //else - SetJumpTarget(negative); - //if ((((nar + wr + 1) ^ nar) & dar) <= wr) - LEA(32, ECX, MComplex(EDI, EDX, 1, 1)); - XOR(32, R(ECX), R(EDI)); - AND(32, R(ECX), R(EAX)); - CMP(32, R(ECX), R(EDX)); - FixupBranch done3 = J_CC(CC_A); - //nar += wr + 1; - LEA(32, EDI, MComplex(EDI, EDX, 1, 1)); - - SetJumpTarget(done); - SetJumpTarget(done2); - SetJumpTarget(done3); - // g_dsp.r.ar[reg] = nar; - - MOV(16, ar_reg, R(DI)); - gpr.putReg(DSP_REG_AR0+reg); -} - -// Decrease addr register according to the correspond ix register -// EAX = g_dsp.r.ar[reg] -// EDX = g_dsp.r.wr[reg] -// ESI = g_dsp.r.ix[reg] -// ECX = temp -// EDI = temp -void DSPEmitter::decrease_addr_reg(int reg) -{ - OpArg ar_reg; - OpArg wr_reg; - OpArg ix_reg; - gpr.getReg(DSP_REG_WR0+reg,wr_reg); - gpr.getReg(DSP_REG_IX0+reg,ix_reg); - MOVZX(32, 16, EDX, wr_reg); - MOVSX(32, 16, ESI, ix_reg); - gpr.putReg(DSP_REG_WR0+reg); - gpr.putReg(DSP_REG_IX0+reg); - gpr.getReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); - - NOT(32, R(ESI)); //esi = ~ix - - //u32 nar = ar - ix; (ar + ~ix + 1) - LEA(32, EDI, MComplex(EAX, ESI, 1, 1)); - - //u32 dar = (nar ^ ar ^ ~ix) & ((wr | 1) << 1); - //eax = dar - XOR(32, R(EAX), R(ESI)); - XOR(32, R(EAX), R(EDI)); - LEA(32, ECX, MComplex(EDX, EDX, 1, 0)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); - - //if ((u32)ix > 0xFFFF8000) ==> (~ix < 0x00007FFF) - CMP(32, R(ESI), Imm32(0x00007FFF)); - FixupBranch positive = J_CC(CC_AE); - //if (dar > wr) - CMP(32, R(EAX), R(EDX)); - FixupBranch done = J_CC(CC_BE); - //nar -= wr + 1; - SUB(16, R(DI), R(DX)); - SUB(16, R(DI), Imm8(1)); - FixupBranch done2 = J(); - - //else - SetJumpTarget(positive); - //if ((((nar + wr + 1) ^ nar) & dar) <= wr) - LEA(32, ECX, MComplex(EDI, EDX, 1, 1)); - XOR(32, R(ECX), R(EDI)); - AND(32, R(ECX), R(EAX)); - CMP(32, R(ECX), R(EDX)); - FixupBranch done3 = J_CC(CC_A); - //nar += wr + 1; - LEA(32, EDI, MComplex(EDI, EDX, 1, 1)); - - SetJumpTarget(done); - SetJumpTarget(done2); - SetJumpTarget(done3); - //return nar - - MOV(16, ar_reg, R(DI)); - gpr.putReg(DSP_REG_AR0+reg); -} - - -// EAX - destination address -// ECX - value -// ESI - Base of dram -void DSPEmitter::dmem_write() -{ - // if (saddr == 0) - CMP(16, R(EAX), Imm16(0x0fff)); - FixupBranch ifx = J_CC(CC_A); - - // g_dsp.dram[addr & DSP_DRAM_MASK] = val; - AND(16, R(EAX), Imm16(DSP_DRAM_MASK)); -#ifdef _M_X64 - MOV(64, R(ESI), ImmPtr(g_dsp.dram)); -#else - MOV(32, R(ESI), ImmPtr(g_dsp.dram)); -#endif - MOV(16, MComplex(ESI, EAX, 2, 0), R(ECX)); - - FixupBranch end = J(); - // else if (saddr == 0xf) - SetJumpTarget(ifx); - // Does it mean gdsp_ifx_write needs u32 rather than u16? - DSPJitRegCache c(gpr); - SaveDSPRegs(); - ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, ECX); - LoadDSPRegs(); - gpr.flushRegs(c); - SetJumpTarget(end); -} - -// ECX - value -void DSPEmitter::dmem_write_imm(u16 address) -{ - switch (address >> 12) - { - case 0x0: // 0xxx DRAM -#ifdef _M_IX86 // All32 - MOV(16, M(&g_dsp.dram[address & DSP_DRAM_MASK]), R(ECX)); -#else - MOV(64, R(RDX), ImmPtr(g_dsp.dram)); - MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK)*2), R(ECX)); -#endif - break; - - case 0xf: // Fxxx HW regs - MOV(16, R(EAX), Imm16(address)); - SaveDSPRegs(); - ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, ECX); - LoadDSPRegs(); - break; - - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", - g_dsp.pc, address); - break; - } -} - -// In: ECX - the address to read -// Out: EAX - the result of the read (used by caller) -// ESI - Base -void DSPEmitter::imem_read() -{ - // if (addr == 0) - CMP(16, R(ECX), Imm16(0x0fff)); - FixupBranch irom = J_CC(CC_A); - // return g_dsp.iram[addr & DSP_IRAM_MASK]; - AND(16, R(ECX), Imm16(DSP_IRAM_MASK)); -#ifdef _M_X64 - MOV(64, R(ESI), ImmPtr(g_dsp.iram)); -#else - MOV(32, R(ESI), ImmPtr(g_dsp.iram)); -#endif - MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); - - FixupBranch end = J(); - SetJumpTarget(irom); - // else if (addr == 0x8) - // return g_dsp.irom[addr & DSP_IROM_MASK]; - AND(16, R(ECX), Imm16(DSP_IROM_MASK)); -#ifdef _M_X64 - MOV(64, R(ESI), ImmPtr(g_dsp.irom)); -#else - MOV(32, R(ESI), ImmPtr(g_dsp.irom)); -#endif - MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); - - SetJumpTarget(end); -} - -// In: ECX - the address to read -// Out: EAX - the result of the read (used by caller) -// ESI - Base -// Trashes R11 on gdsp_ifx_read -void DSPEmitter::dmem_read() -{ - // if (saddr == 0) - CMP(16, R(ECX), Imm16(0x0fff)); - FixupBranch dram = J_CC(CC_A); - // return g_dsp.dram[addr & DSP_DRAM_MASK]; -#ifdef _M_X64 - AND(16, R(ECX), Imm16(DSP_DRAM_MASK)); - MOVZX(64, 16, RCX, R(RCX)); - MOV(64, R(ESI), ImmPtr(g_dsp.dram)); -#else - AND(32, R(ECX), Imm32(DSP_DRAM_MASK)); - MOV(32, R(ESI), ImmPtr(g_dsp.dram)); -#endif - MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); - - FixupBranch end = J(); - SetJumpTarget(dram); - // else if (saddr == 0x1) - CMP(16, R(ECX), Imm16(0x1fff)); - FixupBranch ifx = J_CC(CC_A); - // return g_dsp.coef[addr & DSP_COEF_MASK]; -#ifdef _M_X64 - AND(16, R(ECX), Imm16(DSP_COEF_MASK)); - MOVZX(64, 16, RCX, R(RCX)); - MOV(64, R(ESI), ImmPtr(g_dsp.coef)); -#else - AND(32, R(ECX), Imm32(DSP_COEF_MASK)); - MOV(32, R(ESI), ImmPtr(g_dsp.coef)); -#endif - MOV(16, R(EAX), MComplex(ESI, ECX, 2, 0)); - - FixupBranch end2 = J(); - SetJumpTarget(ifx); - // else if (saddr == 0xf) - // return gdsp_ifx_read(addr); - DSPJitRegCache c(gpr); - SaveDSPRegs(); - ABI_CallFunctionR((void *)gdsp_ifx_read, ECX); - LoadDSPRegs(); - gpr.flushRegs(c); - SetJumpTarget(end); - SetJumpTarget(end2); -} - -void DSPEmitter::dmem_read_imm(u16 address) -{ - switch (address >> 12) - { - case 0x0: // 0xxx DRAM -#ifdef _M_IX86 // All32 - MOV(16, R(EAX), M(&g_dsp.dram[address & DSP_DRAM_MASK])); -#else - MOV(64, R(RDX), ImmPtr(g_dsp.dram)); - MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK)*2)); -#endif - break; - - case 0x1: // 1xxx COEF -#ifdef _M_IX86 // All32 - MOV(16, R(EAX), Imm16(g_dsp.coef[address & DSP_COEF_MASK])); -#else - MOV(64, R(RDX), ImmPtr(g_dsp.coef)); - MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK)*2)); -#endif - break; - - case 0xf: // Fxxx HW regs - SaveDSPRegs(); - ABI_CallFunctionC16((void *)gdsp_ifx_read, address); - LoadDSPRegs(); - break; - - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", - g_dsp.pc, address); - } -} - -// Returns s64 in RAX -void DSPEmitter::get_long_prod(X64Reg long_prod) -{ -#ifdef _M_X64 - // MOV(64, R(R11), ImmPtr(&g_dsp.r)); - //s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH]; - OpArg reg; - gpr.getReg(DSP_REG_PROD_64, reg); - X64Reg tmp; - gpr.getFreeXReg(tmp); - MOV(64, R(long_prod), reg); - MOV(64, R(tmp), R(long_prod)); - SHL(64, R(long_prod), Imm8(64-40));//sign extend - SAR(64, R(long_prod), Imm8(64-40)); - SHR(64, R(tmp), Imm8(48)); - SHL(64, R(tmp), Imm8(16)); - ADD(64, R(long_prod), R(tmp)); - gpr.putXReg(tmp); - gpr.putReg(DSP_REG_PROD_64, false); - -#endif -} - -// Returns s64 in RAX -// Clobbers RSI -void DSPEmitter::get_long_prod_round_prodl(X64Reg long_prod) -{ -#ifdef _M_X64 - //s64 prod = dsp_get_long_prod(); - get_long_prod(long_prod); - - //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; - TEST(32, R(long_prod), Imm32(0x10000)); - FixupBranch jump = J_CC(CC_Z); - ADD(64, R(long_prod), Imm32(0x8000)); - MOV(64, R(ESI), Imm64(~0xffff)); - AND(64, R(long_prod), R(RSI)); - FixupBranch _ret = J(); - //else prod = (prod + 0x7fff) & ~0xffff; - SetJumpTarget(jump); - ADD(64, R(long_prod), Imm32(0x7fff)); - MOV(64, R(RSI), Imm64(~0xffff)); - AND(64, R(long_prod), R(RSI)); - SetJumpTarget(_ret); - //return prod; -#endif -} - -// For accurate emulation, this is wrong - but the real prod registers behave -// in completely bizarre ways. Probably not meaningful to emulate them accurately. -// In: RAX = s64 val -void DSPEmitter::set_long_prod() -{ -#ifdef _M_X64 - OpArg reg; - gpr.getReg(DSP_REG_PROD_64, reg, false); - X64Reg tmp; - gpr.getFreeXReg(tmp); - - MOV(64, R(tmp), Imm64(0x000000ffffffffffULL)); - AND(64, R(RAX), R(tmp)); - // g_dsp.r[DSP_REG_PRODL] = (u16)val; - MOV(64, reg, R(RAX)); - - gpr.putXReg(tmp); - gpr.putReg(DSP_REG_PROD_64, true); -#endif -} - -// Returns s64 in RAX -// Clobbers RSI -void DSPEmitter::round_long_acc(X64Reg long_acc) -{ -#ifdef _M_X64 - //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; - TEST(32, R(long_acc), Imm32(0x10000)); - FixupBranch jump = J_CC(CC_Z); - ADD(64, R(long_acc), Imm32(0x8000)); - MOV(64, R(ESI), Imm64(~0xffff)); - AND(64, R(long_acc), R(RSI)); - FixupBranch _ret = J(); - //else prod = (prod + 0x7fff) & ~0xffff; - SetJumpTarget(jump); - ADD(64, R(long_acc), Imm32(0x7fff)); - MOV(64, R(RSI), Imm64(~0xffff)); - AND(64, R(long_acc), R(RSI)); - SetJumpTarget(_ret); - //return prod; -#endif -} - -// Returns s64 in acc -void DSPEmitter::get_long_acc(int _reg, X64Reg acc) -{ -#ifdef _M_X64 - OpArg reg; - gpr.getReg(DSP_REG_ACC0_64+_reg, reg); - MOV(64, R(acc), reg); - gpr.putReg(DSP_REG_ACC0_64+_reg, false); -#endif -} - -// In: acc = s64 val -void DSPEmitter::set_long_acc(int _reg, X64Reg acc) -{ -#ifdef _M_X64 - OpArg reg; - gpr.getReg(DSP_REG_ACC0_64+_reg, reg, false); - MOV(64, reg, R(acc)); - gpr.putReg(DSP_REG_ACC0_64+_reg); -#endif -} - -// Returns s16 in AX -void DSPEmitter::get_acc_l(int _reg, X64Reg acl, bool sign) -{ - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.readReg(_reg+DSP_REG_ACL0, acl, sign?SIGN:ZERO); -} - -void DSPEmitter::set_acc_l(int _reg, OpArg arg) -{ - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.writeReg(_reg+DSP_REG_ACL0,arg); -} - -// Returns s16 in AX -void DSPEmitter::get_acc_m(int _reg, X64Reg acm, bool sign) -{ -// return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.readReg(_reg+DSP_REG_ACM0, acm, sign?SIGN:ZERO); -} - -// In: s16 in AX -void DSPEmitter::set_acc_m(int _reg, OpArg arg) -{ - // return g_dsp.r.ac[_reg].m; - gpr.writeReg(_reg+DSP_REG_ACM0,arg); -} - -// Returns s16 in AX -void DSPEmitter::get_acc_h(int _reg, X64Reg ach, bool sign) -{ -// return g_dsp.r.ac[_reg].h; - gpr.readReg(_reg+DSP_REG_ACH0, ach, sign?SIGN:ZERO); -} - -// In: s16 in AX -void DSPEmitter::set_acc_h(int _reg, OpArg arg) -{ - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.writeReg(_reg+DSP_REG_ACH0,arg); -} - -// Returns u32 in EAX -void DSPEmitter::get_long_acx(int _reg, X64Reg acx) -{ -// return ((u32)g_dsp.r[DSP_REG_AXH0 + _reg] << 16) | g_dsp.r[DSP_REG_AXL0 + _reg]; - gpr.readReg(_reg+DSP_REG_AX0_32, acx, SIGN); -} - -// Returns s16 in EAX -void DSPEmitter::get_ax_l(int _reg, X64Reg axl) -{ -// return (s16)g_dsp.r[DSP_REG_AXL0 + _reg]; - gpr.readReg(_reg+DSP_REG_AXL0, axl, SIGN); -} - -// Returns s16 in EAX -void DSPEmitter::get_ax_h(int _reg, X64Reg axh) -{ -// return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; - gpr.readReg(_reg+DSP_REG_AXH0, axh, SIGN); -} - -void DSPEmitter::LoadDSPRegs() -{ -#ifdef _M_X64 - MOV(64, R(R11), ImmPtr(&g_dsp.r)); -#endif - - // Load DSP register state here... - gpr.loadStaticRegs(); -} - -void DSPEmitter::SaveDSPRegs() -{ - // Save DSP register state here... - gpr.saveStaticRegs(); -} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.h b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.h deleted file mode 100644 index 2d28b6d520..0000000000 --- a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2010 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef __DSPJITUTIL_H__ -#define __DSPJITUTIL_H__ - -#endif /*__DSPJITUTIL_H__*/ diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp deleted file mode 100644 index bc6b8d7ba2..0000000000 --- a/Source/Core/DSPCore/Src/LabelMap.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "LabelMap.h" -#include "DSPTables.h" - -LabelMap::LabelMap() -{ - -} - -void LabelMap::RegisterDefaults() -{ - for (int i = 0; i < 0x24; i++) - { - if (regnames[i].name) - RegisterLabel(regnames[i].name, regnames[i].addr); - } - for (int i = 0; i < (int)pdlabels_size; i++) - { - if (pdlabels[i].name) - RegisterLabel(pdlabels[i].name, pdlabels[i].addr); - } -} - -void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type) -{ - u16 old_value; - if (GetLabelValue(label, &old_value) && old_value != lval) - { - printf("WARNING: Redefined label %s to %04x - old value %04x\n", - label.c_str(), lval, old_value); - DeleteLabel(label); - } - labels.push_back(label_t(label, lval, type)); -} - -void LabelMap::DeleteLabel(const std::string &label) -{ - for (std::vector::iterator iter = labels.begin(); - iter != labels.end(); ++iter) - { - if (!label.compare(iter->name)) - { - labels.erase(iter); - return; - } - } -} - -bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const -{ - for (u32 i = 0; i < labels.size(); i++) - { - if (!label.compare(labels[i].name)) - { - if (type & labels[i].type) { - *value = labels[i].addr; - return true; - } else { - printf("WARNING: Wrong label type requested. %s\n", label.c_str()); - } - } - } - return false; -} - -void LabelMap::Clear() -{ - labels.clear(); -} diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h deleted file mode 100644 index 2bdaee9049..0000000000 --- a/Source/Core/DSPCore/Src/LabelMap.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _LABELMAP_H -#define _LABELMAP_H - -#include -#include - -#include "Common.h" - -enum LabelType -{ - LABEL_IADDR = 1, // Jump addresses, etc - LABEL_DADDR = 2, // Data addresses, etc - LABEL_VALUE = 4, - LABEL_ANY = 0xFF, -}; - -class LabelMap -{ - struct label_t - { - label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {} - std::string name; - s32 addr; - LabelType type; - }; - std::vector labels; - -public: - LabelMap(); - ~LabelMap() { } - void RegisterDefaults(); - void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE); - void DeleteLabel(const std::string &label); - bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const; - void Clear(); -}; - -#endif // _LABELMAP_H diff --git a/Source/Core/DSPCore/Src/SConscript b/Source/Core/DSPCore/Src/SConscript deleted file mode 100644 index f97a15753c..0000000000 --- a/Source/Core/DSPCore/Src/SConscript +++ /dev/null @@ -1,37 +0,0 @@ -# -*- python -*- - -Import('env') - -files = [ - "assemble.cpp", - "disassemble.cpp", - "DSPAccelerator.cpp", - "DSPIntCCUtil.cpp", - "DSPIntExtOps.cpp", - "DSPHWInterface.cpp", - "DSPMemoryMap.cpp", - "DSPStacks.cpp", - "DSPAnalyzer.cpp", - "DspIntArithmetic.cpp", - "DspIntBranch.cpp", - "DspIntLoadStore.cpp", - "DspIntMisc.cpp", - "DspIntMultiplier.cpp", - "DSPEmitter.cpp", - "DSPCodeUtil.cpp", - "LabelMap.cpp", - "DSPInterpreter.cpp", - "DSPCore.cpp", - "DSPTables.cpp", - "Jit/DSPJitExtOps.cpp", - "Jit/DSPJitBranch.cpp", - "Jit/DSPJitUtil.cpp", - "Jit/DSPJitCCUtil.cpp", - "Jit/DSPJitArithmetic.cpp", - "Jit/DSPJitLoadStore.cpp", - "Jit/DSPJitMultiplier.cpp", - "Jit/DSPJitMisc.cpp", - "Jit/DSPJitRegCache.cpp", - ] - -env.StaticLibrary(env['local_libs'] + 'dspcore', files) diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp deleted file mode 100644 index a8a24e45c2..0000000000 --- a/Source/Core/DSPCore/Src/assemble.cpp +++ /dev/null @@ -1,1020 +0,0 @@ -/*==================================================================== - -$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ - -project: GameCube DSP Tool (gcdsp) -mail: duddie@walla.com - -Copyright (c) 2005 Duddie - -This program is free software; you can redistribute it and/or -modify it 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 received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Revision 1.4 2008/10/04 10:30:00 Hermes -added function to export the code to .h file -added support for '/ *' '* /' and '//' for comentaries -added some sintax detection when use registers - -$Log: not supported by cvs2svn $ -Revision 1.2 2005/09/14 02:19:29 wntrmute -added header guards -use standard main function - -Revision 1.1 2005/08/24 22:13:34 wntrmute -Initial import - - -====================================================================*/ - -#include -#include - -#include -#include -#include - -#include "Common.h" -#include "FileUtil.h" -#include "DSPInterpreter.h" -#include "DSPTables.h" -#include "disassemble.h" -#include "assemble.h" - -static const char *err_string[] = -{ - "", - "Unknown Error", - "Unknown opcode", - "Not enough parameters", - "Too many parameters", - "Wrong parameter", - "Expected parameter of type 'string'", - "Expected parameter of type 'value'", - "Expected parameter of type 'register'", - "Expected parameter of type 'memory pointer'", - "Expected parameter of type 'immediate'", - "Incorrect binary value", - "Incorrect hexadecimal value", - "Incorrect decimal value", - "Label already exists", - "Label not defined", - "No matching brackets", - "This opcode cannot be extended", - "Given extending params for non extensible opcode", - "Wrong parameter: must be accumulator register", - "Wrong parameter: must be mid accumulator register", - "Invalid register", - "Number out of range" -}; - -DSPAssembler::DSPAssembler(const AssemblerSettings &settings) : - gdg_buffer(NULL), - m_cur_addr(0), - m_cur_pass(0), - m_current_param(0), - settings_(settings) - -{ -} - -DSPAssembler::~DSPAssembler() -{ - if(gdg_buffer) - free(gdg_buffer); -} - -bool DSPAssembler::Assemble(const char *text, std::vector &code, std::vector *line_numbers) -{ - if (line_numbers) - line_numbers->clear(); - const char *fname = "tmp.asm"; - if (!File::WriteStringToFile(true, text, fname)) - return false; - InitPass(1); - if (!AssembleFile(fname, 1)) - return false; - - // We now have the size of the output buffer - if (m_totalSize > 0) - { - gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4); - if(!gdg_buffer) - return false; - - memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); - } else - return false; - - InitPass(2); - if (!AssembleFile(fname, 2)) - return false; - - code.resize(m_totalSize); - for (int i = 0; i < m_totalSize; i++) { - code[i] = *(u16 *)(gdg_buffer + i * 2); - } - - if(gdg_buffer) { - free(gdg_buffer); - gdg_buffer = NULL; - } - - last_error_str = "(no errors)"; - last_error = ERR_OK; - - return true; -} - -void DSPAssembler::ShowError(err_t err_code, const char *extra_info) -{ - - if (!settings_.force) - failed = true; - - char error_buffer[1024]; - char *buf_ptr = error_buffer; - buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); - if (!extra_info) - extra_info = "-"; - - if (m_current_param == 0) - buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); - else - buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", - err_string[err_code], code_line, m_current_param, extra_info); - last_error_str = error_buffer; - last_error = err_code; -} - -char *skip_spaces(char *ptr) -{ - while (*ptr == ' ') - ptr++; - return ptr; -} - -const char *skip_spaces(const char *ptr) -{ - while (*ptr == ' ') - ptr++; - return ptr; -} - -// Parse a standalone value - it can be a number in one of several formats or a label. -s32 DSPAssembler::ParseValue(const char *str) -{ - bool negative = false; - s32 val = 0; - const char *ptr = str; - - if (ptr[0] == '#') - { - ptr++; - negative = true; // Wow! Double # (needed one to get in here) negates??? - } - if (ptr[0] == '-') - { - ptr++; - negative = true; - } - if (ptr[0] == '0') - { - if (ptr[1] >= '0' && ptr[1] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_DEC, str); - } - } - else - { - switch (ptr[1]) - { - case 'X': // hex - for (int i = 2 ; ptr[i] != 0 ; i++) - { - val <<= 4; - if (ptr[i] >= 'a' && ptr[i] <= 'f') - val += (ptr[i]-'a'+10); - else if (ptr[i] >= 'A' && ptr[i] <= 'F') - val += (ptr[i]-'A'+10); - else if (ptr[i] >= '0' && ptr[i] <= '9') - val += (ptr[i] - '0'); - else - ShowError(ERR_INCORRECT_HEX, str); - } - break; - case '\'': // binary - for (int i = 2; ptr[i] != 0; i++) - { - val *=2; - if(ptr[i] >= '0' && ptr[i] <= '1') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_BIN, str); - } - break; - default: - // value is 0 or error - val = 0; - break; - } - } - } - else - { - // Symbol starts with a digit - it's a dec number. - if (ptr[0] >= '0' && ptr[0] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_DEC, str); - } - } - else // Everything else is a label. - { - // Lookup label - u16 value; - if (labels.GetLabelValue(ptr, &value)) - return value; - if (m_cur_pass == 2) - ShowError(ERR_UNKNOWN_LABEL, str); - } - } - if (negative) - return -val; - return val; -} - -// Modifies both src and dst! -// What does it do, really?? -char *DSPAssembler::FindBrackets(char *src, char *dst) -{ - s32 len = (s32) strlen(src); - s32 first = -1; - s32 count = 0; - s32 i, j; - j = 0; - for (i = 0 ; i < len ; i++) - { - if (src[i] == '(') - { - if (first < 0) - { - count = 1; - src[i] = 0x0; - first = i; - } - else - { - count++; - dst[j++] = src[i]; - } - } - else if (src[i] == ')') - { - if (--count == 0) - { - dst[j] = 0; - return &src[i+1]; - } - else - { - dst[j++] = src[i]; - } - } - else - { - if (first >= 0) - dst[j++] = src[i]; - } - } - if (count) - ShowError(ERR_NO_MATCHING_BRACKETS); - return NULL; -} - -// Bizarre in-place expression evaluator. -u32 DSPAssembler::ParseExpression(const char *ptr) -{ - char *pbuf; - s32 val = 0; - - char *d_buffer = (char *)malloc(1024); - char *s_buffer = (char *)malloc(1024); - strcpy(s_buffer, ptr); - - while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL) - { - val = ParseExpression(d_buffer); - sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); - strcpy(s_buffer, d_buffer); - } - - int j = 0; - for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) - { - char c = s_buffer[i]; - if (c != ' ') - d_buffer[j++] = c; - } - - for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) - { - char c = d_buffer[i]; - if (c == '-') - { - if (i == 0) - c = '#'; - else - { - switch (d_buffer[i - 1]) - { - case '/': - case '%': - case '*': - c = '#'; - } - } - } - d_buffer[i] = c; - } - - while ((pbuf = strstr(d_buffer, "+")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "-")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); - if (val < 0) - { - val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf - fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); - } - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "*")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "/")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "|")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "&")) != NULL) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - val = ParseValue(d_buffer); - free(d_buffer); - free(s_buffer); - return val; -} - -// Destroys parstr -u32 DSPAssembler::GetParams(char *parstr, param_t *par) -{ - u32 count = 0; - char *tmpstr = skip_spaces(parstr); - tmpstr = strtok(tmpstr, ",\x00"); - for (int i = 0; i < 10; i++) - { - if (tmpstr == NULL) - break; - tmpstr = skip_spaces(tmpstr); - if (strlen(tmpstr) == 0) - break; - if (tmpstr) - count++; - else - break; - - par[i].type = P_NONE; - switch (tmpstr[0]) - { - case '"': - par[i].str = strtok(tmpstr, "\""); - par[i].type = P_STR; - break; - case '#': - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_IMM; - break; - case '@': - if (tmpstr[1] == '$') - { - par[i].val = ParseExpression(tmpstr + 2); - par[i].type = P_PRG; - } - else - { - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_MEM; - } - break; - case '$': - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_REG; - break; - - default: - par[i].val = ParseExpression(tmpstr); - par[i].type = P_VAL; - break; - } - tmpstr = strtok(NULL, ",\x00"); - } - return count; -} - -const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) -{ - if (opcode[0] == 'C' && opcode[1] == 'W') - return &cw; - - AliasMap::const_iterator alias_iter = aliases.find(opcode); - if (alias_iter != aliases.end()) - opcode = alias_iter->second.c_str(); - for (int i = 0; i < opcod_size; i++) - { - const opc_t *opc = &opcod[i]; - if (strcmp(opc->name, opcode) == 0) - { - if (par_count < opc->param_count) - { - ShowError(ERR_NOT_ENOUGH_PARAMETERS); - } - if (par_count > opc->param_count) - { - ShowError(ERR_TOO_MANY_PARAMETERS); - } - return opc; - } - } - ShowError(ERR_UNKNOWN_OPCODE); - return NULL; -} - -// weird... -u16 get_mask_shifted_down(u16 mask) -{ - while (!(mask & 1)) - mask >>= 1; - return mask; -} - -bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) -{ - for (int i = 0; i < count; i++) - { - const int current_param = i + 1; // just for display. - if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) - { - if (par[i].type == P_VAL && - (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) - { - // Data and instruction addresses are valid as VAL values. - continue; - } - - if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) - { - // Just a temp. Should be replaced with more purposeful vars. - int value; - - // modified by Hermes: test the register range - switch ((unsigned)opc->params[i].type) - { - case P_REG18: - case P_REG19: - case P_REG1A: - value = (opc->params[i].type >> 8) & 31; - if ((int)par[i].val < value || - (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) - { - if (ext) fprintf(stderr, "(ext) "); - fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - ShowError(ERR_INVALID_REGISTER); - } - break; - case P_PRG: - if ((int)par[i].val < 0 || (int)par[i].val > 0x3) - { - if (ext) fprintf(stderr, "(ext) "); - fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - ShowError(ERR_INVALID_REGISTER); - } - break; - case P_ACC: - if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) - { - if (ext) fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1e && par[i].val <= 0x1f) { - fprintf(stderr, "%i : %s ", code_line, cur_line.c_str()); - fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); - } - else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { - fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else - ShowError(ERR_WRONG_PARAMETER_ACC); - } - break; - case P_ACCM: - if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) - { - if (ext) fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1c && par[i].val <= 0x1d) - fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - else if (par[i].val >= 0x20 && par[i].val <= 0x21) - fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - else - ShowError(ERR_WRONG_PARAMETER_ACC); - } - break; - - case P_ACCL: - if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) - { - if (ext) fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1e && par[i].val <= 0x1f) - { - fprintf(stderr, "%s ", cur_line.c_str()); - fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else if (par[i].val >= 0x20 && par[i].val <= 0x21) { - fprintf(stderr, "%s ", cur_line.c_str()); - fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else - ShowError(ERR_WRONG_PARAMETER_ACC); - } - break; -/* case P_ACCM_D: //P_ACC_MID: - if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) - { - ShowError(ERR_WRONG_PARAMETER_MID_ACC); - } - break;*/ - } - continue; - } - - switch (par[i].type & (P_REG | 7)) - { - case P_REG: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_REG); - break; - case P_MEM: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_MEM); - break; - case P_VAL: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_VAL); - break; - case P_IMM: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_IMM); - break; - } - ShowError(ERR_WRONG_PARAMETER); - break; - } - else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) - { - // modified by Hermes: test NUMBER range - int value = get_mask_shifted_down(opc->params[i].mask); - unsigned int valueu = 0xffff & ~(value >> 1); - if ((int)par[i].val < 0) - { - if (value == 7) // value 7 por sbclr/sbset - { - fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); - ShowError(ERR_OUT_RANGE_NUMBER); - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); - else - fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); - - ShowError(ERR_OUT_RANGE_NUMBER); - } - else if ((int)par[i].val < -((value >> 1) + 1)) - { - if (value < 128) - fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", - (value >> 1) + 1, value >> 1, par[i].val); - else - fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", - (value >> 1) + 1, value >> 1, value, par[i].val); - - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else - { - if (value == 7) // value 7 por sbclr/sbset - { - if (par[i].val > (unsigned)value) - { - fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - value >>= 1; // addressing 8 bit with sign - if (par[i].val > (unsigned)value && - (par[i].val < valueu || par[i].val > (unsigned)0xffff)) - { - if (value < 256) - fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); - else - fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else - { - if (value < 128) - value >>= 1; // special case ASL/ASR/LSL/LSR - if (par[i].val > (unsigned)value) - { - if (value < 64) - fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); - else - fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - } - continue; - } - } - m_current_param = 0; - return true; -} - - -// Merge opcode with params. -void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) -{ - outbuf[m_cur_addr] |= opc->opcode; - for (u32 i = 0; i < par_count; i++) - { - // Ignore the "reverse" parameters since they are implicit. - if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) - { - u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; - u16 v16 = par[i].val; - if (opc->params[i].lshift > 0) - v16 <<= opc->params[i].lshift; - else - v16 >>= -opc->params[i].lshift; - v16 &= opc->params[i].mask; - outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; - } - } -} - -void DSPAssembler::InitPass(int pass) -{ - failed = false; - if (pass == 1) - { - // Reset label table. Pre-populate with hw addresses and registers. - labels.Clear(); - labels.RegisterDefaults(); - aliases.clear(); - aliases["S15"] = "SET15"; - aliases["S16"] = "SET16"; - aliases["S40"] = "SET40"; - } - m_cur_addr = 0; - m_totalSize = 0; - cur_segment = SEGMENT_CODE; - segment_addr[SEGMENT_CODE] = 0; - segment_addr[SEGMENT_DATA] = 0; - segment_addr[SEGMENT_OVERLAY] = 0; -} - -bool DSPAssembler::AssembleFile(const char *fname, int pass) -{ - int disable_text = 0; // modified by Hermes - - std::ifstream fsrc(fname); - - if (fsrc.fail()) - { - std::cerr << "Cannot open file " << fname << std::endl; - return false; - } - - //printf("%s: Pass %d\n", fname, pass); - code_line = 0; - m_cur_pass = pass; - -#define LINEBUF_SIZE 1024 - char line[LINEBUF_SIZE] = {0}; - while (!failed && !fsrc.fail() && !fsrc.eof()) - { - int opcode_size = 0; - fsrc.getline(line, LINEBUF_SIZE); - if(fsrc.fail()) - break; - - cur_line = line; - //printf("A: %s\n", line); - code_line++; - - param_t params[10] = {{0}}; - param_t params_ext[10] = {{0}}; - - bool upper = true; - for (int i = 0; i < LINEBUF_SIZE; i++) - { - char c = line[i]; - // This stuff handles /**/ and // comments. - // modified by Hermes : added // and /* */ for long commentaries - if (c == '/') - { - if (i < 1023) - { - if (line[i+1] == '/') - c = 0x00; - else if (line[i+1] == '*') - { - // toggle comment mode. - disable_text = !disable_text; - } - } - } - else if (c == '*') - { - if (i < 1023 && line[i+1] == '/' && disable_text) - { - disable_text = 0; - c = 32; - line[i + 1] = 32; - } - } - - // turn text into spaces if disable_text is on (in a comment). - if (disable_text && ((unsigned char)c) > 32) c = 32; - - if (c == 0x0a || c == 0x0d || c == ';') - c = 0x00; - if (c == 0x09) // tabs to spaces - c = ' '; - if (c == '"') - upper = !upper; - if (upper && c >= 'a' && c <= 'z') // convert to uppercase - c = c - 'a' + 'A'; - line[i] = c; - if (c == 0) - break; // modified by Hermes - } - char *ptr = line; - - std::string label; - - size_t col_pos = std::string(line).find(":"); - if (col_pos != std::string::npos) - { - bool valid = true; - - for(int j = 0; j < (int)col_pos; j++) - { - if (j == 0) - if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - } - if (valid) - { - label = std::string(line).substr(0, col_pos); - ptr += col_pos + 1; - } - } - - char *opcode = NULL; - opcode = strtok(ptr, " "); - char *opcode_ext = NULL; - - u32 params_count = 0; - u32 params_count_ext = 0; - if (opcode) - { - if ((opcode_ext = strstr(opcode, "'")) != NULL) - { - opcode_ext[0] = '\0'; - opcode_ext++; - if (strlen(opcode_ext) == 0) - opcode_ext = NULL; - } - // now we have opcode and label - - params_count = 0; - params_count_ext = 0; - - char *paramstr = strtok(NULL, "\0"); - char *paramstr_ext = 0; - // there is valid opcode so probably we have parameters - - if (paramstr) - { - if ((paramstr_ext = strstr(paramstr, ":")) != NULL) - { - paramstr_ext[0] = '\0'; - paramstr_ext++; - } - } - - if (paramstr) - params_count = GetParams(paramstr, params); - if (paramstr_ext) - params_count_ext = GetParams(paramstr_ext, params_ext); - } - - if (!label.empty()) - { - // there is a valid label so lets store it in labels table - u32 lval = m_cur_addr; - if (opcode) - { - if (strcmp(opcode, "EQU") == 0) - { - lval = params[0].val; - opcode = NULL; - } - } - if (pass == 1) - labels.RegisterLabel(label, lval); - } - - if (opcode == NULL) - continue; - - // check if opcode is reserved compiler word - if (strcmp("INCLUDE", opcode) == 0) - { - if (params[0].type == P_STR) - { - char *tmpstr; - u32 thisCodeline = code_line; - - if (include_dir.size()) - { - tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); - sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); - } - else - { - tmpstr = (char *)malloc(strlen(params[0].str) + 1); - strcpy(tmpstr, params[0].str); - } - - AssembleFile(tmpstr, pass); - - code_line = thisCodeline; - - free(tmpstr); - } - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } - - if (strcmp("INCDIR", opcode) == 0) - { - if (params[0].type == P_STR) - include_dir = params[0].str; - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } - - if (strcmp("ORG", opcode) == 0) - { - if (params[0].type == P_VAL) - m_cur_addr = params[0].val; - else - ShowError(ERR_EXPECTED_PARAM_VAL); - continue; - } - - if (strcmp("SEGMENT", opcode) == 0) - { - if (params[0].type == P_STR) - { - segment_addr[cur_segment] = m_cur_addr; - if (strcmp("DATA", params[0].str) == 0) - cur_segment = SEGMENT_DATA; - if (strcmp("CODE", params[0].str) == 0) - cur_segment = SEGMENT_CODE; - m_cur_addr = segment_addr[cur_segment]; - } - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } - - const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); - if (!opc) - opc = &cw; - - opcode_size = opc->size; - - VerifyParams(opc, params, params_count); - - const opc_t *opc_ext = NULL; - // Check for opcode extensions. - if (opc->extended) - { - if (opcode_ext) - { - opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); - VerifyParams(opc_ext, params_ext, params_count_ext, true); - } - else if (params_count_ext) - ShowError(ERR_EXT_PAR_NOT_EXT); - } - else - { - if (opcode_ext) - ShowError(ERR_EXT_CANT_EXTEND_OPCODE); - if (params_count_ext) - ShowError(ERR_EXT_PAR_NOT_EXT); - } - - if (pass == 2) - { - // generate binary - ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000; - BuildCode(opc, params, params_count, (u16 *)gdg_buffer); - if (opc_ext) - BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); - } - - m_cur_addr += opcode_size; - m_totalSize += opcode_size; - }; - - if (!failed) - fsrc.close(); - - return !failed; -} diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h deleted file mode 100644 index f140d0e69e..0000000000 --- a/Source/Core/DSPCore/Src/assemble.h +++ /dev/null @@ -1,139 +0,0 @@ -/*==================================================================== - - project: GameCube DSP Tool (gcdsp) - created: 2005.03.04 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _DSP_ASSEMBLE_H -#define _DSP_ASSEMBLE_H - -#include -#include - -#include "Common.h" -#include "disassemble.h" -#include "DSPTables.h" -#include "LabelMap.h" - -enum err_t -{ - ERR_OK = 0, - ERR_UNKNOWN, - ERR_UNKNOWN_OPCODE, - ERR_NOT_ENOUGH_PARAMETERS, - ERR_TOO_MANY_PARAMETERS, - ERR_WRONG_PARAMETER, - ERR_EXPECTED_PARAM_STR, - ERR_EXPECTED_PARAM_VAL, - ERR_EXPECTED_PARAM_REG, - ERR_EXPECTED_PARAM_MEM, - ERR_EXPECTED_PARAM_IMM, - ERR_INCORRECT_BIN, - ERR_INCORRECT_HEX, - ERR_INCORRECT_DEC, - ERR_LABEL_EXISTS, - ERR_UNKNOWN_LABEL, - ERR_NO_MATCHING_BRACKETS, - ERR_EXT_CANT_EXTEND_OPCODE, - ERR_EXT_PAR_NOT_EXT, - ERR_WRONG_PARAMETER_ACC, - ERR_WRONG_PARAMETER_MID_ACC, - ERR_INVALID_REGISTER, - ERR_OUT_RANGE_NUMBER -}; - - -// Unless you want labels to carry over between files, you probably -// want to create a new DSPAssembler for every file you assemble. -class DSPAssembler -{ -public: - DSPAssembler(const AssemblerSettings &settings); - ~DSPAssembler(); - - // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, - // one for each word of code, indicating the source assembler code line number it came from. - - // If returns false, call GetErrorString to get some text to present to the user. - bool Assemble(const char *text, std::vector &code, std::vector *line_numbers = NULL); - - std::string GetErrorString() const { return last_error_str; } - err_t GetError() const { return last_error; } - -private: - struct param_t - { - u32 val; - partype_t type; - char *str; - }; - - enum segment_t - { - SEGMENT_CODE = 0, - SEGMENT_DATA, - SEGMENT_OVERLAY, - SEGMENT_MAX - }; - - // Utility functions - s32 ParseValue(const char *str); - u32 ParseExpression(const char *ptr); - - u32 GetParams(char *parstr, param_t *par); - - void InitPass(int pass); - bool AssembleFile(const char *fname, int pass); - - void ShowError(err_t err_code, const char *extra_info = NULL); - // void ShowWarning(err_t err_code, const char *extra_info = NULL); - - char *FindBrackets(char *src, char *dst); - const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size); - bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false); - void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); - - char *gdg_buffer; - - std::string include_dir; - std::string cur_line; - - u32 m_cur_addr; - int m_totalSize; - u8 m_cur_pass; - - LabelMap labels; - - u32 code_line; - bool failed; - std::string last_error_str; - err_t last_error; - - typedef std::map AliasMap; - AliasMap aliases; - - segment_t cur_segment; - u32 segment_addr[SEGMENT_MAX]; - int m_current_param; - const AssemblerSettings settings_; -}; - -#endif // _DSP_ASSEMBLE_H diff --git a/Source/Core/DSPCore/Src/disassemble.cpp b/Source/Core/DSPCore/Src/disassemble.cpp deleted file mode 100644 index 03a81ddb1a..0000000000 --- a/Source/Core/DSPCore/Src/disassemble.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/*==================================================================== - - filename: disassemble.cpp - project: GameCube DSP Tool (gcdsp) - created: 2005.03.04 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#include -#include - -#include "Common.h" -#include "FileUtil.h" -#include "disassemble.h" -#include "DSPTables.h" - -#ifdef _MSC_VER -#pragma warning(disable:4996) -#endif - -#ifndef MAX_PATH -#include // For MAX_PATH -#endif - -extern void nop(const UDSPInstruction opc); - -DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings) - : settings_(settings) -{ -} - -DSPDisassembler::~DSPDisassembler() -{ - // Some old code for logging unknown ops. - char filename[MAX_PATH]; - sprintf(filename, "%sUnkOps.txt", File::GetUserPath(D_DUMPDSP_IDX)); - FILE *uo = fopen(filename, "w"); - if (!uo) - return; - - int count = 0; - for (std::map::const_iterator iter = unk_opcodes.begin(); - iter != unk_opcodes.end(); ++iter) - { - if (iter->second > 0) - { - count++; - fprintf(uo, "OP%04x\t%d", iter->first, iter->second); - for (int j = 15; j >= 0; j--) // print op bits - { - if ((j & 0x3) == 3) - fprintf(uo, "\tb"); - fprintf(uo, "%d", (iter->first >> j) & 0x1); - } - fprintf(uo, "\n"); - } - } - fprintf(uo, "Unknown opcodes count: %d\n", count); - fclose(uo); -} - -bool DSPDisassembler::Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text) -{ - const char *tmp1 = "tmp1.bin"; - - // First we have to dump the code to a bin file. - FILE *f = fopen(tmp1, "wb"); - fwrite(&code[0], 1, code.size() * 2, f); - fclose(f); - - // Run the two passes. - return DisFile(tmp1, base_addr, 1, text) && DisFile(tmp1, base_addr, 2, text); -} - -char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char *strbuf) -{ - char *buf = strbuf; - for (int j = 0; j < opc.param_count; j++) - { - if (j > 0) - buf += sprintf(buf, ", "); - - u32 val = (opc.params[j].loc >= 1) ? op2 : op1; - val &= opc.params[j].mask; - if (opc.params[j].lshift < 0) - val = val << (-opc.params[j].lshift); - else - val = val >> opc.params[j].lshift; - - u32 type = opc.params[j].type; - if ((type & 0xff) == 0x10) - type &= 0xff00; - - if (type & P_REG) - { - // Check for _D parameter - if so flip. - if ((type == P_ACC_D) || (type == P_ACCM_D)) // Used to be P_ACCM_D TODO verify - val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8); - else - val |= (type & P_REGS_MASK) >> 8; - type &= ~P_REGS_MASK; - } - - switch (type) - { - case P_REG: - if (settings_.decode_registers) - sprintf(buf, "$%s", pdregname(val)); - else - sprintf(buf, "$%d", val); - break; - - case P_PRG: - if (settings_.decode_registers) - sprintf(buf, "@$%s", pdregname(val)); - else - sprintf(buf, "@$%d", val); - break; - - case P_VAL: - case P_ADDR_I: - case P_ADDR_D: - if (settings_.decode_names) - { - sprintf(buf, "%s", pdname(val)); - } - else - sprintf(buf, "0x%04x", val); - break; - - case P_IMM: - if (opc.params[j].size != 2) - { - if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR - sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension - else - sprintf(buf, "#0x%02x", val); - } - else - { - sprintf(buf, "#0x%04x", val); - } - break; - - case P_MEM: - if (opc.params[j].size != 2) - val = (u16)(s16)(s8)val; - - if (settings_.decode_names) - sprintf(buf, "@%s", pdname(val)); - else - sprintf(buf, "@0x%04x", val); - break; - - default: - ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc.params[j].type); - break; - } - - buf += strlen(buf); - } - - return strbuf; -} - -static void MakeLowerCase(char *ptr) -{ - int i = 0; - while (ptr[i]) - { - ptr[i] = tolower(ptr[i]); - i++; - } -} - -bool DSPDisassembler::DisOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest) -{ - char buffer[256]; - char *buf = buffer; - - // Start with 8 spaces, if there's no label. - buf[0] = ' '; - buf[1] = '\0'; - buf++; - - if ((*pc & 0x7fff) >= 0x1000) - { - ++pc; - dest.append("; outside memory"); - return false; - } - - const u32 op1 = binbuf[*pc & 0x0fff]; - - const DSPOPCTemplate *opc = NULL; - const DSPOPCTemplate *opc_ext = NULL; - - // find opcode - for (int j = 0; j < opcodes_size; j++) - { - u16 mask = opcodes[j].opcode_mask; - - if ((op1 & mask) == opcodes[j].opcode) - { - opc = &opcodes[j]; - break; - } - } - const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, NULL, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false}; - if (!opc) - opc = &fake_op; - - bool extended = false; - bool only7bitext = false; - - if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f)) { - extended = true; - only7bitext = true; - } - else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff)) - extended = true; - else - extended = false; - - if (extended) - { - // opcode has an extension - // find opcode - for (int j = 0; j < opcodes_ext_size; j++) - { - if (only7bitext) { - if (((op1 & 0x7f) & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) - { - opc_ext = &opcodes_ext[j]; - break; - } - } - else { - if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) - { - opc_ext = &opcodes_ext[j]; - break; - } - } - } - } - - // printing - - if (settings_.show_pc) - buf += sprintf(buf, "%04x ", *pc); - - u32 op2; - - // Size 2 - the op has a large immediate. - if (opc->size == 2) - { - op2 = binbuf[(*pc + 1) & 0x0fff]; - if (settings_.show_hex) - buf += sprintf(buf, "%04x %04x ", op1, op2); - } - else - { - op2 = 0; - if (settings_.show_hex) - buf += sprintf(buf, "%04x ", op1); - } - - char opname[20]; - strcpy(opname, opc->name); - if (settings_.lower_case_ops) - MakeLowerCase(opname); - char ext_buf[20]; - if (extended) - sprintf(ext_buf, "%s%c%s", opname, settings_.ext_separator, opc_ext->name); - else - sprintf(ext_buf, "%s", opname); - if (settings_.lower_case_ops) - MakeLowerCase(ext_buf); - - if (settings_.print_tabs) - buf += sprintf(buf, "%s\t", ext_buf); - else - buf += sprintf(buf, "%-12s", ext_buf); - - if (opc->param_count > 0) - DisParams(*opc, op1, op2, buf); - - buf += strlen(buf); - - // Handle opcode extension. - if (extended) - { - if (opc->param_count > 0) - buf += sprintf(buf, " "); - buf += sprintf(buf, ": "); - if (opc_ext->param_count > 0) - DisParams(*opc_ext, op1, op2, buf); - - buf += strlen(buf); - } - - if (opc->opcode_mask == 0) - { - // unknown opcode - unk_opcodes[op1]++; - sprintf(buf, "\t\t; *** UNKNOWN OPCODE ***"); - } - - if (extended) - *pc += opc_ext->size; - else - *pc += opc->size; - - if (pass == 2) - dest.append(buffer); - return true; -} - -bool DSPDisassembler::DisFile(const char* name, int base_addr, int pass, std::string &output) -{ - FILE* in = fopen(name, "rb"); - if (in == NULL) - { - printf("gd_dis_file: No input\n"); - return false; - } - - int size = (int)File::GetSize(in) & ~1; - u16 *binbuf = new u16[size / 2]; - fread(binbuf, 1, size, in); - fclose(in); - - // Actually do the disassembly. - for (u16 pc = 0; pc < (size / 2);) - { - DisOpcode(binbuf, base_addr, pass, &pc, output); - if (pass == 2) - output.append("\n"); - } - delete [] binbuf; - return true; -} diff --git a/Source/Core/DSPCore/Src/disassemble.h b/Source/Core/DSPCore/Src/disassemble.h deleted file mode 100644 index dba9f36287..0000000000 --- a/Source/Core/DSPCore/Src/disassemble.h +++ /dev/null @@ -1,87 +0,0 @@ -/*==================================================================== - - project: GameCube DSP Tool (gcdsp) - created: 2005.03.04 - mail: duddie@walla.com - - Copyright (c) 2005 Duddie - - This program is free software; you can redistribute it and/or - modify it 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 received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - ====================================================================*/ - -#ifndef _DSP_DISASSEMBLE_H -#define _DSP_DISASSEMBLE_H - -#include -#include - -#include "Common.h" -#include "DSPTables.h" -#include "LabelMap.h" - -struct AssemblerSettings -{ - AssemblerSettings() - : print_tabs(false), - show_hex(false), - show_pc(false), - force(false), - decode_names(true), - decode_registers(true), - ext_separator('\''), - lower_case_ops(true), - pc(0) - { - } - - bool print_tabs; - bool show_hex; - bool show_pc; - bool force; - bool decode_names; - bool decode_registers; - char ext_separator; - bool lower_case_ops; - - u16 pc; -}; - -class DSPDisassembler -{ -public: - DSPDisassembler(const AssemblerSettings &settings); - ~DSPDisassembler(); - - bool Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text); - - // Warning - this one is trickier to use right. - // Use pass == 2 if you're just using it by itself. - bool DisOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest); - -private: - // Moves PC forward and writes the result to dest. - bool DisFile(const char* name, int base_addr, int pass, std::string &output); - - char* DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char* strbuf); - std::map unk_opcodes; - - const AssemblerSettings settings_; - - LabelMap labels; -}; - -#endif // _DSP_DISASSEMBLE_H - diff --git a/Source/Core/DebuggerWX/DebuggerWX.vcproj b/Source/Core/DebuggerWX/DebuggerWX.vcproj index 40ec7fe6e6..03c79dfb60 100644 --- a/Source/Core/DebuggerWX/DebuggerWX.vcproj +++ b/Source/Core/DebuggerWX/DebuggerWX.vcproj @@ -46,7 +46,7 @@ Name="VCCLCompilerTool" Optimization="0" WholeProgramOptimization="false" - AdditionalIncludeDirectories="..\Common\Src;..\Core\Src;..\InputCommon\Src;..\DSPCore\Src;..\..\PluginSpecs;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\DebuggerUICommon\Src" + AdditionalIncludeDirectories="..\Common\Src;..\Core\Src;..\InputCommon\Src;..\..\PluginSpecs;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\DebuggerUICommon\Src" PreprocessorDefinitions="WIN32;_DEBUG;_LIB;__WXMSW__;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -113,7 +113,7 @@ Name="VCCLCompilerTool" Optimization="0" WholeProgramOptimization="false" - AdditionalIncludeDirectories="..\Common\Src;..\Core\Src;..\InputCommon\Src;..\DSPCore\Src;..\..\PluginSpecs;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\DebuggerUICommon\Src" + AdditionalIncludeDirectories="..\Common\Src;..\Core\Src;..\InputCommon\Src;..\..\PluginSpecs;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\DebuggerUICommon\Src" PreprocessorDefinitions="WIN32;_DEBUG;_LIB;__WXMSW__;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" MinimalRebuild="true" ExceptionHandling="2" @@ -179,7 +179,7 @@ #include -#include "disassemble.h" -#include "DSPInterpreter.h" -#include "DSPMemoryMap.h" +#include "DSP/disassemble.h" +#include "DSP/DSPInterpreter.h" +#include "DSP/DSPMemoryMap.h" #include "HW/DSPLLE/DSPDebugInterface.h" class DSPRegisterView; diff --git a/Source/Core/DolphinWX/Src/SConscript b/Source/Core/DolphinWX/Src/SConscript index 7e3ea1a5cf..bccbef4232 100644 --- a/Source/Core/DolphinWX/Src/SConscript +++ b/Source/Core/DolphinWX/Src/SConscript @@ -10,8 +10,9 @@ files = [ ] libs = [ - 'audiocommon', 'bdisasm', 'common', 'core', 'discio', 'dspcore', - 'inputcommon', 'lua', 'lzo2', 'sfml-network', 'z', 'GLEW', 'SOIL', + 'core', + 'audiocommon', 'common', 'discio', 'inputcommon', + 'GLEW', 'SOIL', 'bdisasm', 'lua', 'lzo2', 'sfml-network', 'z', ] wxlibs = [ ] @@ -72,7 +73,6 @@ elif sys.platform == 'darwin': else: exe += 'NoGUI' - env.Depends(exe, env['libvideo']) env.Install('#' + env['prefix'] + '/Dolphin.app/Contents/' + 'Frameworks/Cg.framework', source = [ @@ -107,7 +107,7 @@ elif sys.platform == 'darwin': Value(dict( CFBundleExecutable = 'Dolphin', CFBundleIconFile = 'Dolphin.icns', - CFBundleIdentifier = 'com.dolphin-emu.dolphin', + CFBundleIdentifier = 'com.dolphin-emulator.dolphin', CFBundlePackageType = 'APPL', CFBundleShortVersionString = utils.GenerateRevFile('', Dir('#None').abspath, None), @@ -126,7 +126,10 @@ elif sys.platform == 'darwin': "find $SOURCES -name .svn -exec rm -rf {} +") else: files += [ 'X11Utils.cpp' ] - libs += [ 'SDL' ] + libs += [ 'SDL', 'clrun' ] + ldflags += [ '-Wl,--whole-archive,' + env['libvideo'][0].path ] + ldflags += [ '-Wl,--no-whole-archive' ] + ldflags += [ '-Wl,-Wsymbolic' ] if env['HAVE_WX']: exe = env['binary_dir'] + '/dolphin-emu' else: @@ -137,4 +140,5 @@ else: libs = wxlibs + libs + env['LIBS'] linkflags = ldflags + env['LINKFLAGS'] +env.Depends(exe, env['libvideo']) env.Program(exe, files, LIBS = libs, LINKFLAGS = linkflags) -- cgit v1.2.3