Compare commits

..

No commits in common. "master" and "1.0rc" have entirely different histories.

227 changed files with 1062 additions and 1585 deletions

View File

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

View File

@ -4,7 +4,6 @@ on:
push: push:
branches: branches:
- master - master
- ci/*
pull_request: pull_request:
branches: branches:
- master - master
@ -13,27 +12,19 @@ env:
MELONDS_GIT_BRANCH: ${{ github.ref }} MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }} MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions MELONDS_BUILD_PROVIDER: GitHub Actions
# MELONDS_VERSION_SUFFIX: " RC" MELONDS_VERSION_SUFFIX: " RC"
jobs: jobs:
build: build-x86_64:
continue-on-error: true name: x86_64
strategy: runs-on: ubuntu-22.04
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: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
name: Check out sources name: Check out sources
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
sudo apt update sudo apt update
sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev libenet-dev \ 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 qt6-{base,base-private,multimedia}-dev libqt6svg6-dev libarchive-dev libzstd-dev libfuse2
@ -45,19 +36,56 @@ jobs:
DESTDIR=AppDir cmake --install build DESTDIR=AppDir cmake --install build
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: melonDS-ubuntu-${{ matrix.arch.name }} name: melonDS-ubuntu-x86_64
path: AppDir/usr/bin/melonDS path: AppDir/usr/bin/melonDS
- name: Fetch AppImage tools - name: Fetch AppImage tools
run: | run: |
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.arch.name }}.AppImage 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-${{ matrix.arch.name }}.AppImage wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
chmod a+x linuxdeploy-*.AppImage chmod a+x linuxdeploy-*.AppImage
- name: Build the AppImage - name: Build the AppImage
env: env:
QMAKE: /usr/lib/qt6/bin/qmake QMAKE: /usr/lib/qt6/bin/qmake
run: | run: |
./linuxdeploy-${{ matrix.arch.name }}.AppImage --appdir AppDir --plugin qt --output appimage ./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: melonDS-appimage-${{ matrix.arch.name }} name: melonDS-appimage-x86_64
path: melonDS*.AppImage 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,11 +10,10 @@ on:
- master - master
env: env:
VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
MELONDS_GIT_BRANCH: ${{ github.ref }} MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }} MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions MELONDS_BUILD_PROVIDER: GitHub Actions
# MELONDS_VERSION_SUFFIX: " RC" MELONDS_VERSION_SUFFIX: " RC"
jobs: jobs:
build: build:
@ -34,7 +33,7 @@ jobs:
- name: Set up vcpkg - name: Set up vcpkg
uses: lukka/run-vcpkg@v11 uses: lukka/run-vcpkg@v11
with: with:
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }} vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
- name: Configure - name: Configure
run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON
- name: Build - name: Build

View File

@ -9,7 +9,6 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_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") 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) option(USE_VCPKG "Use vcpkg for dependency packages" OFF)
if (USE_VCPKG) if (USE_VCPKG)
@ -30,6 +29,8 @@ include(CheckIPOSupported)
include(SetupCCache) include(SetupCCache)
include(Sanitizers) 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 11)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)

View File

@ -2,7 +2,7 @@
<h2 align="center"><b>melonDS</b></h2> <h2 align="center"><b>melonDS</b></h2>
<p align="center"> <p align="center">
<a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a> <a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a>
<a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 1.0"><img src="https://img.shields.io/badge/release-1.0-%235c913b.svg"></a> <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://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://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> <a href="https://discord.gg/pAMAtExcqV" alt="Discord"><img src="https://img.shields.io/badge/Discord-Kuribo64-7289da?logo=discord&logoColor=white"></a>

View File

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

View File

@ -7,9 +7,3 @@ endif()
string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}") 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}") 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" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1726560853,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1739020877, "lastModified": 1730531603,
"narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

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

View File

@ -1,15 +0,0 @@
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

View File

@ -1,172 +0,0 @@
.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 "FileVersion", "${melonDS_VERSION}"
VALUE "FileDescription", "melonDS emulator" VALUE "FileDescription", "melonDS emulator"
VALUE "InternalName", "SDnolem" VALUE "InternalName", "SDnolem"
VALUE "LegalCopyright", "2016-2025 melonDS team" VALUE "LegalCopyright", "2016-2023 melonDS team"
VALUE "LegalTrademarks", "" VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "melonDS.exe" VALUE "OriginalFilename", "melonDS.exe"
VALUE "ProductName", "melonDS" VALUE "ProductName", "melonDS"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team, RSDuck Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS. 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 // doesn't matter if we put garbage in the MSbs there
if (addr & 0x2) if (addr & 0x2)
{ {
cpu9->CodeRead32(addr-2, true); cpu9->CodeRead32(addr-2, true) >> 16;
cycles += cpu9->CodeCycles; cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+2, false); cpu9->CodeRead32(addr+2, false);
cycles += CurCPU->CodeCycles; cycles += CurCPU->CodeCycles;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,6 @@ add_library(core STATIC
FATStorage.cpp FATStorage.cpp
FIFO.h FIFO.h
GBACart.cpp GBACart.cpp
GBACartMotionPak.cpp
GPU.cpp GPU.cpp
GPU2D.cpp GPU2D.cpp
GPU2D_Soft.cpp GPU2D_Soft.cpp
@ -103,8 +102,6 @@ if (ENABLE_JIT)
dolphin/CommonFuncs.cpp) dolphin/CommonFuncs.cpp)
if (WIN32) 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) target_link_libraries(core PRIVATE onecore)
endif() endif()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -113,8 +113,6 @@ DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
NWRAM_A = JIT.Memory.GetNWRAM_A(); NWRAM_A = JIT.Memory.GetNWRAM_A();
NWRAM_B = JIT.Memory.GetNWRAM_B(); NWRAM_B = JIT.Memory.GetNWRAM_B();
NWRAM_C = JIT.Memory.GetNWRAM_C(); NWRAM_C = JIT.Memory.GetNWRAM_C();
SetFullBIOSBoot(args.FullBIOSBoot);
} }
DSi::~DSi() noexcept DSi::~DSi() noexcept
@ -177,8 +175,6 @@ void DSi::Reset()
// LCD init flag // LCD init flag
GPU.DispStat[0] |= (1<<6); GPU.DispStat[0] |= (1<<6);
GPU.DispStat[1] |= (1<<6); GPU.DispStat[1] |= (1<<6);
UpdateVRAMTimings();
} }
void DSi::Stop(Platform::StopReason reason) void DSi::Stop(Platform::StopReason reason)
@ -284,13 +280,11 @@ void DSi::DoSavestateExtra(Savestate* file)
NDMAs[i].DoSavestate(file); NDMAs[i].DoSavestate(file);
AES.DoSavestate(file); AES.DoSavestate(file);
CamModule.DoSavestate(file);
DSP.DoSavestate(file); DSP.DoSavestate(file);
I2C.DoSavestate(file); I2C.DoSavestate(file);
CamModule.DoSavestate(file);
SDMMC.DoSavestate(file); SDMMC.DoSavestate(file);
SDIO.DoSavestate(file); SDIO.DoSavestate(file);
UpdateVRAMTimings();
} }
void DSi::SetCartInserted(bool inserted) void DSi::SetCartInserted(bool inserted)
@ -672,8 +666,6 @@ void DSi::SetupDirectBoot()
ARM9.CP15Write(0x671, 0x02FFC01B); ARM9.CP15Write(0x671, 0x02FFC01B);
ARM9.CP15Write(0x910, 0x0E00000A); ARM9.CP15Write(0x910, 0x0E00000A);
ARM9.CP15Write(0x911, 0x00000020); ARM9.CP15Write(0x911, 0x00000020);
UpdateVRAMTimings();
} }
void DSi::SoftReset() void DSi::SoftReset()
@ -725,11 +717,10 @@ void DSi::SoftReset()
SCFG_RST = 0; SCFG_RST = 0;
DSP.SetRstLine(false); DSP.SetRstLine(false);
// LCD init flag // LCD init flag
GPU.DispStat[0] |= (1<<6); GPU.DispStat[0] |= (1<<6);
GPU.DispStat[1] |= (1<<6); GPU.DispStat[1] |= (1<<6);
UpdateVRAMTimings();
} }
bool DSi::LoadNAND() bool DSi::LoadNAND()
@ -1261,20 +1252,6 @@ void DSi::MapNWRAMRange(u32 cpu, u32 num, u32 val)
} }
} }
void DSi::UpdateVRAMTimings()
{
if (SCFG_EXT[0] & (1<<13))
{
SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 32, 1, 1);
SetARM7RegionTimings(0x06000, 0x07000, Mem7_VRAM, 32, 1, 1);
}
else
{
SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 16, 1, 1);
SetARM7RegionTimings(0x06000, 0x07000, Mem7_VRAM, 16, 1, 1);
}
}
void DSi::ApplyNewRAMSize(u32 size) void DSi::ApplyNewRAMSize(u32 size)
{ {
switch (size) switch (size)
@ -2588,8 +2565,6 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val)
//if (newram != oldram) //if (newram != oldram)
// NDS::ScheduleEvent(NDS::Event_DSi_RAMSizeChange, false, 512*512*512, ApplyNewRAMSize, newram); // NDS::ScheduleEvent(NDS::Event_DSi_RAMSizeChange, false, 512*512*512, ApplyNewRAMSize, newram);
Log(LogLevel::Debug, "from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), ARM7.R[1]); Log(LogLevel::Debug, "from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), ARM7.R[1]);
UpdateVRAMTimings();
} }
return; return;

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -97,8 +97,6 @@ public:
void MapNWRAM_C(u32 num, u8 val); void MapNWRAM_C(u32 num, u8 val);
void MapNWRAMRange(u32 cpu, u32 num, u32 val); void MapNWRAMRange(u32 cpu, u32 num, u32 val);
void UpdateVRAMTimings();
u8 ARM9Read8(u32 addr) override; u8 ARM9Read8(u32 addr) override;
u16 ARM9Read16(u32 addr) override; u16 ARM9Read16(u32 addr) override;
u32 ARM9Read32(u32 addr) override; u32 ARM9Read32(u32 addr) override;

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -34,11 +34,8 @@ using Platform::LogLevel;
// namely, how long cameras take to process frames // namely, how long cameras take to process frames
// camera IRQ is fired at roughly 15FPS with default config // camera IRQ is fired at roughly 15FPS with default config
// camera IRQ marks camera VBlank const u32 DSi_CamModule::kIRQInterval = 1120000; // ~30 FPS
// each scanline takes roughly 3173 cycles const u32 DSi_CamModule::kTransferStart = 60000;
const u32 DSi_CamModule::kIRQInterval = 2234248; // ~15 FPS
const u32 DSi_CamModule::kScanlineTime = 3173;
const u32 DSi_CamModule::kTransferStart = DSi_CamModule::kIRQInterval - (DSi_CamModule::kScanlineTime * 480);
DSi_CamModule::DSi_CamModule(melonDS::DSi& dsi) : DSi(dsi) DSi_CamModule::DSi_CamModule(melonDS::DSi& dsi) : DSi(dsi)
@ -67,15 +64,12 @@ void DSi_CamModule::Reset()
CropStart = 0; CropStart = 0;
CropEnd = 0; CropEnd = 0;
Transferring = false; memset(DataBuffer, 0, 512*sizeof(u32));
BufferReadPos = 0;
memset(PixelBuffer, 0, sizeof(PixelBuffer)); BufferWritePos = 0;
CurPixelBuffer = 0;
BufferNumLines = 0; BufferNumLines = 0;
CurCamera = nullptr; CurCamera = nullptr;
// TODO: ideally this should be started when a camera is active
// instead of just being a constant thing
DSi.ScheduleEvent(Event_DSi_CamIRQ, false, kIRQInterval, 0, 0); DSi.ScheduleEvent(Event_DSi_CamIRQ, false, kIRQInterval, 0, 0);
} }
@ -92,30 +86,9 @@ void DSi_CamModule::DoSavestate(Savestate* file)
file->Var16(&ModuleCnt); file->Var16(&ModuleCnt);
file->Var16(&Cnt); file->Var16(&Cnt);
file->Var32(&CropStart); /*file->VarArray(FrameBuffer, sizeof(FrameBuffer));
file->Var32(&CropEnd); file->Var32(&TransferPos);
file->Var32(&FrameLength);*/
file->Bool32(&Transferring);
file->VarArray(&PixelBuffer[0].Data, 512);
file->Var32(&PixelBuffer[0].ReadPos);
file->Var32(&PixelBuffer[0].WritePos);
file->VarArray(&PixelBuffer[1].Data, 512);
file->Var32(&PixelBuffer[1].ReadPos);
file->Var32(&PixelBuffer[1].WritePos);
file->Var8(&CurPixelBuffer);
file->Var32(&BufferNumLines);
if (!file->Saving)
{
DSi_Camera* activecam = nullptr;
if (Camera0->IsActivated()) activecam = Camera0;
else if (Camera1->IsActivated()) activecam = Camera1;
CurCamera = activecam;
}
} }
@ -135,8 +108,14 @@ void DSi_CamModule::IRQ(u32 param)
if (Cnt & (1<<11)) if (Cnt & (1<<11))
DSi.SetIRQ(0, IRQ_DSi_Camera); DSi.SetIRQ(0, IRQ_DSi_Camera);
CurCamera = activecam; if (Cnt & (1<<15))
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, kTransferStart, 0, 0); {
BufferReadPos = 0;
BufferWritePos = 0;
BufferNumLines = 0;
CurCamera = activecam;
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, kTransferStart, 0, 0);
}
} }
DSi.ScheduleEvent(Event_DSi_CamIRQ, true, kIRQInterval, 0, 0); DSi.ScheduleEvent(Event_DSi_CamIRQ, true, kIRQInterval, 0, 0);
@ -144,35 +123,17 @@ void DSi_CamModule::IRQ(u32 param)
void DSi_CamModule::TransferScanline(u32 line) void DSi_CamModule::TransferScanline(u32 line)
{ {
if (Cnt & (1<<4)) u32* dstbuf = &DataBuffer[BufferWritePos];
{ int maxlen = 512 - BufferWritePos;
Transferring = false;
return;
}
if (line == 0)
{
if (!(Cnt & (1<<15)))
return;
BufferNumLines = 0;
Transferring = true;
}
sPixelBuffer* buffer = &PixelBuffer[CurPixelBuffer];
u32* dstbuf = &buffer->Data[buffer->WritePos];
int maxlen = 512 - buffer->WritePos;
u32 tmpbuf[512]; u32 tmpbuf[512];
int lines_next; int datalen = CurCamera->TransferScanline(tmpbuf, 512);
int datalen = CurCamera->TransferScanline(tmpbuf, 512, lines_next);
u32 numscan;
u32 delay = lines_next * kScanlineTime; // TODO: must be tweaked such that each block has enough time to transfer
u32 delay = datalen*4 + 16;
int copystart = 0; int copystart = 0;
int copylen = datalen; int copylen = datalen;
bool line_last = false;
if (Cnt & (1<<14)) if (Cnt & (1<<14))
{ {
@ -182,8 +143,10 @@ void DSi_CamModule::TransferScanline(u32 line)
int yend = (CropEnd >> 16) & 0x1FF; int yend = (CropEnd >> 16) & 0x1FF;
if (line < ystart || line > yend) if (line < ystart || line > yend)
{ {
if (line == yend+1) line_last = true; if (!CurCamera->TransferDone())
goto skip_line; DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1);
return;
} }
int xstart = (CropStart >> 1) & 0x1FF; int xstart = (CropStart >> 1) & 0x1FF;
@ -201,6 +164,7 @@ void DSi_CamModule::TransferScanline(u32 line)
if (copylen > maxlen) if (copylen > maxlen)
{ {
copylen = maxlen; copylen = maxlen;
Cnt |= (1<<4);
} }
if (Cnt & (1<<13)) if (Cnt & (1<<13))
@ -242,70 +206,27 @@ void DSi_CamModule::TransferScanline(u32 line)
memcpy(dstbuf, &tmpbuf[copystart], copylen*sizeof(u32)); memcpy(dstbuf, &tmpbuf[copystart], copylen*sizeof(u32));
} }
buffer->WritePos += copylen; u32 numscan = Cnt & 0x000F;
if (buffer->WritePos > 512) buffer->WritePos = 512;
numscan = Cnt & 0x000F;
if (BufferNumLines >= numscan) if (BufferNumLines >= numscan)
{ {
BufferReadPos = 0; // checkme
BufferWritePos = 0;
BufferNumLines = 0; BufferNumLines = 0;
SwapPixelBuffers(); DSi.CheckNDMAs(0, 0x0B);
} }
else else
{ {
BufferWritePos += copylen;
if (BufferWritePos > 512) BufferWritePos = 512;
BufferNumLines++; BufferNumLines++;
} }
skip_line: if (CurCamera->TransferDone())
bool done = CurCamera->TransferDone();
if (done || line_last)
{
// 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)
{
BufferNumLines = 0;
SwapPixelBuffers();
}
}
if (done)
{
Transferring = false;
return; return;
}
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1); DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1);
} }
void DSi_CamModule::SwapPixelBuffers()
{
// pixel buffers are swapped every time a buffer is filled (ie. when the DMA interval is reached)
// the swap fails if the other buffer isn't empty
sPixelBuffer* otherbuf = &PixelBuffer[CurPixelBuffer ^ 1];
if (otherbuf->ReadPos < otherbuf->WritePos)
{
// overrun
Cnt |= (1<<4);
Transferring = false;
}
else
{
PixelBuffer[CurPixelBuffer].ReadPos = 0;
otherbuf->WritePos = 0;
CurPixelBuffer ^= 1;
DSi.CheckNDMAs(0, 0x0B);
}
}
bool DSi_CamModule::IsTransferring()
{
if (Cnt & (1<<15)) return true;
if (Transferring) return true;
return false;
}
u8 DSi_CamModule::Read8(u32 addr) u8 DSi_CamModule::Read8(u32 addr)
{ {
@ -320,7 +241,7 @@ u16 DSi_CamModule::Read16(u32 addr)
switch (addr) switch (addr)
{ {
case 0x04004200: return ModuleCnt; case 0x04004200: return ModuleCnt;
case 0x04004202: return Cnt | (Transferring ? (1<<15) : 0); case 0x04004202: return Cnt;
} }
Log(LogLevel::Debug, "unknown DSi cam read16 %08X\n", addr); Log(LogLevel::Debug, "unknown DSi cam read16 %08X\n", addr);
@ -333,14 +254,14 @@ u32 DSi_CamModule::Read32(u32 addr)
{ {
case 0x04004204: case 0x04004204:
{ {
sPixelBuffer* buffer = &PixelBuffer[CurPixelBuffer ^ 1]; u32 ret = DataBuffer[BufferReadPos];
u32 ret; if (Cnt & (1<<15))
if (buffer->ReadPos < buffer->WritePos) {
ret = buffer->Data[buffer->ReadPos++]; if (BufferReadPos < 511)
else if (buffer->ReadPos > 0) BufferReadPos++;
ret = buffer->Data[buffer->ReadPos - 1]; // CHECKME!!!!
else // also presumably we should set bit4 in Cnt if there's no new data to be read
ret = buffer->Data[0]; }
return ret; return ret;
} }
@ -375,7 +296,6 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
// CHECKME // CHECKME
Cnt = 0; Cnt = 0;
Transferring = false;
} }
if ((ModuleCnt & (1<<5)) && !(oldcnt & (1<<5))) if ((ModuleCnt & (1<<5)) && !(oldcnt & (1<<5)))
@ -387,9 +307,12 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
case 0x04004202: case 0x04004202:
{ {
// TODO: during a transfer, clearing bit15 does not reflect immediately
// maybe it needs to finish the trasnfer or atleast the current block
// checkme // checkme
u16 oldmask; u16 oldmask;
if (IsTransferring()) if (Cnt & 0x8000)
{ {
val &= 0x8F20; val &= 0x8F20;
oldmask = 0x601F; oldmask = 0x601F;
@ -404,26 +327,32 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
if (val & (1<<5)) if (val & (1<<5))
{ {
Cnt &= ~(1<<4); Cnt &= ~(1<<4);
memset(PixelBuffer, 0, sizeof(PixelBuffer)); BufferReadPos = 0;
CurPixelBuffer = 0; BufferWritePos = 0;
}
if ((val & (1<<15)) && !(Cnt & (1<<15)))
{
// start transfer
//DSi::CheckNDMAs(0, 0x0B);
} }
} }
return; return;
case 0x04004210: case 0x04004210:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropStart = (CropStart & 0x01FF0000) | (val & 0x03FE); CropStart = (CropStart & 0x01FF0000) | (val & 0x03FE);
return; return;
case 0x04004212: case 0x04004212:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropStart = (CropStart & 0x03FE) | ((val & 0x01FF) << 16); CropStart = (CropStart & 0x03FE) | ((val & 0x01FF) << 16);
return; return;
case 0x04004214: case 0x04004214:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropEnd = (CropEnd & 0x01FF0000) | (val & 0x03FE); CropEnd = (CropEnd & 0x01FF0000) | (val & 0x03FE);
return; return;
case 0x04004216: case 0x04004216:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropEnd = (CropEnd & 0x03FE) | ((val & 0x01FF) << 16); CropEnd = (CropEnd & 0x03FE) | ((val & 0x01FF) << 16);
return; return;
} }
@ -436,11 +365,11 @@ void DSi_CamModule::Write32(u32 addr, u32 val)
switch (addr) switch (addr)
{ {
case 0x04004210: case 0x04004210:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropStart = val & 0x01FF03FE; CropStart = val & 0x01FF03FE;
return; return;
case 0x04004214: case 0x04004214:
if (IsTransferring()) return; if (Cnt & (1<<15)) return;
CropEnd = val & 0x01FF03FE; CropEnd = val & 0x01FF03FE;
return; return;
} }
@ -500,7 +429,6 @@ void DSi_Camera::Reset()
// default state is preview mode (checkme) // default state is preview mode (checkme)
MCURegs[0x2104] = 3; MCURegs[0x2104] = 3;
InternalY = 0;
TransferY = 0; TransferY = 0;
memset(FrameBuffer, 0, (640*480/2)*sizeof(u32)); memset(FrameBuffer, 0, (640*480/2)*sizeof(u32));
} }
@ -521,7 +449,6 @@ bool DSi_Camera::IsActivated() const
void DSi_Camera::StartTransfer() void DSi_Camera::StartTransfer()
{ {
InternalY = 0;
TransferY = 0; TransferY = 0;
u8 state = MCURegs[0x2104]; u8 state = MCURegs[0x2104];
@ -555,11 +482,9 @@ bool DSi_Camera::TransferDone() const
return TransferY >= FrameHeight; return TransferY >= FrameHeight;
} }
int DSi_Camera::TransferScanline(u32* buffer, int maxlen, int& nlines) int DSi_Camera::TransferScanline(u32* buffer, int maxlen)
{ {
nlines = 0; if (TransferY >= FrameHeight)
if ((TransferY >= FrameHeight) || (InternalY >= 480))
return 0; return 0;
if (FrameWidth > 640 || FrameHeight > 480 || if (FrameWidth > 640 || FrameHeight > 480 ||
@ -575,7 +500,7 @@ int DSi_Camera::TransferScanline(u32* buffer, int maxlen, int& nlines)
// TODO: non-YUV pixel formats and all // TODO: non-YUV pixel formats and all
int retlen = FrameWidth >> 1; int retlen = FrameWidth >> 1;
int sy = InternalY; int sy = (TransferY * 480) / FrameHeight;
if (FrameReadMode & (1<<1)) if (FrameReadMode & (1<<1))
sy = 479 - sy; sy = 479 - sy;
@ -604,15 +529,7 @@ int DSi_Camera::TransferScanline(u32* buffer, int maxlen, int& nlines)
} }
} }
// determine how many scanlines we're skipping until the next scanline TransferY++;
int oldy = TransferY;
do
{
InternalY++;
TransferY = (InternalY * FrameHeight) / 480;
nlines++;
}
while ((TransferY == oldy) && (InternalY < 480));
return retlen; return retlen;
} }

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -44,7 +44,7 @@ public:
bool TransferDone() const; bool TransferDone() const;
// lengths in words // lengths in words
int TransferScanline(u32* buffer, int maxlen, int& nlines); int TransferScanline(u32* buffer, int maxlen);
void Acquire() override; void Acquire() override;
u8 Read(bool last) override; u8 Read(bool last) override;
@ -77,7 +77,6 @@ private:
u16 FrameWidth, FrameHeight; u16 FrameWidth, FrameHeight;
u16 FrameReadMode, FrameFormat; u16 FrameReadMode, FrameFormat;
int InternalY;
int TransferY; int TransferY;
u32 FrameBuffer[640*480/2]; // YUYV framebuffer, two pixels per word u32 FrameBuffer[640*480/2]; // YUYV framebuffer, two pixels per word
}; };
@ -118,26 +117,14 @@ private:
u32 CropStart, CropEnd; u32 CropStart, CropEnd;
bool Transferring; // pixel data buffer holds a maximum of 512 words, regardless of how long scanlines are
u32 DataBuffer[512];
// pixel data buffers hold a maximum of 512 words, regardless of how long scanlines are u32 BufferReadPos, BufferWritePos;
typedef struct
{
u32 Data[512];
u32 ReadPos, WritePos;
} sPixelBuffer;
sPixelBuffer PixelBuffer[2];
u8 CurPixelBuffer;
u32 BufferNumLines; u32 BufferNumLines;
DSi_Camera* CurCamera; DSi_Camera* CurCamera;
static const u32 kIRQInterval; static const u32 kIRQInterval;
static const u32 kScanlineTime;
static const u32 kTransferStart; static const u32 kTransferStart;
void SwapPixelBuffers();
bool IsTransferring();
}; };
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -242,6 +242,8 @@ u16 CartGame::ROMRead(u32 addr) const
case 0xC8: return GPIO.control; case 0xC8: return GPIO.control;
} }
} }
else
return 0;
} }
// CHECKME: does ROM mirror? // CHECKME: does ROM mirror?
@ -537,57 +539,6 @@ 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}; const int CartGameSolarSensor::kLuxLevels[11] = {0, 5, 11, 18, 27, 42, 62, 84, 109, 139, 183};
void CartGameSolarSensor::Reset() void CartGameSolarSensor::Reset()
@ -773,27 +724,6 @@ 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)) GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
{ {
} }
@ -913,27 +843,7 @@ std::unique_ptr<CartCommon> LoadAddon(int type, void* userdata)
case GBAAddon_RumblePak: case GBAAddon_RumblePak:
cart = std::make_unique<CartRumblePak>(userdata); cart = std::make_unique<CartRumblePak>(userdata);
break; 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: default:
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type); Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
return nullptr; return nullptr;

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.
@ -33,30 +33,8 @@ enum CartType
GameSolarSensor = 0x102, GameSolarSensor = 0x102,
RAMExpansion = 0x201, RAMExpansion = 0x201,
RumblePak = 0x202, 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 // CartCommon -- base code shared by all cart types
class CartCommon class CartCommon
{ {
@ -113,8 +91,6 @@ public:
[[nodiscard]] const u8* GetROM() const override { return ROM.get(); } [[nodiscard]] const u8* GetROM() const override { return ROM.get(); }
[[nodiscard]] u32 GetROMLength() const override { return ROMLength; } [[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; u8* GetSaveMemory() const override;
u32 GetSaveMemoryLength() const override; u32 GetSaveMemoryLength() const override;
@ -235,68 +211,11 @@ private:
u16 RumbleState = 0; 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 // possible inputs for GBA carts that might accept user input
enum enum
{ {
Input_SolarSensorDown = 0, Input_SolarSensorDown = 0,
Input_SolarSensorUp, Input_SolarSensorUp,
Input_GuitarGripGreen,
Input_GuitarGripRed,
Input_GuitarGripYellow,
Input_GuitarGripBlue,
}; };
class GBACartSlot class GBACartSlot
@ -390,23 +309,6 @@ std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
std::unique_ptr<CartCommon> LoadAddon(int type, void* userdata); 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 #endif // GBACART_H

View File

@ -1,196 +0,0 @@
/*
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-2025 melonDS team Copyright 2016-2024 melonDS team
This file is part of melonDS. This file is part of melonDS.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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