Merge branch 'master' into printf-debug
This commit is contained in:
commit
07008d3024
|
@ -0,0 +1,18 @@
|
|||
# Vendored Dependencies
|
||||
src/frontend/glad/** linguist-vendored
|
||||
src/frontend/qt_sdl/gif-h/** linguist-vendored
|
||||
src/frontend/qt_sdl/toml/** linguist-vendored
|
||||
src/net/libslirp/** linguist-vendored
|
||||
src/net/pcap/** linguist-vendored
|
||||
src/sha1/** linguist-vendored
|
||||
src/teakra/** linguist-vendored
|
||||
src/tiny-AES-c/** linguist-vendored
|
||||
src/xxhash/** linguist-vendored
|
||||
|
||||
# A handful of custom files embedded in the vendored dependencies
|
||||
|
||||
## Ad-hoc CMakeLists.txt for melonDS
|
||||
src/net/libslirp/src/CMakeLists.txt -linguist-vendored
|
||||
|
||||
## glib stub
|
||||
src/net/libslirp/src/glib/** -linguist-vendored
|
|
@ -1,55 +0,0 @@
|
|||
name: AppImage
|
||||
|
||||
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
|
|
@ -4,10 +4,16 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
- ci/vcpkg-update
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
MELONDS_GIT_BRANCH: ${{ github.ref }}
|
||||
MELONDS_GIT_HASH: ${{ github.sha }}
|
||||
MELONDS_BUILD_PROVIDER: GitHub Actions
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
strategy:
|
||||
|
@ -15,24 +21,25 @@ jobs:
|
|||
arch: [x86_64, arm64]
|
||||
|
||||
name: ${{ matrix.arch }}
|
||||
runs-on: macos-13
|
||||
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 && pip3 install setuptools
|
||||
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: c8696863d371ab7f46e213d8f5ca923c4aef2a00
|
||||
vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
|
||||
- name: Build
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
configurePreset: release-mac-${{ matrix.arch }}
|
||||
buildPreset: release-mac-${{ matrix.arch }}
|
||||
configurePresetAdditionalArgs: "['-DMELONDS_EMBED_BUILD_INFO=ON']"
|
||||
- name: Compress app bundle
|
||||
shell: bash
|
||||
run: |
|
||||
|
@ -43,11 +50,13 @@ jobs:
|
|||
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
|
||||
|
@ -74,11 +83,10 @@ jobs:
|
|||
with:
|
||||
name: macOS-universal
|
||||
path: macOS-universal.zip
|
||||
- name: Clean up architecture-specific artifacts
|
||||
uses: geekyeggo/delete-artifact@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
failOnError: false
|
||||
name: |
|
||||
macOS-x86_64
|
||||
macOS-arm64
|
||||
# - name: Clean up architecture-specific artifacts
|
||||
# uses: geekyeggo/delete-artifact@v4
|
||||
# with:
|
||||
# failOnError: false
|
||||
# name: |
|
||||
# macOS-x86_64
|
||||
# macOS-arm64
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
name: Ubuntu
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: aarch64
|
||||
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
|
|
@ -8,31 +8,84 @@ on:
|
|||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: x86_64
|
||||
env:
|
||||
MELONDS_GIT_BRANCH: ${{ github.ref }}
|
||||
MELONDS_GIT_HASH: ${{ github.sha }}
|
||||
MELONDS_BUILD_PROVIDER: GitHub Actions
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
jobs:
|
||||
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 libenet-dev \
|
||||
qt6-{base,base-private,multimedia}-dev libqt6svg6-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 -DMELONDS_EMBED_BUILD_INFO=ON
|
||||
- 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},libqt6svg6,libarchive,libzstd,libenet}-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 \
|
||||
-DMELONDS_EMBED_BUILD_INFO=ON
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --build build
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: melonDS-ubuntu-aarch64
|
||||
path: build/melonDS
|
||||
|
|
|
@ -4,40 +4,40 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
- ci/*
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
MELONDS_GIT_BRANCH: ${{ github.ref }}
|
||||
MELONDS_GIT_HASH: ${{ github.sha }}
|
||||
MELONDS_BUILD_PROVIDER: GitHub Actions
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: pacman -Sq --noconfirm git pkgconf mingw-w64-x86_64-{cmake,SDL2,qt5-static,libslirp,libarchive,toolchain}
|
||||
|
||||
msystem: ucrt64
|
||||
update: true
|
||||
pacboy: gcc:p cmake:p ninja:p make:p
|
||||
- name: Set up vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
|
||||
- name: Configure
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: cmake -B build $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=C:/tools/msys64/mingw64/qt5-static
|
||||
|
||||
- name: Make
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build .
|
||||
|
||||
- uses: actions/upload-artifact@v1
|
||||
run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON
|
||||
- name: Build
|
||||
run: cmake --build --preset=release-mingw-x86_64
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: melonDS-windows-x86_64
|
||||
path: ${{runner.workspace}}\build\melonDS.exe
|
||||
path: .\build\release-mingw-x86_64\melonDS.exe
|
||||
|
|
|
@ -7,7 +7,8 @@ endif()
|
|||
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/DefaultBuildFlags.cmake")
|
||||
|
||||
option(USE_VCPKG "Use vcpkg for dependency packages" OFF)
|
||||
if (USE_VCPKG)
|
||||
|
@ -25,6 +26,9 @@ include(CheckLibraryExists)
|
|||
include(CMakeDependentOption)
|
||||
include(CheckIPOSupported)
|
||||
|
||||
include(SetupCCache)
|
||||
include(Sanitizers)
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
@ -33,8 +37,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")
|
||||
|
@ -78,14 +80,6 @@ if (ENABLE_LTO)
|
|||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
@ -100,13 +94,6 @@ endif()
|
|||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_program(CCACHE "ccache")
|
||||
if (CCACHE)
|
||||
message(STATUS "Using CCache to speed up compilation")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||
endif()
|
||||
|
||||
option(ENABLE_GDBSTUB "Enable GDB stub" ON)
|
||||
if (ENABLE_GDBSTUB)
|
||||
add_definitions(-DGDBSTUB_ENABLED)
|
||||
|
|
|
@ -20,6 +20,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release-mingw-x86_64",
|
||||
"inherits": "release-vcpkg",
|
||||
"displayName": "Windows MinGW release (x86_64)",
|
||||
"binaryDir": "${sourceDir}/build/release-mingw-x86_64",
|
||||
"generator": "Ninja",
|
||||
"cacheVariables": {
|
||||
"USE_QT6": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"BUILD_STATIC": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release-mac-x86_64",
|
||||
"inherits": "release-vcpkg",
|
||||
|
@ -44,6 +61,10 @@
|
|||
"name": "release-vcpkg",
|
||||
"configurePreset": "release-vcpkg"
|
||||
},
|
||||
{
|
||||
"name": "release-mingw-x86_64",
|
||||
"configurePreset": "release-mingw-x86_64"
|
||||
},
|
||||
{
|
||||
"name": "release-mac-x86_64",
|
||||
"configurePreset": "release-mac-x86_64"
|
||||
|
@ -85,4 +106,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
24
README.md
24
README.md
|
@ -5,11 +5,11 @@
|
|||
<a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 0.9.5"><img src="https://img.shields.io/badge/release-0.9.5-%235c913b.svg"></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a>
|
||||
<a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a>
|
||||
<a href="https://discord.gg/pAMAtExcqV" alt="Discord"><img src="https://img.shields.io/badge/Discord-Kuribo64-7289da?logo=discord&logoColor=white"></a>
|
||||
<br>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Windows+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-windows.yml?label=Windows%20x86-64&logo=GitHub&branch=master"></img></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-ubuntu.yml?label=Linux%20x86-64&logo=GitHub"></img></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+aarch64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-ubuntu-aarch64.yml?label=Linux%20ARM64&logo=GitHub"></img></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos-universal.yml?query=event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-macos-universal.yml?label=macOS%20Universal&logo=GitHub"></img></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-windows.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-windows.yml/badge.svg" /></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-ubuntu.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-ubuntu.yml/badge.svg" /></a>
|
||||
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos.yml/badge.svg" /></a>
|
||||
</p>
|
||||
DS emulator, sorta
|
||||
|
||||
|
@ -35,9 +35,9 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
|||
|
||||
### Linux
|
||||
1. Install dependencies:
|
||||
* Ubuntu 22.04: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev libzstd-dev`
|
||||
* Older Ubuntu: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev libzstd-dev`
|
||||
* Arch Linux: `sudo pacman -S base-devel cmake extra-cmake-modules git libpcap sdl2 qt5-base qt5-multimedia libslirp libarchive zstd`
|
||||
* Ubuntu 22.04: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtbase5-private-dev qtmultimedia5-dev libqt5svg5-dev libarchive-dev libenet-dev libzstd-dev`
|
||||
* Older Ubuntu: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libqt5svg5-dev libarchive-dev libenet-dev libzstd-dev`
|
||||
* Arch Linux: `sudo pacman -S base-devel cmake extra-cmake-modules git libpcap sdl2 qt5-base qt5-multimedia qt5-svg libarchive enet zstd`
|
||||
3. Download the melonDS repository and prepare:
|
||||
```bash
|
||||
git clone https://github.com/melonDS-emu/melonDS
|
||||
|
@ -64,7 +64,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
|||
cd melonDS
|
||||
```
|
||||
#### Dynamic builds (with DLLs)
|
||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,qt5-tools,libslirp,libarchive,zstd}`
|
||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,qt5-svg,qt5-tools,libarchive,enet,zstd}`
|
||||
6. Compile:
|
||||
```bash
|
||||
cmake -B build
|
||||
|
@ -75,7 +75,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
|||
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
||||
|
||||
#### Static builds (without DLLs, standalone executable)
|
||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-static,libslirp,libarchive,zstd}`
|
||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-static,libarchive,enet,zstd}`
|
||||
6. Compile:
|
||||
```bash
|
||||
cmake -B build -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=/mingw64/qt5-static
|
||||
|
@ -85,7 +85,7 @@ If everything went well, melonDS should now be in the `build` folder.
|
|||
|
||||
### macOS
|
||||
1. Install the [Homebrew Package Manager](https://brew.sh)
|
||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive zstd`
|
||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libarchive enet zstd`
|
||||
3. Download the melonDS repository and prepare:
|
||||
```zsh
|
||||
git clone https://github.com/melonDS-emu/melonDS
|
||||
|
@ -93,14 +93,14 @@ If everything went well, melonDS should now be in the `build` folder.
|
|||
```
|
||||
4. Compile:
|
||||
```zsh
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DUSE_QT6=ON
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)"
|
||||
cmake --build build -j$(sysctl -n hw.logicalcpu)
|
||||
```
|
||||
If everything went well, melonDS.app should now be in the `build` directory.
|
||||
|
||||
#### Self-contained app bundle
|
||||
If you want an app bundle that can be distributed to other computers without needing to install dependencies through Homebrew, you can additionally run `
|
||||
../tools/mac-bundle.rb melonDS.app` after the build is completed, or add `-DMACOS_BUNDLE_LIBS=ON` to the first CMake command.
|
||||
../tools/mac-libs.rb .` after the build is completed, or add `-DMACOS_BUNDLE_LIBS=ON` to the first CMake command.
|
||||
|
||||
## TODO LIST
|
||||
|
||||
|
|
|
@ -4,10 +4,12 @@ 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)
|
||||
if (APPLE) # this doesn't work on non-macOS
|
||||
file(LOCK "${_DEFAULT_VCPKG_ROOT}" DIRECTORY GUARD FILE)
|
||||
endif()
|
||||
FetchContent_Declare(vcpkg
|
||||
GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git"
|
||||
GIT_TAG 2023.12.12
|
||||
GIT_TAG 2024.10.21
|
||||
SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg")
|
||||
FetchContent_MakeAvailable(vcpkg)
|
||||
endif()
|
||||
|
@ -16,6 +18,23 @@ 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)
|
||||
|
||||
# Duplicated here because it needs to be set before project()
|
||||
if (NOT WIN32)
|
||||
option(USE_QT6 "Build using Qt 6 instead of 5" ON)
|
||||
else()
|
||||
option(USE_QT6 "Build using Qt 6 instead of 5" OFF)
|
||||
endif()
|
||||
|
||||
# Since the Linux build pulls in glib anyway, we can just use upstream libslirp
|
||||
if (UNIX AND NOT APPLE)
|
||||
option(USE_SYSTEM_LIBSLIRP "Use system libslirp instead of the bundled version" ON)
|
||||
endif()
|
||||
|
||||
if (NOT USE_QT6)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES qt5)
|
||||
set(VCPKG_MANIFEST_NO_DEFAULT_FEATURES ON)
|
||||
endif()
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES MATCHES ";")
|
||||
message(FATAL_ERROR "macOS universal builds are not supported. Build them individually and combine afterwards instead.")
|
||||
endif()
|
||||
|
@ -47,7 +66,15 @@ if (USE_RECOMMENDED_TRIPLETS)
|
|||
elseif(WIN32)
|
||||
# TODO Windows arm64 if possible
|
||||
set(_CAN_TARGET_AS_HOST ON)
|
||||
set(_WANTED_TRIPLET x64-mingw-static)
|
||||
set(_WANTED_TRIPLET x64-mingw-static-release)
|
||||
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
|
||||
# Can't really detect cross compiling here.
|
||||
set(_CAN_TARGET_AS_HOST ON)
|
||||
if (_HOST_PROCESSOR STREQUAL x86_64)
|
||||
set(_WANTED_TRIPLET x64-linux-release)
|
||||
elseif(_HOST_PROCESSOR STREQUAL "aarch64")
|
||||
set(_WANTED_TRIPLET arm64-linux-release)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Don't override it if the user set something else
|
||||
|
|
|
@ -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}")
|
|
@ -0,0 +1,48 @@
|
|||
# - Try to find enet
|
||||
# Once done this will define
|
||||
#
|
||||
# ENET_FOUND - system has enet
|
||||
# ENET_INCLUDE_DIRS - the enet include directory
|
||||
# ENET_LIBRARIES - the libraries needed to use enet
|
||||
#
|
||||
# $ENETDIR is an environment variable used for finding enet.
|
||||
#
|
||||
# Borrowed from The Mana World
|
||||
# http://themanaworld.org/
|
||||
#
|
||||
# Several changes and additions by Fabian 'x3n' Landau
|
||||
# Lots of simplifications by Adrian Friedli
|
||||
# > www.orxonox.net <
|
||||
|
||||
FIND_PATH(ENET_INCLUDE_DIRS enet/enet.h
|
||||
PATHS
|
||||
$ENV{ENETDIR}
|
||||
/usr/local
|
||||
/usr
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ENET_LIBRARY
|
||||
NAMES enet
|
||||
PATHS
|
||||
$ENV{ENETDIR}
|
||||
/usr/local
|
||||
/usr
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ENET_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ENet DEFAULT_MSG ENET_LIBRARY ENET_INCLUDE_DIRS)
|
||||
|
||||
IF (ENET_FOUND)
|
||||
IF(WIN32)
|
||||
SET(WINDOWS_ENET_DEPENDENCIES "ws2_32;winmm")
|
||||
SET(ENET_LIBRARIES ${ENET_LIBRARY} ${WINDOWS_ENET_DEPENDENCIES})
|
||||
ELSE(WIN32)
|
||||
SET(ENET_LIBRARIES ${ENET_LIBRARY})
|
||||
ENDIF(WIN32)
|
||||
ENDIF (ENET_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(ENET_LIBRARY ENET_LIBRARIES ENET_INCLUDE_DIRS)
|
|
@ -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})
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
set(SANITIZE "" CACHE STRING "Sanitizers to enable.")
|
||||
|
||||
string(REGEX MATCHALL "[^,]+" ENABLED_SANITIZERS "${SANITIZE}")
|
||||
|
||||
foreach(SANITIZER ${ENABLED_SANITIZERS})
|
||||
add_compile_options("-fsanitize=${SANITIZER}")
|
||||
add_link_options("-fsanitize=${SANITIZER}")
|
||||
endforeach()
|
|
@ -0,0 +1,19 @@
|
|||
include(FindPackageMessage)
|
||||
|
||||
find_program(CCACHE "ccache")
|
||||
|
||||
cmake_dependent_option(USE_CCACHE "Use CCache to speed up repeated builds." ON CCACHE OFF)
|
||||
|
||||
if (NOT CCACHE OR NOT USE_CCACHE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Fedora, and probably also Red Hat-based distros in general, use CCache by default if it's installed on the system.
|
||||
# We'll try to detect this here, and exit if that's the case.
|
||||
# Trying to launch ccache with ccache as we'd otherwise do seems to cause build issues.
|
||||
if (CMAKE_C_COMPILER MATCHES "ccache" OR CMAKE_CXX_COMPILER MATCHES "ccache")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package_message(CCache "Using CCache to speed up compilation" "${USE_CCACHE}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE}")
|
|
@ -0,0 +1,7 @@
|
|||
set(VCPKG_TARGET_ARCHITECTURE x64)
|
||||
set(VCPKG_CRT_LINKAGE dynamic)
|
||||
set(VCPKG_LIBRARY_LINKAGE static)
|
||||
set(VCPKG_ENV_PASSTHROUGH PATH)
|
||||
set(VCPKG_BUILD_TYPE release)
|
||||
|
||||
set(VCPKG_CMAKE_SYSTEM_NAME MinGW)
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1729665710,
|
||||
"narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
{
|
||||
description = "Nintendo DS emulator";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
inherit (pkgs.lib) cmakeBool optionals makeLibraryPath;
|
||||
inherit (pkgs.stdenv) isLinux isDarwin;
|
||||
|
||||
revision = with self; if sourceInfo?dirtyRev
|
||||
then sourceInfo.dirtyRev
|
||||
else sourceInfo.rev;
|
||||
shortRevision = with self; if sourceInfo?dirtyShortRev
|
||||
then sourceInfo.dirtyShortRev
|
||||
else sourceInfo.shortRev;
|
||||
|
||||
melonDS = pkgs.qt6.qtbase.stdenv.mkDerivation {
|
||||
pname = "melonDS";
|
||||
version = "0.9.5-${shortRevision}";
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
ninja
|
||||
pkg-config
|
||||
qt6.wrapQtAppsHook
|
||||
];
|
||||
|
||||
buildInputs = (with pkgs; [
|
||||
qt6.qtbase
|
||||
qt6.qtmultimedia
|
||||
SDL2
|
||||
zstd
|
||||
libarchive
|
||||
libGL
|
||||
libslirp
|
||||
enet
|
||||
]) ++ optionals (!isDarwin) (with pkgs; [
|
||||
kdePackages.extra-cmake-modules
|
||||
qt6.qtwayland
|
||||
wayland
|
||||
]);
|
||||
|
||||
cmakeFlags = [
|
||||
(cmakeBool "USE_QT6" true)
|
||||
(cmakeBool "USE_SYSTEM_LIBSLIRP" true)
|
||||
(cmakeBool "MELONDS_EMBED_BUILD_INFO" true)
|
||||
];
|
||||
|
||||
env.MELONDS_GIT_HASH = revision;
|
||||
env.MELONDS_GIT_BRANCH = "(unknown)";
|
||||
env.MELONDS_BUILD_PROVIDER = "Nix";
|
||||
|
||||
qtWrapperArgs = optionals isLinux [
|
||||
"--prefix LD_LIBRARY_PATH : ${makeLibraryPath [ pkgs.libpcap pkgs.wayland ]}"
|
||||
] ++ optionals isDarwin [
|
||||
"--prefix DYLD_LIBRARY_PATH : ${makeLibraryPath [ pkgs.libpcap ]}"
|
||||
];
|
||||
|
||||
passthru = {
|
||||
exePath = if isDarwin then
|
||||
"/Applications/melonDS.app/Contents/MacOS/melonDS"
|
||||
else "/bin/melonDS";
|
||||
};
|
||||
};
|
||||
in {
|
||||
packages.default = melonDS;
|
||||
apps.default = flake-utils.lib.mkApp {
|
||||
drv = self.packages.${system}.default;
|
||||
};
|
||||
devShells = {
|
||||
default = pkgs.mkShell.override { stdenv = pkgs.qt6.qtbase.stdenv; } {
|
||||
inputsFrom = [ self.packages.${system}.default ];
|
||||
};
|
||||
|
||||
# Shell for building static melonDS release builds with vcpkg
|
||||
# Use mkShellNoCC to ensure Nix's gcc/clang and stdlib isn't used
|
||||
vcpkg = pkgs.mkShellNoCC {
|
||||
packages = with pkgs; [
|
||||
autoconf
|
||||
autoconf-archive
|
||||
automake
|
||||
cmake
|
||||
cups.dev # Needed by qtbase despite not enabling print support
|
||||
git
|
||||
iconv.dev
|
||||
libtool
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -2,5 +2,6 @@
|
|||
<RCC version="1.0">
|
||||
<qresource>
|
||||
<file alias="melon-icon">icon/melon_256x256.png</file>
|
||||
<file alias="melon-logo">melon.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -33,17 +33,26 @@ ARCodeFile::ARCodeFile(const std::string& filename)
|
|||
{
|
||||
Filename = filename;
|
||||
|
||||
Error = false;
|
||||
|
||||
Categories.clear();
|
||||
|
||||
if (!Load())
|
||||
Error = true;
|
||||
}
|
||||
|
||||
ARCodeFile::~ARCodeFile()
|
||||
std::vector<ARCode> ARCodeFile::GetCodes() const noexcept
|
||||
{
|
||||
Categories.clear();
|
||||
if (Error)
|
||||
return {};
|
||||
|
||||
std::vector<ARCode> codes;
|
||||
|
||||
for (const ARCodeCat& cat : Categories)
|
||||
{
|
||||
for (const ARCode& code : cat.Codes)
|
||||
{
|
||||
codes.push_back(code);
|
||||
}
|
||||
}
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
bool ARCodeFile::Load()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -48,14 +48,16 @@ class ARCodeFile
|
|||
{
|
||||
public:
|
||||
ARCodeFile(const std::string& filename);
|
||||
~ARCodeFile();
|
||||
~ARCodeFile() noexcept = default;
|
||||
|
||||
bool Error;
|
||||
[[nodiscard]] std::vector<ARCode> GetCodes() const noexcept;
|
||||
|
||||
bool Error = false;
|
||||
|
||||
bool Load();
|
||||
bool Save();
|
||||
|
||||
ARCodeCatList Categories;
|
||||
ARCodeCatList Categories {};
|
||||
|
||||
private:
|
||||
std::string Filename;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -31,7 +31,6 @@ using Platform::LogLevel;
|
|||
|
||||
AREngine::AREngine(melonDS::NDS& nds) : NDS(nds)
|
||||
{
|
||||
CodeFile = nullptr;
|
||||
}
|
||||
|
||||
#define case16(x) \
|
||||
|
@ -388,19 +387,12 @@ void AREngine::RunCheat(const ARCode& arcode)
|
|||
|
||||
void AREngine::RunCheats()
|
||||
{
|
||||
if (!CodeFile) return;
|
||||
if (Cheats.empty()) return;
|
||||
|
||||
for (ARCodeCatList::iterator i = CodeFile->Categories.begin(); i != CodeFile->Categories.end(); i++)
|
||||
for (const ARCode& code : Cheats)
|
||||
{
|
||||
ARCodeCat& cat = *i;
|
||||
|
||||
for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++)
|
||||
{
|
||||
ARCode& code = *j;
|
||||
|
||||
if (code.Enabled)
|
||||
RunCheat(code);
|
||||
}
|
||||
if (code.Enabled)
|
||||
RunCheat(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
|||
#ifndef ARENGINE_H
|
||||
#define ARENGINE_H
|
||||
|
||||
#include <vector>
|
||||
#include "ARCodeFile.h"
|
||||
|
||||
namespace melonDS
|
||||
|
@ -29,14 +30,13 @@ class AREngine
|
|||
public:
|
||||
AREngine(melonDS::NDS& nds);
|
||||
|
||||
ARCodeFile* GetCodeFile() { return CodeFile; }
|
||||
void SetCodeFile(ARCodeFile* file) { CodeFile = file; }
|
||||
|
||||
std::vector<ARCode> Cheats {};
|
||||
private:
|
||||
friend class ARM;
|
||||
void RunCheats();
|
||||
void RunCheat(const ARCode& arcode);
|
||||
private:
|
||||
|
||||
melonDS::NDS& NDS;
|
||||
ARCodeFile* CodeFile; // AR code file - frontend is responsible for managing this
|
||||
};
|
||||
|
||||
}
|
||||
|
|
409
src/ARM.cpp
409
src/ARM.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -110,6 +110,7 @@ const u32 ARM::ConditionTable[16] =
|
|||
ARM::ARM(u32 num, bool jit, std::optional<GDBArgs> gdb, melonDS::NDS& nds) :
|
||||
#ifdef GDBSTUB_ENABLED
|
||||
GdbStub(this, gdb ? (num ? gdb->PortARM7 : gdb->PortARM9) : 0),
|
||||
BreakOnStartup(gdb ? (num ? gdb->ARM7BreakOnStartup : gdb->ARM9BreakOnStartup) : false),
|
||||
#endif
|
||||
Num(num), // well uh
|
||||
NDS(nds)
|
||||
|
@ -582,9 +583,11 @@ void ARM::CheckGdbIncoming()
|
|||
GdbCheckA();
|
||||
}
|
||||
|
||||
template <CPUExecuteMode mode>
|
||||
void ARMv5::Execute()
|
||||
{
|
||||
GdbCheckB();
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckB();
|
||||
|
||||
if (Halted)
|
||||
{
|
||||
|
@ -607,231 +610,125 @@ void ARMv5::Execute()
|
|||
|
||||
while (NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
{
|
||||
if (CPSR & 0x20) // THUMB
|
||||
#ifdef JIT_ENABLED
|
||||
if constexpr (mode == CPUExecuteMode::JIT)
|
||||
{
|
||||
GdbCheckC();
|
||||
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
|
||||
|
||||
// prefetch
|
||||
R[15] += 2;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; }
|
||||
else NextInstr[1] = CodeRead32(R[15], false);
|
||||
|
||||
// actually execute
|
||||
u32 icode = (CurInstr >> 6) & 0x3FF;
|
||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 4;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead32(R[15], false);
|
||||
|
||||
// actually execute
|
||||
if (CheckCondition(CurInstr >> 28))
|
||||
{
|
||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||
ARMInterpreter::ARMInstrTable[icode](this);
|
||||
}
|
||||
else if ((CurInstr & 0xFE000000) == 0xFA000000)
|
||||
{
|
||||
ARMInterpreter::A_BLX_IMM(this);
|
||||
}
|
||||
else
|
||||
AddCycles_C();
|
||||
}
|
||||
|
||||
// TODO optimize this shit!!!
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 1 && NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
|
||||
&& !NDS.JIT.SetupExecutableRegion(0, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
|
||||
{
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
Log(LogLevel::Error, "ARMv5 PC in non executable region %08X\n", R[15]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*if (NDS::IF[0] & NDS::IE[0])
|
||||
{
|
||||
if (NDS::IME[0] & 0x1)
|
||||
TriggerIRQ();
|
||||
}*/
|
||||
if (IRQ) TriggerIRQ();
|
||||
|
||||
NDS.ARM9Timestamp += Cycles;
|
||||
Cycles = 0;
|
||||
}
|
||||
JitBlockEntry block = NDS.JIT.LookUpBlock(0, FastBlockLookup,
|
||||
instrAddr - FastBlockLookupStart, instrAddr);
|
||||
if (block)
|
||||
ARM_Dispatch(this, block);
|
||||
else
|
||||
NDS.JIT.CompileBlock(this);
|
||||
|
||||
if (Halted == 2)
|
||||
Halted = 0;
|
||||
}
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
void ARMv5::ExecuteJIT()
|
||||
{
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 2)
|
||||
{
|
||||
Halted = 0;
|
||||
}
|
||||
else if (NDS.HaltInterrupted(0))
|
||||
{
|
||||
Halted = 0;
|
||||
if (NDS.IME[0] & 0x1)
|
||||
TriggerIRQ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
{
|
||||
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
|
||||
|
||||
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
|
||||
&& !NDS.JIT.SetupExecutableRegion(0, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
|
||||
{
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
Log(LogLevel::Error, "ARMv5 PC in non executable region %08X\n", R[15]);
|
||||
return;
|
||||
}
|
||||
|
||||
JitBlockEntry block = NDS.JIT.LookUpBlock(0, FastBlockLookup,
|
||||
instrAddr - FastBlockLookupStart, instrAddr);
|
||||
if (block)
|
||||
ARM_Dispatch(this, block);
|
||||
else
|
||||
NDS.JIT.CompileBlock(this);
|
||||
|
||||
if (StopExecution)
|
||||
{
|
||||
// this order is crucial otherwise idle loops waiting for an IRQ won't function
|
||||
if (IRQ)
|
||||
TriggerIRQ();
|
||||
|
||||
if (Halted || IdleLoop)
|
||||
if (StopExecution)
|
||||
{
|
||||
if ((Halted == 1 || IdleLoop) && NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
// this order is crucial otherwise idle loops waiting for an IRQ won't function
|
||||
if (IRQ)
|
||||
TriggerIRQ();
|
||||
|
||||
if (Halted || IdleLoop)
|
||||
{
|
||||
Cycles = 0;
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
if ((Halted == 1 || IdleLoop) && NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
{
|
||||
Cycles = 0;
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
}
|
||||
IdleLoop = 0;
|
||||
break;
|
||||
}
|
||||
IdleLoop = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NDS.ARM9Timestamp += Cycles;
|
||||
Cycles = 0;
|
||||
}
|
||||
|
||||
if (Halted == 2)
|
||||
Halted = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
void ARMv4::Execute()
|
||||
{
|
||||
GdbCheckB();
|
||||
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 2)
|
||||
{
|
||||
Halted = 0;
|
||||
}
|
||||
else if (NDS.HaltInterrupted(1))
|
||||
{
|
||||
Halted = 0;
|
||||
if (NDS.IME[1] & 0x1)
|
||||
TriggerIRQ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
{
|
||||
if (CPSR & 0x20) // THUMB
|
||||
{
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 2;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead16(R[15]);
|
||||
|
||||
// actually execute
|
||||
u32 icode = (CurInstr >> 6);
|
||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 4;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead32(R[15]);
|
||||
|
||||
// actually execute
|
||||
if (CheckCondition(CurInstr >> 28))
|
||||
if (CPSR & 0x20) // THUMB
|
||||
{
|
||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||
ARMInterpreter::ARMInstrTable[icode](this);
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 2;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; }
|
||||
else NextInstr[1] = CodeRead32(R[15], false);
|
||||
|
||||
// actually execute
|
||||
u32 icode = (CurInstr >> 6) & 0x3FF;
|
||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||
}
|
||||
else
|
||||
AddCycles_C();
|
||||
}
|
||||
|
||||
// TODO optimize this shit!!!
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 1 && NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
{
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*if (NDS::IF[1] & NDS::IE[1])
|
||||
{
|
||||
if (NDS::IME[1] & 0x1)
|
||||
TriggerIRQ();
|
||||
}*/
|
||||
if (IRQ) TriggerIRQ();
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckC();
|
||||
|
||||
NDS.ARM7Timestamp += Cycles;
|
||||
// prefetch
|
||||
R[15] += 4;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead32(R[15], false);
|
||||
|
||||
// actually execute
|
||||
if (CheckCondition(CurInstr >> 28))
|
||||
{
|
||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||
ARMInterpreter::ARMInstrTable[icode](this);
|
||||
}
|
||||
else if ((CurInstr & 0xFE000000) == 0xFA000000)
|
||||
{
|
||||
ARMInterpreter::A_BLX_IMM(this);
|
||||
}
|
||||
else
|
||||
AddCycles_C();
|
||||
}
|
||||
|
||||
// TODO optimize this shit!!!
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 1 && NDS.ARM9Timestamp < NDS.ARM9Target)
|
||||
{
|
||||
NDS.ARM9Timestamp = NDS.ARM9Target;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*if (NDS::IF[0] & NDS::IE[0])
|
||||
{
|
||||
if (NDS::IME[0] & 0x1)
|
||||
TriggerIRQ();
|
||||
}*/
|
||||
if (IRQ) TriggerIRQ();
|
||||
|
||||
}
|
||||
|
||||
NDS.ARM9Timestamp += Cycles;
|
||||
Cycles = 0;
|
||||
}
|
||||
|
||||
if (Halted == 2)
|
||||
Halted = 0;
|
||||
|
||||
if (Halted == 4)
|
||||
{
|
||||
assert(NDS.ConsoleType == 1);
|
||||
auto& dsi = dynamic_cast<melonDS::DSi&>(NDS);
|
||||
dsi.SoftReset();
|
||||
Halted = 2;
|
||||
}
|
||||
}
|
||||
|
||||
template void ARMv5::Execute<CPUExecuteMode::Interpreter>();
|
||||
template void ARMv5::Execute<CPUExecuteMode::InterpreterGDB>();
|
||||
#ifdef JIT_ENABLED
|
||||
void ARMv4::ExecuteJIT()
|
||||
template void ARMv5::Execute<CPUExecuteMode::JIT>();
|
||||
#endif
|
||||
|
||||
template <CPUExecuteMode mode>
|
||||
void ARMv4::Execute()
|
||||
{
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckB();
|
||||
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 2)
|
||||
|
@ -853,38 +750,97 @@ void ARMv4::ExecuteJIT()
|
|||
|
||||
while (NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
{
|
||||
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
|
||||
|
||||
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
|
||||
&& !NDS.JIT.SetupExecutableRegion(1, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
|
||||
#ifdef JIT_ENABLED
|
||||
if constexpr (mode == CPUExecuteMode::JIT)
|
||||
{
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
Log(LogLevel::Error, "ARMv4 PC in non executable region %08X\n", R[15]);
|
||||
return;
|
||||
}
|
||||
u32 instrAddr = R[15] - ((CPSR&0x20)?2:4);
|
||||
|
||||
JitBlockEntry block = NDS.JIT.LookUpBlock(1, FastBlockLookup,
|
||||
instrAddr - FastBlockLookupStart, instrAddr);
|
||||
if (block)
|
||||
ARM_Dispatch(this, block);
|
||||
else
|
||||
NDS.JIT.CompileBlock(this);
|
||||
|
||||
if (StopExecution)
|
||||
{
|
||||
if (IRQ)
|
||||
TriggerIRQ();
|
||||
|
||||
if (Halted || IdleLoop)
|
||||
if ((instrAddr < FastBlockLookupStart || instrAddr >= (FastBlockLookupStart + FastBlockLookupSize))
|
||||
&& !NDS.JIT.SetupExecutableRegion(1, instrAddr, FastBlockLookup, FastBlockLookupStart, FastBlockLookupSize))
|
||||
{
|
||||
if ((Halted == 1 || IdleLoop) && NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
Log(LogLevel::Error, "ARMv4 PC in non executable region %08X\n", R[15]);
|
||||
return;
|
||||
}
|
||||
|
||||
JitBlockEntry block = NDS.JIT.LookUpBlock(1, FastBlockLookup,
|
||||
instrAddr - FastBlockLookupStart, instrAddr);
|
||||
if (block)
|
||||
ARM_Dispatch(this, block);
|
||||
else
|
||||
NDS.JIT.CompileBlock(this);
|
||||
|
||||
if (StopExecution)
|
||||
{
|
||||
if (IRQ)
|
||||
TriggerIRQ();
|
||||
|
||||
if (Halted || IdleLoop)
|
||||
{
|
||||
if ((Halted == 1 || IdleLoop) && NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
{
|
||||
Cycles = 0;
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
}
|
||||
IdleLoop = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (CPSR & 0x20) // THUMB
|
||||
{
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 2;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead16(R[15]);
|
||||
|
||||
// actually execute
|
||||
u32 icode = (CurInstr >> 6);
|
||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (mode == CPUExecuteMode::InterpreterGDB)
|
||||
GdbCheckC();
|
||||
|
||||
// prefetch
|
||||
R[15] += 4;
|
||||
CurInstr = NextInstr[0];
|
||||
NextInstr[0] = NextInstr[1];
|
||||
NextInstr[1] = CodeRead32(R[15]);
|
||||
|
||||
// actually execute
|
||||
if (CheckCondition(CurInstr >> 28))
|
||||
{
|
||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||
ARMInterpreter::ARMInstrTable[icode](this);
|
||||
}
|
||||
else
|
||||
AddCycles_C();
|
||||
}
|
||||
|
||||
// TODO optimize this shit!!!
|
||||
if (Halted)
|
||||
{
|
||||
if (Halted == 1 && NDS.ARM7Timestamp < NDS.ARM7Target)
|
||||
{
|
||||
Cycles = 0;
|
||||
NDS.ARM7Timestamp = NDS.ARM7Target;
|
||||
}
|
||||
IdleLoop = 0;
|
||||
break;
|
||||
}
|
||||
/*if (NDS::IF[1] & NDS::IE[1])
|
||||
{
|
||||
if (NDS::IME[1] & 0x1)
|
||||
TriggerIRQ();
|
||||
}*/
|
||||
if (IRQ) TriggerIRQ();
|
||||
}
|
||||
|
||||
NDS.ARM7Timestamp += Cycles;
|
||||
|
@ -902,6 +858,11 @@ void ARMv4::ExecuteJIT()
|
|||
Halted = 2;
|
||||
}
|
||||
}
|
||||
|
||||
template void ARMv4::Execute<CPUExecuteMode::Interpreter>();
|
||||
template void ARMv4::Execute<CPUExecuteMode::InterpreterGDB>();
|
||||
#ifdef JIT_ENABLED
|
||||
template void ARMv4::Execute<CPUExecuteMode::JIT>();
|
||||
#endif
|
||||
|
||||
void ARMv5::FillPipeline()
|
||||
|
|
27
src/ARM.h
27
src/ARM.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -43,6 +43,15 @@ enum
|
|||
RWFlags_ForceUser = (1<<21),
|
||||
};
|
||||
|
||||
enum class CPUExecuteMode : u32
|
||||
{
|
||||
Interpreter,
|
||||
InterpreterGDB,
|
||||
#ifdef JIT_ENABLED
|
||||
JIT
|
||||
#endif
|
||||
};
|
||||
|
||||
struct GDBArgs;
|
||||
class ARMJIT;
|
||||
class GPU;
|
||||
|
@ -75,10 +84,6 @@ public:
|
|||
}
|
||||
|
||||
void NocashPrint(u32 addr) noexcept;
|
||||
virtual void Execute() = 0;
|
||||
#ifdef JIT_ENABLED
|
||||
virtual void ExecuteJIT() = 0;
|
||||
#endif
|
||||
|
||||
bool CheckCondition(u32 code) const
|
||||
{
|
||||
|
@ -241,10 +246,8 @@ public:
|
|||
void PrefetchAbort();
|
||||
void DataAbort();
|
||||
|
||||
void Execute() override;
|
||||
#ifdef JIT_ENABLED
|
||||
void ExecuteJIT() override;
|
||||
#endif
|
||||
template <CPUExecuteMode mode>
|
||||
void Execute();
|
||||
|
||||
// all code accesses are forced nonseq 32bit
|
||||
u32 CodeRead32(u32 addr, bool branch);
|
||||
|
@ -383,10 +386,8 @@ public:
|
|||
|
||||
void JumpTo(u32 addr, bool restorecpsr = false) override;
|
||||
|
||||
void Execute() override;
|
||||
#ifdef JIT_ENABLED
|
||||
void ExecuteJIT() override;
|
||||
#endif
|
||||
template <CPUExecuteMode mode>
|
||||
void Execute();
|
||||
|
||||
u16 CodeRead16(u32 addr)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -38,7 +38,7 @@ 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);
|
||||
cpu->GdbStub.Enter(cpu->GdbStub.IsConnected(), 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();
|
||||
|
@ -56,7 +56,7 @@ 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);
|
||||
cpu->GdbStub.Enter(cpu->GdbStub.IsConnected(), Gdb::TgtStatus::FaultInsn, cpu->R[15]-4);
|
||||
#endif
|
||||
//NDS::Halt();
|
||||
u32 oldcpsr = cpu->CPSR;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -430,9 +430,9 @@ void A_LDM(ARM* cpu)
|
|||
}
|
||||
}
|
||||
|
||||
u32 pc = 0;
|
||||
if (cpu->CurInstr & (1<<15))
|
||||
{
|
||||
u32 pc;
|
||||
if (preinc) base += 4;
|
||||
if (first) cpu->DataRead32 (base, &pc);
|
||||
else cpu->DataRead32S(base, &pc);
|
||||
|
@ -440,13 +440,8 @@ void A_LDM(ARM* cpu)
|
|||
|
||||
if (cpu->Num == 1)
|
||||
pc &= ~0x1;
|
||||
|
||||
cpu->JumpTo(pc, cpu->CurInstr & (1<<22));
|
||||
}
|
||||
|
||||
if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15)))
|
||||
cpu->UpdateMode((cpu->CPSR&~0x1F)|0x10, cpu->CPSR, true);
|
||||
|
||||
if (cpu->CurInstr & (1<<21))
|
||||
{
|
||||
// post writeback
|
||||
|
@ -466,6 +461,12 @@ void A_LDM(ARM* cpu)
|
|||
cpu->R[baseid] = wbbase;
|
||||
}
|
||||
|
||||
if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15)))
|
||||
cpu->UpdateMode((cpu->CPSR&~0x1F)|0x10, cpu->CPSR, true);
|
||||
|
||||
if (cpu->CurInstr & (1<<15))
|
||||
cpu->JumpTo(pc, cpu->CurInstr & (1<<22));
|
||||
|
||||
cpu->AddCycles_CDI();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2022 melonDS team, RSDuck
|
||||
Copyright 2016-2024 melonDS team, RSDuck
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
14
src/Args.h
14
src/Args.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -69,6 +69,10 @@ struct JITArgs
|
|||
bool FastMemory = true;
|
||||
};
|
||||
|
||||
using ARM9BIOSImage = std::array<u8, ARM9BIOSSize>;
|
||||
using ARM7BIOSImage = std::array<u8, ARM7BIOSSize>;
|
||||
using DSiBIOSImage = std::array<u8, DSiBIOSSize>;
|
||||
|
||||
struct GDBArgs
|
||||
{
|
||||
u16 PortARM7 = 0;
|
||||
|
@ -95,11 +99,11 @@ struct NDSArgs
|
|||
|
||||
/// NDS ARM9 BIOS to install.
|
||||
/// Defaults to FreeBIOS, which is not compatible with DSi mode.
|
||||
std::array<u8, ARM9BIOSSize> ARM9BIOS = bios_arm9_bin;
|
||||
std::unique_ptr<ARM9BIOSImage> ARM9BIOS = std::make_unique<ARM9BIOSImage>(bios_arm9_bin);
|
||||
|
||||
/// NDS ARM7 BIOS to install.
|
||||
/// Defaults to FreeBIOS, which is not compatible with DSi mode.
|
||||
std::array<u8, ARM7BIOSSize> ARM7BIOS = bios_arm7_bin;
|
||||
std::unique_ptr<ARM7BIOSImage> ARM7BIOS = std::make_unique<ARM7BIOSImage>(bios_arm7_bin);
|
||||
|
||||
/// Firmware image to install.
|
||||
/// Defaults to generated NDS firmware.
|
||||
|
@ -131,8 +135,8 @@ struct NDSArgs
|
|||
/// Contains no virtual methods, so there's no vtable.
|
||||
struct DSiArgs final : public NDSArgs
|
||||
{
|
||||
std::array<u8, DSiBIOSSize> ARM9iBIOS = BrokenBIOS<DSiBIOSSize>;
|
||||
std::array<u8, DSiBIOSSize> ARM7iBIOS = BrokenBIOS<DSiBIOSSize>;
|
||||
std::unique_ptr<DSiBIOSImage> ARM9iBIOS = std::make_unique<DSiBIOSImage>(BrokenBIOS<DSiBIOSSize>);
|
||||
std::unique_ptr<DSiBIOSImage> ARM7iBIOS = std::make_unique<DSiBIOSImage>(BrokenBIOS<DSiBIOSSize>);
|
||||
|
||||
/// NAND image to install.
|
||||
/// Required, there is no default value.
|
||||
|
|
|
@ -35,6 +35,8 @@ add_library(core STATIC
|
|||
GPU2D_Soft.cpp
|
||||
GPU3D.cpp
|
||||
GPU3D_Soft.cpp
|
||||
GPU3D_Texcache.cpp
|
||||
GPU3D_Texcache.h
|
||||
melonDLDI.h
|
||||
NDS.cpp
|
||||
NDSCart.cpp
|
||||
|
@ -52,7 +54,6 @@ add_library(core STATIC
|
|||
types.h
|
||||
Utils.cpp
|
||||
Utils.h
|
||||
version.h
|
||||
Wifi.cpp
|
||||
WifiAP.cpp
|
||||
|
||||
|
@ -79,6 +80,9 @@ if (ENABLE_OGLRENDERER)
|
|||
GPU_OpenGL.cpp
|
||||
GPU_OpenGL_shaders.h
|
||||
GPU3D_OpenGL.cpp
|
||||
GPU3D_Compute.cpp
|
||||
GPU3D_TexcacheOpenGL.cpp
|
||||
GPU3D_TexcacheOpenGL.h
|
||||
GPU3D_OpenGL_shaders.h
|
||||
OpenGLSupport.cpp)
|
||||
|
||||
|
@ -123,6 +127,24 @@ if (ENABLE_JIT)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
set(MELONDS_VERSION_SUFFIX "$ENV{MELONDS_VERSION_SUFFIX}" CACHE STRING "Suffix to add to displayed melonDS version")
|
||||
option(MELONDS_EMBED_BUILD_INFO "Embed detailed build info into the binary" OFF)
|
||||
set(MELONDS_GIT_BRANCH "$ENV{MELONDS_GIT_BRANCH}" CACHE STRING "The Git branch used for this build")
|
||||
set(MELONDS_GIT_HASH "$ENV{MELONDS_GIT_HASH}" CACHE STRING "The hash of the Git commit")
|
||||
set(MELONDS_BUILD_PROVIDER "$ENV{MELONDS_BUILD_PROVIDER}" CACHE STRING "The name of the provider of this build")
|
||||
|
||||
if (MELONDS_EMBED_BUILD_INFO)
|
||||
target_compile_definitions(core PUBLIC MELONDS_EMBED_BUILD_INFO)
|
||||
if (NOT MELONDS_GIT_BRANCH OR NOT MELONDS_GIT_HASH OR NOT MELONDS_BUILD_PROVIDER)
|
||||
message(FATAL_ERROR "When embedding build information, all fields must be filled out. See src/CMakeLists.txt.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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}")
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(teakra EXCLUDE_FROM_ALL)
|
||||
# Workaround for building teakra with -O0 on Windows either failing or hanging forever
|
||||
target_compile_options(teakra PRIVATE "$<$<CONFIG:DEBUG>:-Og>")
|
||||
|
@ -130,7 +152,9 @@ 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.
|
||||
# be sure to add equivalent flags here.
|
||||
|
||||
target_compile_options(core PUBLIC -fwrapv)
|
||||
|
||||
target_compile_options(core PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>")
|
||||
# These warnings are excessive, and are only triggered in the ARMJIT code
|
||||
|
@ -154,11 +178,13 @@ endif()
|
|||
|
||||
if (WIN32)
|
||||
target_link_libraries(core PRIVATE ole32 comctl32 wsock32 ws2_32)
|
||||
elseif(NOT APPLE)
|
||||
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)
|
||||
|
|
20
src/CP15.cpp
20
src/CP15.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -186,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<<size); // add 1 left shifted by size to start to determine end point
|
||||
// dont need to bounds check the end point because the force alignment inherently prevents it from breaking
|
||||
|
||||
u8 usermask = 0;
|
||||
u8 privmask = 0;
|
||||
|
@ -239,7 +243,7 @@ void ARMv5::UpdatePURegion(u32 n)
|
|||
"PU region %d: %08X-%08X, user=%02X priv=%02X, %08X/%08X\n",
|
||||
n,
|
||||
start << 12,
|
||||
end << 12,
|
||||
(end << 12) - 1,
|
||||
usermask,
|
||||
privmask,
|
||||
PU_DataRW,
|
||||
|
@ -579,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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
|||
#include "DSi.h"
|
||||
#include "DMA.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D.h"
|
||||
#include "DMA_Timings.h"
|
||||
#include "Platform.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
30
src/DSi.cpp
30
src/DSi.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -70,8 +70,28 @@ const u32 NDMAModes[] =
|
|||
0xFF, // wifi / GBA cart slot (TODO)
|
||||
};
|
||||
|
||||
DSi::DSi(DSiArgs&& args) noexcept :
|
||||
NDS(std::move(args), 1),
|
||||
/*DSi::DSi() noexcept :
|
||||
DSi(
|
||||
DSiArgs {
|
||||
NDSArgs {
|
||||
nullptr,
|
||||
nullptr,
|
||||
bios_arm9_bin,
|
||||
bios_arm7_bin,
|
||||
Firmware(0),
|
||||
},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
false
|
||||
}
|
||||
)
|
||||
{
|
||||
}*/
|
||||
|
||||
DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
|
||||
NDS(std::move(args), 1, userdata),
|
||||
NDMAs {
|
||||
DSi_NDMA(0, 0, *this),
|
||||
DSi_NDMA(0, 1, *this),
|
||||
|
@ -82,8 +102,8 @@ DSi::DSi(DSiArgs&& args) noexcept :
|
|||
DSi_NDMA(1, 2, *this),
|
||||
DSi_NDMA(1, 3, *this),
|
||||
},
|
||||
ARM7iBIOS(args.ARM7iBIOS),
|
||||
ARM9iBIOS(args.ARM9iBIOS),
|
||||
ARM7iBIOS(*args.ARM7iBIOS),
|
||||
ARM9iBIOS(*args.ARM9iBIOS),
|
||||
DSP(*this),
|
||||
SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)),
|
||||
SDIO(*this),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -130,7 +130,8 @@ public:
|
|||
void ARM7IOWrite32(u32 addr, u32 val) override;
|
||||
|
||||
public:
|
||||
DSi(DSiArgs&& args) noexcept;
|
||||
DSi(DSiArgs&& args, void* userdata = nullptr) noexcept;
|
||||
//DSi() noexcept;
|
||||
~DSi() noexcept override;
|
||||
DSi(const DSi&) = delete;
|
||||
DSi& operator=(const DSi&) = delete;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace melonDS
|
|||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 11) // gcc 11.*
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 11) && defined(__SIZEOF_INT128__) // gcc 11.*
|
||||
// NOTE: Yes, the compiler does *not* recognize this code pattern, so it is indeed an optimization.
|
||||
__attribute((always_inline)) static void Bswap128(void* Dst, const void* Src)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -410,7 +410,7 @@ void DSi_Camera::DoSavestate(Savestate* file)
|
|||
|
||||
void DSi_Camera::Reset()
|
||||
{
|
||||
Platform::Camera_Stop(Num);
|
||||
Platform::Camera_Stop(Num, DSi.UserData);
|
||||
|
||||
DataPos = 0;
|
||||
RegAddr = 0;
|
||||
|
@ -435,7 +435,7 @@ void DSi_Camera::Reset()
|
|||
|
||||
void DSi_Camera::Stop()
|
||||
{
|
||||
Platform::Camera_Stop(Num);
|
||||
Platform::Camera_Stop(Num, DSi.UserData);
|
||||
}
|
||||
|
||||
bool DSi_Camera::IsActivated() const
|
||||
|
@ -474,7 +474,7 @@ void DSi_Camera::StartTransfer()
|
|||
FrameFormat = 0;
|
||||
}
|
||||
|
||||
Platform::Camera_CaptureFrame(Num, FrameBuffer, 640, 480, true);
|
||||
Platform::Camera_CaptureFrame(Num, FrameBuffer, 640, 480, true, DSi.UserData);
|
||||
}
|
||||
|
||||
bool DSi_Camera::TransferDone() const
|
||||
|
@ -655,8 +655,8 @@ void DSi_Camera::I2C_WriteReg(u16 addr, u16 val)
|
|||
StandbyCnt = val;
|
||||
//printf("CAM%d STBCNT=%04X (%04X)\n", Num, StandbyCnt, val);
|
||||
bool isactive = IsActivated();
|
||||
if (isactive && !wasactive) Platform::Camera_Start(Num);
|
||||
else if (wasactive && !isactive) Platform::Camera_Stop(Num);
|
||||
if (isactive && !wasactive) Platform::Camera_Start(Num, DSi.UserData);
|
||||
else if (wasactive && !isactive) Platform::Camera_Stop(Num, DSi.UserData);
|
||||
}
|
||||
return;
|
||||
case 0x001A:
|
||||
|
@ -665,8 +665,8 @@ void DSi_Camera::I2C_WriteReg(u16 addr, u16 val)
|
|||
MiscCnt = val & 0x0B7B;
|
||||
//printf("CAM%d MISCCNT=%04X (%04X)\n", Num, MiscCnt, val);
|
||||
bool isactive = IsActivated();
|
||||
if (isactive && !wasactive) Platform::Camera_Start(Num);
|
||||
else if (wasactive && !isactive) Platform::Camera_Stop(Num);
|
||||
if (isactive && !wasactive) Platform::Camera_Start(Num, DSi.UserData);
|
||||
else if (wasactive && !isactive) Platform::Camera_Stop(Num, DSi.UserData);
|
||||
}
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -87,6 +87,7 @@ public:
|
|||
void DoSavestate(Savestate* file) override;
|
||||
|
||||
u8 GetBootFlag() const;
|
||||
void SetBootFlag(u8 boot) noexcept { Registers[0x70] = boot; }
|
||||
|
||||
bool GetBatteryCharging() const;
|
||||
void SetBatteryCharging(bool charging);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include "DSi_NDMA.h"
|
||||
#include "GPU.h"
|
||||
#include "DSi_AES.h"
|
||||
#include "GPU3D.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -1334,7 +1334,7 @@ void DSi_NWifi::WMI_SendPacket(u16 len)
|
|||
}
|
||||
printf("\n");*/
|
||||
|
||||
Platform::LAN_SendPacket(LANBuffer, lan_len);
|
||||
Platform::Net_SendPacket(LANBuffer, lan_len, DSi.UserData);
|
||||
}
|
||||
|
||||
void DSi_NWifi::SendWMIEvent(u8 ep, u16 id, u8* data, u32 len)
|
||||
|
@ -1442,20 +1442,25 @@ void DSi_NWifi::CheckRX()
|
|||
if (!Mailbox[8].CanFit(2048))
|
||||
return;
|
||||
|
||||
int rxlen = Platform::LAN_RecvPacket(LANBuffer);
|
||||
if (rxlen > 0)
|
||||
int rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
|
||||
while (rxlen > 0)
|
||||
{
|
||||
//printf("WMI packet recv %04X %04X %04X\n", *(u16*)&LANBuffer[0], *(u16*)&LANBuffer[2], *(u16*)&LANBuffer[4]);
|
||||
// check destination MAC
|
||||
if (*(u32*)&LANBuffer[0] != 0xFFFFFFFF || *(u16*)&LANBuffer[4] != 0xFFFF)
|
||||
{
|
||||
if (memcmp(&LANBuffer[0], &EEPROM[0x00A], 6))
|
||||
return;
|
||||
{
|
||||
rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// check source MAC, in case we get a packet we just sent out
|
||||
if (!memcmp(&LANBuffer[6], &EEPROM[0x00A], 6))
|
||||
return;
|
||||
{
|
||||
rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
|
||||
continue;
|
||||
}
|
||||
|
||||
// packet is good
|
||||
|
||||
|
@ -1502,6 +1507,7 @@ void DSi_NWifi::CheckRX()
|
|||
Mailbox[8].Write(LANBuffer[14+i]);
|
||||
|
||||
DrainRXBuffer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -110,6 +110,7 @@ bool FATStorage::InjectFile(const std::string& path, u8* data, u32 len)
|
|||
res = f_mount(&fs, "0:", 1);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
f_unmount("0:");
|
||||
ff_disk_close();
|
||||
return false;
|
||||
}
|
||||
|
@ -146,6 +147,7 @@ u32 FATStorage::ReadFile(const std::string& path, u32 start, u32 len, u8* data)
|
|||
res = f_mount(&fs, "0:", 1);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
f_unmount("0:");
|
||||
ff_disk_close();
|
||||
return false;
|
||||
}
|
||||
|
@ -1144,6 +1146,7 @@ bool FATStorage::Save()
|
|||
res = f_mount(&fs, "0:", 1);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
f_unmount("0:");
|
||||
ff_disk_close();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
119
src/FIFO.h
119
src/FIFO.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
|||
|
||||
namespace melonDS
|
||||
{
|
||||
|
||||
template<typename T, u32 NumEntries>
|
||||
class FIFO
|
||||
{
|
||||
|
@ -191,5 +192,121 @@ private:
|
|||
u32 ReadPos, WritePos;
|
||||
};
|
||||
|
||||
template<u32 Size>
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
void Clear()
|
||||
{
|
||||
NumOccupied = 0;
|
||||
ReadPos = 0;
|
||||
WritePos = 0;
|
||||
memset(Buffer, 0, Size);
|
||||
}
|
||||
|
||||
|
||||
void DoSavestate(Savestate* file)
|
||||
{
|
||||
file->Var32(&NumOccupied);
|
||||
file->Var32(&ReadPos);
|
||||
file->Var32(&WritePos);
|
||||
|
||||
file->VarArray(Buffer, Size);
|
||||
}
|
||||
|
||||
|
||||
bool Write(const void* data, u32 len)
|
||||
{
|
||||
if (!CanFit(len)) return false;
|
||||
|
||||
if ((WritePos + len) >= Size)
|
||||
{
|
||||
u32 part1 = Size - WritePos;
|
||||
memcpy(&Buffer[WritePos], data, part1);
|
||||
if (len > part1)
|
||||
memcpy(Buffer, &((u8*)data)[part1], len - part1);
|
||||
WritePos = len - part1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&Buffer[WritePos], data, len);
|
||||
WritePos += len;
|
||||
}
|
||||
|
||||
NumOccupied += len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(void* data, u32 len)
|
||||
{
|
||||
if (NumOccupied < len) return false;
|
||||
|
||||
u32 readpos = ReadPos;
|
||||
if ((readpos + len) >= Size)
|
||||
{
|
||||
u32 part1 = Size - readpos;
|
||||
memcpy(data, &Buffer[readpos], part1);
|
||||
if (len > part1)
|
||||
memcpy(&((u8*)data)[part1], Buffer, len - part1);
|
||||
ReadPos = len - part1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(data, &Buffer[readpos], len);
|
||||
ReadPos += len;
|
||||
}
|
||||
|
||||
NumOccupied -= len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Peek(void* data, u32 offset, u32 len)
|
||||
{
|
||||
if (NumOccupied < len) return false;
|
||||
|
||||
u32 readpos = ReadPos + offset;
|
||||
if (readpos >= Size) readpos -= Size;
|
||||
|
||||
if ((readpos + len) >= Size)
|
||||
{
|
||||
u32 part1 = Size - readpos;
|
||||
memcpy(data, &Buffer[readpos], part1);
|
||||
if (len > part1)
|
||||
memcpy(&((u8*)data)[part1], Buffer, len - part1);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(data, &Buffer[readpos], len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Skip(u32 len)
|
||||
{
|
||||
if (NumOccupied < len) return false;
|
||||
|
||||
ReadPos += len;
|
||||
if (ReadPos >= Size)
|
||||
ReadPos -= Size;
|
||||
|
||||
NumOccupied -= len;
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 Level() const { return NumOccupied; }
|
||||
bool IsEmpty() const { return NumOccupied == 0; }
|
||||
bool IsFull() const { return NumOccupied >= Size; }
|
||||
|
||||
bool CanFit(u32 num) const { return ((NumOccupied + num) <= Size); }
|
||||
|
||||
private:
|
||||
u8 Buffer[Size] = {0};
|
||||
u32 NumOccupied = 0;
|
||||
u32 ReadPos = 0, WritePos = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -95,17 +95,18 @@ u32 CartCommon::GetSaveMemoryLength() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
CartGame::CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, GBACart::CartType type) :
|
||||
CartGame(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, type)
|
||||
CartGame::CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata, GBACart::CartType type) :
|
||||
CartGame(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, userdata, type)
|
||||
{
|
||||
}
|
||||
|
||||
CartGame::CartGame(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, GBACart::CartType type) :
|
||||
CartGame::CartGame(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, void* userdata, GBACart::CartType type) :
|
||||
CartCommon(type),
|
||||
ROM(std::move(rom)),
|
||||
ROMLength(len),
|
||||
SRAM(std::move(sram)),
|
||||
SRAMLength(sramlen)
|
||||
SRAMLength(sramlen),
|
||||
UserData(userdata)
|
||||
{
|
||||
if (SRAM && SRAMLength)
|
||||
{
|
||||
|
@ -170,7 +171,7 @@ void CartGame::DoSavestate(Savestate* file)
|
|||
file->Var8((u8*)&SRAMType);
|
||||
|
||||
if ((!file->Saving) && SRAM)
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, 0, SRAMLength);
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, 0, SRAMLength, UserData);
|
||||
}
|
||||
|
||||
void CartGame::SetupSave(u32 type)
|
||||
|
@ -223,7 +224,7 @@ void CartGame::SetSaveMemory(const u8* savedata, u32 savelen)
|
|||
|
||||
u32 len = std::min(savelen, SRAMLength);
|
||||
memcpy(SRAM.get(), savedata, len);
|
||||
Platform::WriteGBASave(savedata, len, 0, len);
|
||||
Platform::WriteGBASave(savedata, len, 0, len, UserData);
|
||||
}
|
||||
|
||||
u16 CartGame::ROMRead(u32 addr) const
|
||||
|
@ -464,7 +465,7 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
|
|||
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
|
||||
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
|
||||
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, start_addr, 0x1000);
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, start_addr, 0x1000, UserData);
|
||||
}
|
||||
SRAMFlashState.state = 0;
|
||||
SRAMFlashState.cmd = 0;
|
||||
|
@ -523,18 +524,18 @@ void CartGame::SRAMWrite_SRAM(u32 addr, u8 val)
|
|||
*(u8*)&SRAM[addr] = val;
|
||||
|
||||
// TODO: optimize this!!
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, addr, 1);
|
||||
Platform::WriteGBASave(SRAM.get(), SRAMLength, addr, 1, UserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CartGameSolarSensor::CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen) :
|
||||
CartGameSolarSensor(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen)
|
||||
CartGameSolarSensor::CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata) :
|
||||
CartGameSolarSensor(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, userdata)
|
||||
{
|
||||
}
|
||||
|
||||
CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen) :
|
||||
CartGame(std::move(rom), len, std::move(sram), sramlen, CartType::GameSolarSensor)
|
||||
CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, void* userdata) :
|
||||
CartGame(std::move(rom), len, std::move(sram), sramlen, userdata, CartType::GameSolarSensor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -581,6 +582,11 @@ int CartGameSolarSensor::SetInput(int num, bool pressed)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void CartGameSolarSensor::SetLightLevel(u8 level) noexcept
|
||||
{
|
||||
LightLevel = std::clamp<u8>(level, 0, 10);
|
||||
}
|
||||
|
||||
void CartGameSolarSensor::ProcessGPIO()
|
||||
{
|
||||
if (GPIO.data & 4) return; // Boktai chip select
|
||||
|
@ -680,7 +686,45 @@ void CartRAMExpansion::ROMWrite(u32 addr, u16 val)
|
|||
}
|
||||
}
|
||||
|
||||
GBACartSlot::GBACartSlot(std::unique_ptr<CartCommon>&& cart) noexcept : Cart(std::move(cart))
|
||||
CartRumblePak::CartRumblePak(void* userdata) :
|
||||
CartCommon(RumblePak),
|
||||
UserData(userdata)
|
||||
{
|
||||
}
|
||||
|
||||
CartRumblePak::~CartRumblePak() = default;
|
||||
|
||||
void CartRumblePak::Reset()
|
||||
{
|
||||
RumbleState = 0;
|
||||
}
|
||||
|
||||
void CartRumblePak::DoSavestate(Savestate* file)
|
||||
{
|
||||
CartCommon::DoSavestate(file);
|
||||
file->Var16(&RumbleState);
|
||||
}
|
||||
|
||||
u16 CartRumblePak::ROMRead(u32 addr) const
|
||||
{
|
||||
// A1 is pulled low on a real Rumble Pak, so return the
|
||||
// necessary detection value here,
|
||||
// and let the existing open bus implementation take care of the rest
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
void CartRumblePak::ROMWrite(u32 addr, u16 val)
|
||||
{
|
||||
addr &= 0x01FFFFFF;
|
||||
if (RumbleState != val)
|
||||
{
|
||||
Platform::Addon_RumbleStop(UserData);
|
||||
RumbleState = val;
|
||||
Platform::Addon_RumbleStart(16, UserData);
|
||||
}
|
||||
}
|
||||
|
||||
GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -723,24 +767,24 @@ void GBACartSlot::DoSavestate(Savestate* file) noexcept
|
|||
if (Cart) Cart->DoSavestate(file);
|
||||
}
|
||||
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen)
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, void* userdata)
|
||||
{
|
||||
return ParseROM(std::move(romdata), romlen, nullptr, 0);
|
||||
return ParseROM(std::move(romdata), romlen, nullptr, 0, userdata);
|
||||
}
|
||||
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen)
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen, void* userdata)
|
||||
{
|
||||
auto [romcopy, romcopylen] = PadToPowerOf2(romdata, romlen);
|
||||
|
||||
return ParseROM(std::move(romcopy), romcopylen, CopyToUnique(sramdata, sramlen), sramlen);
|
||||
return ParseROM(std::move(romcopy), romcopylen, CopyToUnique(sramdata, sramlen), sramlen, userdata);
|
||||
}
|
||||
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen)
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, void* userdata)
|
||||
{
|
||||
return ParseROM(romdata, romlen, nullptr, 0);
|
||||
return ParseROM(romdata, romlen, nullptr, 0, userdata);
|
||||
}
|
||||
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::unique_ptr<u8[]>&& sramdata, u32 sramlen)
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::unique_ptr<u8[]>&& sramdata, u32 sramlen, void* userdata)
|
||||
{
|
||||
if (romdata == nullptr)
|
||||
{
|
||||
|
@ -773,9 +817,9 @@ std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
|
|||
|
||||
std::unique_ptr<CartCommon> cart;
|
||||
if (solarsensor)
|
||||
cart = std::make_unique<CartGameSolarSensor>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
|
||||
cart = std::make_unique<CartGameSolarSensor>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen, userdata);
|
||||
else
|
||||
cart = std::make_unique<CartGame>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
|
||||
cart = std::make_unique<CartGame>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen, userdata);
|
||||
|
||||
cart->Reset();
|
||||
|
||||
|
@ -794,7 +838,7 @@ void GBACartSlot::SetCart(std::unique_ptr<CartCommon>&& cart) noexcept
|
|||
|
||||
if (!Cart)
|
||||
{
|
||||
Log(LogLevel::Info, "Ejected GBA cart");
|
||||
Log(LogLevel::Info, "Ejected GBA cart\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -820,13 +864,16 @@ void GBACartSlot::SetSaveMemory(const u8* savedata, u32 savelen) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void GBACartSlot::LoadAddon(int type) noexcept
|
||||
void GBACartSlot::LoadAddon(void* userdata, int type) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GBAAddon_RAMExpansion:
|
||||
Cart = std::make_unique<CartRAMExpansion>();
|
||||
break;
|
||||
case GBAAddon_RumblePak:
|
||||
Cart = std::make_unique<CartRumblePak>(userdata);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
|
||||
|
@ -875,4 +922,4 @@ void GBACartSlot::SRAMWrite(u32 addr, u8 val) noexcept
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -32,6 +32,7 @@ enum CartType
|
|||
Game = 0x101,
|
||||
GameSolarSensor = 0x102,
|
||||
RAMExpansion = 0x201,
|
||||
RumblePak = 0x202,
|
||||
};
|
||||
|
||||
// CartCommon -- base code shared by all cart types
|
||||
|
@ -72,8 +73,8 @@ private:
|
|||
class CartGame : public CartCommon
|
||||
{
|
||||
public:
|
||||
CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game);
|
||||
CartGame(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game);
|
||||
CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata, GBACart::CartType type = GBACart::CartType::Game);
|
||||
CartGame(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, void* userdata, GBACart::CartType type = GBACart::CartType::Game);
|
||||
~CartGame() override;
|
||||
|
||||
u32 Checksum() const override;
|
||||
|
@ -104,6 +105,8 @@ protected:
|
|||
u8 SRAMRead_SRAM(u32 addr);
|
||||
void SRAMWrite_SRAM(u32 addr, u8 val);
|
||||
|
||||
void* UserData;
|
||||
|
||||
std::unique_ptr<u8[]> ROM;
|
||||
u32 ROMLength;
|
||||
|
||||
|
@ -147,14 +150,16 @@ private:
|
|||
class CartGameSolarSensor : public CartGame
|
||||
{
|
||||
public:
|
||||
CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen);
|
||||
CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen);
|
||||
CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata);
|
||||
CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, void* userdata);
|
||||
|
||||
void Reset() override;
|
||||
|
||||
void DoSavestate(Savestate* file) override;
|
||||
|
||||
int SetInput(int num, bool pressed) override;
|
||||
void SetLightLevel(u8 level) noexcept;
|
||||
[[nodiscard]] u8 GetLightLevel() const noexcept { return LightLevel; }
|
||||
|
||||
protected:
|
||||
void ProcessGPIO() override;
|
||||
|
@ -187,6 +192,25 @@ private:
|
|||
u16 RAMEnable = 0;
|
||||
};
|
||||
|
||||
// CartRumblePak -- DS Rumble Pak (used in various NDS games)
|
||||
class CartRumblePak : public CartCommon
|
||||
{
|
||||
public:
|
||||
CartRumblePak(void* userdata);
|
||||
~CartRumblePak() override;
|
||||
|
||||
void Reset() override;
|
||||
|
||||
void DoSavestate(Savestate* file) override;
|
||||
|
||||
u16 ROMRead(u32 addr) const override;
|
||||
void ROMWrite(u32 addr, u16 val) override;
|
||||
|
||||
private:
|
||||
void* UserData;
|
||||
u16 RumbleState = 0;
|
||||
};
|
||||
|
||||
// possible inputs for GBA carts that might accept user input
|
||||
enum
|
||||
{
|
||||
|
@ -197,7 +221,7 @@ enum
|
|||
class GBACartSlot
|
||||
{
|
||||
public:
|
||||
GBACartSlot(std::unique_ptr<CartCommon>&& cart = nullptr) noexcept;
|
||||
GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart = nullptr) noexcept;
|
||||
~GBACartSlot() noexcept = default;
|
||||
void Reset() noexcept;
|
||||
void DoSavestate(Savestate* file) noexcept;
|
||||
|
@ -217,7 +241,7 @@ public:
|
|||
[[nodiscard]] CartCommon* GetCart() noexcept { return Cart.get(); }
|
||||
[[nodiscard]] const CartCommon* GetCart() const noexcept { return Cart.get(); }
|
||||
|
||||
void LoadAddon(int type) noexcept;
|
||||
void LoadAddon(void* userdata, int type) noexcept;
|
||||
|
||||
/// @return The cart that was in the cart slot if any,
|
||||
/// or \c nullptr if the cart slot was empty.
|
||||
|
@ -258,6 +282,7 @@ public:
|
|||
/// if a cart is loaded and supports SRAM, otherwise zero.
|
||||
[[nodiscard]] u32 GetSaveMemoryLength() const noexcept { return Cart ? Cart->GetSaveMemoryLength() : 0; }
|
||||
private:
|
||||
melonDS::NDS& NDS;
|
||||
std::unique_ptr<CartCommon> Cart = nullptr;
|
||||
u16 OpenBusDecay = 0;
|
||||
};
|
||||
|
@ -270,9 +295,9 @@ private:
|
|||
/// @param romlen The length of the ROM data in bytes.
|
||||
/// @returns A \c GBACart::CartCommon object representing the parsed ROM,
|
||||
/// or \c nullptr if the ROM data couldn't be parsed.
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen);
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen);
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen);
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, void* userdata = nullptr);
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, void* userdata = nullptr);
|
||||
std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen, void* userdata = nullptr);
|
||||
|
||||
/// @param romdata The ROM data to parse. Will be moved-from.
|
||||
/// @param romlen Length of romdata in bytes.
|
||||
|
@ -282,7 +307,7 @@ std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sr
|
|||
/// May be zero, in which case the cart will have no save data.
|
||||
/// @return Unique pointer to the parsed GBA cart,
|
||||
/// or \c nullptr if there was an error.
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::unique_ptr<u8[]>&& sramdata, u32 sramlen);
|
||||
std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::unique_ptr<u8[]>&& sramdata, u32 sramlen, void* userdata = nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
|||
#include "ARMJIT.h"
|
||||
|
||||
#include "GPU2D_Soft.h"
|
||||
#include "GPU3D_Soft.h"
|
||||
#include "GPU3D.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
|
13
src/GPU.h
13
src/GPU.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -499,6 +499,17 @@ public:
|
|||
OAMDirty |= 1 << (addr / 1024);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ReadVRAMFlat_Texture(u32 addr) const
|
||||
{
|
||||
return *(T*)&VRAMFlat_Texture[addr & 0x7FFFF];
|
||||
}
|
||||
template <typename T>
|
||||
inline T ReadVRAMFlat_TexPal(u32 addr) const
|
||||
{
|
||||
return *(T*)&VRAMFlat_TexPal[addr & 0x1FFFF];
|
||||
}
|
||||
|
||||
void SetPowerCnt(u32 val) noexcept;
|
||||
|
||||
void StartFrame() noexcept;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
|||
#include <string.h>
|
||||
#include "NDS.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
@ -386,6 +387,14 @@ void Unit::Write16(u32 addr, u16 val)
|
|||
if (!Num) GPU.GPU3D.SetRenderXPos(val);
|
||||
break;
|
||||
|
||||
case 0x064:
|
||||
CaptureCnt = (CaptureCnt & 0xFFFF0000) | (val & 0xEF3F1F1F);
|
||||
return;
|
||||
|
||||
case 0x066:
|
||||
CaptureCnt = (CaptureCnt & 0xFFFF) | ((val << 16) & 0xEF3F1F1F);
|
||||
return;
|
||||
|
||||
case 0x068:
|
||||
DispFIFO[DispFIFOWritePtr] = val;
|
||||
return;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include "GPU2D_Soft.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D_OpenGL.h"
|
||||
#include "GPU3D.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
@ -254,7 +254,11 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit)
|
|||
|
||||
if (GPU.GPU3D.IsRendererAccelerated())
|
||||
{
|
||||
dst[256*3] = masterBrightness | (CurUnit->DispCnt & 0x30000);
|
||||
u32 xpos = GPU.GPU3D.GetRenderXPos();
|
||||
|
||||
dst[256*3] = masterBrightness |
|
||||
(CurUnit->DispCnt & 0x30000) |
|
||||
(xpos << 24) | ((xpos & 0x100) << 15);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1503,7 +1507,7 @@ void SoftRenderer::ApplySpriteMosaicX()
|
|||
|
||||
u32* objLine = OBJLine[CurUnit->Num];
|
||||
|
||||
u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[1]].data();
|
||||
u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[0]].data();
|
||||
|
||||
u32 lastcolor = objLine[0];
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
|
124
src/GPU3D.cpp
124
src/GPU3D.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
|||
#include "FIFO.h"
|
||||
#include "GPU3D_Soft.h"
|
||||
#include "Platform.h"
|
||||
#include "GPU3D.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
|
@ -191,7 +192,7 @@ void GPU3D::Reset() noexcept
|
|||
|
||||
CmdStallQueue.Clear();
|
||||
|
||||
ZeroDotWLimit = 0; // CHECKME
|
||||
ZeroDotWLimit = 0xFFFFFF;
|
||||
|
||||
GXStat = 0;
|
||||
|
||||
|
@ -273,6 +274,8 @@ void GPU3D::Reset() noexcept
|
|||
memset(MatEmission, 0, sizeof(MatSpecular));
|
||||
|
||||
UseShininessTable = false;
|
||||
// Shininess table seems to be uninitialized garbage, at least on n3dsxl hw?
|
||||
// Also doesn't seem to be cleared properly unless the system is fully powered off?
|
||||
memset(ShininessTable, 0, sizeof(ShininessTable));
|
||||
|
||||
PolygonAttr = 0;
|
||||
|
@ -1278,7 +1281,7 @@ void GPU3D::SubmitPolygon() noexcept
|
|||
{
|
||||
Vertex* vtx = poly->Vertices[i];
|
||||
|
||||
if (vtx->FinalPosition[1] < ytop || (vtx->FinalPosition[1] == ytop && vtx->FinalPosition[0] < xtop))
|
||||
if (vtx->FinalPosition[1] < ytop)
|
||||
{
|
||||
xtop = vtx->FinalPosition[0];
|
||||
ytop = vtx->FinalPosition[1];
|
||||
|
@ -1458,67 +1461,86 @@ void GPU3D::CalculateLighting() noexcept
|
|||
TexCoords[1] = RawTexCoords[1] + (((s64)Normal[0]*TexMatrix[1] + (s64)Normal[1]*TexMatrix[5] + (s64)Normal[2]*TexMatrix[9]) >> 21);
|
||||
}
|
||||
|
||||
s32 normaltrans[3];
|
||||
normaltrans[0] = (Normal[0]*VecMatrix[0] + Normal[1]*VecMatrix[4] + Normal[2]*VecMatrix[8]) >> 12;
|
||||
normaltrans[1] = (Normal[0]*VecMatrix[1] + Normal[1]*VecMatrix[5] + Normal[2]*VecMatrix[9]) >> 12;
|
||||
normaltrans[2] = (Normal[0]*VecMatrix[2] + Normal[1]*VecMatrix[6] + Normal[2]*VecMatrix[10]) >> 12;
|
||||
|
||||
VertexColor[0] = MatEmission[0];
|
||||
VertexColor[1] = MatEmission[1];
|
||||
VertexColor[2] = MatEmission[2];
|
||||
s32 normaltrans[3]; // should be 1 bit sign 10 bits frac
|
||||
normaltrans[0] = ((Normal[0]*VecMatrix[0] + Normal[1]*VecMatrix[4] + Normal[2]*VecMatrix[8]) << 9) >> 21;
|
||||
normaltrans[1] = ((Normal[0]*VecMatrix[1] + Normal[1]*VecMatrix[5] + Normal[2]*VecMatrix[9]) << 9) >> 21;
|
||||
normaltrans[2] = ((Normal[0]*VecMatrix[2] + Normal[1]*VecMatrix[6] + Normal[2]*VecMatrix[10]) << 9) >> 21;
|
||||
|
||||
s32 c = 0;
|
||||
u32 vtxbuff[3] =
|
||||
{
|
||||
(u32)MatEmission[0] << 14,
|
||||
(u32)MatEmission[1] << 14,
|
||||
(u32)MatEmission[2] << 14
|
||||
};
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!(CurPolygonAttr & (1<<i)))
|
||||
continue;
|
||||
|
||||
// overflow handling (for example, if the normal length is >1)
|
||||
// according to some hardware tests
|
||||
// * diffuse level is saturated to 255
|
||||
// * shininess level mirrors back to 0 and is ANDed with 0xFF, that before being squared
|
||||
// TODO: check how it behaves when the computed shininess is >=0x200
|
||||
// (credit to azusa for working out most of the details of the diff. algorithm, and essentially the entire spec. algorithm)
|
||||
|
||||
// calculate dot product
|
||||
// bottom 9 bits are discarded after multiplying and before adding
|
||||
s32 dot = ((LightDirection[i][0]*normaltrans[0]) >> 9) +
|
||||
((LightDirection[i][1]*normaltrans[1]) >> 9) +
|
||||
((LightDirection[i][2]*normaltrans[2]) >> 9);
|
||||
|
||||
s32 difflevel = (-(LightDirection[i][0]*normaltrans[0] +
|
||||
LightDirection[i][1]*normaltrans[1] +
|
||||
LightDirection[i][2]*normaltrans[2])) >> 10;
|
||||
if (difflevel < 0) difflevel = 0;
|
||||
else if (difflevel > 255) difflevel = 255;
|
||||
s32 shinelevel;
|
||||
if (dot > 0)
|
||||
{
|
||||
// -- diffuse lighting --
|
||||
|
||||
// convert dot to signed 11 bit int
|
||||
// then we truncate the result of the multiplications to an unsigned 20 bits before adding to the vtx color
|
||||
s32 diffdot = (dot << 21) >> 21;
|
||||
vtxbuff[0] += (MatDiffuse[0] * LightColor[i][0] * diffdot) & 0xFFFFF;
|
||||
vtxbuff[1] += (MatDiffuse[1] * LightColor[i][1] * diffdot) & 0xFFFFF;
|
||||
vtxbuff[2] += (MatDiffuse[2] * LightColor[i][2] * diffdot) & 0xFFFFF;
|
||||
|
||||
s32 shinelevel = -(((LightDirection[i][0]>>1)*normaltrans[0] +
|
||||
(LightDirection[i][1]>>1)*normaltrans[1] +
|
||||
((LightDirection[i][2]-0x200)>>1)*normaltrans[2]) >> 10);
|
||||
if (shinelevel < 0) shinelevel = 0;
|
||||
else if (shinelevel > 255) shinelevel = (0x100 - shinelevel) & 0xFF;
|
||||
shinelevel = ((shinelevel * shinelevel) >> 7) - 0x100; // really (2*shinelevel*shinelevel)-1
|
||||
if (shinelevel < 0) shinelevel = 0;
|
||||
// -- specular lighting --
|
||||
|
||||
// reuse the dot product from diffuse lighting
|
||||
dot += normaltrans[2];
|
||||
|
||||
// convert to s11, then square it, and truncate to 10 bits
|
||||
dot = (dot << 21) >> 21;
|
||||
dot = ((dot * dot) >> 10) & 0x3FF;
|
||||
|
||||
// multiply dot and reciprocal, the subtract '1'
|
||||
shinelevel = ((dot * SpecRecip[i]) >> 8) - (1<<9);
|
||||
|
||||
if (shinelevel < 0) shinelevel = 0;
|
||||
else
|
||||
{
|
||||
// sign extend to convert to signed 14 bit integer
|
||||
shinelevel = (shinelevel << 18) >> 18;
|
||||
if (shinelevel < 0) shinelevel = 0; // for some reason there seems to be a redundant check for <0?
|
||||
else if (shinelevel > 0x1FF) shinelevel = 0x1FF;
|
||||
}
|
||||
}
|
||||
else shinelevel = 0;
|
||||
|
||||
// convert shinelevel to use for lookup in the shininess table if enabled.
|
||||
if (UseShininessTable)
|
||||
{
|
||||
// checkme
|
||||
shinelevel >>= 1;
|
||||
shinelevel >>= 2;
|
||||
shinelevel = ShininessTable[shinelevel];
|
||||
shinelevel <<= 1;
|
||||
}
|
||||
|
||||
VertexColor[0] += ((MatSpecular[0] * LightColor[i][0] * shinelevel) >> 13);
|
||||
VertexColor[0] += ((MatDiffuse[0] * LightColor[i][0] * difflevel) >> 13);
|
||||
VertexColor[0] += ((MatAmbient[0] * LightColor[i][0]) >> 5);
|
||||
|
||||
VertexColor[1] += ((MatSpecular[1] * LightColor[i][1] * shinelevel) >> 13);
|
||||
VertexColor[1] += ((MatDiffuse[1] * LightColor[i][1] * difflevel) >> 13);
|
||||
VertexColor[1] += ((MatAmbient[1] * LightColor[i][1]) >> 5);
|
||||
|
||||
VertexColor[2] += ((MatSpecular[2] * LightColor[i][2] * shinelevel) >> 13);
|
||||
VertexColor[2] += ((MatDiffuse[2] * LightColor[i][2] * difflevel) >> 13);
|
||||
VertexColor[2] += ((MatAmbient[2] * LightColor[i][2]) >> 5);
|
||||
|
||||
if (VertexColor[0] > 31) VertexColor[0] = 31;
|
||||
if (VertexColor[1] > 31) VertexColor[1] = 31;
|
||||
if (VertexColor[2] > 31) VertexColor[2] = 31;
|
||||
// Note: ambient seems to be a plain bitshift
|
||||
vtxbuff[0] += ((MatSpecular[0] * shinelevel) + (MatAmbient[0] << 9)) * LightColor[i][0];
|
||||
vtxbuff[1] += ((MatSpecular[1] * shinelevel) + (MatAmbient[1] << 9)) * LightColor[i][1];
|
||||
vtxbuff[2] += ((MatSpecular[2] * shinelevel) + (MatAmbient[2] << 9)) * LightColor[i][2];
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
VertexColor[0] = (vtxbuff[0] >> 14 > 31) ? 31 : (vtxbuff[0] >> 14);
|
||||
VertexColor[1] = (vtxbuff[1] >> 14 > 31) ? 31 : (vtxbuff[1] >> 14);
|
||||
VertexColor[2] = (vtxbuff[2] >> 14 > 31) ? 31 : (vtxbuff[2] >> 14);
|
||||
|
||||
if (c < 1) c = 1;
|
||||
NormalPipeline = 7;
|
||||
AddCycles(c);
|
||||
|
@ -2011,9 +2033,15 @@ void GPU3D::ExecuteCommand() noexcept
|
|||
dir[0] = (s16)((entry.Param & 0x000003FF) << 6) >> 6;
|
||||
dir[1] = (s16)((entry.Param & 0x000FFC00) >> 4) >> 6;
|
||||
dir[2] = (s16)((entry.Param & 0x3FF00000) >> 14) >> 6;
|
||||
LightDirection[l][0] = (dir[0]*VecMatrix[0] + dir[1]*VecMatrix[4] + dir[2]*VecMatrix[8]) >> 12;
|
||||
LightDirection[l][1] = (dir[0]*VecMatrix[1] + dir[1]*VecMatrix[5] + dir[2]*VecMatrix[9]) >> 12;
|
||||
LightDirection[l][2] = (dir[0]*VecMatrix[2] + dir[1]*VecMatrix[6] + dir[2]*VecMatrix[10]) >> 12;
|
||||
// the order of operations here is very specific: discard bottom 12 bits -> negate -> then sign extend to convert to 11 bit signed int
|
||||
// except for when used to calculate the specular reciprocal; then it's: sign extend -> discard lsb -> negate.
|
||||
LightDirection[l][0] = (-((dir[0]*VecMatrix[0] + dir[1]*VecMatrix[4] + dir[2]*VecMatrix[8] ) >> 12) << 21) >> 21;
|
||||
LightDirection[l][1] = (-((dir[0]*VecMatrix[1] + dir[1]*VecMatrix[5] + dir[2]*VecMatrix[9] ) >> 12) << 21) >> 21;
|
||||
LightDirection[l][2] = (-((dir[0]*VecMatrix[2] + dir[1]*VecMatrix[6] + dir[2]*VecMatrix[10]) >> 12) << 21) >> 21;
|
||||
s32 den = -(((dir[0]*VecMatrix[2] + dir[1]*VecMatrix[6] + dir[2]*VecMatrix[10]) << 9) >> 21) + (1<<9);
|
||||
|
||||
if (den == 0) SpecRecip[l] = 0;
|
||||
else SpecRecip[l] = (1<<18) / den;
|
||||
}
|
||||
AddCycles(5);
|
||||
break;
|
||||
|
|
12
src/GPU3D.h
12
src/GPU3D.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016-2023 melonDS team
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
|
@ -197,7 +197,7 @@ public:
|
|||
|
||||
FIFO<CmdFIFOEntry, 64> CmdStallQueue {};
|
||||
|
||||
u32 ZeroDotWLimit = 0;
|
||||
u32 ZeroDotWLimit = 0xFFFFFF;
|
||||
|
||||
u32 GXStat = 0;
|
||||
|
||||
|
@ -286,6 +286,7 @@ public:
|
|||
s16 Normal[3] {};
|
||||
|
||||
s16 LightDirection[4][3] {};
|
||||
s32 SpecRecip[4] {};
|
||||
u8 LightColor[4][3] {};
|
||||
u8 MatDiffuse[3] {};
|
||||
u8 MatAmbient[3] {};
|
||||
|
@ -349,7 +350,14 @@ public:
|
|||
virtual void RestartFrame(GPU& gpu) {};
|
||||
virtual u32* GetLine(int line) = 0;
|
||||
virtual void Blit(const GPU& gpu) {};
|
||||
|
||||
virtual void SetupAccelFrame() {}
|
||||
virtual void PrepareCaptureFrame() {}
|
||||
virtual void BindOutputTexture(int buffer) {}
|
||||
|
||||
virtual bool NeedsShaderCompile() { return false; }
|
||||
virtual void ShaderCompileStep(int& current, int& count) {}
|
||||
|
||||
protected:
|
||||
Renderer3D(bool Accelerated);
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue