Merge latest master changes

This commit is contained in:
Rodolfo Bogado 2016-12-30 15:33:06 -03:00
parent a5d2d480c0
commit c04c806270
203 changed files with 13399 additions and 13369 deletions

View file

@ -15,6 +15,12 @@ option(ENABLE_PCH "Use PCH to speed up compilation" ON)
option(ENABLE_LTO "Enables Link Time Optimization" OFF)
option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF)
option(ENABLE_HEADLESS "Enables running Dolphin as a headless variant" OFF)
option(ENABLE_ALSA "Enables ALSA sound backend" ON)
option(ENABLE_AO "Enables libao sound backend" ON)
option(ENABLE_PULSEAUDIO "Enables PulseAudio sound backend" ON)
option(ENABLE_OPENAL "Enables OpenAL sound backend" ON)
option(ENABLE_LLVM "Enables LLVM support, for disassembly" ON)
option(ENABLE_BLUEZ "Enables bluetooth support" ON)
# Maintainers: if you consider blanket disabling this for your users, please
# consider the following points:
@ -291,17 +297,6 @@ if(APPLE)
# features can be used, not the minimum required version to run.
set(OSX_MIN_VERSION "10.9")
set(TARGET_FLAGS "${TARGET_FLAGS} -mmacosx-version-min=${OSX_MIN_VERSION}")
set(SYSROOT_LEGACY_PATH "/Developer/SDKs/MacOSX10.9.sdk")
set(SYSROOT_PATH "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk")
if(EXISTS "${SYSROOT_PATH}/")
set(TARGET_SYSROOT ${SYSROOT_PATH})
elseif(EXISTS "${SYSROOT_LEGACY_PATH}/")
set(TARGET_SYSROOT ${SYSROOT_LEGACY_PATH})
endif()
if(${TARGET_SYSROOT})
set(TARGET_FLAGS "${TARGET_FLAGS} -isysroot ${TARGET_SYSROOT}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-syslibroot,${TARGET_SYSROOT}")
endif()
# Do not warn about frameworks that are not available on all architectures.
# This avoids a warning when linking with QuickTime.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_arch_warnings")
@ -456,61 +451,83 @@ if (OPENGL_GL)
include_directories(${OPENGL_INCLUDE_DIR})
endif()
include(FindALSA OPTIONAL)
if(ALSA_FOUND)
add_definitions(-DHAVE_ALSA=1)
message("ALSA found, enabling ALSA sound backend")
if(ENABLE_ALSA)
include(FindALSA OPTIONAL)
if(ALSA_FOUND)
add_definitions(-DHAVE_ALSA=1)
message("ALSA found, enabling ALSA sound backend")
else()
add_definitions(-DHAVE_ALSA=0)
message("ALSA NOT found, disabling ALSA sound backend")
endif()
else()
add_definitions(-DHAVE_ALSA=0)
message("ALSA NOT found, disabling ALSA sound backend")
endif(ALSA_FOUND)
message("ALSA explicitly disabled, disabling ALSA sound backend")
endif()
check_lib(AO ao ao QUIET)
if(AO_FOUND)
add_definitions(-DHAVE_AO=1)
message("ao found, enabling ao sound backend")
if(ENABLE_AO)
check_lib(AO ao ao QUIET)
if(AO_FOUND)
add_definitions(-DHAVE_AO=1)
message("ao found, enabling ao sound backend")
else()
add_definitions(-DHAVE_AO=0)
message("ao NOT found, disabling ao sound backend")
endif()
else()
add_definitions(-DHAVE_AO=0)
message("ao NOT found, disabling ao sound backend")
endif(AO_FOUND)
message("ao explicitly disabled, disabling ao sound backend")
endif()
check_lib(BLUEZ bluez bluez QUIET)
if(BLUEZ_FOUND)
add_definitions(-DHAVE_BLUEZ=1)
message("bluez found, enabling bluetooth support")
if(ENABLE_BLUEZ)
check_lib(BLUEZ bluez bluez QUIET)
if(BLUEZ_FOUND)
add_definitions(-DHAVE_BLUEZ=1)
message("bluez found, enabling bluetooth support")
else()
add_definitions(-DHAVE_BLUEZ=0)
message("bluez NOT found, disabling bluetooth support")
endif()
else()
add_definitions(-DHAVE_BLUEZ=0)
message("bluez NOT found, disabling bluetooth support")
endif(BLUEZ_FOUND)
message("bluez explicitly disabled, disabling bluetooth support")
endif()
check_lib(PULSEAUDIO libpulse pulse QUIET)
if(PULSEAUDIO_FOUND)
add_definitions(-DHAVE_PULSEAUDIO=1)
message("PulseAudio found, enabling PulseAudio sound backend")
if(ENABLE_PULSEAUDIO)
check_lib(PULSEAUDIO libpulse pulse QUIET)
if(PULSEAUDIO_FOUND)
add_definitions(-DHAVE_PULSEAUDIO=1)
message("PulseAudio found, enabling PulseAudio sound backend")
else()
add_definitions(-DHAVE_PULSEAUDIO=0)
message("PulseAudio NOT found, disabling PulseAudio sound backend")
endif()
else()
add_definitions(-DHAVE_PULSEAUDIO=0)
message("PulseAudio NOT found, disabling PulseAudio sound backend")
endif(PULSEAUDIO_FOUND)
message("PulseAudio explicitly disabled, disabling PulseAudio sound backend")
endif()
include(FindOpenAL OPTIONAL)
if(OPENAL_FOUND)
add_definitions(-DHAVE_OPENAL=1)
include_directories(${OPENAL_INCLUDE_DIR})
message("OpenAL found, enabling OpenAL sound backend")
if(ENABLE_OPENAL)
include(FindOpenAL OPTIONAL)
if(OPENAL_FOUND)
add_definitions(-DHAVE_OPENAL=1)
include_directories(${OPENAL_INCLUDE_DIR})
message("OpenAL found, enabling OpenAL sound backend")
else()
add_definitions(-DHAVE_OPENAL=0)
message("OpenAL NOT found, disabling OpenAL sound backend")
endif()
else()
add_definitions(-DHAVE_OPENAL=0)
message("OpenAL NOT found, disabling OpenAL sound backend")
endif(OPENAL_FOUND)
message("OpenAL explicitly disabled, disabling OpenAL sound backend")
endif()
include(FindLLVM OPTIONAL)
if (LLVM_FOUND)
add_definitions(-DHAS_LLVM=1)
set(HAS_LLVM 1)
if(ENABLE_LLVM)
include(FindLLVM OPTIONAL)
if (LLVM_FOUND)
add_definitions(-DHAS_LLVM=1)
set(HAS_LLVM 1)
include_directories(${LLVM_INCLUDE_DIRS})
list(APPEND LIBS ${LLVM_LIBRARIES})
include_directories(${LLVM_INCLUDE_DIRS})
list(APPEND LIBS ${LLVM_LIBRARIES})
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
endif()
endif()
set(USE_X11 0)
@ -718,8 +735,17 @@ else()
set(PNG png)
endif()
if(NOT APPLE)
check_lib(SOUNDTOUCH soundtouch SoundTouch soundtouch/SoundTouch.h QUIET)
if(OPENAL_FOUND)
if(NOT APPLE)
check_lib(SOUNDTOUCH soundtouch SoundTouch soundtouch/SoundTouch.h QUIET)
endif()
if (SOUNDTOUCH_FOUND)
message("Using shared soundtouch")
else()
message("Using static soundtouch from Externals")
add_subdirectory(Externals/soundtouch)
include_directories(Externals)
endif()
endif()
if (SOUNDTOUCH_FOUND)
message("Using shared soundtouch")
@ -749,19 +775,19 @@ if(ENABLE_SDL)
endif()
if(NOT ANDROID)
add_definitions(-D__LIBUSB__)
if(NOT APPLE)
find_package(LibUSB)
endif()
if(LIBUSB_FOUND AND NOT APPLE)
message("Using shared LibUSB")
include_directories(${LIBUSB_INCLUDE_DIR})
else()
message("Using static LibUSB from Externals")
add_subdirectory(Externals/libusb)
set(LIBUSB_LIBRARIES usb)
endif()
set(LIBUSB_FOUND true)
add_definitions(-D__LIBUSB__)
if(NOT APPLE)
find_package(LibUSB)
endif()
if(LIBUSB_FOUND AND NOT APPLE)
message("Using shared LibUSB")
include_directories(${LIBUSB_INCLUDE_DIR})
else()
message("Using static LibUSB from Externals")
add_subdirectory(Externals/libusb)
set(LIBUSB_LIBRARIES usb)
endif()
set(LIBUSB_FOUND true)
endif()
set(SFML_REQD_VERSION 2.1)

View file

@ -1,4 +1,4 @@
The two fonts in this directory (font_ansi.bin and font_sjis.bin) were
The two fonts in this directory (font_western.bin and font_japanese.bin) were
generated using gc-font-tool which can be found in the docs/ directory in the
dolphin source code.

View file

@ -10,7 +10,6 @@ EmulationStateId = 4
[Video_Settings]
SafeTextureCacheColorSamples = 0
EFBScale = 2
[Video_Hacks]
# Some very early NES releases use a version of the NES emulator that doesn't require EFB2Ram.

View file

@ -350,6 +350,3 @@ C03F0034 2C0E0001
EC210032 C0010034
EC210024 39C00000
281E0000 00000000
[Video_Settings]
EFBScale = -1

View file

@ -18,5 +18,5 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
EFBScale = 1
EFBScale = -1

View file

@ -0,0 +1,22 @@
# P4BJ01 - Biohazard 4 Preview Disc
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId =
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# override value that was set in P.ini back to defaults
SafeTextureCacheColorSamples =

View file

@ -0,0 +1,22 @@
# PCKJ01 - Pokemon Colosseum Bonus Disc
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId =
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# override value that was set in P.ini back to defaults
SafeTextureCacheColorSamples =

View file

@ -0,0 +1,22 @@
# PCSJ01 - Pokemon Colosseum Bonus Disc
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId =
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# override value that was set in P.ini back to defaults
SafeTextureCacheColorSamples =

View file

@ -0,0 +1,22 @@
# PGSJ01 - METAL GEAR SOLID Special Disc
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId =
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# override value that was set in P.ini back to defaults
SafeTextureCacheColorSamples =

View file

@ -0,0 +1,22 @@
# PNRJ01 - NARUTO COLLECTION
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId =
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# override value that was set in P.ini back to defaults
SafeTextureCacheColorSamples =

View file

@ -0,0 +1,21 @@
# SNSE52 - Nascar: The Game 2011
[Core]
# Values set here will override the main Dolphin settings.
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues =
EmulationStateId =
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
SafeTextureCacheColorSamples = 0

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,8 @@ public class FileListItem implements Comparable<FileListItem>
String fileExtension = mPath.substring(extensionStart);
// The extensions we care about.
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".tgc", ".wad", ".wbfs"));
// Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase()))

View file

@ -150,7 +150,8 @@ public final class GameDatabase extends SQLiteOpenHelper
null,
null); // Order of folders is irrelevant.
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".tgc", ".wad", ".wbfs"));
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
folderCursor.moveToPosition(-1);

View file

@ -114,8 +114,8 @@
// Sys files
#define TOTALDB "totaldb.dsy"
#define FONT_ANSI "font_ansi.bin"
#define FONT_SJIS "font_sjis.bin"
#define FONT_WINDOWS_1252 "font_western.bin"
#define FONT_SHIFT_JIS "font_japanese.bin"
#define DSP_IROM "dsp_rom.bin"
#define DSP_COEF "dsp_coef.bin"

View file

@ -439,12 +439,10 @@ bool CreateEmptyFile(const std::string& filename)
return true;
}
// Scans the directory tree gets, starting from _Directory and adds the
// results into parentEntry. Returns the number of files+directories found
// Recursive or non-recursive list of files and directories under directory.
FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive)
{
INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
// How many files + directories we found
FSTEntry parent_entry;
parent_entry.physicalName = directory;
parent_entry.isDirectory = true;
@ -464,14 +462,12 @@ FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive)
{
const std::string virtual_name(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = nullptr;
DIR* dirp = opendir(directory.c_str());
if (!dirp)
return parent_entry;
// non Windows loop
while (!readdir_r(dirp, &dirent, &result) && result)
while (dirent* result = readdir(dirp))
{
const std::string virtual_name(result->d_name);
#endif
@ -505,7 +501,6 @@ FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive)
}
closedir(dirp);
#endif
// Return number of entries found.
return parent_entry;
}
@ -531,13 +526,12 @@ bool DeleteDirRecursively(const std::string& directory)
{
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = nullptr;
DIR* dirp = opendir(directory.c_str());
if (!dirp)
return false;
// non Windows loop
while (!readdir_r(dirp, &dirent, &result) && result)
while (dirent* result = readdir(dirp))
{
const std::string virtualName = result->d_name;
#endif
@ -602,12 +596,11 @@ void CopyDir(const std::string& source_path, const std::string& dest_path)
{
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = nullptr;
DIR* dirp = opendir(source_path.c_str());
if (!dirp)
return;
while (!readdir_r(dirp, &dirent, &result) && result)
while (dirent* result = readdir(dirp))
{
const std::string virtualName(result->d_name);
#endif

View file

@ -114,7 +114,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename);
// creates an empty file filename, returns true on success
bool CreateEmptyFile(const std::string& filename);
// Recursive or non-recursive list of files under directory.
// Recursive or non-recursive list of files and directories under directory.
FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive);
// deletes the given directory and anything under it. Returns true on success.

View file

@ -19,9 +19,9 @@ const std::string scm_rev_str = "Ishiiruka-Dolphin"
#endif
#ifdef __INTEL_COMPILER
BUILD_TYPE_STR SCM_DESC_STR "-ICC";
" " BUILD_TYPE_STR " " SCM_DESC_STR "-ICC";
#else
BUILD_TYPE_STR SCM_DESC_STR;
" " BUILD_TYPE_STR " " SCM_DESC_STR;
#endif
#ifdef _WIN32

View file

@ -107,7 +107,7 @@ describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2');
var out_contents =
"#define SCM_REV_STR \"" + revision + "\"\n" +
"#define SCM_DESC_STR \" " + revcount + " (" + describe + ")\"\n" +
"#define SCM_DESC_STR \"" + revcount + " (" + describe + ")\"\n" +
"#define SCM_BRANCH_STR \"" + branch + "\"\n" +
"#define SCM_CACHE_STR \"" + cacheversion + "\"\n" +
"#define SCM_IS_MASTER " + isStable + "\n" +

View file

@ -29,23 +29,23 @@ set(SRCS ActionReplay.cpp
DSP/DSPDisassembler.cpp
DSP/DSPAccelerator.cpp
DSP/DSPCaptureLogger.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/Interpreter/DSPIntArithmetic.cpp
DSP/Interpreter/DSPIntBranch.cpp
DSP/Interpreter/DSPIntCCUtil.cpp
DSP/Interpreter/DSPInterpreter.cpp
DSP/Interpreter/DSPIntExtOps.cpp
DSP/Interpreter/DSPIntLoadStore.cpp
DSP/Interpreter/DSPIntMisc.cpp
DSP/Interpreter/DSPIntMultiplier.cpp
DSP/Jit/DSPEmitter.cpp
DSP/Jit/DSPJitRegCache.cpp
DSP/Jit/DSPJitExtOps.cpp
DSP/Jit/DSPJitBranch.cpp

View file

@ -188,6 +188,7 @@ void SConfig::SaveInterfaceSettings(IniFile& ini)
interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo);
interface->Set("ThemeName", theme_name);
interface->Set("PauseOnFocusLost", m_PauseOnFocusLost);
interface->Set("DisableTooltips", m_DisableTooltips);
}
void SConfig::SaveDisplaySettings(IniFile& ini)
@ -493,6 +494,7 @@ void SConfig::LoadInterfaceSettings(IniFile& ini)
interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false);
interface->Get("ThemeName", &theme_name, DEFAULT_THEME_DIR);
interface->Get("PauseOnFocusLost", &m_PauseOnFocusLost, false);
interface->Get("DisableTooltips", &m_DisableTooltips, false);
}
void SConfig::LoadDisplaySettings(IniFile& ini)
@ -850,8 +852,9 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
std::string Extension;
SplitPath(m_strFilename, nullptr, nullptr, &Extension);
if (!strcasecmp(Extension.c_str(), ".gcm") || !strcasecmp(Extension.c_str(), ".iso") ||
!strcasecmp(Extension.c_str(), ".wbfs") || !strcasecmp(Extension.c_str(), ".ciso") ||
!strcasecmp(Extension.c_str(), ".gcz") || bootDrive)
!strcasecmp(Extension.c_str(), ".tgc") || !strcasecmp(Extension.c_str(), ".wbfs") ||
!strcasecmp(Extension.c_str(), ".ciso") || !strcasecmp(Extension.c_str(), ".gcz") ||
bootDrive)
{
m_BootType = BOOT_ISO;
std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename));

View file

@ -297,6 +297,8 @@ struct SConfig : NonCopyable
bool m_PauseOnFocusLost;
bool m_DisableTooltips;
// DSP settings
bool m_DSPEnableJIT;
bool m_DSPCaptureLog;

View file

@ -62,19 +62,19 @@
<ClCompile Include="DSP\DSPCaptureLogger.cpp" />
<ClCompile Include="DSP\DSPCodeUtil.cpp" />
<ClCompile Include="DSP\DSPCore.cpp" />
<ClCompile Include="DSP\DSPEmitter.cpp" />
<ClCompile Include="DSP\DSPHWInterface.cpp" />
<ClCompile Include="DSP\DSPIntArithmetic.cpp" />
<ClCompile Include="DSP\DSPIntBranch.cpp" />
<ClCompile Include="DSP\DSPIntCCUtil.cpp" />
<ClCompile Include="DSP\DSPInterpreter.cpp" />
<ClCompile Include="DSP\DSPIntExtOps.cpp" />
<ClCompile Include="DSP\DSPIntLoadStore.cpp" />
<ClCompile Include="DSP\DSPIntMisc.cpp" />
<ClCompile Include="DSP\DSPIntMultiplier.cpp" />
<ClCompile Include="DSP\DSPMemoryMap.cpp" />
<ClCompile Include="DSP\DSPStacks.cpp" />
<ClCompile Include="DSP\DSPTables.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntArithmetic.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp" />
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntExtOps.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntLoadStore.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntMisc.cpp" />
<ClCompile Include="DSP\Interpreter\DSPIntMultiplier.cpp" />
<ClCompile Include="DSP\Jit\DSPEmitter.cpp" />
<ClCompile Include="DSP\Jit\DSPJitArithmetic.cpp" />
<ClCompile Include="DSP\Jit\DSPJitBranch.cpp" />
<ClCompile Include="DSP\Jit\DSPJitCCUtil.cpp" />
@ -286,16 +286,16 @@
<ClInclude Include="DSP\DSPCodeUtil.h" />
<ClInclude Include="DSP\DSPCommon.h" />
<ClInclude Include="DSP\DSPCore.h" />
<ClInclude Include="DSP\DSPEmitter.h" />
<ClInclude Include="DSP\DSPHost.h" />
<ClInclude Include="DSP\DSPHWInterface.h" />
<ClInclude Include="DSP\DSPIntCCUtil.h" />
<ClInclude Include="DSP\DSPInterpreter.h" />
<ClInclude Include="DSP\DSPIntExtOps.h" />
<ClInclude Include="DSP\DSPIntUtil.h" />
<ClInclude Include="DSP\DSPMemoryMap.h" />
<ClInclude Include="DSP\DSPStacks.h" />
<ClInclude Include="DSP\DSPTables.h" />
<ClInclude Include="DSP\Interpreter\DSPIntCCUtil.h" />
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h" />
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h" />
<ClInclude Include="DSP\Interpreter\DSPIntUtil.h" />
<ClInclude Include="DSP\Jit\DSPEmitter.h" />
<ClInclude Include="DSP\Jit\DSPJitRegCache.h" />
<ClInclude Include="DSP\LabelMap.h" />
<ClInclude Include="ec_wii.h" />

View file

@ -186,30 +186,33 @@
<ClCompile Include="Debugger\PPCDebugInterface.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntArithmetic.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntArithmetic.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntBranch.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntCCUtil.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPInterpreter.cpp">
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntExtOps.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntExtOps.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntLoadStore.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntLoadStore.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntMisc.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntMisc.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPIntMultiplier.cpp">
<ClCompile Include="DSP\Interpreter\DSPIntMultiplier.cpp">
<Filter>DSPCore\Interpreter</Filter>
</ClCompile>
<ClCompile Include="DSP\Jit\DSPEmitter.cpp">
<Filter>DSPCore\Jit</Filter>
</ClCompile>
<ClCompile Include="DSP\Jit\DSPJitArithmetic.cpp">
<Filter>DSPCore\Jit</Filter>
</ClCompile>
@ -237,9 +240,6 @@
<ClCompile Include="DSP\Jit\DSPJitUtil.cpp">
<Filter>DSPCore\Jit</Filter>
</ClCompile>
<ClCompile Include="DSP\DSPEmitter.cpp">
<Filter>DSPCore\Jit</Filter>
</ClCompile>
<ClCompile Include="FifoPlayer\FifoAnalyzer.cpp">
<Filter>FifoPlayer</Filter>
</ClCompile>
@ -809,24 +809,24 @@
<ClInclude Include="Debugger\PPCDebugInterface.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="DSP\DSPIntCCUtil.h">
<ClInclude Include="DSP\Interpreter\DSPIntCCUtil.h">
<Filter>DSPCore\Interpreter</Filter>
</ClInclude>
<ClInclude Include="DSP\DSPInterpreter.h">
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h">
<Filter>DSPCore\Interpreter</Filter>
</ClInclude>
<ClInclude Include="DSP\DSPIntExtOps.h">
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h">
<Filter>DSPCore\Interpreter</Filter>
</ClInclude>
<ClInclude Include="DSP\DSPIntUtil.h">
<ClInclude Include="DSP\Interpreter\DSPIntUtil.h">
<Filter>DSPCore\Interpreter</Filter>
</ClInclude>
<ClInclude Include="DSP\Jit\DSPJitRegCache.h">
<Filter>DSPCore\Jit</Filter>
</ClInclude>
<ClInclude Include="DSP\DSPEmitter.h">
<Filter>DSPCore\Jit</Filter>
</ClInclude>
<ClInclude Include="DSP\Jit\DSPJitRegCache.h">
<Filter>DSPCore\Jit</Filter>
</ClInclude>
<ClInclude Include="FifoPlayer\FifoAnalyzer.h">
<Filter>FifoPlayer</Filter>
</ClInclude>

View file

@ -2,18 +2,19 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPAccelerator.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/MathUtil.h"
#include "Core/DSP/DSPAccelerator.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/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];
const s16* pCoefTable = (const s16*)&g_dsp.ifx_regs[DSP_COEF_A1_0];
if ((_rSamplePos & 15) == 0)
{
@ -27,15 +28,16 @@ static s16 ADPCM_Step(u32& _rSamplePos)
s32 coef1 = pCoefTable[coef_idx * 2 + 0];
s32 coef2 = pCoefTable[coef_idx * 2 + 1];
int temp = (_rSamplePos & 1) ?
(DSPHost::ReadHostMemory(_rSamplePos >> 1) & 0xF) :
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);
int val =
(scale * temp) +
((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11);
val = MathUtil::Clamp(val, -0x7FFF, 0x7FFF);
g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1];
@ -57,11 +59,11 @@ u16 dsp_read_aram_d3()
switch (g_dsp.ifx_regs[DSP_FORMAT])
{
case 0x5: // u8 reads
case 0x5: // u8 reads
val = DSPHost::ReadHostMemory(Address);
Address++;
break;
case 0x6: // u16 reads
case 0x6: // u16 reads
val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1);
Address++;
break;
@ -91,7 +93,7 @@ void dsp_write_aram_d3(u16 value)
switch (g_dsp.ifx_regs[DSP_FORMAT])
{
case 0xA: // u16 writes
case 0xA: // u16 writes
DSPHost::WriteHostMemory(value >> 8, Address * 2);
DSPHost::WriteHostMemory(value & 0xFF, Address * 2 + 1);
Address++;
@ -123,10 +125,10 @@ u16 dsp_read_accelerator()
case 0x00: // ADPCM audio
switch (EndAddress & 15)
{
case 0: // Tom and Jerry
case 0: // Tom and Jerry
step_size_bytes = 1;
break;
case 1: // Blazing Angels
case 1: // Blazing Angels
step_size_bytes = 0;
break;
default:

View file

@ -2,14 +2,21 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPInterpreter.h"
#include <array>
#include <cstddef>
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
namespace DSPAnalyzer {
namespace DSPAnalyzer
{
namespace
{
constexpr size_t ISPACE = 65536;
// Holds data about all instructions in RAM.
std::array<u8, ISPACE> code_flags;
@ -19,55 +26,53 @@ std::array<u8, ISPACE> code_flags;
// 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
constexpr size_t NUM_IDLE_SIGS = 8;
constexpr size_t MAX_IDLE_SIG_SIZE = 6;
// 0xFFFF means ignore.
const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
{
constexpr 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 }
};
{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} };
static void Reset()
void Reset()
{
code_flags.fill(0);
}
static void AnalyzeRange(u16 start_addr, u16 end_addr)
void AnalyzeRange(u16 start_addr, u16 end_addr)
{
// First we run an extremely simplified version of a disassembler to find
// where all instructions start.
@ -78,7 +83,7 @@ static void AnalyzeRange(u16 start_addr, u16 end_addr)
for (u16 addr = start_addr; addr < end_addr;)
{
UDSPInstruction inst = dsp_imem_read(addr);
const DSPOPCTemplate *opcode = GetOpTemplate(inst);
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
if (!opcode)
{
addr++;
@ -114,14 +119,9 @@ static void AnalyzeRange(u16 start_addr, u16 end_addr)
// 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
)
if (opcode->opcode == 0x00c0 || opcode->opcode == 0x1800 || opcode->opcode == 0x1880 ||
opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 ||
opcode->extended)
code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_INT;
addr += opcode->size;
@ -151,6 +151,7 @@ static void AnalyzeRange(u16 start_addr, u16 end_addr)
}
INFO_LOG(DSPLLE, "Finished analysis.");
}
} // Anonymous namespace
void Analyze()
{
@ -159,4 +160,9 @@ void Analyze()
AnalyzeRange(0x8000, 0x9000); // IROM
}
} // namespace
u8 GetCodeFlags(u16 address)
{
return code_flags[address];
}
} // namespace DSPAnalyzer

View file

@ -4,14 +4,11 @@
#pragma once
#include <array>
#include "Common/CommonTypes.h"
// Basic code analysis.
namespace DSPAnalyzer
{
#define ISPACE 65536
// Useful things to detect:
// * Loop endpoints - so that we can avoid checking for loops every cycle.
@ -25,11 +22,6 @@ enum
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 std::array<u8, ISPACE> code_flags;
// 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
@ -38,4 +30,7 @@ extern std::array<u8, ISPACE> code_flags;
// some pretty expensive analysis if necessary.
void Analyze();
} // namespace
// Retrieves the flags set during analysis for code in memory.
u8 GetCodeFlags(u16 address);
} // namespace DSPAnalyzer

View file

@ -3,8 +3,11 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPAssembler.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <map>
@ -13,12 +16,10 @@
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Core/DSP/DSPAssembler.h"
#include "Core/DSP/DSPDisassembler.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPTables.h"
static const char *err_string[] =
static const char* err_string[] =
{
"",
"Unknown Error",
@ -42,17 +43,13 @@ static const char *err_string[] =
"Wrong parameter: must be accumulator register",
"Wrong parameter: must be mid accumulator register",
"Invalid register",
"Number out of range"
};
"Number out of range" };
DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
gdg_buffer(nullptr),
m_cur_addr(0),
m_cur_pass(0),
m_current_param(0),
settings_(settings)
DSPAssembler::DSPAssembler(const AssemblerSettings& settings)
: gdg_buffer(nullptr), m_cur_addr(0), m_cur_pass(0), m_current_param(0), settings_(settings)
{}
{
}
DSPAssembler::~DSPAssembler()
{
@ -60,11 +57,12 @@ DSPAssembler::~DSPAssembler()
free(gdg_buffer);
}
bool DSPAssembler::Assemble(const std::string& text, std::vector<u16> &code, std::vector<int> *line_numbers)
bool DSPAssembler::Assemble(const std::string& text, std::vector<u16>& code,
std::vector<int>* line_numbers)
{
if (line_numbers)
line_numbers->clear();
const char *fname = "tmp.asm";
const char* fname = "tmp.asm";
if (!File::WriteStringToFile(text, fname))
return false;
InitPass(1);
@ -74,7 +72,7 @@ bool DSPAssembler::Assemble(const std::string& text, std::vector<u16> &code, std
// We now have the size of the output buffer
if (m_totalSize > 0)
{
gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
gdg_buffer = (char*)malloc(m_totalSize * sizeof(u16) + 4);
if (!gdg_buffer)
return false;
@ -90,7 +88,7 @@ bool DSPAssembler::Assemble(const std::string& text, std::vector<u16> &code, std
code.resize(m_totalSize);
for (int i = 0; i < m_totalSize; i++)
{
code[i] = *(u16 *)(gdg_buffer + i * 2);
code[i] = *(u16*)(gdg_buffer + i * 2);
}
if (gdg_buffer)
@ -105,28 +103,28 @@ bool DSPAssembler::Assemble(const std::string& text, std::vector<u16> &code, std
return true;
}
void DSPAssembler::ShowError(err_t err_code, const char *extra_info)
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;
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);
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);
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;
}
static char *skip_spaces(char *ptr)
static char* skip_spaces(char* ptr)
{
while (*ptr == ' ')
ptr++;
@ -134,11 +132,11 @@ static char *skip_spaces(char *ptr)
}
// Parse a standalone value - it can be a number in one of several formats or a label.
s32 DSPAssembler::ParseValue(const char *str)
s32 DSPAssembler::ParseValue(const char* str)
{
bool negative = false;
s32 val = 0;
const char *ptr = str;
const char* ptr = str;
if (ptr[0] == '#')
{
@ -167,7 +165,7 @@ s32 DSPAssembler::ParseValue(const char *str)
{
switch (ptr[1])
{
case 'X': // hex
case 'X': // hex
for (int i = 2; ptr[i] != 0; i++)
{
val <<= 4;
@ -181,7 +179,7 @@ s32 DSPAssembler::ParseValue(const char *str)
ShowError(ERR_INCORRECT_HEX, str);
}
break;
case '\'': // binary
case '\'': // binary
for (int i = 2; ptr[i] != 0; i++)
{
val *= 2;
@ -232,14 +230,15 @@ s32 DSPAssembler::ParseValue(const char *str)
// - Text within the first and last opening ('(') and closing (')') parentheses.
// - If text follows after these parentheses, then this is what is returned from the function.
//
// Note that the first opening parenthesis and the last closing parenthesis are discarded from the string.
// Note that the first opening parenthesis and the last closing parenthesis are discarded from the
// string.
// For example: Say "Test (string) 1234" is the string passed in as src.
//
// - src will become "Test "
// - dst will become "string"
// - Returned string from the function will be " 1234"
//
char *DSPAssembler::FindBrackets(char *src, char *dst)
char* DSPAssembler::FindBrackets(char* src, char* dst)
{
s32 len = (s32)strlen(src);
s32 first = -1;
@ -286,13 +285,13 @@ char *DSPAssembler::FindBrackets(char *src, char *dst)
}
// Bizarre in-place expression evaluator.
u32 DSPAssembler::ParseExpression(const char *ptr)
u32 DSPAssembler::ParseExpression(const char* ptr)
{
char *pbuf;
char* pbuf;
s32 val = 0;
char *d_buffer = (char *)malloc(1024);
char *s_buffer = (char *)malloc(1024);
char* d_buffer = (char*)malloc(1024);
char* s_buffer = (char*)malloc(1024);
strcpy(s_buffer, ptr);
while ((pbuf = FindBrackets(s_buffer, d_buffer)) != nullptr)
@ -344,7 +343,9 @@ u32 DSPAssembler::ParseExpression(const char *ptr)
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
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);
@ -385,10 +386,10 @@ u32 DSPAssembler::ParseExpression(const char *ptr)
}
// Destroys parstr
u32 DSPAssembler::GetParams(char *parstr, param_t *par)
u32 DSPAssembler::GetParams(char* parstr, param_t* par)
{
u32 count = 0;
char *tmpstr = skip_spaces(parstr);
char* tmpstr = skip_spaces(parstr);
tmpstr = strtok(tmpstr, ",\x00");
for (int i = 0; i < 10; i++)
{
@ -440,7 +441,8 @@ u32 DSPAssembler::GetParams(char *parstr, param_t *par)
return count;
}
const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
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;
@ -450,7 +452,7 @@ const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const o
opcode = alias_iter->second.c_str();
for (int i = 0; i < opcod_size; i++)
{
const opc_t *opc = &opcod[i];
const opc_t* opc = &opcod[i];
if (strcmp(opc->name, opcode) == 0)
{
if (par_count < opc->param_count)
@ -476,7 +478,7 @@ static u16 get_mask_shifted_down(u16 mask)
return mask;
}
bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext)
bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, int count, bool ext)
{
for (int i = 0; i < count; i++)
{
@ -531,12 +533,15 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
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",
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",
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
@ -553,12 +558,16 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
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",
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",
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
@ -577,13 +586,17 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
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",
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",
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
@ -605,19 +618,23 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
switch (par[i].type & (P_REG | 7))
{
case P_REG:
if (ext) fprintf(stderr, "(ext) ");
if (ext)
fprintf(stderr, "(ext) ");
ShowError(ERR_EXPECTED_PARAM_REG);
break;
case P_MEM:
if (ext) fprintf(stderr, "(ext) ");
if (ext)
fprintf(stderr, "(ext) ");
ShowError(ERR_EXPECTED_PARAM_MEM);
break;
case P_VAL:
if (ext) fprintf(stderr, "(ext) ");
if (ext)
fprintf(stderr, "(ext) ");
ShowError(ERR_EXPECTED_PARAM_VAL);
break;
case P_IMM:
if (ext) fprintf(stderr, "(ext) ");
if (ext)
fprintf(stderr, "(ext) ");
ShowError(ERR_EXPECTED_PARAM_IMM);
break;
}
@ -631,7 +648,7 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
unsigned int valueu = 0xffff & ~(value >> 1);
if ((int)par[i].val < 0)
{
if (value == 7) // value 7 por sbclr/sbset
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);
@ -648,8 +665,8 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
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);
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);
@ -659,7 +676,7 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
}
else
{
if (value == 7) // value 7 por sbclr/sbset
if (value == 7) // value 7 por sbclr/sbset
{
if (par[i].val > (unsigned)value)
{
@ -670,12 +687,13 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
else if (opc->params[i].type == P_MEM)
{
if (value < 256)
value >>= 1; // addressing 8 bit with sign
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);
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);
@ -684,11 +702,12 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
else
{
if (value < 128)
value >>= 1; // special case ASL/ASR/LSL/LSR
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);
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);
@ -702,9 +721,8 @@ bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool
return true;
}
// Merge opcode with params.
void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
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++)
@ -745,9 +763,9 @@ void DSPAssembler::InitPass(int pass)
segment_addr[SEGMENT_OVERLAY] = 0;
}
bool DSPAssembler::AssembleFile(const char *fname, int pass)
bool DSPAssembler::AssembleFile(const char* fname, int pass)
{
int disable_text = 0; // modified by Hermes
int disable_text = 0; // modified by Hermes
std::ifstream fsrc;
OpenFStream(fsrc, fname, std::ios_base::in);
@ -758,7 +776,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
return false;
}
//printf("%s: Pass %d\n", fname, pass);
// printf("%s: Pass %d\n", fname, pass);
code_line = 0;
m_cur_pass = pass;
@ -772,7 +790,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
break;
cur_line = line;
//printf("A: %s\n", line);
// printf("A: %s\n", line);
code_line++;
param_t params[10] = { {0, P_NONE, nullptr} };
@ -808,21 +826,22 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
}
// turn text into spaces if disable_text is on (in a comment).
if (disable_text && ((unsigned char)c) > 32) c = 32;
if (disable_text && ((unsigned char)c) > 32)
c = 32;
if (c == 0x0a || c == 0x0d || c == ';')
c = 0x00;
if (c == 0x09) // tabs to spaces
if (c == 0x09) // tabs to spaces
c = ' ';
if (c == '"')
upper = !upper;
if (upper && c >= 'a' && c <= 'z') // convert to uppercase
if (upper && c >= 'a' && c <= 'z') // convert to uppercase
c = c - 'a' + 'A';
line[i] = c;
if (c == 0)
break; // modified by Hermes
break; // modified by Hermes
}
char *ptr = line;
char* ptr = line;
std::string label;
@ -836,7 +855,8 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
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] == '_')))
if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') ||
(ptr[j] == '_')))
valid = false;
}
if (valid)
@ -865,8 +885,8 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
params_count = 0;
params_count_ext = 0;
char *paramstr = strtok(nullptr, "\0");
char *paramstr_ext = nullptr;
char* paramstr = strtok(nullptr, "\0");
char* paramstr_ext = nullptr;
// there is valid opcode so probably we have parameters
if (paramstr)
@ -908,17 +928,17 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
{
if (params[0].type == P_STR)
{
char *tmpstr;
char* tmpstr;
u32 thisCodeline = code_line;
if (include_dir.size())
{
tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
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);
tmpstr = (char*)malloc(strlen(params[0].str) + 1);
strcpy(tmpstr, params[0].str);
}
@ -967,7 +987,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
continue;
}
const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
const opc_t* opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
if (!opc)
opc = &cw;
@ -975,7 +995,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
VerifyParams(opc, params, params_count);
const opc_t *opc_ext = nullptr;
const opc_t* opc_ext = nullptr;
// Check for opcode extensions.
if (opc->extended)
{
@ -998,10 +1018,10 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
if (pass == 2)
{
// generate binary
((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
((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);
BuildCode(opc_ext, params_ext, params_count_ext, (u16*)gdg_buffer);
}
m_cur_addr += opcode_size;

View file

@ -41,36 +41,29 @@ enum err_t
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(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 std::string& text, std::vector<u16> &code, std::vector<int> *line_numbers = nullptr);
std::string GetErrorString() const
{
return last_error_str;
}
err_t GetError() const
{
return last_error;
}
bool Assemble(const std::string& text, std::vector<u16>& code,
std::vector<int>* line_numbers = nullptr);
std::string GetErrorString() const { return last_error_str; }
err_t GetError() const { return last_error; }
private:
struct param_t
{
u32 val;
u32 val;
partype_t type;
char *str;
char* str;
};
enum segment_t
@ -82,30 +75,31 @@ private:
};
// Utility functions
s32 ParseValue(const char *str);
u32 ParseExpression(const char *ptr);
s32 ParseValue(const char* str);
u32 ParseExpression(const char* ptr);
u32 GetParams(char *parstr, param_t *par);
u32 GetParams(char* parstr, param_t* par);
void InitPass(int pass);
bool AssembleFile(const char *fname, int pass);
bool AssembleFile(const char* fname, int pass);
void ShowError(err_t err_code, const char *extra_info = nullptr);
void ShowError(err_t err_code, const char* extra_info = nullptr);
// void ShowWarning(err_t err_code, const char *extra_info = nullptr);
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* 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;
char* gdg_buffer;
std::string include_dir;
std::string cur_line;
u32 m_cur_addr;
int m_totalSize;
u8 m_cur_pass;
u8 m_cur_pass;
LabelMap labels;

View file

@ -12,17 +12,9 @@
class DSPBreakpoints
{
public:
DSPBreakpoints()
{
Clear();
}
DSPBreakpoints() { Clear(); }
// is address breakpoint
bool IsAddressBreakPoint(u32 addr)
{
return b[addr] != 0;
}
bool IsAddressBreakPoint(u32 addr) { return b[addr] != 0; }
// AddBreakPoint
bool Add(u32 addr, bool temp = false)
{
@ -47,16 +39,8 @@ public:
return was_one;
}
void Clear()
{
memset(b, 0, sizeof(b));
}
void DeleteByAddress(u32 addr)
{
b[addr] = 0;
}
void Clear() { memset(b, 0, sizeof(b)); }
void DeleteByAddress(u32 addr) { b[addr] = 0; }
private:
u8 b[65536];
};

View file

@ -38,14 +38,16 @@ struct DMAPacket
PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(const std::string& pcap_filename)
: m_pcap(new PCAP(new File::IOFile(pcap_filename, "wb")))
{}
{
}
PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(PCAP* pcap) : m_pcap(pcap)
{}
{
}
PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(std::unique_ptr<PCAP>&& pcap)
: m_pcap(std::move(pcap))
{}
PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(std::unique_ptr<PCAP>&& pcap) : m_pcap(std::move(pcap))
{
}
void PCAPDSPCaptureLogger::LogIFXAccess(bool read, u16 address, u16 value)
{
@ -58,8 +60,8 @@ void PCAPDSPCaptureLogger::LogIFXAccess(bool read, u16 address, u16 value)
m_pcap->AddPacket(pkt);
}
void PCAPDSPCaptureLogger::LogDMA(u16 control, u32 gc_address, u16 dsp_address,
u16 length, const u8* data)
void PCAPDSPCaptureLogger::LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length,
const u8* data)
{
// The length of a DMA cannot be above 64K, so we use a static buffer for
// the construction of the packet.

View file

@ -20,9 +20,7 @@ class PCAP;
class DSPCaptureLogger
{
public:
virtual ~DSPCaptureLogger()
{}
virtual ~DSPCaptureLogger() {}
// Accesses (reads or writes) to memory mapped registers (external
// interface, also known as IFX). These are always 16 bits accesses.
virtual void LogIFXRead(u16 address, u16 read_value) = 0;
@ -34,8 +32,7 @@ public:
// is used for DRAM/IRAM in any direction (to/from DSP).
//
// Length is expressed in bytes, not DSP words.
virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address,
u16 length, const u8* data) = 0;
virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) = 0;
};
// A dummy implementation of a capture logger that does nothing. This is the
@ -45,13 +42,9 @@ public:
class DefaultDSPCaptureLogger : public DSPCaptureLogger
{
public:
void LogIFXRead(u16 address, u16 read_value) override
{}
void LogIFXWrite(u16 address, u16 written_value) override
{}
void LogDMA(u16 control, u32 gc_address, u16 dsp_address,
u16 length, const u8* data) override
{}
void LogIFXRead(u16 address, u16 read_value) override {}
void LogIFXWrite(u16 address, u16 written_value) override {}
void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) override {}
};
// A capture logger implementation that logs to PCAP files in a custom
@ -65,16 +58,12 @@ public:
PCAPDSPCaptureLogger(PCAP* pcap);
PCAPDSPCaptureLogger(std::unique_ptr<PCAP>&& pcap);
void LogIFXRead(u16 address, u16 read_value) override
{
LogIFXAccess(true, address, read_value);
}
void LogIFXRead(u16 address, u16 read_value) override { LogIFXAccess(true, address, read_value); }
void LogIFXWrite(u16 address, u16 written_value) override
{
LogIFXAccess(false, address, written_value);
}
void LogDMA(u16 control, u32 gc_address, u16 dsp_address,
u16 length, const u8* data) override;
void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) override;
private:
void LogIFXAccess(bool read, u16 address, u16 value);

View file

@ -15,7 +15,7 @@
#include "Core/DSP/DSPCodeUtil.h"
#include "Core/DSP/DSPDisassembler.h"
bool Assemble(const std::string& text, std::vector<u16> &code, bool force)
bool Assemble(const std::string& text, std::vector<u16>& code, bool force)
{
AssemblerSettings settings;
// settings.pc = 0;
@ -36,7 +36,7 @@ bool Assemble(const std::string& text, std::vector<u16> &code, bool force)
return true;
}
bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text)
bool Disassemble(const std::vector<u16>& code, bool line_numbers, std::string& text)
{
if (code.empty())
return false;
@ -55,7 +55,7 @@ bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &t
return success;
}
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
bool Compare(const std::vector<u16>& code1, const std::vector<u16>& code2)
{
if (code1.size() != code2.size())
printf("Size difference! 1=%zu 2=%zu\n", code1.size(), code2.size());
@ -77,13 +77,14 @@ bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
disassembler.DisassembleOpcode(&code1[0], 0x0000, 2, &pc, line1);
pc = i;
disassembler.DisassembleOpcode(&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());
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<u16> &longest = code1.size() > code2.size() ? code1 : code2;
const std::vector<u16>& longest = code1.size() > code2.size() ? code1 : code2;
for (int i = min_size; i < (int)longest.size(); i++)
{
u16 pc = i;
@ -96,7 +97,7 @@ bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
return code1.size() == code2.size() && code1.size() == count_equal;
}
void GenRandomCode(u32 size, std::vector<u16> &code)
void GenRandomCode(u32 size, std::vector<u16>& code)
{
code.resize(size);
for (u32 i = 0; i < size; i++)
@ -105,8 +106,8 @@ void GenRandomCode(u32 size, std::vector<u16> &code)
}
}
void CodeToHeader(const std::vector<u16> &code, std::string _filename,
const char *name, std::string &header)
void CodeToHeader(const std::vector<u16>& code, std::string _filename, const char* name,
std::string& header)
{
std::vector<u16> code_padded = code;
// Pad with nops to 32byte boundary
@ -117,7 +118,8 @@ void CodeToHeader(const std::vector<u16> &code, std::string _filename,
header.append("#define NUM_UCODES 1\n\n");
std::string filename;
SplitPath(_filename, nullptr, &filename, nullptr);
header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str()));
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");
@ -132,10 +134,10 @@ void CodeToHeader(const std::vector<u16> &code, std::string _filename,
header.append("};\n");
}
void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
u32 numCodes, const char *name, std::string &header)
void CodesToHeader(const std::vector<u16>* codes, const std::vector<std::string>* filenames,
u32 numCodes, const char* name, std::string& header)
{
std::vector<std::vector<u16> > codes_padded;
std::vector<std::vector<u16>> codes_padded;
u32 reserveSize = 0;
for (u32 i = 0; i < numCodes; i++)
{
@ -177,7 +179,7 @@ void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>
header.append("};\n");
}
void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
void CodeToBinaryStringBE(const std::vector<u16>& code, std::string& str)
{
str.resize(code.size() * 2);
for (size_t i = 0; i < code.size(); i++)
@ -187,7 +189,7 @@ void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
}
}
void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
void BinaryStringBEToCode(const std::string& str, std::vector<u16>& code)
{
code.resize(str.size() / 2);
for (size_t i = 0; i < code.size(); i++)
@ -196,7 +198,7 @@ void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
}
}
bool LoadBinary(const std::string& filename, std::vector<u16> &code)
bool LoadBinary(const std::string& filename, std::vector<u16>& code)
{
std::string buffer;
if (!File::ReadFileToString(filename, buffer))
@ -206,7 +208,7 @@ bool LoadBinary(const std::string& filename, std::vector<u16> &code)
return true;
}
bool SaveBinary(const std::vector<u16> &code, const std::string& filename)
bool SaveBinary(const std::vector<u16>& code, const std::string& filename)
{
std::string buffer;
CodeToBinaryStringBE(code, buffer);

View file

@ -9,19 +9,19 @@
#include "Common/CommonTypes.h"
bool Assemble(const std::string& text, std::vector<u16> &code, bool force = false);
bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
void GenRandomCode(u32 size, std::vector<u16> &code);
void CodeToHeader(const std::vector<u16> &code, std::string _filename,
const char *name, std::string &header);
void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
u32 numCodes, const char *name, std::string &header);
bool Assemble(const std::string& text, std::vector<u16>& code, bool force = false);
bool Disassemble(const std::vector<u16>& code, bool line_numbers, std::string& text);
bool Compare(const std::vector<u16>& code1, const std::vector<u16>& code2);
void GenRandomCode(u32 size, std::vector<u16>& code);
void CodeToHeader(const std::vector<u16>& code, std::string _filename, const char* name,
std::string& header);
void CodesToHeader(const std::vector<u16>* codes, const std::vector<std::string>* filenames,
u32 numCodes, const char* name, std::string& header);
// Big-endian, for writing straight to file using File::WriteStringToFile.
void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code);
void CodeToBinaryStringBE(const std::vector<u16>& code, std::string& str);
void BinaryStringBEToCode(const std::string& str, std::vector<u16>& code);
// Load code (big endian binary).
bool LoadBinary(const std::string& filename, std::vector<u16> &code);
bool SaveBinary(const std::vector<u16> &code, const std::string& filename);
bool LoadBinary(const std::string& filename, std::vector<u16>& code);
bool SaveBinary(const std::vector<u16>& code, const std::string& filename);

View file

@ -3,6 +3,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPCore.h"
#include <algorithm>
#include <array>
#include <memory>
@ -10,17 +12,17 @@
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/FileUtil.h"
#include "Common/Hash.h"
#include "Common/Logging/Log.h"
#include "Common/MemoryUtil.h"
#include "Common/MsgHandler.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Core/DSP/Jit/DSPEmitter.h"
SDSP g_dsp;
DSPBreakpoints g_dsp_breakpoints;
@ -249,8 +251,8 @@ int DSPCore_RunCycles(int cycles)
}
g_cycles_left = cycles;
DSPCompiledCode pExecAddr = (DSPCompiledCode)g_dsp_jit->enterDispatcher;
pExecAddr();
auto exec_addr = (DSPEmitter::DSPCompiledCode)g_dsp_jit->enterDispatcher;
exec_addr();
if (g_dsp.reset_dspjit_codespace)
g_dsp_jit->ClearIRAMandDSPJITCodespaceReset();

View file

@ -13,7 +13,8 @@
#include "Core/DSP/DSPBreakpoints.h"
#include "Core/DSP/DSPCaptureLogger.h"
#include "Core/DSP/DSPEmitter.h"
class DSPEmitter;
enum : u32
{
@ -108,12 +109,12 @@ enum : int
DSP_REG_ACC0 = 0x1c,
DSP_REG_ACC1 = 0x1d,
DSP_REG_ACL0 = 0x1c, // Low accumulator
DSP_REG_ACL0 = 0x1c, // Low accumulator
DSP_REG_ACL1 = 0x1d,
DSP_REG_ACM0 = 0x1e, // Mid accumulator
DSP_REG_ACM0 = 0x1e, // Mid accumulator
DSP_REG_ACM1 = 0x1f,
DSP_REG_ACH0 = 0x10, // Sign extended 8 bit register 0
DSP_REG_ACH1 = 0x11 // Sign extended 8 bit register 1
DSP_REG_ACH0 = 0x10, // Sign extended 8 bit register 0
DSP_REG_ACH1 = 0x11 // Sign extended 8 bit register 1
};
// Hardware registers address
@ -121,35 +122,35 @@ enum : u32
{
DSP_COEF_A1_0 = 0xa0,
DSP_DSCR = 0xc9, // DSP DMA Control Reg
DSP_DSPA = 0xcd, // DSP DMA Address (DSP)
DSP_DSBL = 0xcb, // DSP DMA Block Length
DSP_DSMAH = 0xce, // DSP DMA Address High (External)
DSP_DSMAL = 0xcf, // DSP DMA Address Low (External)
DSP_DSCR = 0xc9, // DSP DMA Control Reg
DSP_DSPA = 0xcd, // DSP DMA Address (DSP)
DSP_DSBL = 0xcb, // DSP DMA Block Length
DSP_DSMAH = 0xce, // DSP DMA Address High (External)
DSP_DSMAL = 0xcf, // DSP DMA Address Low (External)
DSP_FORMAT = 0xd1, // Sample format
DSP_ACUNK = 0xd2, // Set to 3 on my dumps
DSP_ACDATA1 = 0xd3, // Used only by Zelda ucodes
DSP_ACSAH = 0xd4, // Start of loop
DSP_FORMAT = 0xd1, // Sample format
DSP_ACUNK = 0xd2, // Set to 3 on my dumps
DSP_ACDATA1 = 0xd3, // Used only by Zelda ucodes
DSP_ACSAH = 0xd4, // Start of loop
DSP_ACSAL = 0xd5,
DSP_ACEAH = 0xd6, // End of sample (and loop)
DSP_ACEAH = 0xd6, // End of sample (and loop)
DSP_ACEAL = 0xd7,
DSP_ACCAH = 0xd8, // Current playback position
DSP_ACCAH = 0xd8, // Current playback position
DSP_ACCAL = 0xd9,
DSP_PRED_SCALE = 0xda, // ADPCM predictor and scale
DSP_PRED_SCALE = 0xda, // ADPCM predictor and scale
DSP_YN1 = 0xdb,
DSP_YN2 = 0xdc,
DSP_ACCELERATOR = 0xdd, // ADPCM accelerator read. Used by AX.
DSP_ACCELERATOR = 0xdd, // ADPCM accelerator read. Used by AX.
DSP_GAIN = 0xde,
DSP_ACUNK2 = 0xdf, // Set to 0xc on my dumps
DSP_ACUNK2 = 0xdf, // Set to 0xc on my dumps
DSP_AMDM = 0xef, // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked
DSP_AMDM = 0xef, // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked
DSP_DIRQ = 0xfb, // DSP Irq Rest
DSP_DMBH = 0xfc, // DSP Mailbox H
DSP_DMBL = 0xfd, // DSP Mailbox L
DSP_CMBH = 0xfe, // CPU Mailbox H
DSP_CMBL = 0xff // CPU Mailbox L
DSP_DIRQ = 0xfb, // DSP Irq Rest
DSP_DMBH = 0xfc, // DSP Mailbox H
DSP_DMBL = 0xfd, // DSP Mailbox L
DSP_CMBH = 0xfe, // CPU Mailbox H
DSP_CMBL = 0xff // CPU Mailbox L
};
// Stacks
@ -175,18 +176,21 @@ enum : u16
SR_OVERFLOW = 0x0002,
SR_ARITH_ZERO = 0x0004,
SR_SIGN = 0x0008,
SR_OVER_S32 = 0x0010, // Set when there was mod/tst/cmp on accu and result is over s32
SR_TOP2BITS = 0x0020, // If the upper (ac?.m/ax?.h) 2 bits are equal
SR_OVER_S32 = 0x0010, // Set when there was mod/tst/cmp on accu and result is over s32
SR_TOP2BITS = 0x0020, // If the upper (ac?.m/ax?.h) 2 bits are equal
SR_LOGIC_ZERO = 0x0040,
SR_OVERFLOW_STICKY = 0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same
SR_100 = 0x0100, // Unknown
SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so.
SR_400 = 0x0400, // Unknown
SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts
SR_1000 = 0x1000, // Unknown
SR_MUL_MODIFY = 0x2000, // 1 = normal. 0 = x2 (M0, M2) (Free mul by 2)
SR_40_MODE_BIT = 0x4000, // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums and data saturation for stores from mid accums.
SR_MUL_UNSIGNED = 0x8000, // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats ax?.l as unsigned (MULX family only).
SR_OVERFLOW_STICKY =
0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same
SR_100 = 0x0100, // Unknown
SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so.
SR_400 = 0x0400, // Unknown
SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts
SR_1000 = 0x1000, // Unknown
SR_MUL_MODIFY = 0x2000, // 1 = normal. 0 = x2 (M0, M2) (Free mul by 2)
SR_40_MODE_BIT = 0x4000, // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when
// loading mid accums and data saturation for stores from mid accums.
SR_MUL_UNSIGNED = 0x8000, // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats ax?.l as
// unsigned (MULX family only).
// This should be the bits affected by CMP. Does not include logic zero.
SR_CMP_MASK = 0x3f
@ -195,13 +199,13 @@ enum : u16
// Exception vectors
enum : int
{
EXP_STOVF = 1, // 0x0002 stack under/over flow
EXP_2 = 2, // 0x0004
EXP_3 = 3, // 0x0006
EXP_4 = 4, // 0x0008
EXP_ACCOV = 5, // 0x000a accelerator address overflow
EXP_6 = 6, // 0x000c
EXP_INT = 7 // 0x000e external int (message from CPU)
EXP_STOVF = 1, // 0x0002 stack under/over flow
EXP_2 = 2, // 0x0004
EXP_3 = 3, // 0x0006
EXP_4 = 4, // 0x0008
EXP_ACCOV = 5, // 0x000a accelerator address overflow
EXP_6 = 6, // 0x000c
EXP_INT = 7 // 0x000e external int (message from CPU)
};
struct DSP_Regs
@ -213,20 +217,18 @@ struct DSP_Regs
u16 cr;
u16 sr;
union
{
union {
u64 val;
struct
{
u16 l;
u16 m;
u16 h;
u16 m2;//if this gets in the way, drop it.
u16 m2; // if this gets in the way, drop it.
};
} prod;
union
{
union {
u32 val;
struct
{
@ -235,8 +237,7 @@ struct DSP_Regs
};
} ax[2];
union
{
union {
u64 val;
struct
{
@ -264,7 +265,7 @@ struct SDSP
u16 cr;
u8 reg_stack_ptr[4];
u8 exceptions; // pending exceptions
u8 exceptions; // pending exceptions
volatile bool external_interrupt_waiting;
bool reset_dspjit_codespace;
@ -288,13 +289,13 @@ struct SDSP
// 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;
u16* iram;
u16* dram;
u16* irom;
u16* coef;
// This one doesn't really belong here.
u8 *cpu_ram;
u8* cpu_ram;
};
extern SDSP g_dsp;
@ -325,10 +326,7 @@ struct DSPInitOptions
// Default: dummy implementation, does nothing.
DSPCaptureLogger* capture_logger;
DSPInitOptions()
: core_type(CORE_JIT),
capture_logger(new DefaultDSPCaptureLogger())
{}
DSPInitOptions() : core_type(CORE_JIT), capture_logger(new DefaultDSPCaptureLogger()) {}
};
// Initializes the DSP emulator using the provided options. Takes ownership of
@ -336,7 +334,7 @@ struct DSPInitOptions
bool DSPCore_Init(const DSPInitOptions& opts);
void DSPCore_Reset();
void DSPCore_Shutdown(); // Frees all allocated memory.
void DSPCore_Shutdown(); // Frees all allocated memory.
void DSPCore_CheckExternalInterrupt();
void DSPCore_CheckExceptions();

View file

@ -3,6 +3,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPDisassembler.h"
#include <algorithm>
#include <cstdlib>
#include <fstream>
@ -12,12 +14,12 @@
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/DSP/DSPDisassembler.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings)
: settings_(settings)
{}
DSPDisassembler::DSPDisassembler(const AssemblerSettings& settings) : settings_(settings)
{
}
DSPDisassembler::~DSPDisassembler()
{
@ -49,9 +51,10 @@ DSPDisassembler::~DSPDisassembler()
uo << StringFromFormat("Unknown opcodes count: %d\n", count);
}
bool DSPDisassembler::Disassemble(int start_pc, const std::vector<u16> &code, int base_addr, std::string &text)
bool DSPDisassembler::Disassemble(int start_pc, const std::vector<u16>& code, int base_addr,
std::string& text)
{
const char *tmp1 = "tmp1.bin";
const char* tmp1 = "tmp1.bin";
// First we have to dump the code to a bin file.
{
@ -125,8 +128,9 @@ std::string DSPDisassembler::DisassembleParameters(const DSPOPCTemplate& opc, u1
case P_IMM:
if (opc.params[j].size != 2)
{
if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
buf += StringFromFormat("#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension
if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
buf += StringFromFormat("#%d",
(val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension
else
buf += StringFromFormat("#0x%02x", val);
}
@ -162,7 +166,8 @@ static std::string MakeLowerCase(std::string in)
return in;
}
bool DSPDisassembler::DisassembleOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest)
bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pass, u16* pc,
std::string& dest)
{
std::string buf(" ");
@ -175,8 +180,8 @@ bool DSPDisassembler::DisassembleOpcode(const u16 *binbuf, int base_addr, int pa
const u32 op1 = binbuf[*pc & 0x0fff];
const DSPOPCTemplate *opc = nullptr;
const DSPOPCTemplate *opc_ext = nullptr;
const DSPOPCTemplate* opc = nullptr;
const DSPOPCTemplate* opc_ext = nullptr;
// find opcode
for (int j = 0; j < opcodes_size; j++)
@ -189,7 +194,10 @@ bool DSPDisassembler::DisassembleOpcode(const u16 *binbuf, int base_addr, int pa
break;
}
}
const DSPOPCTemplate fake_op = { "CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, false };
const DSPOPCTemplate fake_op = { "CW", 0x0000, 0x0000, DSPInterpreter::nop,
nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}},
false, false, false, false,
false };
if (!opc)
opc = &fake_op;
@ -302,7 +310,8 @@ bool DSPDisassembler::DisassembleOpcode(const u16 *binbuf, int base_addr, int pa
return true;
}
bool DSPDisassembler::DisassembleFile(const std::string& name, int base_addr, int pass, std::string &output)
bool DSPDisassembler::DisassembleFile(const std::string& name, int base_addr, int pass,
std::string& output)
{
File::IOFile in(name, "rb");
if (!in)

View file

@ -17,16 +17,10 @@
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)
{}
: 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;
@ -43,18 +37,18 @@ struct AssemblerSettings
class DSPDisassembler
{
public:
DSPDisassembler(const AssemblerSettings &settings);
DSPDisassembler(const AssemblerSettings& settings);
~DSPDisassembler();
bool Disassemble(int start_pc, const std::vector<u16> &code, int base_addr, std::string &text);
bool Disassemble(int start_pc, const std::vector<u16>& 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 DisassembleOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest);
bool DisassembleOpcode(const u16* binbuf, int base_addr, int pass, u16* pc, std::string& dest);
private:
// Moves PC forward and writes the result to dest.
bool DisassembleFile(const std::string& name, int base_addr, int pass, std::string &output);
bool DisassembleFile(const std::string& name, int base_addr, int pass, std::string& output);
std::string DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2);
std::map<u16, int> unk_opcodes;

View file

@ -3,18 +3,17 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPHWInterface.h"
#include "Common/CPUDetect.h"
#include "Common/CommonFuncs.h"
#include "Common/Intrinsics.h"
#include "Common/Logging/Log.h"
#include "Common/MemoryUtil.h"
#include "Common/Thread.h"
#include "Core/DSP/DSPAccelerator.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPTables.h"
static void gdsp_do_dma();

View file

@ -13,12 +13,12 @@ enum Mailbox
MAILBOX_DSP
};
u32 gdsp_mbox_peek(Mailbox mbx);
u32 gdsp_mbox_peek(Mailbox mbx);
void gdsp_mbox_write_h(Mailbox mbx, u16 val);
void gdsp_mbox_write_l(Mailbox mbx, u16 val);
u16 gdsp_mbox_read_h(Mailbox mbx);
u16 gdsp_mbox_read_l(Mailbox mbx);
u16 gdsp_mbox_read_h(Mailbox mbx);
u16 gdsp_mbox_read_l(Mailbox mbx);
void gdsp_ifx_init();
void gdsp_ifx_write(u32 addr, u32 val);
u16 gdsp_ifx_read(u16 addr);
u16 gdsp_ifx_read(u16 addr);

View file

@ -21,6 +21,6 @@ void OSD_AddMessage(const std::string& str, u32 ms);
bool OnThread();
bool IsWiiHost();
void InterruptRequest();
void CodeLoaded(const u8 *ptr, int size);
void CodeLoaded(const u8* ptr, int size);
void UpdateDebugger();
}

View file

@ -3,19 +3,22 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPMemoryMap.h"
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
u16 dsp_imem_read(u16 addr)
{
switch (addr >> 12)
{
case 0: // 0xxx IRAM
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.
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
@ -38,7 +41,7 @@ u16 dsp_dmem_read(u16 addr)
case 0xf: // Fxxx HW regs
return gdsp_ifx_read(addr);
default: // Unmapped/non-existing memory
default: // Unmapped/non-existing memory
ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr);
return 0;
}
@ -48,11 +51,11 @@ void dsp_dmem_write(u16 addr, u16 val)
{
switch (addr >> 12)
{
case 0x0: // 0xxx DRAM
case 0x0: // 0xxx DRAM
g_dsp.dram[addr & DSP_DRAM_MASK] = val;
break;
case 0xf: // Fxxx HW regs
case 0xf: // Fxxx HW regs
gdsp_ifx_write(addr, val);
break;
@ -61,3 +64,21 @@ void dsp_dmem_write(u16 addr, u16 val)
break;
}
}
u16 dsp_fetch_code()
{
u16 opc = dsp_imem_read(g_dsp.pc);
g_dsp.pc++;
return opc;
}
u16 dsp_peek_code()
{
return dsp_imem_read(g_dsp.pc);
}
void dsp_skip_inst()
{
g_dsp.pc += opTable[dsp_peek_code()]->size;
}

View file

@ -7,27 +7,10 @@
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPTables.h"
u16 dsp_imem_read(u16 addr);
u16 dsp_imem_read(u16 addr);
void dsp_dmem_write(u16 addr, u16 val);
u16 dsp_dmem_read(u16 addr);
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;
}
u16 dsp_fetch_code();
u16 dsp_peek_code();
void dsp_skip_inst();

View file

@ -4,27 +4,20 @@
// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntExtOps.h"
#include "Core/DSP/DSPTables.h"
void nop(const UDSPInstruction opc)
{
// The real nop is 0. Anything else is bad.
if (opc)
{
ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x", opc);
}
}
#include "Common/CommonTypes.h"
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Core/DSP/Jit/DSPEmitter.h"
// clang-format off
const DSPOPCTemplate opcodes[] =
{
// # of parameters----+ {type, size, loc, lshift, mask} branch reads PC // instruction approximation
// name opcode mask interpreter function JIT function size-V V param 1 param 2 param 3 extendable uncond. updates SR
{"NOP", 0x0000, 0xfffc, nop, &DSPEmitter::nop, 1, 0, {}, false, false, false, false, false}, // no operation
{"NOP", 0x0000, 0xfffc, DSPInterpreter::nop, &DSPEmitter::nop, 1, 0, {}, false, false, false, false, false}, // no operation
{"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, &DSPEmitter::dar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arD--
{"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, &DSPEmitter::iar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arD++
@ -196,7 +189,7 @@ const DSPOPCTemplate opcodes[] =
{"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}, // $(D+24) = MEM[($cr[0-7] << 8) | I]
{"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}, // MEM[($cr[0-7] << 8) | I] = $(S+24)
// opcodes that can be extended
// 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}, // $acD.m ^= $axS.h
@ -292,7 +285,7 @@ const DSPOPCTemplate opcodes[] =
};
const DSPOPCTemplate cw =
{ "CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, false };
{ "CW", 0x0000, 0x0000, DSPInterpreter::nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, false };
// extended opcodes
@ -482,15 +475,16 @@ const pdlabel_t regnames[] =
{0x22, "AX0", "Extra Accu 0",},
{0x23, "AX1", "Extra Accu 1",},
};
// clang-format on
const DSPOPCTemplate *opTable[OPTABLE_SIZE];
const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE];
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
static char tmpstr[12]; // nasty
for (const pdlabel_t& pdlabel : pdlabels)
{
@ -502,22 +496,21 @@ const char* pdname(u16 val)
return tmpstr;
}
const char *pdregname(int val)
const char* pdregname(int val)
{
return regnames[val].name;
}
const char *pdregnamelong(int val)
const char* pdregnamelong(int val)
{
return regnames[val].description;
}
const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
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()
@ -538,11 +531,12 @@ void InitInstructionTable()
}
else
{
//if the entry already in the table
//is a strict subset, allow it
// if the entry already in the table
// is a strict subset, allow it
if ((extOpTable[i]->opcode_mask | ext.opcode_mask) != extOpTable[i]->opcode_mask)
{
ERROR_LOG(DSPLLE, "opcode ext table place %d already in use by %s when inserting %s", i, extOpTable[i]->name, ext.name);
ERROR_LOG(DSPLLE, "opcode ext table place %d already in use by %s when inserting %s", i,
extOpTable[i]->name, ext.name);
}
}
}

View file

@ -7,7 +7,7 @@
#pragma once
#include "Core/DSP/DSPCommon.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/Jit/DSPEmitter.h"
// The non-ADDR ones that end with _D are the opposite one - if the bit specify
// ACC0, then ACC_D will be ACC1.
@ -26,23 +26,23 @@ enum partype_t
P_ADDR_I = 0x0005,
P_ADDR_D = 0x0006,
P_REG = 0x8000,
P_REG04 = P_REG | 0x0400, // IX
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_REGM18 = P_REG | 0x1810, // used in multiply instructions
P_REG19 = P_REG | 0x1900,
P_REGM19 = P_REG | 0x1910, // used in multiply instructions
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
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 = 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_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
P_REF = P_REG | 0x4000,
P_PRG = P_REF | P_REG,
@ -54,11 +54,6 @@ enum partype_t
#define OPTABLE_SIZE 0xffff + 1
#define EXT_OPTABLE_SIZE 0xff + 1
void nop(const UDSPInstruction opc);
typedef void(*dspIntFunc)(const UDSPInstruction);
typedef void (DSPEmitter::*dspJitFunc)(const UDSPInstruction);
struct param2_t
{
partype_t type;
@ -70,12 +65,15 @@ struct param2_t
struct DSPOPCTemplate
{
const char *name;
using InterpreterFunction = void(*)(UDSPInstruction);
using JITFunction = void (DSPEmitter::*)(UDSPInstruction);
const char* name;
u16 opcode;
u16 opcode_mask;
dspIntFunc intFunc;
dspJitFunc jitFunc;
InterpreterFunction intFunc;
JITFunction jitFunc;
u8 size;
u8 param_count;
@ -98,8 +96,8 @@ extern const DSPOPCTemplate cw;
#define WRITEBACKLOGSIZE 5
extern const DSPOPCTemplate *opTable[OPTABLE_SIZE];
extern const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE];
extern const DSPOPCTemplate* opTable[OPTABLE_SIZE];
extern const DSPOPCTemplate* extOpTable[EXT_OPTABLE_SIZE];
extern u16 writeBackLog[WRITEBACKLOGSIZE];
extern int writeBackLogIdx[WRITEBACKLOGSIZE];
@ -115,33 +113,13 @@ 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);
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();
}
}
const DSPOPCTemplate* GetOpTemplate(const UDSPInstruction& inst);

View file

@ -4,16 +4,16 @@
//
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
// Arithmetic and accumulator control.
namespace DSPInterpreter {
namespace DSPInterpreter
{
// CLR $acR
// 1000 r001 xxxx xxxx
// Clears accumulator $acR
@ -122,7 +122,8 @@ void cmp(const UDSPInstruction opc)
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
Update_SR_Register64(res, isCarry2(acc0, res),
isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100
zeroWriteBackLog();
}
@ -158,7 +159,8 @@ 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 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));
@ -840,7 +842,8 @@ 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 &=
0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes
acc >>= 16;
zeroWriteBackLog();
@ -895,7 +898,8 @@ 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
acc &=
0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes
if ((opc & 0x3f) == 0)
shift = 0;
@ -1154,6 +1158,4 @@ void asrnr(const UDSPInstruction opc)
Update_SR_Register64(dsp_get_long_acc(dreg));
}
} // namespace

View file

@ -5,14 +5,14 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPStacks.h"
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSPInterpreter {
namespace DSPInterpreter
{
// Generic call implementation
// CALLcc addressA
// 0000 0010 1011 cccc
@ -111,7 +111,6 @@ 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
@ -123,7 +122,6 @@ void halt(const UDSPInstruction opc)
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
@ -158,7 +156,6 @@ void HandleLoop()
}
}
// LOOP $R
// 0000 0000 010r rrrr
// Repeatedly execute following opcode until counter specified by value
@ -210,7 +207,6 @@ void loopi(const UDSPInstruction opc)
}
}
// BLOOP $R, addrA
// 0000 0000 011r rrrr
// aaaa aaaa aaaa aaaa

View file

@ -4,15 +4,13 @@
//
// Additional copyrights go to Duddie and Tratax (c) 2004
// HELPER FUNCTIONS
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPInterpreter.h"
namespace DSPInterpreter {
namespace DSPInterpreter
{
void Update_SR_Register64(s64 _Value, bool carry, bool overflow)
{
g_dsp.r.sr &= ~SR_CMP_MASK;
@ -55,7 +53,6 @@ void Update_SR_Register64(s64 _Value, bool carry, bool overflow)
}
}
void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32)
{
g_dsp.r.sr &= ~SR_CMP_MASK;
@ -138,45 +135,46 @@ static bool IsLogicZero()
static bool IsConditionA()
{
return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) && !(g_dsp.r.sr & SR_ARITH_ZERO)) != 0;
return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) &&
!(g_dsp.r.sr & SR_ARITH_ZERO)) != 0;
}
//see DSPCore.h for flags
// see DSPCore.h for flags
bool CheckCondition(u8 _Condition)
{
switch (_Condition & 0xf)
{
case 0xf: // Always true.
case 0xf: // Always true.
return true;
case 0x0: // GE - Greater Equal
case 0x0: // GE - Greater Equal
return !IsLess();
case 0x1: // L - Less
case 0x1: // L - Less
return IsLess();
case 0x2: // G - Greater
case 0x2: // G - Greater
return !IsLess() && !IsZero();
case 0x3: // LE - Less Equal
case 0x3: // LE - Less Equal
return IsLess() || IsZero();
case 0x4: // NZ - Not Zero
case 0x4: // NZ - Not Zero
return !IsZero();
case 0x5: // Z - Zero
case 0x5: // Z - Zero
return IsZero();
case 0x6: // NC - Not carry
case 0x6: // NC - Not carry
return !IsCarry();
case 0x7: // C - Carry
case 0x7: // C - Carry
return IsCarry();
case 0x8: // ? - Not over s32
case 0x8: // ? - Not over s32
return !IsOverS32();
case 0x9: // ? - Over s32
case 0x9: // ? - Over s32
return IsOverS32();
case 0xa: // ?
case 0xa: // ?
return IsConditionA();
case 0xb: // ?
case 0xb: // ?
return !IsConditionA();
case 0xc: // LNZ - Logic Not Zero
case 0xc: // LNZ - Logic Not Zero
return !IsLogicZero();
case 0xd: // LZ - Logic Zero
case 0xd: // LZ - Logic Zero
return IsLogicZero();
case 0xe: // 0 - Overflow
case 0xe: // 0 - Overflow
return IsOverflow();
default:
return true;

View file

@ -12,10 +12,10 @@
namespace DSPInterpreter
{
bool CheckCondition(u8 _Condition);
void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, bool overS32 = false);
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);

View file

@ -2,11 +2,14 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DSPIntExtOps.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
//not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS dspjit64 without it)
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
// not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS
// dspjit64 without it)
//#define PRECISE_BACKLOG
// Extended opcodes do not exist on their own. These opcodes can only be
@ -28,10 +31,8 @@ inline static void writeToBackLog(int i, int idx, u16 value)
namespace DSPInterpreter
{
namespace Ext
{
inline bool IsSameMemArea(u16 a, u16 b)
{
// LM: tested on Wii
@ -199,7 +200,6 @@ void ls(const UDSPInstruction opc)
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
@ -331,10 +331,13 @@ void slnm(const UDSPInstruction opc)
// 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!)
// 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)
// 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;
@ -428,8 +431,7 @@ void ldm(const UDSPInstruction opc)
writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
writeToBackLog(3, DSP_REG_AR3,
dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
}
// LDAXM $axR, @$arS
@ -448,8 +450,7 @@ void ldaxm(const UDSPInstruction opc)
writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
writeToBackLog(3, DSP_REG_AR3,
dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
}
// LDNM $ax0.d, $ax1.r, @$arS
@ -469,8 +470,7 @@ void ldnm(const UDSPInstruction opc)
writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
writeToBackLog(3, DSP_REG_AR3,
dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
}
// LDAXNM $axR, @$arS
@ -489,17 +489,15 @@ void ldaxnm(const UDSPInstruction opc)
writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
writeToBackLog(3, DSP_REG_AR3,
dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
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
{
}
} // 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
@ -551,12 +549,14 @@ void zeroWriteBackLogPreserveAcc(u8 acc)
{
// acc0
if ((acc == 0) &&
((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || (writeBackLogIdx[i] == DSP_REG_ACH0)))
((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)))
((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) ||
(writeBackLogIdx[i] == DSP_REG_ACH1)))
continue;
dsp_op_write_reg(writeBackLogIdx[i], 0);

View file

@ -41,5 +41,5 @@ void ir(const UDSPInstruction opc);
void nr(const UDSPInstruction opc);
void nop(const UDSPInstruction opc);
} // end namespace Ext
} // end namespace DSPinterpeter
} // end namespace Ext
} // end namespace DSPinterpeter

View file

@ -4,12 +4,12 @@
//
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSPInterpreter {
namespace DSPInterpreter
{
// SRS @M, $(0x18+S)
// 0010 1sss mmmm mmmm
// Move value from register $(0x18+D) to data memory pointed by address

View file

@ -5,13 +5,13 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSPInterpreter {
namespace DSPInterpreter
{
// MRR $D, $S
// 0001 11dd ddds ssss
// Move value from register $S to register $D.

View file

@ -4,27 +4,26 @@
//
// Additional copyrights go to Duddie and Tratax (c) 2004
// Multiplier and product register control
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/Interpreter/DSPIntUtil.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
namespace DSPInterpreter {
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
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
else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // mixed
prod = a * (s16)b;
else
prod = (s16)a * (s16)b; //signed
prod = (s16)a * (s16)b; // signed
// Conditionally multiply by 2.
if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
@ -56,13 +55,13 @@ 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
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
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
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
result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
return result;
}

View file

@ -5,12 +5,12 @@
#pragma once
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPStacks.h"
// ---------------------------------------------------------------------------------------
// --- SR
// ---------------------------------------------------------------------------------------
@ -41,12 +41,12 @@ static inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix)
if (ix >= 0)
{
if (dar > wr) //overflow
if (dar > wr) // overflow
nar -= wr + 1;
}
else
{
if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
nar += wr + 1;
}
return nar;
@ -62,14 +62,14 @@ static inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix)
u32 nar = ar - ix;
u32 dar = (nar ^ ar ^ ~ix) & mx;
if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000)
if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000)
{
if (dar > wr) //overflow
if (dar > wr) // overflow
nar -= wr + 1;
}
else
{
if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
nar += wr + 1;
}
return nar;
@ -99,7 +99,6 @@ static inline u16 dsp_decrement_addr_reg(u16 reg)
return nar;
}
// ---------------------------------------------------------------------------------------
// --- reg
// ---------------------------------------------------------------------------------------
@ -133,12 +132,18 @@ static inline u16 dsp_op_read_reg(int _reg)
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_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;
@ -196,12 +201,24 @@ static inline void dsp_op_write_reg(int _reg, u16 val)
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_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;
@ -286,7 +303,7 @@ inline void dsp_set_long_acc(int _reg, s64 val)
g_dsp.r.ac[_reg].val = (u64)val;
}
inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40
inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40
{
return ((val << 24) >> 24);
}

View file

@ -3,18 +3,42 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
namespace DSPInterpreter {
namespace DSPInterpreter
{
namespace
{
void ExecuteInstruction(const UDSPInstruction inst)
{
const DSPOPCTemplate* opcode_template = GetOpTemplate(inst);
if (opcode_template->extended)
{
if ((inst >> 12) == 0x3)
extOpTable[inst & 0x7F]->intFunc(inst);
else
extOpTable[inst & 0xFF]->intFunc(inst);
}
opcode_template->intFunc(inst);
if (opcode_template->extended)
{
applyWriteBackLog();
}
}
} // Anonymous namespace
// NOTE: These have nothing to do with g_dsp.r.cr !
void WriteCR(u16 val)
{
// reset
@ -76,7 +100,7 @@ void Step()
u16 opc = dsp_fetch_code();
ExecuteInstruction(UDSPInstruction(opc));
if (DSPAnalyzer::code_flags[static_cast<u16>(g_dsp.pc - 1u)] & DSPAnalyzer::CODE_LOOP_END)
if (DSPAnalyzer::GetCodeFlags(static_cast<u16>(g_dsp.pc - 1u)) & DSPAnalyzer::CODE_LOOP_END)
HandleLoop();
}
@ -134,7 +158,7 @@ int RunCyclesDebug(int cycles)
return cycles;
}
// Idle skipping.
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
if (DSPAnalyzer::GetCodeFlags(g_dsp.pc) & DSPAnalyzer::CODE_IDLE_SKIP)
return 0;
Step();
cycles--;
@ -184,7 +208,7 @@ int RunCycles(int cycles)
if (g_dsp.cr & CR_HALT)
return 0;
// Idle skipping.
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
if (DSPAnalyzer::GetCodeFlags(g_dsp.pc) & DSPAnalyzer::CODE_IDLE_SKIP)
return 0;
Step();
cycles--;
@ -205,4 +229,13 @@ int RunCycles(int cycles)
}
}
void nop(const UDSPInstruction opc)
{
// The real nop is 0. Anything else is bad.
if (opc == 0)
return;
ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x", opc);
}
} // namespace

View file

@ -6,7 +6,7 @@
#include "Core/DSP/DSPCommon.h"
#define DSP_REG_MASK 0x1f
#define DSP_REG_MASK 0x1f
namespace DSPInterpreter
{
@ -23,126 +23,127 @@ int RunCycles(int cycles);
int RunCyclesDebug(int cycles);
void WriteCR(u16 val);
u16 ReadCR();
u16 ReadCR();
// All the opcode functions.
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 abs(const UDSPInstruction opc);
void add(const UDSPInstruction opc);
void addarn(const UDSPInstruction opc);
void addax(const UDSPInstruction opc);
void addaxl(const UDSPInstruction opc);
void addi(const UDSPInstruction opc);
void addis(const UDSPInstruction opc);
void addp(const UDSPInstruction opc);
void addpaxz(const UDSPInstruction opc);
void addr(const UDSPInstruction opc);
void andc(const UDSPInstruction opc);
void andcf(const UDSPInstruction opc);
void andf(const UDSPInstruction opc);
void andi(const UDSPInstruction opc);
void andr(const UDSPInstruction opc);
void asl(const UDSPInstruction opc);
void asr(const UDSPInstruction opc);
void asr16(const UDSPInstruction opc);
void asrn(const UDSPInstruction opc);
void asrnr(const UDSPInstruction opc);
void asrnrx(const UDSPInstruction opc);
void bloop(const UDSPInstruction opc);
void bloopi(const UDSPInstruction opc);
void mrr(const UDSPInstruction opc);
void call(const UDSPInstruction opc);
void callr(const UDSPInstruction opc);
void clr(const UDSPInstruction opc);
void clrl(const UDSPInstruction opc);
void clrp(const UDSPInstruction opc);
void cmp(const UDSPInstruction opc);
void cmpar(const UDSPInstruction opc);
void cmpi(const UDSPInstruction opc);
void cmpis(const UDSPInstruction opc);
void dar(const UDSPInstruction opc);
void dec(const UDSPInstruction opc);
void decm(const UDSPInstruction opc);
void halt(const UDSPInstruction opc);
void iar(const UDSPInstruction opc);
void ifcc(const UDSPInstruction opc);
void ilrr(const UDSPInstruction opc);
void ilrrd(const UDSPInstruction opc);
void ilrri(const UDSPInstruction opc);
void ilrrn(const UDSPInstruction opc);
void inc(const UDSPInstruction opc);
void incm(const UDSPInstruction opc);
void jcc(const UDSPInstruction opc);
void jmprcc(const UDSPInstruction opc);
void loop(const UDSPInstruction opc);
void loopi(const UDSPInstruction opc);
void lr(const UDSPInstruction opc);
void lri(const UDSPInstruction opc);
void lris(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 lrs(const UDSPInstruction opc);
void lsl(const UDSPInstruction opc);
void lsl16(const UDSPInstruction opc);
void lsr(const UDSPInstruction opc);
void asl(const UDSPInstruction opc);
void asr(const UDSPInstruction opc);
void lsr16(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 lsrnr(const UDSPInstruction opc);
void lsrnrx(const UDSPInstruction opc);
void madd(const UDSPInstruction opc);
void maddc(const UDSPInstruction opc);
void maddx(const UDSPInstruction opc);
void mov(const UDSPInstruction opc);
void movax(const UDSPInstruction opc);
void movnp(const UDSPInstruction opc);
void movp(const UDSPInstruction opc);
void movpz(const UDSPInstruction opc);
void movr(const UDSPInstruction opc);
void mrr(const UDSPInstruction opc);
void msub(const UDSPInstruction opc);
void msubc(const UDSPInstruction opc);
void msubx(const UDSPInstruction opc);
void mul(const UDSPInstruction opc);
void mulac(const UDSPInstruction opc);
void mulaxh(const UDSPInstruction opc);
void mulc(const UDSPInstruction opc);
void mulcac(const UDSPInstruction opc);
void mulcmv(const UDSPInstruction opc);
void mulcmvz(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 neg(const UDSPInstruction opc);
void nop(const UDSPInstruction opc);
void notc(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 orc(const UDSPInstruction opc);
void ori(const UDSPInstruction opc);
void orr(const UDSPInstruction opc);
void ret(const UDSPInstruction opc);
void rti(const UDSPInstruction opc);
void sbclr(const UDSPInstruction opc);
void sbset(const UDSPInstruction opc);
void si(const UDSPInstruction opc);
void sr(const UDSPInstruction opc);
void srbith(const UDSPInstruction opc);
void mulaxh(const UDSPInstruction opc);
void srr(const UDSPInstruction opc);
void srrd(const UDSPInstruction opc);
void srri(const UDSPInstruction opc);
void srrn(const UDSPInstruction opc);
void srs(const UDSPInstruction opc);
void sub(const UDSPInstruction opc);
void subarn(const UDSPInstruction opc);
void subax(const UDSPInstruction opc);
void subp(const UDSPInstruction opc);
void subr(const UDSPInstruction opc);
void tst(const UDSPInstruction opc);
void tstaxh(const UDSPInstruction opc);
void tstprod(const UDSPInstruction opc);
void abs(const UDSPInstruction opc);
void xorc(const UDSPInstruction opc);
void xori(const UDSPInstruction opc);
void xorr(const UDSPInstruction opc);
} // namespace

View file

@ -2,51 +2,43 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/Jit/DSPEmitter.h"
#include <algorithm>
#include <cstring>
#include "Common/Assert.h"
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPTables.h"
#define MAX_BLOCK_SIZE 250
#define DSP_IDLE_SKIP_CYCLES 0x1000
constexpr size_t COMPILED_CODE_SIZE = 2097152;
constexpr size_t MAX_BLOCK_SIZE = 250;
constexpr u16 DSP_IDLE_SKIP_CYCLES = 0x1000;
using namespace Gen;
DSPEmitter::DSPEmitter() : gpr(*this), storeIndex(-1), storeIndex2(-1)
DSPEmitter::DSPEmitter()
: blockLinks(MAX_BLOCKS), blockSize(MAX_BLOCKS), blocks(MAX_BLOCKS),
compileSR{ SR_INT_ENABLE | SR_EXT_INT_ENABLE }
{
m_compiledCode = nullptr;
AllocCodeSpace(COMPILED_CODE_SIZE);
blocks = new DSPCompiledCode[MAX_BLOCKS];
blockLinks = new Block[MAX_BLOCKS];
blockSize = new u16[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] = (DSPCompiledCode)stubEntryPoint;
blockLinks[i] = nullptr;
blockSize[i] = 0;
}
// Clear all of the block references
std::fill(blocks.begin(), blocks.end(), (DSPCompiledCode)stubEntryPoint);
}
DSPEmitter::~DSPEmitter()
{
delete[] blocks;
delete[] blockLinks;
delete[] blockSize;
FreeCodeSpace();
}
@ -98,13 +90,11 @@ void DSPEmitter::checkExceptions(u32 retval)
SetJumpTarget(skipCheck);
}
bool DSPEmitter::FlagsNeeded()
bool DSPEmitter::FlagsNeeded() const
{
if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) ||
(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR))
return true;
else
return false;
const u8 flags = DSPAnalyzer::GetCodeFlags(compilePC);
return !(flags & DSPAnalyzer::CODE_START_OF_INST) || (flags & DSPAnalyzer::CODE_UPDATE_SR);
}
void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
@ -225,7 +215,7 @@ void DSPEmitter::Compile(u16 start_addr)
while (compilePC < start_addr + MAX_BLOCK_SIZE)
{
if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT)
if (DSPAnalyzer::GetCodeFlags(compilePC) & DSPAnalyzer::CODE_CHECK_INT)
checkExceptions(blockSize[start_addr]);
UDSPInstruction inst = dsp_imem_read(compilePC);
@ -243,7 +233,7 @@ void DSPEmitter::Compile(u16 start_addr)
// Handle loop condition, only if current instruction was flagged as a loop destination
// by the analyzer.
if (DSPAnalyzer::code_flags[static_cast<u16>(compilePC - 1u)] & DSPAnalyzer::CODE_LOOP_END)
if (DSPAnalyzer::GetCodeFlags(static_cast<u16>(compilePC - 1u)) & DSPAnalyzer::CODE_LOOP_END)
{
MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2])));
TEST(32, R(EAX), R(EAX));
@ -264,7 +254,8 @@ void DSPEmitter::Compile(u16 start_addr)
DSPJitRegCache c(gpr);
HandleLoop();
gpr.SaveRegs();
if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
if (!DSPHost::OnThread() &&
DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
{
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
}
@ -299,7 +290,7 @@ void DSPEmitter::Compile(u16 start_addr)
// don't update g_dsp.pc -- the branch insn already did
gpr.SaveRegs();
if (!DSPHost::OnThread() &&
DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
{
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
}
@ -316,7 +307,7 @@ void DSPEmitter::Compile(u16 start_addr)
}
// End the block if we're before an idle skip address
if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP)
if (DSPAnalyzer::GetCodeFlags(compilePC) & DSPAnalyzer::CODE_IDLE_SKIP)
{
break;
}
@ -362,7 +353,7 @@ void DSPEmitter::Compile(u16 start_addr)
}
gpr.SaveRegs();
if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
if (!DSPHost::OnThread() && DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
{
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
}
@ -404,7 +395,7 @@ void DSPEmitter::CompileDispatcher()
// Execute block. Cycles executed returned in EAX.
MOVZX(64, 16, ECX, M(&g_dsp.pc));
MOV(64, R(RBX), ImmPtr(blocks));
MOV(64, R(RBX), ImmPtr(blocks.data()));
JMPptr(MComplex(RBX, RCX, SCALE_8, 0));
returnDispatcher = GetCodePtr();

View file

@ -4,28 +4,28 @@
#pragma once
#include <cstddef>
#include <list>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/x64ABI.h"
#include "Common/x64Emitter.h"
#include "Core/DSP/DSPCommon.h"
#include "Core/DSP/Jit/DSPJitRegCache.h"
#define COMPILED_CODE_SIZE 2097152
#define MAX_BLOCKS 0x10000
typedef u32(*DSPCompiledCode)();
typedef const u8 *Block;
class DSPEmitter : public Gen::X64CodeBlock
{
public:
using DSPCompiledCode = u32(*)();
using Block = const u8*;
static constexpr size_t MAX_BLOCKS = 0x10000;
DSPEmitter();
~DSPEmitter();
Block m_compiledCode;
void EmitInstruction(UDSPInstruction inst);
void ClearIRAM();
void ClearIRAMandDSPJITCodespaceReset();
@ -34,7 +34,7 @@ public:
Block CompileStub();
void Compile(u16 start_addr);
bool FlagsNeeded();
bool FlagsNeeded() const;
void FallBackToInterpreter(UDSPInstruction inst);
@ -90,9 +90,7 @@ public:
void dr(const UDSPInstruction opc);
void ir(const UDSPInstruction opc);
void nr(const UDSPInstruction opc);
void nop(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);
@ -103,7 +101,8 @@ public:
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_dont_saturate(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE);
void dsp_op_read_reg_dont_saturate(int reg, Gen::X64Reg host_dreg,
DSPJitSignExtend extend = NONE);
void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE);
// Commands
@ -240,25 +239,26 @@ public:
void msub(const UDSPInstruction opc);
// CALL this to start the dispatcher
const u8 *enterDispatcher;
const u8 *reenterDispatcher;
const u8 *stubEntryPoint;
const u8 *returnDispatcher;
const u8* enterDispatcher;
const u8* reenterDispatcher;
const u8* stubEntryPoint;
const u8* returnDispatcher;
u16 compilePC;
u16 startAddr;
Block *blockLinks;
u16 *blockSize;
std::vector<Block> blockLinks;
std::vector<u16> blockSize;
std::list<u16> unresolvedJumps[MAX_BLOCKS];
DSPJitRegCache gpr;
DSPJitRegCache gpr{ *this };
private:
DSPCompiledCode *blocks;
std::vector<DSPCompiledCode> blocks;
Block blockLinkEntry;
u16 compileSR;
// The index of the last stored ext value (compile time).
int storeIndex;
int storeIndex2;
int storeIndex = -1;
int storeIndex2 = -1;
// Counts down.
// int cycles;

View file

@ -4,11 +4,11 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -177,7 +177,8 @@ void DSPEmitter::cmp(const UDSPInstruction opc)
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
// Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF ->
// influence on ABS/0xa100
NEG(64, R(RDX));
Update_SR_Register64_Carry(EAX, tmp1, true);
gpr.PutXReg(tmp1);
@ -230,7 +231,8 @@ void DSPEmitter::cmpi(const UDSPInstruction opc)
// s64 val = dsp_get_long_acc(reg);
get_long_acc(reg, tmp1);
MOV(64, R(RAX), R(tmp1));
// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator.
// 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);
@ -698,7 +700,7 @@ void DSPEmitter::addi(const UDSPInstruction opc)
MOV(64, R(RAX), R(tmp1));
// s64 imm = (s16)dsp_fetch_code();
s16 imm = dsp_imem_read(compilePC + 1);
//imm <<= 16;
// imm <<= 16;
MOV(16, R(RDX), Imm16(imm));
MOVSX(64, 16, RDX, R(RDX));
SHL(64, R(RDX), Imm8(16));
@ -1169,7 +1171,8 @@ void DSPEmitter::lsr16(const UDSPInstruction opc)
// 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 &= 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));
@ -1248,7 +1251,8 @@ void DSPEmitter::lsr(const UDSPInstruction opc)
if (shift)
{
// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes
// 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));
@ -1302,7 +1306,7 @@ void DSPEmitter::asr(const UDSPInstruction opc)
shift = 0x40 - (opc & 0x3f);
// arithmetic shift
// s64 acc = dsp_get_long_acc(dreg);
// s64 acc = dsp_get_long_acc(dreg);
get_long_acc(dreg);
// acc >>= shift;
SAR(64, R(RAX), Imm8((u8)shift));
@ -1349,18 +1353,18 @@ void DSPEmitter::lsrn(const UDSPInstruction opc)
// acc <<= -shift;
// }
TEST(64, R(RDX), R(RDX));//is this actually worth the branch cost?
TEST(64, R(RDX), R(RDX)); // is this actually worth the branch cost?
FixupBranch zero = J_CC(CC_E);
TEST(16, R(RAX), Imm16(0x3f));//is this actually worth the branch cost?
TEST(16, R(RAX), Imm16(0x3f)); // is this actually worth the branch cost?
FixupBranch noShift = J_CC(CC_Z);
//CL gets automatically masked with 0x3f on IA32/AMD64
//MOVZX(64, 16, RCX, R(RAX));
// CL gets automatically masked with 0x3f on IA32/AMD64
// MOVZX(64, 16, RCX, R(RAX));
MOV(64, R(RCX), R(RAX));
//AND(16, R(RCX), Imm16(0x3f));
// 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));
// ADD(16, R(RCX), Imm16(0x40));
SHL(64, R(RDX), R(RCX));
FixupBranch exit = J();
SetJumpTarget(shiftLeft);
@ -1668,7 +1672,6 @@ void DSPEmitter::asrnr(const UDSPInstruction opc)
}
}
//} // namespace
//

View file

@ -2,10 +2,13 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/DSPStacks.h"
#include "Core/DSP/DSPTables.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -13,7 +16,7 @@ template <void(*jitCode)(const UDSPInstruction, DSPEmitter&)>
static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
{
u8 cond = opc & 0xf;
if (cond == 0xf) // Always true.
if (cond == 0xf) // Always true.
{
jitCode(opc, emitter);
return;
@ -23,34 +26,34 @@ static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
switch (cond)
{
case 0x0: // GE - Greater Equal
case 0x1: // L - Less
case 0x0: // GE - Greater Equal
case 0x1: // L - Less
emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
emitter.XOR(16, R(EAX), R(EDX));
emitter.TEST(16, R(EAX), Imm16(8));
break;
case 0x2: // G - Greater
case 0x3: // LE - Less Equal
case 0x2: // G - Greater
case 0x3: // LE - Less Equal
emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
emitter.XOR(16, R(EAX), R(EDX));
emitter.LEA(16, EAX, MScaled(EAX, SCALE_2, 0));
emitter.OR(16, R(EAX), R(EDX));
emitter.TEST(16, R(EAX), Imm16(0x10));
break;
case 0x4: // NZ - Not Zero
case 0x5: // Z - Zero
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
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
case 0x8: // ? - Not over s32
case 0x9: // ? - Over s32
emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32));
break;
case 0xa: // ?
case 0xb: // ?
case 0xa: // ?
case 0xb: // ?
emitter.LEA(16, EDX, MScaled(EAX, SCALE_2, 0));
emitter.OR(16, R(EAX), R(EDX));
emitter.LEA(16, EDX, MScaled(EDX, SCALE_8, 0));
@ -58,16 +61,17 @@ static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
emitter.OR(16, R(EAX), R(EDX));
emitter.TEST(16, R(EAX), Imm16(0x20));
break;
case 0xc: // LNZ - Logic Not Zero
case 0xd: // LZ - Logic Zero
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
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, true) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)), true);
FixupBranch skipCode =
cond == 0xe ? emitter.J_CC(CC_E, true) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)), true);
jitCode(opc, emitter);
emitter.gpr.FlushRegs(c1);
emitter.SetJumpTarget(skipCode);
@ -77,7 +81,7 @@ static void WriteBranchExit(DSPEmitter& emitter)
{
DSPJitRegCache c(emitter.gpr);
emitter.gpr.SaveRegs();
if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP)
if (DSPAnalyzer::GetCodeFlags(emitter.startAddr) & DSPAnalyzer::CODE_IDLE_SKIP)
{
emitter.MOV(16, R(EAX), Imm16(0x1000));
}
@ -100,7 +104,8 @@ static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
emitter.gpr.FlushRegs();
// Check if we have enough cycles to execute the next block
emitter.MOV(16, R(ECX), M(&g_cycles_left));
emitter.CMP(16, R(ECX), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest]));
emitter.CMP(16, R(ECX),
Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest]));
FixupBranch notEnoughCycles = emitter.J_CC(CC_BE);
emitter.SUB(16, R(ECX), Imm16(emitter.blockSize[emitter.startAddr]));
@ -120,7 +125,7 @@ static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
static void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
{
u16 dest = dsp_imem_read(emitter.compilePC + 1);
const DSPOPCTemplate *opcode = GetOpTemplate(opc);
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
// If the block is unconditional, attempt to link block
if (opcode->uncond_branch)
@ -144,8 +149,8 @@ void DSPEmitter::jcc(const UDSPInstruction opc)
static 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.
// 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);
emitter.MOV(16, M(&g_dsp.pc), R(EAX));
WriteBranchExit(emitter);
@ -166,7 +171,7 @@ static 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);
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
// If the block is unconditional, attempt to link block
if (opcode->uncond_branch)
@ -319,7 +324,7 @@ void DSPEmitter::loop(const UDSPInstruction opc)
{
u16 reg = opc & 0x1f;
// u16 cnt = g_dsp.r[reg];
//todo: check if we can use normal variant here
// todo: check if we can use normal variant here
dsp_op_read_reg_dont_saturate(reg, RDX, ZERO);
u16 loop_pc = compilePC + 1;
@ -375,7 +380,6 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
}
}
// BLOOP $R, addrA
// 0000 0000 011r rrrr
// aaaa aaaa aaaa aaaa
@ -389,7 +393,7 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
{
u16 reg = opc & 0x1f;
// u16 cnt = g_dsp.r[reg];
//todo: check if we can use normal variant here
// todo: check if we can use normal variant here
dsp_op_read_reg_dont_saturate(reg, RDX, ZERO);
u16 loop_pc = dsp_imem_read(compilePC + 1);

View file

@ -4,8 +4,8 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPIntUtil.h" // Helper functions
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -161,6 +161,6 @@ void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val)
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));
// AND(32, R(val), Imm32(0xc0000000));
Update_SR_Register16(val);
}

View file

@ -2,25 +2,27 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/Jit/DSPEmitter.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.
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.
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
@ -109,16 +111,16 @@ void DSPEmitter::sn(const UDSPInstruction opc)
void DSPEmitter::l(const UDSPInstruction opc)
{
u8 sreg = opc & 0x3;
u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; //AX?.?, AC?.[LM]
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
// 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
dsp_op_read_reg(DSP_REG_SR, RAX);
SHL(32, R(EAX), Imm8(16));
OR(32, R(EBX), R(EAX));
@ -140,10 +142,10 @@ void DSPEmitter::ln(const UDSPInstruction opc)
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
// 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
dsp_op_read_reg(DSP_REG_SR, RAX);
SHL(32, R(EAX), Imm8(16));
OR(32, R(EBX), R(EAX));
@ -176,7 +178,6 @@ void DSPEmitter::ls(const UDSPInstruction opc)
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
@ -382,7 +383,7 @@ void DSPEmitter::ld(const UDSPInstruction opc)
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true);
SetJumpTarget(not_equal); // else
SetJumpTarget(not_equal); // else
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3);
gpr.FlushRegs(c);
SetJumpTarget(after);
@ -402,7 +403,7 @@ void DSPEmitter::ldax(const UDSPInstruction opc)
pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -412,7 +413,7 @@ void DSPEmitter::ldax(const UDSPInstruction opc)
FixupBranch not_equal = J_CC(CC_NE, true);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true); // else
FixupBranch after = J(true); // else
SetJumpTarget(not_equal);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3);
gpr.FlushRegs(c);
@ -434,7 +435,7 @@ void DSPEmitter::ldn(const UDSPInstruction opc)
pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -445,7 +446,7 @@ void DSPEmitter::ldn(const UDSPInstruction opc)
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true);
SetJumpTarget(not_equal); // else
SetJumpTarget(not_equal); // else
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3);
gpr.FlushRegs(c);
SetJumpTarget(after);
@ -465,7 +466,7 @@ void DSPEmitter::ldaxn(const UDSPInstruction opc)
pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -475,7 +476,7 @@ void DSPEmitter::ldaxn(const UDSPInstruction opc)
FixupBranch not_equal = J_CC(CC_NE, true);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true); // else
FixupBranch after = J(true); // else
SetJumpTarget(not_equal);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3);
gpr.FlushRegs(c);
@ -497,7 +498,7 @@ void DSPEmitter::ldm(const UDSPInstruction opc)
pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -508,7 +509,7 @@ void DSPEmitter::ldm(const UDSPInstruction opc)
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true);
SetJumpTarget(not_equal); // else
SetJumpTarget(not_equal); // else
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3);
gpr.FlushRegs(c);
SetJumpTarget(after);
@ -528,7 +529,7 @@ void DSPEmitter::ldaxm(const UDSPInstruction opc)
pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -538,7 +539,7 @@ void DSPEmitter::ldaxm(const UDSPInstruction opc)
FixupBranch not_equal = J_CC(CC_NE, true);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true); // else
FixupBranch after = J(true); // else
SetJumpTarget(not_equal);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3);
gpr.FlushRegs(c);
@ -560,7 +561,7 @@ void DSPEmitter::ldnm(const UDSPInstruction opc)
pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -571,7 +572,7 @@ void DSPEmitter::ldnm(const UDSPInstruction opc)
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true);
SetJumpTarget(not_equal); // else
SetJumpTarget(not_equal); // else
pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3);
gpr.FlushRegs(c);
SetJumpTarget(after);
@ -591,7 +592,7 @@ void DSPEmitter::ldaxnm(const UDSPInstruction opc)
pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg);
X64Reg tmp = gpr.GetFreeXReg();
//if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
// if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) {
dsp_op_read_reg(sreg, RCX, NONE);
dsp_op_read_reg(DSP_REG_AR3, tmp, NONE);
XOR(16, R(ECX), R(tmp));
@ -601,7 +602,7 @@ void DSPEmitter::ldaxnm(const UDSPInstruction opc)
FixupBranch not_equal = J_CC(CC_NE, true);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg);
gpr.FlushRegs(c);
FixupBranch after = J(true); // else
FixupBranch after = J(true); // else
SetJumpTarget(not_equal);
pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3);
gpr.FlushRegs(c);
@ -664,14 +665,14 @@ void DSPEmitter::popExtValueToReg()
TEST(32, R(EBX), Imm32(SR_40_MODE_BIT << 16));
FixupBranch not_40bit = J_CC(CC_Z, true);
DSPJitRegCache c(gpr);
//if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)
// if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)
//{
// Sign extend into whole accum.
//u16 val = g_dsp.r[reg];
// 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;
// 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));
//}

View file

@ -4,11 +4,12 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPIntCCUtil.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -21,7 +22,7 @@ using namespace Gen;
void DSPEmitter::srs(const UDSPInstruction opc)
{
u8 reg = ((opc >> 8) & 0x7) + 0x18;
//u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
// u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
X64Reg tmp1 = gpr.GetFreeXReg();
@ -45,7 +46,7 @@ void DSPEmitter::lrs(const UDSPInstruction opc)
X64Reg tmp1 = gpr.GetFreeXReg();
//u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF);
// u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF);
dsp_op_read_reg(DSP_REG_CR, tmp1, ZERO);
SHL(16, R(tmp1), Imm8(8));
OR(16, R(tmp1), Imm16(opc & 0xFF));
@ -348,4 +349,3 @@ void DSPEmitter::ilrrn(const UDSPInstruction opc)
dsp_conditional_extend_accum(dreg + DSP_REG_ACM0);
increase_addr_reg(reg, reg);
}

View file

@ -2,10 +2,12 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPInterpreter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Interpreter/DSPInterpreter.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -58,7 +60,8 @@ void DSPEmitter::lris(const UDSPInstruction opc)
// 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)
{}
{
}
//----
@ -69,7 +72,6 @@ void DSPEmitter::dar(const UDSPInstruction opc)
{
// g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3);
decrement_addr_reg(opc & 0x3);
}
// IAR $arD
@ -108,10 +110,8 @@ void DSPEmitter::addarn(const UDSPInstruction opc)
//----
void DSPEmitter::setCompileSR(u16 bit)
{
// g_dsp.r[DSP_REG_SR] |= bit
OpArg sr_reg;
gpr.GetReg(DSP_REG_SR, sr_reg);
@ -123,7 +123,6 @@ void DSPEmitter::setCompileSR(u16 bit)
void DSPEmitter::clrCompileSR(u16 bit)
{
// g_dsp.r[DSP_REG_SR] &= bit
OpArg sr_reg;
gpr.GetReg(DSP_REG_SR, sr_reg);
@ -192,4 +191,3 @@ void DSPEmitter::srbith(const UDSPInstruction opc)
break;
}
}

View file

@ -4,12 +4,12 @@
// Additional copyrights go to Duddie and Tratax (c) 2004
// Multiplier and product register control
#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPEmitter.h"
#include "Core/DSP/DSPIntUtil.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
@ -74,7 +74,6 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
// 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);
@ -91,7 +90,7 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
if ((axh0 == 0) && (axh1 == 0))
{
// unsigned support ON if both ax?.l regs are used
// prod = (u32)(a * b);
// prod = (u32)(a * b);
MOVZX(64, 16, RCX, R(RCX));
MOVZX(64, 16, RAX, R(RAX));
MUL(64, R(RCX));
@ -99,7 +98,7 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
else if ((axh0 == 0) && (axh1 == 1))
{
// mixed support ON (u16)axl.0 * (s16)axh.1
// prod = a * (s16)b;
// prod = a * (s16)b;
X64Reg tmp = gpr.GetFreeXReg();
MOV(64, R(tmp), R(RAX));
MOVZX(64, 16, RAX, R(RCX));
@ -109,14 +108,14 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
else if ((axh0 == 1) && (axh1 == 0))
{
// mixed support ON (u16)axl.1 * (s16)axh.0
// prod = (s16)a * b;
// prod = (s16)a * b;
MOVZX(64, 16, RAX, R(RAX));
IMUL(64, R(RCX));
}
else
{
// unsigned support OFF if both ax?.h regs are used
// prod = (s16)a * (s16)b; //signed
// prod = (s16)a * (s16)b; //signed
MOVSX(64, 16, RAX, R(RAX));
IMUL(64, R(RCX));
}
@ -125,7 +124,7 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
SetJumpTarget(signedMul);
// Conditionally multiply by 2.
// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
// 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;
@ -148,7 +147,7 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
// direct use of prod regs by AX/AXWII (look @that part of ucode).
void DSPEmitter::clrp(const UDSPInstruction opc)
{
//64bit move to memory does not work. use 2 32bits
// 64bit move to memory does not work. use 2 32bits
MOV(32, M(((u32*)&g_dsp.r.prod.val) + 0), Imm32(0xfff00000U));
MOV(32, M(((u32*)&g_dsp.r.prod.val) + 1), Imm32(0x001000ffU));
}

View file

@ -2,19 +2,23 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/Jit/DSPJitRegCache.h"
#include <cinttypes>
#include "Core/DSP/DSPEmitter.h"
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/DSPJitRegCache.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;
// Ordered in order of prefered use.
// Not all of these are actually available
const std::array<X64Reg, 15> DSPJitRegCache::m_allocation_order = { {
R8, R9, R10, R11, R12, R13, R14, R15, RSI, RDI, RBX, RCX, RDX, RAX, RBP
} };
const std::array<X64Reg, 15> DSPJitRegCache::m_allocation_order = {
{R8, R9, R10, R11, R12, R13, R14, R15, RSI, RDI, RBX, RCX, RDX, RAX, RBP} };
static void* GetRegisterPointer(size_t reg)
{
@ -84,7 +88,7 @@ static void* GetRegisterPointer(size_t reg)
#define STATIC_REG_ACCS
//#undef STATIC_REG_ACCS
DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter)
DSPJitRegCache::DSPJitRegCache(DSPEmitter& _emitter)
: emitter(_emitter), temporary(false), merged(false)
{
for (X64CachedReg& xreg : xregs)
@ -93,23 +97,23 @@ DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter)
xreg.pushed = false;
}
xregs[RAX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV
xregs[RDX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV
xregs[RCX].guest_reg = DSP_REG_STATIC; // reserved for shifts
xregs[RAX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV
xregs[RDX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV
xregs[RCX].guest_reg = DSP_REG_STATIC; // reserved for shifts
xregs[RBX].guest_reg = DSP_REG_STATIC; // extended op backing store
xregs[RBX].guest_reg = DSP_REG_STATIC; // extended op backing store
xregs[RSP].guest_reg = DSP_REG_STATIC; // stack pointer
xregs[RSP].guest_reg = DSP_REG_STATIC; // stack pointer
xregs[RBP].guest_reg = DSP_REG_NONE; // definitely usable in dsplle because
// all external calls are protected
xregs[RBP].guest_reg = DSP_REG_NONE; // definitely usable in dsplle because
// all external calls are protected
xregs[RSI].guest_reg = DSP_REG_NONE;
xregs[RDI].guest_reg = DSP_REG_NONE;
#ifdef STATIC_REG_ACCS
xregs[R8].guest_reg = DSP_REG_STATIC; //acc0
xregs[R9].guest_reg = DSP_REG_STATIC; //acc1
xregs[R8].guest_reg = DSP_REG_STATIC; // acc0
xregs[R9].guest_reg = DSP_REG_STATIC; // acc1
#else
xregs[R8].guest_reg = DSP_REG_NONE;
xregs[R9].guest_reg = DSP_REG_NONE;
@ -138,7 +142,7 @@ DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter)
{
regs[i].size = 2;
}
//special composite registers
// special composite registers
#ifdef STATIC_REG_ACCS
regs[DSP_REG_ACC0_64].host_reg = R8;
regs[DSP_REG_ACC1_64].host_reg = R9;
@ -176,11 +180,12 @@ DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter)
use_ctr = 0;
}
DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache &cache)
DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache& cache)
: regs(cache.regs), xregs(cache.xregs), emitter(cache.emitter), temporary(true), merged(false)
{}
{
}
DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache &cache)
DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache& cache)
{
_assert_msg_(DSPLLE, &emitter == &cache.emitter, "emitter does not match");
_assert_msg_(DSPLLE, temporary, "register cache not temporary??");
@ -202,16 +207,15 @@ void DSPJitRegCache::Drop()
merged = true;
}
void DSPJitRegCache::FlushRegs(DSPJitRegCache &cache, bool emit)
void DSPJitRegCache::FlushRegs(DSPJitRegCache& cache, bool emit)
{
cache.merged = true;
// drop all guest register not used by cache
for (size_t i = 0; i < regs.size(); i++)
{
regs[i].used = false; //used is restored later
if (regs[i].loc.IsSimpleReg() &&
!cache.regs[i].loc.IsSimpleReg())
regs[i].used = false; // used is restored later
if (regs[i].loc.IsSimpleReg() && !cache.regs[i].loc.IsSimpleReg())
{
MovToMemory(i);
}
@ -238,9 +242,7 @@ void DSPJitRegCache::FlushRegs(DSPJitRegCache &cache, bool emit)
// free all host regs that are not used for the same guest reg
for (size_t i = 0; i < regs.size(); i++)
{
if (cache.regs[i].loc.GetSimpleReg() !=
regs[i].loc.GetSimpleReg() &&
regs[i].loc.IsSimpleReg())
if (cache.regs[i].loc.GetSimpleReg() != regs[i].loc.GetSimpleReg() && regs[i].loc.IsSimpleReg())
{
MovToMemory(i);
}
@ -269,13 +271,11 @@ void DSPJitRegCache::FlushRegs(DSPJitRegCache &cache, bool emit)
{
for (size_t i = 0; i < xregs.size(); i++)
{
if (cache.xregs[i].guest_reg == DSP_REG_USED &&
xregs[i].guest_reg == DSP_REG_NONE)
if (cache.xregs[i].guest_reg == DSP_REG_USED && xregs[i].guest_reg == DSP_REG_NONE)
{
xregs[i].guest_reg = DSP_REG_USED;
}
if (cache.xregs[i].guest_reg == DSP_REG_NONE &&
xregs[i].guest_reg == DSP_REG_USED)
if (cache.xregs[i].guest_reg == DSP_REG_NONE && xregs[i].guest_reg == DSP_REG_USED)
{
xregs[i].guest_reg = DSP_REG_NONE;
}
@ -285,27 +285,21 @@ void DSPJitRegCache::FlushRegs(DSPJitRegCache &cache, bool emit)
// consistency checks
for (size_t i = 0; i < xregs.size(); i++)
{
_assert_msg_(DSPLLE,
xregs[i].guest_reg == cache.xregs[i].guest_reg,
_assert_msg_(DSPLLE, xregs[i].guest_reg == cache.xregs[i].guest_reg,
"cache and current xreg guest_reg mismatch for %u", static_cast<u32>(i));
}
for (size_t i = 0; i < regs.size(); i++)
{
_assert_msg_(DSPLLE,
regs[i].loc.IsImm() == cache.regs[i].loc.IsImm(),
_assert_msg_(DSPLLE, regs[i].loc.IsImm() == cache.regs[i].loc.IsImm(),
"cache and current reg loc mismatch for %i", static_cast<u32>(i));
_assert_msg_(DSPLLE,
regs[i].loc.GetSimpleReg() == cache.regs[i].loc.GetSimpleReg(),
_assert_msg_(DSPLLE, regs[i].loc.GetSimpleReg() == cache.regs[i].loc.GetSimpleReg(),
"cache and current reg loc mismatch for %i", static_cast<u32>(i));
_assert_msg_(DSPLLE,
regs[i].dirty || !cache.regs[i].dirty,
_assert_msg_(DSPLLE, regs[i].dirty || !cache.regs[i].dirty,
"cache and current reg dirty mismatch for %i", static_cast<u32>(i));
_assert_msg_(DSPLLE,
regs[i].used == cache.regs[i].used,
_assert_msg_(DSPLLE, regs[i].used == cache.regs[i].used,
"cache and current reg used mismatch for %i", static_cast<u32>(i));
_assert_msg_(DSPLLE,
regs[i].shift == cache.regs[i].shift,
_assert_msg_(DSPLLE, regs[i].shift == cache.regs[i].shift,
"cache and current reg shift mismatch for %i", static_cast<u32>(i));
}
@ -320,8 +314,7 @@ void DSPJitRegCache::FlushMemBackedRegs()
for (size_t i = 0; i < regs.size(); i++)
{
_assert_msg_(DSPLLE, !regs[i].used,
"register %u still in use", static_cast<u32>(i));
_assert_msg_(DSPLLE, !regs[i].used, "register %u still in use", static_cast<u32>(i));
if (regs[i].used)
{
@ -351,59 +344,27 @@ void DSPJitRegCache::FlushRegs()
MovToMemory(i);
}
_assert_msg_(DSPLLE,
!regs[i].loc.IsSimpleReg(),
"register %zu is still a simple reg", i);
_assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i);
}
_assert_msg_(DSPLLE,
xregs[RSP].guest_reg == DSP_REG_STATIC,
"wrong xreg state for %d", RSP);
_assert_msg_(DSPLLE,
xregs[RBX].guest_reg == DSP_REG_STATIC,
"wrong xreg state for %d", RBX);
_assert_msg_(DSPLLE,
xregs[RBP].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", RBP);
_assert_msg_(DSPLLE,
xregs[RSI].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", RSI);
_assert_msg_(DSPLLE,
xregs[RDI].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", RDI);
_assert_msg_(DSPLLE, xregs[RSP].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", RSP);
_assert_msg_(DSPLLE, xregs[RBX].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", RBX);
_assert_msg_(DSPLLE, xregs[RBP].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RBP);
_assert_msg_(DSPLLE, xregs[RSI].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RSI);
_assert_msg_(DSPLLE, xregs[RDI].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RDI);
#ifdef STATIC_REG_ACCS
_assert_msg_(DSPLLE,
xregs[R8].guest_reg == DSP_REG_STATIC,
"wrong xreg state for %d", R8);
_assert_msg_(DSPLLE,
xregs[R9].guest_reg == DSP_REG_STATIC,
"wrong xreg state for %d", R9);
_assert_msg_(DSPLLE, xregs[R8].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", R8);
_assert_msg_(DSPLLE, xregs[R9].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", R9);
#else
_assert_msg_(DSPLLE,
xregs[R8].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R8);
_assert_msg_(DSPLLE,
xregs[R9].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R9);
_assert_msg_(DSPLLE, xregs[R8].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R8);
_assert_msg_(DSPLLE, xregs[R9].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R9);
#endif
_assert_msg_(DSPLLE,
xregs[R10].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R10);
_assert_msg_(DSPLLE,
xregs[R11].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R11);
_assert_msg_(DSPLLE,
xregs[R12].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R12);
_assert_msg_(DSPLLE,
xregs[R13].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R13);
_assert_msg_(DSPLLE,
xregs[R14].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R14);
_assert_msg_(DSPLLE,
xregs[R15].guest_reg == DSP_REG_NONE,
"wrong xreg state for %d", R15);
_assert_msg_(DSPLLE, xregs[R10].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R10);
_assert_msg_(DSPLLE, xregs[R11].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R11);
_assert_msg_(DSPLLE, xregs[R12].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R12);
_assert_msg_(DSPLLE, xregs[R13].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R13);
_assert_msg_(DSPLLE, xregs[R14].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R14);
_assert_msg_(DSPLLE, xregs[R15].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R15);
use_ctr = 0;
}
@ -437,9 +398,7 @@ void DSPJitRegCache::SaveRegs()
MovToMemory(i);
}
_assert_msg_(DSPLLE,
!regs[i].loc.IsSimpleReg(),
"register %zu is still a simple reg", i);
_assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i);
}
emitter.MOV(64, R(RBP), M(&ebp_store));
@ -456,9 +415,7 @@ void DSPJitRegCache::PushRegs()
MovToMemory(i);
}
_assert_msg_(DSPLLE,
!regs[i].loc.IsSimpleReg(),
"register %zu is still a simple reg", i);
_assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i);
}
int push_count = 0;
@ -483,9 +440,7 @@ void DSPJitRegCache::PushRegs()
xregs[i].guest_reg = DSP_REG_NONE;
}
_assert_msg_(DSPLLE,
xregs[i].guest_reg == DSP_REG_NONE ||
xregs[i].guest_reg == DSP_REG_STATIC,
_assert_msg_(DSPLLE, xregs[i].guest_reg == DSP_REG_NONE || xregs[i].guest_reg == DSP_REG_STATIC,
"register %zu is still used", i);
}
@ -546,12 +501,10 @@ X64Reg DSPJitRegCache::MakeABICallSafe(X64Reg reg)
void DSPJitRegCache::MovToHostReg(size_t reg, X64Reg host_reg, bool load)
{
_assert_msg_(DSPLLE, reg < regs.size(),
"bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE,
"register %zu is proxy for %d", reg, regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used,
"moving to host reg in use guest reg %zu", reg);
_assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg,
regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used, "moving to host reg in use guest reg %zu", reg);
X64Reg old_reg = regs[reg].loc.GetSimpleReg();
if (old_reg == host_reg)
{
@ -583,8 +536,7 @@ void DSPJitRegCache::MovToHostReg(size_t reg, X64Reg host_reg, bool load)
}
regs[reg].loc = R(host_reg);
if (old_reg != INVALID_REG &&
xregs[old_reg].guest_reg != DSP_REG_STATIC)
if (old_reg != INVALID_REG && xregs[old_reg].guest_reg != DSP_REG_STATIC)
{
xregs[old_reg].guest_reg = DSP_REG_NONE;
}
@ -592,12 +544,10 @@ void DSPJitRegCache::MovToHostReg(size_t reg, X64Reg host_reg, bool load)
void DSPJitRegCache::MovToHostReg(size_t reg, bool load)
{
_assert_msg_(DSPLLE, reg < regs.size(),
"bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE,
"register %zu is proxy for %d", reg, regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used,
"moving to host reg in use guest reg %zu", reg);
_assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg,
regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used, "moving to host reg in use guest reg %zu", reg);
if (regs[reg].loc.IsSimpleReg())
{
@ -624,14 +574,11 @@ void DSPJitRegCache::MovToHostReg(size_t reg, bool load)
void DSPJitRegCache::RotateHostReg(size_t reg, int shift, bool emit)
{
_assert_msg_(DSPLLE, reg < regs.size(),
"bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE,
"register %zu is proxy for %d", reg, regs[reg].parentReg);
_assert_msg_(DSPLLE, regs[reg].loc.IsSimpleReg(),
"register %zu is not a simple reg", reg);
_assert_msg_(DSPLLE, !regs[reg].used,
"rotating in use guest reg %zu", reg);
_assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg,
regs[reg].parentReg);
_assert_msg_(DSPLLE, regs[reg].loc.IsSimpleReg(), "register %zu is not a simple reg", reg);
_assert_msg_(DSPLLE, !regs[reg].used, "rotating in use guest reg %zu", reg);
if (shift > regs[reg].shift && emit)
{
@ -668,25 +615,22 @@ void DSPJitRegCache::RotateHostReg(size_t reg, int shift, bool emit)
void DSPJitRegCache::MovToMemory(size_t reg)
{
_assert_msg_(DSPLLE, reg < regs.size(),
"bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE,
"register %zu is proxy for %d", reg, regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used,
"moving to memory in use guest reg %zu", reg);
_assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg);
_assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg,
regs[reg].parentReg);
_assert_msg_(DSPLLE, !regs[reg].used, "moving to memory in use guest reg %zu", reg);
if (regs[reg].used)
{
emitter.INT3();
}
if (!regs[reg].loc.IsSimpleReg() &&
!regs[reg].loc.IsImm())
if (!regs[reg].loc.IsSimpleReg() && !regs[reg].loc.IsImm())
{
return;
}
//but first, check for any needed rotations
// but first, check for any needed rotations
if (regs[reg].loc.IsSimpleReg())
{
RotateHostReg(reg, 0, true);
@ -698,7 +642,7 @@ void DSPJitRegCache::MovToMemory(size_t reg)
_assert_msg_(DSPLLE, regs[reg].shift == 0, "still shifted??");
//move to mem
// move to mem
OpArg tmp = M(regs[reg].mem);
if (regs[reg].dirty)
@ -734,7 +678,7 @@ void DSPJitRegCache::MovToMemory(size_t reg)
regs[reg].loc = tmp;
}
void DSPJitRegCache::GetReg(int reg, OpArg &oparg, bool load)
void DSPJitRegCache::GetReg(int reg, OpArg& oparg, bool load)
{
int real_reg;
int shift;
@ -754,8 +698,7 @@ void DSPJitRegCache::GetReg(int reg, OpArg &oparg, bool load)
shift = 0;
}
_assert_msg_(DSPLLE, !regs[real_reg].used,
"register %d already in use", real_reg);
_assert_msg_(DSPLLE, !regs[real_reg].used, "register %d already in use", real_reg);
if (regs[real_reg].used)
{
@ -766,14 +709,13 @@ void DSPJitRegCache::GetReg(int reg, OpArg &oparg, bool load)
MovToHostReg(real_reg, load);
// TODO: actually handle INVALID_REG
_assert_msg_(DSPLLE, regs[real_reg].loc.IsSimpleReg(),
"did not get host reg for %d", reg);
_assert_msg_(DSPLLE, regs[real_reg].loc.IsSimpleReg(), "did not get host reg for %d", reg);
RotateHostReg(real_reg, shift, load);
oparg = regs[real_reg].loc;
regs[real_reg].used = true;
//do some register specific fixup
// do some register specific fixup
switch (reg)
{
case DSP_REG_ACC0_64:
@ -782,7 +724,7 @@ void DSPJitRegCache::GetReg(int reg, OpArg &oparg, bool load)
{
// need to do this because interpreter only does 48 bits
// (and PutReg does the same)
emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend
emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend
emitter.SAR(64, oparg, Imm8(64 - 40));
}
break;
@ -835,7 +777,7 @@ void DSPJitRegCache::PutReg(int reg, bool dirty)
case DSP_REG_ACC1_64:
if (dirty)
{
emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend
emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend
emitter.SAR(64, oparg, Imm8(64 - 40));
}
break;
@ -954,8 +896,7 @@ X64Reg DSPJitRegCache::SpillXReg()
X64Reg least_recent_use_reg = INVALID_REG;
for (X64Reg reg : m_allocation_order)
{
if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED &&
!regs[xregs[reg].guest_reg].used)
if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && !regs[xregs[reg].guest_reg].used)
{
int use_ctr_diff = use_ctr - regs[xregs[reg].guest_reg].last_use_ctr;
if (use_ctr_diff >= max_use_ctr_diff)
@ -972,11 +913,10 @@ X64Reg DSPJitRegCache::SpillXReg()
return least_recent_use_reg;
}
//just choose one.
// just choose one.
for (X64Reg reg : m_allocation_order)
{
if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED &&
!regs[xregs[reg].guest_reg].used)
if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && !regs[xregs[reg].guest_reg].used)
{
MovToMemory(xregs[reg].guest_reg);
return reg;
@ -991,16 +931,15 @@ void DSPJitRegCache::SpillXReg(X64Reg reg)
if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED)
{
_assert_msg_(DSPLLE, !regs[xregs[reg].guest_reg].used,
"to be spilled host reg %x(guest reg %zx) still in use!",
reg, xregs[reg].guest_reg);
"to be spilled host reg %x(guest reg %zx) still in use!", reg,
xregs[reg].guest_reg);
MovToMemory(xregs[reg].guest_reg);
}
else
{
_assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE,
"to be spilled host reg %x still in use!",
reg);
"to be spilled host reg %x still in use!", reg);
}
}
@ -1065,8 +1004,7 @@ void DSPJitRegCache::PutXReg(X64Reg reg)
return;
}
_assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED,
"PutXReg without get(Free)XReg");
_assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED, "PutXReg without get(Free)XReg");
xregs[reg].guest_reg = DSP_REG_NONE;
}

View file

@ -33,65 +33,65 @@ enum DSPJitSignExtend
class DSPJitRegCache
{
public:
DSPJitRegCache(DSPEmitter &_emitter);
DSPJitRegCache(DSPEmitter& _emitter);
// For branching into multiple control flows
DSPJitRegCache(const DSPJitRegCache &cache);
DSPJitRegCache& operator=(const DSPJitRegCache &cache);
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);
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
<code using gpr>
FixupBranch b = JCC();
DSPJitRegCache c = gpr;
<code using c>
gpr.FlushRegs(c);
SetBranchTarget(b);
<code using gpr>
//this does not modify the final state of gpr
<code using gpr>
FixupBranch b = JCC();
DSPJitRegCache c = gpr;
<code using c>
gpr.FlushRegs(c);
SetBranchTarget(b);
<code using gpr>
//this does not modify the final state of gpr
<code using gpr>
DSPJitRegCache c = gpr;
FixupBranch b1 = JCC();
<code using gpr>
gpr.FlushRegs(c);
FixupBranch b2 = JMP();
SetBranchTarget(b1);
<code using gpr>
gpr.FlushRegs(c);
SetBranchTarget(b2);
<code using gpr>
//this does not modify the final state of gpr
<code using gpr>
DSPJitRegCache c = gpr;
FixupBranch b1 = JCC();
<code using gpr>
gpr.FlushRegs(c);
FixupBranch b2 = JMP();
SetBranchTarget(b1);
<code using gpr>
gpr.FlushRegs(c);
SetBranchTarget(b2);
<code using gpr>
//this allows gpr to be modified in the second branch
//and fixes gpr according to the results form in the first branch
<code using gpr>
DSPJitRegCache c = gpr;
FixupBranch b1 = JCC();
<code using c>
FixupBranch b2 = JMP();
SetBranchTarget(b1);
<code using gpr>
gpr.FlushRegs(c);
SetBranchTarget(b2);
<code using gpr>
//this allows gpr to be modified in the second branch
//and fixes gpr according to the results form in the first branch
<code using gpr>
DSPJitRegCache c = gpr;
FixupBranch b1 = JCC();
<code using c>
FixupBranch b2 = JMP();
SetBranchTarget(b1);
<code using gpr>
gpr.FlushRegs(c);
SetBranchTarget(b2);
<code using gpr>
//this does not modify the final state of gpr
<code using gpr>
u8* b = GetCodePtr();
DSPJitRegCache c = gpr;
<code using gpr>
gpr.FlushRegs(c);
JCC(b);
<code using gpr>
//this does not modify the final state of gpr
<code using gpr>
u8* b = GetCodePtr();
DSPJitRegCache c = gpr;
<code using gpr>
gpr.FlushRegs(c);
JCC(b);
<code using gpr>
this all is not needed when gpr would not be used at all in the
conditional branch
this all is not needed when gpr would not be used at all in the
conditional branch
*/
// Drop this copy without warning
@ -100,11 +100,11 @@ public:
// Prepare state so that another flushed DSPJitRegCache can take over
void FlushRegs();
void LoadRegs(bool emit = true);// Load statically allocated regs from memory
void SaveRegs(); // Save statically allocated regs to memory
void LoadRegs(bool emit = true); // Load statically allocated regs from memory
void SaveRegs(); // Save statically allocated regs to memory
void PushRegs();// Save registers before ABI call
void PopRegs(); // Restore registers after ABI call
void PushRegs(); // Save registers before ABI call
void PopRegs(); // Restore registers after ABI call
// Returns a register with the same contents as reg that is safe
// to use through saveStaticRegs and for ABI-calls
@ -113,7 +113,7 @@ public:
// Gives no SCALE_RIP with abs(offset) >= 0x80000000
// 32/64 bit writes allowed when the register has a _64 or _32 suffix
// only 16 bit writes allowed without any suffix.
void GetReg(int reg, Gen::OpArg &oparg, bool load = true);
void GetReg(int reg, Gen::OpArg& oparg, bool load = true);
// Done with all usages of OpArg above
void PutReg(int reg, bool dirty = true);
@ -130,21 +130,21 @@ public:
private:
struct X64CachedReg
{
size_t guest_reg; // Including DSPJitRegSpecial
size_t guest_reg; // Including DSPJitRegSpecial
bool pushed;
};
struct DynamicReg
{
Gen::OpArg loc;
void *mem;
void* mem;
size_t size;
bool dirty;
bool used;
int last_use_ctr;
int parentReg;
int shift; // Current shift if parentReg == DSP_REG_NONE
// otherwise the shift this part can be found at
int shift; // Current shift if parentReg == DSP_REG_NONE
// otherwise the shift this part can be found at
Gen::X64Reg host_reg;
// TODO:

View file

@ -2,9 +2,11 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/DSP/DSPEmitter.h"
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHWInterface.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/DSP/Jit/DSPEmitter.h"
using namespace Gen;

View file

@ -1,5 +0,0 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once

Some files were not shown because too many files have changed in this diff Show more