Compare commits

...

47 Commits

Author SHA1 Message Date
Arisotura f352cf612a call MakeCurrent() before deiniting GL stuff (to avoid deiniting on the wrong context) 2025-06-28 22:55:48 +02:00
Arisotura 4aaea218c1 add a way to tell windows apart 2025-06-28 13:06:53 +02:00
Arisotura 44b0704063 fix video settings update on second instance secondary windows 2025-06-28 12:48:22 +02:00
Arisotura 2499ec36c2 window: undo last commit (was a trainwreck). explicitly close child windows to avoid GL issues. fix bug with window parenting in second multiplayer instances. 2025-06-28 12:37:53 +02:00
Arisotura baad893bc0 window: move cleanup code to destructor (closeEvent() isn't called for children) 2025-06-28 03:48:42 +02:00
Arisotura ec2f7ee838 fix issues with multi-window and OpenGL on Windows 2025-06-28 03:02:00 +02:00
Arisotura 005ef9c9fc camera: fix resolution selection code (could accidentally select a resolution like 640x360) 2025-06-26 23:04:14 +02:00
Arisotura 7b562f71b3 NDMA: fix IRQ in infinite repeat mode 2025-06-25 21:52:23 +02:00
Arisotura fd279bedc5 huh 2025-06-24 16:51:33 +02:00
Arisotura b2af96474f Merge remote-tracking branch 'origin/master' 2025-06-24 01:03:25 +02:00
Arisotura 8cd2d972ab DSP: fix PDATA reads being one off 2025-06-24 01:03:14 +02:00
Edoardo Lolletti ab249fc913
Don't return 0 when attempting to read from the GPA GPIO addresses with GPIO disabled (#2266) 2025-06-23 08:32:17 +02:00
Arisotura 8e163296d3 camera: trigger DMA when reaching the end of a frame (fixes issues when the frame height isn't a multiple of the DMA interval) 2025-06-22 23:58:30 +02:00
Arisotura 83b8f1ae47 DSP: fix bug in PDATA read DMA (was reading wrong register) 2025-06-22 21:27:27 +02:00
Adrian "asie" Siekierka fd74181f7d
Slot-2 Motion Pak, Guitar Grip emulation (#2183)
* Add DS Motion Pak emulation

* Add retail Motion Pak emulation, Guitar Grip emulation

* Simplify Motion Pak acceleration conversion formula

* Fix Motion Pak emulation axes

* Motion Pak: Emulate console laying on a flat table when motion input is not detected

* Motion Pak: Add comment

* GBACartMotionPak: Update comment
2025-06-22 16:30:01 +02:00
Edoardo Lolletti 2d04222442
Load Tad key into DSi AES engine (#2252) 2025-06-22 16:29:20 +02:00
Arisotura 71edf793fc setupMicInputData() ought to be called at all times tho 2025-06-18 19:32:50 +02:00
Nadia Holmquist Pedersen d7a4b2e8fe Don't try to change the core's audio interp setting when the emu
instance has no core yet.

Fixes #2352
2025-06-18 00:51:47 +02:00
Jakly c65d490351
small fix to translucency flag assignment (#2301)
hardware does not care that the polygon's mode would prevent the texture from rendering translucent pixels
2025-06-15 19:24:42 +02:00
Arisotura 79f12de480 multi-instance: load firmware from correct instance-specific file (load from original file if not found) 2025-06-15 01:42:24 +02:00
Nadia Holmquist Pedersen 0b005abedf work around building with LTO causing an ICE in gcc 15.1.0 2025-06-15 01:15:31 +02:00
Arisotura 0d294e9373 fix mic settings not being changed when closing the audio settings dialog 2025-06-14 23:20:31 +02:00
Arisotura 7117178c2d melonDLDI: add support for unaligned I/O 2025-05-27 00:55:12 +02:00
Arisotura d1eff4acf5 update copyright headers (about time) 2025-05-27 00:31:37 +02:00
Arisotura 37ca75acb9 add source for DLDI driver 2025-05-27 00:27:38 +02:00
Jesse Talavera 528f2495fc
Fix a missing `#include` on Windows builds (#2333)
* Fix a GCC 15 build issue on Windows due to a missing `#include`

- `<vector>` was included implicitly by some other header
- The build broke in GCC 15 on MinGW, most likely due to some internal refactoring

* Indent these `#include`s the same as the others
2025-05-21 22:16:00 +02:00
Jesse Talavera 7baeb26e32
Fix undefined behavior when indexing into `ARCode::Code` (#2331)
- Indexing past the end of a `std::vector`'s length is undefined, even if there's extra capacity
- GCC 15 introduced an assert in `vector::operator[]`, so this line caused an abort if melonDS was built with GCC 15
- It was always undefined, but now the STL checks for it
2025-05-20 01:00:48 +02:00
Alex 0e64a06c84 Use standard sysconf
Fixes compilation of JIT builds on non-glibc OSes. After some testing in a Fedora 41 VM,
__sysconf and sysconf return the same value, and sysconf in glibc appears to just
be an alias to __sysconf to begin with
2025-05-15 14:08:43 +02:00
Alex d6d820c013
Set SDL_HINT_APP_NAME (#2319)
Fixes #2300
2025-05-11 13:10:48 +02:00
Nadia Holmquist Pedersen 9ed7e5803e ci: upgrade vcpkg to a commit that works for our deps with CMake 4.0
CMake 4.0 dropped support for projects with a minimum required version
below 3.5. libarchive, as well as possibly other dependencies, had older
versions set so they now fail to build.

GitHub Actions and MSYS2 were very quick to update their CMake version
and there isn't a tagged vcpkg release with a fix for libarchive yet, so
we will use a specific commit for now.
2025-04-09 17:40:12 +02:00
Jesse Talavera 0fcf1f6e3a
Add support for using the solar sensor without requiring a Boktai ROM (#2221)
* Add a `GBAHeader` struct

* Add extra `GBAAddon` entries for the Boktai carts

- Each game in the trilogy has a different effect on Lunar Knights (the only commercial DS game to support the solar sensor)

* Copy the logo data from the NDS ROM's header to the Boktai stub's header
2025-03-09 18:20:27 +01:00
Nadia Holmquist Pedersen 63b468927e ci: enable building of appimages on aarch64
Looks like whatever was causing linuxdeploy to crash got fixed, so we can build them now.
2025-02-21 08:58:48 +01:00
Nadia Holmquist Pedersen e8265df4bd vcpkg 2025.01.13, update nixpkgs 2025-02-10 22:53:51 +01:00
Nadia Holmquist Pedersen 15c3faa26e Use GitHub's new arm64 Linux runners for the Ubuntu CI builds 2025-01-17 04:15:13 +01:00
Jakly a9cce557d2
fix framelimiter bugs (#2256) 2025-01-14 18:21:03 +01:00
Nadia Holmquist Pedersen 0c5dd28b1c just case the string length to int to make std::min happy in all cases 2024-12-26 09:17:46 +01:00
Nadia Holmquist Pedersen c41951d49c
Fix almost every warning (#2195)
Fix almost every warning as of Clang 19

* <codecvt> is deprecated, we can use QString's UTF-16 conversion
  instead
* remove sem_timedwait implementation as we don't need it anymore
* remove a useless shift that has its result discarded
* change usages of deprecated sprintf to snprintf
2024-12-25 16:54:10 +01:00
izder456 be26878b4c FIX: this should be namespace std:: to preserve compatibilty with non-glibc when building without gdb stub 2024-12-25 16:48:46 +01:00
Jakly 66d1091330
improve audio handling at non-60 fps targets (#2246) 2024-12-25 16:34:30 +01:00
Campbell Suter 72c86ade31
Fix gdbstub not activating until the console is reset (#2245)
The check for initialising the gdbstub depending on whether the JIT was
enabled or not was the wrong way around: previously, it would only
enable the gdbstub if the JIT was enabled.

The stub started working again if you reset the console, as
NDS::SetGdbArgs didn't have any such check and it was called by
EmuInstance::updateConsole.
2024-12-24 00:29:21 +01:00
Nadia Holmquist Pedersen 7d718ada39 cmake: set default CMAKE_OSX_DEPLOYMENT_TARGET before project()
project() appears to set it to an empty string (the value of nonexistent
$ENV{MACOSX_DEPLOYMENT_TARGET}?), causing our attempt to set its default
to fail. CMake bug?
2024-12-05 15:40:29 +01:00
Jakly 817b409ec8
ah. (#2225) 2024-11-30 02:54:54 +01:00
Rayyan Ansari cba838dd52
TitleManager: fix handling of title string
Truncate the title at the first occurrence of \0, as title strings
should be null-terminated.

Fixes #2219 (Weird characters on DSi Title Manager on melonDS 1.0RC)
2024-11-27 13:15:18 +00:00
Nadia Holmquist Pedersen 730b488fe3 vcpkg 2024.11.16 & update nixpkgs 2024-11-23 14:41:25 +01:00
Nadia Holmquist Pedersen 1d6c9023ff get rid of the incorrect CLOCK_MONOTONIC redefinition 2024-11-23 12:43:06 +01:00
Nadia Holmquist Pedersen 0db536c063 Set _WIN32_WINNT to Windows 8 when JIT is enabled (fixes #2209) 2024-11-23 12:40:02 +01:00
RSDuck 6a15dbfa12 unmappinged everything 2024-11-22 03:34:18 +01:00
226 changed files with 1350 additions and 919 deletions

View File

@ -4,12 +4,13 @@ on:
push:
branches:
- master
- ci/vcpkg-update
- ci/*
pull_request:
branches:
- master
env:
VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions
@ -34,7 +35,7 @@ jobs:
- name: Set up vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
- name: Build
uses: lukka/run-cmake@v10
with:

View File

@ -4,6 +4,7 @@ on:
push:
branches:
- master
- ci/*
pull_request:
branches:
- master
@ -15,16 +16,24 @@ env:
MELONDS_VERSION_SUFFIX: " RC"
jobs:
build-x86_64:
name: x86_64
runs-on: ubuntu-22.04
build:
continue-on-error: true
strategy:
matrix:
arch:
- runner: ubuntu-22.04
name: x86_64
- runner: ubuntu-22.04-arm
name: aarch64
name: ${{ matrix.arch.name }}
runs-on: ${{ matrix.arch.runner }}
steps:
- 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 --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
@ -36,56 +45,19 @@ jobs:
DESTDIR=AppDir cmake --install build
- uses: actions/upload-artifact@v4
with:
name: melonDS-ubuntu-x86_64
name: melonDS-ubuntu-${{ matrix.arch.name }}
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
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.arch.name }}.AppImage
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-${{ matrix.arch.name }}.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
./linuxdeploy-${{ matrix.arch.name }}.AppImage --appdir AppDir --plugin qt --output appimage
- uses: actions/upload-artifact@v4
with:
name: melonDS-appimage-x86_64
name: melonDS-appimage-${{ matrix.arch.name }}
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 \
-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

View File

@ -10,6 +10,7 @@ on:
- master
env:
VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions
@ -33,7 +34,7 @@ jobs:
- name: Set up vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
- name: Configure
run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON
- name: Build

View File

@ -9,6 +9,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
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")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
option(USE_VCPKG "Use vcpkg for dependency packages" OFF)
if (USE_VCPKG)
@ -29,8 +30,6 @@ 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)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)

View File

@ -9,7 +9,8 @@ if (VCPKG_ROOT STREQUAL "${_DEFAULT_VCPKG_ROOT}")
endif()
FetchContent_Declare(vcpkg
GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git"
GIT_TAG 2024.10.21
GIT_TAG 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
EXCLUDE_FROM_ALL
SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg")
FetchContent_MakeAvailable(vcpkg)
endif()

View File

@ -7,3 +7,9 @@ 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}")
# Building with LTO causes an internal compiler error in GCC 15.1.0
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.1.1)
set(ENABLE_LTO_RELEASE OFF CACHE BOOL "Enable LTO for release builds" FORCE)
set(ENABLE_LTO OFF CACHE BOOL "Enable LTO" FORCE)
endif()

View File

@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1730531603,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
"lastModified": 1739020877,
"narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
"rev": "a79cfe0ebd24952b580b1cf08cd906354996d547",
"type": "github"
},
"original": {

View File

@ -95,7 +95,13 @@
libtool
ninja
pkg-config
python3
];
# Undo the SDK setup done by nixpkgs so we can use AppleClang
shellHook = ''
unset DEVELOPER_DIR SDKROOT MACOSX_DEPLOYMENT_TARGET
'';
};
};
}

15
melonDLDI/Makefile Normal file
View File

@ -0,0 +1,15 @@
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
BIN = melonDLDI
all:
$(AS) $(BIN).s -o $(BIN).o
$(LD) $(BIN).o -Ttext 0xBF800000 -e 0xBF800000 -o $(BIN).elf
$(OBJCOPY) -O binary $(BIN).elf $(BIN).bin
xxd -i -n $(BIN) -c 16 $(BIN).bin $(BIN).h
clean:
rm -f $(BIN).h $(BIN).bin $(BIN).elf $(BIN).o

172
melonDLDI/melonDLDI.s Executable file
View File

@ -0,0 +1,172 @@
.arm
.text
.align 2
_start:
.word 0xBF8DA5ED
.string " Chishm"
.byte 1
.byte 9 @ size
.byte 0
.byte 0
.string "melonDS DLDI driver"
.align 6, 0
.word _start, melon_end
.word 0, 0
.word 0, 0
.word 0, 0
.ascii "MELN"
.word 0x23
.word melon_startup
.word melon_isInserted
.word melon_readSectors
.word melon_writeSectors
.word melon_clearStatus
.word melon_shutdown
.align 2
melon_startup:
mov r0, #1
bx lr
melon_isInserted:
mov r0, #1
bx lr
@ r0=cmd r1=sector r2=out (0=none)
_sendcmd:
mov r12, #0x04000000
add r12, r12, #0x1A0
@ init
mov r3, #0x8000
strh r3, [r12]
@ set cmd
strb r0, [r12, #0x8]
strb r1, [r12, #0xC]
mov r1, r1, lsr #8
strb r1, [r12, #0xB]
mov r1, r1, lsr #8
strb r1, [r12, #0xA]
mov r1, r1, lsr #8
strb r1, [r12, #0x9]
mov r1, r1, lsr #8
strb r1, [r12, #0xD]
strh r1, [r12, #0xE]
@ send
mov r3, #0xA0000000
orr r3, r3, r0, lsl #30
cmp r2, #0
orrne r3, r3, #0x01000000 @ block size
orr r3, r3, #0x00400000 @ KEY2
str r3, [r12, #0x4]
mov r3, #0x04100000
tst r0, #0x01
bne __send_write
@ receive data
tst r2, #0x3
bne __read_unal_loop
__read_busyloop:
ldr r0, [r12, #0x4]
tst r0, #0x80000000
bxeq lr
tst r0, #0x00800000
ldrne r1, [r3, #0x10] @ load data
strne r1, [r2], #4
b __read_busyloop
__read_unal_loop:
ldr r0, [r12, #0x4]
tst r0, #0x80000000
bxeq lr
tst r0, #0x00800000
beq __read_unal_loop
ldr r1, [r3, #0x10] @ load data
strb r1, [r2], #1
mov r1, r1, lsr #8
strb r1, [r2], #1
mov r1, r1, lsr #8
strb r1, [r2], #1
mov r1, r1, lsr #8
strb r1, [r2], #1
b __read_unal_loop
@ send data
__send_write:
mov r1, #0
tst r2, #0x3
bne __write_unal_loop
__write_busyloop:
ldr r0, [r12, #0x4]
tst r0, #0x80000000
bxeq lr
tst r0, #0x00800000
ldrne r1, [r2], #4
strne r1, [r3, #0x10] @ store data
b __write_busyloop
__write_unal_loop:
ldr r0, [r12, #0x4]
tst r0, #0x80000000
bxeq lr
tst r0, #0x00800000
beq __write_unal_loop
ldrb r1, [r2], #1
ldrb r0, [r2], #1
orr r1, r1, r0, lsl #8
ldrb r0, [r2], #1
orr r1, r1, r0, lsl #16
ldrb r0, [r2], #1
orr r1, r1, r0, lsl #24
str r1, [r3, #0x10] @ store data
b __write_unal_loop
@ r0=sector r1=numsectors r2=out
melon_readSectors:
stmdb sp!, {r3-r6, lr}
mov r4, r0
mov r5, r1
mov r6, #0
_readloop:
mov r0, #0xC0
add r1, r4, r6
bl _sendcmd
add r6, r6, #1
cmp r6, r5
bcc _readloop
ldmia sp!, {r3-r6, lr}
mov r0, #1
bx lr
@ r0=sector r1=numsectors r2=out
melon_writeSectors:
stmdb sp!, {r3-r6, lr}
mov r4, r0
mov r5, r1
mov r6, #0
_writeloop:
mov r0, #0xC1
add r1, r4, r6
bl _sendcmd
add r6, r6, #1
cmp r6, r5
bcc _writeloop
ldmia sp!, {r3-r6, lr}
mov r0, #1
bx lr
melon_clearStatus:
mov r0, #1
bx lr
melon_shutdown:
mov r0, #1
bx lr
melon_end:

View File

@ -18,7 +18,7 @@ FILETYPE VFT_APP
VALUE "FileVersion", "${melonDS_VERSION}"
VALUE "FileDescription", "melonDS emulator"
VALUE "InternalName", "SDnolem"
VALUE "LegalCopyright", "2016-2023 melonDS team"
VALUE "LegalCopyright", "2016-2025 melonDS team"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "melonDS.exe"
VALUE "ProductName", "melonDS"

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -58,7 +58,8 @@ void AREngine::RunCheat(const ARCode& arcode)
for (;;)
{
if (code >= &arcode.Code[arcode.Code.size()])
if (code > &arcode.Code[arcode.Code.size() - 1])
// If the instruction pointer is past the end of the cheat code...
break;
u32 a = *code++;

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -115,7 +115,7 @@ ARM::ARM(u32 num, bool jit, std::optional<GDBArgs> gdb, melonDS::NDS& nds) :
Num(num), // well uh
NDS(nds)
{
SetGdbArgs(jit ? gdb : std::nullopt);
SetGdbArgs(jit ? std::nullopt : gdb);
}
ARM::~ARM()

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.
@ -83,7 +83,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
// doesn't matter if we put garbage in the MSbs there
if (addr & 0x2)
{
cpu9->CodeRead32(addr-2, true) >> 16;
cpu9->CodeRead32(addr-2, true);
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+2, false);
cycles += CurCPU->CodeCycles;
@ -437,4 +437,4 @@ void Compiler::T_Comp_BL_Merged()
Comp_JumpTo(target);
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -753,7 +753,7 @@ bool ARMJIT_Memory::IsFastMemSupported()
PageSize = RegularPageSize;
#else
PageSize = __sysconf(_SC_PAGESIZE);
PageSize = sysconf(_SC_PAGESIZE);
isSupported = PageSize == RegularPageSize || PageSize == LargePageSize;
#endif
PageShift = __builtin_ctz(PageSize);
@ -900,7 +900,7 @@ ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
}
#else
char fastmemPidName[snprintf(NULL, 0, "/melondsfastmem%d", getpid()) + 1];
sprintf(fastmemPidName, "/melondsfastmem%d", getpid());
snprintf(fastmemPidName, sizeof(fastmemPidName), "/melondsfastmem%d", getpid());
MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600);
if (MemoryFile == -1)
{
@ -951,7 +951,6 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
MemoryBase = nullptr;
FastMem9Start = nullptr;
FastMem7Start = nullptr;
printf("unmappinged everything\n");
}
if (MemoryFile)
@ -979,6 +978,8 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
MemoryFile = -1;
}
Log(LogLevel::Info, "unmappinged everything\n");
#if defined(__ANDROID__)
if (Libandroid)
{
@ -1599,4 +1600,4 @@ void* ARMJIT_Memory::GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) co
}
return NULL;
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -29,7 +29,8 @@
# if defined(__SWITCH__)
# include <switch.h>
# elif defined(_WIN32)
#include <windows.h>
# include <vector>
# include <windows.h>
# else
# include <sys/mman.h>
# include <sys/stat.h>

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team, RSDuck
Copyright 2016-2025 melonDS team, RSDuck
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -30,6 +30,7 @@ add_library(core STATIC
FATStorage.cpp
FIFO.h
GBACart.cpp
GBACartMotionPak.cpp
GPU.cpp
GPU2D.cpp
GPU2D_Soft.cpp
@ -102,6 +103,8 @@ if (ENABLE_JIT)
dolphin/CommonFuncs.cpp)
if (WIN32)
# Required for memory mapping-related functions introduced in Windows 8
target_compile_definitions(core PRIVATE -D_WIN32_WINNT=_WIN32_WINNT_WIN8)
target_link_libraries(core PRIVATE onecore)
endif()

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -90,6 +90,9 @@ void DSi_AES::Reset()
*(u32*)&KeyX[1][8] = (u32)(consoleid >> 32) ^ 0xC80C4B72;
*(u32*)&KeyX[1][12] = (u32)consoleid;
// slot 2: For 'Tad'
std::memcpy(KeyX[2], &DSi.ARM9iBIOS[0x8B8C], 0x10);
// slot 3: console-unique eMMC crypto
*(u32*)&KeyX[3][0] = (u32)consoleid;
*(u32*)&KeyX[3][4] = (u32)consoleid ^ 0x24EE6906;
@ -575,4 +578,4 @@ void DSi_AES::WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask)
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -128,6 +128,7 @@ void DSi_CamModule::TransferScanline(u32 line)
u32 tmpbuf[512];
int datalen = CurCamera->TransferScanline(tmpbuf, 512);
u32 numscan;
// TODO: must be tweaked such that each block has enough time to transfer
u32 delay = datalen*4 + 16;
@ -142,12 +143,7 @@ void DSi_CamModule::TransferScanline(u32 line)
int ystart = (CropStart >> 16) & 0x1FF;
int yend = (CropEnd >> 16) & 0x1FF;
if (line < ystart || line > yend)
{
if (!CurCamera->TransferDone())
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1);
return;
}
goto skip_line;
int xstart = (CropStart >> 1) & 0x1FF;
int xend = (CropEnd >> 1) & 0x1FF;
@ -206,7 +202,7 @@ void DSi_CamModule::TransferScanline(u32 line)
memcpy(dstbuf, &tmpbuf[copystart], copylen*sizeof(u32));
}
u32 numscan = Cnt & 0x000F;
numscan = Cnt & 0x000F;
if (BufferNumLines >= numscan)
{
BufferReadPos = 0; // checkme
@ -221,8 +217,21 @@ void DSi_CamModule::TransferScanline(u32 line)
BufferNumLines++;
}
skip_line:
if (CurCamera->TransferDone())
{
// when the frame is finished, transfer any remaining data if needed
// (if the frame height isn't a multiple of the DMA interval)
if (BufferNumLines > 0)
{
BufferReadPos = 0;
BufferWritePos = 0;
BufferNumLines = 0;
DSi.CheckNDMAs(0, 0x0B);
}
return;
}
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1);
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -323,7 +323,7 @@ void DSi_DSP::PDataDMAFetch()
}
void DSi_DSP::PDataDMAStart()
{
switch ((DSP_PSTS & (3<<2)) >> 2)
switch ((DSP_PCFG & (3<<2)) >> 2)
{
case 0: PDataDMALen = 1; break;
case 1: PDataDMALen = 8; break;
@ -348,7 +348,7 @@ void DSi_DSP::PDataDMACancel()
}
u16 DSi_DSP::PDataDMAReadMMIO()
{
u16 ret;
u16 ret = 0; // TODO: is this actually 0, or just open bus?
if (!PDATAReadFifo.IsEmpty())
ret = PDATAReadFifo.Read();
@ -362,15 +362,9 @@ u16 DSi_DSP::PDataDMAReadMMIO()
for (int i = 0; i < left; ++i)
PDataDMAFetch();
ret = PDATAReadFifo.Read();
}
else
{
// ah, crap
ret = 0; // TODO: is this actually 0, or just open bus?
}
// TODO only trigger IRQ if enabled!!
if (!PDATAReadFifo.IsEmpty() || PDATAReadFifo.IsFull())
DSi.SetIRQ(0, IRQ_DSi_DSP);

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -132,7 +132,6 @@ void DSi_NDMA::WriteCnt(u32 val)
// TODO: unsupported start modes:
// * timers (00-03)
// * camera (ARM9 0B)
// * microphone (ARM7 0C)
// * NDS-wifi?? (ARM7 07, likely not working)
@ -270,11 +269,18 @@ void DSi_NDMA::Run9()
if ((StartMode & 0x1F) == 0x10) // CHECKME
{
// no repeat
Cnt &= ~(1<<31);
if (Cnt & (1<<30)) DSi.SetIRQ(0, IRQ_DSi_NDMA0 + Num);
}
else if (!(Cnt & (1<<29)))
else if (Cnt & (1<<29))
{
// repeat infinitely
if (Cnt & (1<<30)) DSi.SetIRQ(0, IRQ_DSi_NDMA0 + Num);
}
else
{
// repeat until total count is reached
if (TotalRemCount == 0)
{
Cnt &= ~(1<<31);
@ -359,11 +365,18 @@ void DSi_NDMA::Run7()
if ((StartMode & 0x1F) == 0x10) // CHECKME
{
// no repeat
Cnt &= ~(1<<31);
if (Cnt & (1<<30)) DSi.SetIRQ(1, IRQ_DSi_NDMA0 + Num);
}
else if (!(Cnt & (1<<29)))
else if (Cnt & (1<<29))
{
// repeat infinitely
if (Cnt & (1<<30)) DSi.SetIRQ(1, IRQ_DSi_NDMA0 + Num);
}
else
{
// repeat until total count is reached
if (TotalRemCount == 0)
{
Cnt &= ~(1<<31);

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -242,8 +242,6 @@ u16 CartGame::ROMRead(u32 addr) const
case 0xC8: return GPIO.control;
}
}
else
return 0;
}
// CHECKME: does ROM mirror?
@ -539,6 +537,57 @@ CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, s
{
}
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const NDSCart::CartCommon& cart, void* userdata) noexcept
{
return CreateFakeSolarSensorROM(gamecode, cart.GetHeader().NintendoLogo, userdata);
}
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const GBACart::CartGame& cart, void* userdata) noexcept
{
return CreateFakeSolarSensorROM(gamecode, cart.GetHeader().NintendoLogo, userdata);
}
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const u8* logo, void* userdata) noexcept
{
if (!gamecode)
return nullptr;
if (strnlen(gamecode, sizeof(GBAHeader::GameCode)) > sizeof(GBAHeader::GameCode))
return nullptr;
bool solarsensor = false;
for (const char* i : SOLAR_SENSOR_GAMECODES)
{
if (strcmp(gamecode, i) == 0) {
solarsensor = true;
break;
}
}
if (!solarsensor)
return nullptr;
// just 256 bytes; we don't need a whole ROM!
constexpr size_t FAKE_BOKTAI_ROM_LENGTH = 0x100;
std::unique_ptr<u8[]> rom = std::make_unique<u8[]>(FAKE_BOKTAI_ROM_LENGTH);
// create a fake ROM
GBAHeader& header = *reinterpret_cast<GBAHeader*>(rom.get());
memcpy(header.Title, BOKTAI_STUB_TITLE, strnlen(BOKTAI_STUB_TITLE, sizeof(header.Title)));
memcpy(header.GameCode, gamecode, strnlen(gamecode, sizeof(header.GameCode)));
header.FixedValue = 0x96;
if (logo)
{
memcpy(header.NintendoLogo, logo, sizeof(header.NintendoLogo));
}
else
{
memset(header.NintendoLogo, 0xFF, sizeof(header.NintendoLogo));
}
return std::make_unique<CartGameSolarSensor>(std::move(rom), FAKE_BOKTAI_ROM_LENGTH, nullptr, 0, userdata);
}
const int CartGameSolarSensor::kLuxLevels[11] = {0, 5, 11, 18, 27, 42, 62, 84, 109, 139, 183};
void CartGameSolarSensor::Reset()
@ -724,6 +773,27 @@ void CartRumblePak::ROMWrite(u32 addr, u16 val)
}
}
CartGuitarGrip::CartGuitarGrip(void* userdata) :
CartCommon(GuitarGrip),
UserData(userdata)
{
}
CartGuitarGrip::~CartGuitarGrip() = default;
u16 CartGuitarGrip::ROMRead(u32 addr) const
{
return 0xF9FF;
}
u8 CartGuitarGrip::SRAMRead(u32 addr)
{
return ~((Platform::Addon_KeyDown(Platform::KeyGuitarGripGreen, UserData) ? 0x40 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripRed, UserData) ? 0x20 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripYellow, UserData) ? 0x10 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripBlue, UserData) ? 0x08 : 0));
}
GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
{
}
@ -843,7 +913,27 @@ std::unique_ptr<CartCommon> LoadAddon(int type, void* userdata)
case GBAAddon_RumblePak:
cart = std::make_unique<CartRumblePak>(userdata);
break;
case GBAAddon_SolarSensorBoktai1:
// US Boktai 1
cart = CreateFakeSolarSensorROM("U3IE", nullptr, userdata);
break;
case GBAAddon_SolarSensorBoktai2:
// US Boktai 2
cart = CreateFakeSolarSensorROM("U32E", nullptr, userdata);
break;
case GBAAddon_SolarSensorBoktai3:
// JP Boktai 3
cart = CreateFakeSolarSensorROM("U33J", nullptr, userdata);
break;
case GBAAddon_MotionPakHomebrew:
cart = std::make_unique<CartMotionPakHomebrew>(userdata);
break;
case GBAAddon_MotionPakRetail:
cart = std::make_unique<CartMotionPakRetail>(userdata);
break;
case GBAAddon_GuitarGrip:
cart = std::make_unique<CartGuitarGrip>(userdata);
break;
default:
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
return nullptr;

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -33,8 +33,30 @@ enum CartType
GameSolarSensor = 0x102,
RAMExpansion = 0x201,
RumblePak = 0x202,
MotionPakHomebrew = 0x203,
MotionPakRetail = 0x204,
GuitarGrip = 0x205,
};
// See https://problemkaputt.de/gbatek.htm#gbacartridgeheader for details
struct GBAHeader
{
u32 EntryPoint;
u8 NintendoLogo[156]; // must be valid
char Title[12];
char GameCode[4];
char MakerCode[2];
u8 FixedValue; // must be 0x96
u8 MainUnitCode;
u8 DeviceType;
u8 Reserved0[7];
u8 SoftwareVersion;
u8 ComplementCheck;
u8 Reserved1[2];
};
static_assert(sizeof(GBAHeader) == 192, "GBAHeader should be 192 bytes");
// CartCommon -- base code shared by all cart types
class CartCommon
{
@ -91,6 +113,8 @@ public:
[[nodiscard]] const u8* GetROM() const override { return ROM.get(); }
[[nodiscard]] u32 GetROMLength() const override { return ROMLength; }
[[nodiscard]] const GBAHeader& GetHeader() const noexcept { return *reinterpret_cast<const GBAHeader*>(ROM.get()); }
[[nodiscard]] GBAHeader& GetHeader() noexcept { return *reinterpret_cast<GBAHeader*>(ROM.get()); }
u8* GetSaveMemory() const override;
u32 GetSaveMemoryLength() const override;
@ -211,11 +235,68 @@ private:
u16 RumbleState = 0;
};
// CartGuitarGrip -- DS Guitar Grip (used in various NDS games)
class CartGuitarGrip : public CartCommon
{
public:
CartGuitarGrip(void* userdata);
~CartGuitarGrip() override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
};
// CartMotionPakHomebrew -- DS Motion Pak (Homebrew)
class CartMotionPakHomebrew : public CartCommon
{
public:
CartMotionPakHomebrew(void* userdata);
~CartMotionPakHomebrew() override;
void Reset() override;
void DoSavestate(Savestate* file) override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
u16 ShiftVal = 0;
};
// CartMotionPakRetail -- DS Motion Pack (Retail)
class CartMotionPakRetail : public CartCommon
{
public:
CartMotionPakRetail(void* userdata);
~CartMotionPakRetail() override;
void Reset() override;
void DoSavestate(Savestate* file) override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
u8 Value;
u8 Step = 16;
};
// possible inputs for GBA carts that might accept user input
enum
{
Input_SolarSensorDown = 0,
Input_SolarSensorUp,
Input_GuitarGripGreen,
Input_GuitarGripRed,
Input_GuitarGripYellow,
Input_GuitarGripBlue,
};
class GBACartSlot
@ -309,6 +390,23 @@ std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
std::unique_ptr<CartCommon> LoadAddon(int type, void* userdata);
/// Creates a solar sensor-enabled GBA cart without needing a real Boktai ROM.
/// This enables the solar sensor to be used in supported games.
/// Will not contain any SRAM.
/// @param gamecode
/// @param logo The Nintendo logo data embedded in the headers for GBA ROMs and NDS ROMs.
/// Required for the cart to be recognized as a valid GBA cart.
/// Overloads that accept cart objects directly exist as well.
/// If not provided, then it will have to be patched with equivalent data
/// from a real ROM (NDS or GBA) before booting the emulator.
/// @param userdata Optional user data to associate with the cart.
/// @return A CartGameSolarSensor if the ROM was created successfully,
/// or nullptr if any argument is wrong (e.g. an incorrect game code).
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const u8* logo, void* userdata = nullptr) noexcept;
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const NDSCart::CartCommon& cart, void* userdata = nullptr) noexcept;
std::unique_ptr<CartGameSolarSensor> CreateFakeSolarSensorROM(const char* gamecode, const GBACart::CartGame& cart, void* userdata = nullptr) noexcept;
constexpr const char* BOKTAI_STUB_TITLE = "BOKTAI STUB";
}
#endif // GBACART_H

196
src/GBACartMotionPak.cpp Normal file
View File

@ -0,0 +1,196 @@
/*
Copyright 2016-2024 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <assert.h>
#include "NDS.h"
#include "GBACart.h"
#include "Platform.h"
#include <algorithm>
#include "math.h"
namespace melonDS
{
using Platform::Log;
using Platform::LogLevel;
namespace GBACart
{
CartMotionPakHomebrew::CartMotionPakHomebrew(void* userdata) :
CartCommon(MotionPakHomebrew),
UserData(userdata)
{
}
CartMotionPakHomebrew::~CartMotionPakHomebrew() = default;
void CartMotionPakHomebrew::Reset()
{
ShiftVal = 0;
}
void CartMotionPakHomebrew::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
file->Var16(&ShiftVal);
}
u16 CartMotionPakHomebrew::ROMRead(u32 addr) const
{
// CHECKME: Does this apply to the homebrew cart as well?
return 0xFCFF;
}
static int AccelerationToMotionPak(float accel)
{
const float GRAVITY_M_S2 = 9.80665f;
return std::clamp(
(int) ((accel / (5 * GRAVITY_M_S2) + 0.5) * 4096),
0, 4095
);
}
static int AccelerationToMotionPakRetail(float accel)
{
const float GRAVITY_M_S2 = 9.80665f;
return std::clamp(
(int) ((accel / (5 * GRAVITY_M_S2) + 0.5) * 256),
0, 254
);
}
static int RotationToMotionPak(float rot)
{
const float DEGREES_PER_RAD = 180 / M_PI;
const float COUNTS_PER_DEG_PER_SEC = 0.825;
const int CENTER = 1680;
return std::clamp(
(int) ((rot * DEGREES_PER_RAD * COUNTS_PER_DEG_PER_SEC) + CENTER + 0.5),
0, 4095
);
}
u8 CartMotionPakHomebrew::SRAMRead(u32 addr)
{
// CHECKME: SRAM address mask
addr &= 0xFFFF;
switch (addr)
{
case 0:
// Read next byte
break;
case 2:
// Read X acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationX, UserData)) << 4;
// CHECKME: First byte returned when reading acceleration/rotation
return 0;
case 4:
// Read Y acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationY, UserData)) << 4;
return 0;
case 6:
// Read Z acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationZ, UserData)) << 4;
return 0;
case 8:
// Read Z rotation
// CHECKME: This is a guess, compare with real hardware
ShiftVal = RotationToMotionPak(-Platform::Addon_MotionQuery(Platform::MotionRotationZ, UserData)) << 4;
return 0;
case 10:
// Identify cart
ShiftVal = 0xF00F;
return 0;
case 12:
case 14:
case 16:
case 18:
// Read/enable analog inputs
//
// These are not connected by defualt and require do-it-yourself cart
// modification, so there is no reason to emulate them.
ShiftVal = 0;
break;
}
// Read high byte from the emulated shift register
u8 val = ShiftVal >> 8;
ShiftVal <<= 8;
return val;
}
CartMotionPakRetail::CartMotionPakRetail(void* userdata) :
CartCommon(MotionPakRetail),
UserData(userdata)
{
}
CartMotionPakRetail::~CartMotionPakRetail() = default;
void CartMotionPakRetail::Reset()
{
Value = 0;
Step = 16;
}
void CartMotionPakRetail::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
file->Var8(&Value);
file->Var8(&Step);
}
u16 CartMotionPakRetail::ROMRead(u32 addr) const
{
// A9-A8 is pulled low on a real Motion Pack.
return 0xFCFF;
}
u8 CartMotionPakRetail::SRAMRead(u32 addr)
{
switch (Step)
{
case 0: // Synchronization - read 0xFF
Value = 0xFF;
break;
case 4: // X acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationX, UserData));
break;
case 8: // Y acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationY, UserData));
break;
case 12: // Z acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationZ, UserData));
break;
case 16: // Synchronization - read 0b00
Step = 0;
return 0;
}
int shift = 6 - ((Step & 3) * 2);
Step++;
return (Value >> shift) & 0x03;
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.
@ -1219,7 +1219,7 @@ void GPU3D::SubmitPolygon() noexcept
u32 texfmt = (TexParam >> 26) & 0x7;
u32 polyalpha = (CurPolygonAttr >> 16) & 0x1F;
poly->Translucent = ((texfmt == 1 || texfmt == 6) && !(CurPolygonAttr & 0x10)) || (polyalpha > 0 && polyalpha < 31);
poly->Translucent = (texfmt == 1 || texfmt == 6) || (polyalpha > 0 && polyalpha < 31);
poly->IsShadowMask = ((CurPolygonAttr & 0x3F000030) == 0x00000030);
poly->IsShadow = ((CurPolygonAttr & 0x30) == 0x30) && !poly->IsShadowMask;

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2024 melonDS team
Copyright 2016-2025 melonDS team
This file is part of melonDS.

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