diff --git a/.github/workflows/build-appimage.yml b/.github/workflows/build-appimage.yml
deleted file mode 100644
index 7e7df583..00000000
--- a/.github/workflows/build-appimage.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-name: CMake Build (AppImage x86-64)
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- build:
-
- runs-on: ubuntu-20.04
-
- steps:
- - uses: actions/checkout@v1
- - name: Install dependencies
- run: |
- sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
- sudo apt update
- sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev libqt5multimedia5-plugins qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp0 libslirp-dev libarchive-dev zstd libzstd-dev --allow-downgrades
- - name: Create build environment
- run: mkdir ${{runner.workspace}}/build
- - name: Configure
- working-directory: ${{runner.workspace}}/build
- run: cmake $GITHUB_WORKSPACE
- - name: Make
- working-directory: ${{runner.workspace}}/build
- run: |
- make -j$(nproc --all)
- - name: Prepare AppDir for AppImage
- working-directory: ${{runner.workspace}}/build
- run: |
- make install DESTDIR=AppDir
- mv ./AppDir/usr/local/bin ./AppDir/usr/bin
- mv ./AppDir/usr/local/share ./AppDir/usr/share
- rm -rf ./AppDir/usr/local
- - name: Prepare necessary Tools for building the AppImage
- working-directory: ${{runner.workspace}}/build
- run: |
- wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
- wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
- chmod a+x linuxdeploy-x86_64.AppImage
- chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage
- - name: Build the AppImage
- working-directory: ${{runner.workspace}}/build
- run: |
- ./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
- mkdir dist
- cp ./melonDS*.AppImage ./dist
- - uses: actions/upload-artifact@v1
- with:
- name: melonDS-appimage-x86_64
- path: ${{runner.workspace}}/build/dist
diff --git a/.github/workflows/build-macos-universal.yml b/.github/workflows/build-macos-universal.yml
deleted file mode 100644
index 4416ce7a..00000000
--- a/.github/workflows/build-macos-universal.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-name: CMake Build (macOS Universal)
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- prepare:
- runs-on: [self-hosted, macOS, ARM64]
-
- steps:
- - name: Clean workspace
- run: rm -rf ${{runner.workspace}}/build
-
- - uses: actions/checkout@v3
-
-
- build-arm64:
- needs: prepare
- runs-on: [self-hosted, macOS, ARM64]
- env:
- homebrew_prefix: /opt/homebrew
-
- steps:
- - name: Create build directory
- run: mkdir -p ${{runner.workspace}}/build/arm64
-
- - name: Configure
- working-directory: ${{runner.workspace}}/build/arm64
- run: arch -arm64 ${{env.homebrew_prefix}}/bin/cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="${{env.homebrew_prefix}}/opt/qt@6;${{env.homebrew_prefix}}/opt/libarchive" -DPKG_CONFIG_EXECUTABLE=${{env.homebrew_prefix}}/bin/pkg-config -DMACOS_BUNDLE_LIBS=ON -DUSE_QT6=ON
-
- - name: Make
- working-directory: ${{runner.workspace}}/build/arm64
- run: arch -arm64 make -j$(sysctl -n hw.logicalcpu)
-
- build-x86_64:
- needs: prepare
- runs-on: [self-hosted, macOS, ARM64]
- env:
- homebrew_prefix: /usr/local
-
- steps:
- - name: Create build directory
- run: mkdir -p ${{runner.workspace}}/build/x86_64
-
- - name: Configure
- working-directory: ${{runner.workspace}}/build/x86_64
- run: arch -x86_64 ${{env.homebrew_prefix}}/bin/cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="${{env.homebrew_prefix}}/opt/qt@6;${{env.homebrew_prefix}}/opt/libarchive" -DPKG_CONFIG_EXECUTABLE=${{env.homebrew_prefix}}/bin/pkg-config -DMACOS_BUNDLE_LIBS=ON -DUSE_QT6=ON
-
- - name: Make
- working-directory: ${{runner.workspace}}/build/x86_64
- run: arch -x86_64 make -j$(sysctl -n hw.logicalcpu)
-
- universal-binary:
- needs: [build-arm64, build-x86_64]
- runs-on: [self-hosted, macOS, ARM64]
-
- steps:
- - name: Merge binaries
- run: $GITHUB_WORKSPACE/tools/mac-universal.py ${{runner.workspace}}/build/arm64/melonDS.app ${{runner.workspace}}/build/x86_64/melonDS.app ${{runner.workspace}}/build/universal/melonDS.app
-
- - name: Codesign app
- run: codesign -s - --deep -f ${{runner.workspace}}/build/universal/melonDS.app
-
- - name: Create DMG
- run: hdiutil create -fs HFS+ -volname melonDS -srcfolder ${{runner.workspace}}/build/universal/melonDS.app -ov -format UDBZ ${{runner.workspace}}/build/universal/melonDS.dmg
-
- - uses: actions/upload-artifact@v3
- with:
- name: macOS-universal
- path: ${{runner.workspace}}/build/universal/melonDS.dmg
-
diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml
new file mode 100644
index 00000000..4178157d
--- /dev/null
+++ b/.github/workflows/build-macos.yml
@@ -0,0 +1,85 @@
+name: macOS
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ build-macos:
+ strategy:
+ matrix:
+ arch: [x86_64, arm64]
+
+ name: ${{ matrix.arch }}
+ runs-on: macos-14
+ steps:
+ - name: Check out sources
+ uses: actions/checkout@v3
+ - name: Install dependencies for package building
+ run: |
+ brew install autoconf automake autoconf-archive libtool python-setuptools
+ - name: Set up CMake
+ uses: lukka/get-cmake@latest
+ - name: Set up vcpkg
+ uses: lukka/run-vcpkg@v11
+ with:
+ vcpkgGitCommitId: 53bef8994c541b6561884a8395ea35715ece75db
+ - name: Build
+ uses: lukka/run-cmake@v10
+ with:
+ configurePreset: release-mac-${{ matrix.arch }}
+ buildPreset: release-mac-${{ matrix.arch }}
+ - name: Compress app bundle
+ shell: bash
+ run: |
+ cd build/release-mac-${{ matrix.arch }}
+ zip -r -y ../../macOS-${{ matrix.arch }}.zip melonDS.app
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: macOS-${{ matrix.arch }}
+ path: macOS-${{ matrix.arch }}.zip
+ retention-days: 1
+
+ universal-binary:
+ name: Universal binary
+ needs: [build-macos]
+ runs-on: macos-13
+ continue-on-error: true
+ steps:
+ - name: Download x86_64
+ uses: actions/download-artifact@v4
+ with:
+ name: macOS-x86_64
+ path: x86_64
+ - name: Download arm64
+ uses: actions/download-artifact@v4
+ with:
+ name: macOS-arm64
+ path: arm64
+ - name: Combine app bundles
+ shell: bash
+ run: |
+ unzip x86_64/*.zip -d x86_64
+ unzip arm64/*.zip -d arm64
+ lipo {x86_64,arm64}/melonDS.app/Contents/MacOS/melonDS -create -output melonDS
+ cp -a arm64/melonDS.app melonDS.app
+ cp melonDS melonDS.app/Contents/MacOS/melonDS
+ codesign -s - --deep melonDS.app
+ zip -r -y macOS-universal.zip melonDS.app
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: macOS-universal
+ path: macOS-universal.zip
+# - name: Clean up architecture-specific artifacts
+# uses: geekyeggo/delete-artifact@v4
+# with:
+# failOnError: false
+# name: |
+# macOS-x86_64
+# macOS-arm64
diff --git a/.github/workflows/build-ubuntu-aarch64.yml b/.github/workflows/build-ubuntu-aarch64.yml
deleted file mode 100644
index 096bc0b9..00000000
--- a/.github/workflows/build-ubuntu-aarch64.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: CMake Build (Ubuntu aarch64)
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-env:
- BUILD_TYPE: Release
-
-jobs:
- build:
- runs-on: ubuntu-20.04
- container: ubuntu:20.04
-
- steps:
- - name: Prepare system
- shell: bash
- run: |
- apt update
- apt -y full-upgrade
- apt -y install git
- - name: Check out source
- uses: actions/checkout@v1
- - name: Install dependencies
- shell: bash
- run: |
- dpkg --add-architecture arm64
- sh -c "sed \"s|^deb \([a-z\.:/]*\) \([a-z\-]*\) \(.*\)$|deb [arch=amd64] \1 \2 \3\ndeb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports \2 \3|\" /etc/apt/sources.list > /etc/apt/sources.list.new"
- rm /etc/apt/sources.list
- mv /etc/apt/sources.list{.new,}
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -y {gcc-10,g++-10,pkg-config}-aarch64-linux-gnu {libsdl2,qtbase5,qtbase5-private,qtmultimedia5,libslirp,libarchive,libzstd}-dev:arm64 zstd:arm64 cmake extra-cmake-modules dpkg-dev
- - name: Configure
- shell: bash
- run: |
- CC=aarch64-linux-gnu-gcc-10 CXX=aarch64-linux-gnu-g++-10 cmake -DPKG_CONFIG_EXECUTABLE=/usr/bin/aarch64-linux-gnu-pkg-config $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -B build
- - name: Make
- shell: bash
- run: |
- cmake --build build -j$(nproc --all)
- mkdir dist
- cp build/melonDS dist
- - uses: actions/upload-artifact@v1
- with:
- name: melonDS-ubuntu-aarch64
- path: dist
diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml
index b6c50e9a..e96f98aa 100644
--- a/.github/workflows/build-ubuntu.yml
+++ b/.github/workflows/build-ubuntu.yml
@@ -1,4 +1,4 @@
-name: CMake Build (Ubuntu x86-64)
+name: Ubuntu
on:
push:
@@ -9,29 +9,77 @@ on:
- master
jobs:
- build:
-
- runs-on: ubuntu-20.04
+ build-x86_64:
+ name: x86_64
+ runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v4
+ name: Check out sources
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
sudo apt update
- sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp0 libslirp-dev libarchive-dev zstd libzstd-dev --allow-downgrades
- - name: Create build environment
- run: mkdir ${{runner.workspace}}/build
+ sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev \
+ qt6-{base,base-private,multimedia}-dev libslirp0 libslirp-dev libarchive-dev libzstd-dev libfuse2
- name: Configure
- working-directory: ${{runner.workspace}}/build
- run: cmake $GITHUB_WORKSPACE
- - name: Make
- working-directory: ${{runner.workspace}}/build
+ run: cmake -B build -G Ninja -DUSE_QT6=ON -DCMAKE_INSTALL_PREFIX=/usr
+ - name: Build
run: |
- make -j$(nproc --all)
- mkdir dist
- cp melonDS dist
- - uses: actions/upload-artifact@v1
+ cmake --build build
+ DESTDIR=AppDir cmake --install build
+ - uses: actions/upload-artifact@v4
with:
name: melonDS-ubuntu-x86_64
- path: ${{runner.workspace}}/build/dist
+ path: AppDir/usr/bin/melonDS
+ - name: Fetch AppImage tools
+ run: |
+ wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
+ wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
+ chmod a+x linuxdeploy-*.AppImage
+ - name: Build the AppImage
+ env:
+ QMAKE: /usr/lib/qt6/bin/qmake
+ run: |
+ ./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
+ - uses: actions/upload-artifact@v4
+ with:
+ name: melonDS-appimage-x86_64
+ path: melonDS*.AppImage
+
+ build-aarch64:
+ name: aarch64
+ runs-on: ubuntu-latest
+ container: ubuntu:22.04
+
+ steps:
+ - name: Prepare system
+ shell: bash
+ run: |
+ dpkg --add-architecture arm64
+ sh -c "sed \"s|^deb \([a-z\.:/]*\) \([a-z\-]*\) \(.*\)$|deb [arch=amd64] \1 \2 \3\ndeb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports \2 \3|\" /etc/apt/sources.list > /etc/apt/sources.list.new"
+ rm /etc/apt/sources.list
+ mv /etc/apt/sources.list{.new,}
+ apt update
+ apt -y full-upgrade
+ apt -y install git {gcc-12,g++-12}-aarch64-linux-gnu cmake ninja-build extra-cmake-modules \
+ {libsdl2,qt6-{base,base-private,multimedia},libslirp,libarchive,libzstd}-dev:arm64 \
+ pkg-config dpkg-dev
+ - name: Check out source
+ uses: actions/checkout@v4
+ - name: Configure
+ shell: bash
+ run: |
+ cmake -B build -G Ninja \
+ -DPKG_CONFIG_EXECUTABLE=/usr/bin/aarch64-linux-gnu-pkg-config \
+ -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-12 \
+ -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-12 \
+ -DUSE_QT6=ON
+ - name: Build
+ shell: bash
+ run: |
+ cmake --build build
+ - uses: actions/upload-artifact@v4
+ with:
+ name: melonDS-ubuntu-aarch64
+ path: build/melonDS
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 70b11c05..e6846da7 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -1,4 +1,4 @@
-name: CMake Build (Windows x86-64)
+name: Windows
on:
push:
diff --git a/.gitignore b/.gitignore
index e76a0944..d7001e4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-build
+build*/
bin
obj
*.depend
@@ -7,7 +7,7 @@ obj
melon_grc.c
melon_grc.h
melon.rc
-cmake-build
+cmake-build*
cmake-build-debug
compile_commands.json
.idea
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57d82eff..57400e36 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.16)
cmake_policy(VERSION 3.15)
if (POLICY CMP0076)
@@ -8,6 +8,12 @@ endif()
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_SOURCE_DIR}/cmake/DefaultBuildFlags.cmake")
+
+option(USE_VCPKG "Use vcpkg for dependency packages" OFF)
+if (USE_VCPKG)
+ include(ConfigureVcpkg)
+endif()
project(melonDS
VERSION 0.9.5
@@ -28,8 +34,6 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-add_compile_definitions(MELONDS_VERSION="${melonDS_VERSION}")
-
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
@@ -73,11 +77,6 @@ if (ENABLE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
-string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
-string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
-
if (NOT APPLE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s")
endif()
@@ -99,6 +98,11 @@ if (CCACHE)
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
endif()
+option(ENABLE_GDBSTUB "Enable GDB stub" ON)
+if (ENABLE_GDBSTUB)
+ add_definitions(-DGDBSTUB_ENABLED)
+endif()
+
option(BUILD_QT_SDL "Build Qt/SDL frontend" ON)
add_subdirectory(src)
diff --git a/CMakePresets.json b/CMakePresets.json
new file mode 100644
index 00000000..e14eda24
--- /dev/null
+++ b/CMakePresets.json
@@ -0,0 +1,88 @@
+{
+ "version": 6,
+ "configurePresets": [
+ {
+ "name": "release",
+ "displayName": "Release",
+ "description": "Default release build configuration.",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build/release"
+ },
+ {
+ "inherits": "release",
+ "name": "release-vcpkg",
+ "displayName": "Release (vcpkg)",
+ "description": "Release build with packages from vcpkg.",
+ "cacheVariables": {
+ "USE_VCPKG": {
+ "type": "BOOL",
+ "value": "ON"
+ }
+ }
+ },
+ {
+ "name": "release-mac-x86_64",
+ "inherits": "release-vcpkg",
+ "displayName": "macOS release (x86_64)",
+ "binaryDir": "${sourceDir}/build/release-mac-x86_64",
+ "cacheVariables": { "CMAKE_OSX_ARCHITECTURES": "x86_64" }
+ },
+ {
+ "name": "release-mac-arm64",
+ "inherits": "release-vcpkg",
+ "displayName": "macOS release (arm64)",
+ "binaryDir": "${sourceDir}/build/release-mac-arm64",
+ "cacheVariables": { "CMAKE_OSX_ARCHITECTURES": "arm64" }
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "release",
+ "configurePreset": "release"
+ },
+ {
+ "name": "release-vcpkg",
+ "configurePreset": "release-vcpkg"
+ },
+ {
+ "name": "release-mac-x86_64",
+ "configurePreset": "release-mac-x86_64"
+ },
+ {
+ "name": "release-mac-arm64",
+ "configurePreset": "release-mac-arm64"
+ }
+ ],
+ "workflowPresets": [
+ {
+ "name": "release",
+ "displayName": "Release",
+ "steps": [
+ { "type": "configure", "name": "release" },
+ { "type": "build", "name": "release" }
+ ]
+ },
+ {
+ "name": "release-vcpkg",
+ "displayName": "Release (vcpkg)",
+ "steps": [
+ { "type": "configure", "name": "release-vcpkg" },
+ { "type": "build", "name": "release-vcpkg" }
+ ]
+ },
+ {
+ "name": "release-mac-x86_64",
+ "steps": [
+ { "type": "configure", "name": "release-mac-x86_64" },
+ { "type": "build", "name": "release-mac-x86_64" }
+ ]
+ },
+ {
+ "name": "release-mac-arm64",
+ "steps": [
+ { "type": "configure", "name": "release-mac-arm64" },
+ { "type": "build", "name": "release-mac-arm64" }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index de494305..2cef7983 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,9 @@
-
-
-
-
+
+
+
DS emulator, sorta
diff --git a/cmake/ConfigureVcpkg.cmake b/cmake/ConfigureVcpkg.cmake
new file mode 100644
index 00000000..c9f3e92f
--- /dev/null
+++ b/cmake/ConfigureVcpkg.cmake
@@ -0,0 +1,91 @@
+include(FetchContent)
+
+set(_DEFAULT_VCPKG_ROOT "${CMAKE_SOURCE_DIR}/vcpkg")
+set(VCPKG_ROOT "${_DEFAULT_VCPKG_ROOT}" CACHE STRING "The path to the vcpkg repository")
+
+if (VCPKG_ROOT STREQUAL "${_DEFAULT_VCPKG_ROOT}")
+ file(LOCK "${_DEFAULT_VCPKG_ROOT}" DIRECTORY GUARD FILE)
+ FetchContent_Declare(vcpkg
+ GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git"
+ GIT_TAG 2024.01.12
+ SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg")
+ FetchContent_MakeAvailable(vcpkg)
+endif()
+
+set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_SOURCE_DIR}/cmake/overlay-triplets")
+
+option(USE_RECOMMENDED_TRIPLETS "Use the recommended triplets that are used for official builds" ON)
+
+if (CMAKE_OSX_ARCHITECTURES MATCHES ";")
+ message(FATAL_ERROR "macOS universal builds are not supported. Build them individually and combine afterwards instead.")
+endif()
+
+if (USE_RECOMMENDED_TRIPLETS)
+ execute_process(
+ COMMAND uname -m
+ OUTPUT_VARIABLE _HOST_PROCESSOR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(_CAN_TARGET_AS_HOST OFF)
+
+ if (APPLE)
+ if (NOT CMAKE_OSX_ARCHITECTURES)
+ if (_HOST_PROCESSOR STREQUAL arm64)
+ set(CMAKE_OSX_ARCHITECTURES arm64)
+ else()
+ set(CMAKE_OSX_ARCHITECTURES x86_64)
+ endif()
+ endif()
+
+ if (CMAKE_OSX_ARCHITECTURES STREQUAL arm64)
+ set(_WANTED_TRIPLET arm64-osx-11-release)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
+ else()
+ set(_WANTED_TRIPLET x64-osx-1015-release)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
+ endif()
+ elseif(WIN32)
+ # TODO Windows arm64 if possible
+ set(_CAN_TARGET_AS_HOST ON)
+ set(_WANTED_TRIPLET x64-mingw-static)
+ endif()
+
+ # Don't override it if the user set something else
+ if (NOT VCPKG_TARGET_TRIPLET)
+ set(VCPKG_TARGET_TRIPLET "${_WANTED_TRIPLET}")
+ else()
+ set(_WANTED_TRIPLET "${VCPKG_TARGET_TRIPLET}")
+ endif()
+
+ if (APPLE)
+ if (_HOST_PROCESSOR MATCHES arm64)
+ if (_WANTED_TRIPLET MATCHES "^arm64-osx-")
+ set(_CAN_TARGET_AS_HOST ON)
+ elseif (_WANTED_TRIPLET STREQUAL "x64-osx-1015-release")
+ # Use the default triplet for when building for arm64
+ # because we're probably making a universal build
+ set(VCPKG_HOST_TRIPLET arm64-osx-11-release)
+ endif()
+ else()
+ if (_WANTED_TRIPLET MATCHES "^x64-osx-")
+ set(_CAN_TARGET_AS_HOST ON)
+ elseif (_WANTED_TRIPLET STREQUAL "arm64-osx-11-release")
+ set(VCPKG_HOST_TRIPLET x64-osx-1015-release)
+ endif()
+ endif()
+ endif()
+
+ # If host and target triplet differ, vcpkg seems to always assume that the host can't run the target's binaries.
+ # In cases like cross compiling from ARM -> Intel macOS, or target being an older version of the host OS, we *can* do that so the packages built targeting the host are redundant.
+ if (_CAN_TARGET_AS_HOST AND NOT VCPKG_HOST_TRIPLET)
+ option(VCPKG_TARGET_AS_HOST "Use the target as host triplet to speed up builds" ON)
+ else()
+ option(VCPKG_TARGET_AS_HOST "Use the target as host triplet to speed up builds" OFF)
+ endif()
+
+ if (VCPKG_TARGET_AS_HOST)
+ set(VCPKG_HOST_TRIPLET "${VCPKG_TARGET_TRIPLET}" CACHE STRING "Host triplet to use for vcpkg")
+ endif()
+endif()
+
+set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
diff --git a/cmake/DefaultBuildFlags.cmake b/cmake/DefaultBuildFlags.cmake
new file mode 100644
index 00000000..683767b3
--- /dev/null
+++ b/cmake/DefaultBuildFlags.cmake
@@ -0,0 +1,9 @@
+if (CMAKE_C_COMPILER_ID STREQUAL GNU)
+ set(CMAKE_C_FLAGS_DEBUG_INIT "-g -Og")
+endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
+ set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -Og")
+endif()
+
+string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}")
+string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELEASE_INIT "${CMAKE_CXX_FLAGS_RELEASE_INIT}")
diff --git a/cmake/FixInterfaceIncludes.cmake b/cmake/FixInterfaceIncludes.cmake
index 513c1117..5c285d7a 100644
--- a/cmake/FixInterfaceIncludes.cmake
+++ b/cmake/FixInterfaceIncludes.cmake
@@ -19,6 +19,13 @@ function(fix_interface_includes)
if (PARENT_DIR MATCHES "include$")
list(APPEND NEW_DIRS "${PARENT_DIR}")
endif()
+
+ # HACK
+ # The libarchive pkg-config file in MSYS2 seems to include a UNIX-style path for its
+ # include directory and CMake doesn't like that.
+ if (WIN32 AND MINGW AND target STREQUAL PkgConfig::LibArchive)
+ list(FILTER DIRS EXCLUDE REGEX "^/[^.]+64/.*")
+ endif()
endforeach()
list(APPEND DIRS ${NEW_DIRS})
diff --git a/cmake/overlay-triplets/arm64-osx-11-release.cmake b/cmake/overlay-triplets/arm64-osx-11-release.cmake
new file mode 100644
index 00000000..7c4b43ae
--- /dev/null
+++ b/cmake/overlay-triplets/arm64-osx-11-release.cmake
@@ -0,0 +1,12 @@
+set(VCPKG_TARGET_ARCHITECTURE arm64)
+set(VCPKG_CRT_LINKAGE dynamic)
+set(VCPKG_LIBRARY_LINKAGE static)
+
+set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
+set(VCPKG_CMAKE_SYSTEM_VERSION 11.0)
+set(VCPKG_OSX_ARCHITECTURES arm64)
+set(VCPKG_BUILD_TYPE release)
+set(VCPKG_OSX_DEPLOYMENT_TARGET 11.0)
+
+set(VCPKG_C_FLAGS -mmacosx-version-min=11.0)
+set(VCPKG_CXX_FLAGS -mmacosx-version-min=11.0)
diff --git a/cmake/overlay-triplets/x64-osx-1015-release.cmake b/cmake/overlay-triplets/x64-osx-1015-release.cmake
new file mode 100644
index 00000000..fcb67a7a
--- /dev/null
+++ b/cmake/overlay-triplets/x64-osx-1015-release.cmake
@@ -0,0 +1,12 @@
+set(VCPKG_TARGET_ARCHITECTURE x64)
+set(VCPKG_CRT_LINKAGE dynamic)
+set(VCPKG_LIBRARY_LINKAGE static)
+
+set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
+set(VCPKG_CMAKE_SYSTEM_VERSION 10.15)
+set(VCPKG_OSX_ARCHITECTURES x86_64)
+set(VCPKG_BUILD_TYPE release)
+set(VCPKG_OSX_DEPLOYMENT_TARGET 10.15)
+
+set(VCPKG_C_FLAGS -mmacosx-version-min=10.15)
+set(VCPKG_CXX_FLAGS -mmacosx-version-min=10.15)
diff --git a/freebios/bios_common.S b/freebios/bios_common.S
index 56d349ef..308d67c4 100755
--- a/freebios/bios_common.S
+++ b/freebios/bios_common.S
@@ -517,6 +517,9 @@ swi_get_crc16:
mov const_0x1E, #0x1E
adr crc_table_ptr, crc_table
+ bic crc_value, crc_value, #0xFF000000
+ bic crc_value, crc_value, #0x00FF0000
+
movs crc_length, crc_length, lsr #1
beq 1f
diff --git a/freebios/drastic_bios_arm7.bin b/freebios/drastic_bios_arm7.bin
index e586eb9f..adffb53a 100755
Binary files a/freebios/drastic_bios_arm7.bin and b/freebios/drastic_bios_arm7.bin differ
diff --git a/freebios/drastic_bios_arm9.bin b/freebios/drastic_bios_arm9.bin
index 51a82829..95c330d0 100755
Binary files a/freebios/drastic_bios_arm9.bin and b/freebios/drastic_bios_arm9.bin differ
diff --git a/res/melon.rc.in b/res/melon.rc.in
index 3f2d8e4f..eb437b32 100644
--- a/res/melon.rc.in
+++ b/res/melon.rc.in
@@ -18,7 +18,7 @@ FILETYPE VFT_APP
VALUE "FileVersion", "${melonDS_VERSION}"
VALUE "FileDescription", "melonDS emulator"
VALUE "InternalName", "SDnolem"
- VALUE "LegalCopyright", "2016-2022 melonDS team"
+ VALUE "LegalCopyright", "2016-2023 melonDS team"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "melonDS.exe"
VALUE "ProductName", "melonDS"
diff --git a/src/ARCodeFile.cpp b/src/ARCodeFile.cpp
index d1f34fb6..602a2e7b 100644
--- a/src/ARCodeFile.cpp
+++ b/src/ARCodeFile.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -21,6 +21,8 @@
#include "ARCodeFile.h"
#include "Platform.h"
+namespace melonDS
+{
using namespace Platform;
// TODO: import codes from other sources (usrcheat.dat, ...)
@@ -162,23 +164,25 @@ bool ARCodeFile::Save()
{
ARCodeCat& cat = *it;
- if (it != Categories.begin()) FileWriteFormatted(f, "\r\n");
- FileWriteFormatted(f, "CAT %s\r\n\r\n", cat.Name.c_str());
+ if (it != Categories.begin()) FileWriteFormatted(f, "\n");
+ FileWriteFormatted(f, "CAT %s\n\n", cat.Name.c_str());
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
{
ARCode& code = *jt;
- FileWriteFormatted(f, "CODE %d %s\r\n", code.Enabled, code.Name.c_str());
+ FileWriteFormatted(f, "CODE %d %s\n", code.Enabled, code.Name.c_str());
for (size_t i = 0; i < code.Code.size(); i+=2)
{
- FileWriteFormatted(f, "%08X %08X\r\n", code.Code[i], code.Code[i + 1]);
+ FileWriteFormatted(f, "%08X %08X\n", code.Code[i], code.Code[i + 1]);
}
- FileWriteFormatted(f, "\r\n");
+ FileWriteFormatted(f, "\n");
}
}
CloseFile(f);
return true;
}
+
+}
\ No newline at end of file
diff --git a/src/ARCodeFile.h b/src/ARCodeFile.h
index d0e82550..11e71efe 100644
--- a/src/ARCodeFile.h
+++ b/src/ARCodeFile.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -24,6 +24,8 @@
#include
#include "types.h"
+namespace melonDS
+{
struct ARCode
{
std::string Name;
@@ -59,4 +61,5 @@ private:
std::string Filename;
};
+}
#endif // ARCODEFILE_H
diff --git a/src/AREngine.cpp b/src/AREngine.cpp
index 62600f9e..c7d49fe6 100644
--- a/src/AREngine.cpp
+++ b/src/AREngine.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -23,84 +23,33 @@
#include "AREngine.h"
#include "Platform.h"
+namespace melonDS
+{
+
using Platform::Log;
using Platform::LogLevel;
-namespace AREngine
-{
-
-// AR code file - frontend is responsible for managing this
-ARCodeFile* CodeFile;
-
-u8 (*BusRead8)(u32 addr);
-u16 (*BusRead16)(u32 addr);
-u32 (*BusRead32)(u32 addr);
-void (*BusWrite8)(u32 addr, u8 val);
-void (*BusWrite16)(u32 addr, u16 val);
-void (*BusWrite32)(u32 addr, u32 val);
-
-
-bool Init()
+AREngine::AREngine(melonDS::NDS& nds) : NDS(nds)
{
CodeFile = nullptr;
-
- return true;
}
-void DeInit()
-{
-}
-
-void Reset()
-{
- if (NDS::ConsoleType == 1)
- {
- BusRead8 = DSi::ARM7Read8;
- BusRead16 = DSi::ARM7Read16;
- BusRead32 = DSi::ARM7Read32;
- BusWrite8 = DSi::ARM7Write8;
- BusWrite16 = DSi::ARM7Write16;
- BusWrite32 = DSi::ARM7Write32;
- }
- else
- {
- BusRead8 = NDS::ARM7Read8;
- BusRead16 = NDS::ARM7Read16;
- BusRead32 = NDS::ARM7Read32;
- BusWrite8 = NDS::ARM7Write8;
- BusWrite16 = NDS::ARM7Write16;
- BusWrite32 = NDS::ARM7Write32;
- }
-}
-
-
-ARCodeFile* GetCodeFile()
-{
- return CodeFile;
-}
-
-void SetCodeFile(ARCodeFile* file)
-{
- CodeFile = file;
-}
-
-
#define case16(x) \
case ((x)+0x00): case ((x)+0x01): case ((x)+0x02): case ((x)+0x03): \
case ((x)+0x04): case ((x)+0x05): case ((x)+0x06): case ((x)+0x07): \
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F)
-void RunCheat(ARCode& arcode)
+void AREngine::RunCheat(const ARCode& arcode)
{
- u32* code = &arcode.Code[0];
+ const u32* code = &arcode.Code[0];
u32 offset = 0;
u32 datareg = 0;
u32 cond = 1;
u32 condstack = 0;
- u32* loopstart = code;
+ const u32* loopstart = code;
u32 loopcount = 0;
u32 loopcond = 1;
u32 loopcondstack = 0;
@@ -135,15 +84,15 @@ void RunCheat(ARCode& arcode)
switch (op)
{
case16(0x00): // 32-bit write
- BusWrite32((a & 0x0FFFFFFF) + offset, b);
+ NDS.ARM7Write32((a & 0x0FFFFFFF) + offset, b);
break;
case16(0x10): // 16-bit write
- BusWrite16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
+ NDS.ARM7Write16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
break;
case16(0x20): // 8-bit write
- BusWrite8((a & 0x0FFFFFFF) + offset, b & 0xFF);
+ NDS.ARM7Write8((a & 0x0FFFFFFF) + offset, b & 0xFF);
break;
case16(0x30): // IF b > u32[a]
@@ -153,7 +102,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u32 chk = BusRead32(addr);
+ u32 chk = NDS.ARM7Read32(addr);
cond = (b > chk) ? 1:0;
}
@@ -166,7 +115,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u32 chk = BusRead32(addr);
+ u32 chk = NDS.ARM7Read32(addr);
cond = (b < chk) ? 1:0;
}
@@ -179,7 +128,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u32 chk = BusRead32(addr);
+ u32 chk = NDS.ARM7Read32(addr);
cond = (b == chk) ? 1:0;
}
@@ -192,7 +141,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u32 chk = BusRead32(addr);
+ u32 chk = NDS.ARM7Read32(addr);
cond = (b != chk) ? 1:0;
}
@@ -205,7 +154,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u16 val = BusRead16(addr);
+ u16 val = NDS.ARM7Read16(addr);
u16 chk = ~(b >> 16);
chk &= val;
@@ -220,7 +169,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u16 val = BusRead16(addr);
+ u16 val = NDS.ARM7Read16(addr);
u16 chk = ~(b >> 16);
chk &= val;
@@ -235,7 +184,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u16 val = BusRead16(addr);
+ u16 val = NDS.ARM7Read16(addr);
u16 chk = ~(b >> 16);
chk &= val;
@@ -250,7 +199,7 @@ void RunCheat(ARCode& arcode)
u32 addr = a & 0x0FFFFFFF;
if (!addr) addr = offset;
- u16 val = BusRead16(addr);
+ u16 val = NDS.ARM7Read16(addr);
u16 chk = ~(b >> 16);
chk &= val;
@@ -259,7 +208,7 @@ void RunCheat(ARCode& arcode)
break;
case16(0xB0): // offset = u32[a + offset]
- offset = BusRead32((a & 0x0FFFFFFF) + offset);
+ offset = NDS.ARM7Read32((a & 0x0FFFFFFF) + offset);
break;
case 0xC0: // FOR 0..b
@@ -296,7 +245,7 @@ void RunCheat(ARCode& arcode)
break;
case 0xC6: // u32[b] = offset
- BusWrite32(b, offset);
+ NDS.ARM7Write32(b, offset);
break;
case 0xD0: // ENDIF
@@ -345,30 +294,30 @@ void RunCheat(ARCode& arcode)
break;
case 0xD6: // u32[b+offset] = datareg / offset += 4
- BusWrite32(b + offset, datareg);
+ NDS.ARM7Write32(b + offset, datareg);
offset += 4;
break;
case 0xD7: // u16[b+offset] = datareg / offset += 2
- BusWrite16(b + offset, datareg & 0xFFFF);
+ NDS.ARM7Write16(b + offset, datareg & 0xFFFF);
offset += 2;
break;
case 0xD8: // u8[b+offset] = datareg / offset += 1
- BusWrite8(b + offset, datareg & 0xFF);
+ NDS.ARM7Write8(b + offset, datareg & 0xFF);
offset += 1;
break;
case 0xD9: // datareg = u32[b+offset]
- datareg = BusRead32(b + offset);
+ datareg = NDS.ARM7Read32(b + offset);
break;
case 0xDA: // datareg = u16[b+offset]
- datareg = BusRead16(b + offset);
+ datareg = NDS.ARM7Read16(b + offset);
break;
case 0xDB: // datareg = u8[b+offset]
- datareg = BusRead8(b + offset);
+ datareg = NDS.ARM7Read8(b + offset);
break;
case 0xDC: // offset += b
@@ -383,8 +332,8 @@ void RunCheat(ARCode& arcode)
u32 bytesleft = b;
while (bytesleft >= 8)
{
- BusWrite32(dstaddr, *code++); dstaddr += 4;
- BusWrite32(dstaddr, *code++); dstaddr += 4;
+ NDS.ARM7Write32(dstaddr, *code++); dstaddr += 4;
+ NDS.ARM7Write32(dstaddr, *code++); dstaddr += 4;
bytesleft -= 8;
}
if (bytesleft > 0)
@@ -393,13 +342,13 @@ void RunCheat(ARCode& arcode)
code += 2;
if (bytesleft >= 4)
{
- BusWrite32(dstaddr, *(u32*)leftover); dstaddr += 4;
+ NDS.ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
leftover += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
- BusWrite8(dstaddr, *leftover++); dstaddr++;
+ NDS.ARM7Write8(dstaddr, *leftover++); dstaddr++;
bytesleft--;
}
}
@@ -415,14 +364,14 @@ void RunCheat(ARCode& arcode)
u32 bytesleft = b;
while (bytesleft >= 4)
{
- BusWrite32(dstaddr, BusRead32(srcaddr));
+ NDS.ARM7Write32(dstaddr, NDS.ARM7Read32(srcaddr));
srcaddr += 4;
dstaddr += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
- BusWrite8(dstaddr, BusRead8(srcaddr));
+ NDS.ARM7Write8(dstaddr, NDS.ARM7Read8(srcaddr));
srcaddr++;
dstaddr++;
bytesleft--;
@@ -437,7 +386,7 @@ void RunCheat(ARCode& arcode)
}
}
-void RunCheats()
+void AREngine::RunCheats()
{
if (!CodeFile) return;
@@ -454,5 +403,4 @@ void RunCheats()
}
}
}
-
}
diff --git a/src/AREngine.h b/src/AREngine.h
index 3e6e9dd4..21044676 100644
--- a/src/AREngine.h
+++ b/src/AREngine.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -21,18 +21,23 @@
#include "ARCodeFile.h"
-namespace AREngine
+namespace melonDS
{
+class NDS;
+class AREngine
+{
+public:
+ AREngine(melonDS::NDS& nds);
-bool Init();
-void DeInit();
-void Reset();
+ ARCodeFile* GetCodeFile() { return CodeFile; }
+ void SetCodeFile(ARCodeFile* file) { CodeFile = file; }
-ARCodeFile* GetCodeFile();
-void SetCodeFile(ARCodeFile* file);
-
-void RunCheats();
+ void RunCheats();
+ void RunCheat(const ARCode& arcode);
+private:
+ melonDS::NDS& NDS;
+ ARCodeFile* CodeFile; // AR code file - frontend is responsible for managing this
+};
}
-
#endif // ARENGINE_H
diff --git a/src/ARM.cpp b/src/ARM.cpp
index b59530d1..c2f6a6c2 100644
--- a/src/ARM.cpp
+++ b/src/ARM.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,6 +17,7 @@
*/
#include
+#include
#include
#include "NDS.h"
#include "DSi.h"
@@ -25,15 +26,53 @@
#include "AREngine.h"
#include "ARMJIT.h"
#include "Platform.h"
-
-#ifdef JIT_ENABLED
-#include "ARMJIT.h"
+#include "GPU.h"
#include "ARMJIT_Memory.h"
-#endif
+namespace melonDS
+{
using Platform::Log;
using Platform::LogLevel;
+#ifdef GDBSTUB_ENABLED
+void ARM::GdbCheckA()
+{
+ if (!IsSingleStep && !BreakReq)
+ { // check if eg. break signal is incoming etc.
+ Gdb::StubState st = GdbStub.Enter(false, Gdb::TgtStatus::NoEvent, ~(u32)0u, BreakOnStartup);
+ BreakOnStartup = false;
+ IsSingleStep = st == Gdb::StubState::Step;
+ BreakReq = st == Gdb::StubState::Attach || st == Gdb::StubState::Break;
+ }
+}
+void ARM::GdbCheckB()
+{
+ if (IsSingleStep || BreakReq)
+ { // use else here or we single-step the same insn twice in gdb
+ u32 pc_real = R[15] - ((CPSR & 0x20) ? 2 : 4);
+ Gdb::StubState st = GdbStub.Enter(true, Gdb::TgtStatus::SingleStep, pc_real);
+ IsSingleStep = st == Gdb::StubState::Step;
+ BreakReq = st == Gdb::StubState::Attach || st == Gdb::StubState::Break;
+ }
+}
+void ARM::GdbCheckC()
+{
+ u32 pc_real = R[15] - ((CPSR & 0x20) ? 2 : 4);
+ Gdb::StubState st = GdbStub.CheckBkpt(pc_real, true, true);
+ if (st != Gdb::StubState::CheckNoHit)
+ {
+ IsSingleStep = st == Gdb::StubState::Step;
+ BreakReq = st == Gdb::StubState::Attach || st == Gdb::StubState::Break;
+ }
+ else GdbCheckB();
+}
+#else
+void ARM::GdbCheckA() {}
+void ARM::GdbCheckB() {}
+void ARM::GdbCheckC() {}
+#endif
+
+
// instruction timing notes
//
// * simple instruction: 1S (code)
@@ -48,7 +87,7 @@ using Platform::LogLevel;
-u32 ARM::ConditionTable[16] =
+const u32 ARM::ConditionTable[16] =
{
0xF0F0, // EQ
0x0F0F, // NE
@@ -68,11 +107,22 @@ u32 ARM::ConditionTable[16] =
0x0000 // NE
};
-
-ARM::ARM(u32 num)
+ARM::ARM(u32 num, bool jit, std::optional gdb, melonDS::NDS& nds) :
+#ifdef GDBSTUB_ENABLED
+ GdbStub(this, gdb ? (num ? gdb->PortARM7 : gdb->PortARM9) : 0),
+#endif
+ Num(num), // well uh
+ NDS(nds)
{
- // well uh
- Num = num;
+#ifdef GDBSTUB_ENABLED
+ if (gdb
+#ifdef JIT_ENABLED
+ && !jit // TODO: Should we support toggling the GdbStub without destroying the ARM?
+#endif
+ )
+ GdbStub.Init();
+ IsSingleStep = false;
+#endif
}
ARM::~ARM()
@@ -80,25 +130,21 @@ ARM::~ARM()
// dorp
}
-ARMv5::ARMv5() : ARM(0)
+ARMv5::ARMv5(melonDS::NDS& nds, std::optional gdb, bool jit) : ARM(0, jit, gdb, nds)
{
-#ifndef JIT_ENABLED
- DTCM = new u8[DTCMPhysicalSize];
-#endif
+ DTCM = NDS.JIT.Memory.GetARM9DTCM();
PU_Map = PU_PrivMap;
}
-ARMv4::ARMv4() : ARM(1)
+ARMv4::ARMv4(melonDS::NDS& nds, std::optional gdb, bool jit) : ARM(1, jit, gdb, nds)
{
//
}
ARMv5::~ARMv5()
{
-#ifndef JIT_ENABLED
- delete[] DTCM;
-#endif
+ // DTCM is owned by Memory, not going to delete it
}
void ARM::Reset()
@@ -139,62 +185,22 @@ void ARM::Reset()
FastBlockLookupSize = 0;
#endif
+#ifdef GDBSTUB_ENABLED
+ IsSingleStep = false;
+ BreakReq = false;
+#endif
+
// zorp
JumpTo(ExceptionBase);
}
void ARMv5::Reset()
{
- if (NDS::ConsoleType == 1)
- {
- BusRead8 = DSi::ARM9Read8;
- BusRead16 = DSi::ARM9Read16;
- BusRead32 = DSi::ARM9Read32;
- BusWrite8 = DSi::ARM9Write8;
- BusWrite16 = DSi::ARM9Write16;
- BusWrite32 = DSi::ARM9Write32;
- GetMemRegion = DSi::ARM9GetMemRegion;
- }
- else
- {
- BusRead8 = NDS::ARM9Read8;
- BusRead16 = NDS::ARM9Read16;
- BusRead32 = NDS::ARM9Read32;
- BusWrite8 = NDS::ARM9Write8;
- BusWrite16 = NDS::ARM9Write16;
- BusWrite32 = NDS::ARM9Write32;
- GetMemRegion = NDS::ARM9GetMemRegion;
- }
-
PU_Map = PU_PrivMap;
ARM::Reset();
}
-void ARMv4::Reset()
-{
- if (NDS::ConsoleType)
- {
- BusRead8 = DSi::ARM7Read8;
- BusRead16 = DSi::ARM7Read16;
- BusRead32 = DSi::ARM7Read32;
- BusWrite8 = DSi::ARM7Write8;
- BusWrite16 = DSi::ARM7Write16;
- BusWrite32 = DSi::ARM7Write32;
- }
- else
- {
- BusRead8 = NDS::ARM7Read8;
- BusRead16 = NDS::ARM7Read16;
- BusRead32 = NDS::ARM7Read32;
- BusWrite8 = NDS::ARM7Write8;
- BusWrite16 = NDS::ARM7Write16;
- BusWrite32 = NDS::ARM7Write32;
- }
-
- ARM::Reset();
-}
-
void ARM::DoSavestate(Savestate* file)
{
@@ -217,7 +223,7 @@ void ARM::DoSavestate(Savestate* file)
file->VarArray(R_UND, 3*sizeof(u32));
file->Var32(&CurInstr);
#ifdef JIT_ENABLED
- if (file->Saving && NDS::EnableJIT)
+ if (file->Saving && NDS.IsJITEnabled())
{
// hack, the JIT doesn't really pipeline
// but we still want JIT save states to be
@@ -343,7 +349,7 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr)
return;
}
- NDS::MonitorARM9Jump(addr);
+ NDS.MonitorARM9Jump(addr);
}
void ARMv4::JumpTo(u32 addr, bool restorecpsr)
@@ -371,7 +377,7 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr)
NextInstr[0] = CodeRead16(addr);
NextInstr[1] = CodeRead16(addr+2);
- Cycles += NDS::ARM7MemTimings[CodeCycles][0] + NDS::ARM7MemTimings[CodeCycles][1];
+ Cycles += NDS.ARM7MemTimings[CodeCycles][0] + NDS.ARM7MemTimings[CodeCycles][1];
CPSR |= 0x20;
}
@@ -384,7 +390,7 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr)
NextInstr[0] = CodeRead32(addr);
NextInstr[1] = CodeRead32(addr+4);
- Cycles += NDS::ARM7MemTimings[CodeCycles][2] + NDS::ARM7MemTimings[CodeCycles][3];
+ Cycles += NDS.ARM7MemTimings[CodeCycles][2] + NDS.ARM7MemTimings[CodeCycles][3];
CPSR &= ~0x20;
}
@@ -529,8 +535,8 @@ void ARM::TriggerIRQ()
// normally, those work by hijacking the ARM7 VBlank handler
if (Num == 1)
{
- if ((NDS::IF[1] & NDS::IE[1]) & (1<>12] & 0x04))
{
Log(LogLevel::Error, "!!!!! EXCEPTION REGION NOT EXECUTABLE. THIS IS VERY BAD!!\n");
- NDS::Stop(Platform::StopReason::BadExceptionRegion);
+ NDS.Stop(Platform::StopReason::BadExceptionRegion);
return;
}
@@ -571,31 +577,40 @@ void ARMv5::DataAbort()
JumpTo(ExceptionBase + 0x10);
}
+void ARM::CheckGdbIncoming()
+{
+ GdbCheckA();
+}
+
void ARMv5::Execute()
{
+ GdbCheckB();
+
if (Halted)
{
if (Halted == 2)
{
Halted = 0;
}
- else if (NDS::HaltInterrupted(0))
+ else if (NDS.HaltInterrupted(0))
{
Halted = 0;
- if (NDS::IME[0] & 0x1)
+ if (NDS.IME[0] & 0x1)
TriggerIRQ();
}
else
{
- NDS::ARM9Timestamp = NDS::ARM9Target;
+ NDS.ARM9Timestamp = NDS.ARM9Target;
return;
}
}
- while (NDS::ARM9Timestamp < NDS::ARM9Target)
+ while (NDS.ARM9Timestamp < NDS.ARM9Target)
{
if (CPSR & 0x20) // THUMB
{
+ GdbCheckC();
+
// prefetch
R[15] += 2;
CurInstr = NextInstr[0];
@@ -609,6 +624,8 @@ void ARMv5::Execute()
}
else
{
+ GdbCheckC();
+
// prefetch
R[15] += 4;
CurInstr = NextInstr[0];
@@ -632,9 +649,9 @@ void ARMv5::Execute()
// TODO optimize this shit!!!
if (Halted)
{
- if (Halted == 1 && NDS::ARM9Timestamp < NDS::ARM9Target)
+ if (Halted == 1 && NDS.ARM9Timestamp < NDS.ARM9Target)
{
- NDS::ARM9Timestamp = NDS::ARM9Target;
+ NDS.ARM9Timestamp = NDS.ARM9Target;
}
break;
}
@@ -645,7 +662,7 @@ void ARMv5::Execute()
}*/
if (IRQ) TriggerIRQ();
- NDS::ARM9Timestamp += Cycles;
+ NDS.ARM9Timestamp += Cycles;
Cycles = 0;
}
@@ -662,37 +679,37 @@ void ARMv5::ExecuteJIT()
{
Halted = 0;
}
- else if (NDS::HaltInterrupted(0))
+ else if (NDS.HaltInterrupted(0))
{
Halted = 0;
- if (NDS::IME[0] & 0x1)
+ if (NDS.IME[0] & 0x1)
TriggerIRQ();
}
else
{
- NDS::ARM9Timestamp = NDS::ARM9Target;
+ NDS.ARM9Timestamp = NDS.ARM9Target;
return;
}
}
- while (NDS::ARM9Timestamp < NDS::ARM9Target)
+ while (NDS.ARM9Timestamp < NDS.ARM9Target)
{
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
- && !ARMJIT::SetupExecutableRegion(0, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
+ && !NDS.JIT.SetupExecutableRegion(0, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
{
- NDS::ARM9Timestamp = NDS::ARM9Target;
+ NDS.ARM9Timestamp = NDS.ARM9Target;
Log(LogLevel::Error, "ARMv5 PC in non executable region %08X\n", R[15]);
return;
}
- ARMJIT::JitBlockEntry block = ARMJIT::LookUpBlock(0, FastBlockLookup,
+ JitBlockEntry block = NDS.JIT.LookUpBlock(0, FastBlockLookup,
instrAddr - FastBlockLookupStart, instrAddr);
if (block)
ARM_Dispatch(this, block);
else
- ARMJIT::CompileBlock(this);
+ NDS.JIT.CompileBlock(this);
if (StopExecution)
{
@@ -702,17 +719,17 @@ void ARMv5::ExecuteJIT()
if (Halted || IdleLoop)
{
- if ((Halted == 1 || IdleLoop) && NDS::ARM9Timestamp < NDS::ARM9Target)
+ if ((Halted == 1 || IdleLoop) && NDS.ARM9Timestamp < NDS.ARM9Target)
{
Cycles = 0;
- NDS::ARM9Timestamp = NDS::ARM9Target;
+ NDS.ARM9Timestamp = NDS.ARM9Target;
}
IdleLoop = 0;
break;
}
}
- NDS::ARM9Timestamp += Cycles;
+ NDS.ARM9Timestamp += Cycles;
Cycles = 0;
}
@@ -723,29 +740,33 @@ void ARMv5::ExecuteJIT()
void ARMv4::Execute()
{
+ GdbCheckB();
+
if (Halted)
{
if (Halted == 2)
{
Halted = 0;
}
- else if (NDS::HaltInterrupted(1))
+ else if (NDS.HaltInterrupted(1))
{
Halted = 0;
- if (NDS::IME[1] & 0x1)
+ if (NDS.IME[1] & 0x1)
TriggerIRQ();
}
else
{
- NDS::ARM7Timestamp = NDS::ARM7Target;
+ NDS.ARM7Timestamp = NDS.ARM7Target;
return;
}
}
- while (NDS::ARM7Timestamp < NDS::ARM7Target)
+ while (NDS.ARM7Timestamp < NDS.ARM7Target)
{
if (CPSR & 0x20) // THUMB
{
+ GdbCheckC();
+
// prefetch
R[15] += 2;
CurInstr = NextInstr[0];
@@ -758,6 +779,8 @@ void ARMv4::Execute()
}
else
{
+ GdbCheckC();
+
// prefetch
R[15] += 4;
CurInstr = NextInstr[0];
@@ -777,9 +800,9 @@ void ARMv4::Execute()
// TODO optimize this shit!!!
if (Halted)
{
- if (Halted == 1 && NDS::ARM7Timestamp < NDS::ARM7Target)
+ if (Halted == 1 && NDS.ARM7Timestamp < NDS.ARM7Target)
{
- NDS::ARM7Timestamp = NDS::ARM7Target;
+ NDS.ARM7Timestamp = NDS.ARM7Target;
}
break;
}
@@ -790,7 +813,7 @@ void ARMv4::Execute()
}*/
if (IRQ) TriggerIRQ();
- NDS::ARM7Timestamp += Cycles;
+ NDS.ARM7Timestamp += Cycles;
Cycles = 0;
}
@@ -799,7 +822,9 @@ void ARMv4::Execute()
if (Halted == 4)
{
- DSi::SoftReset();
+ assert(NDS.ConsoleType == 1);
+ auto& dsi = dynamic_cast(NDS);
+ dsi.SoftReset();
Halted = 2;
}
}
@@ -813,37 +838,37 @@ void ARMv4::ExecuteJIT()
{
Halted = 0;
}
- else if (NDS::HaltInterrupted(1))
+ else if (NDS.HaltInterrupted(1))
{
Halted = 0;
- if (NDS::IME[1] & 0x1)
+ if (NDS.IME[1] & 0x1)
TriggerIRQ();
}
else
{
- NDS::ARM7Timestamp = NDS::ARM7Target;
+ NDS.ARM7Timestamp = NDS.ARM7Target;
return;
}
}
- while (NDS::ARM7Timestamp < NDS::ARM7Target)
+ while (NDS.ARM7Timestamp < NDS.ARM7Target)
{
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
- && !ARMJIT::SetupExecutableRegion(1, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
+ && !NDS.JIT.SetupExecutableRegion(1, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
{
- NDS::ARM7Timestamp = NDS::ARM7Target;
+ NDS.ARM7Timestamp = NDS.ARM7Target;
Log(LogLevel::Error, "ARMv4 PC in non executable region %08X\n", R[15]);
return;
}
- ARMJIT::JitBlockEntry block = ARMJIT::LookUpBlock(1, FastBlockLookup,
+ JitBlockEntry block = NDS.JIT.LookUpBlock(1, FastBlockLookup,
instrAddr - FastBlockLookupStart, instrAddr);
if (block)
ARM_Dispatch(this, block);
else
- ARMJIT::CompileBlock(this);
+ NDS.JIT.CompileBlock(this);
if (StopExecution)
{
@@ -852,17 +877,17 @@ void ARMv4::ExecuteJIT()
if (Halted || IdleLoop)
{
- if ((Halted == 1 || IdleLoop) && NDS::ARM7Timestamp < NDS::ARM7Target)
+ if ((Halted == 1 || IdleLoop) && NDS.ARM7Timestamp < NDS.ARM7Target)
{
Cycles = 0;
- NDS::ARM7Timestamp = NDS::ARM7Target;
+ NDS.ARM7Timestamp = NDS.ARM7Target;
}
IdleLoop = 0;
break;
}
}
- NDS::ARM7Timestamp += Cycles;
+ NDS.ARM7Timestamp += Cycles;
Cycles = 0;
}
@@ -871,7 +896,9 @@ void ARMv4::ExecuteJIT()
if (Halted == 4)
{
- DSi::SoftReset();
+ assert(NDS.ConsoleType == 1);
+ auto& dsi = dynamic_cast(NDS);
+ dsi.SoftReset();
Halted = 2;
}
}
@@ -916,3 +943,402 @@ void ARMv4::FillPipeline()
NextInstr[1] = CodeRead32(R[15]);
}
}
+
+#ifdef GDBSTUB_ENABLED
+u32 ARM::ReadReg(Gdb::Register reg)
+{
+ using Gdb::Register;
+ int r = static_cast(reg);
+
+ if (reg < Register::pc) return R[r];
+ else if (reg == Register::pc)
+ {
+ return R[r] - ((CPSR & 0x20) ? 2 : 4);
+ }
+ else if (reg == Register::cpsr) return CPSR;
+ else if (reg == Register::sp_usr || reg == Register::lr_usr)
+ {
+ r -= static_cast(Register::sp_usr);
+ if (ModeIs(0x10) || ModeIs(0x1f))
+ {
+ return R[13 + r];
+ }
+ else switch (CPSR & 0x1f)
+ {
+ case 0x11: return R_FIQ[5 + r];
+ case 0x12: return R_IRQ[0 + r];
+ case 0x13: return R_SVC[0 + r];
+ case 0x17: return R_ABT[0 + r];
+ case 0x1b: return R_UND[0 + r];
+ }
+ }
+ else if (reg >= Register::r8_fiq && reg <= Register::lr_fiq)
+ {
+ r -= static_cast(Register::r8_fiq);
+ return ModeIs(0x11) ? R[ 8 + r] : R_FIQ[r];
+ }
+ else if (reg == Register::sp_irq || reg == Register::lr_irq)
+ {
+ r -= static_cast(Register::sp_irq);
+ return ModeIs(0x12) ? R[13 + r] : R_IRQ[r];
+ }
+ else if (reg == Register::sp_svc || reg == Register::lr_svc)
+ {
+ r -= static_cast(Register::sp_svc);
+ return ModeIs(0x13) ? R[13 + r] : R_SVC[r];
+ }
+ else if (reg == Register::sp_abt || reg == Register::lr_abt)
+ {
+ r -= static_cast(Register::sp_abt);
+ return ModeIs(0x17) ? R[13 + r] : R_ABT[r];
+ }
+ else if (reg == Register::sp_und || reg == Register::lr_und)
+ {
+ r -= static_cast(Register::sp_und);
+ return ModeIs(0x1b) ? R[13 + r] : R_UND[r];
+ }
+ else if (reg == Register::spsr_fiq) return ModeIs(0x11) ? CPSR : R_FIQ[7];
+ else if (reg == Register::spsr_irq) return ModeIs(0x12) ? CPSR : R_IRQ[2];
+ else if (reg == Register::spsr_svc) return ModeIs(0x13) ? CPSR : R_SVC[2];
+ else if (reg == Register::spsr_abt) return ModeIs(0x17) ? CPSR : R_ABT[2];
+ else if (reg == Register::spsr_und) return ModeIs(0x1b) ? CPSR : R_UND[2];
+
+ Log(LogLevel::Warn, "GDB reg read: unknown reg no %d\n", r);
+ return 0xdeadbeef;
+}
+void ARM::WriteReg(Gdb::Register reg, u32 v)
+{
+ using Gdb::Register;
+ int r = static_cast(reg);
+
+ if (reg < Register::pc) R[r] = v;
+ else if (reg == Register::pc) JumpTo(v);
+ else if (reg == Register::cpsr) CPSR = v;
+ else if (reg == Register::sp_usr || reg == Register::lr_usr)
+ {
+ r -= static_cast(Register::sp_usr);
+ if (ModeIs(0x10) || ModeIs(0x1f))
+ {
+ R[13 + r] = v;
+ }
+ else switch (CPSR & 0x1f)
+ {
+ case 0x11: R_FIQ[5 + r] = v; break;
+ case 0x12: R_IRQ[0 + r] = v; break;
+ case 0x13: R_SVC[0 + r] = v; break;
+ case 0x17: R_ABT[0 + r] = v; break;
+ case 0x1b: R_UND[0 + r] = v; break;
+ }
+ }
+ else if (reg >= Register::r8_fiq && reg <= Register::lr_fiq)
+ {
+ r -= static_cast(Register::r8_fiq);
+ *(ModeIs(0x11) ? &R[ 8 + r] : &R_FIQ[r]) = v;
+ }
+ else if (reg == Register::sp_irq || reg == Register::lr_irq)
+ {
+ r -= static_cast(Register::sp_irq);
+ *(ModeIs(0x12) ? &R[13 + r] : &R_IRQ[r]) = v;
+ }
+ else if (reg == Register::sp_svc || reg == Register::lr_svc)
+ {
+ r -= static_cast(Register::sp_svc);
+ *(ModeIs(0x13) ? &R[13 + r] : &R_SVC[r]) = v;
+ }
+ else if (reg == Register::sp_abt || reg == Register::lr_abt)
+ {
+ r -= static_cast(Register::sp_abt);
+ *(ModeIs(0x17) ? &R[13 + r] : &R_ABT[r]) = v;
+ }
+ else if (reg == Register::sp_und || reg == Register::lr_und)
+ {
+ r -= static_cast(Register::sp_und);
+ *(ModeIs(0x1b) ? &R[13 + r] : &R_UND[r]) = v;
+ }
+ else if (reg == Register::spsr_fiq)
+ {
+ *(ModeIs(0x11) ? &CPSR : &R_FIQ[7]) = v;
+ }
+ else if (reg == Register::spsr_irq)
+ {
+ *(ModeIs(0x12) ? &CPSR : &R_IRQ[2]) = v;
+ }
+ else if (reg == Register::spsr_svc)
+ {
+ *(ModeIs(0x13) ? &CPSR : &R_SVC[2]) = v;
+ }
+ else if (reg == Register::spsr_abt)
+ {
+ *(ModeIs(0x17) ? &CPSR : &R_ABT[2]) = v;
+ }
+ else if (reg == Register::spsr_und)
+ {
+ *(ModeIs(0x1b) ? &CPSR : &R_UND[2]) = v;
+ }
+ else Log(LogLevel::Warn, "GDB reg write: unknown reg no %d (write 0x%08x)\n", r, v);
+}
+u32 ARM::ReadMem(u32 addr, int size)
+{
+ if (size == 8) return BusRead8(addr);
+ else if (size == 16) return BusRead16(addr);
+ else if (size == 32) return BusRead32(addr);
+ else return 0xfeedface;
+}
+void ARM::WriteMem(u32 addr, int size, u32 v)
+{
+ if (size == 8) BusWrite8(addr, (u8)v);
+ else if (size == 16) BusWrite16(addr, (u16)v);
+ else if (size == 32) BusWrite32(addr, v);
+}
+
+void ARM::ResetGdb()
+{
+ NDS.Reset();
+ NDS.GPU.StartFrame(); // need this to properly kick off the scheduler & frame output
+}
+int ARM::RemoteCmd(const u8* cmd, size_t len)
+{
+ (void)len;
+
+ Log(LogLevel::Info, "[ARMGDB] Rcmd: \"%s\"\n", cmd);
+ if (!strcmp((const char*)cmd, "reset") || !strcmp((const char*)cmd, "r"))
+ {
+ Reset();
+ return 0;
+ }
+
+ return 1; // not implemented (yet)
+}
+
+void ARMv5::WriteMem(u32 addr, int size, u32 v)
+{
+ if (addr < ITCMSize)
+ {
+ if (size == 8) *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = (u8)v;
+ else if (size == 16) *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = (u16)v;
+ else if (size == 32) *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = (u32)v;
+ else {}
+ return;
+ }
+ else if ((addr & DTCMMask) == DTCMBase)
+ {
+ if (size == 8) *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = (u8)v;
+ else if (size == 16) *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = (u16)v;
+ else if (size == 32) *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = (u32)v;
+ else {}
+ return;
+ }
+
+ ARM::WriteMem(addr, size, v);
+}
+u32 ARMv5::ReadMem(u32 addr, int size)
+{
+ if (addr < ITCMSize)
+ {
+ if (size == 8) return *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)];
+ else if (size == 16) return *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)];
+ else if (size == 32) return *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)];
+ else return 0xfeedface;
+ }
+ else if ((addr & DTCMMask) == DTCMBase)
+ {
+ if (size == 8) return *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)];
+ else if (size == 16) return *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)];
+ else if (size == 32) return *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)];
+ else return 0xfeedface;
+ }
+
+ return ARM::ReadMem(addr, size);
+}
+#endif
+
+void ARMv4::DataRead8(u32 addr, u32* val)
+{
+ *val = BusRead8(addr);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
+}
+
+void ARMv4::DataRead16(u32 addr, u32* val)
+{
+ addr &= ~1;
+
+ *val = BusRead16(addr);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
+}
+
+void ARMv4::DataRead32(u32 addr, u32* val)
+{
+ addr &= ~3;
+
+ *val = BusRead32(addr);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
+}
+
+void ARMv4::DataRead32S(u32 addr, u32* val)
+{
+ addr &= ~3;
+
+ *val = BusRead32(addr);
+ DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
+}
+
+void ARMv4::DataWrite8(u32 addr, u8 val)
+{
+ BusWrite8(addr, val);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
+}
+
+void ARMv4::DataWrite16(u32 addr, u16 val)
+{
+ addr &= ~1;
+
+ BusWrite16(addr, val);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
+}
+
+void ARMv4::DataWrite32(u32 addr, u32 val)
+{
+ addr &= ~3;
+
+ BusWrite32(addr, val);
+ DataRegion = addr;
+ DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
+}
+
+void ARMv4::DataWrite32S(u32 addr, u32 val)
+{
+ addr &= ~3;
+
+ BusWrite32(addr, val);
+ DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
+}
+
+
+void ARMv4::AddCycles_C()
+{
+ // code only. this code fetch is sequential.
+ Cycles += NDS.ARM7MemTimings[CodeCycles][(CPSR&0x20)?1:3];
+}
+
+void ARMv4::AddCycles_CI(s32 num)
+{
+ // code+internal. results in a nonseq code fetch.
+ Cycles += NDS.ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2] + num;
+}
+
+void ARMv4::AddCycles_CDI()
+{
+ // LDR/LDM cycles.
+ s32 numC = NDS.ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2];
+ s32 numD = DataCycles;
+
+ if ((DataRegion >> 24) == 0x02) // mainRAM
+ {
+ if (CodeRegion == 0x02)
+ Cycles += numC + numD;
+ else
+ {
+ numC++;
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ }
+ else if (CodeRegion == 0x02)
+ {
+ numD++;
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else
+ {
+ Cycles += numC + numD + 1;
+ }
+}
+
+void ARMv4::AddCycles_CD()
+{
+ // TODO: max gain should be 5c when writing to mainRAM
+ s32 numC = NDS.ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2];
+ s32 numD = DataCycles;
+
+ if ((DataRegion >> 24) == 0x02)
+ {
+ if (CodeRegion == 0x02)
+ Cycles += numC + numD;
+ else
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else if (CodeRegion == 0x02)
+ {
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else
+ {
+ Cycles += numC + numD;
+ }
+}
+
+u8 ARMv5::BusRead8(u32 addr)
+{
+ return NDS.ARM9Read8(addr);
+}
+
+u16 ARMv5::BusRead16(u32 addr)
+{
+ return NDS.ARM9Read16(addr);
+}
+
+u32 ARMv5::BusRead32(u32 addr)
+{
+ return NDS.ARM9Read32(addr);
+}
+
+void ARMv5::BusWrite8(u32 addr, u8 val)
+{
+ NDS.ARM9Write8(addr, val);
+}
+
+void ARMv5::BusWrite16(u32 addr, u16 val)
+{
+ NDS.ARM9Write16(addr, val);
+}
+
+void ARMv5::BusWrite32(u32 addr, u32 val)
+{
+ NDS.ARM9Write32(addr, val);
+}
+
+u8 ARMv4::BusRead8(u32 addr)
+{
+ return NDS.ARM7Read8(addr);
+}
+
+u16 ARMv4::BusRead16(u32 addr)
+{
+ return NDS.ARM7Read16(addr);
+}
+
+u32 ARMv4::BusRead32(u32 addr)
+{
+ return NDS.ARM7Read32(addr);
+}
+
+void ARMv4::BusWrite8(u32 addr, u8 val)
+{
+ NDS.ARM7Write8(addr, val);
+}
+
+void ARMv4::BusWrite16(u32 addr, u16 val)
+{
+ NDS.ARM7Write16(addr, val);
+}
+
+void ARMv4::BusWrite32(u32 addr, u32 val)
+{
+ NDS.ARM7Write32(addr, val);
+}
+}
+
diff --git a/src/ARM.h b/src/ARM.h
index 6cfb6772..1e0b71b8 100644
--- a/src/ARM.h
+++ b/src/ARM.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -20,10 +20,18 @@
#define ARM_H
#include
+#include
#include "types.h"
-#include "NDS.h"
+#include "MemRegion.h"
+#include "MemConstants.h"
+#ifdef GDBSTUB_ENABLED
+#include "debug/GdbStub.h"
+#endif
+
+namespace melonDS
+{
inline u32 ROR(u32 x, u32 n)
{
return (x >> (n&0x1F)) | (x << ((32-n)&0x1F));
@@ -35,13 +43,20 @@ enum
RWFlags_ForceUser = (1<<21),
};
-const u32 ITCMPhysicalSize = 0x8000;
-const u32 DTCMPhysicalSize = 0x4000;
+struct GDBArgs;
+class ARMJIT;
+class GPU;
+class ARMJIT_Memory;
+class NDS;
+class Savestate;
class ARM
+#ifdef GDBSTUB_ENABLED
+ : public Gdb::StubCallbacks
+#endif
{
public:
- ARM(u32 num);
+ ARM(u32 num, bool jit, std::optional gdb, NDS& nds);
virtual ~ARM(); // destroy shit
virtual void Reset();
@@ -59,12 +74,13 @@ public:
Halted = halt;
}
+ void NocashPrint(u32 addr) noexcept;
virtual void Execute() = 0;
#ifdef JIT_ENABLED
virtual void ExecuteJIT() = 0;
#endif
- bool CheckCondition(u32 code)
+ bool CheckCondition(u32 code) const
{
if (code == 0xE) return true;
if (ConditionTable[code] & (1 << (CPSR>>28))) return true;
@@ -93,6 +109,18 @@ public:
if (v) CPSR |= 0x10000000;
}
+ inline bool ModeIs(u32 mode) const
+ {
+ u32 cm = CPSR & 0x1f;
+ mode &= 0x1f;
+
+ if (mode == cm) return true;
+ if (mode == 0x17) return cm >= 0x14 && cm <= 0x17; // abt
+ if (mode == 0x1b) return cm >= 0x18 && cm <= 0x1b; // und
+
+ return false;
+ }
+
void UpdateMode(u32 oldmode, u32 newmode, bool phony = false);
void TriggerIRQ();
@@ -114,6 +142,7 @@ public:
virtual void AddCycles_CDI() = 0;
virtual void AddCycles_CD() = 0;
+ void CheckGdbIncoming();
u32 Num;
@@ -147,75 +176,103 @@ public:
u32 ExceptionBase;
- NDS::MemRegion CodeMem;
+ MemRegion CodeMem;
#ifdef JIT_ENABLED
u32 FastBlockLookupStart, FastBlockLookupSize;
u64* FastBlockLookup;
#endif
- static u32 ConditionTable[16];
+ static const u32 ConditionTable[16];
+#ifdef GDBSTUB_ENABLED
+ Gdb::GdbStub GdbStub;
+#endif
+
+ melonDS::NDS& NDS;
+protected:
+ virtual u8 BusRead8(u32 addr) = 0;
+ virtual u16 BusRead16(u32 addr) = 0;
+ virtual u32 BusRead32(u32 addr) = 0;
+ virtual void BusWrite8(u32 addr, u8 val) = 0;
+ virtual void BusWrite16(u32 addr, u16 val) = 0;
+ virtual void BusWrite32(u32 addr, u32 val) = 0;
+
+#ifdef GDBSTUB_ENABLED
+ bool IsSingleStep;
+ bool BreakReq;
+ bool BreakOnStartup;
+ u16 Port;
+
+public:
+ int GetCPU() const override { return Num ? 7 : 9; }
+
+ u32 ReadReg(Gdb::Register reg) override;
+ void WriteReg(Gdb::Register reg, u32 v) override;
+ u32 ReadMem(u32 addr, int size) override;
+ void WriteMem(u32 addr, int size, u32 v) override;
+
+ void ResetGdb() override;
+ int RemoteCmd(const u8* cmd, size_t len) override;
protected:
- u8 (*BusRead8)(u32 addr);
- u16 (*BusRead16)(u32 addr);
- u32 (*BusRead32)(u32 addr);
- void (*BusWrite8)(u32 addr, u8 val);
- void (*BusWrite16)(u32 addr, u16 val);
- void (*BusWrite32)(u32 addr, u32 val);
+#endif
+
+ void GdbCheckA();
+ void GdbCheckB();
+ void GdbCheckC();
};
class ARMv5 : public ARM
{
public:
- ARMv5();
+ ARMv5(melonDS::NDS& nds, std::optional gdb, bool jit);
~ARMv5();
- void Reset();
+ void Reset() override;
- void DoSavestate(Savestate* file);
+ void DoSavestate(Savestate* file) override;
void UpdateRegionTimings(u32 addrstart, u32 addrend);
- void FillPipeline();
+ void FillPipeline() override;
- void JumpTo(u32 addr, bool restorecpsr = false);
+ void JumpTo(u32 addr, bool restorecpsr = false) override;
void PrefetchAbort();
void DataAbort();
- void Execute();
+ void Execute() override;
#ifdef JIT_ENABLED
- void ExecuteJIT();
+ void ExecuteJIT() override;
#endif
// all code accesses are forced nonseq 32bit
u32 CodeRead32(u32 addr, bool branch);
- void DataRead8(u32 addr, u32* val);
- void DataRead16(u32 addr, u32* val);
- void DataRead32(u32 addr, u32* val);
- void DataRead32S(u32 addr, u32* val);
- void DataWrite8(u32 addr, u8 val);
- void DataWrite16(u32 addr, u16 val);
- void DataWrite32(u32 addr, u32 val);
- void DataWrite32S(u32 addr, u32 val);
+ void DataRead8(u32 addr, u32* val) override;
+ void DataRead16(u32 addr, u32* val) override;
+ void DataRead32(u32 addr, u32* val) override;
+ void DataRead32S(u32 addr, u32* val) override;
+ void DataWrite8(u32 addr, u8 val) override;
+ void DataWrite16(u32 addr, u16 val) override;
+ void DataWrite32(u32 addr, u32 val) override;
+ void DataWrite32S(u32 addr, u32 val) override;
- void AddCycles_C()
+ void AddCycles_C() override
{
// code only. always nonseq 32-bit for ARM9.
s32 numC = (R[15] & 0x2) ? 0 : CodeCycles;
Cycles += numC;
}
- void AddCycles_CI(s32 numI)
+ void AddCycles_CI(s32 numI) override
{
// code+internal
s32 numC = (R[15] & 0x2) ? 0 : CodeCycles;
Cycles += numC + numI;
}
- void AddCycles_CDI()
+ void AddCycles_CDI() override
{
// LDR/LDM cycles. ARM9 seems to skip the internal cycle there.
// TODO: ITCM data fetches shouldn't be parallelized, they say
@@ -228,7 +285,7 @@ public:
// Cycles += numC + numD;
}
- void AddCycles_CD()
+ void AddCycles_CD() override
{
// TODO: ITCM data fetches shouldn't be parallelized, they say
s32 numC = (R[15] & 0x2) ? 0 : CodeCycles;
@@ -240,7 +297,7 @@ public:
// Cycles += numC + numD;
}
- void GetCodeMemRegion(u32 addr, NDS::MemRegion* region);
+ void GetCodeMemRegion(u32 addr, MemRegion* region);
void CP15Reset();
void CP15DoSavestate(Savestate* file);
@@ -258,7 +315,7 @@ public:
void ICacheInvalidateAll();
void CP15Write(u32 id, u32 val);
- u32 CP15Read(u32 id);
+ u32 CP15Read(u32 id) const;
u32 CP15Control;
@@ -301,23 +358,34 @@ public:
u8* CurICacheLine;
- bool (*GetMemRegion)(u32 addr, bool write, NDS::MemRegion* region);
+ bool (*GetMemRegion)(u32 addr, bool write, MemRegion* region);
+
+#ifdef GDBSTUB_ENABLED
+ u32 ReadMem(u32 addr, int size) override;
+ void WriteMem(u32 addr, int size, u32 v) override;
+#endif
+
+protected:
+ u8 BusRead8(u32 addr) override;
+ u16 BusRead16(u32 addr) override;
+ u32 BusRead32(u32 addr) override;
+ void BusWrite8(u32 addr, u8 val) override;
+ void BusWrite16(u32 addr, u16 val) override;
+ void BusWrite32(u32 addr, u32 val) override;
};
class ARMv4 : public ARM
{
public:
- ARMv4();
+ ARMv4(melonDS::NDS& nds, std::optional gdb, bool jit);
- void Reset();
+ void FillPipeline() override;
- void FillPipeline();
+ void JumpTo(u32 addr, bool restorecpsr = false) override;
- void JumpTo(u32 addr, bool restorecpsr = false);
-
- void Execute();
+ void Execute() override;
#ifdef JIT_ENABLED
- void ExecuteJIT();
+ void ExecuteJIT() override;
#endif
u16 CodeRead16(u32 addr)
@@ -330,134 +398,25 @@ public:
return BusRead32(addr);
}
- void DataRead8(u32 addr, u32* val)
- {
- *val = BusRead8(addr);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][0];
- }
-
- void DataRead16(u32 addr, u32* val)
- {
- addr &= ~1;
-
- *val = BusRead16(addr);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][0];
- }
-
- void DataRead32(u32 addr, u32* val)
- {
- addr &= ~3;
-
- *val = BusRead32(addr);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][2];
- }
-
- void DataRead32S(u32 addr, u32* val)
- {
- addr &= ~3;
-
- *val = BusRead32(addr);
- DataCycles += NDS::ARM7MemTimings[addr >> 15][3];
- }
-
- void DataWrite8(u32 addr, u8 val)
- {
- BusWrite8(addr, val);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][0];
- }
-
- void DataWrite16(u32 addr, u16 val)
- {
- addr &= ~1;
-
- BusWrite16(addr, val);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][0];
- }
-
- void DataWrite32(u32 addr, u32 val)
- {
- addr &= ~3;
-
- BusWrite32(addr, val);
- DataRegion = addr;
- DataCycles = NDS::ARM7MemTimings[addr >> 15][2];
- }
-
- void DataWrite32S(u32 addr, u32 val)
- {
- addr &= ~3;
-
- BusWrite32(addr, val);
- DataCycles += NDS::ARM7MemTimings[addr >> 15][3];
- }
-
-
- void AddCycles_C()
- {
- // code only. this code fetch is sequential.
- Cycles += NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?1:3];
- }
-
- void AddCycles_CI(s32 num)
- {
- // code+internal. results in a nonseq code fetch.
- Cycles += NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2] + num;
- }
-
- void AddCycles_CDI()
- {
- // LDR/LDM cycles.
- s32 numC = NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2];
- s32 numD = DataCycles;
-
- if ((DataRegion >> 24) == 0x02) // mainRAM
- {
- if (CodeRegion == 0x02)
- Cycles += numC + numD;
- else
- {
- numC++;
- Cycles += std::max(numC + numD - 3, std::max(numC, numD));
- }
- }
- else if (CodeRegion == 0x02)
- {
- numD++;
- Cycles += std::max(numC + numD - 3, std::max(numC, numD));
- }
- else
- {
- Cycles += numC + numD + 1;
- }
- }
-
- void AddCycles_CD()
- {
- // TODO: max gain should be 5c when writing to mainRAM
- s32 numC = NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2];
- s32 numD = DataCycles;
-
- if ((DataRegion >> 24) == 0x02)
- {
- if (CodeRegion == 0x02)
- Cycles += numC + numD;
- else
- Cycles += std::max(numC + numD - 3, std::max(numC, numD));
- }
- else if (CodeRegion == 0x02)
- {
- Cycles += std::max(numC + numD - 3, std::max(numC, numD));
- }
- else
- {
- Cycles += numC + numD;
- }
- }
+ void DataRead8(u32 addr, u32* val) override;
+ void DataRead16(u32 addr, u32* val) override;
+ void DataRead32(u32 addr, u32* val) override;
+ void DataRead32S(u32 addr, u32* val) override;
+ void DataWrite8(u32 addr, u8 val) override;
+ void DataWrite16(u32 addr, u16 val) override;
+ void DataWrite32(u32 addr, u32 val) override;
+ void DataWrite32S(u32 addr, u32 val) override;
+ void AddCycles_C() override;
+ void AddCycles_CI(s32 num) override;
+ void AddCycles_CDI() override;
+ void AddCycles_CD() override;
+protected:
+ u8 BusRead8(u32 addr) override;
+ u16 BusRead16(u32 addr) override;
+ u32 BusRead32(u32 addr) override;
+ void BusWrite8(u32 addr, u8 val) override;
+ void BusWrite16(u32 addr, u16 val) override;
+ void BusWrite32(u32 addr, u32 val) override;
};
namespace ARMInterpreter
@@ -467,13 +426,5 @@ void A_UNK(ARM* cpu);
void T_UNK(ARM* cpu);
}
-
-namespace NDS
-{
-
-extern ARMv5* ARM9;
-extern ARMv4* ARM7;
-
}
-
#endif // ARM_H
diff --git a/src/ARMInterpreter.cpp b/src/ARMInterpreter.cpp
index 35854d16..ff73e230 100644
--- a/src/ARMInterpreter.cpp
+++ b/src/ARMInterpreter.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -24,16 +24,22 @@
#include "ARMInterpreter_LoadStore.h"
#include "Platform.h"
-using Platform::Log;
-using Platform::LogLevel;
+#ifdef GDBSTUB_ENABLED
+#include "debug/GdbStub.h"
+#endif
-namespace ARMInterpreter
+namespace melonDS::ARMInterpreter
{
+ using Platform::Log;
+ using Platform::LogLevel;
void A_UNK(ARM* cpu)
{
Log(LogLevel::Warn, "undefined ARM%d instruction %08X @ %08X\n", cpu->Num?7:9, cpu->CurInstr, cpu->R[15]-8);
+#ifdef GDBSTUB_ENABLED
+ cpu->GdbStub.Enter(true, Gdb::TgtStatus::FaultInsn, cpu->R[15]-8);
+#endif
//for (int i = 0; i < 16; i++) printf("R%d: %08X\n", i, cpu->R[i]);
//NDS::Halt();
u32 oldcpsr = cpu->CPSR;
@@ -49,6 +55,9 @@ void A_UNK(ARM* cpu)
void T_UNK(ARM* cpu)
{
Log(LogLevel::Warn, "undefined THUMB%d instruction %04X @ %08X\n", cpu->Num?7:9, cpu->CurInstr, cpu->R[15]-4);
+#ifdef GDBSTUB_ENABLED
+ cpu->GdbStub.Enter(true, Gdb::TgtStatus::FaultInsn, cpu->R[15]-4);
+#endif
//NDS::Halt();
u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xBF;
diff --git a/src/ARMInterpreter.h b/src/ARMInterpreter.h
index 9a0fc28e..cff4821a 100644
--- a/src/ARMInterpreter.h
+++ b/src/ARMInterpreter.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -22,6 +22,8 @@
#include "types.h"
#include "ARM.h"
+namespace melonDS
+{
namespace ARMInterpreter
{
@@ -41,4 +43,5 @@ void A_BLX_IMM(ARM* cpu); // I'm a special one look at me
}
+}
#endif // ARMINTERPRETER_H
diff --git a/src/ARMInterpreter_ALU.cpp b/src/ARMInterpreter_ALU.cpp
index 95b6f379..315d59d0 100644
--- a/src/ARMInterpreter_ALU.cpp
+++ b/src/ARMInterpreter_ALU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -18,8 +18,9 @@
#include
#include "ARM.h"
+#include "NDS.h"
-namespace ARMInterpreter
+namespace melonDS::ARMInterpreter
{
inline bool CarryAdd(u32 a, u32 b)
@@ -692,7 +693,7 @@ void A_MOV_REG_LSL_IMM_DBG(ARM* cpu)
// but since they serve no purpose ATTOW, we can skip them
u32 addr = cpu->R[15] + 4; // Skip 2nd ID and flags
// TODO: Pass flags to NocashPrint
- NDS::NocashPrint(cpu->Num, addr);
+ cpu->NDS.NocashPrint(cpu->Num, addr);
}
}
@@ -1561,7 +1562,7 @@ void T_MOV_HIREG(ARM* cpu)
// but since they serve no purpose ATTOW, we can skip them
u32 addr = cpu->R[15] + 4; // Skip 2nd ID and flags
// TODO: Pass flags to NocashPrint
- NDS::NocashPrint(cpu->Num, addr);
+ cpu->NDS.NocashPrint(cpu->Num, addr);
}
}
diff --git a/src/ARMInterpreter_ALU.h b/src/ARMInterpreter_ALU.h
index 8dcc3118..6998b637 100644
--- a/src/ARMInterpreter_ALU.h
+++ b/src/ARMInterpreter_ALU.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,6 +19,8 @@
#ifndef ARMINTERPRETER_ALU_H
#define ARMINTERPRETER_ALU_H
+namespace melonDS
+{
namespace ARMInterpreter
{
@@ -134,4 +136,5 @@ void T_ADD_SP(ARM* cpu);
}
+}
#endif
diff --git a/src/ARMInterpreter_Branch.cpp b/src/ARMInterpreter_Branch.cpp
index ab66395e..015f5682 100644
--- a/src/ARMInterpreter_Branch.cpp
+++ b/src/ARMInterpreter_Branch.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,12 +19,11 @@
#include "ARM.h"
#include "Platform.h"
+namespace melonDS::ARMInterpreter
+{
using Platform::Log;
using Platform::LogLevel;
-namespace ARMInterpreter
-{
-
void A_B(ARM* cpu)
{
diff --git a/src/ARMInterpreter_Branch.h b/src/ARMInterpreter_Branch.h
index 775e8957..51a561c1 100644
--- a/src/ARMInterpreter_Branch.h
+++ b/src/ARMInterpreter_Branch.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,6 +19,8 @@
#ifndef ARMINTERPRETER_BRANCH_H
#define ARMINTERPRETER_BRANCH_H
+namespace melonDS
+{
namespace ARMInterpreter
{
@@ -36,4 +38,5 @@ void T_BL_LONG_2(ARM* cpu);
}
+}
#endif
diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp
index e7b83eb9..91acaacc 100644
--- a/src/ARMInterpreter_LoadStore.cpp
+++ b/src/ARMInterpreter_LoadStore.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -20,7 +20,7 @@
#include "ARM.h"
-namespace ARMInterpreter
+namespace melonDS::ARMInterpreter
{
@@ -62,14 +62,20 @@ namespace ARMInterpreter
#define A_STR \
offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \
- cpu->DataWrite32(offset, cpu->R[(cpu->CurInstr>>12) & 0xF]); \
+ u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \
+ if (((cpu->CurInstr>>12) & 0xF) == 0xF) \
+ storeval += 4; \
+ cpu->DataWrite32(offset, storeval); \
if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \
cpu->AddCycles_CD();
// TODO: user mode (bit21)
#define A_STR_POST \
u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
- cpu->DataWrite32(addr, cpu->R[(cpu->CurInstr>>12) & 0xF]); \
+ u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \
+ if (((cpu->CurInstr>>12) & 0xF) == 0xF) \
+ storeval += 4; \
+ cpu->DataWrite32(addr, storeval); \
cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \
cpu->AddCycles_CD();
diff --git a/src/ARMInterpreter_LoadStore.h b/src/ARMInterpreter_LoadStore.h
index efd4f180..32d6e4d2 100644
--- a/src/ARMInterpreter_LoadStore.h
+++ b/src/ARMInterpreter_LoadStore.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,7 +19,7 @@
#ifndef ARMINTERPRETER_LOADSTORE_H
#define ARMINTERPRETER_LOADSTORE_H
-namespace ARMInterpreter
+namespace melonDS::ARMInterpreter
{
#define A_PROTO_WB_LDRSTR(x) \
diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp
index 77bb50dc..c3fcba26 100644
--- a/src/ARMJIT.cpp
+++ b/src/ARMJIT.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,7 +17,7 @@
*/
#include "ARMJIT.h"
-
+#include "ARMJIT_Memory.h"
#include
#include
#include
@@ -43,138 +43,51 @@
#include "Wifi.h"
#include "NDSCart.h"
#include "Platform.h"
+#include "ARMJIT_x64/ARMJIT_Offsets.h"
+namespace melonDS
+{
using Platform::Log;
using Platform::LogLevel;
-#include "ARMJIT_x64/ARMJIT_Offsets.h"
static_assert(offsetof(ARM, CPSR) == ARM_CPSR_offset, "");
static_assert(offsetof(ARM, Cycles) == ARM_Cycles_offset, "");
static_assert(offsetof(ARM, StopExecution) == ARM_StopExecution_offset, "");
-namespace ARMJIT
-{
#define JIT_DEBUGPRINT(msg, ...)
//#define JIT_DEBUGPRINT(msg, ...) Platform::Log(Platform::LogLevel::Debug, msg, ## __VA_ARGS__)
-Compiler* JITCompiler;
-
-int MaxBlockSize;
-bool LiteralOptimizations;
-bool BranchOptimizations;
-bool FastMemory;
-
-
-std::unordered_map JitBlocks9;
-std::unordered_map JitBlocks7;
-
-std::unordered_map RestoreCandidates;
-
-TinyVector InvalidLiterals;
-
-AddressRange CodeIndexITCM[ITCMPhysicalSize / 512];
-AddressRange CodeIndexMainRAM[NDS::MainRAMMaxSize / 512];
-AddressRange CodeIndexSWRAM[NDS::SharedWRAMSize / 512];
-AddressRange CodeIndexVRAM[0x100000 / 512];
-AddressRange CodeIndexARM9BIOS[sizeof(NDS::ARM9BIOS) / 512];
-AddressRange CodeIndexARM7BIOS[sizeof(NDS::ARM7BIOS) / 512];
-AddressRange CodeIndexARM7WRAM[NDS::ARM7WRAMSize / 512];
-AddressRange CodeIndexARM7WVRAM[0x40000 / 512];
-AddressRange CodeIndexBIOS9DSi[0x10000 / 512];
-AddressRange CodeIndexBIOS7DSi[0x10000 / 512];
-AddressRange CodeIndexNWRAM_A[DSi::NWRAMSize / 512];
-AddressRange CodeIndexNWRAM_B[DSi::NWRAMSize / 512];
-AddressRange CodeIndexNWRAM_C[DSi::NWRAMSize / 512];
-
-u64 FastBlockLookupITCM[ITCMPhysicalSize / 2];
-u64 FastBlockLookupMainRAM[NDS::MainRAMMaxSize / 2];
-u64 FastBlockLookupSWRAM[NDS::SharedWRAMSize / 2];
-u64 FastBlockLookupVRAM[0x100000 / 2];
-u64 FastBlockLookupARM9BIOS[sizeof(NDS::ARM9BIOS) / 2];
-u64 FastBlockLookupARM7BIOS[sizeof(NDS::ARM7BIOS) / 2];
-u64 FastBlockLookupARM7WRAM[NDS::ARM7WRAMSize / 2];
-u64 FastBlockLookupARM7WVRAM[0x40000 / 2];
-u64 FastBlockLookupBIOS9DSi[0x10000 / 2];
-u64 FastBlockLookupBIOS7DSi[0x10000 / 2];
-u64 FastBlockLookupNWRAM_A[DSi::NWRAMSize / 2];
-u64 FastBlockLookupNWRAM_B[DSi::NWRAMSize / 2];
-u64 FastBlockLookupNWRAM_C[DSi::NWRAMSize / 2];
-
const u32 CodeRegionSizes[ARMJIT_Memory::memregions_Count] =
{
0,
ITCMPhysicalSize,
0,
- sizeof(NDS::ARM9BIOS),
- NDS::MainRAMMaxSize,
- NDS::SharedWRAMSize,
+ ARM9BIOSSize,
+ MainRAMMaxSize,
+ SharedWRAMSize,
0,
0x100000,
- sizeof(NDS::ARM7BIOS),
- NDS::ARM7WRAMSize,
+ ARM7BIOSSize,
+ ARM7WRAMSize,
0,
0,
0x40000,
0x10000,
0x10000,
- DSi::NWRAMSize,
- DSi::NWRAMSize,
- DSi::NWRAMSize,
+ NWRAMSize,
+ NWRAMSize,
+ NWRAMSize,
};
-AddressRange* const CodeMemRegions[ARMJIT_Memory::memregions_Count] =
-{
- NULL,
- CodeIndexITCM,
- NULL,
- CodeIndexARM9BIOS,
- CodeIndexMainRAM,
- CodeIndexSWRAM,
- NULL,
- CodeIndexVRAM,
- CodeIndexARM7BIOS,
- CodeIndexARM7WRAM,
- NULL,
- NULL,
- CodeIndexARM7WVRAM,
- CodeIndexBIOS9DSi,
- CodeIndexBIOS7DSi,
- CodeIndexNWRAM_A,
- CodeIndexNWRAM_B,
- CodeIndexNWRAM_C
-};
-
-u64* const FastBlockLookupRegions[ARMJIT_Memory::memregions_Count] =
-{
- NULL,
- FastBlockLookupITCM,
- NULL,
- FastBlockLookupARM9BIOS,
- FastBlockLookupMainRAM,
- FastBlockLookupSWRAM,
- NULL,
- FastBlockLookupVRAM,
- FastBlockLookupARM7BIOS,
- FastBlockLookupARM7WRAM,
- NULL,
- NULL,
- FastBlockLookupARM7WVRAM,
- FastBlockLookupBIOS9DSi,
- FastBlockLookupBIOS7DSi,
- FastBlockLookupNWRAM_A,
- FastBlockLookupNWRAM_B,
- FastBlockLookupNWRAM_C
-};
-
-u32 LocaliseCodeAddress(u32 num, u32 addr)
+u32 ARMJIT::LocaliseCodeAddress(u32 num, u32 addr) const noexcept
{
int region = num == 0
- ? ARMJIT_Memory::ClassifyAddress9(addr)
- : ARMJIT_Memory::ClassifyAddress7(addr);
+ ? Memory.ClassifyAddress9(addr)
+ : Memory.ClassifyAddress7(addr);
if (CodeMemRegions[region])
- return ARMJIT_Memory::LocaliseAddress(region, num, addr);
+ return Memory.LocaliseAddress(region, num, addr);
return 0;
}
@@ -190,11 +103,31 @@ T SlowRead9(u32 addr, ARMv5* cpu)
else if ((addr & cpu->DTCMMask) == cpu->DTCMBase)
val = *(T*)&cpu->DTCM[addr & 0x3FFF];
else if (std::is_same::value)
- val = (ConsoleType == 0 ? NDS::ARM9Read32 : DSi::ARM9Read32)(addr);
+ val = NDS::Current->ARM9Read32(addr);
else if (std::is_same::value)
- val = (ConsoleType == 0 ? NDS::ARM9Read16 : DSi::ARM9Read16)(addr);
+ val = NDS::Current->ARM9Read16(addr);
else
- val = (ConsoleType == 0 ? NDS::ARM9Read8 : DSi::ARM9Read8)(addr);
+ val = NDS::Current->ARM9Read8(addr);
+
+ if (std::is_same::value)
+ return ROR(val, offset << 3);
+ else
+ return val;
+}
+
+template
+T SlowRead7(u32 addr)
+{
+ u32 offset = addr & 0x3;
+ addr &= ~(sizeof(T) - 1);
+
+ T val;
+ if (std::is_same::value)
+ val = NDS::Current->ARM7Read32(addr);
+ else if (std::is_same::value)
+ val = NDS::Current->ARM7Read16(addr);
+ else
+ val = NDS::Current->ARM7Read8(addr);
if (std::is_same::value)
return ROR(val, offset << 3);
@@ -209,7 +142,7 @@ void SlowWrite9(u32 addr, ARMv5* cpu, u32 val)
if (addr < cpu->ITCMSize)
{
- CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
+ cpu->NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
*(T*)&cpu->ITCM[addr & 0x7FFF] = val;
}
else if ((addr & cpu->DTCMMask) == cpu->DTCMBase)
@@ -218,49 +151,29 @@ void SlowWrite9(u32 addr, ARMv5* cpu, u32 val)
}
else if (std::is_same::value)
{
- (ConsoleType == 0 ? NDS::ARM9Write32 : DSi::ARM9Write32)(addr, val);
+ NDS::Current->ARM9Write32(addr, val);
}
else if (std::is_same::value)
{
- (ConsoleType == 0 ? NDS::ARM9Write16 : DSi::ARM9Write16)(addr, val);
+ NDS::Current->ARM9Write16(addr, val);
}
else
{
- (ConsoleType == 0 ? NDS::ARM9Write8 : DSi::ARM9Write8)(addr, val);
+ NDS::Current->ARM9Write8(addr, val);
}
}
-template
-T SlowRead7(u32 addr)
-{
- u32 offset = addr & 0x3;
- addr &= ~(sizeof(T) - 1);
-
- T val;
- if (std::is_same::value)
- val = (ConsoleType == 0 ? NDS::ARM7Read32 : DSi::ARM7Read32)(addr);
- else if (std::is_same::value)
- val = (ConsoleType == 0 ? NDS::ARM7Read16 : DSi::ARM7Read16)(addr);
- else
- val = (ConsoleType == 0 ? NDS::ARM7Read8 : DSi::ARM7Read8)(addr);
-
- if (std::is_same::value)
- return ROR(val, offset << 3);
- else
- return val;
-}
-
template
void SlowWrite7(u32 addr, u32 val)
{
addr &= ~(sizeof(T) - 1);
if (std::is_same::value)
- (ConsoleType == 0 ? NDS::ARM7Write32 : DSi::ARM7Write32)(addr, val);
+ NDS::Current->ARM7Write32(addr, val);
else if (std::is_same::value)
- (ConsoleType == 0 ? NDS::ARM7Write16 : DSi::ARM7Write16)(addr, val);
+ NDS::Current->ARM7Write16(addr, val);
else
- (ConsoleType == 0 ? NDS::ARM7Write8 : DSi::ARM7Write8)(addr, val);
+ NDS::Current->ARM7Write8(addr, val);
}
template
@@ -316,39 +229,18 @@ void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
INSTANTIATE_SLOWMEM(0)
INSTANTIATE_SLOWMEM(1)
-void Init()
-{
- JITCompiler = new Compiler();
-
- ARMJIT_Memory::Init();
-}
-
-void DeInit()
+ARMJIT::~ARMJIT() noexcept
{
JitEnableWrite();
ResetBlockCache();
- ARMJIT_Memory::DeInit();
-
- delete JITCompiler;
- JITCompiler = nullptr;
}
-void Reset()
+void ARMJIT::Reset() noexcept
{
- MaxBlockSize = Platform::GetConfigInt(Platform::JIT_MaxBlockSize);
- LiteralOptimizations = Platform::GetConfigBool(Platform::JIT_LiteralOptimizations);
- BranchOptimizations = Platform::GetConfigBool(Platform::JIT_BranchOptimizations);
- FastMemory = Platform::GetConfigBool(Platform::JIT_FastMemory);
-
- if (MaxBlockSize < 1)
- MaxBlockSize = 1;
- if (MaxBlockSize > 32)
- MaxBlockSize = 32;
-
JitEnableWrite();
ResetBlockCache();
- ARMJIT_Memory::Reset();
+ Memory.Reset();
}
void FloodFillSetFlags(FetchedInstr instrs[], int start, u8 flags)
@@ -575,7 +467,7 @@ InterpreterFunc InterpretTHUMB[ARMInstrInfo::tk_Count] =
};
#undef F
-void RetireJitBlock(JitBlock* block)
+void ARMJIT::RetireJitBlock(JitBlock* block) noexcept
{
auto it = RestoreCandidates.find(block->InstrHash);
if (it != RestoreCandidates.end())
@@ -589,7 +481,57 @@ void RetireJitBlock(JitBlock* block)
}
}
-void CompileBlock(ARM* cpu)
+void ARMJIT::SetJITArgs(JITArgs args) noexcept
+{
+ args.MaxBlockSize = std::clamp(args.MaxBlockSize, 1u, 32u);
+
+ if (MaxBlockSize != args.MaxBlockSize
+ || LiteralOptimizations != args.LiteralOptimizations
+ || BranchOptimizations != args.BranchOptimizations
+ || FastMemory != args.FastMemory)
+ ResetBlockCache();
+
+ MaxBlockSize = args.MaxBlockSize;
+ LiteralOptimizations = args.LiteralOptimizations;
+ BranchOptimizations = args.BranchOptimizations;
+ FastMemory = args.FastMemory;
+}
+
+void ARMJIT::SetMaxBlockSize(int size) noexcept
+{
+ size = std::clamp(size, 1, 32);
+
+ if (size != MaxBlockSize)
+ ResetBlockCache();
+
+ MaxBlockSize = size;
+}
+
+void ARMJIT::SetLiteralOptimizations(bool enabled) noexcept
+{
+ if (LiteralOptimizations != enabled)
+ ResetBlockCache();
+
+ LiteralOptimizations = enabled;
+}
+
+void ARMJIT::SetBranchOptimizations(bool enabled) noexcept
+{
+ if (BranchOptimizations != enabled)
+ ResetBlockCache();
+
+ BranchOptimizations = enabled;
+}
+
+void ARMJIT::SetFastMemory(bool enabled) noexcept
+{
+ if (FastMemory != enabled)
+ ResetBlockCache();
+
+ FastMemory = enabled;
+}
+
+void ARMJIT::CompileBlock(ARM* cpu) noexcept
{
bool thumb = cpu->CPSR & 0x20;
@@ -616,7 +558,7 @@ void CompileBlock(ARM* cpu)
u64* entry = &FastBlockLookupRegions[localAddr >> 27][(localAddr & 0x7FFFFFF) / 2];
*entry = ((u64)blockAddr | cpu->Num) << 32;
- *entry |= JITCompiler->SubEntryOffset(existingBlockIt->second->EntryPoint);
+ *entry |= JITCompiler.SubEntryOffset(existingBlockIt->second->EntryPoint);
return;
}
@@ -717,7 +659,7 @@ void CompileBlock(ARM* cpu)
nextInstr[1] = cpuv4->CodeRead32(r15);
instrs[i].CodeCycles = cpu->CodeCycles;
}
- instrs[i].Info = ARMInstrInfo::Decode(thumb, cpu->Num, instrs[i].Instr);
+ instrs[i].Info = ARMInstrInfo::Decode(thumb, cpu->Num, instrs[i].Instr, LiteralOptimizations);
hasMemoryInstr |= thumb
? (instrs[i].Info.Kind >= ARMInstrInfo::tk_LDR_PCREL && instrs[i].Info.Kind <= ARMInstrInfo::tk_STMIA)
@@ -875,7 +817,7 @@ void CompileBlock(ARM* cpu)
i++;
- bool canCompile = JITCompiler->CanCompile(thumb, instrs[i - 1].Info.Kind);
+ bool canCompile = JITCompiler.CanCompile(thumb, instrs[i - 1].Info.Kind);
bool secondaryFlagReadCond = !canCompile || (instrs[i - 1].BranchFlags & (branch_FollowCondTaken | branch_FollowCondNotTaken));
if (instrs[i - 1].Info.ReadFlags != 0 || secondaryFlagReadCond)
FloodFillSetFlags(instrs, i - 2, !secondaryFlagReadCond ? instrs[i - 1].Info.ReadFlags : 0xF);
@@ -956,7 +898,7 @@ void CompileBlock(ARM* cpu)
FloodFillSetFlags(instrs, i - 1, 0xF);
JitEnableWrite();
- block->EntryPoint = JITCompiler->CompileBlock(cpu, thumb, instrs, i, hasMemoryInstr);
+ block->EntryPoint = JITCompiler.CompileBlock(cpu, thumb, instrs, i, hasMemoryInstr);
JitEnableExecute();
JIT_DEBUGPRINT("block start %p\n", block->EntryPoint);
@@ -977,7 +919,7 @@ void CompileBlock(ARM* cpu)
AddressRange* region = CodeMemRegions[addressRanges[j] >> 27];
if (!PageContainsCode(®ion[(addressRanges[j] & 0x7FFF000) / 512]))
- ARMJIT_Memory::SetCodeProtection(addressRanges[j] >> 27, addressRanges[j] & 0x7FFFFFF, true);
+ Memory.SetCodeProtection(addressRanges[j] >> 27, addressRanges[j] & 0x7FFFFFF, true);
AddressRange* range = ®ion[(addressRanges[j] & 0x7FFFFFF) / 512];
range->Code |= addressMasks[j];
@@ -991,10 +933,10 @@ void CompileBlock(ARM* cpu)
u64* entry = &FastBlockLookupRegions[(localAddr >> 27)][(localAddr & 0x7FFFFFF) / 2];
*entry = ((u64)blockAddr | cpu->Num) << 32;
- *entry |= JITCompiler->SubEntryOffset(block->EntryPoint);
+ *entry |= JITCompiler.SubEntryOffset(block->EntryPoint);
}
-void InvalidateByAddr(u32 localAddr)
+void ARMJIT::InvalidateByAddr(u32 localAddr) noexcept
{
JIT_DEBUGPRINT("invalidating by addr %x\n", localAddr);
@@ -1031,7 +973,7 @@ void InvalidateByAddr(u32 localAddr)
if (range->Blocks.Length == 0
&& !PageContainsCode(®ion[(localAddr & 0x7FFF000) / 512]))
{
- ARMJIT_Memory::SetCodeProtection(localAddr >> 27, localAddr & 0x7FFFFFF, false);
+ Memory.SetCodeProtection(localAddr >> 27, localAddr & 0x7FFFFFF, false);
}
bool literalInvalidation = false;
@@ -1064,7 +1006,7 @@ void InvalidateByAddr(u32 localAddr)
if (otherRange->Blocks.Length == 0)
{
if (!PageContainsCode(&otherRegion[(addr & 0x7FFF000) / 512]))
- ARMJIT_Memory::SetCodeProtection(addr >> 27, addr & 0x7FFFFFF, false);
+ Memory.SetCodeProtection(addr >> 27, addr & 0x7FFFFFF, false);
otherRange->Code = 0;
}
@@ -1088,7 +1030,7 @@ void InvalidateByAddr(u32 localAddr)
}
}
-void CheckAndInvalidateITCM()
+void ARMJIT::CheckAndInvalidateITCM() noexcept
{
for (u32 i = 0; i < ITCMPhysicalSize; i+=512)
{
@@ -1106,7 +1048,7 @@ void CheckAndInvalidateITCM()
}
}
-void CheckAndInvalidateWVRAM(int bank)
+void ARMJIT::CheckAndInvalidateWVRAM(int bank) noexcept
{
u32 start = bank == 1 ? 0x20000 : 0;
for (u32 i = start; i < start+0x20000; i+=512)
@@ -1122,38 +1064,30 @@ void CheckAndInvalidateWVRAM(int bank)
}
}
-template
-void CheckAndInvalidate(u32 addr)
-{
- u32 localAddr = ARMJIT_Memory::LocaliseAddress(region, num, addr);
- if (CodeMemRegions[region][(localAddr & 0x7FFFFFF) / 512].Code & (1 << ((localAddr & 0x1FF) / 16)))
- InvalidateByAddr(localAddr);
-}
-
-JitBlockEntry LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr)
+JitBlockEntry ARMJIT::LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr) noexcept
{
u64* entry = &entries[offset / 2];
if (*entry >> 32 == (addr | num))
- return JITCompiler->AddEntryOffset((u32)*entry);
+ return JITCompiler.AddEntryOffset((u32)*entry);
return NULL;
}
-void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry)
+void ARMJIT::blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry) noexcept
{
u32 localAddr = LocaliseCodeAddress(num, blockAddr);
- assert(JITCompiler->AddEntryOffset((u32)FastBlockLookupRegions[localAddr >> 27][(localAddr & 0x7FFFFFF) / 2]) == entry);
+ assert(JITCompiler.AddEntryOffset((u32)FastBlockLookupRegions[localAddr >> 27][(localAddr & 0x7FFFFFF) / 2]) == entry);
}
-bool SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32& size)
+bool ARMJIT::SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32& size) noexcept
{
// amazingly ignoring the DTCM is the proper behaviour for code fetches
int region = num == 0
- ? ARMJIT_Memory::ClassifyAddress9(blockAddr)
- : ARMJIT_Memory::ClassifyAddress7(blockAddr);
+ ? Memory.ClassifyAddress9(blockAddr)
+ : Memory.ClassifyAddress7(blockAddr);
u32 memoryOffset;
if (FastBlockLookupRegions[region]
- && ARMJIT_Memory::GetMirrorLocation(region, num, blockAddr, memoryOffset, start, size))
+ && Memory.GetMirrorLocation(region, num, blockAddr, memoryOffset, start, size))
{
//printf("setup exec region %d %d %08x %08x %x %x\n", num, region, blockAddr, start, size, memoryOffset);
entry = FastBlockLookupRegions[region] + memoryOffset / 2;
@@ -1162,28 +1096,28 @@ bool SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32&
return false;
}
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_WRAM7>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_VWRAM>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32);
-template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32);
-template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32);
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_WRAM7>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_VWRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32) noexcept;
+template void ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32) noexcept;
-void ResetBlockCache()
+void ARMJIT::ResetBlockCache() noexcept
{
Log(LogLevel::Debug, "Resetting JIT block cache...\n");
// could be replace through a function which only resets
// the permissions but we're too lazy
- ARMJIT_Memory::Reset();
+ Memory.Reset();
InvalidLiterals.Clear();
for (int i = 0; i < ARMJIT_Memory::memregions_Count; i++)
@@ -1221,10 +1155,10 @@ void ResetBlockCache()
JitBlocks9.clear();
JitBlocks7.clear();
- JITCompiler->Reset();
+ JITCompiler.Reset();
}
-void JitEnableWrite()
+void ARMJIT::JitEnableWrite() noexcept
{
#if defined(__APPLE__) && defined(__aarch64__)
if (__builtin_available(macOS 11.0, *))
@@ -1232,7 +1166,7 @@ void JitEnableWrite()
#endif
}
-void JitEnableExecute()
+void ARMJIT::JitEnableExecute() noexcept
{
#if defined(__APPLE__) && defined(__aarch64__)
if (__builtin_available(macOS 11.0, *))
diff --git a/src/ARMJIT.h b/src/ARMJIT.h
index 97c79cd9..7619f234 100644
--- a/src/ARMJIT.h
+++ b/src/ARMJIT.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,49 +19,195 @@
#ifndef ARMJIT_H
#define ARMJIT_H
+#include
+#include
+#include
#include "types.h"
+#include "MemConstants.h"
+#include "Args.h"
+#include "ARMJIT_Memory.h"
-#include "ARM.h"
-#include "ARM_InstrInfo.h"
+#ifdef JIT_ENABLED
+#include "JitBlock.h"
#if defined(__APPLE__) && defined(__aarch64__)
#include
#endif
-namespace ARMJIT
+#include "ARMJIT_Compiler.h"
+
+namespace melonDS
{
+class ARM;
-typedef void (*JitBlockEntry)();
+class JitBlock;
+class ARMJIT
+{
+public:
+ ARMJIT(melonDS::NDS& nds, std::optional jit) noexcept :
+ NDS(nds),
+ Memory(nds),
+ JITCompiler(nds),
+ MaxBlockSize(jit.has_value() ? std::clamp(jit->MaxBlockSize, 1u, 32u) : 32),
+ LiteralOptimizations(jit.has_value() ? jit->LiteralOptimizations : false),
+ BranchOptimizations(jit.has_value() ? jit->BranchOptimizations : false),
+ FastMemory(jit.has_value() ? jit->FastMemory : false)
+ {}
+ ~ARMJIT() noexcept;
+ void InvalidateByAddr(u32) noexcept;
+ void CheckAndInvalidateWVRAM(int) noexcept;
+ void CheckAndInvalidateITCM() noexcept;
+ void Reset() noexcept;
+ void JitEnableWrite() noexcept;
+ void JitEnableExecute() noexcept;
+ void CompileBlock(ARM* cpu) noexcept;
+ void ResetBlockCache() noexcept;
-extern int MaxBlockSize;
-extern bool LiteralOptimizations;
-extern bool BranchOptimizations;
-extern bool FastMemory;
+ template
+ void CheckAndInvalidate(u32 addr) noexcept
+ {
+ u32 localAddr = Memory.LocaliseAddress(region, num, addr);
+ if (CodeMemRegions[region][(localAddr & 0x7FFFFFF) / 512].Code & (1 << ((localAddr & 0x1FF) / 16)))
+ InvalidateByAddr(localAddr);
+ }
+ JitBlockEntry LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr) noexcept;
+ bool SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32& size) noexcept;
+ u32 LocaliseCodeAddress(u32 num, u32 addr) const noexcept;
-void Init();
-void DeInit();
+ ARMJIT_Memory Memory;
+private:
+ int MaxBlockSize {};
+ bool LiteralOptimizations = false;
+ bool BranchOptimizations = false;
+ bool FastMemory = false;
+public:
+ melonDS::NDS& NDS;
+ TinyVector InvalidLiterals {};
+ friend class ARMJIT_Memory;
+ void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry) noexcept;
+ void RetireJitBlock(JitBlock* block) noexcept;
-void Reset();
+ int GetMaxBlockSize() const noexcept { return MaxBlockSize; }
+ bool LiteralOptimizationsEnabled() const noexcept { return LiteralOptimizations; }
+ bool BranchOptimizationsEnabled() const noexcept { return BranchOptimizations; }
+ bool FastMemoryEnabled() const noexcept { return FastMemory; }
-void CheckAndInvalidateITCM();
-void CheckAndInvalidateWVRAM(int bank);
+ void SetJITArgs(JITArgs args) noexcept;
+ void SetMaxBlockSize(int size) noexcept;
+ void SetLiteralOptimizations(bool enabled) noexcept;
+ void SetBranchOptimizations(bool enabled) noexcept;
+ void SetFastMemory(bool enabled) noexcept;
-void InvalidateByAddr(u32 pseudoPhysical);
+ Compiler JITCompiler;
+ std::unordered_map JitBlocks9 {};
+ std::unordered_map JitBlocks7 {};
-template
-void CheckAndInvalidate(u32 addr);
+ std::unordered_map RestoreCandidates {};
-void CompileBlock(ARM* cpu);
-void ResetBlockCache();
+ AddressRange CodeIndexITCM[ITCMPhysicalSize / 512] {};
+ AddressRange CodeIndexMainRAM[MainRAMMaxSize / 512] {};
+ AddressRange CodeIndexSWRAM[SharedWRAMSize / 512] {};
+ AddressRange CodeIndexVRAM[0x100000 / 512] {};
+ AddressRange CodeIndexARM9BIOS[ARM9BIOSSize / 512] {};
+ AddressRange CodeIndexARM7BIOS[ARM7BIOSSize / 512] {};
+ AddressRange CodeIndexARM7WRAM[ARM7WRAMSize / 512] {};
+ AddressRange CodeIndexARM7WVRAM[0x40000 / 512] {};
+ AddressRange CodeIndexBIOS9DSi[0x10000 / 512] {};
+ AddressRange CodeIndexBIOS7DSi[0x10000 / 512] {};
+ AddressRange CodeIndexNWRAM_A[NWRAMSize / 512] {};
+ AddressRange CodeIndexNWRAM_B[NWRAMSize / 512] {};
+ AddressRange CodeIndexNWRAM_C[NWRAMSize / 512] {};
-JitBlockEntry LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr);
-bool SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32& size);
+ u64 FastBlockLookupITCM[ITCMPhysicalSize / 2] {};
+ u64 FastBlockLookupMainRAM[MainRAMMaxSize / 2] {};
+ u64 FastBlockLookupSWRAM[SharedWRAMSize / 2] {};
+ u64 FastBlockLookupVRAM[0x100000 / 2] {};
+ u64 FastBlockLookupARM9BIOS[ARM9BIOSSize / 2] {};
+ u64 FastBlockLookupARM7BIOS[ARM7BIOSSize / 2] {};
+ u64 FastBlockLookupARM7WRAM[ARM7WRAMSize / 2] {};
+ u64 FastBlockLookupARM7WVRAM[0x40000 / 2] {};
+ u64 FastBlockLookupBIOS9DSi[0x10000 / 2] {};
+ u64 FastBlockLookupBIOS7DSi[0x10000 / 2] {};
+ u64 FastBlockLookupNWRAM_A[NWRAMSize / 2] {};
+ u64 FastBlockLookupNWRAM_B[NWRAMSize / 2] {};
+ u64 FastBlockLookupNWRAM_C[NWRAMSize / 2] {};
-void JitEnableWrite();
-void JitEnableExecute();
+ AddressRange* const CodeMemRegions[ARMJIT_Memory::memregions_Count] =
+ {
+ NULL,
+ CodeIndexITCM,
+ NULL,
+ CodeIndexARM9BIOS,
+ CodeIndexMainRAM,
+ CodeIndexSWRAM,
+ NULL,
+ CodeIndexVRAM,
+ CodeIndexARM7BIOS,
+ CodeIndexARM7WRAM,
+ NULL,
+ NULL,
+ CodeIndexARM7WVRAM,
+ CodeIndexBIOS9DSi,
+ CodeIndexBIOS7DSi,
+ CodeIndexNWRAM_A,
+ CodeIndexNWRAM_B,
+ CodeIndexNWRAM_C
+ };
+
+ u64* const FastBlockLookupRegions[ARMJIT_Memory::memregions_Count] =
+ {
+ NULL,
+ FastBlockLookupITCM,
+ NULL,
+ FastBlockLookupARM9BIOS,
+ FastBlockLookupMainRAM,
+ FastBlockLookupSWRAM,
+ NULL,
+ FastBlockLookupVRAM,
+ FastBlockLookupARM7BIOS,
+ FastBlockLookupARM7WRAM,
+ NULL,
+ NULL,
+ FastBlockLookupARM7WVRAM,
+ FastBlockLookupBIOS9DSi,
+ FastBlockLookupBIOS7DSi,
+ FastBlockLookupNWRAM_A,
+ FastBlockLookupNWRAM_B,
+ FastBlockLookupNWRAM_C
+ };
+};
}
-extern "C" void ARM_Dispatch(ARM* cpu, ARMJIT::JitBlockEntry entry);
+// Defined in assembly
+extern "C" void ARM_Dispatch(melonDS::ARM* cpu, melonDS::JitBlockEntry entry);
+#else
+namespace melonDS
+{
+class ARM;
+
+// This version is a stub; the methods all do nothing,
+// but there's still a Memory member.
+class ARMJIT
+{
+public:
+ ARMJIT(melonDS::NDS& nds, std::optional) noexcept : Memory(nds) {}
+ ~ARMJIT() noexcept {}
+ void InvalidateByAddr(u32) noexcept {}
+ void CheckAndInvalidateWVRAM(int) noexcept {}
+ void CheckAndInvalidateITCM() noexcept {}
+ void Reset() noexcept {}
+ void JitEnableWrite() noexcept {}
+ void JitEnableExecute() noexcept {}
+ void CompileBlock(ARM*) noexcept {}
+ void ResetBlockCache() noexcept {}
+ template
+ void CheckAndInvalidate(u32 addr) noexcept {}
+
+ ARMJIT_Memory Memory;
+};
+}
+#endif // JIT_ENABLED
+
+#endif // ARMJIT_H
-#endif
diff --git a/src/ARMJIT_A64/ARMJIT_ALU.cpp b/src/ARMJIT_A64/ARMJIT_ALU.cpp
index 3d52f280..b25bcaa3 100644
--- a/src/ARMJIT_A64/ARMJIT_ALU.cpp
+++ b/src/ARMJIT_A64/ARMJIT_ALU.cpp
@@ -20,7 +20,7 @@
using namespace Arm64Gen;
-namespace ARMJIT
+namespace melonDS
{
void Compiler::Comp_RegShiftReg(int op, bool S, Op2& op2, ARM64Reg rs)
@@ -480,7 +480,7 @@ void Compiler::A_Comp_GetOp2(bool S, Op2& op2)
Comp_AddCycles_C();
u32 shift = (CurInstr.Instr >> 7) & 0x1E;
- u32 imm = ::ROR(CurInstr.Instr & 0xFF, shift);
+ u32 imm = melonDS::ROR(CurInstr.Instr & 0xFF, shift);
if (S && shift && (CurInstr.SetFlags & 0x2))
{
diff --git a/src/ARMJIT_A64/ARMJIT_Branch.cpp b/src/ARMJIT_A64/ARMJIT_Branch.cpp
index c7b6e98e..92717e91 100644
--- a/src/ARMJIT_A64/ARMJIT_Branch.cpp
+++ b/src/ARMJIT_A64/ARMJIT_Branch.cpp
@@ -17,13 +17,14 @@
*/
#include "ARMJIT_Compiler.h"
+#include "../NDS.h"
using namespace Arm64Gen;
// hack
const int kCodeCacheTiming = 3;
-namespace ARMJIT
+namespace melonDS
{
template
@@ -132,7 +133,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
u32 compileTimePC = CurCPU->R[15];
CurCPU->R[15] = newPC;
- cycles += NDS::ARM7MemTimings[codeCycles][0] + NDS::ARM7MemTimings[codeCycles][1];
+ cycles += NDS.ARM7MemTimings[codeCycles][0] + NDS.ARM7MemTimings[codeCycles][1];
CurCPU->R[15] = compileTimePC;
}
@@ -144,7 +145,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
u32 compileTimePC = CurCPU->R[15];
CurCPU->R[15] = newPC;
- cycles += NDS::ARM7MemTimings[codeCycles][2] + NDS::ARM7MemTimings[codeCycles][3];
+ cycles += NDS.ARM7MemTimings[codeCycles][2] + NDS.ARM7MemTimings[codeCycles][3];
CurCPU->R[15] = compileTimePC;
}
@@ -235,7 +236,7 @@ void* Compiler::Gen_JumpTo7(int kind)
LSR(W1, W0, 15);
STR(INDEX_UNSIGNED, W1, RCPU, offsetof(ARM, CodeCycles));
- MOVP2R(X2, NDS::ARM7MemTimings);
+ MOVP2R(X2, NDS.ARM7MemTimings);
LDR(W3, X2, ArithOption(W1, true));
FixupBranch switchToThumb;
diff --git a/src/ARMJIT_A64/ARMJIT_Compiler.cpp b/src/ARMJIT_A64/ARMJIT_Compiler.cpp
index 55bca846..7981ed67 100644
--- a/src/ARMJIT_A64/ARMJIT_Compiler.cpp
+++ b/src/ARMJIT_A64/ARMJIT_Compiler.cpp
@@ -20,6 +20,8 @@
#include "../ARMJIT_Internal.h"
#include "../ARMInterpreter.h"
+#include "../ARMJIT.h"
+#include "../NDS.h"
#if defined(__SWITCH__)
#include
@@ -38,7 +40,7 @@ using namespace Arm64Gen;
extern "C" void ARM_Ret();
-namespace ARMJIT
+namespace melonDS
{
/*
@@ -105,7 +107,7 @@ void Compiler::A_Comp_MSR()
if (CurInstr.Instr & (1 << 25))
{
val = W0;
- MOVI2R(val, ::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)));
+ MOVI2R(val, melonDS::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)));
}
else
{
@@ -219,7 +221,7 @@ void Compiler::PopRegs(bool saveHiRegs, bool saveRegsToBeChanged)
}
}
-Compiler::Compiler()
+Compiler::Compiler(melonDS::NDS& nds) : Arm64Gen::ARM64XEmitter(), NDS(nds)
{
#ifdef __SWITCH__
JitRWBase = aligned_alloc(0x1000, JitMemSize);
@@ -274,7 +276,7 @@ Compiler::Compiler()
VirtualProtect(pageAligned, alignedSize, PAGE_EXECUTE_READWRITE, &dummy);
#elif defined(__APPLE__)
pageAligned = (u8*)mmap(NULL, 1024*1024*16, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT,-1, 0);
- JitEnableWrite();
+ nds.JIT.JitEnableWrite();
#else
mprotect(pageAligned, alignedSize, PROT_EXEC | PROT_READ | PROT_WRITE);
#endif
@@ -704,12 +706,12 @@ JitBlockEntry Compiler::CompileBlock(ARM* cpu, bool thumb, FetchedInstr instrs[]
if (JitMemMainSize - GetCodeOffset() < 1024 * 16)
{
Log(LogLevel::Debug, "JIT near memory full, resetting...\n");
- ResetBlockCache();
+ NDS.JIT.ResetBlockCache();
}
if ((JitMemMainSize + JitMemSecondarySize) - OtherCodeRegion < 1024 * 8)
{
Log(LogLevel::Debug, "JIT far memory full, resetting...\n");
- ResetBlockCache();
+ NDS.JIT.ResetBlockCache();
}
JitBlockEntry res = (JitBlockEntry)GetRXPtr();
@@ -722,7 +724,7 @@ JitBlockEntry Compiler::CompileBlock(ARM* cpu, bool thumb, FetchedInstr instrs[]
CPSRDirty = false;
if (hasMemInstr)
- MOVP2R(RMemBase, Num == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
+ MOVP2R(RMemBase, Num == 0 ? NDS.JIT.Memory.FastMem9Start : NDS.JIT.Memory.FastMem7Start);
for (int i = 0; i < instrsCount; i++)
{
@@ -870,7 +872,7 @@ void Compiler::Reset()
void Compiler::Comp_AddCycles_C(bool forceNonConstant)
{
s32 cycles = Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 1 : 3]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 1 : 3]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles);
if (forceNonConstant)
@@ -884,7 +886,7 @@ void Compiler::Comp_AddCycles_CI(u32 numI)
IrregularCycles = true;
s32 cycles = (Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles)) + numI;
if (Thumb || CurInstr.Cond() == 0xE)
@@ -898,7 +900,7 @@ void Compiler::Comp_AddCycles_CI(u32 c, ARM64Reg numI, ArithOption shift)
IrregularCycles = true;
s32 cycles = (Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles)) + c;
ADD(RCycles, RCycles, cycles);
@@ -918,7 +920,7 @@ void Compiler::Comp_AddCycles_CDI()
s32 cycles;
- s32 numC = NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
+ s32 numC = NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
s32 numD = CurInstr.DataCycles;
if ((CurInstr.DataRegion >> 24) == 0x02) // mainRAM
@@ -963,7 +965,7 @@ void Compiler::Comp_AddCycles_CD()
}
else
{
- s32 numC = NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
+ s32 numC = NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
s32 numD = CurInstr.DataCycles;
if ((CurInstr.DataRegion >> 24) == 0x02)
diff --git a/src/ARMJIT_A64/ARMJIT_Compiler.h b/src/ARMJIT_A64/ARMJIT_Compiler.h
index 5045cb5f..2b0048a9 100644
--- a/src/ARMJIT_A64/ARMJIT_Compiler.h
+++ b/src/ARMJIT_A64/ARMJIT_Compiler.h
@@ -19,8 +19,9 @@
#ifndef ARMJIT_A64_COMPILER_H
#define ARMJIT_A64_COMPILER_H
+#if defined(JIT_ENABLED) && defined(__aarch64__)
+
#include "../ARM.h"
-#include "../ARMJIT.h"
#include "../dolphin/Arm64Emitter.h"
@@ -29,9 +30,9 @@
#include
-namespace ARMJIT
+namespace melonDS
{
-
+class ARMJIT;
const Arm64Gen::ARM64Reg RMemBase = Arm64Gen::X26;
const Arm64Gen::ARM64Reg RCPSR = Arm64Gen::W27;
const Arm64Gen::ARM64Reg RCycles = Arm64Gen::W28;
@@ -68,7 +69,7 @@ struct Op2
bool IsSimpleReg()
{ return !IsImm && !Reg.ShiftAmount && Reg.ShiftType == Arm64Gen::ST_LSL; }
bool ImmFits12Bit()
- { return IsImm && (Imm & 0xFFF == Imm); }
+ { return IsImm && ((Imm & 0xFFF) == Imm); }
bool IsZero()
{ return IsImm && !Imm; }
@@ -97,8 +98,8 @@ class Compiler : public Arm64Gen::ARM64XEmitter
public:
typedef void (Compiler::*CompileFunc)();
- Compiler();
- ~Compiler();
+ explicit Compiler(melonDS::NDS& nds);
+ ~Compiler() override;
void PushRegs(bool saveHiRegs, bool saveRegsToBeChanged, bool allowUnload = true);
void PopRegs(bool saveHiRegs, bool saveRegsToBeChanged);
@@ -113,7 +114,7 @@ public:
bool CanCompile(bool thumb, u16 kind);
- bool FlagsNZNeeded()
+ bool FlagsNZNeeded() const
{
return CurInstr.SetFlags & 0xC;
}
@@ -233,7 +234,7 @@ public:
return (u8*)entry - GetRXBase();
}
- bool IsJITFault(u8* pc);
+ bool IsJITFault(const u8* pc);
u8* RewriteMemAccess(u8* pc);
void SwapCodeRegion()
@@ -243,6 +244,7 @@ public:
OtherCodeRegion = offset;
}
+ melonDS::NDS& NDS;
ptrdiff_t OtherCodeRegion;
bool Exit;
@@ -287,3 +289,5 @@ public:
}
#endif
+
+#endif
diff --git a/src/ARMJIT_A64/ARMJIT_Linkage.S b/src/ARMJIT_A64/ARMJIT_Linkage.S
index c1ecd7c8..b73905bd 100644
--- a/src/ARMJIT_A64/ARMJIT_Linkage.S
+++ b/src/ARMJIT_A64/ARMJIT_Linkage.S
@@ -94,3 +94,8 @@ ARM_RestoreContext:
mov sp, x17
br x18
+
+#if !defined(__APPLE__) && !defined(__WIN32__)
+.section .note.GNU-stack,"",@progbits
+#endif
+
diff --git a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
index ee8aabe2..e108b7b4 100644
--- a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
+++ b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
@@ -21,13 +21,14 @@
#include "../ARMJIT.h"
#include "../ARMJIT_Memory.h"
+#include "../NDS.h"
using namespace Arm64Gen;
-namespace ARMJIT
+namespace melonDS
{
-bool Compiler::IsJITFault(u8* pc)
+bool Compiler::IsJITFault(const u8* pc)
{
return (u64)pc >= (u64)GetRXBase() && (u64)pc - (u64)GetRXBase() < (JitMemMainSize + JitMemSecondarySize);
}
@@ -62,9 +63,9 @@ u8* Compiler::RewriteMemAccess(u8* pc)
bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
{
- u32 localAddr = LocaliseCodeAddress(Num, addr);
+ u32 localAddr = NDS.JIT.LocaliseCodeAddress(Num, addr);
- int invalidLiteralIdx = InvalidLiterals.Find(localAddr);
+ int invalidLiteralIdx = NDS.JIT.InvalidLiterals.Find(localAddr);
if (invalidLiteralIdx != -1)
{
return false;
@@ -79,7 +80,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
- val = ::ROR(val, (addr & 0x3) << 3);
+ val = melonDS::ROR(val, (addr & 0x3) << 3);
}
else if (size == 16)
{
@@ -111,7 +112,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
if (size == 16)
addressMask = ~1;
- if (ARMJIT::LiteralOptimizations && rn == 15 && rd != 15 && offset.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback)))
+ if (NDS.JIT.LiteralOptimizationsEnabled() && rn == 15 && rd != 15 && offset.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback)))
{
u32 addr = R15 + offset.Imm * ((flags & memop_SubtractOffset) ? -1 : 1);
@@ -146,7 +147,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
MOV(W0, rnMapped);
}
- bool addrIsStatic = ARMJIT::LiteralOptimizations
+ bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled()
&& RegCache.IsLiteral(rn) && offset.IsImm && !(flags & (memop_Writeback|memop_Post));
u32 staticAddress;
if (addrIsStatic)
@@ -185,18 +186,18 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
MOV(rnMapped, W0);
u32 expectedTarget = Num == 0
- ? ARMJIT_Memory::ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion)
- : ARMJIT_Memory::ClassifyAddress7(addrIsStatic ? staticAddress : CurInstr.DataRegion);
+ ? NDS.JIT.Memory.ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion)
+ : NDS.JIT.Memory.ClassifyAddress7(addrIsStatic ? staticAddress : CurInstr.DataRegion);
- if (ARMJIT::FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || ARMJIT_Memory::IsFastmemCompatible(expectedTarget)))
+ if (NDS.JIT.FastMemoryEnabled() && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget)))
{
ptrdiff_t memopStart = GetCodeOffset();
LoadStorePatch patch;
assert((rdMapped >= W8 && rdMapped <= W15) || (rdMapped >= W19 && rdMapped <= W25) || rdMapped == W4);
patch.PatchFunc = flags & memop_Store
- ? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped]
- : PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped];
+ ? PatchedStoreFuncs[NDS.ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped]
+ : PatchedLoadFuncs[NDS.ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped];
// take a chance at fastmem
if (size > 8)
@@ -225,7 +226,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
{
void* func = NULL;
if (addrIsStatic)
- func = ARMJIT_Memory::GetFuncForAddr(CurCPU, staticAddress, flags & memop_Store, size);
+ func = NDS.JIT.Memory.GetFuncForAddr(CurCPU, staticAddress, flags & memop_Store, size);
PushRegs(false, false);
@@ -263,7 +264,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
if (flags & memop_Store)
{
MOV(W2, rdMapped);
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: QuickCallFunction(X3, SlowWrite9); break;
case 33: QuickCallFunction(X3, SlowWrite9); break;
@@ -275,7 +276,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
}
else
{
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: QuickCallFunction(X3, SlowRead9); break;
case 33: QuickCallFunction(X3, SlowRead9); break;
@@ -291,7 +292,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
if (flags & memop_Store)
{
MOV(W1, rdMapped);
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: QuickCallFunction(X3, SlowWrite7); break;
case 33: QuickCallFunction(X3, SlowWrite7); break;
@@ -303,7 +304,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
}
else
{
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: QuickCallFunction(X3, SlowRead7); break;
case 33: QuickCallFunction(X3, SlowRead7); break;
@@ -452,7 +453,7 @@ void Compiler::T_Comp_LoadPCRel()
u32 offset = ((CurInstr.Instr & 0xFF) << 2);
u32 addr = (R15 & ~0x2) + offset;
- if (!ARMJIT::LiteralOptimizations || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr))
+ if (!NDS.JIT.LiteralOptimizationsEnabled() || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr))
Comp_MemAccess(CurInstr.T_Reg(8), 15, Op2(offset), 32, 0);
}
@@ -494,11 +495,11 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
Comp_AddCycles_CDI();
int expectedTarget = Num == 0
- ? ARMJIT_Memory::ClassifyAddress9(CurInstr.DataRegion)
- : ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
+ ? NDS.JIT.Memory.ClassifyAddress9(CurInstr.DataRegion)
+ : NDS.JIT.Memory.ClassifyAddress7(CurInstr.DataRegion);
- bool compileFastPath = ARMJIT::FastMemory
- && store && !usermode && (CurInstr.Cond() < 0xE || ARMJIT_Memory::IsFastmemCompatible(expectedTarget));
+ bool compileFastPath = NDS.JIT.FastMemoryEnabled()
+ && store && !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget));
{
s32 offset = decrement
@@ -680,7 +681,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
if (Num == 0)
{
MOV(X3, RCPU);
- switch ((u32)store * 2 | NDS::ConsoleType)
+ switch ((u32)store * 2 | NDS.ConsoleType)
{
case 0: QuickCallFunction(X4, SlowBlockTransfer9); break;
case 1: QuickCallFunction(X4, SlowBlockTransfer9); break;
@@ -690,7 +691,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
}
else
{
- switch ((u32)store * 2 | NDS::ConsoleType)
+ switch ((u32)store * 2 | NDS.ConsoleType)
{
case 0: QuickCallFunction(X4, SlowBlockTransfer7); break;
case 1: QuickCallFunction(X4, SlowBlockTransfer7); break;
diff --git a/src/ARMJIT_Compiler.h b/src/ARMJIT_Compiler.h
index c5348f48..ff4f8ff7 100644
--- a/src/ARMJIT_Compiler.h
+++ b/src/ARMJIT_Compiler.h
@@ -19,6 +19,8 @@
#ifndef ARMJIT_COMPILER_H
#define ARMJIT_COMPILER_H
+#ifdef JIT_ENABLED
+
#if defined(__x86_64__)
#include "ARMJIT_x64/ARMJIT_Compiler.h"
#elif defined(__aarch64__)
@@ -27,9 +29,6 @@
#error "The current target platform doesn't have a JIT backend"
#endif
-namespace ARMJIT
-{
-extern Compiler* JITCompiler;
-}
+#endif
#endif
diff --git a/src/ARMJIT_Internal.h b/src/ARMJIT_Internal.h
index fb803072..8429bade 100644
--- a/src/ARMJIT_Internal.h
+++ b/src/ARMJIT_Internal.h
@@ -24,13 +24,17 @@
#include
#include
-#include "ARMJIT.h"
-#include "ARMJIT_Memory.h"
+#include "ARM_InstrInfo.h"
+#include "JitBlock.h"
+#include "TinyVector.h"
+
+namespace melonDS
+{
+class ARM;
+class ARMv5;
// here lands everything which doesn't fit into ARMJIT.h
// where it would be included by pretty much everything
-namespace ARMJIT
-{
enum
{
@@ -69,139 +73,6 @@ struct FetchedInstr
ARMInstrInfo::Info Info;
};
-/*
- TinyVector
- - because reinventing the wheel is the best!
-
- - meant to be used very often, with not so many elements
- max 1 << 16 elements
- - doesn't allocate while no elements are inserted
- - not stl confirmant of course
- - probably only works with POD types
- - remove operations don't preserve order, but O(1)!
-*/
-template
-struct __attribute__((packed)) TinyVector
-{
- T* Data = NULL;
- u16 Capacity = 0;
- u16 Length = 0;
-
- ~TinyVector()
- {
- delete[] Data;
- }
-
- void MakeCapacity(u32 capacity)
- {
- assert(capacity <= UINT16_MAX);
- assert(capacity > Capacity);
- T* newMem = new T[capacity];
- if (Data != NULL)
- memcpy(newMem, Data, sizeof(T) * Length);
-
- T* oldData = Data;
- Data = newMem;
- if (oldData != NULL)
- delete[] oldData;
-
- Capacity = capacity;
- }
-
- void SetLength(u16 length)
- {
- if (Capacity < length)
- MakeCapacity(length);
-
- Length = length;
- }
-
- void Clear()
- {
- Length = 0;
- }
-
- void Add(T element)
- {
- assert(Length + 1 <= UINT16_MAX);
- if (Length + 1 > Capacity)
- MakeCapacity(((Capacity + 4) * 3) / 2);
-
- Data[Length++] = element;
- }
-
- void Remove(int index)
- {
- assert(Length > 0);
- assert(index >= 0 && index < Length);
-
- Length--;
- Data[index] = Data[Length];
- /*for (int i = index; i < Length; i++)
- Data[i] = Data[i + 1];*/
- }
-
- int Find(T needle)
- {
- for (int i = 0; i < Length; i++)
- {
- if (Data[i] == needle)
- return i;
- }
- return -1;
- }
-
- bool RemoveByValue(T needle)
- {
- for (int i = 0; i < Length; i++)
- {
- if (Data[i] == needle)
- {
- Remove(i);
- return true;
- }
- }
- return false;
- }
-
- T& operator[](int index)
- {
- assert(index >= 0 && index < Length);
- return Data[index];
- }
-};
-
-class JitBlock
-{
-public:
- JitBlock(u32 num, u32 literalHash, u32 numAddresses, u32 numLiterals)
- {
- Num = num;
- NumAddresses = numAddresses;
- NumLiterals = numLiterals;
- Data.SetLength(numAddresses * 2 + numLiterals);
- }
-
- u32 StartAddr;
- u32 StartAddrLocal;
- u32 InstrHash, LiteralHash;
- u8 Num;
- u16 NumAddresses;
- u16 NumLiterals;
-
- JitBlockEntry EntryPoint;
-
- u32* AddressRanges()
- { return &Data[0]; }
- u32* AddressMasks()
- { return &Data[NumAddresses]; }
- u32* Literals()
- { return &Data[NumAddresses * 2]; }
-
-private:
- TinyVector Data;
-};
-
// size should be 16 bytes because I'm to lazy to use mul and whatnot
struct __attribute__((packed)) AddressRange
{
@@ -214,11 +85,7 @@ typedef void (*InterpreterFunc)(ARM* cpu);
extern InterpreterFunc InterpretARM[];
extern InterpreterFunc InterpretTHUMB[];
-extern TinyVector InvalidLiterals;
-
-extern AddressRange* const CodeMemRegions[ARMJIT_Memory::memregions_Count];
-
-inline bool PageContainsCode(AddressRange* range)
+inline bool PageContainsCode(const AddressRange* range)
{
for (int i = 0; i < 8; i++)
{
@@ -228,11 +95,6 @@ inline bool PageContainsCode(AddressRange* range)
return false;
}
-u32 LocaliseCodeAddress(u32 num, u32 addr);
-
-template
-void LinkBlock(ARM* cpu, u32 codeOffset);
-
template T SlowRead9(u32 addr, ARMv5* cpu);
template void SlowWrite9(u32 addr, ARMv5* cpu, u32 val);
template T SlowRead7(u32 addr);
diff --git a/src/ARMJIT_Memory.cpp b/src/ARMJIT_Memory.cpp
index 25652cb8..c8969aee 100644
--- a/src/ARMJIT_Memory.cpp
+++ b/src/ARMJIT_Memory.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -34,6 +34,7 @@
#include
#endif
+#include "ARMJIT.h"
#include "ARMJIT_Memory.h"
#include "ARMJIT_Internal.h"
@@ -48,9 +49,6 @@
#include
-using Platform::Log;
-using Platform::LogLevel;
-
/*
We're handling fastmem here.
@@ -72,17 +70,6 @@ using Platform::LogLevel;
*/
-namespace ARMJIT_Memory
-{
-struct FaultDescription
-{
- u32 EmulatedFaultAddr;
- u8* FaultPC;
-};
-
-bool FaultHandler(FaultDescription& faultDesc);
-}
-
// Yes I know this looks messy, but better here than somewhere else in the code
#if defined(__x86_64__)
#if defined(_WIN32)
@@ -110,9 +97,14 @@ bool FaultHandler(FaultDescription& faultDesc);
#endif
#endif
+namespace melonDS
+{
+
+using Platform::Log;
+using Platform::LogLevel;
+
#if defined(__ANDROID__)
#define ASHMEM_DEVICE "/dev/ashmem"
-Platform::DynamicLibrary* Libandroid = nullptr;
#endif
#if defined(__SWITCH__)
@@ -146,7 +138,7 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
integerRegisters[31] = ctx->sp.x;
integerRegisters[32] = ctx->pc.x;
- if (ARMJIT_Memory::FaultHandler(desc))
+ if (Melon::FaultHandler(desc))
{
integerRegisters[32] = (u64)desc.FaultPC;
@@ -160,19 +152,19 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
#elif defined(_WIN32)
-static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
+LONG ARMJIT_Memory::ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
{
if (exceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
{
return EXCEPTION_CONTINUE_SEARCH;
}
- ARMJIT_Memory::FaultDescription desc;
- u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
+ u8* curArea = (u8*)(NDS::Current->CurCPU == 0 ? NDS::Current->JIT.Memory.FastMem9Start : NDS::Current->JIT.Memory.FastMem7Start);
+ FaultDescription desc {};
desc.EmulatedFaultAddr = (u8*)exceptionInfo->ExceptionRecord->ExceptionInformation[1] - curArea;
desc.FaultPC = (u8*)exceptionInfo->ContextRecord->CONTEXT_PC;
- if (ARMJIT_Memory::FaultHandler(desc))
+ if (FaultHandler(desc, *NDS::Current))
{
exceptionInfo->ContextRecord->CONTEXT_PC = (u64)desc.FaultPC;
return EXCEPTION_CONTINUE_EXECUTION;
@@ -186,7 +178,7 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
static struct sigaction OldSaSegv;
static struct sigaction OldSaBus;
-static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
+void ARMJIT_Memory::SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
{
if (sig != SIGSEGV && sig != SIGBUS)
{
@@ -201,13 +193,13 @@ static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
ucontext_t* context = (ucontext_t*)rawContext;
- ARMJIT_Memory::FaultDescription desc;
- u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
+ FaultDescription desc {};
+ u8* curArea = (u8*)(NDS::Current->CurCPU == 0 ? NDS::Current->JIT.Memory.FastMem9Start : NDS::Current->JIT.Memory.FastMem7Start);
desc.EmulatedFaultAddr = (u8*)info->si_addr - curArea;
desc.FaultPC = (u8*)context->CONTEXT_PC;
- if (ARMJIT_Memory::FaultHandler(desc))
+ if (FaultHandler(desc, *NDS::Current))
{
context->CONTEXT_PC = (u64)desc.FaultPC;
return;
@@ -239,33 +231,7 @@ static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
#endif
-namespace ARMJIT_Memory
-{
-
-void* FastMem9Start, *FastMem7Start;
-
-#ifdef _WIN32
-inline u32 RoundUp(u32 size)
-{
- return (size + 0xFFFF) & ~0xFFFF;
-}
-#else
-inline u32 RoundUp(u32 size)
-{
- return size;
-}
-#endif
-
-const u32 MemBlockMainRAMOffset = 0;
-const u32 MemBlockSWRAMOffset = RoundUp(NDS::MainRAMMaxSize);
-const u32 MemBlockARM7WRAMOffset = MemBlockSWRAMOffset + RoundUp(NDS::SharedWRAMSize);
-const u32 MemBlockDTCMOffset = MemBlockARM7WRAMOffset + RoundUp(NDS::ARM7WRAMSize);
-const u32 MemBlockNWRAM_AOffset = MemBlockDTCMOffset + RoundUp(DTCMPhysicalSize);
-const u32 MemBlockNWRAM_BOffset = MemBlockNWRAM_AOffset + RoundUp(DSi::NWRAMSize);
-const u32 MemBlockNWRAM_COffset = MemBlockNWRAM_BOffset + RoundUp(DSi::NWRAMSize);
-const u32 MemoryTotalSize = MemBlockNWRAM_COffset + RoundUp(DSi::NWRAMSize);
-
-const u32 OffsetsPerRegion[memregions_Count] =
+const u32 OffsetsPerRegion[ARMJIT_Memory::memregions_Count] =
{
UINT32_MAX,
UINT32_MAX,
@@ -295,23 +261,9 @@ enum
memstate_MappedProtected,
};
-u8 MappingStatus9[1 << (32-12)];
-u8 MappingStatus7[1 << (32-12)];
-#if defined(__SWITCH__)
-VirtmemReservation* FastMem9Reservation, *FastMem7Reservation;
-u8* MemoryBase;
-u8* MemoryBaseCodeMem;
-#elif defined(_WIN32)
-u8* MemoryBase;
-HANDLE MemoryFile;
-LPVOID ExceptionHandlerHandle;
-#else
-u8* MemoryBase;
-int MemoryFile = -1;
-#endif
-bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size)
+bool ARMJIT_Memory::MapIntoRange(u32 addr, u32 num, u32 offset, u32 size) noexcept
{
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
#ifdef __SWITCH__
@@ -326,7 +278,7 @@ bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size)
#endif
}
-bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size)
+bool ARMJIT_Memory::UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size) noexcept
{
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
#ifdef __SWITCH__
@@ -341,7 +293,7 @@ bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size)
}
#ifndef __SWITCH__
-void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
+void ARMJIT_Memory::SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection) noexcept
{
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
#if defined(_WIN32)
@@ -367,82 +319,74 @@ void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
}
#endif
-struct Mapping
+void ARMJIT_Memory::Mapping::Unmap(int region, melonDS::NDS& nds) noexcept
{
- u32 Addr;
- u32 Size, LocalOffset;
- u32 Num;
-
- void Unmap(int region)
+ u32 dtcmStart = nds.ARM9.DTCMBase;
+ u32 dtcmSize = ~nds.ARM9.DTCMMask + 1;
+ bool skipDTCM = Num == 0 && region != memregion_DTCM;
+ u8* statuses = Num == 0 ? nds.JIT.Memory.MappingStatus9 : nds.JIT.Memory.MappingStatus7;
+ u32 offset = 0;
+ while (offset < Size)
{
- u32 dtcmStart = NDS::ARM9->DTCMBase;
- u32 dtcmSize = ~NDS::ARM9->DTCMMask + 1;
- bool skipDTCM = Num == 0 && region != memregion_DTCM;
- u8* statuses = Num == 0 ? MappingStatus9 : MappingStatus7;
- u32 offset = 0;
- while (offset < Size)
+ if (skipDTCM && Addr + offset == dtcmStart)
{
- if (skipDTCM && Addr + offset == dtcmStart)
+ offset += dtcmSize;
+ }
+ else
+ {
+ u32 segmentOffset = offset;
+ u8 status = statuses[(Addr + offset) >> 12];
+ while (statuses[(Addr + offset) >> 12] == status
+ && offset < Size
+ && (!skipDTCM || Addr + offset != dtcmStart))
{
- offset += dtcmSize;
+ assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
+ statuses[(Addr + offset) >> 12] = memstate_Unmapped;
+ offset += 0x1000;
}
- else
- {
- u32 segmentOffset = offset;
- u8 status = statuses[(Addr + offset) >> 12];
- while (statuses[(Addr + offset) >> 12] == status
- && offset < Size
- && (!skipDTCM || Addr + offset != dtcmStart))
- {
- assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
- statuses[(Addr + offset) >> 12] = memstate_Unmapped;
- offset += 0x1000;
- }
#ifdef __SWITCH__
- if (status == memstate_MappedRW)
- {
- u32 segmentSize = offset - segmentOffset;
- Log(LogLevel::Debug, "unmapping %x %x %x %x\n", Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
- bool success = UnmapFromRange(Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
- assert(success);
- }
-#endif
+ if (status == memstate_MappedRW)
+ {
+ u32 segmentSize = offset - segmentOffset;
+ Log(LogLevel::Debug, "unmapping %x %x %x %x\n", Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
+ bool success = memory.UnmapFromRange(Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
+ assert(success);
}
+#endif
}
+ }
#ifndef __SWITCH__
#ifndef _WIN32
- u32 dtcmEnd = dtcmStart + dtcmSize;
- if (Num == 0
- && dtcmEnd >= Addr
- && dtcmStart < Addr + Size)
+ u32 dtcmEnd = dtcmStart + dtcmSize;
+ if (Num == 0
+ && dtcmEnd >= Addr
+ && dtcmStart < Addr + Size)
+ {
+ bool success;
+ if (dtcmStart > Addr)
{
- bool success;
- if (dtcmStart > Addr)
- {
- success = UnmapFromRange(Addr, 0, OffsetsPerRegion[region] + LocalOffset, dtcmStart - Addr);
- assert(success);
- }
- if (dtcmEnd < Addr + Size)
- {
- u32 offset = dtcmStart - Addr + dtcmSize;
- success = UnmapFromRange(dtcmEnd, 0, OffsetsPerRegion[region] + LocalOffset + offset, Size - offset);
- assert(success);
- }
+ success = nds.JIT.Memory.UnmapFromRange(Addr, 0, OffsetsPerRegion[region] + LocalOffset, dtcmStart - Addr);
+ assert(success);
}
- else
-#endif
+ if (dtcmEnd < Addr + Size)
{
- bool succeded = UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
- assert(succeded);
+ u32 offset = dtcmStart - Addr + dtcmSize;
+ success = nds.JIT.Memory.UnmapFromRange(dtcmEnd, 0, OffsetsPerRegion[region] + LocalOffset + offset, Size - offset);
+ assert(success);
}
-#endif
}
-};
-ARMJIT::TinyVector Mappings[memregions_Count];
+ else
+#endif
+ {
+ bool succeded = nds.JIT.Memory.UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
+ assert(succeded);
+ }
+#endif
+}
-void SetCodeProtection(int region, u32 offset, bool protect)
+void ARMJIT_Memory::SetCodeProtection(int region, u32 offset, bool protect) noexcept
{
offset &= ~0xFFF;
//printf("set code protection %d %x %d\n", region, offset, protect);
@@ -457,7 +401,7 @@ void SetCodeProtection(int region, u32 offset, bool protect)
u32 effectiveAddr = mapping.Addr + (offset - mapping.LocalOffset);
if (mapping.Num == 0
&& region != memregion_DTCM
- && (effectiveAddr & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
+ && (effectiveAddr & NDS.ARM9.DTCMMask) == NDS.ARM9.DTCMBase)
continue;
u8* states = (u8*)(mapping.Num == 0 ? MappingStatus9 : MappingStatus7);
@@ -479,13 +423,13 @@ void SetCodeProtection(int region, u32 offset, bool protect)
}
}
-void RemapDTCM(u32 newBase, u32 newSize)
+void ARMJIT_Memory::RemapDTCM(u32 newBase, u32 newSize) noexcept
{
// this first part could be made more efficient
// by unmapping DTCM first and then map the holes
- u32 oldDTCMBase = NDS::ARM9->DTCMBase;
- u32 oldDTCMSize = ~NDS::ARM9->DTCMMask + 1;
- u32 oldDTCMEnd = oldDTCMBase + NDS::ARM9->DTCMMask;
+ u32 oldDTCMBase = NDS.ARM9.DTCMBase;
+ u32 oldDTCMSize = ~NDS.ARM9.DTCMMask + 1;
+ u32 oldDTCMEnd = oldDTCMBase + NDS.ARM9.DTCMMask;
u32 newEnd = newBase + newSize;
@@ -510,7 +454,7 @@ void RemapDTCM(u32 newBase, u32 newSize)
if (mapping.Num == 0 && overlap)
{
- mapping.Unmap(region);
+ mapping.Unmap(region, NDS);
Mappings[region].Remove(i);
}
else
@@ -522,20 +466,24 @@ void RemapDTCM(u32 newBase, u32 newSize)
for (int i = 0; i < Mappings[memregion_DTCM].Length; i++)
{
- Mappings[memregion_DTCM][i].Unmap(memregion_DTCM);
+ Mappings[memregion_DTCM][i].Unmap(memregion_DTCM, NDS);
}
Mappings[memregion_DTCM].Clear();
}
-void RemapNWRAM(int num)
+void ARMJIT_Memory::RemapNWRAM(int num) noexcept
{
+ if (NDS.ConsoleType == 0)
+ return;
+
+ auto* dsi = static_cast(&NDS);
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
{
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
- if (DSi::NWRAMStart[mapping.Num][num] < mapping.Addr + mapping.Size
- && DSi::NWRAMEnd[mapping.Num][num] > mapping.Addr)
+ if (dsi->NWRAMStart[mapping.Num][num] < mapping.Addr + mapping.Size
+ && dsi->NWRAMEnd[mapping.Num][num] > mapping.Addr)
{
- mapping.Unmap(memregion_SharedWRAM);
+ mapping.Unmap(memregion_SharedWRAM, NDS);
Mappings[memregion_SharedWRAM].Remove(i);
}
else
@@ -545,12 +493,12 @@ void RemapNWRAM(int num)
}
for (int i = 0; i < Mappings[memregion_NewSharedWRAM_A + num].Length; i++)
{
- Mappings[memregion_NewSharedWRAM_A + num][i].Unmap(memregion_NewSharedWRAM_A + num);
+ Mappings[memregion_NewSharedWRAM_A + num][i].Unmap(memregion_NewSharedWRAM_A + num, NDS);
}
Mappings[memregion_NewSharedWRAM_A + num].Clear();
}
-void RemapSWRAM()
+void ARMJIT_Memory::RemapSWRAM() noexcept
{
Log(LogLevel::Debug, "remapping SWRAM\n");
for (int i = 0; i < Mappings[memregion_WRAM7].Length;)
@@ -558,7 +506,7 @@ void RemapSWRAM()
Mapping& mapping = Mappings[memregion_WRAM7][i];
if (mapping.Addr + mapping.Size <= 0x03800000)
{
- mapping.Unmap(memregion_WRAM7);
+ mapping.Unmap(memregion_WRAM7, NDS);
Mappings[memregion_WRAM7].Remove(i);
}
else
@@ -566,14 +514,14 @@ void RemapSWRAM()
}
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length; i++)
{
- Mappings[memregion_SharedWRAM][i].Unmap(memregion_SharedWRAM);
+ Mappings[memregion_SharedWRAM][i].Unmap(memregion_SharedWRAM, NDS);
}
Mappings[memregion_SharedWRAM].Clear();
}
-bool MapAtAddress(u32 addr)
+bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
{
- u32 num = NDS::CurCPU;
+ u32 num = NDS.CurCPU;
int region = num == 0
? ClassifyAddress9(addr)
@@ -589,10 +537,10 @@ bool MapAtAddress(u32 addr)
u8* states = num == 0 ? MappingStatus9 : MappingStatus7;
//printf("mapping mirror %x, %x %x %d %d\n", mirrorStart, mirrorSize, memoryOffset, region, num);
- bool isExecutable = ARMJIT::CodeMemRegions[region];
+ bool isExecutable = NDS.JIT.CodeMemRegions[region];
- u32 dtcmStart = NDS::ARM9->DTCMBase;
- u32 dtcmSize = ~NDS::ARM9->DTCMMask + 1;
+ u32 dtcmStart = NDS.ARM9.DTCMBase;
+ u32 dtcmSize = ~NDS.ARM9.DTCMMask + 1;
u32 dtcmEnd = dtcmStart + dtcmSize;
#ifndef __SWITCH__
#ifndef _WIN32
@@ -621,7 +569,7 @@ bool MapAtAddress(u32 addr)
}
#endif
- ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset / 512;
+ AddressRange* range = NDS.JIT.CodeMemRegions[region] + memoryOffset / 512;
// this overcomplicated piece of code basically just finds whole pieces of code memory
// which can be mapped/protected
@@ -639,10 +587,10 @@ bool MapAtAddress(u32 addr)
else
{
u32 sectionOffset = offset;
- bool hasCode = isExecutable && ARMJIT::PageContainsCode(&range[offset / 512]);
+ bool hasCode = isExecutable && PageContainsCode(&range[offset / 512]);
while (offset < mirrorSize
- && (!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode)
- && (!skipDTCM || mirrorStart + offset != NDS::ARM9->DTCMBase))
+ && (!isExecutable || PageContainsCode(&range[offset / 512]) == hasCode)
+ && (!skipDTCM || mirrorStart + offset != NDS.ARM9.DTCMBase))
{
assert(states[(mirrorStart + offset) >> 12] == memstate_Unmapped);
states[(mirrorStart + offset) >> 12] = hasCode ? memstate_MappedProtected : memstate_MappedRW;
@@ -676,19 +624,19 @@ bool MapAtAddress(u32 addr)
return true;
}
-bool FaultHandler(FaultDescription& faultDesc)
+bool ARMJIT_Memory::FaultHandler(FaultDescription& faultDesc, melonDS::NDS& nds)
{
- if (ARMJIT::JITCompiler->IsJITFault(faultDesc.FaultPC))
+ if (nds.JIT.JITCompiler.IsJITFault(faultDesc.FaultPC))
{
bool rewriteToSlowPath = true;
- u8* memStatus = NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7;
+ u8* memStatus = nds.CurCPU == 0 ? nds.JIT.Memory.MappingStatus9 : nds.JIT.Memory.MappingStatus7;
if (memStatus[faultDesc.EmulatedFaultAddr >> 12] == memstate_Unmapped)
- rewriteToSlowPath = !MapAtAddress(faultDesc.EmulatedFaultAddr);
+ rewriteToSlowPath = !nds.JIT.Memory.MapAtAddress(faultDesc.EmulatedFaultAddr);
if (rewriteToSlowPath)
- faultDesc.FaultPC = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc.FaultPC);
+ faultDesc.FaultPC = nds.JIT.JITCompiler.RewriteMemAccess(faultDesc.FaultPC);
return true;
}
@@ -697,7 +645,7 @@ bool FaultHandler(FaultDescription& faultDesc)
const u64 AddrSpaceSize = 0x100000000;
-void Init()
+ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
{
#if defined(__SWITCH__)
MemoryBase = (u8*)aligned_alloc(0x1000, MemoryTotalSize);
@@ -740,8 +688,6 @@ void Init()
MemoryBase = MemoryBase + AddrSpaceSize*3;
MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, MemoryTotalSize, MemoryBase);
-
- u8* basePtr = MemoryBase;
#else
// this used to be allocated with three different mmaps
// The idea was to give the OS more freedom where to position the buffers,
@@ -798,16 +744,9 @@ void Init()
u8* basePtr = MemoryBase;
#endif
- NDS::MainRAM = basePtr + MemBlockMainRAMOffset;
- NDS::SharedWRAM = basePtr + MemBlockSWRAMOffset;
- NDS::ARM7WRAM = basePtr + MemBlockARM7WRAMOffset;
- NDS::ARM9->DTCM = basePtr + MemBlockDTCMOffset;
- DSi::NWRAM_A = basePtr + MemBlockNWRAM_AOffset;
- DSi::NWRAM_B = basePtr + MemBlockNWRAM_BOffset;
- DSi::NWRAM_C = basePtr + MemBlockNWRAM_COffset;
}
-void DeInit()
+ARMJIT_Memory::~ARMJIT_Memory() noexcept
{
#if defined(__SWITCH__)
virtmemLock();
@@ -875,12 +814,12 @@ void DeInit()
#endif
}
-void Reset()
+void ARMJIT_Memory::Reset() noexcept
{
for (int region = 0; region < memregions_Count; region++)
{
for (int i = 0; i < Mappings[region].Length; i++)
- Mappings[region][i].Unmap(region);
+ Mappings[region][i].Unmap(region, NDS);
Mappings[region].Clear();
}
@@ -893,7 +832,7 @@ void Reset()
Log(LogLevel::Debug, "done resetting jit mem\n");
}
-bool IsFastmemCompatible(int region)
+bool ARMJIT_Memory::IsFastmemCompatible(int region) const noexcept
{
#ifdef _WIN32
/*
@@ -909,7 +848,7 @@ bool IsFastmemCompatible(int region)
return OffsetsPerRegion[region] != UINT32_MAX;
}
-bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize)
+bool ARMJIT_Memory::GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize) const noexcept
{
memoryOffset = 0;
switch (region)
@@ -931,8 +870,8 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
}
return false;
case memregion_MainRAM:
- mirrorStart = addr & ~NDS::MainRAMMask;
- mirrorSize = NDS::MainRAMMask + 1;
+ mirrorStart = addr & ~NDS.MainRAMMask;
+ mirrorSize = NDS.MainRAMMask + 1;
return true;
case memregion_BIOS9:
if (num == 0)
@@ -951,26 +890,26 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
}
return false;
case memregion_SharedWRAM:
- if (num == 0 && NDS::SWRAM_ARM9.Mem)
+ if (num == 0 && NDS.SWRAM_ARM9.Mem)
{
- mirrorStart = addr & ~NDS::SWRAM_ARM9.Mask;
- mirrorSize = NDS::SWRAM_ARM9.Mask + 1;
- memoryOffset = NDS::SWRAM_ARM9.Mem - NDS::SharedWRAM;
+ mirrorStart = addr & ~NDS.SWRAM_ARM9.Mask;
+ mirrorSize = NDS.SWRAM_ARM9.Mask + 1;
+ memoryOffset = NDS.SWRAM_ARM9.Mem - GetSharedWRAM();
return true;
}
- else if (num == 1 && NDS::SWRAM_ARM7.Mem)
+ else if (num == 1 && NDS.SWRAM_ARM7.Mem)
{
- mirrorStart = addr & ~NDS::SWRAM_ARM7.Mask;
- mirrorSize = NDS::SWRAM_ARM7.Mask + 1;
- memoryOffset = NDS::SWRAM_ARM7.Mem - NDS::SharedWRAM;
+ mirrorStart = addr & ~NDS.SWRAM_ARM7.Mask;
+ mirrorSize = NDS.SWRAM_ARM7.Mask + 1;
+ memoryOffset = NDS.SWRAM_ARM7.Mem - GetSharedWRAM();
return true;
}
return false;
case memregion_WRAM7:
if (num == 1)
{
- mirrorStart = addr & ~(NDS::ARM7WRAMSize - 1);
- mirrorSize = NDS::ARM7WRAMSize;
+ mirrorStart = addr & ~(ARM7WRAMSize - 1);
+ mirrorSize = ARM7WRAMSize;
return true;
}
return false;
@@ -992,10 +931,12 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
return false;
case memregion_NewSharedWRAM_A:
{
- u8* ptr = DSi::NWRAMMap_A[num][(addr >> 16) & DSi::NWRAMMask[num][0]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_A[num][(addr >> 16) & dsi->NWRAMMask[num][0]];
if (ptr)
{
- memoryOffset = ptr - DSi::NWRAM_A;
+ memoryOffset = ptr - GetNWRAM_A();
mirrorStart = addr & ~0xFFFF;
mirrorSize = 0x10000;
return true;
@@ -1004,10 +945,12 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
}
case memregion_NewSharedWRAM_B:
{
- u8* ptr = DSi::NWRAMMap_B[num][(addr >> 15) & DSi::NWRAMMask[num][1]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_B[num][(addr >> 15) & dsi->NWRAMMask[num][1]];
if (ptr)
{
- memoryOffset = ptr - DSi::NWRAM_B;
+ memoryOffset = ptr - GetNWRAM_B();
mirrorStart = addr & ~0x7FFF;
mirrorSize = 0x8000;
return true;
@@ -1016,10 +959,12 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
}
case memregion_NewSharedWRAM_C:
{
- u8* ptr = DSi::NWRAMMap_C[num][(addr >> 15) & DSi::NWRAMMask[num][2]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_C[num][(addr >> 15) & dsi->NWRAMMask[num][2]];
if (ptr)
{
- memoryOffset = ptr - DSi::NWRAM_C;
+ memoryOffset = ptr - GetNWRAM_C();
mirrorStart = addr & ~0x7FFF;
mirrorSize = 0x8000;
return true;
@@ -1029,16 +974,20 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
case memregion_BIOS9DSi:
if (num == 0)
{
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
mirrorStart = addr & ~0xFFFF;
- mirrorSize = DSi::SCFG_BIOS & (1<<0) ? 0x8000 : 0x10000;
+ mirrorSize = dsi->SCFG_BIOS & (1<<0) ? 0x8000 : 0x10000;
return true;
}
return false;
case memregion_BIOS7DSi:
if (num == 1)
{
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
mirrorStart = addr & ~0xFFFF;
- mirrorSize = DSi::SCFG_BIOS & (1<<8) ? 0x8000 : 0x10000;
+ mirrorSize = dsi->SCFG_BIOS & (1<<8) ? 0x8000 : 0x10000;
return true;
}
return false;
@@ -1048,25 +997,25 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
}
}
-u32 LocaliseAddress(int region, u32 num, u32 addr)
+u32 ARMJIT_Memory::LocaliseAddress(int region, u32 num, u32 addr) const noexcept
{
switch (region)
{
case memregion_ITCM:
return (addr & (ITCMPhysicalSize - 1)) | (memregion_ITCM << 27);
case memregion_MainRAM:
- return (addr & NDS::MainRAMMask) | (memregion_MainRAM << 27);
+ return (addr & NDS.MainRAMMask) | (memregion_MainRAM << 27);
case memregion_BIOS9:
return (addr & 0xFFF) | (memregion_BIOS9 << 27);
case memregion_BIOS7:
return (addr & 0x3FFF) | (memregion_BIOS7 << 27);
case memregion_SharedWRAM:
if (num == 0)
- return ((addr & NDS::SWRAM_ARM9.Mask) + (NDS::SWRAM_ARM9.Mem - NDS::SharedWRAM)) | (memregion_SharedWRAM << 27);
+ return ((addr & NDS.SWRAM_ARM9.Mask) + (NDS.SWRAM_ARM9.Mem - GetSharedWRAM())) | (memregion_SharedWRAM << 27);
else
- return ((addr & NDS::SWRAM_ARM7.Mask) + (NDS::SWRAM_ARM7.Mem - NDS::SharedWRAM)) | (memregion_SharedWRAM << 27);
+ return ((addr & NDS.SWRAM_ARM7.Mask) + (NDS.SWRAM_ARM7.Mem - GetSharedWRAM())) | (memregion_SharedWRAM << 27);
case memregion_WRAM7:
- return (addr & (NDS::ARM7WRAMSize - 1)) | (memregion_WRAM7 << 27);
+ return (addr & (melonDS::ARM7WRAMSize - 1)) | (memregion_WRAM7 << 27);
case memregion_VRAM:
// TODO: take mapping properly into account
return (addr & 0xFFFFF) | (memregion_VRAM << 27);
@@ -1075,25 +1024,31 @@ u32 LocaliseAddress(int region, u32 num, u32 addr)
return (addr & 0x3FFFF) | (memregion_VWRAM << 27);
case memregion_NewSharedWRAM_A:
{
- u8* ptr = DSi::NWRAMMap_A[num][(addr >> 16) & DSi::NWRAMMask[num][0]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_A[num][(addr >> 16) & dsi->NWRAMMask[num][0]];
if (ptr)
- return (ptr - DSi::NWRAM_A + (addr & 0xFFFF)) | (memregion_NewSharedWRAM_A << 27);
+ return (ptr - GetNWRAM_A() + (addr & 0xFFFF)) | (memregion_NewSharedWRAM_A << 27);
else
return memregion_Other << 27; // zero filled memory
}
case memregion_NewSharedWRAM_B:
{
- u8* ptr = DSi::NWRAMMap_B[num][(addr >> 15) & DSi::NWRAMMask[num][1]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_B[num][(addr >> 15) & dsi->NWRAMMask[num][1]];
if (ptr)
- return (ptr - DSi::NWRAM_B + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_B << 27);
+ return (ptr - GetNWRAM_B() + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_B << 27);
else
return memregion_Other << 27;
}
case memregion_NewSharedWRAM_C:
{
- u8* ptr = DSi::NWRAMMap_C[num][(addr >> 15) & DSi::NWRAMMask[num][2]];
+ auto* dsi = dynamic_cast(&NDS);
+ assert(dsi != nullptr);
+ u8* ptr = dsi->NWRAMMap_C[num][(addr >> 15) & dsi->NWRAMMask[num][2]];
if (ptr)
- return (ptr - DSi::NWRAM_C + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_C << 27);
+ return (ptr - GetNWRAM_C() + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_C << 27);
else
return memregion_Other << 27;
}
@@ -1106,26 +1061,31 @@ u32 LocaliseAddress(int region, u32 num, u32 addr)
}
}
-int ClassifyAddress9(u32 addr)
+int ARMJIT_Memory::ClassifyAddress9(u32 addr) const noexcept
{
- if (addr < NDS::ARM9->ITCMSize)
+ if (addr < NDS.ARM9.ITCMSize)
{
return memregion_ITCM;
}
- else if ((addr & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
+ else if ((addr & NDS.ARM9.DTCMMask) == NDS.ARM9.DTCMBase)
{
return memregion_DTCM;
}
else
{
- if (NDS::ConsoleType == 1 && addr >= 0xFFFF0000 && !(DSi::SCFG_BIOS & (1<<1)))
+ if (NDS.ConsoleType == 1)
{
- if ((addr >= 0xFFFF8000) && (DSi::SCFG_BIOS & (1<<0)))
- return memregion_Other;
+ auto& dsi = static_cast(NDS);
+ if (addr >= 0xFFFF0000 && !(dsi.SCFG_BIOS & (1<<1)))
+ {
+ if ((addr >= 0xFFFF8000) && (dsi.SCFG_BIOS & (1<<0)))
+ return memregion_Other;
- return memregion_BIOS9DSi;
+ return memregion_BIOS9DSi;
+ }
}
- else if ((addr & 0xFFFFF000) == 0xFFFF0000)
+
+ if ((addr & 0xFFFFF000) == 0xFFFF0000)
{
return memregion_BIOS9;
}
@@ -1135,17 +1095,18 @@ int ClassifyAddress9(u32 addr)
case 0x02000000:
return memregion_MainRAM;
case 0x03000000:
- if (NDS::ConsoleType == 1)
+ if (NDS.ConsoleType == 1)
{
- if (addr >= DSi::NWRAMStart[0][0] && addr < DSi::NWRAMEnd[0][0])
+ auto& dsi = static_cast(NDS);
+ if (addr >= dsi.NWRAMStart[0][0] && addr < dsi.NWRAMEnd[0][0])
return memregion_NewSharedWRAM_A;
- if (addr >= DSi::NWRAMStart[0][1] && addr < DSi::NWRAMEnd[0][1])
+ if (addr >= dsi.NWRAMStart[0][1] && addr < dsi.NWRAMEnd[0][1])
return memregion_NewSharedWRAM_B;
- if (addr >= DSi::NWRAMStart[0][2] && addr < DSi::NWRAMEnd[0][2])
+ if (addr >= dsi.NWRAMStart[0][2] && addr < dsi.NWRAMEnd[0][2])
return memregion_NewSharedWRAM_C;
}
- if (NDS::SWRAM_ARM9.Mem)
+ if (NDS.SWRAM_ARM9.Mem)
return memregion_SharedWRAM;
return memregion_Other;
case 0x04000000:
@@ -1153,23 +1114,28 @@ int ClassifyAddress9(u32 addr)
case 0x06000000:
return memregion_VRAM;
case 0x0C000000:
- return (NDS::ConsoleType==1) ? memregion_MainRAM : memregion_Other;
+ return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
default:
return memregion_Other;
}
}
}
-int ClassifyAddress7(u32 addr)
+int ARMJIT_Memory::ClassifyAddress7(u32 addr) const noexcept
{
- if (NDS::ConsoleType == 1 && addr < 0x00010000 && !(DSi::SCFG_BIOS & (1<<9)))
+ if (NDS.ConsoleType == 1)
{
- if (addr >= 0x00008000 && DSi::SCFG_BIOS & (1<<8))
- return memregion_Other;
+ auto& dsi = static_cast(NDS);
+ if (addr < 0x00010000 && !(dsi.SCFG_BIOS & (1<<9)))
+ {
+ if (addr >= 0x00008000 && dsi.SCFG_BIOS & (1<<8))
+ return memregion_Other;
- return memregion_BIOS7DSi;
+ return memregion_BIOS7DSi;
+ }
}
- else if (addr < 0x00004000)
+
+ if (addr < 0x00004000)
{
return memregion_BIOS7;
}
@@ -1181,17 +1147,18 @@ int ClassifyAddress7(u32 addr)
case 0x02800000:
return memregion_MainRAM;
case 0x03000000:
- if (NDS::ConsoleType == 1)
+ if (NDS.ConsoleType == 1)
{
- if (addr >= DSi::NWRAMStart[1][0] && addr < DSi::NWRAMEnd[1][0])
+ auto& dsi = static_cast(NDS);
+ if (addr >= dsi.NWRAMStart[1][0] && addr < dsi.NWRAMEnd[1][0])
return memregion_NewSharedWRAM_A;
- if (addr >= DSi::NWRAMStart[1][1] && addr < DSi::NWRAMEnd[1][1])
+ if (addr >= dsi.NWRAMStart[1][1] && addr < dsi.NWRAMEnd[1][1])
return memregion_NewSharedWRAM_B;
- if (addr >= DSi::NWRAMStart[1][2] && addr < DSi::NWRAMEnd[1][2])
+ if (addr >= dsi.NWRAMStart[1][2] && addr < dsi.NWRAMEnd[1][2])
return memregion_NewSharedWRAM_C;
}
- if (NDS::SWRAM_ARM7.Mem)
+ if (NDS.SWRAM_ARM7.Mem)
return memregion_SharedWRAM;
return memregion_WRAM7;
case 0x03800000:
@@ -1205,14 +1172,14 @@ int ClassifyAddress7(u32 addr)
return memregion_VWRAM;
case 0x0C000000:
case 0x0C800000:
- return (NDS::ConsoleType==1) ? memregion_MainRAM : memregion_Other;
+ return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
default:
return memregion_Other;
}
}
}
-void WifiWrite32(u32 addr, u32 val)
+/*void WifiWrite32(u32 addr, u32 val)
{
Wifi::Write(addr, val & 0xFFFF);
Wifi::Write(addr + 2, val >> 16);
@@ -1221,18 +1188,18 @@ void WifiWrite32(u32 addr, u32 val)
u32 WifiRead32(u32 addr)
{
return (u32)Wifi::Read(addr) | ((u32)Wifi::Read(addr + 2) << 16);
-}
+}*/
template
void VRAMWrite(u32 addr, T val)
{
switch (addr & 0x00E00000)
{
- case 0x00000000: GPU::WriteVRAM_ABG(addr, val); return;
- case 0x00200000: GPU::WriteVRAM_BBG(addr, val); return;
- case 0x00400000: GPU::WriteVRAM_AOBJ(addr, val); return;
- case 0x00600000: GPU::WriteVRAM_BOBJ(addr, val); return;
- default: GPU::WriteVRAM_LCDC(addr, val); return;
+ case 0x00000000: NDS::Current->GPU.WriteVRAM_ABG(addr, val); return;
+ case 0x00200000: NDS::Current->GPU.WriteVRAM_BBG(addr, val); return;
+ case 0x00400000: NDS::Current->GPU.WriteVRAM_AOBJ(addr, val); return;
+ case 0x00600000: NDS::Current->GPU.WriteVRAM_BOBJ(addr, val); return;
+ default: NDS::Current->GPU.WriteVRAM_LCDC(addr, val); return;
}
}
template
@@ -1240,23 +1207,130 @@ T VRAMRead(u32 addr)
{
switch (addr & 0x00E00000)
{
- case 0x00000000: return GPU::ReadVRAM_ABG(addr);
- case 0x00200000: return GPU::ReadVRAM_BBG(addr);
- case 0x00400000: return GPU::ReadVRAM_AOBJ(addr);
- case 0x00600000: return GPU::ReadVRAM_BOBJ(addr);
- default: return GPU::ReadVRAM_LCDC(addr);
+ case 0x00000000: return NDS::Current->GPU.ReadVRAM_ABG(addr);
+ case 0x00200000: return NDS::Current->GPU.ReadVRAM_BBG(addr);
+ case 0x00400000: return NDS::Current->GPU.ReadVRAM_AOBJ(addr);
+ case 0x00600000: return NDS::Current->GPU.ReadVRAM_BOBJ(addr);
+ default: return NDS::Current->GPU.ReadVRAM_LCDC(addr);
}
}
-void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
+static u8 GPU3D_Read8(u32 addr) noexcept
+{
+ return NDS::Current->GPU.GPU3D.Read8(addr);
+}
+
+static u16 GPU3D_Read16(u32 addr) noexcept
+{
+ return NDS::Current->GPU.GPU3D.Read16(addr);
+}
+
+static u32 GPU3D_Read32(u32 addr) noexcept
+{
+ return NDS::Current->GPU.GPU3D.Read32(addr);
+}
+
+static void GPU3D_Write8(u32 addr, u8 val) noexcept
+{
+ NDS::Current->GPU.GPU3D.Write8(addr, val);
+}
+
+static void GPU3D_Write16(u32 addr, u16 val) noexcept
+{
+ NDS::Current->GPU.GPU3D.Write16(addr, val);
+}
+
+static void GPU3D_Write32(u32 addr, u32 val) noexcept
+{
+ NDS::Current->GPU.GPU3D.Write32(addr, val);
+}
+
+template
+static T GPU_ReadVRAM_ARM7(u32 addr) noexcept
+{
+ return NDS::Current->GPU.ReadVRAM_ARM7(addr);
+}
+
+template
+static void GPU_WriteVRAM_ARM7(u32 addr, T val) noexcept
+{
+ NDS::Current->GPU.WriteVRAM_ARM7(addr, val);
+}
+
+u32 NDSCartSlot_ReadROMData()
+{ // TODO: Add a NDS* parameter, when NDS* is eventually implemented
+ return NDS::Current->NDSCartSlot.ReadROMData();
+}
+
+static u8 NDS_ARM9IORead8(u32 addr)
+{
+ return NDS::Current->ARM9IORead8(addr);
+}
+
+static u16 NDS_ARM9IORead16(u32 addr)
+{
+ return NDS::Current->ARM9IORead16(addr);
+}
+
+static u32 NDS_ARM9IORead32(u32 addr)
+{
+ return NDS::Current->ARM9IORead32(addr);
+}
+
+static void NDS_ARM9IOWrite8(u32 addr, u8 val)
+{
+ NDS::Current->ARM9IOWrite8(addr, val);
+}
+
+static void NDS_ARM9IOWrite16(u32 addr, u16 val)
+{
+ NDS::Current->ARM9IOWrite16(addr, val);
+}
+
+static void NDS_ARM9IOWrite32(u32 addr, u32 val)
+{
+ NDS::Current->ARM9IOWrite32(addr, val);
+}
+
+static u8 NDS_ARM7IORead8(u32 addr)
+{
+ return NDS::Current->ARM7IORead8(addr);
+}
+
+static u16 NDS_ARM7IORead16(u32 addr)
+{
+ return NDS::Current->ARM7IORead16(addr);
+}
+
+static u32 NDS_ARM7IORead32(u32 addr)
+{
+ return NDS::Current->ARM7IORead32(addr);
+}
+
+static void NDS_ARM7IOWrite8(u32 addr, u8 val)
+{
+ NDS::Current->ARM7IOWrite8(addr, val);
+}
+
+static void NDS_ARM7IOWrite16(u32 addr, u16 val)
+{
+ NDS::Current->ARM7IOWrite16(addr, val);
+}
+
+static void NDS_ARM7IOWrite32(u32 addr, u32 val)
+{
+ NDS::Current->ARM7IOWrite32(addr, val);
+}
+
+void* ARMJIT_Memory::GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) const noexcept
{
if (cpu->Num == 0)
{
switch (addr & 0xFF000000)
{
case 0x04000000:
- if (!store && size == 32 && addr == 0x04100010 && NDS::ExMemCnt[0] & (1<<11))
- return (void*)NDSCart::ReadROMData;
+ if (!store && size == 32 && addr == 0x04100010 && NDS.ExMemCnt[0] & (1<<11))
+ return (void*)NDSCartSlot_ReadROMData;
/*
unfortunately we can't map GPU2D this way
@@ -1268,39 +1342,26 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
{
switch (size | store)
{
- case 8: return (void*)GPU3D::Read8;
- case 9: return (void*)GPU3D::Write8;
- case 16: return (void*)GPU3D::Read16;
- case 17: return (void*)GPU3D::Write16;
- case 32: return (void*)GPU3D::Read32;
- case 33: return (void*)GPU3D::Write32;
+ case 8: return (void*)GPU3D_Read8;
+ case 9: return (void*)GPU3D_Write8;
+ case 16: return (void*)GPU3D_Read16;
+ case 17: return (void*)GPU3D_Write16;
+ case 32: return (void*)GPU3D_Read32;
+ case 33: return (void*)GPU3D_Write32;
}
}
- if (NDS::ConsoleType == 0)
+ switch (size | store)
{
- switch (size | store)
- {
- case 8: return (void*)NDS::ARM9IORead8;
- case 9: return (void*)NDS::ARM9IOWrite8;
- case 16: return (void*)NDS::ARM9IORead16;
- case 17: return (void*)NDS::ARM9IOWrite16;
- case 32: return (void*)NDS::ARM9IORead32;
- case 33: return (void*)NDS::ARM9IOWrite32;
- }
- }
- else
- {
- switch (size | store)
- {
- case 8: return (void*)DSi::ARM9IORead8;
- case 9: return (void*)DSi::ARM9IOWrite8;
- case 16: return (void*)DSi::ARM9IORead16;
- case 17: return (void*)DSi::ARM9IOWrite16;
- case 32: return (void*)DSi::ARM9IORead32;
- case 33: return (void*)DSi::ARM9IOWrite32;
- }
+ case 8: return (void*)NDS_ARM9IORead8;
+ case 9: return (void*)NDS_ARM9IOWrite8;
+ case 16: return (void*)NDS_ARM9IORead16;
+ case 17: return (void*)NDS_ARM9IOWrite16;
+ case 32: return (void*)NDS_ARM9IORead32;
+ case 33: return (void*)NDS_ARM9IOWrite32;
}
+ // NDS::Current will delegate to the DSi versions of these methods
+ // if it's really a DSi
break;
case 0x06000000:
switch (size | store)
@@ -1320,7 +1381,7 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
switch (addr & 0xFF800000)
{
case 0x04000000:
- if (addr >= 0x04000400 && addr < 0x04000520)
+ /*if (addr >= 0x04000400 && addr < 0x04000520)
{
switch (size | store)
{
@@ -1331,34 +1392,20 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
case 32: return (void*)SPU::Read32;
case 33: return (void*)SPU::Write32;
}
- }
+ }*/
- if (NDS::ConsoleType == 0)
+ switch (size | store)
{
- switch (size | store)
- {
- case 8: return (void*)NDS::ARM7IORead8;
- case 9: return (void*)NDS::ARM7IOWrite8;
- case 16: return (void*)NDS::ARM7IORead16;
- case 17: return (void*)NDS::ARM7IOWrite16;
- case 32: return (void*)NDS::ARM7IORead32;
- case 33: return (void*)NDS::ARM7IOWrite32;
- }
- }
- else
- {
- switch (size | store)
- {
- case 8: return (void*)DSi::ARM7IORead8;
- case 9: return (void*)DSi::ARM7IOWrite8;
- case 16: return (void*)DSi::ARM7IORead16;
- case 17: return (void*)DSi::ARM7IOWrite16;
- case 32: return (void*)DSi::ARM7IORead32;
- case 33: return (void*)DSi::ARM7IOWrite32;
- }
+ case 8: return (void*)NDS_ARM7IORead8;
+ case 9: return (void*)NDS_ARM7IOWrite8;
+ case 16: return (void*)NDS_ARM7IORead16;
+ case 17: return (void*)NDS_ARM7IOWrite16;
+ case 32: return (void*)NDS_ARM7IORead32;
+ case 33: return (void*)NDS_ARM7IOWrite32;
}
break;
- case 0x04800000:
+ // TODO: the wifi funcs also ought to check POWCNT
+ /*case 0x04800000:
if (addr < 0x04810000 && size >= 16)
{
switch (size | store)
@@ -1369,21 +1416,20 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
case 33: return (void*)WifiWrite32;
}
}
- break;
+ break;*/
case 0x06000000:
case 0x06800000:
switch (size | store)
{
- case 8: return (void*)GPU::ReadVRAM_ARM7;
- case 9: return (void*)GPU::WriteVRAM_ARM7;
- case 16: return (void*)GPU::ReadVRAM_ARM7;
- case 17: return (void*)GPU::WriteVRAM_ARM7;
- case 32: return (void*)GPU::ReadVRAM_ARM7;
- case 33: return (void*)GPU::WriteVRAM_ARM7;
+ case 8: return (void*)GPU_ReadVRAM_ARM7;
+ case 9: return (void*)GPU_WriteVRAM_ARM7;
+ case 16: return (void*)GPU_ReadVRAM_ARM7;
+ case 17: return (void*)GPU_WriteVRAM_ARM7;
+ case 32: return (void*)GPU_ReadVRAM_ARM7;
+ case 33: return (void*)GPU_WriteVRAM_ARM7;
}
}
}
return NULL;
}
-
-}
+}
\ No newline at end of file
diff --git a/src/ARMJIT_Memory.h b/src/ARMJIT_Memory.h
index 726b7108..d36f6032 100644
--- a/src/ARMJIT_Memory.h
+++ b/src/ARMJIT_Memory.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -20,62 +20,209 @@
#define ARMJIT_MEMORY
#include "types.h"
+#include "MemConstants.h"
-#include "ARM.h"
+#ifdef JIT_ENABLED
+# include "TinyVector.h"
+# include "ARM.h"
+# if defined(__SWITCH__)
+# include
+# elif defined(_WIN32)
+#include
+# else
+# include
+# include
+# include
+# include
+# include
+# endif
+#else
+# include
+#endif
-namespace ARMJIT_Memory
+namespace melonDS
{
+#ifdef JIT_ENABLED
+namespace Platform { struct DynamicLibrary; }
+class Compiler;
+class ARMJIT;
+#endif
-extern void* FastMem9Start;
-extern void* FastMem7Start;
-
-void Init();
-void DeInit();
-
-void Reset();
-
-enum
+constexpr u32 RoundUp(u32 size) noexcept
{
- memregion_Other = 0,
- memregion_ITCM,
- memregion_DTCM,
- memregion_BIOS9,
- memregion_MainRAM,
- memregion_SharedWRAM,
- memregion_IO9,
- memregion_VRAM,
- memregion_BIOS7,
- memregion_WRAM7,
- memregion_IO7,
- memregion_Wifi,
- memregion_VWRAM,
-
- // DSi
- memregion_BIOS9DSi,
- memregion_BIOS7DSi,
- memregion_NewSharedWRAM_A,
- memregion_NewSharedWRAM_B,
- memregion_NewSharedWRAM_C,
-
- memregions_Count
-};
-
-int ClassifyAddress9(u32 addr);
-int ClassifyAddress7(u32 addr);
-
-bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize);
-u32 LocaliseAddress(int region, u32 num, u32 addr);
-
-bool IsFastmemCompatible(int region);
-
-void RemapDTCM(u32 newBase, u32 newSize);
-void RemapSWRAM();
-void RemapNWRAM(int num);
-
-void SetCodeProtection(int region, u32 offset, bool protect);
-
-void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size);
-
+#ifdef _WIN32
+ return (size + 0xFFFF) & ~0xFFFF;
+#else
+ return size;
+#endif
}
+const u32 MemBlockMainRAMOffset = 0;
+const u32 MemBlockSWRAMOffset = RoundUp(MainRAMMaxSize);
+const u32 MemBlockARM7WRAMOffset = MemBlockSWRAMOffset + RoundUp(SharedWRAMSize);
+const u32 MemBlockDTCMOffset = MemBlockARM7WRAMOffset + RoundUp(ARM7WRAMSize);
+const u32 MemBlockNWRAM_AOffset = MemBlockDTCMOffset + RoundUp(DTCMPhysicalSize);
+const u32 MemBlockNWRAM_BOffset = MemBlockNWRAM_AOffset + RoundUp(NWRAMSize);
+const u32 MemBlockNWRAM_COffset = MemBlockNWRAM_BOffset + RoundUp(NWRAMSize);
+const u32 MemoryTotalSize = MemBlockNWRAM_COffset + RoundUp(NWRAMSize);
+
+class ARMJIT_Memory
+{
+public:
+ enum
+ {
+ memregion_Other = 0,
+ memregion_ITCM,
+ memregion_DTCM,
+ memregion_BIOS9,
+ memregion_MainRAM,
+ memregion_SharedWRAM,
+ memregion_IO9,
+ memregion_VRAM,
+ memregion_BIOS7,
+ memregion_WRAM7,
+ memregion_IO7,
+ memregion_Wifi,
+ memregion_VWRAM,
+
+ // DSi
+ memregion_BIOS9DSi,
+ memregion_BIOS7DSi,
+ memregion_NewSharedWRAM_A,
+ memregion_NewSharedWRAM_B,
+ memregion_NewSharedWRAM_C,
+
+ memregions_Count
+ };
+
+#ifdef JIT_ENABLED
+public:
+ explicit ARMJIT_Memory(melonDS::NDS& nds);
+ ~ARMJIT_Memory() noexcept;
+ ARMJIT_Memory(const ARMJIT_Memory&) = delete;
+ ARMJIT_Memory(ARMJIT_Memory&&) = delete;
+ ARMJIT_Memory& operator=(const ARMJIT_Memory&) = delete;
+ ARMJIT_Memory& operator=(ARMJIT_Memory&&) = delete;
+ void Reset() noexcept;
+ void RemapDTCM(u32 newBase, u32 newSize) noexcept;
+ void RemapSWRAM() noexcept;
+ void RemapNWRAM(int num) noexcept;
+ void SetCodeProtection(int region, u32 offset, bool protect) noexcept;
+
+ [[nodiscard]] u8* GetMainRAM() noexcept { return MemoryBase + MemBlockMainRAMOffset; }
+ [[nodiscard]] const u8* GetMainRAM() const noexcept { return MemoryBase + MemBlockMainRAMOffset; }
+
+ [[nodiscard]] u8* GetSharedWRAM() noexcept { return MemoryBase + MemBlockSWRAMOffset; }
+ [[nodiscard]] const u8* GetSharedWRAM() const noexcept { return MemoryBase + MemBlockSWRAMOffset; }
+
+ [[nodiscard]] u8* GetARM7WRAM() noexcept { return MemoryBase + MemBlockARM7WRAMOffset; }
+ [[nodiscard]] const u8* GetARM7WRAM() const noexcept { return MemoryBase + MemBlockARM7WRAMOffset; }
+
+ [[nodiscard]] u8* GetARM9DTCM() noexcept { return MemoryBase + MemBlockDTCMOffset; }
+ [[nodiscard]] const u8* GetARM9DTCM() const noexcept { return MemoryBase + MemBlockDTCMOffset; }
+
+ [[nodiscard]] u8* GetNWRAM_A() noexcept { return MemoryBase + MemBlockNWRAM_AOffset; }
+ [[nodiscard]] const u8* GetNWRAM_A() const noexcept { return MemoryBase + MemBlockNWRAM_AOffset; }
+
+ [[nodiscard]] u8* GetNWRAM_B() noexcept { return MemoryBase + MemBlockNWRAM_BOffset; }
+ [[nodiscard]] const u8* GetNWRAM_B() const noexcept { return MemoryBase + MemBlockNWRAM_BOffset; }
+
+ [[nodiscard]] u8* GetNWRAM_C() noexcept { return MemoryBase + MemBlockNWRAM_COffset; }
+ [[nodiscard]] const u8* GetNWRAM_C() const noexcept { return MemoryBase + MemBlockNWRAM_COffset; }
+
+ int ClassifyAddress9(u32 addr) const noexcept;
+ int ClassifyAddress7(u32 addr) const noexcept;
+ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize) const noexcept;
+ u32 LocaliseAddress(int region, u32 num, u32 addr) const noexcept;
+ bool IsFastmemCompatible(int region) const noexcept;
+ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) const noexcept;
+ bool MapAtAddress(u32 addr) noexcept;
+private:
+ friend class Compiler;
+ struct Mapping
+ {
+ u32 Addr;
+ u32 Size, LocalOffset;
+ u32 Num;
+
+ void Unmap(int region, NDS& nds) noexcept;
+ };
+
+ struct FaultDescription
+ {
+ u32 EmulatedFaultAddr;
+ u8* FaultPC;
+ };
+ static bool FaultHandler(FaultDescription& faultDesc, melonDS::NDS& nds);
+ bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size) noexcept;
+ bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size) noexcept;
+ void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection) noexcept;
+
+ melonDS::NDS& NDS;
+ void* FastMem9Start;
+ void* FastMem7Start;
+ u8* MemoryBase = nullptr;
+#if defined(__SWITCH__)
+ VirtmemReservation* FastMem9Reservation, *FastMem7Reservation;
+ u8* MemoryBaseCodeMem;
+#elif defined(_WIN32)
+ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo);
+ HANDLE MemoryFile = INVALID_HANDLE_VALUE;
+ LPVOID ExceptionHandlerHandle = nullptr;
+#else
+ static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext);
+ int MemoryFile = -1;
+#endif
+#ifdef ANDROID
+ Platform::DynamicLibrary* Libandroid = nullptr;
+#endif
+ u8 MappingStatus9[1 << (32-12)] {};
+ u8 MappingStatus7[1 << (32-12)] {};
+ TinyVector Mappings[memregions_Count] {};
+#else
+public:
+ explicit ARMJIT_Memory(melonDS::NDS&) {};
+ ~ARMJIT_Memory() = default;
+ ARMJIT_Memory(const ARMJIT_Memory&) = delete;
+ ARMJIT_Memory(ARMJIT_Memory&&) = delete;
+ ARMJIT_Memory& operator=(const ARMJIT_Memory&) = delete;
+ ARMJIT_Memory& operator=(ARMJIT_Memory&&) = delete;
+
+ void Reset() noexcept {}
+ void RemapDTCM(u32 newBase, u32 newSize) noexcept {}
+ void RemapSWRAM() noexcept {}
+ void RemapNWRAM(int num) noexcept {}
+ void SetCodeProtection(int region, u32 offset, bool protect) noexcept {}
+
+ [[nodiscard]] u8* GetMainRAM() noexcept { return MainRAM.data(); }
+ [[nodiscard]] const u8* GetMainRAM() const noexcept { return MainRAM.data(); }
+
+ [[nodiscard]] u8* GetSharedWRAM() noexcept { return SharedWRAM.data(); }
+ [[nodiscard]] const u8* GetSharedWRAM() const noexcept { return SharedWRAM.data(); }
+
+ [[nodiscard]] u8* GetARM7WRAM() noexcept { return ARM7WRAM.data(); }
+ [[nodiscard]] const u8* GetARM7WRAM() const noexcept { return ARM7WRAM.data(); }
+
+ [[nodiscard]] u8* GetARM9DTCM() noexcept { return DTCM.data(); }
+ [[nodiscard]] const u8* GetARM9DTCM() const noexcept { return DTCM.data(); }
+
+ [[nodiscard]] u8* GetNWRAM_A() noexcept { return NWRAM_A.data(); }
+ [[nodiscard]] const u8* GetNWRAM_A() const noexcept { return NWRAM_A.data(); }
+
+ [[nodiscard]] u8* GetNWRAM_B() noexcept { return NWRAM_B.data(); }
+ [[nodiscard]] const u8* GetNWRAM_B() const noexcept { return NWRAM_B.data(); }
+
+ [[nodiscard]] u8* GetNWRAM_C() noexcept { return NWRAM_C.data(); }
+ [[nodiscard]] const u8* GetNWRAM_C() const noexcept { return NWRAM_C.data(); }
+private:
+ std::array MainRAM {};
+ std::array ARM7WRAM {};
+ std::array SharedWRAM {};
+ std::array DTCM {};
+ std::array NWRAM_A {};
+ std::array NWRAM_B {};
+ std::array NWRAM_C {};
+#endif
+};
+}
#endif
diff --git a/src/ARMJIT_RegisterCache.h b/src/ARMJIT_RegisterCache.h
index 7ea44ed3..e5f28dd6 100644
--- a/src/ARMJIT_RegisterCache.h
+++ b/src/ARMJIT_RegisterCache.h
@@ -19,7 +19,6 @@
#ifndef ARMJIT_REGCACHE_H
#define ARMJIT_REGCACHE_H
-#include "ARMJIT.h"
#include "ARMJIT_Internal.h"
#include "Platform.h"
@@ -28,10 +27,11 @@
#include
-namespace ARMJIT
+namespace melonDS
{
using Platform::Log;
using Platform::LogLevel;
+ using namespace Common;
// Imported inside the namespace so that other headers aren't polluted
template
@@ -99,7 +99,7 @@ public:
LiteralsLoaded &= ~(1 << reg);
}
- bool IsLiteral(int reg)
+ bool IsLiteral(int reg) const
{
return LiteralsLoaded & (1 << reg);
}
diff --git a/src/ARMJIT_x64/ARMJIT_ALU.cpp b/src/ARMJIT_x64/ARMJIT_ALU.cpp
index ff307873..69449ff9 100644
--- a/src/ARMJIT_x64/ARMJIT_ALU.cpp
+++ b/src/ARMJIT_x64/ARMJIT_ALU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,10 +17,11 @@
*/
#include "ARMJIT_Compiler.h"
+#include "../ARM.h"
using namespace Gen;
-namespace ARMJIT
+namespace melonDS
{
// uses RSCRATCH3
@@ -128,7 +129,7 @@ OpArg Compiler::A_Comp_GetALUOp2(bool S, bool& carryUsed)
Comp_AddCycles_C();
u32 shift = (CurInstr.Instr >> 7) & 0x1E;
- u32 imm = ::ROR(CurInstr.Instr & 0xFF, shift);
+ u32 imm = melonDS::ROR(CurInstr.Instr & 0xFF, shift);
carryUsed = false;
if (S && shift)
diff --git a/src/ARMJIT_x64/ARMJIT_Branch.cpp b/src/ARMJIT_x64/ARMJIT_Branch.cpp
index 281b24a2..f7a01f48 100644
--- a/src/ARMJIT_x64/ARMJIT_Branch.cpp
+++ b/src/ARMJIT_x64/ARMJIT_Branch.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,10 +17,12 @@
*/
#include "ARMJIT_Compiler.h"
+#include "../ARM.h"
+#include "../NDS.h"
using namespace Gen;
-namespace ARMJIT
+namespace melonDS
{
template
@@ -119,7 +121,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
u32 compileTimePC = CurCPU->R[15];
CurCPU->R[15] = newPC;
- cycles += NDS::ARM7MemTimings[codeCycles][0] + NDS::ARM7MemTimings[codeCycles][1];
+ cycles += NDS.ARM7MemTimings[codeCycles][0] + NDS.ARM7MemTimings[codeCycles][1];
CurCPU->R[15] = compileTimePC;
}
@@ -131,7 +133,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
u32 compileTimePC = CurCPU->R[15];
CurCPU->R[15] = newPC;
- cycles += NDS::ARM7MemTimings[codeCycles][2] + NDS::ARM7MemTimings[codeCycles][3];
+ cycles += NDS.ARM7MemTimings[codeCycles][2] + NDS.ARM7MemTimings[codeCycles][3];
CurCPU->R[15] = compileTimePC;
}
diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.cpp b/src/ARMJIT_x64/ARMJIT_Compiler.cpp
index ce098710..b18837f3 100644
--- a/src/ARMJIT_x64/ARMJIT_Compiler.cpp
+++ b/src/ARMJIT_x64/ARMJIT_Compiler.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -18,7 +18,9 @@
#include "ARMJIT_Compiler.h"
+#include "../ARMJIT.h"
#include "../ARMInterpreter.h"
+#include "../NDS.h"
#include
#include
@@ -33,10 +35,11 @@
#endif
using namespace Gen;
+using namespace Common;
extern "C" void ARM_Ret();
-namespace ARMJIT
+namespace melonDS
{
template <>
const X64Reg RegisterCache::NativeRegAllocOrder[] =
@@ -140,7 +143,7 @@ void Compiler::A_Comp_MSR()
Comp_AddCycles_C();
OpArg val = CurInstr.Instr & (1 << 25)
- ? Imm32(::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)))
+ ? Imm32(melonDS::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)))
: MapReg(CurInstr.A_Reg(0));
u32 mask = 0;
@@ -232,7 +235,7 @@ void Compiler::A_Comp_MSR()
*/
u8 CodeMemory[1024 * 1024 * 32];
-Compiler::Compiler()
+Compiler::Compiler(melonDS::NDS& nds) : XEmitter(), NDS(nds)
{
{
#ifdef _WIN32
@@ -648,7 +651,7 @@ const Compiler::CompileFunc T_Comp[ARMInstrInfo::tk_Count] = {
};
#undef F
-bool Compiler::CanCompile(bool thumb, u16 kind)
+bool Compiler::CanCompile(bool thumb, u16 kind) const
{
return (thumb ? T_Comp[kind] : A_Comp[kind]) != NULL;
}
@@ -664,7 +667,7 @@ void Compiler::Reset()
LoadStorePatches.clear();
}
-bool Compiler::IsJITFault(u8* addr)
+bool Compiler::IsJITFault(const u8* addr)
{
return (u64)addr >= (u64)ResetStart && (u64)addr < (u64)ResetStart + CodeMemSize;
}
@@ -712,12 +715,12 @@ JitBlockEntry Compiler::CompileBlock(ARM* cpu, bool thumb, FetchedInstr instrs[]
if (NearSize - (GetCodePtr() - NearStart) < 1024 * 32) // guess...
{
Log(LogLevel::Debug, "near reset\n");
- ResetBlockCache();
+ NDS.JIT.ResetBlockCache();
}
if (FarSize - (FarCode - FarStart) < 1024 * 32) // guess...
{
Log(LogLevel::Debug, "far reset\n");
- ResetBlockCache();
+ NDS.JIT.ResetBlockCache();
}
ConstantCycles = 0;
@@ -861,7 +864,7 @@ JitBlockEntry Compiler::CompileBlock(ARM* cpu, bool thumb, FetchedInstr instrs[]
void Compiler::Comp_AddCycles_C(bool forceNonConstant)
{
s32 cycles = Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 1 : 3]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 1 : 3]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles);
if ((!Thumb && CurInstr.Cond() < 0xE) || forceNonConstant)
@@ -873,7 +876,7 @@ void Compiler::Comp_AddCycles_C(bool forceNonConstant)
void Compiler::Comp_AddCycles_CI(u32 i)
{
s32 cycles = (Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles)) + i;
if (!Thumb && CurInstr.Cond() < 0xE)
@@ -885,7 +888,7 @@ void Compiler::Comp_AddCycles_CI(u32 i)
void Compiler::Comp_AddCycles_CI(Gen::X64Reg i, int add)
{
s32 cycles = Num ?
- NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
+ NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2]
: ((R15 & 0x2) ? 0 : CurInstr.CodeCycles);
if (!Thumb && CurInstr.Cond() < 0xE)
@@ -910,7 +913,7 @@ void Compiler::Comp_AddCycles_CDI()
s32 cycles;
- s32 numC = NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
+ s32 numC = NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
s32 numD = CurInstr.DataCycles;
if ((CurInstr.DataRegion >> 24) == 0x02) // mainRAM
@@ -955,7 +958,7 @@ void Compiler::Comp_AddCycles_CD()
}
else
{
- s32 numC = NDS::ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
+ s32 numC = NDS.ARM7MemTimings[CurInstr.CodeCycles][Thumb ? 0 : 2];
s32 numD = CurInstr.DataCycles;
if ((CurInstr.DataRegion >> 4) == 0x02)
diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.h b/src/ARMJIT_x64/ARMJIT_Compiler.h
index f5817a92..941d8924 100644
--- a/src/ARMJIT_x64/ARMJIT_Compiler.h
+++ b/src/ARMJIT_x64/ARMJIT_Compiler.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,9 +19,10 @@
#ifndef ARMJIT_X64_COMPILER_H
#define ARMJIT_X64_COMPILER_H
+#if defined(JIT_ENABLED) && defined(__x86_64__)
+
#include "../dolphin/x64Emitter.h"
-#include "../ARMJIT.h"
#include "../ARMJIT_Internal.h"
#include "../ARMJIT_RegisterCache.h"
@@ -31,9 +32,12 @@
#include
-namespace ARMJIT
-{
+namespace melonDS
+{
+class ARMJIT;
+class ARMJIT_Memory;
+class NDS;
const Gen::X64Reg RCPU = Gen::RBP;
const Gen::X64Reg RCPSR = Gen::R15;
@@ -79,7 +83,7 @@ struct Op2
class Compiler : public Gen::XEmitter
{
public:
- Compiler();
+ explicit Compiler(melonDS::NDS& nds);
void Reset();
@@ -88,7 +92,7 @@ public:
void LoadReg(int reg, Gen::X64Reg nativeReg);
void SaveReg(int reg, Gen::X64Reg nativeReg);
- bool CanCompile(bool thumb, u16 kind);
+ bool CanCompile(bool thumb, u16 kind) const;
typedef void (Compiler::*CompileFunc)();
@@ -167,7 +171,7 @@ public:
memop_SubtractOffset = 1 << 4
};
void Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flags);
- s32 Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc, bool decrement, bool usermode, bool skipLoadingRn);
+ s32 Comp_MemAccessBlock(int rn, Common::BitSet16 regs, bool store, bool preinc, bool decrement, bool usermode, bool skipLoadingRn);
bool Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr);
void Comp_ArithTriOp(void (Compiler::*op)(int, const Gen::OpArg&, const Gen::OpArg&),
@@ -230,7 +234,7 @@ public:
SetCodePtr(FarCode);
}
- bool IsJITFault(u8* addr);
+ bool IsJITFault(const u8* addr);
u8* RewriteMemAccess(u8* pc);
@@ -238,44 +242,46 @@ public:
void CreateMethod(const char* namefmt, void* start, ...);
#endif
- u8* FarCode;
- u8* NearCode;
- u32 FarSize;
- u32 NearSize;
+ melonDS::NDS& NDS;
+ u8* FarCode {};
+ u8* NearCode {};
+ u32 FarSize {};
+ u32 NearSize {};
- u8* NearStart;
- u8* FarStart;
+ u8* NearStart {};
+ u8* FarStart {};
- void* PatchedStoreFuncs[2][2][3][16];
- void* PatchedLoadFuncs[2][2][3][2][16];
+ void* PatchedStoreFuncs[2][2][3][16] {};
+ void* PatchedLoadFuncs[2][2][3][2][16] {};
- std::unordered_map LoadStorePatches;
+ std::unordered_map LoadStorePatches {};
- u8* ResetStart;
- u32 CodeMemSize;
+ u8* ResetStart {};
+ u32 CodeMemSize {};
- bool Exit;
- bool IrregularCycles;
+ bool Exit {};
+ bool IrregularCycles {};
- void* ReadBanked;
- void* WriteBanked;
+ void* ReadBanked {};
+ void* WriteBanked {};
bool CPSRDirty = false;
- FetchedInstr CurInstr;
+ FetchedInstr CurInstr {};
- RegisterCache RegCache;
+ RegisterCache RegCache {};
- bool Thumb;
- u32 Num;
- u32 R15;
- u32 CodeRegion;
+ bool Thumb {};
+ u32 Num {};
+ u32 R15 {};
+ u32 CodeRegion {};
- u32 ConstantCycles;
+ u32 ConstantCycles {};
- ARM* CurCPU;
+ ARM* CurCPU {};
};
}
+#endif
#endif
diff --git a/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp b/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
index 0961fdd9..e2a74eee 100644
--- a/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
+++ b/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
@@ -17,7 +17,7 @@
*/
#include "../ARM.h"
-
+using namespace melonDS;
int main(int argc, char* argv[])
{
FILE* f = fopen("ARMJIT_Offsets.h", "w");
diff --git a/src/ARMJIT_x64/ARMJIT_Linkage.S b/src/ARMJIT_x64/ARMJIT_Linkage.S
index fe7b1435..023f6e7b 100644
--- a/src/ARMJIT_x64/ARMJIT_Linkage.S
+++ b/src/ARMJIT_x64/ARMJIT_Linkage.S
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -104,3 +104,8 @@ ARM_Ret:
#endif
ret
+
+#if !defined(__APPLE__) && !defined(WIN64)
+.section .note.GNU-stack,"",@progbits
+#endif
+
diff --git a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
index 99555fff..8520bebc 100644
--- a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
+++ b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,10 +17,12 @@
*/
#include "ARMJIT_Compiler.h"
+#include "../ARMJIT.h"
+#include "../NDS.h"
using namespace Gen;
-namespace ARMJIT
+namespace melonDS
{
template
@@ -67,9 +69,9 @@ u8* Compiler::RewriteMemAccess(u8* pc)
bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
{
- u32 localAddr = LocaliseCodeAddress(Num, addr);
+ u32 localAddr = NDS.JIT.LocaliseCodeAddress(Num, addr);
- int invalidLiteralIdx = InvalidLiterals.Find(localAddr);
+ int invalidLiteralIdx = NDS.JIT.InvalidLiterals.Find(localAddr);
if (invalidLiteralIdx != -1)
{
return false;
@@ -84,7 +86,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
- val = ::ROR(val, (addr & 0x3) << 3);
+ val = melonDS::ROR(val, (addr & 0x3) << 3);
}
else if (size == 16)
{
@@ -117,7 +119,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
if (size == 16)
addressMask = ~1;
- if (LiteralOptimizations && rn == 15 && rd != 15 && op2.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback)))
+ if (NDS.JIT.LiteralOptimizationsEnabled() && rn == 15 && rd != 15 && op2.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback)))
{
u32 addr = R15 + op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1);
@@ -134,7 +136,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
Comp_AddCycles_CDI();
}
- bool addrIsStatic = LiteralOptimizations
+ bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled()
&& RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post));
u32 staticAddress;
if (addrIsStatic)
@@ -195,10 +197,10 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
MOV(32, rnMapped, R(finalAddr));
u32 expectedTarget = Num == 0
- ? ARMJIT_Memory::ClassifyAddress9(CurInstr.DataRegion)
- : ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
+ ? NDS.JIT.Memory.ClassifyAddress9(CurInstr.DataRegion)
+ : NDS.JIT.Memory.ClassifyAddress7(CurInstr.DataRegion);
- if (ARMJIT::FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || ARMJIT_Memory::IsFastmemCompatible(expectedTarget)))
+ if (NDS.JIT.FastMemoryEnabled() && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget)))
{
if (rdMapped.IsImm())
{
@@ -211,12 +213,12 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
assert(rdMapped.GetSimpleReg() >= 0 && rdMapped.GetSimpleReg() < 16);
patch.PatchFunc = flags & memop_Store
- ? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
- : PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];
+ ? PatchedStoreFuncs[NDS.ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
+ : PatchedLoadFuncs[NDS.ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];
assert(patch.PatchFunc != NULL);
- MOV(64, R(RSCRATCH), ImmPtr(Num == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start));
+ MOV(64, R(RSCRATCH), ImmPtr(Num == 0 ? NDS.JIT.Memory.FastMem9Start : NDS.JIT.Memory.FastMem7Start));
X64Reg maskedAddr = RSCRATCH3;
if (size > 8)
@@ -267,7 +269,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
void* func = NULL;
if (addrIsStatic)
- func = ARMJIT_Memory::GetFuncForAddr(CurCPU, staticAddress, flags & memop_Store, size);
+ func = NDS.JIT.Memory.GetFuncForAddr(CurCPU, staticAddress, flags & memop_Store, size);
if (func)
{
@@ -312,7 +314,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
if (flags & memop_Store)
{
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: CALL((void*)&SlowWrite9); break;
case 16: CALL((void*)&SlowWrite9); break;
@@ -324,7 +326,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
}
else
{
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: CALL((void*)&SlowRead9); break;
case 16: CALL((void*)&SlowRead9); break;
@@ -343,7 +345,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
{
MOV(32, R(ABI_PARAM2), rdMapped);
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: CALL((void*)&SlowWrite7); break;
case 16: CALL((void*)&SlowWrite7); break;
@@ -355,7 +357,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
}
else
{
- switch (size | NDS::ConsoleType)
+ switch (size | NDS.ConsoleType)
{
case 32: CALL((void*)&SlowRead7); break;
case 16: CALL((void*)&SlowRead7); break;
@@ -421,16 +423,16 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
s32 offset = (regsCount * 4) * (decrement ? -1 : 1);
int expectedTarget = Num == 0
- ? ARMJIT_Memory::ClassifyAddress9(CurInstr.DataRegion)
- : ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
+ ? NDS.JIT.Memory.ClassifyAddress9(CurInstr.DataRegion)
+ : NDS.JIT.Memory.ClassifyAddress7(CurInstr.DataRegion);
if (!store)
Comp_AddCycles_CDI();
else
Comp_AddCycles_CD();
- bool compileFastPath = FastMemory
- && !usermode && (CurInstr.Cond() < 0xE || ARMJIT_Memory::IsFastmemCompatible(expectedTarget));
+ bool compileFastPath = NDS.JIT.FastMemoryEnabled()
+ && !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget));
// we need to make sure that the stack stays aligned to 16 bytes
#ifdef _WIN32
@@ -453,7 +455,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
u8* fastPathStart = GetWritableCodePtr();
u8* loadStoreAddr[16];
- MOV(64, R(RSCRATCH2), ImmPtr(Num == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start));
+ MOV(64, R(RSCRATCH2), ImmPtr(Num == 0 ? NDS.JIT.Memory.FastMem9Start : NDS.JIT.Memory.FastMem7Start));
ADD(64, R(RSCRATCH2), R(RSCRATCH4));
u32 offset = 0;
@@ -522,7 +524,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
if (Num == 0)
MOV(64, R(ABI_PARAM4), R(RCPU));
- switch (Num * 2 | NDS::ConsoleType)
+ switch (Num * 2 | NDS.ConsoleType)
{
case 0: CALL((void*)&SlowBlockTransfer9); break;
case 1: CALL((void*)&SlowBlockTransfer9); break;
@@ -626,7 +628,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
if (Num == 0)
MOV(64, R(ABI_PARAM4), R(RCPU));
- switch (Num * 2 | NDS::ConsoleType)
+ switch (Num * 2 | NDS.ConsoleType)
{
case 0: CALL((void*)&SlowBlockTransfer9); break;
case 1: CALL((void*)&SlowBlockTransfer9); break;
@@ -807,7 +809,7 @@ void Compiler::T_Comp_LoadPCRel()
{
u32 offset = (CurInstr.Instr & 0xFF) << 2;
u32 addr = (R15 & ~0x2) + offset;
- if (!LiteralOptimizations || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr))
+ if (!NDS.JIT.LiteralOptimizationsEnabled() || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr))
Comp_MemAccess(CurInstr.T_Reg(8), 15, Op2(offset), 32, 0);
}
diff --git a/src/ARM_InstrInfo.cpp b/src/ARM_InstrInfo.cpp
index a7171ba0..d53c88f0 100644
--- a/src/ARM_InstrInfo.cpp
+++ b/src/ARM_InstrInfo.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -22,7 +22,7 @@
#include "ARMJIT.h"
-namespace ARMInstrInfo
+namespace melonDS::ARMInstrInfo
{
#define ak(x) ((x) << 23)
@@ -315,7 +315,7 @@ const u32 T_SVC = T_BranchAlways | T_WriteR14 | tk(tk_SVC);
#include "ARM_InstrTable.h"
#undef INSTRFUNC_PROTO
-Info Decode(bool thumb, u32 num, u32 instr)
+Info Decode(bool thumb, u32 num, u32 instr, bool literaloptimizations)
{
const u8 FlagsReadPerCond[7] = {
flag_Z,
@@ -386,7 +386,7 @@ Info Decode(bool thumb, u32 num, u32 instr)
{
if (res.Kind == tk_LDR_PCREL)
{
- if (!ARMJIT::LiteralOptimizations)
+ if (!literaloptimizations)
res.SrcRegs |= 1 << 15;
res.SpecialKind = special_LoadLiteral;
}
diff --git a/src/ARM_InstrInfo.h b/src/ARM_InstrInfo.h
index 0104027f..13f66b09 100644
--- a/src/ARM_InstrInfo.h
+++ b/src/ARM_InstrInfo.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -21,7 +21,7 @@
#include "types.h"
-namespace ARMInstrInfo
+namespace melonDS::ARMInstrInfo
{
// Instruction kinds, for faster dispatch
@@ -274,7 +274,7 @@ struct Info
}
};
-Info Decode(bool thumb, u32 num, u32 instr);
+Info Decode(bool thumb, u32 num, u32 instr, bool literaloptimizations);
}
diff --git a/src/ARM_InstrTable.h b/src/ARM_InstrTable.h
index e4b29061..7cdad66d 100644
--- a/src/ARM_InstrTable.h
+++ b/src/ARM_InstrTable.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
diff --git a/src/Args.h b/src/Args.h
new file mode 100644
index 00000000..0b20bbf0
--- /dev/null
+++ b/src/Args.h
@@ -0,0 +1,152 @@
+/*
+ Copyright 2016-2023 melonDS team
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef MELONDS_ARGS_H
+#define MELONDS_ARGS_H
+
+#include
+#include
+#include
+
+#include "NDSCart.h"
+#include "GBACart.h"
+#include "types.h"
+#include "MemConstants.h"
+#include "DSi_NAND.h"
+#include "FATStorage.h"
+#include "FreeBIOS.h"
+#include "GPU3D_Soft.h"
+#include "SPI_Firmware.h"
+#include "SPU.h"
+
+namespace melonDS
+{
+namespace NDSCart { class CartCommon; }
+namespace GBACart { class CartCommon; }
+
+template
+constexpr std::array BrokenBIOS = []() constexpr {
+ std::array broken {};
+
+ for (int i = 0; i < 16; i++)
+ {
+ broken[i*4+0] = 0xE7;
+ broken[i*4+1] = 0xFF;
+ broken[i*4+2] = 0xDE;
+ broken[i*4+3] = 0xFF;
+ }
+
+ return broken;
+}();
+
+/// Arguments that configure the JIT.
+/// Ignored in builds that don't have the JIT included.
+struct JITArgs
+{
+ unsigned MaxBlockSize = 32;
+ bool LiteralOptimizations = true;
+ bool BranchOptimizations = true;
+
+ /// Ignored in builds that have fast memory excluded
+ /// (even if the JIT is otherwise available).
+ /// Enabled by default, but frontends should disable this when debugging
+ /// so the constants segfaults don't hinder debugging.
+ bool FastMemory = true;
+};
+
+using ARM9BIOSImage = std::array;
+using ARM7BIOSImage = std::array;
+using DSiBIOSImage = std::array;
+
+struct GDBArgs
+{
+ u16 PortARM7 = 0;
+ u16 PortARM9 = 0;
+ bool ARM7BreakOnStartup = false;
+ bool ARM9BreakOnStartup = false;
+};
+
+/// Arguments to pass into the NDS constructor.
+/// New fields here should have default values if possible.
+struct NDSArgs
+{
+ /// NDS ROM to install.
+ /// Defaults to nullptr, which means no cart.
+ /// Should be populated with the desired save data beforehand,
+ /// including an SD card if applicable.
+ std::unique_ptr NDSROM = nullptr;
+
+ /// GBA ROM to install.
+ /// Defaults to nullptr, which means no cart.
+ /// Should be populated with the desired save data beforehand.
+ /// Ignored in DSi mode.
+ std::unique_ptr GBAROM = nullptr;
+
+ /// NDS ARM9 BIOS to install.
+ /// Defaults to FreeBIOS, which is not compatible with DSi mode.
+ std::unique_ptr ARM9BIOS = std::make_unique(bios_arm9_bin);
+
+ /// NDS ARM7 BIOS to install.
+ /// Defaults to FreeBIOS, which is not compatible with DSi mode.
+ std::unique_ptr ARM7BIOS = std::make_unique(bios_arm7_bin);
+
+ /// Firmware image to install.
+ /// Defaults to generated NDS firmware.
+ /// Generated firmware is not compatible with DSi mode.
+ melonDS::Firmware Firmware {0};
+
+ /// How the JIT should be configured when initializing.
+ /// Defaults to enabled, with default settings.
+ /// To disable the JIT, set this to std::nullopt.
+ /// Ignored in builds that don't have the JIT included.
+ std::optional JIT = JITArgs();
+
+ AudioBitDepth BitDepth = AudioBitDepth::Auto;
+ AudioInterpolation Interpolation = AudioInterpolation::None;
+
+ /// How the GDB stub should be handled.
+ /// Defaults to disabled.
+ /// Ignored in builds that don't have the GDB stub included.
+ std::optional GDB = std::nullopt;
+
+ /// The 3D renderer to initialize the DS with.
+ /// Defaults to the software renderer.
+ /// Can be changed later at any time.
+ std::unique_ptr Renderer3D = std::make_unique();
+};
+
+/// Arguments to pass into the DSi constructor.
+/// New fields here should have default values if possible.
+/// Contains no virtual methods, so there's no vtable.
+struct DSiArgs final : public NDSArgs
+{
+ std::unique_ptr ARM9iBIOS = std::make_unique(BrokenBIOS);
+ std::unique_ptr ARM7iBIOS = std::make_unique(BrokenBIOS);
+
+ /// NAND image to install.
+ /// Required, there is no default value.
+ DSi_NAND::NANDImage NANDImage;
+
+ /// SD card to install.
+ /// Defaults to std::nullopt, which means no SD card.
+ std::optional DSiSDCard;
+
+ bool FullBIOSBoot = false;
+};
+}
+#endif //MELONDS_ARGS_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 250aef94..50cd7708 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,7 @@ add_library(core STATIC
CRC32.cpp
DMA.cpp
DMA_Timings.h
+ DMA_Timings.cpp
DSi.cpp
DSi_AES.cpp
DSi_Camera.cpp
@@ -25,6 +26,7 @@ add_library(core STATIC
DSi_NWifi.cpp
DSi_SD.cpp
DSi_SPI_TSC.cpp
+ FATIO.cpp
FATStorage.cpp
FIFO.h
GBACart.cpp
@@ -38,6 +40,7 @@ add_library(core STATIC
melonDLDI.h
NDS.cpp
NDSCart.cpp
+ NDSCartR4.cpp
Platform.h
ROMList.h
ROMList.cpp
@@ -49,11 +52,11 @@ add_library(core STATIC
SPI_Firmware.cpp
SPU.cpp
types.h
- version.h
+ Utils.cpp
+ Utils.h
Wifi.cpp
WifiAP.cpp
- fatfs/diskio.c
fatfs/ff.c
fatfs/ffsystem.c
fatfs/ffunicode.c
@@ -63,6 +66,15 @@ add_library(core STATIC
tiny-AES-c/aes.c
xxhash/xxhash.c)
+if (ENABLE_GDBSTUB)
+ message(NOTICE "Enabling GDB stub")
+ target_sources(core PRIVATE
+ debug/GdbStub.cpp
+ debug/GdbProto.cpp
+ debug/GdbCmds.cpp
+ )
+endif()
+
if (ENABLE_OGLRENDERER)
target_sources(core PRIVATE
GPU_OpenGL.cpp
@@ -115,11 +127,26 @@ if (ENABLE_JIT)
endif()
endif()
+set(MELONDS_VERSION_SUFFIX "$ENV{MELONDS_VERSION_SUFFIX}" CACHE STRING "Suffix to add to displayed melonDS version")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/version.h")
+target_sources(core PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/version.h")
+target_include_directories(core PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
+
add_subdirectory(teakra EXCLUDE_FROM_ALL)
# Workaround for building teakra with -O0 on Windows either failing or hanging forever
target_compile_options(teakra PRIVATE "$<$:-Og>")
target_link_libraries(core PRIVATE teakra)
+if (NOT MSVC)
+ # MSVC has its own compiler flag syntax; if we ever support it,
+ # be sure to silence any equivalent warnings there.
+
+ target_compile_options(core PRIVATE "$<$:-Wno-invalid-offsetof>")
+ # These warnings are excessive, and are only triggered in the ARMJIT code
+ # (which is fundamentally non-portable, so this is fine)
+endif()
+
find_library(m MATH_LIBRARY)
if (MATH_LIBRARY)
@@ -136,15 +163,28 @@ if (ENABLE_JIT)
endif()
if (WIN32)
- target_link_libraries(core PRIVATE ole32 comctl32 ws2_32)
-elseif(NOT APPLE)
+ target_link_libraries(core PRIVATE ole32 comctl32 wsock32 ws2_32)
+elseif(NOT APPLE AND NOT HAIKU)
check_library_exists(rt shm_open "" NEED_LIBRT)
if (NEED_LIBRT)
target_link_libraries(core PRIVATE rt)
endif()
+elseif(HAIKU)
+ target_link_libraries(core PRIVATE network)
endif()
if (ENABLE_JIT_PROFILING)
target_include_directories(core PRIVATE "${VTUNE_INCLUDE_DIR}")
target_link_libraries(core PRIVATE "${VTUNE_LIBRARY}")
endif()
+
+#if(CMAKE_BUILD_TYPE MATCHES "Debug")
+# set(
+# CMAKE_C_FLAGS
+# "${CMAKE_C_FLAGS} -fsanitize=undefined -fsanitize=address"
+# )
+# target_link_options(core
+# BEFORE PUBLIC -fsanitize=undefined PUBLIC -fsanitize=address
+# )
+#endif()
+
diff --git a/src/CP15.cpp b/src/CP15.cpp
index 52fd5604..5e5b35ea 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -22,12 +22,11 @@
#include "DSi.h"
#include "ARM.h"
#include "Platform.h"
-
-#ifdef JIT_ENABLED
-#include "ARMJIT.h"
#include "ARMJIT_Memory.h"
-#endif
+#include "ARMJIT.h"
+namespace melonDS
+{
using Platform::Log;
using Platform::LogLevel;
@@ -125,9 +124,7 @@ void ARMv5::UpdateDTCMSetting()
if (newDTCMBase != DTCMBase || newDTCMMask != DTCMMask)
{
-#ifdef JIT_ENABLED
- ARMJIT_Memory::RemapDTCM(newDTCMBase, newDTCMSize);
-#endif
+ NDS.JIT.Memory.RemapDTCM(newDTCMBase, newDTCMSize);
DTCMBase = newDTCMBase;
DTCMMask = newDTCMMask;
}
@@ -189,10 +186,14 @@ void ARMv5::UpdatePURegion(u32 n)
return;
}
- u32 start = rgn >> 12;
- u32 sz = 2 << ((rgn >> 1) & 0x1F);
- u32 end = start + (sz >> 12);
- // TODO: check alignment of start
+ // notes:
+ // * min size of a pu region is 4KiB (12 bits)
+ // * size is calculated as size + 1, but the 12 lsb of address space are ignored, therefore we need it as size + 1 - 12, or size - 11
+ // * pu regions are aligned based on their size
+ u32 size = std::max((int)((rgn>>1) & 0x1F) - 11, 0); // obtain the size, subtract 11 and clamp to a min of 0.
+ u32 start = ((rgn >> 12) >> size) << size; // determine the start offset, and use shifts to force alignment with a multiple of the size.
+ u32 end = start + (1<> 2];
+ u8* bustimings = NDS.ARM9MemTimings[i >> 2];
if (pu & 0x40)
{
@@ -306,7 +307,7 @@ void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend)
}
else
{
- MemTimings[i][0] = bustimings[2] << NDS::ARM9ClockShift;
+ MemTimings[i][0] = bustimings[2] << NDS.ARM9ClockShift;
}
if (pu & 0x10)
@@ -317,9 +318,9 @@ void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend)
}
else
{
- MemTimings[i][1] = bustimings[0] << NDS::ARM9ClockShift;
- MemTimings[i][2] = bustimings[2] << NDS::ARM9ClockShift;
- MemTimings[i][3] = bustimings[3] << NDS::ARM9ClockShift;
+ MemTimings[i][1] = bustimings[0] << NDS.ARM9ClockShift;
+ MemTimings[i][2] = bustimings[2] << NDS.ARM9ClockShift;
+ MemTimings[i][3] = bustimings[3] << NDS.ARM9ClockShift;
}
}
}
@@ -391,14 +392,14 @@ void ARMv5::ICacheLookup(u32 addr)
else
{
for (int i = 0; i < 32; i+=4)
- *(u32*)&ptr[i] = NDS::ARM9Read32(addr+i);
+ *(u32*)&ptr[i] = NDS.ARM9Read32(addr+i);
}
ICacheTags[line] = tag;
// ouch :/
//printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]);
- CodeCycles = (NDS::ARM9MemTimings[addr >> 14][2] + (NDS::ARM9MemTimings[addr >> 14][3] * 7)) << NDS::ARM9ClockShift;
+ CodeCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * 7)) << NDS.ARM9ClockShift;
CurICacheLine = ptr;
}
@@ -582,12 +583,12 @@ void ARMv5::CP15Write(u32 id, u32 val)
std::snprintf(log_output,
sizeof(log_output),
- "PU: region %d = %08X : %s, %08X-%08X\n",
+ "PU: region %d = %08X : %s, start: %08X size: %02X\n",
(id >> 4) & 0xF,
val,
val & 1 ? "enabled" : "disabled",
val & 0xFFFFF000,
- (val & 0xFFFFF000) + (2 << ((val & 0x3E) >> 1))
+ (val & 0x3E) >> 1
);
Log(LogLevel::Debug, "%s", log_output);
// Some implementations of Log imply a newline, so we build up the line before printing it
@@ -671,7 +672,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val);
}
-u32 ARMv5::CP15Read(u32 id)
+u32 ARMv5::CP15Read(u32 id) const
{
//printf("CP15 read op %03X %08X\n", id, NDS::ARM9->R[15]);
@@ -926,9 +927,7 @@ void ARMv5::DataWrite8(u32 addr, u8 val)
{
DataCycles = 1;
*(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
-#endif
+ NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
return;
}
if ((addr & DTCMMask) == DTCMBase)
@@ -958,9 +957,7 @@ void ARMv5::DataWrite16(u32 addr, u16 val)
{
DataCycles = 1;
*(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
-#endif
+ NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
return;
}
if ((addr & DTCMMask) == DTCMBase)
@@ -990,9 +987,7 @@ void ARMv5::DataWrite32(u32 addr, u32 val)
{
DataCycles = 1;
*(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
-#endif
+ NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
return;
}
if ((addr & DTCMMask) == DTCMBase)
@@ -1015,7 +1010,7 @@ void ARMv5::DataWrite32S(u32 addr, u32 val)
DataCycles += 1;
*(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
+ NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
#endif
return;
}
@@ -1030,7 +1025,7 @@ void ARMv5::DataWrite32S(u32 addr, u32 val)
DataCycles += MemTimings[addr >> 12][3];
}
-void ARMv5::GetCodeMemRegion(u32 addr, NDS::MemRegion* region)
+void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region)
{
/*if (addr < ITCMSize)
{
@@ -1039,6 +1034,7 @@ void ARMv5::GetCodeMemRegion(u32 addr, NDS::MemRegion* region)
return;
}*/
- GetMemRegion(addr, false, &CodeMem);
+ NDS.ARM9GetMemRegion(addr, false, &CodeMem);
}
+}
diff --git a/src/CRC32.cpp b/src/CRC32.cpp
index 4dec9595..0756c034 100644
--- a/src/CRC32.cpp
+++ b/src/CRC32.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -20,6 +20,8 @@
// http://www.codeproject.com/KB/recipes/crc32_large.aspx
+namespace melonDS
+{
constexpr u32 _reflect(u32 refl, char ch)
{
u32 value = 0;
@@ -62,3 +64,5 @@ u32 CRC32(const u8 *data, int len, u32 start)
return (crc ^ 0xFFFFFFFF);
}
+
+}
\ No newline at end of file
diff --git a/src/CRC32.h b/src/CRC32.h
index 133cf51d..11879057 100644
--- a/src/CRC32.h
+++ b/src/CRC32.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -23,6 +23,9 @@
#include "types.h"
+namespace melonDS
+{
u32 CRC32(const u8* data, int len, u32 start=0);
+}
#endif // CRC32_H
diff --git a/src/DMA.cpp b/src/DMA.cpp
index 7d54b413..0fc6cf05 100644
--- a/src/DMA.cpp
+++ b/src/DMA.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -25,6 +25,8 @@
#include "DMA_Timings.h"
#include "Platform.h"
+namespace melonDS
+{
using Platform::Log;
using Platform::LogLevel;
@@ -48,21 +50,17 @@ using Platform::LogLevel;
// TODO: timings are nonseq when address is fixed/decrementing
-DMA::DMA(u32 cpu, u32 num)
+DMA::DMA(u32 cpu, u32 num, melonDS::NDS& nds) :
+ CPU(cpu),
+ Num(num),
+ NDS(nds)
{
- CPU = cpu;
- Num = num;
-
if (cpu == 0)
CountMask = 0x001FFFFF;
else
CountMask = (num==3 ? 0x0000FFFF : 0x00003FFF);
}
-DMA::~DMA()
-{
-}
-
void DMA::Reset()
{
SrcAddr = 0;
@@ -83,6 +81,7 @@ void DMA::Reset()
Executing = false;
InProgress = false;
MRAMBurstCount = 0;
+ MRAMBurstTable = DMATiming::MRAMDummy;
}
void DMA::DoSavestate(Savestate* file)
@@ -107,6 +106,10 @@ void DMA::DoSavestate(Savestate* file)
file->Bool32(&InProgress);
file->Bool32(&IsGXFIFODMA);
file->Var32(&MRAMBurstCount);
+ file->Bool32(&Executing);
+ file->Bool32(&Stall);
+
+ file->VarArray(MRAMBurstTable.data(), sizeof(MRAMBurstTable));
}
void DMA::WriteCnt(u32 val)
@@ -143,7 +146,7 @@ void DMA::WriteCnt(u32 val)
if ((StartMode & 0x7) == 0)
Start();
else if (StartMode == 0x07)
- GPU3D::CheckFIFODMA();
+ NDS.GPU.GPU3D.CheckFIFODMA();
if (StartMode==0x06 || StartMode==0x13)
Log(LogLevel::Warn, "UNIMPLEMENTED ARM%d DMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr);
@@ -190,7 +193,7 @@ void DMA::Start()
MRAMBurstTable = DMATiming::MRAMDummy;
InProgress = true;
- NDS::StopCPU(CPU, 1<> 14;
u32 dst_id = CurDstAddr >> 14;
- u32 src_rgn = NDS::ARM9Regions[src_id];
- u32 dst_rgn = NDS::ARM9Regions[dst_id];
+ u32 src_rgn = NDS.ARM9Regions[src_id];
+ u32 dst_rgn = NDS.ARM9Regions[dst_id];
u32 src_n, src_s, dst_n, dst_s;
- src_n = NDS::ARM9MemTimings[src_id][4];
- src_s = NDS::ARM9MemTimings[src_id][5];
- dst_n = NDS::ARM9MemTimings[dst_id][4];
- dst_s = NDS::ARM9MemTimings[dst_id][5];
+ src_n = NDS.ARM9MemTimings[src_id][4];
+ src_s = NDS.ARM9MemTimings[src_id][5];
+ dst_n = NDS.ARM9MemTimings[dst_id][4];
+ dst_s = NDS.ARM9MemTimings[dst_id][5];
- if (src_rgn == NDS::Mem9_MainRAM)
+ if (src_rgn == Mem9_MainRAM)
{
- if (dst_rgn == NDS::Mem9_MainRAM)
+ if (dst_rgn == Mem9_MainRAM)
return 16;
if (SrcAddrInc > 0)
@@ -218,7 +221,7 @@ u32 DMA::UnitTimings9_16(bool burststart)
{
MRAMBurstCount = 0;
- if (dst_rgn == NDS::Mem9_GBAROM)
+ if (dst_rgn == Mem9_GBAROM)
{
if (dst_s == 4)
MRAMBurstTable = DMATiming::MRAMRead16Bursts[1];
@@ -239,7 +242,7 @@ u32 DMA::UnitTimings9_16(bool burststart)
(burststart ? dst_n : dst_s);
}
}
- else if (dst_rgn == NDS::Mem9_MainRAM)
+ else if (dst_rgn == Mem9_MainRAM)
{
if (DstAddrInc > 0)
{
@@ -247,7 +250,7 @@ u32 DMA::UnitTimings9_16(bool burststart)
{
MRAMBurstCount = 0;
- if (src_rgn == NDS::Mem9_GBAROM)
+ if (src_rgn == Mem9_GBAROM)
{
if (src_s == 4)
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1];
@@ -284,18 +287,18 @@ u32 DMA::UnitTimings9_32(bool burststart)
u32 src_id = CurSrcAddr >> 14;
u32 dst_id = CurDstAddr >> 14;
- u32 src_rgn = NDS::ARM9Regions[src_id];
- u32 dst_rgn = NDS::ARM9Regions[dst_id];
+ u32 src_rgn = NDS.ARM9Regions[src_id];
+ u32 dst_rgn = NDS.ARM9Regions[dst_id];
u32 src_n, src_s, dst_n, dst_s;
- src_n = NDS::ARM9MemTimings[src_id][6];
- src_s = NDS::ARM9MemTimings[src_id][7];
- dst_n = NDS::ARM9MemTimings[dst_id][6];
- dst_s = NDS::ARM9MemTimings[dst_id][7];
+ src_n = NDS.ARM9MemTimings[src_id][6];
+ src_s = NDS.ARM9MemTimings[src_id][7];
+ dst_n = NDS.ARM9MemTimings[dst_id][6];
+ dst_s = NDS.ARM9MemTimings[dst_id][7];
- if (src_rgn == NDS::Mem9_MainRAM)
+ if (src_rgn == Mem9_MainRAM)
{
- if (dst_rgn == NDS::Mem9_MainRAM)
+ if (dst_rgn == Mem9_MainRAM)
return 18;
if (SrcAddrInc > 0)
@@ -304,7 +307,7 @@ u32 DMA::UnitTimings9_32(bool burststart)
{
MRAMBurstCount = 0;
- if (dst_rgn == NDS::Mem9_GBAROM)
+ if (dst_rgn == Mem9_GBAROM)
{
if (dst_s == 8)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
@@ -327,7 +330,7 @@ u32 DMA::UnitTimings9_32(bool burststart)
(burststart ? dst_n : dst_s);
}
}
- else if (dst_rgn == NDS::Mem9_MainRAM)
+ else if (dst_rgn == Mem9_MainRAM)
{
if (DstAddrInc > 0)
{
@@ -335,7 +338,7 @@ u32 DMA::UnitTimings9_32(bool burststart)
{
MRAMBurstCount = 0;
- if (src_rgn == NDS::Mem9_GBAROM)
+ if (src_rgn == Mem9_GBAROM)
{
if (src_s == 8)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
@@ -376,18 +379,18 @@ u32 DMA::UnitTimings7_16(bool burststart)
u32 src_id = CurSrcAddr >> 15;
u32 dst_id = CurDstAddr >> 15;
- u32 src_rgn = NDS::ARM7Regions[src_id];
- u32 dst_rgn = NDS::ARM7Regions[dst_id];
+ u32 src_rgn = NDS.ARM7Regions[src_id];
+ u32 dst_rgn = NDS.ARM7Regions[dst_id];
u32 src_n, src_s, dst_n, dst_s;
- src_n = NDS::ARM7MemTimings[src_id][0];
- src_s = NDS::ARM7MemTimings[src_id][1];
- dst_n = NDS::ARM7MemTimings[dst_id][0];
- dst_s = NDS::ARM7MemTimings[dst_id][1];
+ src_n = NDS.ARM7MemTimings[src_id][0];
+ src_s = NDS.ARM7MemTimings[src_id][1];
+ dst_n = NDS.ARM7MemTimings[dst_id][0];
+ dst_s = NDS.ARM7MemTimings[dst_id][1];
- if (src_rgn == NDS::Mem7_MainRAM)
+ if (src_rgn == Mem7_MainRAM)
{
- if (dst_rgn == NDS::Mem7_MainRAM)
+ if (dst_rgn == Mem7_MainRAM)
return 16;
if (SrcAddrInc > 0)
@@ -396,7 +399,7 @@ u32 DMA::UnitTimings7_16(bool burststart)
{
MRAMBurstCount = 0;
- if (dst_rgn == NDS::Mem7_GBAROM || dst_rgn == NDS::Mem7_Wifi0 || dst_rgn == NDS::Mem7_Wifi1)
+ if (dst_rgn == Mem7_GBAROM || dst_rgn == Mem7_Wifi0 || dst_rgn == Mem7_Wifi1)
{
if (dst_s == 4)
MRAMBurstTable = DMATiming::MRAMRead16Bursts[1];
@@ -417,7 +420,7 @@ u32 DMA::UnitTimings7_16(bool burststart)
(burststart ? dst_n : dst_s);
}
}
- else if (dst_rgn == NDS::Mem7_MainRAM)
+ else if (dst_rgn == Mem7_MainRAM)
{
if (DstAddrInc > 0)
{
@@ -425,7 +428,7 @@ u32 DMA::UnitTimings7_16(bool burststart)
{
MRAMBurstCount = 0;
- if (src_rgn == NDS::Mem7_GBAROM || src_rgn == NDS::Mem7_Wifi0 || src_rgn == NDS::Mem7_Wifi1)
+ if (src_rgn == Mem7_GBAROM || src_rgn == Mem7_Wifi0 || src_rgn == Mem7_Wifi1)
{
if (src_s == 4)
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1];
@@ -462,18 +465,18 @@ u32 DMA::UnitTimings7_32(bool burststart)
u32 src_id = CurSrcAddr >> 15;
u32 dst_id = CurDstAddr >> 15;
- u32 src_rgn = NDS::ARM7Regions[src_id];
- u32 dst_rgn = NDS::ARM7Regions[dst_id];
+ u32 src_rgn = NDS.ARM7Regions[src_id];
+ u32 dst_rgn = NDS.ARM7Regions[dst_id];
u32 src_n, src_s, dst_n, dst_s;
- src_n = NDS::ARM7MemTimings[src_id][2];
- src_s = NDS::ARM7MemTimings[src_id][3];
- dst_n = NDS::ARM7MemTimings[dst_id][2];
- dst_s = NDS::ARM7MemTimings[dst_id][3];
+ src_n = NDS.ARM7MemTimings[src_id][2];
+ src_s = NDS.ARM7MemTimings[src_id][3];
+ dst_n = NDS.ARM7MemTimings[dst_id][2];
+ dst_s = NDS.ARM7MemTimings[dst_id][3];
- if (src_rgn == NDS::Mem7_MainRAM)
+ if (src_rgn == Mem7_MainRAM)
{
- if (dst_rgn == NDS::Mem7_MainRAM)
+ if (dst_rgn == Mem7_MainRAM)
return 18;
if (SrcAddrInc > 0)
@@ -482,7 +485,7 @@ u32 DMA::UnitTimings7_32(bool burststart)
{
MRAMBurstCount = 0;
- if (dst_rgn == NDS::Mem7_GBAROM || dst_rgn == NDS::Mem7_Wifi0 || dst_rgn == NDS::Mem7_Wifi1)
+ if (dst_rgn == Mem7_GBAROM || dst_rgn == Mem7_Wifi0 || dst_rgn == Mem7_Wifi1)
{
if (dst_s == 8)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
@@ -505,7 +508,7 @@ u32 DMA::UnitTimings7_32(bool burststart)
(burststart ? dst_n : dst_s);
}
}
- else if (dst_rgn == NDS::Mem7_MainRAM)
+ else if (dst_rgn == Mem7_MainRAM)
{
if (DstAddrInc > 0)
{
@@ -513,7 +516,7 @@ u32 DMA::UnitTimings7_32(bool burststart)
{
MRAMBurstCount = 0;
- if (src_rgn == NDS::Mem7_GBAROM || src_rgn == NDS::Mem7_Wifi0 || src_rgn == NDS::Mem7_Wifi1)
+ if (src_rgn == Mem7_GBAROM || src_rgn == Mem7_Wifi0 || src_rgn == Mem7_Wifi1)
{
if (src_s == 8)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
@@ -547,10 +550,9 @@ u32 DMA::UnitTimings7_32(bool burststart)
}
}
-template
void DMA::Run9()
{
- if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+ if (NDS.ARM9Timestamp >= NDS.ARM9Target) return;
Executing = true;
@@ -562,40 +564,34 @@ void DMA::Run9()
{
while (IterCount > 0 && !Stall)
{
- NDS::ARM9Timestamp += (UnitTimings9_16(burststart) << NDS::ARM9ClockShift);
+ NDS.ARM9Timestamp += (UnitTimings9_16(burststart) << NDS.ARM9ClockShift);
burststart = false;
- if (ConsoleType == 1)
- DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr));
- else
- NDS::ARM9Write16(CurDstAddr, NDS::ARM9Read16(CurSrcAddr));
+ NDS.ARM9Write16(CurDstAddr, NDS.ARM9Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
IterCount--;
RemCount--;
- if (NDS::ARM9Timestamp >= NDS::ARM9Target) break;
+ if (NDS.ARM9Timestamp >= NDS.ARM9Target) break;
}
}
else
{
while (IterCount > 0 && !Stall)
{
- NDS::ARM9Timestamp += (UnitTimings9_32(burststart) << NDS::ARM9ClockShift);
+ NDS.ARM9Timestamp += (UnitTimings9_32(burststart) << NDS.ARM9ClockShift);
burststart = false;
- if (ConsoleType == 1)
- DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
- else
- NDS::ARM9Write32(CurDstAddr, NDS::ARM9Read32(CurSrcAddr));
+ NDS.ARM9Write32(CurDstAddr, NDS.ARM9Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
IterCount--;
RemCount--;
- if (NDS::ARM9Timestamp >= NDS::ARM9Target) break;
+ if (NDS.ARM9Timestamp >= NDS.ARM9Target) break;
}
}
@@ -607,10 +603,10 @@ void DMA::Run9()
if (IterCount == 0)
{
Running = 0;
- NDS::ResumeCPU(0, 1<
void DMA::Run7()
{
- if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+ if (NDS.ARM7Timestamp >= NDS.ARM7Target) return;
Executing = true;
@@ -642,40 +637,34 @@ void DMA::Run7()
{
while (IterCount > 0 && !Stall)
{
- NDS::ARM7Timestamp += UnitTimings7_16(burststart);
+ NDS.ARM7Timestamp += UnitTimings7_16(burststart);
burststart = false;
- if (ConsoleType == 1)
- DSi::ARM7Write16(CurDstAddr, DSi::ARM7Read16(CurSrcAddr));
- else
- NDS::ARM7Write16(CurDstAddr, NDS::ARM7Read16(CurSrcAddr));
+ NDS.ARM7Write16(CurDstAddr, NDS.ARM7Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
IterCount--;
RemCount--;
- if (NDS::ARM7Timestamp >= NDS::ARM7Target) break;
+ if (NDS.ARM7Timestamp >= NDS.ARM7Target) break;
}
}
else
{
while (IterCount > 0 && !Stall)
{
- NDS::ARM7Timestamp += UnitTimings7_32(burststart);
+ NDS.ARM7Timestamp += UnitTimings7_32(burststart);
burststart = false;
- if (ConsoleType == 1)
- DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
- else
- NDS::ARM7Write32(CurDstAddr, NDS::ARM7Read32(CurSrcAddr));
+ NDS.ARM7Write32(CurDstAddr, NDS.ARM7Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
IterCount--;
RemCount--;
- if (NDS::ARM7Timestamp >= NDS::ARM7Target) break;
+ if (NDS.ARM7Timestamp >= NDS.ARM7Target) break;
}
}
@@ -687,7 +676,7 @@ void DMA::Run7()
if (IterCount == 0)
{
Running = 0;
- NDS::ResumeCPU(1, 1<
void DMA::Run()
{
if (!Running) return;
- if (CPU == 0) return Run9();
- else return Run7();
+ if (CPU == 0) return Run9();
+ else return Run7();
}
-template void DMA::Run<0>();
-template void DMA::Run<1>();
+}
\ No newline at end of file
diff --git a/src/DMA.h b/src/DMA.h
index ad194c11..e0e3be15 100644
--- a/src/DMA.h
+++ b/src/DMA.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,14 +19,19 @@
#ifndef DMA_H
#define DMA_H
+#include
#include "types.h"
-#include "Savestate.h"
+
+namespace melonDS
+{
+class NDS;
+class Savestate;
class DMA
{
public:
- DMA(u32 cpu, u32 num);
- ~DMA();
+ DMA(u32 cpu, u32 num, NDS& nds);
+ ~DMA() = default;
void Reset();
@@ -40,20 +45,16 @@ public:
u32 UnitTimings7_16(bool burststart);
u32 UnitTimings7_32(bool burststart);
- template
void Run();
-
- template
void Run9();
- template
void Run7();
- bool IsInMode(u32 mode)
+ bool IsInMode(u32 mode) const noexcept
{
return ((mode == StartMode) && (Cnt & 0x80000000));
}
- bool IsRunning() { return Running!=0; }
+ bool IsRunning() const noexcept { return Running!=0; }
void StartIfNeeded(u32 mode)
{
@@ -72,32 +73,35 @@ public:
if (Executing) Stall = true;
}
- u32 SrcAddr;
- u32 DstAddr;
- u32 Cnt;
+ u32 SrcAddr {};
+ u32 DstAddr {};
+ u32 Cnt {};
private:
- u32 CPU, Num;
+ melonDS::NDS& NDS;
+ u32 CPU {};
+ u32 Num {};
- u32 StartMode;
- u32 CurSrcAddr;
- u32 CurDstAddr;
- u32 RemCount;
- u32 IterCount;
- s32 SrcAddrInc;
- s32 DstAddrInc;
- u32 CountMask;
+ u32 StartMode {};
+ u32 CurSrcAddr {};
+ u32 CurDstAddr {};
+ u32 RemCount {};
+ u32 IterCount {};
+ s32 SrcAddrInc {};
+ s32 DstAddrInc {};
+ u32 CountMask {};
- u32 Running;
- bool InProgress;
+ u32 Running {};
+ bool InProgress {};
- bool Executing;
- bool Stall;
+ bool Executing {};
+ bool Stall {};
- bool IsGXFIFODMA;
+ bool IsGXFIFODMA {};
- u32 MRAMBurstCount;
- const u8* MRAMBurstTable;
+ u32 MRAMBurstCount {};
+ std::array MRAMBurstTable;
};
+}
#endif
diff --git a/src/DMA_Timings.cpp b/src/DMA_Timings.cpp
new file mode 100644
index 00000000..912e4e2e
--- /dev/null
+++ b/src/DMA_Timings.cpp
@@ -0,0 +1,243 @@
+/*
+ Copyright 2016-2023 melonDS team
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include "DMA_Timings.h"
+#include "types.h"
+
+namespace melonDS::DMATiming
+{
+
+// DMA timing tables
+//
+// DMA timings on the DS are normally straightforward, except in one case: when
+// main RAM is involved.
+// Main RAM to main RAM is the easy case: 16c/unit in 16bit mode, 18c/unit in 32bit
+// mode.
+// It gets more complicated when transferring from main RAM to somewhere else, or
+// vice versa: main RAM supports burst accesses, but the rules dictating how long
+// bursts can be are weird and inconsistent. Main RAM also supports parallel
+// memory operations, to some extent.
+// I haven't figured out the full logic behind it, let alone how to emulate it
+// efficiently, so for now we will use these tables.
+// A zero denotes the end of a burst pattern.
+//
+// Note: burst patterns only apply when the main RAM address is incrementing.
+// A fixed or decrementing address results in nonsequential accesses.
+//
+// Note about GBA slot/wifi timings: these take into account the sequential timing
+// setting. Timings are such that the nonseq setting only matters for the first
+// access, and minor edge cases (like the last of a 0x20000-byte block).
+
+extern const std::array MRAMDummy = {0};
+
+extern const std::array MRAMRead16Bursts[] =
+{
+ // main RAM to regular 16bit or 32bit bus (similar)
+ {7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 7, 3,
+ 0},
+ // main RAM to GBA/wifi, seq=4
+ {8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5,
+ 0},
+ // main RAM to GBA/wifi, seq=6
+ {10, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8,
+ 0},
+};
+
+extern const std::array MRAMRead32Bursts[] =
+{
+ // main RAM to regular 16bit bus
+ {9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
+ 0},
+ // main RAM to regular 32bit bus
+ {9, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 0},
+ // main RAM to GBA/wifi, seq=4
+ {14, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13,
+ 0},
+ // main RAM to GBA/wifi, seq=6
+ {18, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17,
+ 0},
+};
+
+extern const std::array MRAMWrite16Bursts[] =
+{
+ // regular 16bit or 32bit bus to main RAM (similar)
+ {8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0},
+ // GBA/wifi to main RAM, seq=4
+ {10, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 0},
+ // GBA/wifi to main RAM, seq=6
+ {9, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7,
+ 0},
+};
+
+extern const std::array MRAMWrite32Bursts[4] =
+{
+ // regular 16bit bus to main RAM
+ {9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 0},
+ // regular 32bit bus to main RAM
+ {9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0},
+ // GBA/wifi to main RAM, seq=4
+ {15, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10,
+ 0},
+ // GBA/wifi to main RAM, seq=6
+ {16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 0},
+};
+
+}
\ No newline at end of file
diff --git a/src/DMA_Timings.h b/src/DMA_Timings.h
index 4281c783..63dc4676 100644
--- a/src/DMA_Timings.h
+++ b/src/DMA_Timings.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -19,9 +19,10 @@
#ifndef DMA_TIMINGS_H
#define DMA_TIMINGS_H
+#include
#include "types.h"
-namespace DMATiming
+namespace melonDS::DMATiming
{
// DMA timing tables
@@ -45,202 +46,15 @@ namespace DMATiming
// setting. Timings are such that the nonseq setting only matters for the first
// access, and minor edge cases (like the last of a 0x20000-byte block).
-constexpr u8 MRAMDummy[1] = {0};
+extern const std::array MRAMDummy;
-constexpr u8 MRAMRead16Bursts[][256] =
-{
- // main RAM to regular 16bit or 32bit bus (similar)
- {7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 3,
- 0},
- // main RAM to GBA/wifi, seq=4
- {8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5,
- 0},
- // main RAM to GBA/wifi, seq=6
- {10, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7,
- 12, 8,
- 0},
-};
+extern const std::array MRAMRead16Bursts[3];
-constexpr u8 MRAMRead32Bursts[][256] =
-{
- // main RAM to regular 16bit bus
- {9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
- 0},
- // main RAM to regular 32bit bus
- {9, 3, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 0},
- // main RAM to GBA/wifi, seq=4
- {14, 10, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9,
- 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9,
- 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9,
- 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9,
- 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9,
- 13,
- 0},
- // main RAM to GBA/wifi, seq=6
- {18, 14, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 17,
- 0},
-};
+extern const std::array MRAMRead32Bursts[4];
-constexpr u8 MRAMWrite16Bursts[][256] =
-{
- // regular 16bit or 32bit bus to main RAM (similar)
- {8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 0},
- // GBA/wifi to main RAM, seq=4
- {10, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5,
- 0},
- // GBA/wifi to main RAM, seq=6
- {9, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7,
- 0},
-};
+extern const std::array MRAMWrite16Bursts[3];
-constexpr u8 MRAMWrite32Bursts[][256] =
-{
- // regular 16bit bus to main RAM
- {9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 0},
- // regular 32bit bus to main RAM
- {9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 0},
- // GBA/wifi to main RAM, seq=4
- {15, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10,
- 0},
- // GBA/wifi to main RAM, seq=6
- {16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14,
- 0},
-};
+extern const std::array MRAMWrite32Bursts[4];
}
diff --git a/src/DSi.cpp b/src/DSi.cpp
index 64bc6d2d..306c5d1c 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2023 melonDS team
This file is part of melonDS.
@@ -17,8 +17,10 @@
*/
#include
+#include
#include
#include
+#include "Args.h"
#include "NDS.h"
#include "DSi.h"
#include "ARM.h"
@@ -28,10 +30,8 @@
#include "DSi_SPI_TSC.h"
#include "Platform.h"
-#ifdef JIT_ENABLED
#include "ARMJIT.h"
#include "ARMJIT_Memory.h"
-#endif
#include "DSi_NDMA.h"
#include "DSi_I2C.h"
@@ -43,140 +43,95 @@
#include "tiny-AES-c/aes.hpp"
+namespace melonDS
+{
using namespace Platform;
-namespace DSi
+// matching NDMA modes for DSi
+const u32 NDMAModes[] =
{
+ // ARM9
-u16 SCFG_BIOS;
-u16 SCFG_Clock9;
-u16 SCFG_Clock7;
-u32 SCFG_EXT[2];
-u32 SCFG_MC;
-u16 SCFG_RST;
+ 0x10, // immediate
+ 0x06, // VBlank
+ 0x07, // HBlank
+ 0x08, // scanline start
+ 0x09, // mainmem FIFO
+ 0x04, // DS cart slot
+ 0xFF, // GBA cart slot
+ 0x0A, // GX FIFO
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-u8 ARM9iBIOS[0x10000] = { 0 };
-u8 ARM7iBIOS[0x10000] = { 0 };
+ // ARM7
-u32 MBK[2][9];
+ 0x30, // immediate
+ 0x26, // VBlank
+ 0x24, // DS cart slot
+ 0xFF, // wifi / GBA cart slot (TODO)
+};
-u8* NWRAM_A;
-u8* NWRAM_B;
-u8* NWRAM_C;
-
-u8* NWRAMMap_A[2][4];
-u8* NWRAMMap_B[3][8];
-u8* NWRAMMap_C[3][8];
-
-u32 NWRAMStart[2][3];
-u32 NWRAMEnd[2][3];
-u32 NWRAMMask[2][3];
-
-u32 NDMACnt[2];
-DSi_NDMA* NDMAs[8];
-
-DSi_SDHost* SDMMC;
-DSi_SDHost* SDIO;
-
-u64 ConsoleID;
-u8 eMMC_CID[16];
-
-// FIXME: these currently have no effect (and aren't stored in a savestate)
-// ... not that they matter all that much
-u8 GPIO_Data;
-u8 GPIO_Dir;
-u8 GPIO_IEdgeSel;
-u8 GPIO_IE;
-u8 GPIO_WiFi;
-
-
-void Set_SCFG_Clock9(u16 val);
-void Set_SCFG_MC(u32 val);
-
-
-bool Init()
+DSi::DSi(DSiArgs&& args) noexcept :
+ NDS(std::move(args), 1),
+ NDMAs {
+ DSi_NDMA(0, 0, *this),
+ DSi_NDMA(0, 1, *this),
+ DSi_NDMA(0, 2, *this),
+ DSi_NDMA(0, 3, *this),
+ DSi_NDMA(1, 0, *this),
+ DSi_NDMA(1, 1, *this),
+ DSi_NDMA(1, 2, *this),
+ DSi_NDMA(1, 3, *this),
+ },
+ ARM7iBIOS(*args.ARM7iBIOS),
+ ARM9iBIOS(*args.ARM9iBIOS),
+ DSP(*this),
+ SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)),
+ SDIO(*this),
+ I2C(*this),
+ CamModule(*this),
+ AES(*this)
{
-#ifndef JIT_ENABLED
- NWRAM_A = new u8[NWRAMSize];
- NWRAM_B = new u8[NWRAMSize];
- NWRAM_C = new u8[NWRAMSize];
-#endif
-
- if (!DSi_I2C::Init()) return false;
- if (!DSi_CamModule::Init()) return false;
- if (!DSi_AES::Init()) return false;
- if (!DSi_DSP::Init()) return false;
-
- NDMAs[0] = new DSi_NDMA(0, 0);
- NDMAs[1] = new DSi_NDMA(0, 1);
- NDMAs[2] = new DSi_NDMA(0, 2);
- NDMAs[3] = new DSi_NDMA(0, 3);
- NDMAs[4] = new DSi_NDMA(1, 0);
- NDMAs[5] = new DSi_NDMA(1, 1);
- NDMAs[6] = new DSi_NDMA(1, 2);
- NDMAs[7] = new DSi_NDMA(1, 3);
-
- SDMMC = new DSi_SDHost(0);
- SDIO = new DSi_SDHost(1);
-
- return true;
+ // Memory is owned by ARMJIT_Memory, don't free it
+ NWRAM_A = JIT.Memory.GetNWRAM_A();
+ NWRAM_B = JIT.Memory.GetNWRAM_B();
+ NWRAM_C = JIT.Memory.GetNWRAM_C();
}
-void DeInit()
+DSi::~DSi() noexcept
{
-#ifndef JIT_ENABLED
- delete[] NWRAM_A;
- delete[] NWRAM_B;
- delete[] NWRAM_C;
-
+ // Memory is owned externally
NWRAM_A = nullptr;
NWRAM_B = nullptr;
NWRAM_C = nullptr;
-#endif
-
- DSi_I2C::DeInit();
- DSi_CamModule::DeInit();
- DSi_AES::DeInit();
- DSi_DSP::DeInit();
-
- for (int i = 0; i < 8; i++)
- {
- delete NDMAs[i];
- NDMAs[i] = nullptr;
- }
-
- delete SDMMC;
- SDMMC = nullptr;
- delete SDIO;
- SDIO = nullptr;
}
-void Reset()
+void DSi::Reset()
{
- //NDS::ARM9->CP15Write(0x910, 0x0D00000A);
- //NDS::ARM9->CP15Write(0x911, 0x00000020);
- //NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000);
+ //ARM9.CP15Write(0x910, 0x0D00000A);
+ //ARM9.CP15Write(0x911, 0x00000020);
+ //ARM9.CP15Write(0x100, ARM9.CP15Read(0x100) | 0x00050000);
+ NDS::Reset();
- NDS::MapSharedWRAM(3);
+ // The SOUNDBIAS register does nothing on DSi
+ SPU.SetApplyBias(false);
+ KeyInput &= ~(1 << (16+6));
+ MapSharedWRAM(3);
NDMACnt[0] = 0; NDMACnt[1] = 0;
- for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
+ for (int i = 0; i < 8; i++) NDMAs[i].Reset();
- DSi_I2C::Reset();
- DSi_CamModule::Reset();
- DSi_DSP::Reset();
-
- SDMMC->CloseHandles();
- SDIO->CloseHandles();
+ I2C.Reset();
+ CamModule.Reset();
+ DSP.Reset();
LoadNAND();
- SDMMC->Reset();
- SDIO->Reset();
+ SDMMC.Reset();
+ SDIO.Reset();
- DSi_AES::Reset();
+ AES.Reset();
- if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
+ if (FullBIOSBoot)
{
SCFG_BIOS = 0x0000;
}
@@ -188,10 +143,10 @@ void Reset()
SCFG_Clock7 = 0x0187;
SCFG_EXT[0] = 0x8307F100;
SCFG_EXT[1] = 0x93FFFB06;
- SCFG_MC = 0x0010 | (~((u32)(NDSCart::Cart != nullptr))&1);//0x0011;
+ SCFG_MC = 0x0010 | (~((u32)(NDSCartSlot.GetCart() != nullptr))&1);//0x0011;
SCFG_RST = 0;
- DSi_DSP::SetRstLine(false);
+ DSP.SetRstLine(false);
GPIO_Data = 0xff; // these actually initialize to high after reset
GPIO_Dir = 0x80; // enable sound out, all others input
@@ -200,16 +155,42 @@ void Reset()
GPIO_WiFi = 0;
// LCD init flag
- GPU::DispStat[0] |= (1<<6);
- GPU::DispStat[1] |= (1<<6);
+ GPU.DispStat[0] |= (1<<6);
+ GPU.DispStat[1] |= (1<<6);
}
-void Stop()
+void DSi::Stop(Platform::StopReason reason)
{
- DSi_CamModule::Stop();
+ NDS::Stop(reason);
+ CamModule.Stop();
}
-void DoSavestate(Savestate* file)
+void DSi::SetNDSCart(std::unique_ptr&& cart)
+{
+ NDS::SetNDSCart(std::move(cart));
+ SetCartInserted(NDSCartSlot.GetCart() != nullptr);
+}
+
+
+std::unique_ptr DSi::EjectCart()
+{
+ auto oldcart = NDS::EjectCart();
+
+ SetCartInserted(false);
+
+ return oldcart;
+}
+
+void DSi::CamInputFrame(int cam, const u32* data, int width, int height, bool rgb)
+{
+ switch (cam)
+ {
+ case 0: return I2C.GetOuterCamera()->InputFrame(data, width, height, rgb);
+ case 1: return I2C.GetInnerCamera()->InputFrame(data, width, height, rgb);
+ }
+}
+
+void DSi::DoSavestateExtra(Savestate* file)
{
file->Section("DSIG");
@@ -233,7 +214,7 @@ void DoSavestate(Savestate* file)
{
Set_SCFG_Clock9(SCFG_Clock9);
Set_SCFG_MC(SCFG_MC);
- DSi_DSP::SetRstLine(SCFG_RST & 0x0001);
+ DSP.SetRstLine(SCFG_RST & 0x0001);
MBK[0][8] = 0;
MBK[1][8] = 0;
@@ -278,17 +259,17 @@ void DoSavestate(Savestate* file)
}
for (int i = 0; i < 8; i++)
- NDMAs[i]->DoSavestate(file);
+ NDMAs[i].DoSavestate(file);
- DSi_AES::DoSavestate(file);
- DSi_CamModule::DoSavestate(file);
- DSi_DSP::DoSavestate(file);
- DSi_I2C::DoSavestate(file);
- SDMMC->DoSavestate(file);
- SDIO->DoSavestate(file);
+ AES.DoSavestate(file);
+ CamModule.DoSavestate(file);
+ DSP.DoSavestate(file);
+ I2C.DoSavestate(file);
+ SDMMC.DoSavestate(file);
+ SDIO.DoSavestate(file);
}
-void SetCartInserted(bool inserted)
+void DSi::SetCartInserted(bool inserted)
{
if (inserted)
SCFG_MC &= ~1;
@@ -296,7 +277,7 @@ void SetCartInserted(bool inserted)
SCFG_MC |= 1;
}
-void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
+void DSi::DecryptModcryptArea(u32 offset, u32 size, const u8* iv)
{
AES_ctx ctx;
u8 key[16];
@@ -305,13 +286,13 @@ void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
if ((offset == 0) || (size == 0))
return;
- const NDSHeader& header = NDSCart::Cart->GetHeader();
+ const NDSHeader& header = NDSCartSlot.GetCart()->GetHeader();
if ((header.DSiCryptoFlags & (1<<4)) ||
(header.AppFlags & (1<<7)))
{
// dev key
- const u8* cartrom = NDSCart::Cart->GetROM();
+ const u8* cartrom = NDSCartSlot.GetCart()->GetROM();
memcpy(key, &cartrom[0], 16);
}
else
@@ -395,12 +376,13 @@ void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
}
}
-void SetupDirectBoot()
+void DSi::SetupDirectBoot()
{
bool dsmode = false;
- NDSHeader& header = NDSCart::Cart->GetHeader();
- const u8* cartrom = NDSCart::Cart->GetROM();
- u32 cartid = NDSCart::Cart->ID();
+ NDSHeader& header = NDSCartSlot.GetCart()->GetHeader();
+ const u8* cartrom = NDSCartSlot.GetCart()->GetROM();
+ u32 cartid = NDSCartSlot.GetCart()->ID();
+ DSi_TSC* tsc = (DSi_TSC*)SPI.GetTSC();
// TODO: add controls for forcing DS or DSi mode?
if (!(header.UnitCode & 0x02))
@@ -427,7 +409,7 @@ void SetupDirectBoot()
NDS::MapSharedWRAM(3);
- DSi_SPI_TSC::SetMode(0x00);
+ tsc->SetMode(0x00);
Set_SCFG_Clock9(0x0000);
}
else
@@ -479,7 +461,7 @@ void SetupDirectBoot()
NDS::MapSharedWRAM(mbk[11] >> 24);
if (!(header.AppFlags & (1<<0)))
- DSi_SPI_TSC::SetMode(0x00);
+ tsc->SetMode(0x00);
}
// setup main RAM data
@@ -528,32 +510,34 @@ void SetupDirectBoot()
ARM9Write32(0x02FFE000+i, tmp);
}
- if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
- {
- u8 userdata[0x1B0];
- DSi_NAND::ReadUserData(userdata);
- for (u32 i = 0; i < 0x128; i+=4)
- ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
+ if (DSi_NAND::NANDImage* image = SDMMC.GetNAND(); image && *image)
+ { // If a NAND image is installed, and it's valid...
+ if (DSi_NAND::NANDMount nand = DSi_NAND::NANDMount(*image))
+ {
+ DSi_NAND::DSiFirmwareSystemSettings userdata {};
+ nand.ReadUserData(userdata);
+ for (u32 i = 0; i < 0x128; i+=4)
+ ARM9Write32(0x02000400+i, *(u32*)&userdata.Bytes[0x88+i]);
- u8 hwinfoS[0xA4];
- u8 hwinfoN[0x9C];
- DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
+ DSi_NAND::DSiSerialData hwinfoS {};
+ nand.ReadSerialData(hwinfoS);
+ DSi_NAND::DSiHardwareInfoN hwinfoN;
+ nand.ReadHardwareInfoN(hwinfoN);
- for (u32 i = 0; i < 0x14; i+=4)
- ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
+ for (u32 i = 0; i < 0x14; i+=4)
+ ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
- for (u32 i = 0; i < 0x18; i+=4)
- ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
-
- DSi_NAND::DeInit();
+ for (u32 i = 0; i < 0x18; i+=4)
+ ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS.Bytes[0x88+i]);
+ }
}
- SPI_Firmware::WifiBoard nwifiver = SPI_Firmware::GetFirmware()->Header().WifiBoard;
+ Firmware::WifiBoard nwifiver = SPI.GetFirmware().GetHeader().WifiBoard;
ARM9Write8(0x020005E0, static_cast(nwifiver));
// TODO: these should be taken from the wifi firmware in NAND
// but, hey, this works too.
- if (nwifiver == SPI_Firmware::WifiBoard::W015)
+ if (nwifiver == Firmware::WifiBoard::W015)
{
ARM9Write16(0x020005E2, 0xB57E);
ARM9Write32(0x020005E4, 0x00500400);
@@ -574,7 +558,7 @@ void SetupDirectBoot()
ARM9Write32(0x02FFFC00, cartid);
ARM9Write16(0x02FFFC40, 0x0001); // boot indicator
- ARM9Write8(0x02FFFDFA, DSi_BPTWL::GetBootFlag() | 0x80);
+ ARM9Write8(0x02FFFDFA, I2C.GetBPTWL()->GetBootFlag() | 0x80);
ARM9Write8(0x02FFFDFB, 0x01);
}
@@ -586,7 +570,7 @@ void SetupDirectBoot()
if (header.ARM9ROMOffset >= 0x4000 && header.ARM9ROMOffset < 0x8000)
{
u8 securearea[0x800];
- NDSCart::DecryptSecureArea(securearea);
+ NDSCartSlot.DecryptSecureArea(securearea);
for (u32 i = 0; i < 0x800; i+=4)
{
@@ -636,37 +620,37 @@ void SetupDirectBoot()
}
}
- NDS::ARM7BIOSProt = 0x20;
+ ARM7BIOSProt = 0x20;
- SPI_Firmware::SetupDirectBoot(true);
+ SPI.GetFirmwareMem()->SetupDirectBoot();
- NDS::ARM9->CP15Write(0x100, 0x00056078);
- NDS::ARM9->CP15Write(0x200, 0x0000004A);
- NDS::ARM9->CP15Write(0x201, 0x0000004A);
- NDS::ARM9->CP15Write(0x300, 0x0000000A);
- NDS::ARM9->CP15Write(0x502, 0x15111011);
- NDS::ARM9->CP15Write(0x503, 0x05101011);
- NDS::ARM9->CP15Write(0x600, 0x04000033);
- NDS::ARM9->CP15Write(0x601, 0x04000033);
- NDS::ARM9->CP15Write(0x610, 0x02000031);
- NDS::ARM9->CP15Write(0x611, 0x02000031);
- NDS::ARM9->CP15Write(0x620, 0x00000000);
- NDS::ARM9->CP15Write(0x621, 0x00000000);
- NDS::ARM9->CP15Write(0x630, 0x08000033);
- NDS::ARM9->CP15Write(0x631, 0x08000033);
- NDS::ARM9->CP15Write(0x640, 0x0E00001B);
- NDS::ARM9->CP15Write(0x641, 0x0E00001B);
- NDS::ARM9->CP15Write(0x650, 0x00000000);
- NDS::ARM9->CP15Write(0x651, 0x00000000);
- NDS::ARM9->CP15Write(0x660, 0xFFFF001D);
- NDS::ARM9->CP15Write(0x661, 0xFFFF001D);
- NDS::ARM9->CP15Write(0x670, 0x02FFC01B);
- NDS::ARM9->CP15Write(0x671, 0x02FFC01B);
- NDS::ARM9->CP15Write(0x910, 0x0E00000A);
- NDS::ARM9->CP15Write(0x911, 0x00000020);
+ ARM9.CP15Write(0x100, 0x00056078);
+ ARM9.CP15Write(0x200, 0x0000004A);
+ ARM9.CP15Write(0x201, 0x0000004A);
+ ARM9.CP15Write(0x300, 0x0000000A);
+ ARM9.CP15Write(0x502, 0x15111011);
+ ARM9.CP15Write(0x503, 0x05101011);
+ ARM9.CP15Write(0x600, 0x04000033);
+ ARM9.CP15Write(0x601, 0x04000033);
+ ARM9.CP15Write(0x610, 0x02000031);
+ ARM9.CP15Write(0x611, 0x02000031);
+ ARM9.CP15Write(0x620, 0x00000000);
+ ARM9.CP15Write(0x621, 0x00000000);
+ ARM9.CP15Write(0x630, 0x08000033);
+ ARM9.CP15Write(0x631, 0x08000033);
+ ARM9.CP15Write(0x640, 0x0E00001B);
+ ARM9.CP15Write(0x641, 0x0E00001B);
+ ARM9.CP15Write(0x650, 0x00000000);
+ ARM9.CP15Write(0x651, 0x00000000);
+ ARM9.CP15Write(0x660, 0xFFFF001D);
+ ARM9.CP15Write(0x661, 0xFFFF001D);
+ ARM9.CP15Write(0x670, 0x02FFC01B);
+ ARM9.CP15Write(0x671, 0x02FFC01B);
+ ARM9.CP15Write(0x910, 0x0E00000A);
+ ARM9.CP15Write(0x911, 0x00000020);
}
-void SoftReset()
+void DSi::SoftReset()
{
// TODO: check exactly what is reset
// presumably, main RAM isn't reset, since the DSi can be told
@@ -676,34 +660,29 @@ void SoftReset()
// also, BPTWL[0x70] could be abused to quickly boot specific titles
-#ifdef JIT_ENABLED
- ARMJIT_Memory::Reset();
- ARMJIT::CheckAndInvalidateITCM();
-#endif
+ JIT.Reset();
+ JIT.CheckAndInvalidateITCM();
- NDS::ARM9->Reset();
- NDS::ARM7->Reset();
+ ARM9.Reset();
+ ARM7.Reset();
- NDS::ARM9->CP15Reset();
+ ARM9.CP15Reset();
NDS::MapSharedWRAM(3);
// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
// the DSP most likely gets reset
- DSi_DSP::Reset();
-
- SDMMC->CloseHandles();
- SDIO->CloseHandles();
+ DSP.Reset();
LoadNAND();
- SDMMC->Reset();
- SDIO->Reset();
+ SDMMC.Reset();
+ SDIO.Reset();
- DSi_AES::Reset();
+ AES.Reset();
- if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
+ if (FullBIOSBoot)
{
SCFG_BIOS = 0x0000;
}
@@ -718,25 +697,32 @@ void SoftReset()
SCFG_MC = 0x0010;//0x0011;
// TODO: is this actually reset?
SCFG_RST = 0;
- DSi_DSP::SetRstLine(false);
+ DSP.SetRstLine(false);
// LCD init flag
- GPU::DispStat[0] |= (1<<6);
- GPU::DispStat[1] |= (1<<6);
+ GPU.DispStat[0] |= (1<<6);
+ GPU.DispStat[1] |= (1<<6);
}
-bool LoadNAND()
+bool DSi::LoadNAND()
{
+ DSi_NAND::NANDImage* image = SDMMC.GetNAND();
+ if (!(image && *image))
+ {
+ Log(LogLevel::Error, "No NAND image loaded\n");
+ return false;
+ }
Log(LogLevel::Info, "Loading DSi NAND\n");
- if (!DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
+ DSi_NAND::NANDMount nandmount(*SDMMC.GetNAND());
+ if (!nandmount)
{
Log(LogLevel::Error, "Failed to load DSi NAND\n");
return false;
}
- FileHandle* nand = DSi_NAND::GetFile();
+ FileHandle* nand = image->GetFile();
// Make sure NWRAM is accessible.
// The Bits are set to the startup values in Reset() and we might
@@ -758,7 +744,7 @@ bool LoadNAND()
memset(NWRAMMask, 0, sizeof(NWRAMMask));
u32 bootparams[8];
- if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
+ if (FullBIOSBoot)
{
// TODO: figure out default MBK mapping
// MBK1..5: disable mappings
@@ -892,37 +878,33 @@ bool LoadNAND()
}
}
-#define printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); }
-#define printhex_rev(str, size) { for (int z = (size)-1; z >= 0; z--) printf("%02X", (str)[z]); printf("\n"); }
+ const DSi_NAND::DSiKey& emmccid = image->GetEMMCID();
+ Log(LogLevel::Debug, "eMMC CID: %08llX%08llX\n", *(const u64*)&emmccid[0], *(const u64*)&emmccid[8]);
+ Log(LogLevel::Debug, "Console ID: %" PRIx64 "\n", image->GetConsoleID());
- DSi_NAND::GetIDs(eMMC_CID, ConsoleID);
-
- Log(LogLevel::Debug, "eMMC CID: "); printhex(eMMC_CID, 16);
- Log(LogLevel::Debug, "Console ID: %" PRIx64 "\n", ConsoleID);
-
- if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
+ if (FullBIOSBoot)
{
// point CPUs to boot ROM reset vectors
- NDS::ARM9->JumpTo(0xFFFF0000);
- NDS::ARM7->JumpTo(0x00000000);
+ ARM9.JumpTo(0xFFFF0000);
+ ARM7.JumpTo(0x00000000);
}
else
{
u32 eaddr = 0x03FFE6E4;
- ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
- ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
- ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
- ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
+ ARM7Write32(eaddr+0x00, *(const u32*)&emmccid[0]);
+ ARM7Write32(eaddr+0x04, *(const u32*)&emmccid[4]);
+ ARM7Write32(eaddr+0x08, *(const u32*)&emmccid[8]);
+ ARM7Write32(eaddr+0x0C, *(const u32*)&emmccid[12]);
ARM7Write16(eaddr+0x2C, 0x0001);
ARM7Write16(eaddr+0x2E, 0x0001);
ARM7Write16(eaddr+0x3C, 0x0100);
ARM7Write16(eaddr+0x3E, 0x40E0);
ARM7Write16(eaddr+0x42, 0x0001);
- memcpy(&NDS::ARM9->ITCM[0x4400], &ARM9iBIOS[0x87F4], 0x400);
- memcpy(&NDS::ARM9->ITCM[0x4800], &ARM9iBIOS[0x9920], 0x80);
- memcpy(&NDS::ARM9->ITCM[0x4894], &ARM9iBIOS[0x99A0], 0x1048);
- memcpy(&NDS::ARM9->ITCM[0x58DC], &ARM9iBIOS[0xA9E8], 0x1048);
+ memcpy(&ARM9.ITCM[0x4400], &ARM9iBIOS[0x87F4], 0x400);
+ memcpy(&ARM9.ITCM[0x4800], &ARM9iBIOS[0x9920], 0x80);
+ memcpy(&ARM9.ITCM[0x4894], &ARM9iBIOS[0x99A0], 0x1048);
+ memcpy(&ARM9.ITCM[0x58DC], &ARM9iBIOS[0xA9E8], 0x1048);
u8 ARM7Init[0x3C00];
memset(ARM7Init, 0, 0x3C00);
@@ -935,90 +917,114 @@ bool LoadNAND()
ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
// repoint the CPUs to the boot2 binaries
- NDS::ARM9->JumpTo(bootparams[2]);
- NDS::ARM7->JumpTo(bootparams[6]);
+ ARM9.JumpTo(bootparams[2]);
+ ARM7.JumpTo(bootparams[6]);
}
- DSi_NAND::PatchUserData();
-
- DSi_NAND::DeInit();
+ // user data is now expected to be patched by the frontend
return true;
}
-void RunNDMAs(u32 cpu)
+void DSi::RunNDMAs(u32 cpu)
{
// TODO: round-robin mode (requires DMA channels to have a subblock delay set)
if (cpu == 0)
{
- if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+ if (ARM9Timestamp >= ARM9Target) return;
- if (!(NDS::CPUStop & 0x80000000)) NDMAs[0]->Run();
- if (!(NDS::CPUStop & 0x80000000)) NDMAs[1]->Run();
- if (!(NDS::CPUStop & 0x80000000)) NDMAs[2]->Run();
- if (!(NDS::CPUStop & 0x80000000)) NDMAs[3]->Run();
+ if (!(CPUStop & CPUStop_GXStall)) NDMAs[0].Run();
+ if (!(CPUStop & CPUStop_GXStall)) NDMAs[1].Run();
+ if (!(CPUStop & CPUStop_GXStall)) NDMAs[2].Run();
+ if (!(CPUStop & CPUStop_GXStall)) NDMAs[3].Run();
}
else
{
- if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+ if (ARM7Timestamp >= ARM7Target) return;
- NDMAs[4]->Run();
- NDMAs[5]->Run();
- NDMAs[6]->Run();
- NDMAs[7]->Run();
+ NDMAs[4].Run();
+ NDMAs[5].Run();
+ NDMAs[6].Run();
+ NDMAs[7].Run();
}
}
-void StallNDMAs()
+void DSi::StallNDMAs()
{
// TODO
}
-bool NDMAsInMode(u32 cpu, u32 mode)
+
+bool DSi::DMAsInMode(u32 cpu, u32 mode) const
+{
+ if (NDS::DMAsInMode(cpu, mode)) return true;
+
+ return NDMAsInMode(cpu, NDMAModes[mode]);
+}
+
+bool DSi::DMAsRunning(u32 cpu) const
+{
+ if (NDS::DMAsRunning(cpu)) return true;
+
+ return NDMAsRunning(cpu);
+}
+
+bool DSi::NDMAsInMode(u32 cpu, u32 mode) const
{
cpu <<= 2;
- if (NDMAs[cpu+0]->IsInMode(mode)) return true;
- if (NDMAs[cpu+1]->IsInMode(mode)) return true;
- if (NDMAs[cpu+2]->IsInMode(mode)) return true;
- if (NDMAs[cpu+3]->IsInMode(mode)) return true;
+ if (NDMAs[cpu+0].IsInMode(mode)) return true;
+ if (NDMAs[cpu+1].IsInMode(mode)) return true;
+ if (NDMAs[cpu+2].IsInMode(mode)) return true;
+ if (NDMAs[cpu+3].IsInMode(mode)) return true;
return false;
}
-bool NDMAsRunning(u32 cpu)
+bool DSi::NDMAsRunning(u32 cpu) const
{
cpu <<= 2;
- if (NDMAs[cpu+0]->IsRunning()) return true;
- if (NDMAs[cpu+1]->IsRunning()) return true;
- if (NDMAs[cpu+2]->IsRunning()) return true;
- if (NDMAs[cpu+3]->IsRunning()) return true;
+ if (NDMAs[cpu+0].IsRunning()) return true;
+ if (NDMAs[cpu+1].IsRunning()) return true;
+ if (NDMAs[cpu+2].IsRunning()) return true;
+ if (NDMAs[cpu+3].IsRunning()) return true;
return false;
}
-void CheckNDMAs(u32 cpu, u32 mode)
+void DSi::CheckNDMAs(u32 cpu, u32 mode)
{
cpu <<= 2;
- NDMAs[cpu+0]->StartIfNeeded(mode);
- NDMAs[cpu+1]->StartIfNeeded(mode);
- NDMAs[cpu+2]->StartIfNeeded(mode);
- NDMAs[cpu+3]->StartIfNeeded(mode);
+ NDMAs[cpu+0].StartIfNeeded(mode);
+ NDMAs[cpu+1].StartIfNeeded(mode);
+ NDMAs[cpu+2].StartIfNeeded(mode);
+ NDMAs[cpu+3].StartIfNeeded(mode);
}
-void StopNDMAs(u32 cpu, u32 mode)
+void DSi::StopNDMAs(u32 cpu, u32 mode)
{
cpu <<= 2;
- NDMAs[cpu+0]->StopIfNeeded(mode);
- NDMAs[cpu+1]->StopIfNeeded(mode);
- NDMAs[cpu+2]->StopIfNeeded(mode);
- NDMAs[cpu+3]->StopIfNeeded(mode);
+ NDMAs[cpu+0].StopIfNeeded(mode);
+ NDMAs[cpu+1].StopIfNeeded(mode);
+ NDMAs[cpu+2].StopIfNeeded(mode);
+ NDMAs[cpu+3].StopIfNeeded(mode);
}
+void DSi::StopDMAs(u32 cpu, u32 mode)
+{
+ NDS::StopDMAs(cpu, mode);
+ StopNDMAs(cpu, mode);
+}
+void DSi::CheckDMAs(u32 cpu, u32 mode)
+{
+ NDS::CheckDMAs(cpu, mode);
+
+ CheckNDMAs(cpu, NDMAModes[mode]);
+}
// new WRAM mapping
// TODO: find out what happens upon overlapping slots!!
-void MapNWRAM_A(u32 num, u8 val)
+void DSi::MapNWRAM_A(u32 num, u8 val)
{
// NWRAM Bank A does not allow all bits to be set
// possible non working combinations are caught by later code, but these are not set-able at all
@@ -1035,9 +1041,7 @@ void MapNWRAM_A(u32 num, u8 val)
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
-#ifdef JIT_ENABLED
- ARMJIT_Memory::RemapNWRAM(0);
-#endif
+ JIT.Memory.RemapNWRAM(0);
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
@@ -1065,7 +1069,7 @@ void MapNWRAM_A(u32 num, u8 val)
}
}
-void MapNWRAM_B(u32 num, u8 val)
+void DSi::MapNWRAM_B(u32 num, u8 val)
{
// NWRAM Bank B does not allow all bits to be set
// possible non working combinations are caught by later code, but these are not set-able at all
@@ -1082,9 +1086,7 @@ void MapNWRAM_B(u32 num, u8 val)
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
-#ifdef JIT_ENABLED
- ARMJIT_Memory::RemapNWRAM(1);
-#endif
+ JIT.Memory.RemapNWRAM(1);
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
@@ -1114,7 +1116,7 @@ void MapNWRAM_B(u32 num, u8 val)
}
}
-void MapNWRAM_C(u32 num, u8 val)
+void DSi::MapNWRAM_C(u32 num, u8 val)
{
// NWRAM Bank C does not allow all bits to be set
// possible non working combinations are caught by later code, but these are not set-able at all
@@ -1131,9 +1133,7 @@ void MapNWRAM_C(u32 num, u8 val)
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
-#ifdef JIT_ENABLED
- ARMJIT_Memory::RemapNWRAM(2);
-#endif
+ JIT.Memory.RemapNWRAM(2);
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
@@ -1163,7 +1163,7 @@ void MapNWRAM_C(u32 num, u8 val)
}
}
-void MapNWRAMRange(u32 cpu, u32 num, u32 val)
+void DSi::MapNWRAMRange(u32 cpu, u32 num, u32 val)
{
// The windowing registers are not writeable in all bits
// We need to do this before the change test, so we do not
@@ -1182,9 +1182,7 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val)
u32 oldval = MBK[cpu][5+num];
if (oldval == val) return;
-#ifdef JIT_ENABLED
- ARMJIT_Memory::RemapNWRAM(num);
-#endif
+ JIT.Memory.RemapNWRAM(num);
MBK[cpu][5+num] = val;
@@ -1236,41 +1234,41 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val)
}
}
-void ApplyNewRAMSize(u32 size)
+void DSi::ApplyNewRAMSize(u32 size)
{
switch (size)
{
case 0:
case 1:
- NDS::MainRAMMask = 0x3FFFFF;
+ MainRAMMask = 0x3FFFFF;
Log(LogLevel::Debug, "RAM: 4MB\n");
break;
case 2:
case 3: // TODO: debug console w/ 32MB?
- NDS::MainRAMMask = 0xFFFFFF;
+ MainRAMMask = 0xFFFFFF;
Log(LogLevel::Debug, "RAM: 16MB\n");
break;
}
}
-void Set_SCFG_Clock9(u16 val)
+void DSi::Set_SCFG_Clock9(u16 val)
{
- NDS::ARM9Timestamp >>= NDS::ARM9ClockShift;
- NDS::ARM9Target >>= NDS::ARM9ClockShift;
+ ARM9Timestamp >>= ARM9ClockShift;
+ ARM9Target >>= ARM9ClockShift;
Log(LogLevel::Debug, "CLOCK9=%04X\n", val);
SCFG_Clock9 = val & 0x0187;
- if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2;
- else NDS::ARM9ClockShift = 1;
+ if (SCFG_Clock9 & (1<<0)) ARM9ClockShift = 2;
+ else ARM9ClockShift = 1;
- NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
- NDS::ARM9Target <<= NDS::ARM9ClockShift;
- NDS::ARM9->UpdateRegionTimings(0x00000, 0x100000);
+ ARM9Timestamp <<= ARM9ClockShift;
+ ARM9Target <<= ARM9ClockShift;
+ ARM9.UpdateRegionTimings(0x00000, 0x100000);
}
-void Set_SCFG_MC(u32 val)
+void DSi::Set_SCFG_MC(u32 val)
{
u32 oldslotstatus = SCFG_MC & 0xC;
@@ -1281,13 +1279,14 @@ void Set_SCFG_MC(u32 val)
if ((oldslotstatus == 0x0) && ((SCFG_MC & 0xC) == 0x4))
{
- NDSCart::ResetCart();
+ NDSCartSlot.ResetCart();
}
}
-u8 ARM9Read8(u32 addr)
+u8 DSi::ARM9Read8(u32 addr)
{
+ assert(ConsoleType == 1);
if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
{
if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0)))
@@ -1325,17 +1324,18 @@ u8 ARM9Read8(u32 addr)
case 0x08000000:
case 0x09000000:
case 0x0A000000:
- return (NDS::ExMemCnt[0] & (1<<7)) ? 0 : 0xFF;
+ return (ExMemCnt[0] & (1<<7)) ? 0 : 0xFF;
case 0x0C000000:
- return *(u8*)&NDS::MainRAM[addr & NDS::MainRAMMask];
+ return *(u8*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read8(addr);
}
-u16 ARM9Read16(u32 addr)
+u16 DSi::ARM9Read16(u32 addr)
{
+ assert(ConsoleType == 1);
addr &= ~0x1;
if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
@@ -1375,17 +1375,18 @@ u16 ARM9Read16(u32 addr)
case 0x08000000:
case 0x09000000:
case 0x0A000000:
- return (NDS::ExMemCnt[0] & (1<<7)) ? 0 : 0xFFFF;
+ return (ExMemCnt[0] & (1<<7)) ? 0 : 0xFFFF;
case 0x0C000000:
- return *(u16*)&NDS::MainRAM[addr & NDS::MainRAMMask];
+ return *(u16*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read16(addr);
}
-u32 ARM9Read32(u32 addr)
+u32 DSi::ARM9Read32(u32 addr)
{
+ assert(ConsoleType == 1);
addr &= ~0x3;
if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
@@ -1430,17 +1431,18 @@ u32 ARM9Read32(u32 addr)
case 0x08000000:
case 0x09000000:
case 0x0A000000:
- return (NDS::ExMemCnt[0] & (1<<7)) ? 0 : 0xFFFFFFFF;
+ return (ExMemCnt[0] & (1<<7)) ? 0 : 0xFFFFFFFF;
case 0x0C000000:
- return *(u32*)&NDS::MainRAM[addr & NDS::MainRAMMask];
+ return *(u32*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read32(addr);
}
-void ARM9Write8(u32 addr, u8 val)
+void DSi::ARM9Write8(u32 addr, u8 val)
{
+ assert(ConsoleType == 1);
switch (addr & 0xFF000000)
{
case 0x03000000:
@@ -1460,9 +1462,7 @@ void ARM9Write8(u32 addr, u8 val)
continue;
u8* ptr = &NWRAM_A[page * 0x10000];
*(u8*)&ptr[addr & 0xFFFF] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
-#endif
+ JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
}
return;
}
@@ -1480,9 +1480,7 @@ void ARM9Write8(u32 addr, u8 val)
continue;
u8* ptr = &NWRAM_B[page * 0x8000];
*(u8*)&ptr[addr & 0x7FFF] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
-#endif
+ JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
}
return;
}
@@ -1500,9 +1498,7 @@ void ARM9Write8(u32 addr, u8 val)
continue;
u8* ptr = &NWRAM_C[page * 0x8000];
*(u8*)&ptr[addr & 0x7FFF] = val;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
-#endif
+ JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
}
return;
}
@@ -1515,16 +1511,14 @@ void ARM9Write8(u32 addr, u8 val)
case 0x06000000:
if (!(SCFG_EXT[0] & (1<<13))) return;
-#ifdef JIT_ENABLED
- ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(addr);
-#endif
+ JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(addr);
switch (addr & 0x00E00000)
{
- case 0x00000000: GPU::WriteVRAM_ABG(addr, val); return;
- case 0x00200000: GPU::WriteVRAM_BBG(addr, val); return;
- case 0x00400000: GPU::WriteVRAM_AOBJ(addr, val); return;
- case 0x00600000: GPU::WriteVRAM_BOBJ(addr, val); return;
- default: GPU::WriteVRAM_LCDC(addr, val); return;
+ case 0x00000000: GPU.WriteVRAM_ABG(addr, val); return;
+ case 0x00200000: GPU.WriteVRAM_BBG(addr, val); return;
+ case 0x00400000: GPU.WriteVRAM_AOBJ(addr, val); return;
+ case 0x00600000: GPU.WriteVRAM_BOBJ(addr, val); return;
+ default: GPU.WriteVRAM_LCDC