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

View File

@ -4,7 +4,6 @@ on:
push:
branches:
- master
- ci/*
pull_request:
branches:
- master
@ -13,27 +12,19 @@ env:
MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions
# MELONDS_VERSION_SUFFIX: " RC"
MELONDS_VERSION_SUFFIX: " RC"
jobs:
build:
continue-on-error: true
strategy:
matrix:
arch:
- runner: ubuntu-22.04
build-x86_64:
name: x86_64
- runner: ubuntu-22.04-arm
name: aarch64
name: ${{ matrix.arch.name }}
runs-on: ${{ matrix.arch.runner }}
runs-on: ubuntu-22.04
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
@ -45,19 +36,56 @@ jobs:
DESTDIR=AppDir cmake --install build
- uses: actions/upload-artifact@v4
with:
name: melonDS-ubuntu-${{ matrix.arch.name }}
name: melonDS-ubuntu-x86_64
path: AppDir/usr/bin/melonDS
- name: Fetch AppImage tools
run: |
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
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
chmod a+x linuxdeploy-*.AppImage
- name: Build the AppImage
env:
QMAKE: /usr/lib/qt6/bin/qmake
run: |
./linuxdeploy-${{ 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
with:
name: melonDS-appimage-${{ matrix.arch.name }}
name: melonDS-appimage-x86_64
path: melonDS*.AppImage
build-aarch64:
name: aarch64
runs-on: ubuntu-latest
container: ubuntu:22.04
steps:
- name: Prepare system
shell: bash
run: |
dpkg --add-architecture arm64
sh -c "sed \"s|^deb \([a-z\.:/]*\) \([a-z\-]*\) \(.*\)$|deb [arch=amd64] \1 \2 \3\ndeb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports \2 \3|\" /etc/apt/sources.list > /etc/apt/sources.list.new"
rm /etc/apt/sources.list
mv /etc/apt/sources.list{.new,}
apt update
apt -y full-upgrade
apt -y install git {gcc-12,g++-12}-aarch64-linux-gnu cmake ninja-build extra-cmake-modules \
{libsdl2,qt6-{base,base-private,multimedia},libqt6svg6,libarchive,libzstd,libenet}-dev:arm64 \
pkg-config dpkg-dev
- name: Check out source
uses: actions/checkout@v4
- name: Configure
shell: bash
run: |
cmake -B build -G Ninja \
-DPKG_CONFIG_EXECUTABLE=/usr/bin/aarch64-linux-gnu-pkg-config \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-12 \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-12 \
-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
env:
VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
MELONDS_GIT_BRANCH: ${{ github.ref }}
MELONDS_GIT_HASH: ${{ github.sha }}
MELONDS_BUILD_PROVIDER: GitHub Actions
# MELONDS_VERSION_SUFFIX: " RC"
MELONDS_VERSION_SUFFIX: " RC"
jobs:
build:
@ -34,7 +33,7 @@ jobs:
- name: Set up vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4
- name: Configure
run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON
- 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_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)
@ -30,6 +29,8 @@ 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

@ -2,7 +2,7 @@
<h2 align="center"><b>melonDS</b></h2>
<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/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://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>

View File

@ -9,8 +9,7 @@ if (VCPKG_ROOT STREQUAL "${_DEFAULT_VCPKG_ROOT}")
endif()
FetchContent_Declare(vcpkg
GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git"
GIT_TAG 2ad004460f5db4d3b66f62f5799ff66c265c4b5d
EXCLUDE_FROM_ALL
GIT_TAG 2024.10.21
SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg")
FetchContent_MakeAvailable(vcpkg)
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_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": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1739020877,
"narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=",
"lastModified": 1730531603,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a79cfe0ebd24952b580b1cf08cd906354996d547",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
"type": "github"
},
"original": {

View File

@ -95,13 +95,7 @@
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
'';
};
};
}

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 "FileDescription", "melonDS emulator"
VALUE "InternalName", "SDnolem"
VALUE "LegalCopyright", "2016-2025 melonDS team"
VALUE "LegalCopyright", "2016-2023 melonDS team"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "melonDS.exe"
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.

View File

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

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 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 ? std::nullopt : gdb);
SetGdbArgs(jit ? gdb : std::nullopt);
}
ARM::~ARM()

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team, RSDuck
Copyright 2016-2024 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);
cpu9->CodeRead32(addr-2, true) >> 16;
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+2, false);
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team, RSDuck
Copyright 2016-2024 melonDS team, RSDuck
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team, RSDuck
Copyright 2016-2024 melonDS team, RSDuck
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 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];
snprintf(fastmemPidName, sizeof(fastmemPidName), "/melondsfastmem%d", getpid());
sprintf(fastmemPidName, "/melondsfastmem%d", getpid());
MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600);
if (MemoryFile == -1)
{
@ -951,6 +951,7 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
MemoryBase = nullptr;
FastMem9Start = nullptr;
FastMem7Start = nullptr;
printf("unmappinged everything\n");
}
if (MemoryFile)
@ -978,8 +979,6 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
MemoryFile = -1;
}
Log(LogLevel::Info, "unmappinged everything\n");
#if defined(__ANDROID__)
if (Libandroid)
{

View File

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

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team, RSDuck
Copyright 2016-2024 melonDS team, RSDuck
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -30,7 +30,6 @@ add_library(core STATIC
FATStorage.cpp
FIFO.h
GBACart.cpp
GBACartMotionPak.cpp
GPU.cpp
GPU2D.cpp
GPU2D_Soft.cpp
@ -103,8 +102,6 @@ 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-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.
@ -113,8 +113,6 @@ DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
NWRAM_A = JIT.Memory.GetNWRAM_A();
NWRAM_B = JIT.Memory.GetNWRAM_B();
NWRAM_C = JIT.Memory.GetNWRAM_C();
SetFullBIOSBoot(args.FullBIOSBoot);
}
DSi::~DSi() noexcept
@ -177,8 +175,6 @@ void DSi::Reset()
// LCD init flag
GPU.DispStat[0] |= (1<<6);
GPU.DispStat[1] |= (1<<6);
UpdateVRAMTimings();
}
void DSi::Stop(Platform::StopReason reason)
@ -284,13 +280,11 @@ void DSi::DoSavestateExtra(Savestate* file)
NDMAs[i].DoSavestate(file);
AES.DoSavestate(file);
CamModule.DoSavestate(file);
DSP.DoSavestate(file);
I2C.DoSavestate(file);
CamModule.DoSavestate(file);
SDMMC.DoSavestate(file);
SDIO.DoSavestate(file);
UpdateVRAMTimings();
}
void DSi::SetCartInserted(bool inserted)
@ -672,8 +666,6 @@ void DSi::SetupDirectBoot()
ARM9.CP15Write(0x671, 0x02FFC01B);
ARM9.CP15Write(0x910, 0x0E00000A);
ARM9.CP15Write(0x911, 0x00000020);
UpdateVRAMTimings();
}
void DSi::SoftReset()
@ -725,11 +717,10 @@ void DSi::SoftReset()
SCFG_RST = 0;
DSP.SetRstLine(false);
// LCD init flag
GPU.DispStat[0] |= (1<<6);
GPU.DispStat[1] |= (1<<6);
UpdateVRAMTimings();
}
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)
{
switch (size)
@ -2588,8 +2565,6 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val)
//if (newram != oldram)
// 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]);
UpdateVRAMTimings();
}
return;

View File

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

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.
@ -34,11 +34,8 @@ using Platform::LogLevel;
// namely, how long cameras take to process frames
// camera IRQ is fired at roughly 15FPS with default config
// camera IRQ marks camera VBlank
// each scanline takes roughly 3173 cycles
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);
const u32 DSi_CamModule::kIRQInterval = 1120000; // ~30 FPS
const u32 DSi_CamModule::kTransferStart = 60000;
DSi_CamModule::DSi_CamModule(melonDS::DSi& dsi) : DSi(dsi)
@ -67,15 +64,12 @@ void DSi_CamModule::Reset()
CropStart = 0;
CropEnd = 0;
Transferring = false;
memset(PixelBuffer, 0, sizeof(PixelBuffer));
CurPixelBuffer = 0;
memset(DataBuffer, 0, 512*sizeof(u32));
BufferReadPos = 0;
BufferWritePos = 0;
BufferNumLines = 0;
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);
}
@ -92,30 +86,9 @@ void DSi_CamModule::DoSavestate(Savestate* file)
file->Var16(&ModuleCnt);
file->Var16(&Cnt);
file->Var32(&CropStart);
file->Var32(&CropEnd);
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;
}
/*file->VarArray(FrameBuffer, sizeof(FrameBuffer));
file->Var32(&TransferPos);
file->Var32(&FrameLength);*/
}
@ -135,44 +108,32 @@ void DSi_CamModule::IRQ(u32 param)
if (Cnt & (1<<11))
DSi.SetIRQ(0, IRQ_DSi_Camera);
if (Cnt & (1<<15))
{
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);
}
void DSi_CamModule::TransferScanline(u32 line)
{
if (Cnt & (1<<4))
{
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* dstbuf = &DataBuffer[BufferWritePos];
int maxlen = 512 - BufferWritePos;
u32 tmpbuf[512];
int lines_next;
int datalen = CurCamera->TransferScanline(tmpbuf, 512, lines_next);
u32 numscan;
int datalen = CurCamera->TransferScanline(tmpbuf, 512);
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 copylen = datalen;
bool line_last = false;
if (Cnt & (1<<14))
{
@ -182,8 +143,10 @@ void DSi_CamModule::TransferScanline(u32 line)
int yend = (CropEnd >> 16) & 0x1FF;
if (line < ystart || line > yend)
{
if (line == yend+1) line_last = true;
goto skip_line;
if (!CurCamera->TransferDone())
DSi.ScheduleEvent(Event_DSi_CamTransfer, false, delay, 0, line+1);
return;
}
int xstart = (CropStart >> 1) & 0x1FF;
@ -201,6 +164,7 @@ void DSi_CamModule::TransferScanline(u32 line)
if (copylen > maxlen)
{
copylen = maxlen;
Cnt |= (1<<4);
}
if (Cnt & (1<<13))
@ -242,70 +206,27 @@ void DSi_CamModule::TransferScanline(u32 line)
memcpy(dstbuf, &tmpbuf[copystart], copylen*sizeof(u32));
}
buffer->WritePos += copylen;
if (buffer->WritePos > 512) buffer->WritePos = 512;
numscan = Cnt & 0x000F;
u32 numscan = Cnt & 0x000F;
if (BufferNumLines >= numscan)
{
BufferReadPos = 0; // checkme
BufferWritePos = 0;
BufferNumLines = 0;
SwapPixelBuffers();
DSi.CheckNDMAs(0, 0x0B);
}
else
{
BufferWritePos += copylen;
if (BufferWritePos > 512) BufferWritePos = 512;
BufferNumLines++;
}
skip_line:
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;
if (CurCamera->TransferDone())
return;
}
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)
{
@ -320,7 +241,7 @@ u16 DSi_CamModule::Read16(u32 addr)
switch (addr)
{
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);
@ -333,14 +254,14 @@ u32 DSi_CamModule::Read32(u32 addr)
{
case 0x04004204:
{
sPixelBuffer* buffer = &PixelBuffer[CurPixelBuffer ^ 1];
u32 ret;
if (buffer->ReadPos < buffer->WritePos)
ret = buffer->Data[buffer->ReadPos++];
else if (buffer->ReadPos > 0)
ret = buffer->Data[buffer->ReadPos - 1];
else
ret = buffer->Data[0];
u32 ret = DataBuffer[BufferReadPos];
if (Cnt & (1<<15))
{
if (BufferReadPos < 511)
BufferReadPos++;
// CHECKME!!!!
// also presumably we should set bit4 in Cnt if there's no new data to be read
}
return ret;
}
@ -375,7 +296,6 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
// CHECKME
Cnt = 0;
Transferring = false;
}
if ((ModuleCnt & (1<<5)) && !(oldcnt & (1<<5)))
@ -387,9 +307,12 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
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
u16 oldmask;
if (IsTransferring())
if (Cnt & 0x8000)
{
val &= 0x8F20;
oldmask = 0x601F;
@ -404,26 +327,32 @@ void DSi_CamModule::Write16(u32 addr, u16 val)
if (val & (1<<5))
{
Cnt &= ~(1<<4);
memset(PixelBuffer, 0, sizeof(PixelBuffer));
CurPixelBuffer = 0;
BufferReadPos = 0;
BufferWritePos = 0;
}
if ((val & (1<<15)) && !(Cnt & (1<<15)))
{
// start transfer
//DSi::CheckNDMAs(0, 0x0B);
}
}
return;
case 0x04004210:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropStart = (CropStart & 0x01FF0000) | (val & 0x03FE);
return;
case 0x04004212:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropStart = (CropStart & 0x03FE) | ((val & 0x01FF) << 16);
return;
case 0x04004214:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropEnd = (CropEnd & 0x01FF0000) | (val & 0x03FE);
return;
case 0x04004216:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropEnd = (CropEnd & 0x03FE) | ((val & 0x01FF) << 16);
return;
}
@ -436,11 +365,11 @@ void DSi_CamModule::Write32(u32 addr, u32 val)
switch (addr)
{
case 0x04004210:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropStart = val & 0x01FF03FE;
return;
case 0x04004214:
if (IsTransferring()) return;
if (Cnt & (1<<15)) return;
CropEnd = val & 0x01FF03FE;
return;
}
@ -500,7 +429,6 @@ void DSi_Camera::Reset()
// default state is preview mode (checkme)
MCURegs[0x2104] = 3;
InternalY = 0;
TransferY = 0;
memset(FrameBuffer, 0, (640*480/2)*sizeof(u32));
}
@ -521,7 +449,6 @@ bool DSi_Camera::IsActivated() const
void DSi_Camera::StartTransfer()
{
InternalY = 0;
TransferY = 0;
u8 state = MCURegs[0x2104];
@ -555,11 +482,9 @@ bool DSi_Camera::TransferDone() const
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) || (InternalY >= 480))
if (TransferY >= FrameHeight)
return 0;
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
int retlen = FrameWidth >> 1;
int sy = InternalY;
int sy = (TransferY * 480) / FrameHeight;
if (FrameReadMode & (1<<1))
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
int oldy = TransferY;
do
{
InternalY++;
TransferY = (InternalY * FrameHeight) / 480;
nlines++;
}
while ((TransferY == oldy) && (InternalY < 480));
TransferY++;
return retlen;
}

View File

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

View File

@ -323,7 +323,7 @@ void DSi_DSP::PDataDMAFetch()
}
void DSi_DSP::PDataDMAStart()
{
switch ((DSP_PCFG & (3<<2)) >> 2)
switch ((DSP_PSTS & (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 = 0; // TODO: is this actually 0, or just open bus?
u16 ret;
if (!PDATAReadFifo.IsEmpty())
ret = PDATAReadFifo.Read();
@ -362,9 +362,15 @@ 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-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
This file is part of melonDS.
@ -132,6 +132,7 @@ 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)
@ -269,18 +270,11 @@ 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);
@ -365,18 +359,11 @@ 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-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.
@ -242,6 +242,8 @@ u16 CartGame::ROMRead(u32 addr) const
case 0xC8: return GPIO.control;
}
}
else
return 0;
}
// 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};
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))
{
}
@ -913,27 +843,7 @@ 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-2025 melonDS team
Copyright 2016-2024 melonDS team
This file is part of melonDS.
@ -33,30 +33,8 @@ 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
{
@ -113,8 +91,6 @@ 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;
@ -235,68 +211,11 @@ 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
@ -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);
/// 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

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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.
@ -1219,7 +1219,7 @@ void GPU3D::SubmitPolygon() noexcept
u32 texfmt = (TexParam >> 26) & 0x7;
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->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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2025 melonDS team
Copyright 2016-2024 melonDS team
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.

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