mirror of
https://github.com/Tinob/Ishiiruka.git
synced 2024-06-16 03:17:27 -04:00
Merge latest master changes
This commit is contained in:
parent
a5d2d480c0
commit
c04c806270
164
CMakeLists.txt
164
CMakeLists.txt
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -350,6 +350,3 @@ C03F0034 2C0E0001
|
|||
EC210032 C0010034
|
||||
EC210024 39C00000
|
||||
281E0000 00000000
|
||||
|
||||
[Video_Settings]
|
||||
EFBScale = -1
|
||||
|
|
|
@ -18,5 +18,5 @@ EmulationIssues =
|
|||
# Add action replay cheats here.
|
||||
|
||||
[Video_Settings]
|
||||
EFBScale = 1
|
||||
EFBScale = -1
|
||||
|
||||
|
|
22
Data/Sys/GameSettings/P4B.ini
Normal file
22
Data/Sys/GameSettings/P4B.ini
Normal 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 =
|
22
Data/Sys/GameSettings/PCK.ini
Normal file
22
Data/Sys/GameSettings/PCK.ini
Normal 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 =
|
22
Data/Sys/GameSettings/PCS.ini
Normal file
22
Data/Sys/GameSettings/PCS.ini
Normal 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 =
|
22
Data/Sys/GameSettings/PGS.ini
Normal file
22
Data/Sys/GameSettings/PGS.ini
Normal 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 =
|
22
Data/Sys/GameSettings/PNJ.ini
Normal file
22
Data/Sys/GameSettings/PNJ.ini
Normal 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 =
|
21
Data/Sys/GameSettings/SNS.ini
Normal file
21
Data/Sys/GameSettings/SNS.ini
Normal 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
|
@ -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()))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" +
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -297,6 +297,8 @@ struct SConfig : NonCopyable
|
|||
|
||||
bool m_PauseOnFocusLost;
|
||||
|
||||
bool m_DisableTooltips;
|
||||
|
||||
// DSP settings
|
||||
bool m_DSPEnableJIT;
|
||||
bool m_DSPCaptureLog;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
|
@ -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;
|
|
@ -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
|
||||
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
//}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue